================
@@ -26,32 +32,161 @@ struct WrapEmpty {
int s;
};
WrapEmpty w;
-// CIR: !rec_OuterWithEmpty = !cir.union<"OuterWithEmpty" {!rec_Empty,
!s32i}>
-// CIR: !rec_WrapEmpty = !cir.struct<"WrapEmpty" {!rec_OuterWithEmpty,
!s32i}>
-// CIR: cir.global external @w = #cir.zero : !rec_WrapEmpty {alignment =
4 : i64}
+// CIR-DAG: !rec_OuterWithEmpty = !cir.union<"OuterWithEmpty" {!rec_Empty,
!s32i}>
+// CIR-DAG: !rec_WrapEmpty = !cir.struct<"WrapEmpty" {!rec_OuterWithEmpty,
!s32i}>
+// CIR-DAG: cir.global external @w = #cir.zero : !rec_WrapEmpty {alignment = 4
: i64}
// LLVM-DAG: %struct.WrapEmpty = type { %union.OuterWithEmpty, i32 }
// LLVM-DAG: %union.OuterWithEmpty = type { i32 }
-// LLVM: @w = global %struct.WrapEmpty zeroinitializer, align 4
-// OGCG-DAG: %struct.WrapEmpty = type { %union.OuterWithEmpty, i32 }
-// OGCG-DAG: %union.OuterWithEmpty = type { i32 }
-// OGCG: @w = global %struct.WrapEmpty zeroinitializer, align 4
+// LLVM-DAG: @w = global %struct.WrapEmpty zeroinitializer, align 4
+
+// A union whose only member is itself storage-less. This one HAS a storage
+// type, so it is the storage member's reported size that must be right.
+union OnlyEmpty {
+ Empty e;
+};
+// CIR-DAG: !rec_OnlyEmpty = !cir.union<"OnlyEmpty" {!rec_Empty}>
+// LLVM-DAG: %union.OnlyEmpty = type { %union.Empty }
+
+// A storage-less union still occupies its own bytes inside a record, so the
+// fields after it must not be pushed past them.
+struct Leading {
+ Empty e;
+ int x;
+};
+
+struct Trailing {
+ int x;
+ Empty e;
+};
+
+struct Middle {
+ int a;
+ Empty e;
+ int b;
+};
+
+struct LeadingOver {
+ EmptyAligned e;
+ int x;
+};
+
+struct LeadingZeroBitfield {
+ OnlyZeroBitfield e;
+ int x;
+};
+
+OnlyEmpty onlyEmpty;
+Leading lead;
+Trailing trail;
+Middle mid;
+LeadingOver leadOver;
+LeadingZeroBitfield leadZero;
+Leading leadArr[2];
+
+// CIR-DAG: !rec_Leading = !cir.struct<"Leading" {!rec_Empty, !s32i}>
+// CIR-DAG: !rec_Trailing = !cir.struct<"Trailing" {!s32i, !rec_Empty}>
+// CIR-DAG: !rec_Middle = !cir.struct<"Middle" {!s32i, !rec_Empty, !s32i}>
+// CIR-DAG: !rec_LeadingOver = !cir.struct<"LeadingOver" padded
{!rec_EmptyAligned, !s32i, !cir.array<!u8i x 12>}>
+// CIR-DAG: !rec_LeadingZeroBitfield = !cir.struct<"LeadingZeroBitfield"
{!rec_OnlyZeroBitfield, !s32i}>
+
+// CIR keeps the union's own named type as the record's field and leaves the
+// bytes after it to the LLVM struct layout. Classic covers the union together
+// with those bytes in one char array.
+// LLVMCIR-DAG: %struct.Leading = type { %union.Empty, i32 }
+// LLVMCIR-DAG: %struct.Trailing = type { i32, %union.Empty }
+// LLVMCIR-DAG: %struct.Middle = type { i32, %union.Empty, i32 }
+// LLVMCIR-DAG: %struct.LeadingZeroBitfield = type { %union.OnlyZeroBitfield,
i32 }
+// LLVMCIR-DAG: %struct.LeadingOver = type { %union.EmptyAligned, i32, [12 x
i8] }
+// OGCG-DAG: %struct.Leading = type { [4 x i8], i32 }
+// OGCG-DAG: %struct.Trailing = type { i32, [4 x i8] }
+// OGCG-DAG: %struct.Middle = type { i32, [4 x i8], i32 }
+// OGCG-DAG: %struct.LeadingZeroBitfield = type { [4 x i8], i32 }
+// OGCG-DAG: %struct.LeadingOver = type { [16 x i8], i32, [12 x i8] }
+// LLVM-DAG: @lead = global %struct.Leading zeroinitializer, align 4
+// LLVM-DAG: @leadOver = global %struct.LeadingOver zeroinitializer, align
16
void useEmpty() {
Empty e;
}
// CIR: cir.func {{.*}}@_Z8useEmptyv()
// CIR: cir.alloca "e" align(1) : !cir.ptr<!rec_Empty>
// LLVM: define {{.*}} void @_Z8useEmptyv()
-// LLVM: alloca %union.Empty, i64 1, align 1
-// OGCG: define {{.*}} void @_Z8useEmptyv()
-// OGCG: alloca %union.Empty, align 1
+// LLVMCIR: alloca %union.Empty, i64 1, align 1
+// OGCG: alloca %union.Empty, align 1
void useEmptyAligned() {
EmptyAligned e;
}
// CIR: cir.func {{.*}}@_Z15useEmptyAlignedv()
// CIR: cir.alloca "e" align(16) : !cir.ptr<!rec_EmptyAligned>
// LLVM: define {{.*}} void @_Z15useEmptyAlignedv()
-// LLVM: alloca %union.EmptyAligned, i64 1, align 16
-// OGCG: define {{.*}} void @_Z15useEmptyAlignedv()
-// OGCG: alloca %union.EmptyAligned, align 16
+// LLVMCIR: alloca %union.EmptyAligned, i64 1, align 16
+// OGCG: alloca %union.EmptyAligned, align 16
+
+// Classic never refers to this union's type from inside LeadingZeroBitfield,
so
+// a variable of the type is what puts it in both modules.
+void useZeroBitfield() {
+ OnlyZeroBitfield e;
+}
+// CIR: cir.func {{.*}}@_Z15useZeroBitfieldv()
+// CIR: cir.alloca "e" align(1) : !cir.ptr<!rec_OnlyZeroBitfield>
+// LLVM: define {{.*}} void @_Z15useZeroBitfieldv()
+// LLVMCIR: alloca %union.OnlyZeroBitfield, i64 1, align 1
----------------
adams381 wrote:
You are right. I've made that change and it is much cleaner now.
https://github.com/llvm/llvm-project/pull/213591
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits