Skip to content

Commit 6ef0921

Browse files
authored
[CIR] support union without field in C++ (#1703)
In [libstdc++ std::variant implementation](https://github.com/gcc-mirror/gcc/blob/b0419798447ae25de2f58d1a695db6dadb5d8547/libstdc%2B%2B-v3/include/std/variant#L387-L394), union without any fields is used. According to current CodeGen logic, append 1 byte padding for this kind of union. Handle this union in `mlir::RecordType` for getLargestMember` return nullptr also. The original LLVM IR ```llvm %union.EmptyUnion = type { i8 } @__const._Z2f0v.e = private unnamed_addr constant %union.EmptyUnion undef, align 1 define dso_local void @_Z2f0v() #0 { entry: %e = alloca %union.EmptyUnion, align 1 call void @llvm.memcpy.p0.p0.i64(ptr align 1 %e, ptr align 1 @__const._Z2f0v.e, i64 1, i1 false) ret void } ``` The CIR lowered LLVM IR ```llvm %union.EmptyUnion = type { i8 } define dso_local void @_Z2f0v() #0 { %1 = alloca %union.EmptyUnion, i64 1, align 1 store %union.EmptyUnion undef, ptr %1, align 1 ret void } ``` The major different is original use global const and memcpy, the current use store. The difference between the two is not related to this revision.
1 parent 4820d60 commit 6ef0921

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ void CIRRecordLowering::lowerUnion() {
364364
}
365365
// If we have no storage type just pad to the appropriate size and return.
366366
if (!StorageType)
367-
llvm_unreachable("no-storage union NYI");
367+
return appendPaddingBytes(LayoutSize);
368368
// If our storage size was bigger than our required size (can happen in the
369369
// case of packed bitfields on Itanium) then just use an I8 array.
370370
if (LayoutSize < getSize(StorageType))

clang/lib/CIR/Dialect/IR/CIRTypes.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,9 @@ RecordType::computeUnionSize(const mlir::DataLayout &dataLayout) const {
453453
unsigned recordSize = 0;
454454
llvm::Align recordAlignment{1};
455455

456-
auto largestMember = getLargestMember(dataLayout);
457-
recordSize = dataLayout.getTypeSize(largestMember);
456+
Type largestMember = getLargestMember(dataLayout);
457+
if (largestMember)
458+
recordSize = dataLayout.getTypeSize(largestMember);
458459

459460
// If the union is padded, add the padding to the size.
460461
if (getPadded()) {
@@ -517,7 +518,10 @@ RecordType::computeStructAlignment(const mlir::DataLayout &dataLayout) const {
517518

518519
uint64_t
519520
RecordType::computeUnionAlignment(const mlir::DataLayout &dataLayout) const {
520-
auto largestMember = getLargestMember(dataLayout);
521+
Type largestMember = getLargestMember(dataLayout);
522+
// use 1 byte alignment for empty union
523+
if (!largestMember)
524+
return 1;
521525
return dataLayout.getTypeABIAlignment(largestMember);
522526
}
523527

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM
5+
6+
union EmptyUnion {
7+
EmptyUnion() = default;
8+
};
9+
10+
void f0() {
11+
EmptyUnion e;
12+
};
13+
14+
// CIR: !rec_EmptyUnion = !cir.record<union "EmptyUnion" padded {!u8i}>
15+
// CIR: cir.func dso_local @_Z2f0v()
16+
// CIR: %0 = cir.alloca !rec_EmptyUnion, !cir.ptr<!rec_EmptyUnion>, ["e"] {alignment = 1 : i64}
17+
// CIR: cir.return
18+
19+
// LLVM: %union.EmptyUnion = type { i8 }
20+
// LLVM: define dso_local void @_Z2f0v()
21+
// LLVM: %1 = alloca %union.EmptyUnion, i64 1, align 1
22+
// LLVM: ret void

0 commit comments

Comments
 (0)