Author: Erich Keane Date: 2026-04-02T06:00:36-07:00 New Revision: 58b719660c8d4137f5c7f280731a324f142e75e7
URL: https://github.com/llvm/llvm-project/commit/58b719660c8d4137f5c7f280731a324f142e75e7 DIFF: https://github.com/llvm/llvm-project/commit/58b719660c8d4137f5c7f280731a324f142e75e7.diff LOG: [CIR] Implement union aggregate init (#190057) This ends up being a pretty trivial amount of work, since we just have to forward the initialization for a union on to the 'active' field, which this patch does. Added: clang/test/CIR/CodeGen/union-agg-init.c clang/test/CIR/CodeGen/union-agg-init.cpp Modified: clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 0ba77f63b18a8..8e63a64b3e664 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -1090,8 +1090,35 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr( LValue destLV = cgf.makeAddrLValue(dest.getAddress(), e->getType()); if (record->isUnion()) { - cgf.cgm.errorNYI(e->getSourceRange(), - "visitCXXParenListOrInitListExpr union type"); + // Only initialize one field of a union. The field itself is + // specified by the initializer list. + if (!initializedFieldInUnion) { + // Empty union; we have nothing to do. + + // Make sure that it's really an empty and not a failure of + // semantic analysis. + assert(llvm::all_of(record->fields(), + [](const FieldDecl *f) { + return f->isUnnamedBitField() || + f->isAnonymousStructOrUnion(); + }) && + "Only unnamed bitfields or anonymous class allowed"); + return; + } + + // FIXME: volatility + FieldDecl *initedField = initializedFieldInUnion; + + LValue fieldLV = cgf.emitLValueForFieldInitialization( + destLV, initedField, initedField->getName()); + + if (numInitElements) { + // Store the initializer into the field + emitInitializationToLValue(args[0], fieldLV); + } else { + // Default-initialize to null. + emitNullInitializationToLValue(loc, fieldLV); + } return; } diff --git a/clang/test/CIR/CodeGen/union-agg-init.c b/clang/test/CIR/CodeGen/union-agg-init.c new file mode 100644 index 0000000000000..135020ea609a4 --- /dev/null +++ b/clang/test/CIR/CodeGen/union-agg-init.c @@ -0,0 +1,65 @@ +// 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,LLVMCIR --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=LLVM,OGCG --input-file=%t.ll %s + +typedef union vec3 { + struct { double x, y, z; }; + double component[3]; +} vec3; + +// OGCG: @__const.ret_outer.o = {{.*}}{ { i32, [4 x i8] }, i32, [4 x i8] } { { i32, [4 x i8] } zeroinitializer, i32 1, [4 x i8] zeroinitializer } + +// In C mode, this does do zero padding. +vec3 ret_vec3() { + // CIR-LABEL: ret_vec3 + // CIR: %[[RET_ALLOCA:.*]] = cir.alloca !rec_vec3, !cir.ptr<!rec_vec3>, ["__retval"] + // CIR: %[[GET_ANON:.*]] = cir.get_member %[[RET_ALLOCA]][0] {name = ""} + // CIR: %[[GET_X:.*]] = cir.get_member %[[GET_ANON]][0] {name = "x"} + // CIR: %[[FIVE:.*]] = cir.const #cir.fp<5.{{.*}}> : !cir.double + // CIR: cir.store{{.*}} %[[FIVE]], %[[GET_X]] + // CIR: %[[GET_Y:.*]] = cir.get_member %[[GET_ANON]][1] {name = "y"} + // CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.{{.*}}> : !cir.double + // CIR: cir.store{{.*}} %[[ZERO]], %[[GET_Y]] + // CIR: %[[GET_Z:.*]] = cir.get_member %[[GET_ANON]][2] {name = "z"} + // CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.{{.*}}> : !cir.double + // CIR: cir.store{{.*}} %[[ZERO]], %[[GET_Z]] + + // LLVM-LABEL: ret_vec3 + // OGCG-SAME: ptr{{.*}}sret(%union.vec3){{.*}}%[[RET_ALLOCA:.*]]) + // LLVMCIR: %[[RET_ALLOCA:.*]] = alloca %union.vec3 + // LLVM: %[[GET_X:.*]] = getelementptr {{.*}}, ptr %[[RET_ALLOCA]], i32 0, i32 0 + // LLVM: store double 5{{.*}}, ptr %[[GET_X]] + // LLVM: %[[GET_Y:.*]] = getelementptr {{.*}}, ptr %[[RET_ALLOCA]], i32 0, i32 1 + // LLVM: store double 0{{.*}}, ptr %[[GET_Y]] + // LLVM: %[[GET_Z:.*]] = getelementptr {{.*}}, ptr %[[RET_ALLOCA]], i32 0, i32 2 + // LLVM: store double 0{{.*}}, ptr %[[GET_Z]] + return (vec3) {{ .x = 5.0 }}; +} + +union needs_padding { + int a; + long long b; +}; +struct outer { + union needs_padding np; + int x; +}; + +struct outer ret_outer() { + struct outer o = {{}, 1}; + return o; + + // CIR-LABEL: ret_outer + // CIR: %[[RET_ALLOCA:.*]] = cir.alloca !rec_outer, !cir.ptr<!rec_outer>, ["__retval"] + // CIR: %[[BITCAST:.*]] = cir.cast bitcast %0 : !cir.ptr<!rec_outer> -> !cir.ptr<!{{.*}}> + // CIR: %[[RECORD:.*]] = cir.const #cir.const_record<{#cir.zero : !{{.*}}, #cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 4>}> + // CIR: cir.store {{.*}}%[[RECORD]], %[[BITCAST]] + + // LLVM-LABEL: ret_outer + // LLVM: %[[RET_ALLOCA:.*]] = alloca %struct.outer + // LLVMCIR: store { { i32, [4 x i8] }, i32, [4 x i8] } { { i32, [4 x i8] } zeroinitializer, i32 1, [4 x i8] zeroinitializer }, ptr %[[RET_ALLOCA]] + // OGCG: call void @llvm.memcpy{{.*}}(ptr{{.*}}%[[RET_ALLOCA]], ptr {{.*}}@__const.ret_outer.o, i64 16, i1 false) +} diff --git a/clang/test/CIR/CodeGen/union-agg-init.cpp b/clang/test/CIR/CodeGen/union-agg-init.cpp new file mode 100644 index 0000000000000..e83a9ea017772 --- /dev/null +++ b/clang/test/CIR/CodeGen/union-agg-init.cpp @@ -0,0 +1,53 @@ +// 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,LLVMCIR --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=LLVM,OGCG --input-file=%t.ll %s + +typedef union vec3 { + struct { double x, y, z; }; + double component[3]; +} vec3; + +// In C++ mode, this doesn't do zero padding. +extern "C" vec3 ret_vec3() { + // CIR-LABEL: ret_vec3 + // CIR: %[[RET_ALLOCA:.*]] = cir.alloca !rec_vec3, !cir.ptr<!rec_vec3>, ["__retval"] + // CIR: %[[GET_ANON:.*]] = cir.get_member %[[RET_ALLOCA]][0] {name = ""} + // CIR: %[[GET_X:.*]] = cir.get_member %[[GET_ANON]][0] {name = "x"} + // CIR: %[[FIVE:.*]] = cir.const #cir.fp<5.{{.*}}> : !cir.double + // CIR: cir.store{{.*}} %[[FIVE]], %[[GET_X]] + // CIR: %[[GET_Y:.*]] = cir.get_member %[[GET_ANON]][1] {name = "y"} + // CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.{{.*}}> : !cir.double + // CIR: cir.store{{.*}} %[[ZERO]], %[[GET_Y]] + // CIR: %[[GET_Z:.*]] = cir.get_member %[[GET_ANON]][2] {name = "z"} + // CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.{{.*}}> : !cir.double + // CIR: cir.store{{.*}} %[[ZERO]], %[[GET_Z]] + + // LLVM-LABEL: ret_vec3 + // OGCG-SAME: ptr{{.*}}sret(%union.vec3){{.*}}%[[RET_ALLOCA:.*]]) + // LLVMCIR: %[[RET_ALLOCA:.*]] = alloca %union.vec3 + // LLVM: %[[GET_X:.*]] = getelementptr {{.*}}, ptr %[[RET_ALLOCA]], i32 0, i32 0 + // LLVM: store double 5{{.*}}, ptr %[[GET_X]] + // LLVM: %[[GET_Y:.*]] = getelementptr {{.*}}, ptr %[[RET_ALLOCA]], i32 0, i32 1 + // LLVM: store double 0{{.*}}, ptr %[[GET_Y]] + // LLVM: %[[GET_Z:.*]] = getelementptr {{.*}}, ptr %[[RET_ALLOCA]], i32 0, i32 2 + // LLVM: store double 0{{.*}}, ptr %[[GET_Z]] + return (vec3) {{ .x = 5.0 }}; +} + +typedef union Trivial { + int a; +} Trivial; + +extern "C" Trivial ret_trivial() { return {}; } + // CIR-LABEL: ret_trivial + // CIR: %[[RET_ALLOCA:.*]] = cir.alloca !rec_Trivial, !cir.ptr<!rec_Trivial>, ["__retval"] + // CIR: %[[GET_A:.*]] = cir.get_member %[[RET_ALLOCA]][0] {name = "a"} + // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> + // CIR: cir.store{{.*}} %[[ZERO]], %[[GET_A]] + + // LLVM-LABEL: ret_trivial + // LLVM: %[[RET_ALLOCA:.*]] = alloca %union.Trivial + // LLVM: store i32 0, ptr %[[RET_ALLOCA]] _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
