>> What I really wonder is why it isn't >> >> %I = type { i32, i8 } >> %J = type { %I, i16, i8 } >> >> because llvm at least knows alignment rules by >> >> target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16... >> >> Therefore llvm has no other choice than assigning %I a size of 8 >> since an array may consist of %I elements and size of 5 would violate >> the aligment of the i32 member. > I can't quite parse this. %I doesn't get "assigned" a size by anyone. > Do you meant the size of struct I is eight bytes? Yes, that's true.Yes I mean that %I = type { i32, i8 } is 8 bytes given the alignment rules (i.e. llvm "assigns" a size of 8 bytes to this struct after parsing it)> Yes, the padding is required. I believe %J = type { %I, i16, i8 } would > work just as well as long as %I = type { i32, i8 } as in your example.Yes but given the ABI requires the last member to be at offset 5, which may happen (i.e. no tail padding if I is derived from), then your solution %I = type { i32, i8, i16 } is problematic or do you switch struct generation dependent on the ABI? The question arises to me since I would use an "always working" solution (with no case distinction) but of course I'm not deep enough in the matter. -Jochen
Jochen Wilhelmy <j.wilhelmy at arcor.de> writes:>> Yes, the padding is required. I believe %J = type { %I, i16, i8 } would >> work just as well as long as %I = type { i32, i8 } as in your example.> Yes but given the ABI requires the last member to be at offset 5, > which may happen > (i.e. no tail padding if I is derived from), then your solutionNo, this is not true for this example. This is getting into extremely delicate areas of the Itanium C++ ABI. In this example, %I is a "POD for the purposes of layout" type. Such types cannot have their tail padding overlapped when they are inherited from. So %I is eight bytes in all contexts. If %I is not a "POD for the purposes of layout" type, that it's tail padding MUST be overlapped when inherited from. In this case, we end up creating two types for %I, %I and %I' and use %I' as the type when it is inherited from. Fun, eh? :-/ -Dave
On 23 February 2011 19:12, David A. Greene <greened at obbligato.org> wrote:> If %I is not a "POD for the purposes of layout" type, that it's tail > padding MUST be overlapped when inherited from. In this case, we > end up creating two types for %I, %I and %I' and use %I' as the > type when it is inherited from.Some other fun examples... ** POD-layout: struct I { int, char }; // size 8 = { i32, i8 }; struct J : I { char }; // size 12 = { %I, i8 }; struct K : J { char }; // size 12 = { [9 x i8], i8, [2 x i8] }; I is POD-layout, but J is NOT. ** Default C-tor: struct I { int, char }; in C++ has the default and copy constructors created automatically, right? So I is POD-layout. But struct A { int, char, A(){} }; has the default constructor overwritten exactly the same way, but A is not a POD-layout any more. So: struct A { int, char }; // size 8 = { i32, i8 }; struct B : A { char }; // size 8 = { [5 x i8], char, [2 x i8] } struct C : B { char }; // size 8 = { [6 x i8], i8, i8 } Of course, as David said, all those types have their "normal sized" components, so there is B-full (8 bytes) and B-inheritable (6 bytes)... cheers, --renato
> If %I is not a "POD for the purposes of layout" type, that it's tail > padding MUST be overlapped when inherited from. In this case, we > end up creating two types for %I, %I and %I' and use %I' as the > type when it is inherited from. >But this is the question why two types in this case. if %I = type { i32, i8 }; then %I has 8 bytes if used directly and when used in %J %J = type { %I, i8 } then %I has only 5 bytes. Of course %I' could be %I' = type { i32, i8, i16 }; or %I' = type { i32, i8, i8, i16 }; but I don't see the point of this since %I already does the job or do I miss something? -Jochen