Skip to content

Commit 5f3b2c3

Browse files
authored
[CIR][CodeGen] fixes access to globals with bitfields (#1244)
This PR adds a bitcast when we rewrite globals type. Previously we just set a new type and it worked. But recently I started to test ClangIR with CSmith in order to find some run time bugs and faced with the next problem. ``` typedef struct { int x : 15; uint8_t y; } S; S g = { -12, 254}; int main() { printf("%d\n", g.y); return 0; } ``` The output for this program is ... 127 but not 254! The reason is that first global var is created with the type of struct `S`, then `get_member` operation is generated with index `1` and then after, the type of the global is rewritten - I assume because of the anon struct created on the right side in the initialization. But the `get_member` operation still wants to access to the field at index `1` and get a wrong byte. If we change the `y` type to `int` we will fail on the verification stage. But in the example above it's a run time error! This is why I suggest to add a bitcast once we have to rewrite the global type.
1 parent 445f2a5 commit 5f3b2c3

File tree

2 files changed

+25
-0
lines changed

2 files changed

+25
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,13 @@ void CIRGenModule::replaceGlobal(cir::GlobalOp Old, cir::GlobalOp New) {
814814
auto UseOpResultValue = GGO.getAddr();
815815
UseOpResultValue.setType(
816816
cir::PointerType::get(&getMLIRContext(), NewTy));
817+
818+
mlir::OpBuilder::InsertionGuard guard(builder);
819+
builder.setInsertionPointAfter(UserOp);
820+
mlir::Type ptrTy = builder.getPointerTo(OldTy);
821+
mlir::Value cast =
822+
builder.createBitcast(GGO->getLoc(), UseOpResultValue, ptrTy);
823+
UseOpResultValue.replaceAllUsesExcept(cast, {cast.getDefiningOp()});
817824
}
818825
}
819826
}

clang/test/CIR/CodeGen/bitfields.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ typedef struct {
5454
} U;
5555

5656
// CHECK: !ty_D = !cir.struct<struct "D" {!u16i, !s32i}>
57+
// CHECK: !ty_G = !cir.struct<struct "G" {!u16i, !s32i} #cir.record.decl.ast>
5758
// CHECK: !ty_T = !cir.struct<struct "T" {!u8i, !u32i} #cir.record.decl.ast>
5859
// CHECK: !ty_anon2E0_ = !cir.struct<struct "anon.0" {!u32i} #cir.record.decl.ast>
5960
// CHECK: !ty_anon_struct = !cir.struct<struct {!u8i, !u8i, !s32i}>
@@ -129,3 +130,20 @@ void createU() {
129130
void createD() {
130131
D d = {1,2,3};
131132
}
133+
134+
typedef struct {
135+
int x : 15;
136+
int y ;
137+
} G;
138+
139+
// CHECK: cir.global external @g = #cir.const_struct<{#cir.int<133> : !u8i, #cir.int<127> : !u8i, #cir.int<254> : !s32i}> : !ty_anon_struct
140+
G g = { -123, 254UL};
141+
142+
// CHECK: cir.func {{.*@get_y}}
143+
// CHECK: %[[V1:.*]] = cir.get_global @g : !cir.ptr<!ty_anon_struct>
144+
// CHECK: %[[V2:.*]] = cir.cast(bitcast, %[[V1]] : !cir.ptr<!ty_anon_struct>), !cir.ptr<!ty_G>
145+
// CHECK: %[[V3:.*]] = cir.get_member %[[V2]][1] {name = "y"} : !cir.ptr<!ty_G> -> !cir.ptr<!s32i>
146+
// CHECK: cir.load %[[V3]] : !cir.ptr<!s32i>, !s32i
147+
int get_y() {
148+
return g.y;
149+
}

0 commit comments

Comments
 (0)