[clang] [CIR] Record how far a bit-field's declared types reach on x86_64 (PR #220069)

Adam Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 2 05:49:42 PDT 2026


adams381 wrote:

I've been struggling with this representation.  The field description is the right place to look, and `#cir.bitfield_info` is the natural home for all of it.  However, that cannot be reached from here.  It is an operand of `cir.get_bitfield` and `cir.set_bitfield`, so it exists only where a field is accessed.  CallConvLowering classifies a signature and sees the record type alone, and the type carries no equivalent: a member is marked `bitfield` and has a storage type, but no name, width, offset or signedness.  `bitfield_info` itself already carries `storage_type`, `size` and `offset`, so the declared type really is the only piece missing from it.

The equivalent that is reachable is to put it on the member description in the record type.  `StructType` and `UnionType` already carry a `member_kinds` array parallel to the member types.  We could add a third array that carries the extent per member, printed on the kind:

```mlir
    !rec_S = !cir.struct<"S" {bitfield<11> !u64i, bitfield<4> !u16i, data !u32i}>
```

against today's

```mlir
    !rec_S = !cir.struct<"S" {bitfield !u64i, bitfield !cir.array<!cir.array<!u8i x 3> x 0>, bitfield !u16i, bitfield !cir.array<!cir.array<!u8i x 2> x 0>, data !u32i}>
```

`bitfield<11> !u64i` reads as an 8-byte access unit whose bit-fields were declared with types extending to 11 bytes.  Absent means nothing outruns the unit, so records without such a unit print exactly as they do now.

This fixes the problem that a zero-length member is still a member, so it reaches the LLVM struct type and shifts member indices:

```mlir
    %struct.S = type { i64, [0 x i8], i16, [0 x i8], i32 }   // -fclangir
    %struct.S = type { i64, i16, i32 }                        // classic
```

That divergence is why this patch has to split CHECK prefixes in `bitfields.cpp` and move `cir.get_member` indices in `paren-list-agg-init.cpp`.  An extent on the member description adds no member, so the lowered struct matches classic again and most of the test churn here disappears.

I can implement the extent parameter as a prereq for this PR and then rebase when that lands.

https://github.com/llvm/llvm-project/pull/220069


More information about the cfe-commits mailing list