Skip to content

Commit 577ee97

Browse files
[CIR] Fix access to bitfields inside a union (#154398)
This PR fixes the access to bitfields inside a union. Previously, we were using a `getMemberOp` to access the field, but because it is a union, `getMemberOp` would always use index `0`. For example, given: ```c typedef union { int x; int y : 4; int z : 8; } demo; ``` ```mlir !rec_demo = !cir.record<union "demo" {!s32i, !u8i, !u8i}> ``` In the case of: ```c d.y = 2; ``` It would generate: ```mlir cir.get_member %0[0] {name = "y"} : !cir.ptr<!rec_demo> -> !cir.ptr<!s32i> ``` with a return type of `!s32i`, when it should be `!u8i`. the get_member verifier would detect that the return type does not match the `y` member. To fix this, we now use `bitcast` to get the start of the union.
1 parent 7f20c6c commit 577ee97

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,10 @@ Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base,
369369
unsigned index) {
370370
mlir::Location loc = getLoc(field->getLocation());
371371
cir::PointerType fieldPtr = cir::PointerType::get(fieldType);
372-
cir::GetMemberOp sea = getBuilder().createGetMember(
373-
loc, fieldPtr, base.getPointer(), field->getName(), index);
374372
auto rec = cast<cir::RecordType>(base.getAddress().getElementType());
373+
cir::GetMemberOp sea = getBuilder().createGetMember(
374+
loc, fieldPtr, base.getPointer(), field->getName(),
375+
rec.isUnion() ? field->getFieldIndex() : index);
375376
CharUnits offset = CharUnits::fromQuantity(
376377
rec.getElementOffset(cgm.getDataLayout().layout, index));
377378
return Address(sea, base.getAlignment().alignmentAtOffset(offset));

clang/test/CIR/CodeGen/bitfield-union.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,44 @@ typedef union {
2828

2929
demo d;
3030
zero_bit z;
31+
32+
void f() {
33+
demo d;
34+
d.x = 1;
35+
d.y = 2;
36+
d.z = 0;
37+
}
38+
39+
// CIR: #bfi_y = #cir.bitfield_info<name = "y", storage_type = !u8i, size = 4, offset = 0, is_signed = true>
40+
// CIR: #bfi_z = #cir.bitfield_info<name = "z", storage_type = !u8i, size = 8, offset = 0, is_signed = true>
41+
42+
// CIR: cir.func no_proto dso_local @f
43+
// CIR: [[ALLOC:%.*]] = cir.alloca !rec_demo, !cir.ptr<!rec_demo>, ["d"] {alignment = 4 : i64}
44+
// CIR: [[ONE:%.*]] = cir.const #cir.int<1> : !s32i
45+
// CIR: [[X:%.*]] = cir.get_member [[ALLOC]][0] {name = "x"} : !cir.ptr<!rec_demo> -> !cir.ptr<!s32i>
46+
// CIR: cir.store align(4) [[ONE]], [[X]] : !s32i, !cir.ptr<!s32i>
47+
// CIR: [[TWO:%.*]] = cir.const #cir.int<2> : !s32i
48+
// CIR: [[Y:%.*]] = cir.get_member [[ALLOC]][1] {name = "y"} : !cir.ptr<!rec_demo> -> !cir.ptr<!u8i>
49+
// CIR: [[SET:%.*]] = cir.set_bitfield align(4) (#bfi_y, [[Y]] : !cir.ptr<!u8i>, [[TWO]] : !s32i) -> !s32i
50+
// CIR: [[ZERO:%.*]] = cir.const #cir.int<0> : !s32i
51+
// CIR: [[Z:%.*]] = cir.get_member [[ALLOC]][2] {name = "z"} : !cir.ptr<!rec_demo> -> !cir.ptr<!u8i>
52+
// CIR: [[SET2:%.*]] = cir.set_bitfield align(4) (#bfi_z, [[Z]] : !cir.ptr<!u8i>, [[ZERO]] : !s32i) -> !s32i
53+
// CIR: cir.return
54+
55+
// LLVM: define dso_local void @f
56+
// LLVM: [[ALLOC:%.*]] = alloca %union.demo, i64 1, align 4
57+
// LLVM: store i32 1, ptr [[ALLOC]], align 4
58+
// LLVM: [[BFLOAD:%.*]] = load i8, ptr [[ALLOC]], align 4
59+
// LLVM: [[CLEAR:%.*]] = and i8 [[BFLOAD]], -16
60+
// LLVM: [[SET:%.*]] = or i8 [[CLEAR]], 2
61+
// LLVM: store i8 [[SET]], ptr [[ALLOC]], align 4
62+
// LLVM: store i8 0, ptr [[ALLOC]], align 4
63+
64+
// OGCG: define dso_local void @f
65+
// OGCG: [[ALLOC:%.*]] = alloca %union.demo, align 4
66+
// OGCG: store i32 1, ptr [[ALLOC]], align 4
67+
// OGCG: [[BFLOAD:%.*]] = load i8, ptr [[ALLOC]], align 4
68+
// OGCG: [[CLEAR:%.*]] = and i8 [[BFLOAD]], -16
69+
// OGCG: [[SET:%.*]] = or i8 [[CLEAR]], 2
70+
// OGCG: store i8 [[SET]], ptr [[ALLOC]], align 4
71+
// OGCG: store i8 0, ptr [[ALLOC]], align 4

0 commit comments

Comments
 (0)