[Openmcl-devel] Structure Alignment of Foreign Double Floats
Gary Byers
gb at clozure.com
Sun Jun 5 16:19:18 PDT 2005
On Sun, 5 Jun 2005, James Bielman wrote:
> Hi,
>
> (I'm using OpenMCL 0.14.3 on OS X 10.4.1)
>
> I'm trying to write a function to determine the alignment of a foreign
> type within a structure (for use in a portable FFI library). I came up
> with the following:
>
> (defun foreign-type-alignment (type)
> "Return the alignment in bytes of foreign type TYPE."
> (/ (ccl::foreign-type-alignment
> (ccl::parse-foreign-type type)) 8))
>
> When testing with gcc it seems that doubles are aligned to 4-byte
> boundaries in structures, yet OpenMCL returns:
>
> ? (foreign-type-alignment 'double)
> 8
>
> Similar code used in SBCL (both systems are derived from CMUCL?)
> agrees with GCC and returns 4.
>
> I created a structure type using the OpenMCL FFI and it seems to align
> a double to a 4-byte boundary as expected, apparently ignoring the 8
> returned by FOREIGN-TYPE-ALIGNMENT.
>
> So, is what I'm trying to do here completely misguided? Is there
> a better way to get this information?
>
> Thanks!
>
> James
Apple's ABI documentation uses terms like "natural alignment" and
"embedding alignment", and notes that for some data types (notably
double-floats) the two are different. (When embedded in a structure,
a double is aligned - somewhat unnaturally - on a 32-bit boundary,
unless it's the first member of the structure; that special case
affects the overall alignment of the structure.)
It gets worse: some legacy Carbon strutures are define with 68K
alignment rules in effect (via
#pragma options align=mac68k /* I may be misremembering
the syntax here */
); such structures impose 16-bit alignment on their members.
The slightly unnatural default alignment rules are (IIRC) inherited
from AIX. I think that OpenMCL's FFI follows them correctly, and
(at least in the case of things imported from the interface database)
handles the legacy 68K case as well, (I'm not sure if there's
syntax for this in DEF-FOREIGN-TYPE, but I'm not sure that there's
a great need to define legacy 68K structures manually, either.)
It's possible to specify some compiler options that'll override
the default alignment rules (so, for instance, it's possible to
compile things with "natural" alignment in effect.)
On most other platforms, a function like FOREIGN-TYPE-ALIGNMENT
would be asking a reasonable and simple question. On OSX, the
answer you obtain (the natural alignment of the type) isn't always
relevant; you might need something like:
(defun foreign-type-embedded-alignment (type &key first-field-p
mac68k-p)
(let* ((natural-alignment
(/ (ccl::foreign-type-alignment
(ccl::parse-foreign-type type)) 8)))
(if mac68k-p
(min 16 natural-alignment
(if first-field-p
natural-alignment
(min 32 natural-alignment))))))
The special treatment of a double in the first field obviously
doesn't affect that field's offset within the structure, but
it does affect the overall alignment of the structure. If we
have:
struct {
double x;
int y;
int z;
} a;
and
struct {
int y;
int z;
double x;
} b;
then instances of "a" need to be aligned on 64-bit boundaries, whereas
instance of "b" only need 32-bit alignment.
32-bit LinuxPPC (like most other platforms) just uses what Apple calls
"natural" alignment. Some early versions of the 64-bit LinuxPPC tried
to preserve the old AIX alignment rules; IIRC, the developers said
something like "what on earth are we thinking of ?" and switched to
natural alignment. Since pointers (and long ints) are 64 bits wide on
64-bit LinuxPPC, the performance penalty associated with a misaligned
access would presumably be encountered more often.
That performance penalty can be anything from an extra bus cycle to an
alignment fault (if the double crosses a page boundary) that has to be
handled in software. I'm not sure how often this happens, but it'd
nice if the system ABI made it easy to avoid.
More information about the Openmcl-devel
mailing list