Skip to content

Commit 47fbf70

Browse files
Add requested example, test, and address review comments
1 parent 38b98a5 commit 47fbf70

File tree

4 files changed

+108
-31
lines changed

4 files changed

+108
-31
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1684,8 +1684,12 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> {
16841684
base record, a size of the storage, a size the bit field, an offset
16851685
of the bit field and a sign. Returns a value being stored.
16861686

1687-
A unit attribute `volatile` can be used to indicate a volatile load of the
1687+
A unit attribute `volatile` can be used to indicate a volatile store of the
16881688
bitfield.
1689+
```mlir
1690+
cir.set_bitfield(#bfi, %0 : !cir.ptr<!u32i>, %1 : !s32i) {is_volatile}
1691+
-> !s32i
1692+
```
16891693

16901694
Example.
16911695
Suppose we have a struct with multiple bitfields stored in

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst,
224224
return;
225225
}
226226

227-
assert(dst.isBitField() && "NIY LValue type");
227+
assert(dst.isBitField() && "Unknown LValue type");
228228
emitStoreThroughBitfieldLValue(src, dst);
229229
return;
230230

@@ -332,6 +332,7 @@ mlir::Value CIRGenFunction::emitStoreThroughBitfieldLValue(RValue src,
332332
mlir::Type resLTy = convertTypeForMem(dst.getType());
333333
Address ptr = dst.getBitFieldAddress();
334334

335+
assert(!cir::MissingFeatures::armComputeVolatileBitfields());
335336
const bool useVolatile = false;
336337

337338
mlir::Value dstAddr = dst.getAddress().getPointer();
@@ -1077,11 +1078,10 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) {
10771078
LValue lv = emitLValue(e->getLHS());
10781079

10791080
SourceLocRAIIObject loc{*this, getLoc(e->getSourceRange())};
1080-
if (lv.isBitField()) {
1081+
if (lv.isBitField())
10811082
emitStoreThroughBitfieldLValue(rv, lv);
1082-
} else {
1083+
else
10831084
emitStoreThroughLValue(rv, lv);
1084-
}
10851085

10861086
if (getLangOpts().OpenMP) {
10871087
cgm.errorNYI(e->getSourceRange(), "openmp");

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2385,6 +2385,24 @@ mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite(
23852385
return mlir::success();
23862386
}
23872387

2388+
mlir::IntegerType computeBitfieldIntType(mlir::Type storageType,
2389+
mlir::MLIRContext *context,
2390+
unsigned &storageSize) {
2391+
return TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)
2392+
.Case<cir::ArrayType>([&](cir::ArrayType atTy) {
2393+
storageSize = atTy.getSize() * 8;
2394+
return mlir::IntegerType::get(context, storageSize);
2395+
})
2396+
.Case<cir::IntType>([&](cir::IntType intTy) {
2397+
storageSize = intTy.getWidth();
2398+
return mlir::IntegerType::get(context, storageSize);
2399+
})
2400+
.Default([](mlir::Type) -> mlir::IntegerType {
2401+
llvm_unreachable(
2402+
"Either ArrayType or IntType expected for bitfields storage");
2403+
});
2404+
}
2405+
23882406
mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite(
23892407
cir::SetBitfieldOp op, OpAdaptor adaptor,
23902408
mlir::ConversionPatternRewriter &rewriter) const {
@@ -2400,19 +2418,7 @@ mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite(
24002418
unsigned storageSize = 0;
24012419

24022420
mlir::IntegerType intType =
2403-
TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)
2404-
.Case<cir::ArrayType>([&](cir::ArrayType atTy) {
2405-
storageSize = atTy.getSize() * 8;
2406-
return mlir::IntegerType::get(context, storageSize);
2407-
})
2408-
.Case<cir::IntType>([&](cir::IntType intTy) {
2409-
storageSize = intTy.getWidth();
2410-
return mlir::IntegerType::get(context, storageSize);
2411-
})
2412-
.Default([](mlir::Type) -> mlir::IntegerType {
2413-
llvm_unreachable(
2414-
"Either ArrayType or IntType expected for bitfields storage");
2415-
});
2421+
computeBitfieldIntType(storageType, context, storageSize);
24162422

24172423
mlir::Value srcVal = createIntCast(rewriter, adaptor.getSrc(), intType);
24182424
unsigned srcWidth = storageSize;
@@ -2476,19 +2482,7 @@ mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
24762482
unsigned storageSize = 0;
24772483

24782484
mlir::IntegerType intType =
2479-
TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)
2480-
.Case<cir::ArrayType>([&](cir::ArrayType atTy) {
2481-
storageSize = atTy.getSize() * 8;
2482-
return mlir::IntegerType::get(context, storageSize);
2483-
})
2484-
.Case<cir::IntType>([&](cir::IntType intTy) {
2485-
storageSize = intTy.getWidth();
2486-
return mlir::IntegerType::get(context, storageSize);
2487-
})
2488-
.Default([](mlir::Type) -> mlir::IntegerType {
2489-
llvm_unreachable(
2490-
"Either ArrayType or IntType expected for bitfields storage");
2491-
});
2485+
computeBitfieldIntType(storageType, context, storageSize);
24922486

24932487
mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(
24942488
op.getLoc(), intType, adaptor.getAddr(), 0, op.getIsVolatile());

clang/test/CIR/CodeGen/bitfields.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,82 @@ void store_field() {
160160
// OGCG: [[TMP3:%.*]] = and i16 [[TMP2]], -32768
161161
// OGCG: [[TMP4:%.*]] = or i16 [[TMP3]], 3
162162
// OGCG: store i16 [[TMP4]], ptr [[TMP1]], align 4
163+
164+
void store_bitfield_to_bitfield() {
165+
S s;
166+
s.a = s.c;
167+
}
168+
169+
// CIR: cir.func {{.*@store_bitfield_to_bitfield}}
170+
// CIR: [[TMP0:%.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s"] {alignment = 4 : i64}
171+
// CIR: [[TMP1:%.*]] = cir.get_member [[TMP0]][0] {name = "c"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i>
172+
// CIR: [[TMP2:%.*]] = cir.get_bitfield(#bfi_c, [[TMP1]] : !cir.ptr<!u64i>) -> !s32i
173+
// CIR: [[TMP3:%.*]] = cir.get_member [[TMP0]][0] {name = "a"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i>
174+
// CIR: [[TMP4:%.*]] = cir.set_bitfield(#bfi_a, [[TMP3]] : !cir.ptr<!u64i>, [[TMP2]] : !s32i) -> !s32i
175+
176+
// LLVM: define dso_local void @store_bitfield_to_bitfield()
177+
// LLVM: [[TMP0:%.*]] = alloca %struct.S, i64 1, align 4
178+
// LLVM: [[TMP1:%.*]] = getelementptr %struct.S, ptr [[TMP0]], i32 0, i32 0
179+
// LLVM: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
180+
// LLVM: [[TMP3:%.*]] = shl i64 [[TMP2]], 15
181+
// LLVM: [[TMP4:%.*]] = ashr i64 [[TMP3]], 47
182+
// LLVM: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32
183+
// LLVM: [[TMP6:%.*]] = getelementptr %struct.S, ptr [[TMP0]], i32 0, i32 0
184+
// LLVM: [[TMP7:%.*]] = zext i32 [[TMP5]] to i64
185+
// LLVM: [[TMP8:%.*]] = load i64, ptr [[TMP6]], align 8
186+
// LLVM: [[TMP9:%.*]] = and i64 [[TMP7]], 15
187+
// LLVM: [[TMP10:%.*]] = and i64 [[TMP8]], -16
188+
// LLVM: [[TMP11:%.*]] = or i64 [[TMP10]], [[TMP9]]
189+
// LLVM: store i64 [[TMP11]], ptr [[TMP6]], align 8
190+
// LLVM: [[TMP12:%.*]] = shl i64 [[TMP9]], 60
191+
// LLVM: [[TMP13:%.*]] = ashr i64 [[TMP12]], 60
192+
// LLVM: [[TMP15:%.*]] = trunc i64 [[TMP13]] to i32
193+
194+
// OGCG: define dso_local void @store_bitfield_to_bitfield()
195+
// OGCG: [[TMP0:%.*]] = alloca %struct.S, align 4
196+
// OGCG: [[TMP1:%.*]] = load i64, ptr [[TMP0]], align 4
197+
// OGCG: [[TMP2:%.*]] = shl i64 [[TMP1]], 15
198+
// OGCG: [[TMP3:%.*]] = ashr i64 [[TMP2]], 47
199+
// OGCG: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i32
200+
// OGCG: [[TMP5:%.*]] = zext i32 [[TMP4]] to i64
201+
// OGCG: [[TMP6:%.*]] = load i64, ptr [[TMP0]], align 4
202+
// OGCG: [[TMP7:%.*]] = and i64 [[TMP5]], 15
203+
// OGCG: [[TMP8:%.*]] = and i64 [[TMP6]], -16
204+
// OGCG: [[TMP9:%.*]] = or i64 [[TMP8]], [[TMP7]]
205+
// OGCG: store i64 [[TMP9]], ptr [[TMP0]], align 4
206+
// OGCG: [[TMP10:%.*]] = shl i64 %bf.value, 60
207+
// OGCG: [[TMP11:%.*]] = ashr i64 [[TMP10]], 60
208+
// OGCG: [[TMP12:%.*]] = trunc i64 [[TMP11]] to i32
209+
210+
typedef struct {
211+
int a : 30;
212+
int volatile b : 8;
213+
int c;
214+
} V;
215+
216+
void set_volatile(V* v) {
217+
v->b = 3;
218+
}
219+
//CIR: cir.func dso_local @set_volatile
220+
//CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_V>, !cir.ptr<!cir.ptr<!rec_V>>, ["v", init] {alignment = 8 : i64}
221+
//CIR: [[TMP1:%.*]] = cir.const #cir.int<3> : !s32i
222+
//CIR: [[TMP2:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_V>>, !cir.ptr<!rec_V>
223+
//CIR: [[TMP3:%.*]] = cir.get_member [[TMP2]][0] {name = "b"} : !cir.ptr<!rec_V> -> !cir.ptr<!u64i>
224+
//CIR: [[TMP4:%.*]] = cir.set_bitfield(#bfi_b, [[TMP3]] : !cir.ptr<!u64i>, [[TMP1]] : !s32i) {is_volatile} -> !s32i
225+
226+
// LLVM: define dso_local void @set_volatile
227+
// LLVM: [[TMP0:%.*]] = alloca ptr, i64 1, align 8
228+
// LLVM: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
229+
// LLVM: [[TMP2:%.*]] = getelementptr %struct.V, ptr [[TMP1]], i32 0, i32 0
230+
// LLVM: [[TMP3:%.*]] = load volatile i64, ptr [[TMP2]], align 8
231+
// LLVM: [[TMP4:%.*]] = and i64 [[TMP3]], -1095216660481
232+
// LLVM: [[TMP5:%.*]] = or i64 [[TMP4]], 12884901888
233+
// LLVM: store volatile i64 [[TMP5]], ptr [[TMP2]], align 8
234+
235+
// OGCG: define dso_local void @set_volatile
236+
// OGCG: [[TMP0:%.*]] = alloca ptr, align 8
237+
// OGCG: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
238+
// OGCG: [[TMP2:%.*]] = load volatile i64, ptr [[TMP1]], align 4
239+
// OGCG: [[TMP3:%.*]] = and i64 [[TMP2]], -1095216660481
240+
// OGCG: [[TMP4:%.*]] = or i64 [[TMP3]], 12884901888
241+
// OGCG: store volatile i64 [[TMP4]], ptr [[TMP1]], align 4

0 commit comments

Comments
 (0)