Skip to content

Commit 100576e

Browse files
andykaylorLukacma
authored andcommitted
[CIR] Handle overlapping values in constant init expressions (llvm#164508)
This adds handling for generating constant initializers in the case where a value we are emitting overlaps with a previous constant, such as can happen when initializing a structure with bitfields.
1 parent ceaf9ed commit 100576e

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,23 @@ bool ConstantAggregateBuilder::add(mlir::TypedAttr typedAttr, CharUnits offset,
179179
}
180180

181181
// Uncommon case: constant overlaps what we've already created.
182-
cgm.errorNYI("overlapping constants");
183-
return false;
182+
std::optional<size_t> firstElemToReplace = splitAt(offset);
183+
if (!firstElemToReplace)
184+
return false;
185+
186+
CharUnits cSize = getSize(typedAttr);
187+
std::optional<size_t> lastElemToReplace = splitAt(offset + cSize);
188+
if (!lastElemToReplace)
189+
return false;
190+
191+
assert((firstElemToReplace == lastElemToReplace || allowOverwrite) &&
192+
"unexpectedly overwriting field");
193+
194+
Element newElt(typedAttr, offset);
195+
replace(elements, *firstElemToReplace, *lastElemToReplace, {newElt});
196+
size = std::max(size, offset + cSize);
197+
naturalLayout = false;
198+
return true;
184199
}
185200

186201
bool ConstantAggregateBuilder::addBits(llvm::APInt bits, uint64_t offsetInBits,

clang/test/CIR/CodeGen/struct-init.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
66
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
77

8+
struct BitfieldStruct {
9+
unsigned int a:4;
10+
unsigned int b:14;
11+
unsigned int c:14;
12+
};
13+
14+
BitfieldStruct overlapping_init = { 3, 2, 1 };
15+
16+
// This is unintuitive. The bitfields are initialized using a struct of constants
17+
// that maps to the bitfields but splits the value into bytes.
18+
19+
// CIR: cir.global external @overlapping_init = #cir.const_record<{#cir.int<35> : !u8i, #cir.int<0> : !u8i, #cir.int<4> : !u8i, #cir.int<0> : !u8i}> : !rec_anon_struct
20+
// LLVM: @overlapping_init = global { i8, i8, i8, i8 } { i8 35, i8 0, i8 4, i8 0 }
21+
// OGCG: @overlapping_init = global { i8, i8, i8, i8 } { i8 35, i8 0, i8 4, i8 0 }
22+
823
struct S {
924
int a, b, c;
1025
};

0 commit comments

Comments
 (0)