Skip to content

Conversation

AmrDeveloper
Copy link
Member

  • Reorder the CIRGenExprComplex functions to be similar to OCG.
  • Add errors for unhandled visitors.
  • Rename the test file to be similar to complex-mul-div.

Issue: #141365

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Aug 31, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 31, 2025

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes
  • Reorder the CIRGenExprComplex functions to be similar to OCG.
  • Add errors for unhandled visitors.
  • Rename the test file to be similar to complex-mul-div.

Issue: #141365


Patch is 47.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/156241.diff

2 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+519-431)
  • (renamed) clang/test/CIR/CodeGen/complex-plus-minus.cpp ()
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index cbdd525068f5d..36ea5d08c2948 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -6,6 +6,16 @@
 using namespace clang;
 using namespace clang::CIRGen;
 
+#ifndef NDEBUG
+/// Return the complex type that we are meant to emit.
+static const ComplexType *getComplexType(QualType type) {
+  type = type.getCanonicalType();
+  if (const ComplexType *comp = dyn_cast<ComplexType>(type))
+    return comp;
+  return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+}
+#endif // NDEBUG
+
 namespace {
 class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   CIRGenFunction &cgf;
@@ -19,13 +29,6 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   //                               Utilities
   //===--------------------------------------------------------------------===//
 
-  LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val);
-
-  mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy);
-
-  mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant,
-                           Expr *e);
-
   /// Given an expression with complex type that represents a value l-value,
   /// this method emits the address of the l-value, then loads and returns the
   /// result.
@@ -48,20 +51,75 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   mlir::Value emitScalarToComplexCast(mlir::Value value, QualType srcType,
                                       QualType destType, SourceLocation loc);
 
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  mlir::Value Visit(Expr *e) {
+    return StmtVisitor<ComplexExprEmitter, mlir::Value>::Visit(e);
+  }
+
+  mlir::Value VisitStmt(Stmt *s) {
+    cgf.cgm.errorNYI(s->getBeginLoc(), "ComplexExprEmitter VisitStmt");
+    return {};
+  }
+
+  mlir::Value VisitExpr(Expr *e);
+  mlir::Value VisitConstantExpr(ConstantExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitConstantExpr");
+    return {};
+  }
+
+  mlir::Value VisitParenExpr(ParenExpr *pe) { return Visit(pe->getSubExpr()); }
+  mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
+    return Visit(ge->getResultExpr());
+  }
+  mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il);
   mlir::Value
-  VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
-  mlir::Value VisitArraySubscriptExpr(Expr *e);
-  mlir::Value VisitBinAssign(const BinaryOperator *e);
-  mlir::Value VisitBinComma(const BinaryOperator *e);
-  mlir::Value VisitCallExpr(const CallExpr *e);
-  mlir::Value VisitCastExpr(CastExpr *e);
-  mlir::Value VisitChooseExpr(ChooseExpr *e);
-  mlir::Value VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e);
-  mlir::Value VisitDeclRefExpr(DeclRefExpr *e);
-  mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *e);
-  mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e);
-  mlir::Value VisitInitListExpr(InitListExpr *e);
+  VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *pe) {
+    return Visit(pe->getReplacement());
+  }
+  mlir::Value VisitCoawaitExpr(CoawaitExpr *s) {
+    cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoawaitExpr");
+    return {};
+  }
+  mlir::Value VisitCoyieldExpr(CoyieldExpr *s) {
+    cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoyieldExpr");
+    return {};
+  }
+  mlir::Value VisitUnaryCoawait(const UnaryOperator *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitUnaryCoawait");
+    return {};
+  }
+
+  mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant,
+                           Expr *e) {
+    assert(constant && "not a constant");
+    if (constant.isReference())
+      return emitLoadOfLValue(constant.getReferenceLValue(cgf, e),
+                              e->getExprLoc());
+
+    mlir::TypedAttr valueAttr = constant.getValue();
+    return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr);
+  }
 
+  // l-values.
+  mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
+    if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
+      return emitConstant(constant, e);
+    return emitLoadOfLValue(e);
+  }
+  mlir::Value VisitObjCIvarRefExpr(ObjCIvarRefExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitObjCIvarRefExpr");
+    return {};
+  }
+  mlir::Value VisitObjCMessageExpr(ObjCMessageExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitObjCMessageExpr");
+    return {};
+  }
+  mlir::Value VisitArraySubscriptExpr(Expr *e) { return emitLoadOfLValue(e); }
   mlir::Value VisitMemberExpr(MemberExpr *me) {
     if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(me)) {
       cgf.emitIgnoredExpr(me->getBase());
@@ -69,45 +127,99 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
     }
     return emitLoadOfLValue(me);
   }
+  mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitOpaqueValueExpr");
+    return {};
+  }
 
-  mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
-    return emitLoadOfLValue(e);
+  mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitPseudoObjectExpr");
+    return {};
   }
 
-  mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il);
-  mlir::Value VisitParenExpr(ParenExpr *e);
-  mlir::Value
-  VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);
+  mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy);
+  mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e) {
+    // Unlike for scalars, we don't have to worry about function->ptr demotion
+    // here.
+    if (e->changesVolatileQualification())
+      return emitLoadOfLValue(e);
+    return emitCast(e->getCastKind(), e->getSubExpr(), e->getType());
+  }
+  mlir::Value VisitCastExpr(CastExpr *e) {
+    if (const auto *ece = dyn_cast<ExplicitCastExpr>(e)) {
+      // Bind VLAs in the cast type.
+      if (ece->getType()->isVariablyModifiedType()) {
+        cgf.cgm.errorNYI(e->getExprLoc(),
+                         "VisitCastExpr Bind VLAs in the cast type");
+        return {};
+      }
+    }
 
-  mlir::Value VisitPrePostIncDec(const UnaryOperator *e, cir::UnaryOpKind op,
-                                 bool isPre);
+    if (e->changesVolatileQualification())
+      return emitLoadOfLValue(e);
+
+    return emitCast(e->getCastKind(), e->getSubExpr(), e->getType());
+  }
+  mlir::Value VisitCallExpr(const CallExpr *e);
+  mlir::Value VisitStmtExpr(const StmtExpr *e);
 
+  // Operators.
+  mlir::Value VisitPrePostIncDec(const UnaryOperator *e, cir::UnaryOpKind op,
+                                 bool isPre) {
+    LValue lv = cgf.emitLValue(e->getSubExpr());
+    return cgf.emitComplexPrePostIncDec(e, lv, op, isPre);
+  }
   mlir::Value VisitUnaryPostDec(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Dec, false);
   }
-
   mlir::Value VisitUnaryPostInc(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Inc, false);
   }
-
   mlir::Value VisitUnaryPreDec(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Dec, true);
   }
-
   mlir::Value VisitUnaryPreInc(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Inc, true);
   }
-
-  mlir::Value VisitUnaryDeref(const Expr *e);
+  mlir::Value VisitUnaryDeref(const Expr *e) { return emitLoadOfLValue(e); }
 
   mlir::Value VisitUnaryPlus(const UnaryOperator *e);
-
+  mlir::Value VisitUnaryMinus(const UnaryOperator *e);
   mlir::Value VisitPlusMinus(const UnaryOperator *e, cir::UnaryOpKind kind,
                              QualType promotionType);
-
-  mlir::Value VisitUnaryMinus(const UnaryOperator *e);
-
   mlir::Value VisitUnaryNot(const UnaryOperator *e);
+  // LNot,Real,Imag never return complex.
+  mlir::Value VisitUnaryExtension(const UnaryOperator *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitUnaryExtension");
+    return {};
+  }
+  mlir::Value VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
+    cgf.cgm.errorNYI(dae->getExprLoc(),
+                     "ComplexExprEmitter VisitCXXDefaultArgExpr");
+    return {};
+  }
+  mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
+    cgf.cgm.errorNYI(die->getExprLoc(),
+                     "ComplexExprEmitter VisitCXXDefaultInitExpr");
+    return {};
+  }
+  mlir::Value VisitExprWithCleanups(ExprWithCleanups *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitExprWithCleanups");
+    return {};
+  }
+  mlir::Value VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
+    mlir::Location loc = cgf.getLoc(e->getExprLoc());
+    mlir::Type complexTy = cgf.convertType(e->getType());
+    return builder.getNullValue(complexTy, loc);
+  }
+  mlir::Value VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitImplicitValueInitExpr");
+    return {};
+  }
 
   struct BinOpInfo {
     mlir::Location loc;
@@ -121,14 +233,11 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
                        QualType promotionTy = QualType());
 
   mlir::Value emitPromoted(const Expr *e, QualType promotionTy);
-
   mlir::Value emitPromotedComplexOperand(const Expr *e, QualType promotionTy);
-
   LValue emitCompoundAssignLValue(
       const CompoundAssignOperator *e,
       mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &),
       RValue &value);
-
   mlir::Value emitCompoundAssign(
       const CompoundAssignOperator *e,
       mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &));
@@ -166,52 +275,179 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   HANDLEBINOP(Div)
 #undef HANDLEBINOP
 
+  mlir::Value VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitCXXRewrittenBinaryOperator");
+    return {};
+  }
+
   // Compound assignments.
   mlir::Value VisitBinAddAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinAdd);
   }
-
   mlir::Value VisitBinSubAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinSub);
   }
-
   mlir::Value VisitBinMulAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinMul);
   }
-
   mlir::Value VisitBinDivAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinDiv);
   }
 
+  // GCC rejects rem/and/or/xor for integer complex.
+  // Logical and/or always return int, never complex.
+
+  // No comparisons produce a complex result.
+
+  LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val);
+  mlir::Value VisitBinAssign(const BinaryOperator *e);
+  mlir::Value VisitBinComma(const BinaryOperator *e);
+
+  mlir::Value
+  VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
+  mlir::Value VisitChooseExpr(ChooseExpr *e);
+
+  mlir::Value VisitInitListExpr(InitListExpr *e);
+
+  mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
+    return emitLoadOfLValue(e);
+  }
+
   mlir::Value VisitVAArgExpr(VAArgExpr *e);
+
+  mlir::Value VisitAtomicExpr(AtomicExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitAtomicExpr");
+    return {};
+  }
+
+  mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitPackIndexingExpr");
+    return {};
+  }
 };
 } // namespace
 
-#ifndef NDEBUG
-// Only used in asserts
-static const ComplexType *getComplexType(QualType type) {
-  type = type.getCanonicalType();
-  if (const ComplexType *comp = dyn_cast<ComplexType>(type))
-    return comp;
-  return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+//===----------------------------------------------------------------------===//
+//                                Utilities
+//===----------------------------------------------------------------------===//
+
+/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
+/// load the real and imaginary pieces, returning them as Real/Imag.
+mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
+                                                 SourceLocation loc) {
+  assert(lv.isSimple() && "non-simple complex l-value?");
+  if (lv.getType()->isAtomicType())
+    cgf.cgm.errorNYI(loc, "emitLoadOfLValue with Atomic LV");
+
+  const Address srcAddr = lv.getAddress();
+  return builder.createLoad(cgf.getLoc(loc), srcAddr);
 }
-#endif // NDEBUG
 
-LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e,
-                                               mlir::Value &value) {
-  assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(),
-                                                 e->getRHS()->getType()) &&
-         "Invalid assignment");
+/// EmitStoreOfComplex - Store the specified real/imag parts into the
+/// specified value pointer.
+void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
+                                            LValue lv, bool isInit) {
+  if (lv.getType()->isAtomicType() ||
+      (!isInit && cgf.isLValueSuitableForInlineAtomic(lv))) {
+    cgf.cgm.errorNYI(loc, "StoreOfComplex with Atomic LV");
+    return;
+  }
 
-  // Emit the RHS.  __block variables need the RHS evaluated first.
-  value = Visit(e->getRHS());
+  const Address destAddr = lv.getAddress();
+  builder.createStore(loc, val, destAddr);
+}
 
-  // Compute the address to store into.
-  LValue lhs = cgf.emitLValue(e->getLHS());
+//===----------------------------------------------------------------------===//
+//                            Visitor Methods
+//===----------------------------------------------------------------------===//
 
-  // Store the result value into the LHS lvalue.
-  emitStoreOfComplex(cgf.getLoc(e->getExprLoc()), value, lhs, /*isInit*/ false);
-  return lhs;
+mlir::Value ComplexExprEmitter::VisitExpr(Expr *e) {
+  cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitExpr");
+  return {};
+}
+
+mlir::Value
+ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *il) {
+  auto ty = mlir::cast<cir::ComplexType>(cgf.convertType(il->getType()));
+  mlir::Type elementTy = ty.getElementType();
+  mlir::Location loc = cgf.getLoc(il->getExprLoc());
+
+  mlir::TypedAttr realValueAttr;
+  mlir::TypedAttr imagValueAttr;
+
+  if (mlir::isa<cir::IntType>(elementTy)) {
+    llvm::APInt imagValue = cast<IntegerLiteral>(il->getSubExpr())->getValue();
+    realValueAttr = cir::IntAttr::get(elementTy, 0);
+    imagValueAttr = cir::IntAttr::get(elementTy, imagValue);
+  } else {
+    assert(mlir::isa<cir::FPTypeInterface>(elementTy) &&
+           "Expected complex element type to be floating-point");
+
+    llvm::APFloat imagValue =
+        cast<FloatingLiteral>(il->getSubExpr())->getValue();
+    realValueAttr = cir::FPAttr::get(
+        elementTy, llvm::APFloat::getZero(imagValue.getSemantics()));
+    imagValueAttr = cir::FPAttr::get(elementTy, imagValue);
+  }
+
+  auto complexAttr = cir::ConstComplexAttr::get(realValueAttr, imagValueAttr);
+  return builder.create<cir::ConstantOp>(loc, complexAttr);
+}
+
+mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) {
+  if (e->getCallReturnType(cgf.getContext())->isReferenceType())
+    return emitLoadOfLValue(e);
+  return cgf.emitCallExpr(e).getComplexValue();
+}
+
+mlir::Value ComplexExprEmitter::VisitStmtExpr(const StmtExpr *e) {
+  cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitExpr");
+  return {};
+}
+
+mlir::Value ComplexExprEmitter::emitComplexToComplexCast(mlir::Value val,
+                                                         QualType srcType,
+                                                         QualType destType,
+                                                         SourceLocation loc) {
+  if (srcType == destType)
+    return val;
+
+  // Get the src/dest element type.
+  QualType srcElemTy = srcType->castAs<ComplexType>()->getElementType();
+  QualType destElemTy = destType->castAs<ComplexType>()->getElementType();
+
+  cir::CastKind castOpKind;
+  if (srcElemTy->isFloatingType() && destElemTy->isFloatingType())
+    castOpKind = cir::CastKind::float_complex;
+  else if (srcElemTy->isFloatingType() && destElemTy->isIntegerType())
+    castOpKind = cir::CastKind::float_complex_to_int_complex;
+  else if (srcElemTy->isIntegerType() && destElemTy->isFloatingType())
+    castOpKind = cir::CastKind::int_complex_to_float_complex;
+  else if (srcElemTy->isIntegerType() && destElemTy->isIntegerType())
+    castOpKind = cir::CastKind::int_complex;
+  else
+    llvm_unreachable("unexpected src type or dest type");
+
+  return builder.createCast(cgf.getLoc(loc), castOpKind, val,
+                            cgf.convertType(destType));
+}
+
+mlir::Value ComplexExprEmitter::emitScalarToComplexCast(mlir::Value val,
+                                                        QualType srcType,
+                                                        QualType destType,
+                                                        SourceLocation loc) {
+  cir::CastKind castOpKind;
+  if (srcType->isFloatingType())
+    castOpKind = cir::CastKind::float_to_complex;
+  else if (srcType->isIntegerType())
+    castOpKind = cir::CastKind::int_to_complex;
+  else
+    llvm_unreachable("unexpected src type");
+
+  return builder.createCast(cgf.getLoc(loc), castOpKind, val,
+                            cgf.convertType(destType));
 }
 
 mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
@@ -334,6 +570,14 @@ mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *e) {
   return result;
 }
 
+mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) {
+  QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
+  mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy);
+  if (!promotionTy.isNull())
+    return cgf.emitUnPromotedValue(result, e->getSubExpr()->getType());
+  return result;
+}
+
 mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e,
                                                cir::UnaryOpKind kind,
                                                QualType promotionType) {
@@ -349,258 +593,149 @@ mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e,
   return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()), kind, op);
 }
 
-mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) {
-  QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
-  mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy);
-  if (!promotionTy.isNull())
-    return cgf.emitUnPromotedValue(result, e->getSubExpr()->getType());
-  return result;
+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {
+  mlir::Value op = Visit(e->getSubExpr());
+  return builder.createNot(op);
 }
 
-mlir::Value ComplexExprEmitter::emitConstant(
-    const CIRGenFunction::ConstantEmission &constant, Expr *e) {
-  assert(constant && "not a constant");
-  if (constant.isReference())
-    return emitLoadOfLValue(constant.getReferenceLValue(cgf, e),
-                            e->getExprLoc());
-
-  mlir::TypedAttr valueAttr = constant.getValue();
-  return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr);
-}
+mlir::Value ComplexExprEmitter::emitBinAdd(const BinOpInfo &op) {
+  assert(!cir::MissingFeatures::fastMathFlags());
+  assert(!cir::MissingFeatures::cgFPOptionsRAII());
 
-mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
-                                      ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Aug 31, 2025

@llvm/pr-subscribers-clang

Author: Amr Hesham (AmrDeveloper)

Changes
  • Reorder the CIRGenExprComplex functions to be similar to OCG.
  • Add errors for unhandled visitors.
  • Rename the test file to be similar to complex-mul-div.

Issue: #141365


Patch is 47.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/156241.diff

2 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+519-431)
  • (renamed) clang/test/CIR/CodeGen/complex-plus-minus.cpp ()
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index cbdd525068f5d..36ea5d08c2948 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -6,6 +6,16 @@
 using namespace clang;
 using namespace clang::CIRGen;
 
+#ifndef NDEBUG
+/// Return the complex type that we are meant to emit.
+static const ComplexType *getComplexType(QualType type) {
+  type = type.getCanonicalType();
+  if (const ComplexType *comp = dyn_cast<ComplexType>(type))
+    return comp;
+  return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+}
+#endif // NDEBUG
+
 namespace {
 class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   CIRGenFunction &cgf;
@@ -19,13 +29,6 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   //                               Utilities
   //===--------------------------------------------------------------------===//
 
-  LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val);
-
-  mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy);
-
-  mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant,
-                           Expr *e);
-
   /// Given an expression with complex type that represents a value l-value,
   /// this method emits the address of the l-value, then loads and returns the
   /// result.
@@ -48,20 +51,75 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   mlir::Value emitScalarToComplexCast(mlir::Value value, QualType srcType,
                                       QualType destType, SourceLocation loc);
 
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  mlir::Value Visit(Expr *e) {
+    return StmtVisitor<ComplexExprEmitter, mlir::Value>::Visit(e);
+  }
+
+  mlir::Value VisitStmt(Stmt *s) {
+    cgf.cgm.errorNYI(s->getBeginLoc(), "ComplexExprEmitter VisitStmt");
+    return {};
+  }
+
+  mlir::Value VisitExpr(Expr *e);
+  mlir::Value VisitConstantExpr(ConstantExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitConstantExpr");
+    return {};
+  }
+
+  mlir::Value VisitParenExpr(ParenExpr *pe) { return Visit(pe->getSubExpr()); }
+  mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
+    return Visit(ge->getResultExpr());
+  }
+  mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il);
   mlir::Value
-  VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
-  mlir::Value VisitArraySubscriptExpr(Expr *e);
-  mlir::Value VisitBinAssign(const BinaryOperator *e);
-  mlir::Value VisitBinComma(const BinaryOperator *e);
-  mlir::Value VisitCallExpr(const CallExpr *e);
-  mlir::Value VisitCastExpr(CastExpr *e);
-  mlir::Value VisitChooseExpr(ChooseExpr *e);
-  mlir::Value VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e);
-  mlir::Value VisitDeclRefExpr(DeclRefExpr *e);
-  mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *e);
-  mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e);
-  mlir::Value VisitInitListExpr(InitListExpr *e);
+  VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *pe) {
+    return Visit(pe->getReplacement());
+  }
+  mlir::Value VisitCoawaitExpr(CoawaitExpr *s) {
+    cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoawaitExpr");
+    return {};
+  }
+  mlir::Value VisitCoyieldExpr(CoyieldExpr *s) {
+    cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoyieldExpr");
+    return {};
+  }
+  mlir::Value VisitUnaryCoawait(const UnaryOperator *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitUnaryCoawait");
+    return {};
+  }
+
+  mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant,
+                           Expr *e) {
+    assert(constant && "not a constant");
+    if (constant.isReference())
+      return emitLoadOfLValue(constant.getReferenceLValue(cgf, e),
+                              e->getExprLoc());
+
+    mlir::TypedAttr valueAttr = constant.getValue();
+    return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr);
+  }
 
+  // l-values.
+  mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
+    if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
+      return emitConstant(constant, e);
+    return emitLoadOfLValue(e);
+  }
+  mlir::Value VisitObjCIvarRefExpr(ObjCIvarRefExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitObjCIvarRefExpr");
+    return {};
+  }
+  mlir::Value VisitObjCMessageExpr(ObjCMessageExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitObjCMessageExpr");
+    return {};
+  }
+  mlir::Value VisitArraySubscriptExpr(Expr *e) { return emitLoadOfLValue(e); }
   mlir::Value VisitMemberExpr(MemberExpr *me) {
     if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(me)) {
       cgf.emitIgnoredExpr(me->getBase());
@@ -69,45 +127,99 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
     }
     return emitLoadOfLValue(me);
   }
+  mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitOpaqueValueExpr");
+    return {};
+  }
 
-  mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
-    return emitLoadOfLValue(e);
+  mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitPseudoObjectExpr");
+    return {};
   }
 
-  mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il);
-  mlir::Value VisitParenExpr(ParenExpr *e);
-  mlir::Value
-  VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);
+  mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy);
+  mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e) {
+    // Unlike for scalars, we don't have to worry about function->ptr demotion
+    // here.
+    if (e->changesVolatileQualification())
+      return emitLoadOfLValue(e);
+    return emitCast(e->getCastKind(), e->getSubExpr(), e->getType());
+  }
+  mlir::Value VisitCastExpr(CastExpr *e) {
+    if (const auto *ece = dyn_cast<ExplicitCastExpr>(e)) {
+      // Bind VLAs in the cast type.
+      if (ece->getType()->isVariablyModifiedType()) {
+        cgf.cgm.errorNYI(e->getExprLoc(),
+                         "VisitCastExpr Bind VLAs in the cast type");
+        return {};
+      }
+    }
 
-  mlir::Value VisitPrePostIncDec(const UnaryOperator *e, cir::UnaryOpKind op,
-                                 bool isPre);
+    if (e->changesVolatileQualification())
+      return emitLoadOfLValue(e);
+
+    return emitCast(e->getCastKind(), e->getSubExpr(), e->getType());
+  }
+  mlir::Value VisitCallExpr(const CallExpr *e);
+  mlir::Value VisitStmtExpr(const StmtExpr *e);
 
+  // Operators.
+  mlir::Value VisitPrePostIncDec(const UnaryOperator *e, cir::UnaryOpKind op,
+                                 bool isPre) {
+    LValue lv = cgf.emitLValue(e->getSubExpr());
+    return cgf.emitComplexPrePostIncDec(e, lv, op, isPre);
+  }
   mlir::Value VisitUnaryPostDec(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Dec, false);
   }
-
   mlir::Value VisitUnaryPostInc(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Inc, false);
   }
-
   mlir::Value VisitUnaryPreDec(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Dec, true);
   }
-
   mlir::Value VisitUnaryPreInc(const UnaryOperator *e) {
     return VisitPrePostIncDec(e, cir::UnaryOpKind::Inc, true);
   }
-
-  mlir::Value VisitUnaryDeref(const Expr *e);
+  mlir::Value VisitUnaryDeref(const Expr *e) { return emitLoadOfLValue(e); }
 
   mlir::Value VisitUnaryPlus(const UnaryOperator *e);
-
+  mlir::Value VisitUnaryMinus(const UnaryOperator *e);
   mlir::Value VisitPlusMinus(const UnaryOperator *e, cir::UnaryOpKind kind,
                              QualType promotionType);
-
-  mlir::Value VisitUnaryMinus(const UnaryOperator *e);
-
   mlir::Value VisitUnaryNot(const UnaryOperator *e);
+  // LNot,Real,Imag never return complex.
+  mlir::Value VisitUnaryExtension(const UnaryOperator *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitUnaryExtension");
+    return {};
+  }
+  mlir::Value VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
+    cgf.cgm.errorNYI(dae->getExprLoc(),
+                     "ComplexExprEmitter VisitCXXDefaultArgExpr");
+    return {};
+  }
+  mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
+    cgf.cgm.errorNYI(die->getExprLoc(),
+                     "ComplexExprEmitter VisitCXXDefaultInitExpr");
+    return {};
+  }
+  mlir::Value VisitExprWithCleanups(ExprWithCleanups *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitExprWithCleanups");
+    return {};
+  }
+  mlir::Value VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
+    mlir::Location loc = cgf.getLoc(e->getExprLoc());
+    mlir::Type complexTy = cgf.convertType(e->getType());
+    return builder.getNullValue(complexTy, loc);
+  }
+  mlir::Value VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitImplicitValueInitExpr");
+    return {};
+  }
 
   struct BinOpInfo {
     mlir::Location loc;
@@ -121,14 +233,11 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
                        QualType promotionTy = QualType());
 
   mlir::Value emitPromoted(const Expr *e, QualType promotionTy);
-
   mlir::Value emitPromotedComplexOperand(const Expr *e, QualType promotionTy);
-
   LValue emitCompoundAssignLValue(
       const CompoundAssignOperator *e,
       mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &),
       RValue &value);
-
   mlir::Value emitCompoundAssign(
       const CompoundAssignOperator *e,
       mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &));
@@ -166,52 +275,179 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
   HANDLEBINOP(Div)
 #undef HANDLEBINOP
 
+  mlir::Value VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitCXXRewrittenBinaryOperator");
+    return {};
+  }
+
   // Compound assignments.
   mlir::Value VisitBinAddAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinAdd);
   }
-
   mlir::Value VisitBinSubAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinSub);
   }
-
   mlir::Value VisitBinMulAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinMul);
   }
-
   mlir::Value VisitBinDivAssign(const CompoundAssignOperator *e) {
     return emitCompoundAssign(e, &ComplexExprEmitter::emitBinDiv);
   }
 
+  // GCC rejects rem/and/or/xor for integer complex.
+  // Logical and/or always return int, never complex.
+
+  // No comparisons produce a complex result.
+
+  LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val);
+  mlir::Value VisitBinAssign(const BinaryOperator *e);
+  mlir::Value VisitBinComma(const BinaryOperator *e);
+
+  mlir::Value
+  VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
+  mlir::Value VisitChooseExpr(ChooseExpr *e);
+
+  mlir::Value VisitInitListExpr(InitListExpr *e);
+
+  mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
+    return emitLoadOfLValue(e);
+  }
+
   mlir::Value VisitVAArgExpr(VAArgExpr *e);
+
+  mlir::Value VisitAtomicExpr(AtomicExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitAtomicExpr");
+    return {};
+  }
+
+  mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {
+    cgf.cgm.errorNYI(e->getExprLoc(),
+                     "ComplexExprEmitter VisitPackIndexingExpr");
+    return {};
+  }
 };
 } // namespace
 
-#ifndef NDEBUG
-// Only used in asserts
-static const ComplexType *getComplexType(QualType type) {
-  type = type.getCanonicalType();
-  if (const ComplexType *comp = dyn_cast<ComplexType>(type))
-    return comp;
-  return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+//===----------------------------------------------------------------------===//
+//                                Utilities
+//===----------------------------------------------------------------------===//
+
+/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
+/// load the real and imaginary pieces, returning them as Real/Imag.
+mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
+                                                 SourceLocation loc) {
+  assert(lv.isSimple() && "non-simple complex l-value?");
+  if (lv.getType()->isAtomicType())
+    cgf.cgm.errorNYI(loc, "emitLoadOfLValue with Atomic LV");
+
+  const Address srcAddr = lv.getAddress();
+  return builder.createLoad(cgf.getLoc(loc), srcAddr);
 }
-#endif // NDEBUG
 
-LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e,
-                                               mlir::Value &value) {
-  assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(),
-                                                 e->getRHS()->getType()) &&
-         "Invalid assignment");
+/// EmitStoreOfComplex - Store the specified real/imag parts into the
+/// specified value pointer.
+void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
+                                            LValue lv, bool isInit) {
+  if (lv.getType()->isAtomicType() ||
+      (!isInit && cgf.isLValueSuitableForInlineAtomic(lv))) {
+    cgf.cgm.errorNYI(loc, "StoreOfComplex with Atomic LV");
+    return;
+  }
 
-  // Emit the RHS.  __block variables need the RHS evaluated first.
-  value = Visit(e->getRHS());
+  const Address destAddr = lv.getAddress();
+  builder.createStore(loc, val, destAddr);
+}
 
-  // Compute the address to store into.
-  LValue lhs = cgf.emitLValue(e->getLHS());
+//===----------------------------------------------------------------------===//
+//                            Visitor Methods
+//===----------------------------------------------------------------------===//
 
-  // Store the result value into the LHS lvalue.
-  emitStoreOfComplex(cgf.getLoc(e->getExprLoc()), value, lhs, /*isInit*/ false);
-  return lhs;
+mlir::Value ComplexExprEmitter::VisitExpr(Expr *e) {
+  cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitExpr");
+  return {};
+}
+
+mlir::Value
+ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *il) {
+  auto ty = mlir::cast<cir::ComplexType>(cgf.convertType(il->getType()));
+  mlir::Type elementTy = ty.getElementType();
+  mlir::Location loc = cgf.getLoc(il->getExprLoc());
+
+  mlir::TypedAttr realValueAttr;
+  mlir::TypedAttr imagValueAttr;
+
+  if (mlir::isa<cir::IntType>(elementTy)) {
+    llvm::APInt imagValue = cast<IntegerLiteral>(il->getSubExpr())->getValue();
+    realValueAttr = cir::IntAttr::get(elementTy, 0);
+    imagValueAttr = cir::IntAttr::get(elementTy, imagValue);
+  } else {
+    assert(mlir::isa<cir::FPTypeInterface>(elementTy) &&
+           "Expected complex element type to be floating-point");
+
+    llvm::APFloat imagValue =
+        cast<FloatingLiteral>(il->getSubExpr())->getValue();
+    realValueAttr = cir::FPAttr::get(
+        elementTy, llvm::APFloat::getZero(imagValue.getSemantics()));
+    imagValueAttr = cir::FPAttr::get(elementTy, imagValue);
+  }
+
+  auto complexAttr = cir::ConstComplexAttr::get(realValueAttr, imagValueAttr);
+  return builder.create<cir::ConstantOp>(loc, complexAttr);
+}
+
+mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) {
+  if (e->getCallReturnType(cgf.getContext())->isReferenceType())
+    return emitLoadOfLValue(e);
+  return cgf.emitCallExpr(e).getComplexValue();
+}
+
+mlir::Value ComplexExprEmitter::VisitStmtExpr(const StmtExpr *e) {
+  cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitExpr");
+  return {};
+}
+
+mlir::Value ComplexExprEmitter::emitComplexToComplexCast(mlir::Value val,
+                                                         QualType srcType,
+                                                         QualType destType,
+                                                         SourceLocation loc) {
+  if (srcType == destType)
+    return val;
+
+  // Get the src/dest element type.
+  QualType srcElemTy = srcType->castAs<ComplexType>()->getElementType();
+  QualType destElemTy = destType->castAs<ComplexType>()->getElementType();
+
+  cir::CastKind castOpKind;
+  if (srcElemTy->isFloatingType() && destElemTy->isFloatingType())
+    castOpKind = cir::CastKind::float_complex;
+  else if (srcElemTy->isFloatingType() && destElemTy->isIntegerType())
+    castOpKind = cir::CastKind::float_complex_to_int_complex;
+  else if (srcElemTy->isIntegerType() && destElemTy->isFloatingType())
+    castOpKind = cir::CastKind::int_complex_to_float_complex;
+  else if (srcElemTy->isIntegerType() && destElemTy->isIntegerType())
+    castOpKind = cir::CastKind::int_complex;
+  else
+    llvm_unreachable("unexpected src type or dest type");
+
+  return builder.createCast(cgf.getLoc(loc), castOpKind, val,
+                            cgf.convertType(destType));
+}
+
+mlir::Value ComplexExprEmitter::emitScalarToComplexCast(mlir::Value val,
+                                                        QualType srcType,
+                                                        QualType destType,
+                                                        SourceLocation loc) {
+  cir::CastKind castOpKind;
+  if (srcType->isFloatingType())
+    castOpKind = cir::CastKind::float_to_complex;
+  else if (srcType->isIntegerType())
+    castOpKind = cir::CastKind::int_to_complex;
+  else
+    llvm_unreachable("unexpected src type");
+
+  return builder.createCast(cgf.getLoc(loc), castOpKind, val,
+                            cgf.convertType(destType));
 }
 
 mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
@@ -334,6 +570,14 @@ mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *e) {
   return result;
 }
 
+mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) {
+  QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
+  mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy);
+  if (!promotionTy.isNull())
+    return cgf.emitUnPromotedValue(result, e->getSubExpr()->getType());
+  return result;
+}
+
 mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e,
                                                cir::UnaryOpKind kind,
                                                QualType promotionType) {
@@ -349,258 +593,149 @@ mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e,
   return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()), kind, op);
 }
 
-mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) {
-  QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
-  mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy);
-  if (!promotionTy.isNull())
-    return cgf.emitUnPromotedValue(result, e->getSubExpr()->getType());
-  return result;
+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {
+  mlir::Value op = Visit(e->getSubExpr());
+  return builder.createNot(op);
 }
 
-mlir::Value ComplexExprEmitter::emitConstant(
-    const CIRGenFunction::ConstantEmission &constant, Expr *e) {
-  assert(constant && "not a constant");
-  if (constant.isReference())
-    return emitLoadOfLValue(constant.getReferenceLValue(cgf, e),
-                            e->getExprLoc());
-
-  mlir::TypedAttr valueAttr = constant.getValue();
-  return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr);
-}
+mlir::Value ComplexExprEmitter::emitBinAdd(const BinOpInfo &op) {
+  assert(!cir::MissingFeatures::fastMathFlags());
+  assert(!cir::MissingFeatures::cgFPOptionsRAII());
 
-mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
-                                      ...
[truncated]

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. Thanks for handling this!

Copy link
Contributor

@xlauko xlauko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@AmrDeveloper AmrDeveloper merged commit 3e5f49a into llvm:main Sep 2, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants