Skip to content

Padding for union type #1281

Open
Open
@gitoleg

Description

There is a problem with union type: it has no padding. And it's important to have one.

Example:

  typedef union {    
     uint16_t f0;
     signed   f1 : 11;
     unsigned f2 : 2;
     signed   f3 : 5;
  } U;

  static U g0 = {65534};
  static U g1[2] = {{65534}, {65534}};
  static uint16_t *g2 = &g1[1].f0;

This is how the original LLVM IR looks like:

  @g0 = global %union.U { i16 -2, [2 x i8] zeroinitializer }
  @g1 = global [2 x %union.U] [%union.U { i16 -2, [2 x i8] zeroinitializer }, %union.U0 { i16 -2, [2 x i8] zeroinitializer }]
  @g2 = global ptr getelementptr (i8, ptr @g1, i64 4)

As one can see, there is an extra padding for the union type: [2 x i8] zeroinitializer , and g0 size is 4 bytes in total. And for g2 offset is computes as 4 - since it points to the second element of g1.

LLVM IR after CIR doesn't have these padding bytes neither it has union keyword (I wonder when we lost it but it's not a problem right now).

@g0 = global { i16 } { i16 -2 }
@g1 = global [2 x { i16 }] [{ i16 } { i16 -2 }, { i16 } { i16 -2 }]
@g2 = global ptr getelementptr inbounds ([2 x { i16 }], ptr @g1, i32 0, i32 2)

g0 has size of 2 bytes, so as g1 element size as well.

The problem is in the g2 initialization: unfortunately the offset is computed from APValue methods here and is equal to 4 as in the OG, no CIR is involved.

Thus, the offset of the second element of g1 is computed as 4, and element size is 2 -> we got wrong indices for the GlobalViewAttr from the very beginning: @g2 = #cir.global_view<@g1, [2 : i32]> : !cir.ptr<!u16i>!

The g0 size is 2 because for unions we compute size as a size of the largest member and nothing else.

According to the comments we chose to track all union members and deffer padding computation to the lowering. But looks like that was not happened.

So the question is - what do you think, how to fix it properly?
I see the following ways:

  1. Make a separate type for unions. In this case we can still track all the members and have padding bytes as a separate field
  2. Add a notion about trailing padding into the struct type - as a parameter, e.g. index of the field.
  3. Try to add padding in the lowering like it was planned, e.g. in the type conversion. I'm not sure that's a good way though.

Any other thoughts, ideas?

Metadata

Assignees

No one assigned

    Labels

    IR designConsiderations around the design of ClangIRIR differenceA difference in ClangIR-generated LLVM IR that could complicate reusing original CodeGen testsbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions