Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,19 +377,32 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom(
CharUnits AlignedSize = Size.alignTo(Align);

bool Packed = false;
ArrayRef<mlir::Attribute> UnpackedElems;
ArrayRef<mlir::Attribute> UnpackedElems = Elems;

if (DesiredSize < AlignedSize || DesiredSize.alignTo(Align) != DesiredSize) {
NaturalLayout = false;
Packed = true;
}

llvm::SmallVector<mlir::Attribute, 32> UnpackedElemStorage;

// Fill the init elements for union. This comes from a fundamental
// difference between CIR and LLVM IR. In LLVM IR, the union is simply a
// struct with the largest member. So it is fine to have only one init
// element. But in CIR, the union has the information for all members. So if
// we only pass a single init element, we may be in trouble. We solve the
// problem by appending placeholder attribute for the uninitialized fields.
//
// FIXME: Currently, we can't use InactiveUnionFieldAttr for elems which is
// not the biggest member since we may failed to get the padding bits then.
// However, adding these padding bits will have problems for identifying
// the unions as the same type in the array of unions. See
// https://github.com/llvm/clangir/pull/1007 for example.
llvm::SmallVector<mlir::Attribute, 32> UnionElemsStorage;
if (auto desired = dyn_cast<cir::StructType>(DesiredTy);
desired && desired.isUnion() &&
Elems.size() != desired.getNumElements()) {
llvm::SmallVector<mlir::Attribute, 32> UnionElemsStorage;

Elems.size() != desired.getNumElements() && Elems.size() == 1 &&
DesiredSize == AlignedSize) {
for (auto elemTy : desired.getMembers()) {
if (auto Ty = mlir::dyn_cast<mlir::TypedAttr>(Elems.back());
Ty && Ty.getType() == elemTy)
Expand All @@ -400,13 +413,6 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom(
}

UnpackedElems = UnionElemsStorage;
} else
UnpackedElems = Elems;

llvm::SmallVector<mlir::Attribute, 32> UnpackedElemStorage;
if (DesiredSize < AlignedSize || DesiredSize.alignTo(Align) != DesiredSize) {
NaturalLayout = false;
Packed = true;
} else if (DesiredSize > AlignedSize) {
// The natural layout would be too small. Add padding to fix it. (This
// is ignored if we choose a packed layout.)
Expand Down
35 changes: 35 additions & 0 deletions clang/test/CIR/Lowering/union-in-struct-init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM
typedef struct {
union {
int a;
long b;
};
} S;

S s = { .a = 1 };

// LLVM: @s = global { { i32, [4 x i8] } } { { i32, [4 x i8] } { i32 1, [4 x i8] zeroinitializer } }

typedef struct {
union {
int a;
long b;
};
} S2;

S2 s2 = { .b = 1 };

// LLVM: @s2 = global %struct.S2 { %union.anon.1 { i64 1 } }

typedef struct {
union {
int a;
long b;
long double c;
};
} S3;

S3 s3 = { .a = 1 };

// LLVM: @s3 = global { { i32, [12 x i8] } } { { i32, [12 x i8] } { i32 1, [12 x i8] zeroinitializer } }