[llvm-commits] Size of long double (X86_FP80Ty)

Dale Johannesen dalej at apple.com
Fri Sep 28 14:14:01 PDT 2007


I tried having the padding by part of the type but concluded this way is
better (although there's a bug, see below.)

The idea is that the size represents how many bytes actually have data,
and the padding in structs and arrays is handled by the alignment (btw,
size and alignment are both 16 on Darwin, rather than 12/4.)    
Exercising
this a bit, there's a bug in array referencing, but this seems to  
work for structs
and array allocations.  The end data layout is definitely supposed to  
be the
same as gcc's; ABI compatibility is a requirement, at least for us.
sizeof is computed by the FE, of course, so things like
(char*)&ld + i*sizeof(long double)
work fine.

I'm not persuaded the approach is wrong; if we
make the padding part of the type it has to have a deterministic  
value, or
bitwise comparisons don't work, and there's all those useless bytes  
being
carried around.  (If you experiment with gcc, you'll find those bytes  
are not
deterministic; when copying long doubles, sometimes it uses fldt/fstpt
to get just 10 bytes, other times it will get 12 or 16, which may be
uninitialized.  I want to avoid this sort of thing.)

I need to fix the array-reference issue; the code that translates  
getelementpr
to bytes needs to look at alignment(element type).  Do you have any  
other
examples that don't work?

On Sep 28, 2007, at 1:04 PM, Duncan Sands wrote:

> Hi Dale, on my machine (x86-32, linux) LLVM considers long double to
> have a size of 10 bytes and an alignment of 4 bytes.  GCC gives it a
> size of 12 bytes and an alignment of 4 bytes (of course only the first
> 80 bits (10 bytes) are actually used - the rest is padding).
>
> I can see several problems with a 10 byte size.
>
> First, problems that aren't related to gcc.  In an array of long  
> double,
> the elements may not be aligned even if the array is aligned.  This is
> because the usual invariant "the size is a multiple of the  
> alignment" does
> not hold for size 10, alignment 4.  I'm betting that the logic for  
> working
> out alignments of loads and stores in LLVM is not expecting this!   
> Since
> this type only exists on x86, which is pretty lenient about unaligned
> pointer access, I suppose this might not really matter.  Isn't  
> unaligned
> access slower than aligned access though?  Anyway, it seems to me much
> better to avoid this can of worms and have the size be a multiple  
> of the
> alignment.
>
> Second, problems related to gcc.  We convert long double to X86_FP80Ty
> (which I've been referring to as long double).  The result is that  
> the size
> of the gcc type is not equal to the size of the LLVM type.  This  
> causes all
> kinds of problems with arrays and pointer arithmetic.   That's the  
> reason
> for the check that sizes are the same (which you turned off in this  
> case,
> tut tut!).  For example, suppose you declare an array of long doubles,
> cast to an i8* and start moving around in it based on sizeof(long  
> double).
> Well you'll end up at the wrong place because sizeof is the gcc  
> size (12)
> but LLVM will have placed the elements 10 bytes apart!  This also has
> knock-on effects, like LLVM arrays of long doubles having different
> lengths to the corresponding gcc arrays etc.  If you think about it I
> hope you will agree that it is important to convert gcc types to LLVM
> types of the same size.
>
> By the way, are there any standards that require size to be a multiple
> of alignment?
>
> The solution I would prefer is: make getTypeSize return 12 for long  
> double,
> have getTypeSizeInBits return 80 (I think this should be renamed to
> getBitsUsedByType or something like that, see APInt comments  
> below).  Make
> it a requirement that getTypeSize always returns a multiple of the  
> alignment.
> Document that getTypeSize is the offset between successive elements  
> in arrays
> of this type, or between fields in a struct; and that loads and  
> stores of this
> type can write up to this many bytes.  Document that  
> getBitsUsedByType returns
> the minimum number of bits needed to hold all values of this type,  
> and that
> this can be less than 8*getTypeSize.  Correct all places that  
> assume that
> getBitsUsedByType is 8*getTypeSize (like the check that the gcc  
> type has
> the same size as the llvm type, which should be using 8*getTypeSize).
>
> Note that this is exactly how it is already for APInt.  Consider a  
> type
> like i36.  For this, getTypeSize returns 8, i.e. 64 bits, while
> getTypeSizeInBits returns 36.  Thus getTypeSize corresponds to gcc's
> TYPE_SIZE while getTypeSizeInBits corresponds to TYPE_PRECISION.  This
> seems like a good model to me.
>
> That said, other solutions are possible.  For example, we could ignore
> the unaligned array element problem, and alter gcc so that TYPE_SIZE
> for long double becomes 80 bits.  I have no idea what kind of problems
> this might cause, if any.
>
> Or we could convert long double to a struct { X86_FP80Ty, i16 }, and
> fix up all the floating point stuff in llvm-convert.  Chris mentioned
> to me on IRC that this is a pessimisation in general, and would rather
> have X86_FP80Ty be used for scalar operations (so you can continue to
> use registers) but have { X86_FP80Ty, i16 } be used for loads and  
> stores
> to memory.  He also noted that this kind of thing would be also  
> helpful
> for Darwin's funky 32 bit boolean type (which would be more optimally
> manipulated as in i1 in scalar expressions, but needs to be stored as
> 32 bits).  Thus he suggested associating two LLVM types with each  
> primitive
> gcc type: a type used for lvalues (i.e. memory access) and a type  
> used for
> scalar operations (LLVM register operations).  The lvalue type  
> would always
> have the same size as the gcc type, while the scalar type could  
> differ in size.
>
> What do you think?
>
> Best wishes,
>
> Duncan.




More information about the llvm-commits mailing list