[clang] 58b7196 - [CIR] Implement union aggregate init (#190057)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 2 06:00:41 PDT 2026
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]]
More information about the cfe-commits
mailing list