From dbb59df126bda29434ffbfdd679e6b948c07b4f2 Mon Sep 17 00:00:00 2001 From: Morris Hafner Date: Tue, 14 Oct 2025 22:11:06 +0700 Subject: [PATCH 1/2] [CIR] Add Aggregate Expression LValue Visitors This patch implements visitors for most of the aggregate expressions yielding lvalues. --- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 47 +++++--- clang/lib/CIR/CodeGen/CIRGenValue.h | 2 + clang/test/CIR/CodeGen/agg-expr-lvalue.c | 111 ++++++++++++++++++ clang/test/CIR/CodeGen/compound_literal.cpp | 27 +++++ 4 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 clang/test/CIR/CodeGen/agg-expr-lvalue.c diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 901b937e4e3e7..e59bec4106bc5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -170,23 +170,11 @@ class AggExprEmitter : public StmtVisitor { void VisitConstantExpr(ConstantExpr *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr"); } - void VisitMemberExpr(MemberExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitMemberExpr"); - } - void VisitUnaryDeref(UnaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryDeref"); - } - void VisitStringLiteral(StringLiteral *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitStringLiteral"); - } - void VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitCompoundLiteralExpr"); - } - void VisitPredefinedExpr(const PredefinedExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitPredefinedExpr"); - } + void VisitMemberExpr(MemberExpr *e) { emitAggLoadOfLValue(e); } + void VisitUnaryDeref(UnaryOperator *e) { emitAggLoadOfLValue(e); } + void VisitStringLiteral(StringLiteral *e) { emitAggLoadOfLValue(e); } + void VisitCompoundLiteralExpr(CompoundLiteralExpr *e); + void VisitPredefinedExpr(const PredefinedExpr *e) { emitAggLoadOfLValue(e); } void VisitBinaryOperator(const BinaryOperator *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinaryOperator"); @@ -325,6 +313,31 @@ void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) { emitFinalDestCopy(e->getType(), lv); } +void AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { + if (dest.isPotentiallyAliased() && e->getType().isPODType(cgf.getContext())) { + // For a POD type, just emit a load of the lvalue + a copy, because our + // compound literal might alias the destination. + emitAggLoadOfLValue(e); + return; + } + + AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType()); + + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + bool destruct = + !cgf.getLangOpts().CPlusPlus && !slot.isExternallyDestructed(); + if (destruct) + slot.setExternallyDestructed(); + + cgf.emitAggExpr(e->getInitializer(), slot); + + if (destruct) + if ([[maybe_unused]] QualType::DestructionKind dtorKind = + e->getType().isDestructedType()) + cgf.cgm.errorNYI(e->getSourceRange(), "compound literal with destructor"); +} + void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType arrayQTy, Expr *e, ArrayRef args, Expr *arrayFiller) { diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index 25b6ecb503a6e..c4ff351afa871 100644 --- a/clang/lib/CIR/CodeGen/CIRGenValue.h +++ b/clang/lib/CIR/CodeGen/CIRGenValue.h @@ -390,6 +390,8 @@ class AggValueSlot { IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); } + IsAliased_t isPotentiallyAliased() const { return IsAliased_t(aliasedFlag); } + RValue asRValue() const { if (isIgnored()) return RValue::getIgnored(); diff --git a/clang/test/CIR/CodeGen/agg-expr-lvalue.c b/clang/test/CIR/CodeGen/agg-expr-lvalue.c new file mode 100644 index 0000000000000..c826f8fa829d0 --- /dev/null +++ b/clang/test/CIR/CodeGen/agg-expr-lvalue.c @@ -0,0 +1,111 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct Point { + int x, y; +}; + +struct Line { + struct Point start; + struct Point end; +}; + +// AggExprEmitter::VisitMemberExpr +void test_member_in_array(void) { + struct Line line = {{1, 2}, {3, 4}}; + struct Point arr[1] = {line.start}; +} + +// CIR-LABEL: cir.func{{.*}} @test_member_in_array +// CIR: %[[LINE:.*]] = cir.alloca !rec_Line{{.*}}, ["line", init] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array{{.*}}, ["arr", init] +// CIR: %[[MEMBER:.*]] = cir.get_member %[[LINE]][0] {name = "start"} +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_member_in_array +// LLVM: %[[LINE:.*]] = alloca %struct.Line +// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point] +// LLVM: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LINE]]{{.*}}i32 0, i32 0 +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_member_in_array +// OGCG: %[[LINE:.*]] = alloca %struct.Line +// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point] +// OGCG: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LINE]]{{.*}}i32 0, i32 0 +// OGCG: call void @llvm.memcpy + +// AggExprEmitter::VisitMemberExpr +void test_member_arrow_in_array(void) { + struct Line *line_ptr; + struct Point arr[1] = {line_ptr->start}; +} + +// CIR-LABEL: cir.func{{.*}} @test_member_arrow_in_array +// CIR: %[[PTR:.*]] = cir.alloca !cir.ptr{{.*}}, ["line_ptr"] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array{{.*}}, ["arr", init] +// CIR: %[[LOADED:.*]] = cir.load{{.*}}%[[PTR]] +// CIR: %[[MEMBER:.*]] = cir.get_member %[[LOADED]][0] {name = "start"} +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_member_arrow_in_array +// LLVM: %[[PTR:.*]] = alloca ptr +// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point] +// LLVM: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// LLVM: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LOADED]]{{.*}}i32 0, i32 0 +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_member_arrow_in_array +// OGCG: %[[PTR:.*]] = alloca ptr +// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point] +// OGCG: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// OGCG: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LOADED]]{{.*}}i32 0, i32 0 +// OGCG: call void @llvm.memcpy + +// AggExprEmitter::VisitUnaryDeref +void test_deref_in_array(void) { + struct Point *ptr; + struct Point arr[1] = {*ptr}; +} + +// CIR-LABEL: cir.func{{.*}} @test_deref_in_array +// CIR: %[[PTR:.*]] = cir.alloca !cir.ptr{{.*}}, ["ptr"] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array{{.*}}, ["arr", init] +// CIR: %[[LOADED:.*]] = cir.load{{.*}}%[[PTR]] +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_deref_in_array +// LLVM: %[[PTR:.*]] = alloca ptr +// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point] +// LLVM: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_deref_in_array +// OGCG: %[[PTR:.*]] = alloca ptr +// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point] +// OGCG: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// OGCG: call void @llvm.memcpy + +// AggExprEmitter::VisitStringLiteral +void test_string_array_in_array(void) { + char matrix[2][6] = {"hello", "world"}; +} + +// CIR-LABEL: cir.func{{.*}} @test_string_array_in_array +// CIR: cir.alloca !cir.array x 2>, {{.*}}, ["matrix", init] +// CIR: cir.get_global +// CIR: cir.copy +// CIR: cir.get_global +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_string_array_in_array +// LLVM: alloca [2 x [6 x i8]] +// LLVM: call void @llvm.memcpy +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_string_array_in_array +// OGCG: alloca [2 x [6 x i8]] +// OGCG: call void @llvm.memcpy{{.*}}@__const.test_string_array_in_array diff --git a/clang/test/CIR/CodeGen/compound_literal.cpp b/clang/test/CIR/CodeGen/compound_literal.cpp index a92af95c62a1b..30a1dc03c449b 100644 --- a/clang/test/CIR/CodeGen/compound_literal.cpp +++ b/clang/test/CIR/CodeGen/compound_literal.cpp @@ -97,3 +97,30 @@ void foo3() { // OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[CL_ADDR]], align 16 // OGCG: store <4 x i32> %[[TMP]], ptr %[[A_ADDR]], align 16 +struct Point { + int x, y; +}; + +void foo4() { + Point p = (Point){5, 10}; +} + +// CIR-LABEL: @_Z4foo4v +// CIR: %[[P:.*]] = cir.alloca !rec_Point, !cir.ptr, ["p", init] +// CIR: %[[P_X:.*]] = cir.get_member %[[P]][0] {name = "x"} +// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store{{.*}} %[[FIVE]], %[[P_X]] +// CIR: %[[P_Y:.*]] = cir.get_member %[[P]][1] {name = "y"} +// CIR: %[[TEN:.*]] = cir.const #cir.int<10> : !s32i +// CIR: cir.store{{.*}} %[[TEN]], %[[P_Y]] + +// LLVM-LABEL: @_Z4foo4v +// LLVM: %[[P:.*]] = alloca %struct.Point +// LLVM: %[[P_X:.*]] = getelementptr %struct.Point, ptr %[[P]], i32 0, i32 0 +// LLVM: store i32 5, ptr %[[P_X]] +// LLVM: %[[P_Y:.*]] = getelementptr %struct.Point, ptr %[[P]], i32 0, i32 1 +// LLVM: store i32 10, ptr %[[P_Y]] + +// OGCG-LABEL: @_Z4foo4v +// OGCG: %[[P:.*]] = alloca %struct.Point +// OGCG: call void @llvm.memcpy{{.*}}(ptr{{.*}} %[[P]], ptr{{.*}} @__const._Z4foo4v.p From 6767d2b94995e50c9cabda6c085c91dfc8200df9 Mon Sep 17 00:00:00 2001 From: Morris Hafner Date: Mon, 20 Oct 2025 21:55:36 +0700 Subject: [PATCH 2/2] remove VisitPredefinedExpr --- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index e59bec4106bc5..ddee000056c7e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -174,7 +174,10 @@ class AggExprEmitter : public StmtVisitor { void VisitUnaryDeref(UnaryOperator *e) { emitAggLoadOfLValue(e); } void VisitStringLiteral(StringLiteral *e) { emitAggLoadOfLValue(e); } void VisitCompoundLiteralExpr(CompoundLiteralExpr *e); - void VisitPredefinedExpr(const PredefinedExpr *e) { emitAggLoadOfLValue(e); } + void VisitPredefinedExpr(const PredefinedExpr *e) { + cgf.cgm.errorNYI(e->getSourceRange(), + "AggExprEmitter: VisitPredefinedExpr"); + } void VisitBinaryOperator(const BinaryOperator *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinaryOperator");