April 13, 2009
On Mon, 13 Apr 2009 16:44:25 +0400, Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> wrote:

> On Mon, Apr 13, 2009 at 2:05 PM, Frits van Bommel
> <fvbommel@remwovexcapss.nl> wrote:
>> Kagamin wrote:
>>>
>>> Stewart Gordon Wrote:
>>>
>>>> At the moment, the problem seems to be that the compiler is silently
>>>> ignoring many cases of (a), (b) and (c) alike.  Some people argue that the
>>>> spec doesn't forbid such use of inapplicable attributes explicitly, and so
>>>> the compiler's treatment of these cannot be called a bug.
>>>>
>>>> I argue that this isn't right.  Nothing I've managed to find in the spec
>>>> states or implies that such obviously wrong code is allowed.  So, by
>>>> applying common sense, one would conclude that it isn't allowed.
>>>
>>> Such mood was always in the spec: "AlignAttribute is ignored when applied
>>> to declarations that are not structs or struct members".
>>
>> I never saw that before. So it doesn't work for class members? And it won't
>> change the alignment of unions if applied to union members (by changing the
>> maximum alignment of the members)?
>>
>
> align is defined in terms of the companion C compiler.
>
> align(16) int foo; does not guarantee that foo.offsetof is aligned to 16 bytes.
> Since C doesn't have D classes, the align attribute makes little sense here.

You are kind of contradict yourself.

Let's assme that align is defined in terms of the companion C compiler.
Then, since C doesn't have D classes, the align attribute makes little sense when applied to /D classes/.

I don't know how to judge about C built-in types from that.

April 13, 2009
Stewart Gordon wrote:
> Frits van Bommel wrote:
>> Kagamin wrote:
> <snip>
>>> Such mood was always in the spec: "AlignAttribute is ignored when applied to declarations that are not structs or struct members".
>>
>> I never saw that before. So it doesn't work for class members?
> 
> http://www.digitalmars.com/d/1.0/class.html
> "The D compiler is free to rearrange the order of fields in a class to optimally pack them in an implementation-defined manner. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes."

Right, forgot about that bit. Probably because AFAIK no D compiler actually reorganizes them...

(How does this combine with the "D ABI" anyway? I know binary compatibility between the different compilers is a bit of a pipe dream at the moment, but the only way that could work would be to standardize any and all shuffling of class fields...)

>> And it won't change the alignment of unions if applied to union members (by changing the maximum alignment of the members)?
> 
> I'm not sure what you mean....

Unions are normally aligned to the maximum alignment for any member. Now consider:

union U {
    align(1) void* p;
    ubyte[size_t.sizeof] bytes;
}
union U2 {
    align(4) ubyte[12] data;
    char[12] str;
}
What are U.alignof and U2.alignof?

According to that piece of the spec, those align() attributes should be useless.
However, according to DMD[1] U.alignof is 1, and without the attribute it's 4.
U2 on the other hand is align(1) regardless of attribute.

It seems DMD disagrees with the spec here.
Same goes for GDC, except U.alignof is 8 without the attribute instead of 4 because I'm using a 64-bit version.
LDC seems to agree with the spec (it ignores the aligns), but that may just be because it doesn't fully support align() in the first place...

[1]: 1.042 on Linux:
void main() {
    printf("%d %d\n", cast(int)U.alignof, cast(int)U2.alignof);
}
April 13, 2009
Frits van Bommel wrote:
> Stewart Gordon wrote:
<snip>
[rearrangement of class fields]
> 
> Right, forgot about that bit. Probably because AFAIK no D compiler actually reorganizes them...
> 
> (How does this combine with the "D ABI" anyway? I know binary compatibility between the different compilers is a bit of a pipe dream at the moment, but the only way that could work would be to standardize any and all shuffling of class fields...)

Good question.  But AAs are another thing that's implementation defined at the moment.

<snip>
> Unions are normally aligned to the maximum alignment for any member. Now consider:
> 
> union U {
>     align(1) void* p;
>     ubyte[size_t.sizeof] bytes;
> }
> union U2 {
>     align(4) ubyte[12] data;
>     char[12] str;
> }
> What are U.alignof and U2.alignof?
> 
> According to that piece of the spec, those align() attributes should be useless.
> However, according to DMD[1] U.alignof is 1, and without the attribute it's 4.
> U2 on the other hand is align(1) regardless of attribute.
<snip>

Sounds like a bug.

Surely, align isn't applicable to unions at all.  IINM the members of a union, by design, start at the same offset.  An anonymous struct within a union, or an anonymous union within a struct, might have alignment - in either case, it would be in relation to the struct.

Stewart.
April 13, 2009
On Mon, Apr 13, 2009 at 3:00 PM, Denis Koroskin <2korden@gmail.com> wrote:
> On Mon, 13 Apr 2009 16:44:25 +0400, Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> wrote:
>
>> On Mon, Apr 13, 2009 at 2:05 PM, Frits van Bommel <fvbommel@remwovexcapss.nl> wrote:
>>>
>>> Kagamin wrote:
>>>>
>>>> Stewart Gordon Wrote:
>>>>
>>>>> At the moment, the problem seems to be that the compiler is silently
>>>>> ignoring many cases of (a), (b) and (c) alike.  Some people argue that
>>>>> the
>>>>> spec doesn't forbid such use of inapplicable attributes explicitly, and
>>>>> so
>>>>> the compiler's treatment of these cannot be called a bug.
>>>>>
>>>>> I argue that this isn't right.  Nothing I've managed to find in the
>>>>> spec
>>>>> states or implies that such obviously wrong code is allowed.  So, by
>>>>> applying common sense, one would conclude that it isn't allowed.
>>>>
>>>> Such mood was always in the spec: "AlignAttribute is ignored when
>>>> applied
>>>> to declarations that are not structs or struct members".
>>>
>>> I never saw that before. So it doesn't work for class members? And it
>>> won't
>>> change the alignment of unions if applied to union members (by changing
>>> the
>>> maximum alignment of the members)?
>>>
>>
>> align is defined in terms of the companion C compiler.
>>
>> align(16) int foo; does not guarantee that foo.offsetof is aligned to 16
>> bytes.
>> Since C doesn't have D classes, the align attribute makes little sense
>> here.
>
> You are kind of contradict yourself.
>
> Let's assme that align is defined in terms of the companion C compiler. Then, since C doesn't have D classes, the align attribute makes little sense when applied to /D classes/.
>
> I don't know how to judge about C built-in types from that.
>
>

Yes now I read it again I can see it doesn't make much sense.

What I meant was just to say that align does not work for classes!!!

What also snuck in there was that align(N) provides no guarantee that it will actually affect any field offsets. It wasn't supposed to have anything to do with the discussion, so just ignore it if you will...
April 14, 2009
On 2009-04-13 09:43:53 -0400, Frits van Bommel <fvbommel@REMwOVExCAPSs.nl> said:

> (How does this combine with the "D ABI" anyway? I know binary compatibility between the different compilers is a bit of a pipe dream at the moment, but the only way that could work would be to standardize any and all shuffling of class fields...)

Interesting observation.

But you don't necessarily need to standardize the shuffling algorithm. If the offsets for fields in a class could be resolved at link time (the compiler could dump the offsets in the object file), then the linker could arange the final executable for any layout. The same could be done for virtual functions too, giving us a true non-fragile ABI capable of supporting changes in the order of member fields and functions.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

April 14, 2009
Michel Fortin wrote:
> On 2009-04-13 09:43:53 -0400, Frits van Bommel <fvbommel@REMwOVExCAPSs.nl> said:
> 
>> (How does this combine with the "D ABI" anyway? I know binary compatibility between the different compilers is a bit of a pipe dream at the moment, but the only way that could work would be to standardize any and all shuffling of class fields...)
> 
> Interesting observation.
> 
> But you don't necessarily need to standardize the shuffling algorithm. If the offsets for fields in a class could be resolved at link time (the compiler could dump the offsets in the object file), then the linker could arange the final executable for any layout. The same could be done for virtual functions too, giving us a true non-fragile ABI capable of supporting changes in the order of member fields and functions.

Some problems I see with this:
* Good luck implementing that for all of OMF (DMD/win), COFF (GDC/win), ELF(anything *nix).
* Same for LLVM bitcode, for LDC and any other future compilers based on LLVM. Especially because this is a *typed* IR, and optimizations usually work best if you don't work around types with pointer<-->int conversions.
* Implementing this without reducing the quality of generated code; some architectures allow better instructions if you know the offset is below a certain limit, which must then be known at compile-time (except for something like LLVM, where link-time is early enough for this if you're generating IR instead of native code at first).
* If you do this, you don't know how big a class body is at compile-time (because padding is unknown). So the compiler doesn't know what size to allocate in the stack frame for 'scope c = new C;"

So yeah, in theory this might be possible, but I don't know of any object format that supports all these without it pessimizing the generated code. I just don't think it's worth it at the moment.

Though if you feel like extending LLVM to support this... (it's IR object format is probably closest to efficiently supporting something like this due to arbitrarily-complex constant expression support in IR and inter-module optimizations. You might be able to get it to work, as long as the offsets and sizes are known by the time the assembler gets involved)

It would certainly allow support for some other cool stuff, like adding fields and (virtual) methods to classes from other object files (aka modules).
April 14, 2009
Stewart Gordon wrote:
>> Unions are normally aligned to the maximum alignment for any member. Now consider:
>>
>> union U {
>>     align(1) void* p;
>>     ubyte[size_t.sizeof] bytes;
>> }
>> union U2 {
>>     align(4) ubyte[12] data;
>>     char[12] str;
>> }
>> What are U.alignof and U2.alignof?
>>
>> According to that piece of the spec, those align() attributes should be useless.
>> However, according to DMD[1] U.alignof is 1, and without the attribute it's 4.
>> U2 on the other hand is align(1) regardless of attribute.
> <snip>
> 
> Sounds like a bug.

Definitely.
> 
> Surely, align isn't applicable to unions at all.  IINM the members of a union, by design, start at the same offset.

Not so, the alignment of each member should be respected. Most obviously, a union U consisting of a single member x should have U.alignof == x.alignof.


  An anonymous struct within
> a union, or an anonymous union within a struct, might have alignment - in either case, it would be in relation to the struct.

> 
> Stewart.
April 14, 2009
Don wrote:
> Stewart Gordon wrote:
<snip>
>> Surely, align isn't applicable to unions at all.  IINM the members of a union, by design, start at the same offset.
> 
> Not so, the alignment of each member should be respected. 

But the offset of a union member is always zero.  So what would this do?

> Most obviously, a union U consisting of a single member x should have
> U.alignof == x.alignof.
<snip>

Yes, by propagating the union's alignment (relative to the containing struct) to the member.

Stewart.
April 14, 2009
Stewart Gordon wrote:
> Don wrote:
>> Stewart Gordon wrote:
> <snip>
>>> Surely, align isn't applicable to unions at all.  IINM the members of a union, by design, start at the same offset.
>>
>> Not so, the alignment of each member should be respected. 
> 
> But the offset of a union member is always zero.  So what would this do?

It should make sure the union is aligned appropriately in a containing struct, meaning U.alignof >= M.alignof for all members M. Specifying per-member alignment allows you to change that member's effect on the union's alignment.

>> Most obviously, a union U consisting of a single member x should have
>> U.alignof == x.alignof.
> <snip>
> 
> Yes, by propagating the union's alignment (relative to the containing struct) to the member.

But the union's alignment needs to be sufficient for all members, so it depends on the maximum alignment of all members.
April 14, 2009
Frits van Bommel wrote:
> Stewart Gordon wrote:
<snip>
>> But the offset of a union member is always zero.  So what would this do?
> 
> It should make sure the union is aligned appropriately in a containing struct, meaning U.alignof >= M.alignof for all members M. Specifying per-member alignment allows you to change that member's effect on the union's alignment.

But alignment of a member within a structure and alignment of the whole structure relative to an outer one are two distinct concepts.  What sense is there in being able to use one to control the other?

>>> Most obviously, a union U consisting of a single member x should have
>>> U.alignof == x.alignof.
>> <snip>
>>
>> Yes, by propagating the union's alignment (relative to the containing struct) to the member.
> 
> But the union's alignment needs to be sufficient for all members, so it depends on the maximum alignment of all members.

That's only because you want to be able to attach alignments to individual members of a union.  And I still don't know why.

If you want a union to have a certain alignment relative to a struct in which it's contained, in what cases is it not sufficient to put the align attribute on the union's instance in the struct?

Stewart.