Begin to add long long to C compiler for linux386.

Add long long type, but without literals; you can't say '123LL' yet.
You can try constant operations, like `(long long)123 + 1`, but the
compiler's `arith` type might not be wide enough.  Conversions,
shifts, and some other operations don't work in i386 ncg; I am using a
union instead of conversions:

	union q {
		long long ll;
		unsigned long long ull;
		int i[2];
	};

Hack plat/linux386/descr to enable long long (size 8, alignment 4)
only for this platform.  The default for other platforms is to disable
long long (size -1).

In lang/cem/cemcom.ansi,

 - BigPars, SmallPars: Add default size, alignment of long long.
 - align.h: Add lnglng_align.
 - arith.c: Convert arithmetic operands to long long or unsigned long
   long when necessary; avoid conversion from long long to long.
   Allow long long as an arithmetic, integral, or logical operand.
 - ch3.c: Handle long long like int and long when erroneously applying
   a selector, like `long long ll; ll.member` or `ll->member`.  Add
   long long to integral and arithmetic types.
 - code.c: Add long long to type stabs for debugging.
 - conversion.c: Add long long to integral conversions.
 - cstoper.c: Write masks up to full_mask[8].  Add FIXME comment.
 - declar.g: Parse `long long` in code.
 - decspecs.c: Understand long long in type declarations.
 - eval.c: Add long long to operations, to generate code like `adi 8`.
   Don't use `ldc` with constant over 4 bytes.
 - ival.g: Allow long long in initializations.
 - main.c: Set lnglng_type and related values.
 - options.c: Add option like `-Vq8.4` to set long long to size 8,
   alignment 4.  I chose 'q', because Perl's pack and Ruby's
   Array#pack use 'q' for 64-bit or long long values; it might be a
   reference to BSD's old quad_t alias for long long.
 - sizes.h: Add lnglng_size.
 - stab.c: Allow long long when writing the type stab for debugging.
   Switch from calculating the ranges to hardcoding them in strings;
   add 8-byte ranges as a special case.  This also hardcodes the
   unsigned 4-byte range as "0;-1".  Before it was either "0;-1" or
   "0;4294967295", depending on sizeof(long) in the compiler.
 - struct.c: Try long long bitfield, but it will probably give the
   error, "bit field type long long does not fit in a word".
 - switch.c: Update comment.
 - tokenname.c: Define LNGLNG (long long) like LNGDBL (long double).
 - type.c, type.str: Add lnglng_type and ulnglng_type.  Add function
   no_long_long() to check if long long is disabled.
This commit is contained in:
George Koehler 2019-09-02 11:24:44 -04:00
parent 893df4b79b
commit 007a63d529
22 changed files with 187 additions and 56 deletions

View file

@ -55,6 +55,7 @@
#define SZ_WORD 4
#define SZ_INT 4
#define SZ_LONG 4
#define SZ_LNGLNG -1
#define SZ_FLOAT 4
#define SZ_DOUBLE 8
#define SZ_LNGDBL 8 /* for now */
@ -66,6 +67,7 @@
#define AL_WORD SZ_WORD
#define AL_INT SZ_WORD
#define AL_LONG SZ_WORD
#define AL_LNGLNG SZ_WORD
#define AL_FLOAT SZ_WORD
#define AL_DOUBLE SZ_WORD
#define AL_LNGDBL SZ_WORD

View file

@ -55,6 +55,7 @@
#define SZ_WORD 4
#define SZ_INT 4
#define SZ_LONG 4
#define SZ_LNGLNG -1
#define SZ_FLOAT 4
#define SZ_DOUBLE 8
#define SZ_LNGDBL 8 /* for now */
@ -66,6 +67,7 @@
#define AL_WORD SZ_WORD
#define AL_INT SZ_WORD
#define AL_LONG SZ_WORD
#define AL_LNGLNG SZ_WORD
#define AL_FLOAT SZ_WORD
#define AL_DOUBLE SZ_WORD
#define AL_LNGDBL SZ_WORD

View file

@ -10,6 +10,7 @@
#ifndef NOCROSS
extern int
short_align, word_align, int_align, long_align,
lnglng_align,
float_align, double_align, lngdbl_align,
pointer_align,
struct_align, union_align;
@ -18,6 +19,7 @@ extern int
#define word_align ((int)AL_WORD)
#define int_align ((int)AL_INT)
#define long_align ((int)AL_LONG)
#define lnglng_align ((int)AL_LNGLNG)
#define float_align ((int)AL_FLOAT)
#define double_align ((int)AL_DOUBLE)
#define lngdbl_align ((int)AL_LNGDBL)

View file

@ -12,6 +12,7 @@
*/
#include <assert.h>
#include <stddef.h>
#include "parameters.h"
#include <alloc.h>
#include <flt_arith.h>
@ -45,7 +46,8 @@ void arithbalance(register struct expr **e1p, int oper, register struct expr **e
have a floating type, in which case the flags shouldn't
travel upward in the expression tree.
*/
register int t1, t2, u1, u2;
struct type *convert1, *convert2;
int t1, t2, u1, u2;
int shifting = (oper == LEFT || oper == RIGHT
|| oper == LEFTAB || oper == RIGHTAB);
int ptrdiff = 0;
@ -56,9 +58,11 @@ void arithbalance(register struct expr **e1p, int oper, register struct expr **e
if (int_size != pointer_size) {
if (ptrdiff = ((*e1p)->ex_flags & EX_PTRDIFF)
|| ((*e2p)->ex_flags & EX_PTRDIFF)) {
if (!((*e1p)->ex_flags & EX_PTRDIFF) && t1 == LONG)
if (!((*e1p)->ex_flags & EX_PTRDIFF)
&& (t1 == LONG || t1 == LNGLNG))
ptrdiff = 0;
if (!((*e2p)->ex_flags & EX_PTRDIFF) && t2 == LONG
if (!((*e2p)->ex_flags & EX_PTRDIFF)
&& (t2 == LONG || t2 == LNGLNG)
&& !shifting)
ptrdiff = 0;
}
@ -67,7 +71,9 @@ void arithbalance(register struct expr **e1p, int oper, register struct expr **e
(*e2p)->ex_flags &= ~EX_PTRDIFF;
}
/* Now t1 and t2 are either INT, LONG, FLOAT, DOUBLE, or LNGDBL */
/* Now t1 and t2 are either INT, LONG, LNGLNG,
FLOAT, DOUBLE, or LNGDBL
*/
/* If any operand has the type long double, the other operand
is converted to long double.
@ -82,11 +88,12 @@ void arithbalance(register struct expr **e1p, int oper, register struct expr **e
}
return;
} else if (t2 == LNGDBL) {
if (t1 != LNGDBL)
if (t1 != LNGDBL) {
if (t1 == DOUBLE || t1 == FLOAT)
float2float(e1p, lngdbl_type);
else
int2float(e1p, lngdbl_type);
}
return;
}
@ -120,38 +127,63 @@ void arithbalance(register struct expr **e1p, int oper, register struct expr **e
return;
}
/* Now they are INT or LONG */
/* Now they are INT, LONG or LNGLNG */
u1 = (*e1p)->ex_type->tp_unsigned;
u2 = (*e2p)->ex_type->tp_unsigned;
convert1 = NULL;
convert2 = NULL;
/* If either operand has type unsigned long int, the other
operand is converted to unsigned long int.
*/
if (t1 == LONG && u1 && (t2 != LONG || !u2))
t2 = int2int(e2p, ulong_type);
else if (t2 == LONG && u2 && (t1 != LONG || !u1)
&& !shifting) /* ??? */
t1 = int2int(e1p, ulong_type);
/* If either operand is a long long, the other operand
is converted to long long; else if either operand is
a long, the other operand is converted to a long.
/* If one operand has type long int and the other has type unsigned
int, if a long int can represent all values of an unsigned int,
the operand of type unsigned int is converted to long int; if
a long int cannot represent all values of an unsigned int,
both operands are converted to unsigned long int.
If one operand is signed and the other operand is
unsigned, if the signed type can represent all values
of the unsigned type, the unsigned operand is
converted to the signed type, else both operands are
converted to an unsigned type.
*/
if (t1 == LONG && t2 == INT && u2)
t2 = int2int(e2p, (int_size<long_size)? long_type : ulong_type);
else if (t2 == LONG && t1 == INT && u1 && !shifting) /* ??? */
t1 = int2int(e1p, (int_size<long_size)? long_type : ulong_type);
if (t1 == LNGLNG && u1 && (t2 != LNGLNG || !u2))
convert2 = ulnglng_type;
else if (t2 == LNGLNG && u2 && (t1 != LNGLNG || !u1))
convert1 = ulnglng_type;
else if (t1 == LNGLNG && t2 != LNGLNG && u2) {
if ((t2 == LONG ? long_size : int_size) < lnglng_size)
convert2 = lnglng_type;
else
convert1 = convert2 = ulnglng_type;
} else if (t2 == LNGLNG && t1 != LNGLNG && u1) {
if ((t1 == LONG ? long_size : int_size) < lnglng_size)
convert1 = lnglng_type;
else
convert1 = convert2 = ulnglng_type;
} else if (t1 == LNGLNG && t2 != LNGLNG)
convert2 = lnglng_type;
else if (t2 == LNGLNG && t1 != LNGLNG)
convert1 = lnglng_type;
else if (t1 == LONG && u1 && (t2 != LONG || !u2))
convert2 = ulong_type;
else if (t2 == LONG && u2 && (t1 != LONG || !u1))
convert1 = ulong_type;
else if (t1 == LONG && t2 == INT && u2) {
if (int_size < long_size)
convert2 = long_type;
else
convert1 = convert2 = ulong_type;
} else if (t2 == LONG && t1 == INT && u1) {
if (int_size < long_size)
convert1 = long_type;
else
convert1 = convert2 = ulong_type;
} else if (t1 == LONG && t2 != LONG)
convert2 = long_type;
else if (t2 == LONG && t1 != LONG)
convert1 = long_type;
/* If either operand has type long int, the other operand is con-
verted to long int.
*/
if (t1 == LONG && t2 != LONG)
t2 = int2int(e2p, long_type);
else
if (t2 == LONG && t1 != LONG && !shifting) /* ??? */
t1 = int2int(e1p, long_type);
if (convert1 && !shifting) /* ??? */
t1 = int2int(e1p, convert1);
if (convert2)
t2 = int2int(e2p, convert2);
u1 = (*e1p)->ex_type->tp_unsigned;
u2 = (*e2p)->ex_type->tp_unsigned;
@ -161,10 +193,10 @@ void arithbalance(register struct expr **e1p, int oper, register struct expr **e
Otherwise, both operands have type int.
*/
if (u1 && !u2 && !shifting)
t2 = int2int(e2p, (t1 == LONG) ? ulong_type : uint_type);
t2 = int2int(e2p, uint_type);
else
if (!u1 && u2 && !shifting)
t1 = int2int(e1p, (t2 == LONG) ? ulong_type : uint_type);
t1 = int2int(e1p, uint_type);
if (int_size != pointer_size) {
if (ptrdiff) {
@ -259,6 +291,7 @@ any2arith(register struct expr **expp, register int oper)
break;
case INT:
case LONG:
case LNGLNG:
break;
case ENUM:
#ifndef LINT
@ -457,7 +490,7 @@ void opnd2integral(register struct expr **expp, int oper)
{
register int fund = (*expp)->ex_type->tp_fund;
if (fund != INT && fund != LONG) {
if (fund != INT && fund != LONG && fund != LNGLNG) {
expr_error(*expp, "%s operand to %s",
symbol2str(fund), symbol2str(oper));
erroneous2int(expp);
@ -486,6 +519,7 @@ void opnd2logical(register struct expr **expp, int oper)
case SHORT:
case INT:
case LONG:
case LNGLNG:
case ENUM:
case POINTER:
case FLOAT:

View file

@ -58,6 +58,7 @@ void ch3sel(struct expr **expp, int oper, struct idf *idf)
break;
case INT:
case LONG:
case LNGLNG:
/* An error is given in idf2sdef() */
ch3cast(expp, CAST, pa_type);
sd = idf2sdef(idf, tp);
@ -82,6 +83,7 @@ void ch3sel(struct expr **expp, int oper, struct idf *idf)
break;
case INT:
case LONG:
case LNGLNG:
/* warning will be given by idf2sdef() */
break;
default:
@ -679,6 +681,7 @@ int is_integral_type(register struct type *tp)
case SHORT:
case INT:
case LONG:
case LNGLNG:
case ENUM:
return 1;
#ifndef NOBITFIELD
@ -697,6 +700,7 @@ int is_arith_type(register struct type *tp)
case SHORT:
case INT:
case LONG:
case LNGLNG:
case ENUM:
case FLOAT:
case DOUBLE:

View file

@ -101,6 +101,10 @@ void init_code(char *dst_file)
stb_typedef(ushort_type, "unsigned short");
stb_typedef(ulong_type, "unsigned long");
stb_typedef(uint_type, "unsigned int");
if (lnglng_size >= 0) {
stb_typedef(lnglng_type, "long long");
stb_typedef(ulnglng_type, "unsigned long long");
}
stb_typedef(float_type, "float");
stb_typedef(double_type, "double");
stb_typedef(lngdbl_type, "long double");

View file

@ -137,6 +137,7 @@ static int convtype(register struct type *tp)
case INT:
case ERRONEOUS:
case LONG:
case LNGLNG:
case ENUM:
return tp->tp_unsigned ? T_UNSIGNED : T_SIGNED;
case FLOAT:

View file

@ -175,7 +175,11 @@ void init_cst(void)
register int i = 0;
register arith bt = (arith)0;
while (!(bt < 0)) {
/* FIXME arith is insufficient for long long. We ignore
this problem and write masks up to full_mask[8], but
masks are wrong after bt < 0.
*/
while (!(bt < 0) || i < 8) {
bt = (bt << 8) + 0377, i++;
if (i > MAXSIZE)
fatal("array full_mask too small for this machine");

View file

@ -123,9 +123,13 @@ single_decl_specifier /* non_empty */ (register struct decspecs *ds;)
}
|
[ SHORT | LONG ]
{ if (ds->ds_size)
error("repeated size specifier");
ds->ds_size = DOT;
{ if (ds->ds_size == LONG && DOT == LONG)
ds->ds_size = LNGLNG;
else {
if (ds->ds_size)
error("repeated size specifier");
ds->ds_size = DOT;
}
}
|
[ SIGNED | UNSIGNED ]

View file

@ -69,7 +69,8 @@ void do_decspecs(register struct decspecs *ds)
}
if (ds->ds_size)
{
register int ds_isshort = (ds->ds_size == SHORT);
int ds_isshort = (ds->ds_size == SHORT);
int ds_islong = (ds->ds_size == LONG);
if (ds->ds_typedef)
goto SIZE_ERROR;
@ -78,10 +79,18 @@ void do_decspecs(register struct decspecs *ds)
{
if (ds_isshort)
tp = short_type;
else
else if (ds_islong)
tp = long_type;
else
{
assert(ds->ds_size == LNGLNG);
if (no_long_long())
tp = error_type;
else
tp = lnglng_type;
}
}
else if (tp == double_type && !ds_isshort)
else if (tp == double_type && ds_islong)
{
tp = lngdbl_type;
}
@ -122,6 +131,11 @@ void do_decspecs(register struct decspecs *ds)
if (ds_isunsigned)
tp = ulong_type;
}
else if (tp == lnglng_type)
{
if (ds_isunsigned)
tp = ulnglng_type;
}
else
{
SIGN_ERROR: error("%s with illegal type",

View file

@ -133,13 +133,15 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
case '+':
/* We have the following possibilities :
int + int, pointer + int, pointer + long,
long + long, double + double
long + long, long long + long long,
double + double
*/
operands(expr, gencode);
if (gencode) {
switch (tp->tp_fund) {
case INT:
case LONG:
case LNGLNG:
if (tp->tp_unsigned)
C_adu(tp->tp_size);
else
@ -165,6 +167,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
switch (tp->tp_fund) {
case INT:
case LONG:
case LNGLNG:
case POINTER:
C_ngi(tp->tp_size);
break;
@ -181,7 +184,8 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
}
/* else binary; we have the following flavours:
int - int, pointer - int, pointer - long,
pointer - pointer, long - long, double - double
pointer - pointer, long - long,
long long - long long, double - double
*/
operands(expr, gencode);
if (!gencode)
@ -189,6 +193,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
switch (tp->tp_fund) {
case INT:
case LONG:
case LNGLNG:
if (tp->tp_unsigned)
C_sbu(tp->tp_size);
else
@ -224,6 +229,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
switch (tp->tp_fund) {
case INT:
case LONG:
case LNGLNG:
case POINTER:
if (tp->tp_unsigned)
C_mlu(tp->tp_size);
@ -246,6 +252,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
switch (tp->tp_fund) {
case INT:
case LONG:
case LNGLNG:
case POINTER:
if (tp->tp_unsigned)
C_dvu(tp->tp_size);
@ -264,7 +271,8 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
break;
case '%':
operands(expr, gencode);
assert(tp->tp_fund==INT || tp->tp_fund==LONG);
assert(tp->tp_fund==INT || tp->tp_fund==LONG ||
tp->tp_fund==LNGLNG);
if (gencode)
if (tp->tp_unsigned)
C_rmu(tp->tp_size);
@ -301,6 +309,7 @@ void EVAL(register struct expr *expr, int val, int code, label true_label, label
switch (tp->tp_fund) {
case INT:
case LONG:
case LNGLNG:
if (left->ex_type->tp_unsigned)
C_cmu(size);
else
@ -736,6 +745,7 @@ void assop(register struct type *type, int oper)
case SHORT:
case INT:
case LONG:
case LNGLNG:
case ENUM:
switch (oper) {
case PLUSAB:
@ -1014,10 +1024,13 @@ void load_val(register struct expr *expr, int rlval)
void load_cst(arith val, arith siz)
{
/* EM can't encode ldc with constant over 4 bytes.
Such a constant must go into rom.
*/
if ((int)siz <= (int)word_size)
C_loc(val);
else
if ((int)siz == (int)dword_size)
if ((int)siz == (int)dword_size && (int)dword_size <= 4)
C_ldc(val);
else {
label datlab;

View file

@ -518,6 +518,7 @@ void check_ival(struct expr **expp, register struct type *tp)
case SHORT:
case INT:
case LONG:
case LNGLNG:
case ENUM:
case POINTER:
ch3cast(expp, '=', tp);

View file

@ -57,6 +57,7 @@ arith
dword_size = (2 * SZ_WORD),
int_size = SZ_INT,
long_size = SZ_LONG,
lnglng_size = SZ_LNGLNG,
float_size = SZ_FLOAT,
double_size = SZ_DOUBLE,
lngdbl_size = SZ_LNGDBL,
@ -67,6 +68,7 @@ int
word_align = AL_WORD,
int_align = AL_INT,
long_align = AL_LONG,
lnglng_align = AL_LNGLNG,
float_align = AL_FLOAT,
double_align = AL_DOUBLE,
lngdbl_align = AL_LNGDBL,
@ -227,6 +229,10 @@ static void init(void)
long_type = standard_type(LONG, 0, long_align, long_size);
ulong_type = standard_type(LONG, UNSIGNED, long_align, long_size);
lnglng_type = standard_type(LNGLNG, 0, lnglng_align, lnglng_size);
ulnglng_type = standard_type(LNGLNG, UNSIGNED, lnglng_align,
lnglng_size);
float_type = standard_type(FLOAT, 0, float_align, float_size);
double_type = standard_type(DOUBLE, 0, double_align, double_size);
lngdbl_type = standard_type(LNGDBL, 0, lngdbl_align, lngdbl_size);

View file

@ -159,6 +159,12 @@ next_option: /* to allow combined one-char options */
if (algn != 0)
long_align = algn;
break;
case 'q': /* long long */
if (sz != (arith)0)
lnglng_size = sz;
if (algn != 0)
lnglng_align = algn;
break;
case 'f': /* float */
if (sz != (arith)0)
float_size = sz;

View file

@ -10,6 +10,7 @@
#ifndef NOCROSS
extern arith
short_size, word_size, dword_size, int_size, long_size,
lnglng_size,
float_size, double_size, lngdbl_size,
pointer_size;
@ -20,6 +21,7 @@ extern arith max_int, max_unsigned; /* cstoper.c */
#define dword_size ((arith)2*SZ_WORD)
#define int_size ((arith)SZ_INT)
#define long_size ((arith)SZ_LONG)
#define lnglng_size ((arith)SZ_LNGLNG)
#define float_size ((arith)SZ_FLOAT)
#define double_size ((arith)SZ_DOUBLE)
#define lngdbl_size ((arith)SZ_LNGDBL)

View file

@ -74,9 +74,10 @@ static void adds_db_str(char *s)
static void stb_type(register struct type *tp)
{
char buf[128];
char buf[128], *range;
static int stb_count;
long l;
int uns;
if (tp->tp_dbindex > 0)
{
@ -101,18 +102,26 @@ static void stb_type(register struct type *tp)
break;
case INT:
case LONG:
case LNGLNG:
case CHAR:
case SHORT:
l = full_mask[(int) tp->tp_size];
if (tp->tp_unsigned)
switch ((tp->tp_size << 3) + !tp->tp_unsigned)
{
adds_db_str(sprint(buf, "r%d;0;%ld", tp->tp_dbindex, l));
}
else
{
l &= ~(1L << ((int) tp->tp_size * 8 - 1));
adds_db_str(sprint(buf, "r%d;%ld;%ld", tp->tp_dbindex, -l - 1, l));
#define R(s) range = #s; break
case 0010: R(0;255);
case 0011: R(-128;127);
case 0020: R(0;65535);
case 0021: R(-32768;32767);
default: R(0;-1); /* acts as 0;4294967295 */
case 0041: R(-2147483648;2147483647);
/* The stabs reader in gdb(1) needs an octal integer
when its value doesn't fit in type long.
*/
case 0100: R(0;01777777777777777777777);
case 0101: R(01000000000000000000000;0777777777777777777777);
#undef R
}
adds_db_str(sprint(buf, "r%d;%s", tp->tp_dbindex, range));
break;
case FLOAT:
case DOUBLE:

View file

@ -360,6 +360,7 @@ add_field(
case SHORT:
case ENUM:
case LONG:
case LNGLNG:
strict("non-portable field type");
case INT:
/* right type; size OK? */

View file

@ -61,7 +61,7 @@ void code_startswitch(struct expr **expp)
register label l_break = text_label();
register struct switch_hdr *sh = new_switch_hdr();
int fund = any2arith(expp, SWITCH);
/* INT, LONG, FLOAT, DOUBLE or LNGDBL */
/* INT, LONG, LNGLNG, FLOAT, DOUBLE or LNGDBL */
switch (fund) {
case FLOAT:

View file

@ -104,6 +104,7 @@ struct tokenname tkidf[] = { /* names of the identifier tokens */
#ifdef ____
struct tokenname tkfunny[] = { /* internal keywords */
{LNGLNG, "long long"},
{LNGDBL, "long double"},
{ULONG, "unsigned long"},

View file

@ -25,6 +25,7 @@
*/
struct type *schar_type, *uchar_type, *short_type, *ushort_type, *word_type,
*uword_type, *int_type, *uint_type, *long_type, *ulong_type,
*lnglng_type, *ulnglng_type,
*float_type, *double_type, *lngdbl_type, *void_type, *string_type,
*funint_type, *error_type;
@ -291,3 +292,20 @@ void completed(struct type *tp)
atp = atp->next;
}
}
int no_long_long(void)
{
static int shown = 0;
if (lnglng_size < 0)
{
if (!shown)
{
error("no long long for this machine");
shown = 1;
}
return 1;
}
else
return 0;
}

View file

@ -71,6 +71,7 @@ extern struct type
*word_type, *uword_type,
*int_type, *uint_type,
*long_type, *ulong_type,
*lnglng_type, *ulnglng_type,
*float_type, *double_type, *lngdbl_type,
*void_type,
*string_type, *funint_type, *error_type;
@ -93,6 +94,7 @@ void idf2type(struct idf *idf, struct type **tpp);
arith align(arith pos, int al);
struct type * standard_type(int fund, int sgn, int algn, arith sz);
void completed(struct type *tp);
int no_long_long(void);
/* ALLOCDEF "type" 50 */

View file

@ -23,7 +23,8 @@ var CPP_F=-D__unix
var ALIGN=-a0:4 -a1:4 -a2:4 -a3:4 -b0:0x08048054
var C_LIB={PLATFORMDIR}/libc-ansi.a
# bitfields reversed for compatibility with (g)cc.
var CC_ALIGN=-Vr
# long long enabled.
var CC_ALIGN=-Vrq8.4
var OLD_C_LIB={C_LIB}
var MACHOPT_F=-m10
var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr