mirror of
https://github.com/PDP-10/PCC20.git
synced 2026-01-13 15:17:51 +00:00
1001 lines
23 KiB
C
1001 lines
23 KiB
C
# include "cc.h"
|
||
# include "c3.h"
|
||
|
||
/*
|
||
|
||
C COMPILER
|
||
Phase C: Code Generator
|
||
Section 2: Semantic Interpretation and Optimization
|
||
|
||
Copyright (c) 1977 by Alan Snyder
|
||
|
||
*/
|
||
|
||
/**********************************************************************
|
||
|
||
CODE GENERATOR: SEMANTIC INTERPRETATION ROUTINES
|
||
|
||
chktype
|
||
fudge
|
||
esize
|
||
pointer
|
||
ectype
|
||
pctype
|
||
conv
|
||
conv4
|
||
convert
|
||
convx
|
||
convd
|
||
texpr
|
||
txpr2
|
||
txpr3
|
||
tptrop
|
||
tpsub
|
||
tpadd
|
||
tpcomp
|
||
txinc
|
||
taddr
|
||
telist
|
||
tfarg
|
||
|
||
*/
|
||
|
||
/**********************************************************************
|
||
|
||
CHKTYPE - Check type of enode. If the enode is not of a valid
|
||
type, then issue an error message and return TRUE.
|
||
|
||
M - integer indicating the valid types:
|
||
If M is negative, the enode must be an lvalue.
|
||
If M is zero, the enode is checked only to see if it
|
||
is an lvalue. The valid types are indicated by the
|
||
low-order bits of the absolute value of M:
|
||
|
||
bit 0 - integer
|
||
bit 1 - character
|
||
bit 2 - float
|
||
bit 3 - double
|
||
bit 4 - pointer
|
||
|
||
**********************************************************************/
|
||
|
||
int chktype (ep, m) enode *ep; int m;
|
||
|
||
{type t;
|
||
|
||
if (!ep) return (FALSE);
|
||
t = ep->etype;
|
||
if (m <= 0)
|
||
{m = -m;
|
||
if (!ep->lvalue)
|
||
{errx (2023, cur_op);
|
||
return (TRUE);
|
||
}
|
||
if (m==0) return (FALSE);
|
||
}
|
||
|
||
if (t == TUNDEF) return (TRUE);
|
||
if ((t==TINT) && (m&001) ||
|
||
(t==TCHAR) && (m&002) ||
|
||
(t==TFLOAT) && (m&004) ||
|
||
(t==TDOUBLE) && (m&010) ||
|
||
(m&020) && (pointer(ep))) return (FALSE);
|
||
|
||
errx (2022, cur_op);
|
||
return (TRUE);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
FUDGE - determine constant used in pointer arithmetic
|
||
|
||
**********************************************************************/
|
||
|
||
int fudge (ep) enode *ep;
|
||
|
||
{type t;
|
||
|
||
t = ep->etype;
|
||
if (t->tag != TTPTR) errx (6026);
|
||
return (t->val->size);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
ESIZE - return the size of an expression
|
||
|
||
**********************************************************************/
|
||
|
||
int esize (ep) enode *ep;
|
||
|
||
{return (ep->etype->size);}
|
||
|
||
/**********************************************************************
|
||
|
||
POINTER - is the given expression subtree a pointer
|
||
|
||
**********************************************************************/
|
||
|
||
int pointer (p1) enode *p1;
|
||
|
||
{return (p1 && p1->etype->tag == TTPTR);}
|
||
|
||
/**********************************************************************
|
||
|
||
ECTYPE - return CTYPE of an expression
|
||
|
||
**********************************************************************/
|
||
|
||
int ectype (ep) enode *ep;
|
||
|
||
{return (ctype (ep->etype));}
|
||
|
||
/**********************************************************************
|
||
|
||
PCTYPE - return POINTER TYPE of expression
|
||
|
||
**********************************************************************/
|
||
|
||
int pctype (ep) enode *ep;
|
||
|
||
{return (ectype (ep) - ct_p0);}
|
||
|
||
/**********************************************************************
|
||
|
||
CONV - check for certain types
|
||
|
||
convert CHAR -> INT
|
||
convert FLOAT -> DOUBLE
|
||
convert POINTER -> INT
|
||
|
||
return pointer to enode
|
||
|
||
**********************************************************************/
|
||
|
||
enode *conv (p1, m) enode *p1; int m;
|
||
|
||
{type t;
|
||
|
||
if (!p1) return (NULL);
|
||
if (chktype (p1, m)) return (NULL);
|
||
t = p1->etype;
|
||
if (t==TCHAR || pointer (p1)) p1=convert (p1, TINT);
|
||
else if (t==TFLOAT) p1=convert (p1, TDOUBLE);
|
||
return (p1);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
CONV4 - Convert Two Expressions As Appropriate For Arithmetic
|
||
Operators: Check for CHAR, INT, FLOAT, or DOUBLE.
|
||
Convert to INT or DOUBLE as appropriate (expressions
|
||
passed by reference). Return 0 if result is INT,
|
||
1 if result is DOUBLE, -1 if error.
|
||
|
||
**********************************************************************/
|
||
|
||
int conv4 (epp1, epp2) enode **epp1,**epp2;
|
||
|
||
{type t1;
|
||
type t2;
|
||
|
||
if (chktype (*epp1, 017) | chktype (*epp2, 017))
|
||
return (-1); /* note: NOT || */
|
||
t1 = (*epp1)->etype;
|
||
t2 = (*epp2)->etype;
|
||
if (t1==TFLOAT || t1==TDOUBLE || t2==TFLOAT || t2==TDOUBLE)
|
||
{*epp1 = convert (*epp1, TDOUBLE);
|
||
*epp2 = convert (*epp2, TDOUBLE);
|
||
return (1);
|
||
}
|
||
else
|
||
{*epp1 = convert (*epp1, TINT);
|
||
*epp2 = convert (*epp2, TINT);
|
||
return (0);
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
CONVERT - convert expression (EP) to given type (T)
|
||
|
||
**********************************************************************/
|
||
|
||
enode *convert (ep, t) enode *ep; type t;
|
||
{return (convd (ep, ctype (t), t));}
|
||
|
||
/**********************************************************************
|
||
|
||
CONVX - Convert expression to a given CTYPE.
|
||
(Type field will be set to TUNDEF.)
|
||
|
||
**********************************************************************/
|
||
|
||
enode *convx (ep, ct) enode *ep;
|
||
{return (convd (ep, ct, TUNDEF));}
|
||
|
||
/**********************************************************************
|
||
|
||
CONVD - Real Conversion Routine
|
||
|
||
**********************************************************************/
|
||
|
||
# define _BAD 0177 /* illegal conversion */
|
||
# define _SAME 0176 /* identity conversion */
|
||
# define _STR 0175 /* structure : structure */
|
||
|
||
char cvt[10][10] {
|
||
_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,
|
||
_BAD,_STR,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,_BAD,
|
||
_BAD,_BAD,_SAME,0040,0041,0042,_BAD,_BAD,_BAD,_BAD,
|
||
_BAD,_BAD,0043,_SAME,0044,0045,0046,0047,0050,0051,
|
||
_BAD,_BAD,0052,0053,_SAME,0054,_BAD,_BAD,_BAD,_BAD,
|
||
_BAD,_BAD,0055,0056,0057,_SAME,_BAD,_BAD,_BAD,_BAD,
|
||
_BAD,_BAD,_BAD,0060,_BAD,_BAD,_SAME,0061,0062,0063,
|
||
_BAD,_BAD,_BAD,0064,_BAD,_BAD,0065,_SAME,0066,0067,
|
||
_BAD,_BAD,_BAD,0070,_BAD,_BAD,0071,0072,_SAME,0073,
|
||
_BAD,_BAD,_BAD,0074,_BAD,_BAD,0075,0076,0077,_SAME};
|
||
|
||
enode *convd (ep, ct, t) enode *ep; type t;
|
||
|
||
{int op;
|
||
switch (op = cvt[ectype (ep)][ct]) {
|
||
case _BAD: errx (2026, cur_op);
|
||
return (NULL);
|
||
case _SAME:
|
||
case _STR: return (ep);
|
||
}
|
||
return (mkenode (op, t, 0, ep, NULL));
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TEXPR - Translate expression from syntax tree form
|
||
to expanded form with AMOPs.
|
||
|
||
**********************************************************************/
|
||
|
||
/* definition of OPDOPE fields */
|
||
|
||
# define NSUBTREE 0003 /* number of subtrees */
|
||
# define UNARY 1
|
||
# define BINARY 2
|
||
# define LVFLAG 0004 /* indicates to check for left lvalue */
|
||
# define CVMODE 0030 /* indicates some default conversions */
|
||
# define BITSTRING 010 /* check for int or char */
|
||
# define INTEGER 010 /* check for int or char */
|
||
# define ARITH 020 /* do arithmetic conversions */
|
||
# define LOGICAL 030 /* check for fundamental or ptr */
|
||
# define PTFLAG 0040 /* indicates special action on pointer */
|
||
# define OPFLAG 0100 /* indicates to set OP */
|
||
# define EQOP 0200 /* indicates op is an =OP */
|
||
# define SWFLAG 0400 /* indicates to execute main switch */
|
||
|
||
int opdope [] { /* info on some node ops */
|
||
|
||
0,
|
||
0,
|
||
/* idn */ SWFLAG + OPFLAG,
|
||
/* int */ SWFLAG + OPFLAG,
|
||
/* float */ SWFLAG + OPFLAG,
|
||
/* string */ SWFLAG + OPFLAG,
|
||
/* call */ SWFLAG + OPFLAG,
|
||
/* ? */ SWFLAG + OPFLAG + BINARY,
|
||
/* ++x */ SWFLAG + UNARY,
|
||
/* x++ */ SWFLAG + UNARY,
|
||
/* --x */ SWFLAG + UNARY,
|
||
/* x-- */ SWFLAG + UNARY,
|
||
/* *p */ SWFLAG + UNARY,
|
||
/* &x */ SWFLAG + LVFLAG + UNARY,
|
||
/* -x */ SWFLAG + UNARY,
|
||
/* ~x */ SWFLAG + OPFLAG + UNARY,
|
||
/* !x */ OPFLAG + LOGICAL + UNARY,
|
||
/* x & y */ OPFLAG + BITSTRING + BINARY,
|
||
/* x | y */ OPFLAG + BITSTRING + BINARY,
|
||
/* x ^ y */ OPFLAG + BITSTRING + BINARY,
|
||
/* x % y */ OPFLAG + INTEGER + BINARY,
|
||
/* x / y */ OPFLAG + ARITH + BINARY,
|
||
/* x * y */ OPFLAG + ARITH + BINARY,
|
||
/* x - y */ OPFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x + y */ OPFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x = y */ SWFLAG + LVFLAG + BINARY,
|
||
/* x == y */ SWFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x != y */ SWFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x < y */ SWFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x > y */ SWFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x <= y */ SWFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x >= y */ SWFLAG + PTFLAG + ARITH + BINARY,
|
||
/* x << y */ OPFLAG + BITSTRING + BINARY,
|
||
/* x >> y */ OPFLAG + BITSTRING + BINARY,
|
||
/* x =>> y */ EQOP + OPFLAG + LVFLAG + BITSTRING + BINARY,
|
||
/* x =<< y */ EQOP + OPFLAG + LVFLAG + BITSTRING + BINARY,
|
||
/* x =+ y */ EQOP + OPFLAG + PTFLAG + LVFLAG + ARITH + BINARY,
|
||
/* x =- y */ EQOP + OPFLAG + PTFLAG + LVFLAG + ARITH + BINARY,
|
||
/* x =* y */ EQOP + OPFLAG + LVFLAG + ARITH + BINARY,
|
||
/* x =/ y */ EQOP + OPFLAG + LVFLAG + ARITH + BINARY,
|
||
/* x =% y */ EQOP + OPFLAG + LVFLAG + INTEGER + BINARY,
|
||
/* x =& y */ EQOP + OPFLAG + LVFLAG + BITSTRING + BINARY,
|
||
/* x =^ y */ EQOP + OPFLAG + LVFLAG + BITSTRING + BINARY,
|
||
/* x =| y */ EQOP + OPFLAG + LVFLAG + BITSTRING + BINARY,
|
||
/* x && y */ OPFLAG + LOGICAL + BINARY,
|
||
/* x || y */ OPFLAG + LOGICAL + BINARY,
|
||
/* x . y */ SWFLAG + UNARY,
|
||
/* x : y */ SWFLAG + OPFLAG + BINARY,
|
||
/* x , y */ SWFLAG + OPFLAG + BINARY,
|
||
/* sizeof x */ SWFLAG
|
||
};
|
||
|
||
enode *texpr (np) int *np;
|
||
|
||
{enode *p1, *p2;
|
||
int errflag;
|
||
|
||
if (!exprlev) e_free();
|
||
++exprlev;
|
||
|
||
p1 = p2 = NULL;
|
||
errflag = FALSE;
|
||
switch (opdope[np[0]] & NSUBTREE) {
|
||
case BINARY: if (!(p2 = texpr (np[2]))) errflag = TRUE;
|
||
case UNARY: if (!(p1 = texpr (np[1]))) errflag = TRUE;
|
||
}
|
||
if (!errflag) p1 = txpr2 (np, p1, p2);
|
||
else p1 = NULL;
|
||
--exprlev;
|
||
return (p1);
|
||
}
|
||
|
||
enode *txpr2 (np, p1, p2) int *np; enode *p1, *p2;
|
||
|
||
{enode *ep;
|
||
type t;
|
||
|
||
# ifndef SCRIMP
|
||
|
||
if (aflag) cprint ("%2d TXPR2 %o[%d,%o,%o]\n",
|
||
exprlev, np, np[0], p1, p2);
|
||
|
||
# endif
|
||
|
||
ep = txpr3 (np, p1, p2);
|
||
if (ep && exprlev != aquote && (t=ep->etype)->tag==TTARRAY)
|
||
{ep->etype = t = t->val;
|
||
ep = taddr (ep);
|
||
ep->etype = mkptr (t);
|
||
}
|
||
|
||
# ifndef SCRIMP
|
||
|
||
if (aflag)
|
||
{if (ep) cprint ("%2d TXPR2 RETURNS %o [%o,%o,%o]\n",
|
||
exprlev, ep, ep->op, ep->ep1, ep->ep2);
|
||
else cprint ("%2d TXPR2 RETURNS 0\n", exprlev);
|
||
}
|
||
|
||
# endif
|
||
|
||
return (ep);
|
||
}
|
||
|
||
enode *txpr3 (np, p1, p2) int *np; enode *p1, *p2;
|
||
|
||
{field *fp;
|
||
type t;
|
||
int i, j, lvalue, op, eval, dope, cop, *ip;
|
||
|
||
dope = opdope[cop=np[0]];
|
||
eval = lvalue = 0;
|
||
t = TINT;
|
||
cur_op = cop;
|
||
|
||
if (dope & LVFLAG)
|
||
{if (chktype (p1, 0)) return (NULL);
|
||
op = 1;
|
||
}
|
||
else op = 0;
|
||
|
||
if ((dope & PTFLAG) && (pointer(p1) || pointer(p2)))
|
||
return (tptrop (cop, p1, p2));
|
||
|
||
switch (dope & CVMODE) {
|
||
case BITSTRING: p1 = conv (p1, 003);
|
||
p2 = conv (p2, 003);
|
||
if (!p1 || !p2) return (NULL);
|
||
break;
|
||
case ARITH: switch (conv4 (&p1, &p2)) {
|
||
case 1: t = TDOUBLE; op =+ 2; break;
|
||
case -1: return (NULL);
|
||
}
|
||
break;
|
||
case LOGICAL: if (chktype (p1, 037) | chktype (p2, 037))
|
||
return (NULL); /* note: NOT || */
|
||
}
|
||
if (dope & OPFLAG) op =+ opbop[cop];
|
||
if (dope & EQOP)
|
||
{if (!p1->lvalue || undfop (op))
|
||
|
||
/* lvalue==0 indicates an =op to a character or a float -
|
||
p1 is a conversion operator
|
||
|
||
convert to an assignment a = a op b with the
|
||
subtree "a" pointed to by both operators
|
||
|
||
*/
|
||
|
||
{p2 = mkenode (op-1, t, lvalue, p1, p2);
|
||
if (!p1->lvalue) p1 = p1->ep1; /* the lvalue */
|
||
p1->lvalue = 2; /* special marker indicating this node
|
||
is a direct descendant of two nodes */
|
||
goto case_assign; /* make assignment */
|
||
}
|
||
}
|
||
|
||
if (dope & SWFLAG) switch (cop) {
|
||
|
||
case n_incb:
|
||
case n_inca:
|
||
case n_decb:
|
||
case n_deca: return (txinc (cop, p1, 1));
|
||
|
||
case n_star:
|
||
case_star: if (chktype (p1, 020)) return (NULL);
|
||
if (p1->op >= e_a0 && p1->op <= e_a3) return (p1->ep1);
|
||
t = p1->etype->val;
|
||
op = e_ind;
|
||
lvalue = 1;
|
||
break;
|
||
|
||
case n_addr: return (taddr (p1));
|
||
|
||
case n_uminus: if (!(p1 = conv (p1, 017))) return (NULL);
|
||
if ((t=p1->etype) == TINT) op = e_iminus;
|
||
else op = e_dminus;
|
||
break;
|
||
|
||
case n_bnot: if (!(p1 = conv (p1, 003))) return (NULL);
|
||
op = e_bnot;
|
||
break;
|
||
|
||
case n_assign:
|
||
case_assign: if (!(p2 = convert (p2, t = p1->etype))) return (NULL);
|
||
op = e_assign;
|
||
break;
|
||
|
||
case n_idn: return (txidn (np+1));
|
||
|
||
case n_int: t = TINT;
|
||
eval = np[1];
|
||
p1 = eval;
|
||
break;
|
||
|
||
case n_float: t = TDOUBLE;
|
||
eval = np[1];
|
||
p1 = eval;
|
||
break;
|
||
|
||
case n_string: t = TACHAR;
|
||
eval = np[1];
|
||
p1 = eval;
|
||
break;
|
||
|
||
case n_eq:
|
||
case n_ne:
|
||
case n_lt:
|
||
case n_gt:
|
||
case n_le:
|
||
case n_ge: op = (t==TDOUBLE ? e_eqd : e_eqi) + cop - n_eq;
|
||
t = TINT;
|
||
break;
|
||
|
||
case n_call: ip = np[1]; /* the function being called */
|
||
if (!(p1 = texpr (ip))) return (NULL);
|
||
if (ip[0] == n_idn && p1->op != e_idn) /* undo coercion */
|
||
{p1 = p1->ep1;
|
||
if (!p1) return (NULL);
|
||
}
|
||
if (p1->etype->tag != TTFUNC)
|
||
{errx (2028);
|
||
return (NULL);
|
||
}
|
||
p2 = telist (np[2]); /* the arguments */
|
||
t = p1->etype->val; /* the return type */
|
||
break;
|
||
|
||
case n_dot: /*
|
||
* Structure Reference
|
||
*
|
||
* Get structure type and search for the named
|
||
* field.
|
||
*
|
||
*/
|
||
|
||
if (p1->etype->tag != TTSTRUCT)
|
||
{errx (2030);
|
||
return (NULL);
|
||
}
|
||
j = np[2]; /* field name */
|
||
fp = p1->etype->val;
|
||
while (fp->name != UNDEF)
|
||
if (fp->name == j) break;
|
||
else ++fp;
|
||
if (fp->name != j) /* field not found */
|
||
{errx (2029, TIDN, j);
|
||
return (NULL);
|
||
}
|
||
t = fp->dtype;
|
||
i = fp->offset;
|
||
p1 = taddr (p1);
|
||
t = mkptr (t);
|
||
j = ctype (t);
|
||
p1 = convx (p1, j);
|
||
p1->etype = t;
|
||
j =- ct_p0;
|
||
p1 = mkenode (e_add0+j, t, 0, p1, intcon(i/spoint[j]));
|
||
goto case_star;
|
||
|
||
case n_qmark: if (chktype (p1, 037)) return (NULL);
|
||
|
||
case n_comma: t = p2->etype; /* fall through */
|
||
break;
|
||
|
||
case n_colon: if (p1->etype != p2->etype)
|
||
{if (p1->etype->tag <= TTDOUBLE &&
|
||
p2->etype->tag <= TTDOUBLE)
|
||
{switch (conv4 (&p1, &p2)) {
|
||
case 1: t = TDOUBLE; break;
|
||
case -1: return (NULL);
|
||
default: t = TINT;
|
||
}
|
||
}
|
||
else
|
||
{errx (2031);
|
||
return (NULL);
|
||
}
|
||
}
|
||
else t = p1->etype;
|
||
break;
|
||
|
||
case n_sizeof: i = aquote;
|
||
aquote = exprlev + 1;
|
||
p1 = texpr (np[1]);
|
||
aquote = i;
|
||
if (!p1) return (NULL);
|
||
return (intcon (esize (p1)));
|
||
|
||
default: errx (2035, cop);
|
||
return (NULL);
|
||
}
|
||
|
||
return (mkenode (op, t, lvalue, p1, p2));
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TPTROP - Translate pointer operation
|
||
|
||
**********************************************************************/
|
||
|
||
enode *tptrop (cop, p1, p2)
|
||
enode *p1, *p2;
|
||
|
||
{switch (cop) {
|
||
case n_minus: return (tpsub (p1, p2));
|
||
case n_aminus: return (tpadd (e_sub0, TRUE, p1, p2));
|
||
case n_plus: if (pointer(p2))
|
||
return (tpadd (e_add0, FALSE, p2, p1));
|
||
return (tpadd (e_add0, FALSE, p1, p2));
|
||
case n_aplus: return (tpadd (e_add0, TRUE, p1, p2));
|
||
case n_eq:
|
||
case n_ne:
|
||
case n_lt:
|
||
case n_gt:
|
||
case n_le:
|
||
case n_ge: return (tpcomp (p1, p2, cop-n_eq));
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TPSUB - Translate pointer subtraction
|
||
|
||
**********************************************************************/
|
||
|
||
enode *tpsub (p1, p2)
|
||
enode *p1, *p2;
|
||
|
||
{int i;
|
||
|
||
if (pointer (p1) && pointer (p2))
|
||
{if (p1->etype != p2->etype) errx (2025);
|
||
i = fudge (p1);
|
||
p1 = convert (p1, TPCHAR);
|
||
p2 = convert (p2, TPCHAR);
|
||
p1 = mkenode (e_p0sub, TINT, 0, p1, p2);
|
||
p2 = intcon (i);
|
||
return (mkenode (e_divi, TINT, 0, p1, p2));
|
||
}
|
||
if (pointer(p2))
|
||
{errx (2034);
|
||
return (NULL);
|
||
}
|
||
return (tpadd (e_sub0, FALSE, p1, p2));
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TPADD - Translate pointer addition/subtraction with integer
|
||
|
||
**********************************************************************/
|
||
|
||
enode *tpadd (op, assign, p1, p2)
|
||
enode *p1, *p2;
|
||
|
||
{type t;
|
||
int j;
|
||
enode *ep;
|
||
|
||
t = p1->etype;
|
||
j = pctype (p1);
|
||
if (!(p2 = conv (p2, 003))) return (NULL);
|
||
ep = mkenode (e_muli, TINT, 0, p2, intcon (fudge(p1)/spoint[j]));
|
||
ep = mkenode (op+j, t, 0, p1, ep);
|
||
if (assign)
|
||
{p1 = ep->ep1;
|
||
p1->lvalue = 2;
|
||
ep = mkenode (e_assign, t, 0, p1, ep);
|
||
}
|
||
return (ep);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TPCOMP - Construct Pointer Comparison
|
||
|
||
**********************************************************************/
|
||
|
||
enode *tpcomp (p1, p2, cc) enode *p1, *p2;
|
||
|
||
{int op, j;
|
||
enode *ep;
|
||
econst *ecp;
|
||
|
||
if (pointer (p1) && pointer (p2))
|
||
{j = min (pctype (p1), pctype (p2));
|
||
op = e_eqp0 + cc + 6*j;
|
||
while (undfop(op) && j>0) {--j; op =- 6;}
|
||
j =+ ct_p0;
|
||
p1 = convx (p1, j);
|
||
p2 = convx (p2, j);
|
||
return (mkenode (op, TINT, 0, p1, p2));
|
||
}
|
||
|
||
if (pointer (p2)) {ep=p1;p1=p2;p2=ep;}
|
||
|
||
p2 = opt(p2);
|
||
if (cc<cc_lt0 && p2->op==e_int && (ecp=p2)->eval==0)
|
||
{op = e_jz0 + 4*cc + pctype (p1);
|
||
if (!undfop (op)) return (mkenode (op, TINT, 0, p1, NULL));
|
||
return (mkenode (e_eqi+cc, TINT, 0,
|
||
convx (p1, ct_int), intcon (0)));
|
||
}
|
||
|
||
errx (2032);
|
||
return (intcon (0));
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TXIDN - Translate IDN node
|
||
|
||
**********************************************************************/
|
||
|
||
enode *txidn (p)
|
||
struct {int itype, iclass, ioffset;} *p;
|
||
|
||
{type t;
|
||
enode *ep;
|
||
|
||
t = to2p (p->itype);
|
||
ep = mkenode (e_idn, t, 1, p->iclass, p->ioffset);
|
||
if (t->tag==TTFUNC || p->iclass==c_label)
|
||
ep = mkenode (e_a0+tpoint[TTINT], mkptr (t), 0, ep, NULL);
|
||
else if (flt_hack && t==TDOUBLE && p->iclass==c_param)
|
||
{ep->etype = mkptr (t);
|
||
ep->lvalue = 0;
|
||
ep = mkenode (e_ind, t, 1, ep, NULL);
|
||
}
|
||
return (ep);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TXINC - Translate increment/decrement
|
||
|
||
**********************************************************************/
|
||
|
||
enode *txinc (cop, p1, n)
|
||
enode *p1;
|
||
|
||
{int op, bop, j;
|
||
type t;
|
||
enode *p2;
|
||
|
||
p2 = NULL;
|
||
bop = op = cop - n_incb;
|
||
if (chktype (p1, -037)) return (NULL);
|
||
t = p1->etype;
|
||
switch (t->tag) {
|
||
case TTCHAR: op =+ e_incbc; break;
|
||
case TTINT: op =+ e_incbi; break;
|
||
case TTFLOAT: op =+ e_incbf; break;
|
||
case TTDOUBLE: op =+ e_incbd; break;
|
||
default: j = pctype (p1);
|
||
op =+ e_incb0 + (j<<2);
|
||
p2 = intcon (fudge(p1)/spoint[j]);
|
||
}
|
||
if (undfop (op))
|
||
{switch (bop) {
|
||
case 0: /* prefix */
|
||
case 2: op = (bop==0 ? n_aplus : n_aminus);
|
||
return (txpr3 (&op, p1, intcon (1)));
|
||
case 1: /* postfix */
|
||
case 3: op = (bop==1 ? n_aplus : n_aminus);
|
||
p2 = txpr2 (&op, p1, intcon (1));
|
||
++p1->lvalue;
|
||
op = e_lseq;
|
||
break;
|
||
}
|
||
}
|
||
return (mkenode (op, t, 0, p1, p2));
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TADDR - Construct Address of Expression
|
||
|
||
**********************************************************************/
|
||
|
||
enode *taddr (ep) enode *ep;
|
||
|
||
{int op;
|
||
type t;
|
||
|
||
if (!ep) return (NULL);
|
||
op = ep->op;
|
||
|
||
if (op==e_ind) ep = ep->ep1;
|
||
else
|
||
{if (ep->lvalue==0) ep->lvalue=1;
|
||
t = mkptr (ep->etype);
|
||
op = e_a0 + ctype (t) - ct_p0;
|
||
ep = mkenode (op, t, 0, ep, NULL);
|
||
}
|
||
return (ep);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TELIST - translate an expression_list subtree
|
||
|
||
Translate the expressions in an expression list. Use the
|
||
ELIST node structure to hold the translated expressions.
|
||
Mark such nodes with -1 to distinguish from ENODEs.
|
||
|
||
**********************************************************************/
|
||
|
||
enode *telist (np)
|
||
int *np;
|
||
|
||
{enode *ep;
|
||
int count, *onp;
|
||
|
||
if (!np) return (NULL);
|
||
if (np[0] != n_elist) return (tfarg (np));
|
||
ep = np;
|
||
count = 1;
|
||
do
|
||
{np[0] = -1; /* mark */
|
||
np[2] = tfarg (np[2]);
|
||
onp = np;
|
||
np = np[1];
|
||
++count;
|
||
} while (np && np[0] == n_elist);
|
||
onp[1] = tfarg (np);
|
||
|
||
if (count > maxfarg) {errx (2039); return (NULL);}
|
||
return (ep);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
TFARG - translate a function argument
|
||
|
||
**********************************************************************/
|
||
|
||
enode *tfarg (np)
|
||
int *np;
|
||
|
||
{enode *ep;
|
||
int op;
|
||
|
||
if (!(ep = texpr (np))) return (NULL);
|
||
cur_op = n_call; /* for error messages */
|
||
if (ep->etype == TCHAR) ep = convert (ep, TINT);
|
||
else if (ep->etype == TFLOAT) ep = convert (ep, TDOUBLE);
|
||
if (chktype (ep, 031)) return (NULL);
|
||
if (!argops) return (ep);
|
||
switch (ep->etype->tag) {
|
||
case TTINT: op = e_argi; break;
|
||
case TTDOUBLE: if (flt_hack) return (ep);
|
||
op = e_argd; break;
|
||
case TTPTR: op = e_arg0 + pctype (ep); break;
|
||
}
|
||
return (mkenode (op, ep->etype, 0, ep, NULL));
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
CODE GENERATOR: OPTIMIZATION ROUTINES
|
||
|
||
opt
|
||
|
||
*/
|
||
|
||
/**********************************************************************
|
||
|
||
OPT - Optimize Expression
|
||
|
||
Evaluate Integer Constant Expressions
|
||
Commute Where Desirable
|
||
Simplify Operations by 0 or 1
|
||
Rearrange Multiple Additions to a Pointer
|
||
|
||
**********************************************************************/
|
||
|
||
# define COMMUTATIVE 1
|
||
# define ZEROIDENTITY 2
|
||
# define ZEROFLUSH 4
|
||
# define ONEIDENTITY 010
|
||
|
||
int adope [] { /* info on some AMOPs */
|
||
|
||
/* +i */ COMMUTATIVE + ZEROIDENTITY,
|
||
/* =+i */ ZEROIDENTITY,
|
||
/* +d */ COMMUTATIVE,
|
||
/* =+d */ 0,
|
||
/* -i */ ZEROIDENTITY,
|
||
/* =-i */ ZEROIDENTITY,
|
||
/* -d */ 0,
|
||
/* =-d */ 0,
|
||
/* *i */ COMMUTATIVE + ZEROFLUSH + ONEIDENTITY,
|
||
/* =*i */ ZEROFLUSH + ONEIDENTITY,
|
||
/* *d */ COMMUTATIVE,
|
||
/* =*d */ 0,
|
||
/* /i */ ONEIDENTITY,
|
||
/* =/i */ ONEIDENTITY,
|
||
/* /d */ 0,
|
||
/* =/d */ 0,
|
||
/* % */ 0,
|
||
/* =% */ 0,
|
||
/* << */ ZEROIDENTITY,
|
||
/* =<< */ ZEROIDENTITY,
|
||
/* >> */ ZEROIDENTITY,
|
||
/* =>> */ ZEROIDENTITY,
|
||
/* & */ COMMUTATIVE + ZEROFLUSH,
|
||
/* =& */ 0,
|
||
/* ^ */ COMMUTATIVE + ZEROIDENTITY,
|
||
/* =^ */ ZEROIDENTITY,
|
||
/* | */ COMMUTATIVE + ZEROIDENTITY,
|
||
/* =| */ ZEROIDENTITY,
|
||
/* && */ 0,
|
||
/* || */ 0,
|
||
/* -p0p0 */ 0,
|
||
/* = */ 0,
|
||
/* .argi */ 0,
|
||
/* .argd */ 0,
|
||
/* .arg0 */ 0,
|
||
/* .arg1 */ 0,
|
||
/* .arg2 */ 0,
|
||
/* .arg3 */ 0,
|
||
/* +p0 */ ZEROIDENTITY,
|
||
/* +p1 */ ZEROIDENTITY,
|
||
/* +p2 */ ZEROIDENTITY,
|
||
/* +p3 */ ZEROIDENTITY,
|
||
/* -p0 */ ZEROIDENTITY,
|
||
/* -p1 */ ZEROIDENTITY,
|
||
/* -p2 */ ZEROIDENTITY,
|
||
/* -p3 */ ZEROIDENTITY
|
||
};
|
||
|
||
enode *opt (ep) enode *ep;
|
||
|
||
{int op, dope, c1, c2, v1, v2, v;
|
||
enode *p1, *p2, *p;
|
||
econst *ecp;
|
||
|
||
if (!ep) return (ep);
|
||
switch (op = ep->op) {
|
||
case e_call:
|
||
case e_idn:
|
||
case e_int:
|
||
case e_float:
|
||
case e_string: return (ep);
|
||
}
|
||
if (!(p1 = ep->ep1)) return (ep);
|
||
p1 = ep->ep1 = opt (p1);
|
||
p2 = ep->ep2 = opt (ep->ep2);
|
||
if (c1 = (p1->op == e_int)) v1 = (ecp=p1)->eval;
|
||
if (c2 = (p2 && p2->op == e_int)) v2 = (ecp=p2)->eval;
|
||
|
||
# define y goto yes;
|
||
|
||
/* evaluate unary operations on integer constants */
|
||
|
||
if (op<=e_not && c1) switch (op) {
|
||
case e_iminus: v = -v1; y
|
||
case e_bnot: v = ~v1; y
|
||
case e_not: v = !v1; y
|
||
}
|
||
|
||
else if (op>=e_addi && op<=e_sub3 && p2)
|
||
{dope = adope[op-e_addi];
|
||
|
||
/* evaluate binary operations on integer constants */
|
||
|
||
if (c1 && c2) switch (op) {
|
||
case e_addi: v = v1+v2; y
|
||
case e_subi: v = v1-v2; y
|
||
case e_muli: v = v1*v2; y
|
||
case e_divi: v = v1/v2; y
|
||
case e_mod: v = v1%v2; y
|
||
case e_ls: v = v1<<v2; y
|
||
case e_rs: v = v1>>v2; y
|
||
case e_band: v = v1&v2; y
|
||
case e_xor: v = v1^v2; y
|
||
case e_bor: v = v1|v2; y
|
||
case e_and: v = v1&&v2; y
|
||
case e_or: v = v1||v2; y
|
||
}
|
||
|
||
/* commute where suitable */
|
||
|
||
else
|
||
{if ((dope & COMMUTATIVE)
|
||
&& (c1 || p2->degree > p1->degree))
|
||
{p = p1; ep->ep1 = p1 = p2; ep->ep2 = p2 = p;
|
||
v = c1; c1 = c2; c2 = v;
|
||
v = v1; v1 = v2; v2 = v;
|
||
}
|
||
|
||
/* hack operations by 0 */
|
||
|
||
if (c2)
|
||
if (v2==0)
|
||
{if (dope & ZEROIDENTITY)
|
||
return (p1);
|
||
if (dope & ZEROFLUSH)
|
||
return (p2);
|
||
}
|
||
|
||
/* hack operations by 1 */
|
||
|
||
else if (v2==1)
|
||
if (dope & ONEIDENTITY)
|
||
return (p1);
|
||
|
||
/* rearrange pointer additions */
|
||
|
||
if (op>=e_add0 && op<=e_sub3 && p1->op==op)
|
||
{p = p1->ep1;
|
||
p1->op = e_addi;
|
||
p1->etype = TINT;
|
||
p1->ep1 = p2;
|
||
ep->ep2 = opt (p1);
|
||
ep->ep1 = p;
|
||
}
|
||
}
|
||
}
|
||
return (ep);
|
||
yes: return (intcon (v));
|
||
}
|
||
|