From 7196e39abba2e19a930872ce18348613887d783e Mon Sep 17 00:00:00 2001 From: gitoleg Date: Wed, 14 Feb 2024 22:55:12 +0300 Subject: [PATCH] [CIR][CodeGen] Locally inited structures with bitfields (#463) 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 } ``` --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 7 +++++++ clang/test/CIR/CodeGen/bitfields.c | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index a91c3b7bd0c7..2483d3d371ac 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -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); } diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c index 8aad4d503a0c..83eb940840bc 100644 --- a/clang/test/CIR/CodeGen/bitfields.c +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -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; @@ -27,9 +33,12 @@ typedef struct { int a : 3; // one bitfield with size < 8 unsigned b; } T; + +// CHECK: !ty_22D22 = !cir.struct, !cir.int}> // CHECK: !ty_22S22 = !cir.struct, !cir.int, !cir.int, !cir.int}> // CHECK: !ty_22T22 = !cir.struct, !cir.int} #cir.record.decl.ast> // CHECK: !ty_22anon2E122 = !cir.struct} #cir.record.decl.ast> +// CHECK: !ty_anon_struct = !cir.struct, !cir.int, !cir.int}> // CHECK: !ty_22__long22 = !cir.struct} #cir.record.decl.ast>, !cir.int, !cir.ptr>}> // CHECK: cir.func {{.*@store_field}} @@ -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 , ["d"] {alignment = 4 : i64} +// CHECK: %1 = cir.cast(bitcast, %0 : !cir.ptr), !cir.ptr +// 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 +void createD() { + D d = {1,2,3}; } \ No newline at end of file