[MLton] [iI]sBigEndian necessary?

Stephen Weeks MLton@mlton.org
Fri, 10 Dec 2004 18:27:53 -0800


> ./basis-library/integer/pack-word32.sml:   if isBigEndian = Primitive.MLton.Platform.Arch.isBigEndian
> ./basis-library/real/pack-real.sml:   if isBigEndian = Primitive.MLton.Platform.Arch.isBigEndian
> ./mlton/backend/rssa.fun:   if not (Control.targetIsBigEndian ())
...
> The first two comparisons make no sense to me at all.
> The thing on the right hand side is a function, but the left is a bool.

Ah yes, quite confusing.  Primitive.MLton.Platform.Arch.isBigEndian
and MLton.Platform.Arch.isBigEndian are two different things.  The
former is a bool (see misc/primitive.sml) while the latter is a
function (see mlton/platform.sml).  I changed the name of the former
to hostIsBigEndian to clarify.

Once you get through that, you can see that the purpose of these
tests is to select the appropriate primitives for packing according to
endianness.  On a big-endian machine, PackWordBig is easy, since the
bytes are in order.  Ditto for PackWordLittle on a little-endian
machine.  If the endianness of the host doesn't match the endianness
of the Pack structure, then we need to reorder the bytes.

> The second test is in a function called Rssa.byteOffset which is used by
> ./mlton/backend/packed-representation.fun in exactly one place.

This use is to extracting a byte from a packed record.

> Is this knowledge of the endian-ness really required?
> It's a bit complicated for mips where it can be either big or little.
> 
> I might be being a bit niave, but as long as there's no native code
> generator, why should endian ever matter?

MLton's ILs are not designed to express platform-independent programs.
The ILs know about sizes of objects, offsets, endianness, etc.  For
example, the code in packed-representation to extract a byte from a
packed record needs to know about endianness, since a record is a
sequence of words, and we may need to extract only a particular byte
from a word.  Without knowledge of endianness, we would first have to
extract the word, then shift and mask to get the byte.  That could
hurt.

Using a platform-independent IL (like RSSA and Machine) that expresses
platform-dependent programs means that we can share as much code as
possible among all codegens while taking advantage of
platform-dependent knowledge in a single IL.

One could try to maintain platform-independent code all the way down
to MLton's Machine IL.  That might make sense if we only generated C
(I believe Jeff Siskind does this with Stalin).  But, MLton is a
compiler, with a hopefully growing number of native codegens -- so
moving that way seems to me like it's pushing platform-independence on
the wrong party.

> However, scattered throughout the mlton compiler code are references to
> alignment and I get lost here. Since alignment depends on the object stored,
> how is it that a single constant align := Align4/Align8 works?

The align stuff was a simple hack to support the Sparc port, for which
it can really hurt performance to have doubles not 8-byte aligned.
With -align 8, the compiler and runtime collaborate to ensure that all
doubles are 8-byte aligned.  They do this with the expense of
inserting padding to make sure object widths are 8-byte aligned.  With
-align 4 on Sparc, there is special code to load misaligned doubles
(see c-codegen.fun and c-chunk.h)

A new platform should be treated either like x86, with -align 4, if it
handles misaligned doubles, or like Sparc, with -align 8, if it
doesn't.

I am sure this whole mess could be improved and generalized to be
clearer and to support different types of values that require
different alignments.  -align conflates two notions:

1. the guarantee that the compiler/runtime makes about the address of
   the start of an object
2. the guarantee that the compiler/runtime makes about the address of
   individual types within an object.

Obviously, (2) depends on (1).

I am all for improvements to this stuff.