[cfe-dev] Implementation of the CGRecordLayoutBuilder for Microsoft ABI.

r4start r4start at gmail.com
Sun Sep 25 23:55:37 PDT 2011


On 23/09/2011 22:44, John McCall wrote:
> On Sep 23, 2011, at 5:30 AM, r4start wrote:
>> I am writing CGRecordLayoutBuilder for Microsoft ABI and I have a problem.
>> I have the following code for testing http://pastebin.com/27U2hcDC .
>>
>> When generated layout for a class C, I have break assert in
>> CGRecordLayoutBuilder.cpp line 968
>> assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty)&&
>>           "Type size mismatch!");.
>> During debugging, I discovered that TypeSizeInBits smaller
>> getTargetData().getTypeAllocSizeInBits(Ty)  4 bytes.
>> After investigation, I discovered that the alignment is added in
>> StructLayout constructor (TargetData.cpp line 73)
>> // Add padding to the end of the struct so that it could be put in an array
>>   // and all array elements would be aligned correctly.
>>    if ((StructSize&  (StructAlignment-1)) != 0)
>>      StructSize = TargetData::RoundUpAlignment(StructSize, StructAlignment);
>>
>> But this alignment is not necessary for class C.
>> MSVC doesn't add to the end of the class alignment, if it has a virtual
>> base classes.
>> I see two solutions to this problem:
>>   1. Rewrite assert like this
>>       (pseudocode)
>>       if ABI == Microsoft&&  Class has virtual basses
>>         assert(TypeSizeInBits ==
>> (getTargetData().getTypeAllocSizeInBits(Ty) - 32)&&
>>                      "Type size mismatch!");
>>        else
>>          old version;
>>    2. Provide to StructLyout information about ABI.
>>
>> I think the first way is more simple.
> No.  A *lot* of downstream code will be broken if LLVM doesn't lay
> out the IR type the way we think it's laid out, and that includes the
> presence or absence of tail padding.
>
> I don't see how this is possible, though.  Can you run through an
> example?  What's the size and layout of class B here?
>
> class A {
>    char c;
> };
>
> class B : public virtual A {
>    void *p;
> };
>
> I would expect that sizeof(B) is 12, and that it's laid out like this:
>    [0-3] virtual base pointer
>    [4-7] B.p
>      [8] A.c
>   [9-11] tail padding
MSVS with pragma pack 8 generates such layout:
1>  class A    size(1):
1>      +---
1>  0  | c
1>      +---

1>  class B    size(9):
1>      +---
1>  0  | {vbptr}
1>  4  | p
1>      +---
1>      +--- (virtual base A)
1>  8  | c
1>      +---

My code generates same layout (i32* in B is vbtable pointer):
*** Dumping AST Record Layout
    0 | class A
    0 |   char c
   sizeof=1, dsize=1, align=1
   nvsize=1, nvalign=1

LLVMType:%class.A = type { i8 }
NonVirtualBaseLLVMType:%class.A = type { i8 }
IsZeroInitializable:1

*** Dumping AST Record Layout
    0 | class B
    0 |   (B vtable pointer)
    0 |   (B vbtable pointer)
    4 |   void * p
    8 |   class A (virtual base)
    8 |     char c
   sizeof=9, dsize=9, align=4
   nvsize=8, nvalign=4

LLVMType:%class.B = type { i32*, i8*, %class.A }
NonVirtualBaseLLVMType:%class.B.base = type { i32*, i8* }
IsZeroInitializable:1
> Or are we talking about the base-subobject struct type?  It shouldn't
> matter whether that type gets tail padding or not, because it's never
> separately allocated.
>
> John.
MSVC doesn't add additional alignment for virtual base classes, so class 
size can not be a multiple of alignment(in this example it's 9, but 
pragma is 8).
But StructLayout ctor adds trailing alignment.

  - Dmitry.



More information about the cfe-dev mailing list