Author: Amr Hesham Date: 2025-06-21T10:30:59+02:00 New Revision: 4a4582dd788b8bb7dab919fe4b76807ad9c7ed48
URL: https://github.com/llvm/llvm-project/commit/4a4582dd788b8bb7dab919fe4b76807ad9c7ed48 DIFF: https://github.com/llvm/llvm-project/commit/4a4582dd788b8bb7dab919fe4b76807ad9c7ed48.diff LOG: [CIR] Upstream BinAssign for ComplexType (#144868) This change adds support for the BinAssign op and LValueToRValue for ComplexType https://github.com/llvm/llvm-project/issues/141365 Added: Modified: clang/lib/CIR/CodeGen/CIRGenExpr.cpp clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h clang/lib/CIR/CodeGen/CIRGenValue.h clang/test/CIR/CodeGen/complex.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 4f2046ad26d72..c31754dc11d69 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -997,10 +997,9 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { } case cir::TEK_Complex: { - assert(!cir::MissingFeatures::complexType()); - cgm.errorNYI(e->getSourceRange(), "complex l-values"); - return {}; + return emitComplexAssignmentLValue(e); } + case cir::TEK_Aggregate: cgm.errorNYI(e->getSourceRange(), "aggregate lvalues"); return {}; diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 12e8e27948cf7..eaa199abc1657 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -19,6 +19,13 @@ 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. @@ -27,18 +34,18 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { } mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc); - /// Store the specified real/imag parts into the /// specified value pointer. void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv, bool isInit); + mlir::Value VisitBinAssign(const BinaryOperator *e); mlir::Value VisitCallExpr(const CallExpr *e); - mlir::Value VisitInitListExpr(InitListExpr *e); - + mlir::Value VisitDeclRefExpr(DeclRefExpr *e); + mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e); + mlir::Value VisitInitListExpr(const InitListExpr *e); mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il); }; - } // namespace static const ComplexType *getComplexType(QualType type) { @@ -48,6 +55,46 @@ static const ComplexType *getComplexType(QualType type) { return cast<ComplexType>(cast<AtomicType>(type)->getValueType()); } +LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e, + mlir::Value &value) { + assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(), + e->getRHS()->getType()) && + "Invalid assignment"); + + // Emit the RHS. __block variables need the RHS evaluated first. + value = Visit(e->getRHS()); + + // Compute the address to store into. + LValue lhs = cgf.emitLValue(e->getLHS()); + + // Store the result value into the LHS lvalue. + emitStoreOfComplex(cgf.getLoc(e->getExprLoc()), value, lhs, /*isInit*/ false); + return lhs; +} + +mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, + QualType destTy) { + switch (ck) { + case CK_LValueToRValue: + return Visit(op); + default: + cgf.cgm.errorNYI("ComplexType Cast"); + break; + } + return {}; +} + +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::emitLoadOfLValue(LValue lv, SourceLocation loc) { assert(lv.isSimple() && "non-simple complex l-value?"); @@ -70,6 +117,22 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, builder.createStore(loc, val, destAddr); } +mlir::Value ComplexExprEmitter::VisitBinAssign(const BinaryOperator *e) { + mlir::Value value; + LValue lv = emitBinAssignLValue(e, value); + + // The result of an assignment in C is the assigned r-value. + if (!cgf.getLangOpts().CPlusPlus) + return value; + + // If the lvalue is non-volatile, return the computed value of the + // assignment. + if (!lv.isVolatile()) + return value; + + return emitLoadOfLValue(lv, e->getExprLoc()); +} + mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) { if (e->getCallReturnType(cgf.getContext())->isReferenceType()) return emitLoadOfLValue(e); @@ -77,7 +140,21 @@ mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) { return cgf.emitCallExpr(e).getValue(); } -mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *e) { +mlir::Value ComplexExprEmitter::VisitDeclRefExpr(DeclRefExpr *e) { + if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e)) + return emitConstant(constant, e); + return emitLoadOfLValue(e); +} + +mlir::Value ComplexExprEmitter::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 ComplexExprEmitter::VisitInitListExpr(const InitListExpr *e) { mlir::Location loc = cgf.getLoc(e->getExprLoc()); if (e->getNumInits() == 2) { mlir::Value real = cgf.emitScalarExpr(e->getInit(0)); @@ -127,6 +204,17 @@ ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *il) { return builder.create<cir::ConstantOp>(loc, complexAttr); } +LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) { + assert(e->getOpcode() == BO_Assign && "Expected assign op"); + + mlir::Value value; // ignored + LValue lvalue = ComplexExprEmitter(*this).emitBinAssignLValue(e, value); + if (getLangOpts().OpenMP) + cgm.errorNYI("emitComplexAssignmentLValue OpenMP"); + + return lvalue; +} + mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) { assert(e && getComplexType(e->getType()) && "Invalid complex expression to emit"); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 6c490a72b2e93..82aa7ec9cb220 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -870,6 +870,8 @@ class CIRGenFunction : public CIRGenTypeCache { /// returning the result. mlir::Value emitComplexExpr(const Expr *e); + LValue emitComplexAssignmentLValue(const BinaryOperator *e); + void emitCompoundStmt(const clang::CompoundStmt &s); void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s); diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index 7180d92f8c314..a5a457ddafa9c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenValue.h +++ b/clang/lib/CIR/CodeGen/CIRGenValue.h @@ -182,9 +182,7 @@ class LValue { bool isSimple() const { return lvType == Simple; } bool isVectorElt() const { return lvType == VectorElt; } bool isBitField() const { return lvType == BitField; } - - // TODO: Add support for volatile - bool isVolatile() const { return false; } + bool isVolatile() const { return quals.hasVolatile(); } unsigned getVRQualifiers() const { return quals.getCVRQualifiers() & ~clang::Qualifiers::Const; diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 721db235b37de..cfeed345b4f11 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -230,3 +230,29 @@ void foo14() { // OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1 // OGCG: store i32 0, ptr %[[C_REAL_PTR]], align 4 // OGCG: store i32 2, ptr %[[C_IMAG_PTR]], align 4 + +void foo15() { + int _Complex a; + int _Complex b = a; +} + +// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"] +// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: cir.store{{.*}} %[[TMP_A]], %[[COMPLEX_B]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> + +// LLVM: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[COMPLEX_A]], align 4 +// LLVM: store { i32, i32 } %[[TMP_A]], ptr %[[COMPLEX_B]], align 4 + +// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 0 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1 +// OGCG: store i32 %[[A_REAL]], ptr %[[B_REAL_PTR]], align 4 +// OGCG: store i32 %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 4 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits