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

Eli Friedman eli.friedman at gmail.com
Mon Sep 26 00:18:15 PDT 2011


On Sun, Sep 25, 2011 at 11:55 PM, r4start <r4start at gmail.com> wrote:
> 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

That's can't be what MSVC actually does: the size of B must be a
multiple of its alignment.  If you're representation of what MSVC
computes is accurate, you must be miscomputing the alignment.

-Eli




More information about the cfe-dev mailing list