================
@@ -624,29 +624,42 @@ def CIR_VoidType : CIR_Type<"Void", "void"> {
 
//===----------------------------------------------------------------------===//
 // RecordMemberKind
 //
-// What a record member holds, for members that do not hold source data.
+// What a record member holds, and whether its extent is a declared one.
 
//===----------------------------------------------------------------------===//
 
 def CIR_RecordMemberKind : CIR_I32EnumAttr<
     "RecordMemberKind", "what a record member holds", [
   I32EnumAttrCase<"Data", 0, "data">,
   I32EnumAttrCase<"Pad", 1, "pad">,
-  I32EnumAttrCase<"Empty", 2, "empty">
+  I32EnumAttrCase<"Empty", 2, "empty">,
----------------
adams381 wrote:

I went looking for the example you requested, and tried everything I would 
think of: plain fields, arrays of empty records, empty base subobjects, 
`[[no_unique_address]]`, over-aligned empty structs, zero-length arrays.  Every 
`empty` member CIRGen emits is either zero-sized or gets its bytes from unnamed 
bit-fields.  So the pass can work it out without the `empty_bitfield` mark: an 
`empty` member that occupies bytes has to stay in the field list, one that 
occupies nothing can be dropped.  That rule gives the right answer on every 
shape I tried, so `empty_bitfield` is not carrying its weight and I will drop 
it.

However, `bitfield` is a different story.  Consider this pair:

```c
struct A { long long x : 32; long long y; };  // classic: (i64, i64)
struct B { unsigned  x;      long long y; };  // classic: (i32, i64)
```

```mlir
!cir.struct<"A" {bitfield !u32i, data !s64i}>
!cir.struct<"B" {data     !u32i, data !s64i}>
```

Same size, same member types, same offsets, no padding members in either.  The 
mark is the only difference in the whole type, and classic passes the first 
register differently.

There is one more wrinkle.  My next planned PR is for zero-width bit-fields and 
is a sibling of this PR.  I can't find a way to work around needing a mark in 
this example:

```c
struct ZA { int x; int a[0];     } __attribute__((aligned(16)));  // classic: 
i32
struct ZB { int x; unsigned : 0; } __attribute__((aligned(16)));  // classic: 
i64
```

`ZB`'s whole module is byte-identical to `struct { int x; } 
__attribute__((aligned(16)))`, because CIRGen emits nothing at all for the 
zero-width bit-field.  `ZA` is `{data !s32i, empty !cir.array<!s32i x 0>, pad 
...}`.  So the obvious spelling for `ZB`, an `empty` member at zero size, is 
already taken by `ZA`, and the two have to come out opposite ways.

My plan there is a zero-size member carrying the declared type, `!cir.array<T x 
0>`, under a mark of its own.  It cannot be `empty`, for the reason above.  It 
cannot be `bitfield` either, because by definition `holdsDataForABI` is true 
for that and `struct { int : 0; }` would stop being empty for the ABI and take 
a register where classic passes nothing.

I'm convinced now that `empty_bitfield` can go, but I think we still need five 
marks:

1) data
2) pad
3) empty
4) bitfield
5) zero_width_bitfield

That would allow the pair above to be emitted as

```mlir
// already emitted today
!cir.struct<"ZA" {data !s32i, empty !cir.array<!s32i x 0>, pad !cir.array<!u8i 
x 12>}>
// proposed zero_width_bitfield
!cir.struct<"ZB" {data !s32i, zero_width_bitfield !cir.array<!u32i x 0>, pad 
!cir.array<!u8i x 12>}>
```

https://github.com/llvm/llvm-project/pull/216864
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to