https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/148943
>From a83dcd3f747751cf1da861405572fbe94ff6c8f9 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Tue, 15 Jul 2025 21:47:30 +0200 Subject: [PATCH 1/2] [CIR] Upstream CompoundLiteralExpr for Scalar --- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 62 +++++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 4 ++ clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 2 + clang/lib/CIR/CodeGen/CIRGenFunction.h | 6 ++ clang/test/CIR/CodeGen/compound_literal.cpp | 42 ++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 clang/test/CIR/CodeGen/compound_literal.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 51da48d330f55..11b66f4dda049 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1053,6 +1053,68 @@ LValue CIRGenFunction::emitMemberExpr(const MemberExpr *e) { llvm_unreachable("Unhandled member declaration!"); } +/// Evaluate an expression into a given memory location. +void CIRGenFunction::emitAnyExprToMem(const Expr *e, Address location, + Qualifiers quals, bool isInit) { + // FIXME: This function should take an LValue as an argument. + switch (getEvaluationKind(e->getType())) { + case cir::TEK_Complex: { + RValue rv = RValue::get(emitComplexExpr(e)); + LValue lv = makeAddrLValue(location, e->getType()); + emitStoreThroughLValue(rv, lv); + return; + } + + case cir::TEK_Aggregate: { + emitAggExpr(e, AggValueSlot::forAddr(location, quals, + AggValueSlot::IsDestructed_t(isInit), + AggValueSlot::IsAliased_t(!isInit), + AggValueSlot::MayOverlap)); + return; + } + + case cir::TEK_Scalar: { + RValue rv = RValue::get(emitScalarExpr(e)); + LValue lv = makeAddrLValue(location, e->getType()); + emitStoreThroughLValue(rv, lv); + return; + } + } + + llvm_unreachable("bad evaluation kind"); +} + +LValue CIRGenFunction::emitCompoundLiteralLValue(const CompoundLiteralExpr *e) { + if (e->isFileScope()) { + cgm.errorNYI(e->getSourceRange(), "emitCompoundLiteralLValue: FileScope"); + return {}; + } + + if (e->getType()->isVariablyModifiedType()) { + cgm.errorNYI(e->getSourceRange(), + "emitCompoundLiteralLValue: VariablyModifiedType"); + return {}; + } + + Address declPtr = createMemTemp(e->getType(), getLoc(e->getSourceRange()), + ".compoundliteral"); + const Expr *initExpr = e->getInitializer(); + LValue result = makeAddrLValue(declPtr, e->getType(), AlignmentSource::Decl); + + emitAnyExprToMem(initExpr, declPtr, e->getType().getQualifiers(), + /*Init*/ true); + + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + if (!getLangOpts().CPlusPlus && e->getType().isDestructedType()) { + cgm.errorNYI(e->getSourceRange(), + "emitCompoundLiteralLValue: non C++ DestructedType"); + return {}; + } + + return result; +} + LValue CIRGenFunction::emitCallExprLValue(const CallExpr *e) { RValue rv = emitCallExpr(e); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 9e13b4c83e3a8..23112be6bf3e7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -233,6 +233,10 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { mlir::Value VisitMemberExpr(MemberExpr *e); + mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { + return emitLoadOfLValue(e); + } + mlir::Value VisitInitListExpr(InitListExpr *e); mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index e532b9d855843..7e1a44ce602d4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -698,6 +698,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { return emitStringLiteralLValue(cast<StringLiteral>(e)); case Expr::MemberExprClass: return emitMemberExpr(cast<MemberExpr>(e)); + case Expr::CompoundLiteralExprClass: + return emitCompoundLiteralLValue(cast<CompoundLiteralExpr>(e)); case Expr::BinaryOperatorClass: return emitBinaryOperatorLValue(cast<BinaryOperator>(e)); case Expr::CompoundAssignOperatorClass: { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 9541f4f0725eb..75f9e65719d82 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -757,6 +757,11 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitAnyExpr(const clang::Expr *e, AggValueSlot aggSlot = AggValueSlot::ignored()); + /// Emits the code necessary to evaluate an arbitrary expression into the + /// given memory location. + void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, + bool isInitializer); + /// Similarly to emitAnyExpr(), however, the result will always be accessible /// even if no aggregate location is provided. RValue emitAnyExprToTemp(const clang::Expr *e); @@ -828,6 +833,7 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitCheckedArgForAssume(const Expr *e); LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e); + LValue emitCompoundLiteralLValue(const CompoundLiteralExpr *e); void emitConstructorBody(FunctionArgList &args); void emitDestructorBody(FunctionArgList &args); diff --git a/clang/test/CIR/CodeGen/compound_literal.cpp b/clang/test/CIR/CodeGen/compound_literal.cpp new file mode 100644 index 0000000000000..a3f15b9437885 --- /dev/null +++ b/clang/test/CIR/CodeGen/compound_literal.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +int foo() { + int e = (int){1}; + return e; +} + +// CIR: %[[RET:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init] +// CIR: %[[COMPOUND:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, [".compoundliteral", init] +// CIR: %[[VALUE:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[VALUE]], %[[COMPOUND]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[COMPOUND]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store{{.*}} %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP_2:.*]] = cir.load{{.*}} %[[INIT]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[TMP_2]], %[[RET]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP_3:.*]] = cir.load %[[RET]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[TMP_3]] : !s32i + +// LLVM: %[[RET:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[INIT:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[COMPOUND:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 1, ptr %[[COMPOUND]], align 4 +// LLVM: %[[TMP:.*]] = load i32, ptr %[[COMPOUND]], align 4 +// LLVM: store i32 %[[TMP]], ptr %[[INIT]], align 4 +// LLVM: %[[TMP_2:.*]] = load i32, ptr %[[INIT]], align 4 +// LLVM: store i32 %[[TMP_2]], ptr %[[RET]], align 4 +// LLVM: %[[TMP_3:.*]] = load i32, ptr %[[RET]], align 4 +// LLVM: ret i32 %[[TMP_3]] + +// OGCG: %[[INIT:.*]] = alloca i32, align 4 +// OGCG: %[[COMPOUND:.*]] = alloca i32, align 4 +// OGCG: store i32 1, ptr %[[COMPOUND]], align 4 +// OGCG: %[[TMP:.*]] = load i32, ptr %[[COMPOUND]], align 4 +// OGCG: store i32 %[[TMP]], ptr %[[INIT]], align 4 +// OGCG: %[[TMP_2:.*]] = load i32, ptr %[[INIT]], align 4 +// OGCG: ret i32 %[[TMP_2]] >From e8d6879bd8dd88e2fea36a19306e77cceb8422f6 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Thu, 17 Jul 2025 20:20:58 +0200 Subject: [PATCH 2/2] Address code review comments --- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 3 +- clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 14 +++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 + clang/test/CIR/CodeGen/compound_literal.cpp | 57 +++++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 11b66f4dda049..ff0096555fbce 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1059,9 +1059,8 @@ void CIRGenFunction::emitAnyExprToMem(const Expr *e, Address location, // FIXME: This function should take an LValue as an argument. switch (getEvaluationKind(e->getType())) { case cir::TEK_Complex: { - RValue rv = RValue::get(emitComplexExpr(e)); LValue lv = makeAddrLValue(location, e->getType()); - emitStoreThroughLValue(rv, lv); + emitComplexExprIntoLValue(e, lv, isInit); return; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 0a22771378ff1..81cb7f9cf77cb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -52,6 +52,11 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *e); mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e); mlir::Value VisitInitListExpr(const InitListExpr *e); + + mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { + return emitLoadOfLValue(e); + } + mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il); mlir::Value VisitParenExpr(ParenExpr *e); mlir::Value @@ -467,6 +472,15 @@ mlir::Value CIRGenFunction::emitComplexPrePostIncDec(const UnaryOperator *e, return isPre ? incVal : inVal; } +void CIRGenFunction::emitComplexExprIntoLValue(const Expr *e, LValue dest, + bool isInit) { + assert(e && getComplexType(e->getType()) && + "Invalid complex expression to emit"); + ComplexExprEmitter emitter(*this); + mlir::Value value = emitter.Visit(const_cast<Expr *>(e)); + emitter.emitStoreOfComplex(getLoc(e->getExprLoc()), value, dest, isInit); +} + mlir::Value CIRGenFunction::emitLoadOfComplex(LValue src, SourceLocation loc) { return ComplexExprEmitter(*this).emitLoadOfLValue(src, loc); } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 75f9e65719d82..e2fa03d03b81e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -936,6 +936,8 @@ class CIRGenFunction : public CIRGenTypeCache { /// returning the result. mlir::Value emitComplexExpr(const Expr *e); + void emitComplexExprIntoLValue(const Expr *e, LValue dest, bool isInit); + mlir::Value emitComplexPrePostIncDec(const UnaryOperator *e, LValue lv, bool isInc, bool isPre); diff --git a/clang/test/CIR/CodeGen/compound_literal.cpp b/clang/test/CIR/CodeGen/compound_literal.cpp index a3f15b9437885..a92af95c62a1b 100644 --- a/clang/test/CIR/CodeGen/compound_literal.cpp +++ b/clang/test/CIR/CodeGen/compound_literal.cpp @@ -40,3 +40,60 @@ int foo() { // OGCG: store i32 %[[TMP]], ptr %[[INIT]], align 4 // OGCG: %[[TMP_2:.*]] = load i32, ptr %[[INIT]], align 4 // OGCG: ret i32 %[[TMP_2]] + +void foo2() { + int _Complex a = (int _Complex) { 1, 2}; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a", init] +// CIR: %[[CL_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, [".compoundliteral"] +// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex<!s32i> +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[CL_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> +// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[CL_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: cir.store{{.*}} %[[TMP]], %[[A_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[CL_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: store { i32, i32 } { i32 1, i32 2 }, ptr %[[CL_ADDR]], align 4 +// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[CL_ADDR]], align 4 +// LLVM: store { i32, i32 } %[[TMP]], ptr %[[A_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[CL_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[CL_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[CL_ADDR]], i32 0, i32 0 +// OGCG: %[[CL_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[CL_ADDR]], i32 0, i32 1 +// OGCG: store i32 1, ptr %[[CL_REAL_PTR]], align 4 +// OGCG: store i32 2, ptr %[[CL_IMAG_PTR]], align 4 +// OGCG: %[[CL_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[CL_ADDR]], i32 0, i32 0 +// OGCG: %[[CL_REAL:.*]] = load i32, ptr %[[CL_REAL_PTR]], align 4 +// OGCG: %[[CL_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[CL_ADDR]], i32 0, i32 1 +// OGCG: %[[CL_IMAG:.*]] = load i32, ptr %[[CL_IMAG_PTR]], align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: store i32 %[[CL_REAL]], ptr %[[A_REAL_PTR]], align 4 +// OGCG: store i32 %[[CL_IMAG]], ptr %[[A_IMAG_PTR]], align 4 + +void foo3() { + typedef int vi4 __attribute__((vector_size(16))); + auto a = (vi4){10, 20, 30, 40}; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[CL_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, [".compoundliteral", init] +// CIR: %[[VEC:.*]] = cir.const #cir.const_vector<[#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.int<30> : !s32i, #cir.int<40> : !s32i]> : !cir.vector<4 x !s32i> +// CIR: cir.store{{.*}} %[[VEC]], %[[CL_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[CL_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: cir.store{{.*}} %[[TMP]], %[[A_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[CL_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 10, i32 20, i32 30, i32 40>, ptr %[[CL_ADDR]], align 16 +// LLVM: %[[TMP:.*]] = load <4 x i32>, ptr %[[CL_ADDR]], align 16 +// LLVM: store <4 x i32> %[[TMP]], ptr %[[A_ADDR]], align 16 + +// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[CL_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 10, i32 20, i32 30, i32 40>, ptr %[[CL_ADDR]], align 16 +// OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[CL_ADDR]], align 16 +// OGCG: store <4 x i32> %[[TMP]], ptr %[[A_ADDR]], align 16 + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits