Skip to content

Commit

Permalink
[CIR][CodeGen] Locally inited structures with bitfields (#463)
Browse files Browse the repository at this point in the history
The second part of the job started in #412 , now about local structures.

As it was mentioned previously, sometimes the layout for structures with
bit fields inited with constants differ from the originally created in
`CIRRecordLayoutBuilder` and it cause `storeOp` verification fail due to
different structure type was used to allocation.
This PR fix it.
An example:
```
typedef struct {
  int a : 4;
  int b : 5;
  int c;
} D;

void bar () {
  D d = {1,2,3};  
}
```

Well, I can't say I'm proud of these changes - it seems like a type
safety violation, but looks like it's the best we can do here.

The original codegen doesn't have this problem at all, there is just a
`memcpy` there, I provide LLVM IR just for reference:

```
%struct.D = type { i16, i32 }

@__const.bar.d = private unnamed_addr constant { i8, i8, i32 } { i8 33, i8 0, i32 3 }, align 4

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @bar() #0 {
entry:
  %d = alloca %struct.D, align 4
  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %d, ptr align 4 @__const.bar.d, i64 8, i1 false)
  ret void
}
```
  • Loading branch information
gitoleg authored and lanza committed Apr 29, 2024
1 parent 21b39bc commit 7196e39
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ static void emitStoresForConstant(CIRGenModule &CGM, const VarDecl &D,
//
// FIXME(cir): This is closer to memcpy behavior but less optimal, instead of
// copy from a global, we just create a cir.const out of it.

if (addr.getElementType() != Ty) {
auto ptr = addr.getPointer();
ptr = builder.createBitcast(ptr.getLoc(), ptr, builder.getPointerTo(Ty));
addr = addr.withPointer(ptr, addr.isKnownNonNull());
}

auto loc = CGM.getLoc(D.getSourceRange());
builder.createStore(loc, builder.getConstant(loc, constant), addr);
}
Expand Down
19 changes: 19 additions & 0 deletions clang/test/CIR/CodeGen/bitfields.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ void m() {
struct __long l;
}

typedef struct {
int a : 4;
int b : 5;
int c;
} D;

typedef struct {
int a : 4;
int b : 27;
Expand All @@ -27,9 +33,12 @@ typedef struct {
int a : 3; // one bitfield with size < 8
unsigned b;
} T;

// CHECK: !ty_22D22 = !cir.struct<struct "D" {!cir.int<u, 16>, !cir.int<s, 32>}>
// CHECK: !ty_22S22 = !cir.struct<struct "S" {!cir.int<u, 32>, !cir.int<u, 32>, !cir.int<u, 16>, !cir.int<u, 32>}>
// CHECK: !ty_22T22 = !cir.struct<struct "T" {!cir.int<u, 8>, !cir.int<u, 32>} #cir.record.decl.ast>
// CHECK: !ty_22anon2E122 = !cir.struct<struct "anon.1" {!cir.int<u, 32>} #cir.record.decl.ast>
// CHECK: !ty_anon_struct = !cir.struct<struct {!cir.int<u, 8>, !cir.int<u, 8>, !cir.int<s, 32>}>
// CHECK: !ty_22__long22 = !cir.struct<struct "__long" {!cir.struct<struct "anon.1" {!cir.int<u, 32>} #cir.record.decl.ast>, !cir.int<u, 32>, !cir.ptr<!cir.int<u, 32>>}>

// CHECK: cir.func {{.*@store_field}}
Expand Down Expand Up @@ -96,4 +105,14 @@ unsigned load_non_bitfield(S *s) {
// CHECK: cir.func {{.*@load_one_bitfield}}
int load_one_bitfield(T* t) {
return t->a;
}

// for this struct type we create an anon structure with different storage types in initialization
// CHECK: cir.func {{.*@createD}}
// CHECK: %0 = cir.alloca !ty_22D22, cir.ptr <!ty_22D22>, ["d"] {alignment = 4 : i64}
// CHECK: %1 = cir.cast(bitcast, %0 : !cir.ptr<!ty_22D22>), !cir.ptr<!ty_anon_struct>
// CHECK: %2 = cir.const(#cir.const_struct<{#cir.int<33> : !u8i, #cir.int<0> : !u8i, #cir.int<3> : !s32i}> : !ty_anon_struct) : !ty_anon_struct
// CHECK: cir.store %2, %1 : !ty_anon_struct, cir.ptr <!ty_anon_struct>
void createD() {
D d = {1,2,3};
}

0 comments on commit 7196e39

Please sign in to comment.