previous next top contents index framed top this page unframed
64-bit implementations of MAINSAIL are newer than 32-bit implementations and have somewhat different characteristics, so there some potential problems you should be aware of when writing 64-bit code or porting existing 32-bit applications to a 64-bit platform.
A 64-bit implementation of MAINSAIL provides a much larger address space than a 32-bit implementation, and also a greatly expanded range of values for the data types LONG INTEGER and LONG BITS. However, to take advantage of these features, you must make sure that your code does not contain implicit assumptions that it is running on a 32-bit implementation of MAINSAIL.
Theoretically, a carefully coded 32-bit MAINSAIL program should not need any changes when ported to a 64-bit platform, but it is not difficult for some 32-bit dependencies to creep into your code.
It is uncertain when, or whether, machines with 128-bit address spaces will be introduced. If MAINSAIL is ever ported to such a machine, it may be necessary to eliminate 64-bit dependencies from your code. However, XIDAK does not anticipate the need to do so anytime soon.
27.1. Constants
Beware of constants that are 32-bit dependent, like those in the
following examples:
Possibly32-Bit-Dependent
Works for 32-Bit and 64-Bit MAINSAIL 4 size(longIntegerCode) 31 $sizeInBits(longIntegerCode) - 1 32 $sizeInBits(longIntegerCode) 2L ^ 31 - 1L $maxLongInteger 'HFFFFFFFFL $lbOnes 'H80000000L '1L SHL ($sizeInBits(longIntegerCode)
- 1) DEFINE hexDigitsInAddress = 8;
DEFINE hexDigitsInAddress =
size(addressCode) * 2;
27.2. Alignment Gaps
Currently, no 32-bit MAINSAIL compiler pads record layouts with gaps for alignment purposes (see Section 10.13), but all 64-bit systems do. Alignment gaps used by 64-bit MAINSAIL can affect existing code. For example, consider the following code where INTEGERs are 4 bytes, LONG INTEGERs are 8 bytes, and both must be aligned to their size boundary:
i := iLoad(a);
a := displace(a,size(integerCode));
li := liLoad(a);
If a is initially at an 8-byte alignment, the liLoad
fails since a is
only at a 4-byte alignment when the liLoad is executed.
This code works
on 32-bit MAINSAIL implementations, but must be changed before being
executed on 64-bit MAINSAIL. The programmer
has incorrectly assumed that a
LONG INTEGER can immediately follow an INTEGER
in memory, with no alignment gaps.
Consider the following C struct:
Assuming a C int is 4 bytes,
in 32-bit MAINSAIL the following class
accurately represent cFoo:
In 64-bit MAINSAIL, with an LP64 C model (in which C
longs and pointers
are each 64 bits), mFoo does not represent cFoo
since mFoo.f is 8 bytes whereas cFoo.f is 4 bytes.
The correct approach
is to use the C data type names introduced in Version 15 of MAINSAIL:
This works for both 32-bit MAINSAIL and 64-bit MAINSAIL.
Similarly, a C procedure that takes an int array could be
declared in 32-bit MAINSAIL as:
This should be declared as:
which works for both 32-bit and 64-bit MAINSAIL.
A MAINSAIL entry FLI procedure that takes
an ADDRESS a of a C int and
accesses the int using liLoad(a) should instead use
$liLoadSized(a,0,$cIntCode).
Another example is a buffer created by C, packed with C shorts. If
MAINSAIL has been passed an ADDRESS a
that points to the buffer, then
the following code can be used in 32-bit MAINSAIL
on big-endian machines to access the shorts:
This code assumes a C short
is 16 bits and a MAINSAIL long bits is 32
bits; this assumption is incorrect in 64-bit MAINSAIL. Portable code
for the above is as follows:
27.3. Relationship between MAINSAIL and C Data Types
In the 32-bit world,
MAINSAIL INTEGERs and LONG INTEGERs, and C ints and
longs, are all 4 bytes.
struct cFoo {int f;};
CLASS mFoo (LONG INTEGER f);
$ALIGN CLASS mFoo ($CINT f);
PROCEDURE foo (LONG INTEGER ARRAY(0 TO *) ary);
PROCEDURE foo ($CINT ARRAY(0 TO *) ary);
DOB read(a,bb);
firstShort := bb SHR 16; secondShort := bb MSK 'HFFFFL;
... END;
DOB firstShort := $lbLoadSized(a,0,$cShortCode);
a := displace(a,$shortSize);
secondShort := $lbLoadSized(a,0,$cShortCode);
a := displace(a,$shortSize);
... END;
27.4. Assumption That
size(realCode) = size(longBitsCode))
Even though it was never documented that
size(realCode) = size(longBitsCode),
this was true until the first implementation of
64-bit MAINSAIL. The
following procedure is not portable:
LONG BITS PROCEDURE realToLb (REAL r);
BEGIN
OWN ADDRESS a;
IF NOT a THEN a := newScratch(size(realCode));
store(a,r); RETURN(lbLoad(a)) END;
The following version currently works on both 32-bit and 64-bit MAINSAILs:
LONG BITS PROCEDURE realToLb (REAL r);
BEGIN
OWN ADDRESS a;
IF NOT a THEN a := newScratch(size(realCode));
store(a,r);
# following IFC allows for case that a MAINSAIL real is 8 bytes
RETURN(
IFC size(realCode) = 4 THENC
$lbLoadSized(a,0,$longBits4Code)
$EFC size(longBitsCode) = size(realCode) THENC
lbLoad(a)
ELSEC MESSAGE "realToLb: impossible","error"; '0L ENDC);
END;
Note that the language does not guarantee that the REAL
data type occupies only 4 bytes.
It is possible that a future implementation of MAINSAIL might provide
8-byte REALs.
To allow it to work on 64-bit machines,
add the following as the first statement:
27.5. Assumption That size(longBitsCode) = 32
The following procedure works for 32-bit but not for 64-bit MAINSAIL:
INTEGER PROCEDURE findFirstSetBit (LONG BITS bb);
BEGIN
INTEGER n;
IF NOT bb THEN RETURN(-1); # no bits set
n _ 0;
IF bb NTST 'HFFFFL THENB bb .SHR 16; n .+ 16 END;
IF bb NTST 'HFFL THENB bb .SHR 8; n .+ 8 END;
IF bb NTST 'HFL THENB bb .SHR 4; n .+ 4 END;
IF bb NTST '3L THENB bb .SHR 2; n .+ 2 END;
IF bb NTST '1L THEN n .+ 1;
RETURN(n) END;
IFC size(longBitsCode) = 8 THENC
IF bb NTST 'HFFFFFFFFL THENB bb .SHR 32; n .+ 32 END;
ENDC
27.6. Data Files
Data files that contain LONG INTEGERs and long bits are not portable
between 32-bit and 64-bit MAINSAIL.
27.7. FLI Parameter Data Types and C Data Type Macros
It is strongly recommended (starting with Version 16.29 of MAINSAIL)
that you use the appropriate
C data type macros ($CSHORT, $CINT, etc.;
see Appendix L)
when declaring parameter types for FLI procedures
(this is not recommended in earlier versions of MAINSAIL
because the FLI compiler did
not take explicit sizes of parameter data types into account).
For example, instead of declaring an FLI procedure:
PROCEDURE p (MODIFIES LONG INTEGER s); # WRONG!
declare:
PROCEDURE p (MODIFIES $CINT s);
because the latter will work on any platform, provided that the corresponding C function declares its parameter as a int, whereas the first form would not work on any current 64-bit platform, because MAINSAIL's LONG INTEGER is the same size as a C long, but not an int, on those platforms.
For FLI code that predates Version 16.29 and therefore
does not use the C data type macros, consult the appropriate
operating-system-specific documentation (e.g.,
Table 10–1 of the User's Guide for MAINSAIL on UNIX for UNIX) for the correspondence of
MAINSAIL and C data types in FLI procedures.
27.8. PDF
MAINSAIL'S PDF (portable data format) uses 2-byte BOOLEANs, INTEGERs and BITS, 4-byte LONG INTEGERs and LONG BITS, and 8-byte LONG REALs. This results in restrictions on the range of INTEGER and BITS values in PDF data for 32-bit MAINSAIL, and, in addition, LONG INTEGER and LONG BITS values for 64-bit MAINSAIL.
If you attempt to write out to a PDF file a LONG INTEGER or LONG BITS value that exceeds the 32-bit range, the value will be silently truncated to 32 bits. If this poses a problem, please contact XIDAK for assistance.