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

Reply via email to