Skip to content

Commit

Permalink
Begin to add long long to C compiler for linux386.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kernigh committed Sep 2, 2019
1 parent 893df4b commit 007a63d
Show file tree
Hide file tree
Showing 22 changed files with 190 additions and 59 deletions.
2 changes: 2 additions & 0 deletions lang/cem/cemcom.ansi/BigPars
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lang/cem/cemcom.ansi/SmallPars
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lang/cem/cemcom.ansi/align.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down
108 changes: 71 additions & 37 deletions lang/cem/cemcom.ansi/arith.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

#include <assert.h>
#include <stddef.h>
#include "parameters.h"
#include <alloc.h>
#include <flt_arith.h>
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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.
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

/* 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 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.
convert1 = NULL;
convert2 = NULL;

/* 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 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 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 (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 (convert1 && !shifting) /* ??? */
t1 = int2int(e1p, convert1);
if (convert2)
t2 = int2int(e2p, convert2);

u1 = (*e1p)->ex_type->tp_unsigned;
u2 = (*e2p)->ex_type->tp_unsigned;
Expand All @@ -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) {
Expand Down Expand Up @@ -259,6 +291,7 @@ any2arith(register struct expr **expp, register int oper)
break;
case INT:
case LONG:
case LNGLNG:
break;
case ENUM:
#ifndef LINT
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions lang/cem/cemcom.ansi/ch3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions lang/cem/cemcom.ansi/code.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
1 change: 1 addition & 0 deletions lang/cem/cemcom.ansi/conversion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 5 additions & 1 deletion lang/cem/cemcom.ansi/cstoper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
10 changes: 7 additions & 3 deletions lang/cem/cemcom.ansi/declar.g
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]
Expand Down
20 changes: 17 additions & 3 deletions lang/cem/cemcom.ansi/decspecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 007a63d

Please sign in to comment.