📄 ccgen1.c
字号:
/* CCGEN1.C - Generate code for parse-tree statement execution
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.198, 9-Mar-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.112, 8-Aug-1985
**
** Original version (C) 1981 K. Chen
*/
#include "cc.h"
#include "ccgen.h"
#include <ctype.h> /* isdigit */
/* Imported functions */
extern void vrfree(VREG *);
extern VREG *vrget(void); /* CCREG */
extern void code_debugcall(NODE *); /* CCDBUG */
extern NODE *ndeflr(int op, NODE *l, NODE *r); /* CCSTMT */
extern VREG *genexpr(NODE *); /* CCGEN2 for expressions */
extern void genxrelease(NODE *); /* CCGEN2 for discarded expressions */
extern VREG *getmem(VREG *, TYPE *, int, int),
*stomem(VREG *, VREG *, INT, int); /* CCGEN2 */
extern void gswitch(NODE *); /* CCGSWI for switch statement */
extern void codlabel(SYMBOL *), codgolab(SYMBOL *);/*CCCODE for label output*/
extern SYMBOL *newlabel(void); /* CCSYM */
extern INT sizetype(TYPE *); /* CCSYM */
extern void outlab(SYMBOL *); /* CCOUT */
extern void code0(int, VREG *, VREG *), code3(int, VREG *, SYMBOL *),
code4(int, VREG *, VREG *), code4s(int, VREG *, VREG *, int, INT),
code5(int, VREG *), code00(int, int, int),
code6(int, VREG *, SYMBOL *), code8(int, VREG *, INT),
code13(int, VREG *, INT);
extern void relflush(VREG *), gboolean(NODE *, SYMBOL *, int),
flushcode(void), freelabel(SYMBOL *);
extern INT istrue(NODE *, NODE *); /* CCEVAL */
extern int deadjump(void); /* CCJSKP */
extern void killstack(void); /* CCOPT */
extern void outepilog(SYMBOL *); /* CCOUT */
extern VREG *gmuuo(NODE *); /* CCGEN2 for imuuo key word; KAR 1/91 */
extern
void outiepilog (void); /* FW 2A(52) */
/* Exported functions defined here */
void genstmt(NODE *);
/* Internal functions */
static void genadata(NODE *);
static void gdo(NODE *), gfor(NODE *), gif(NODE *),
gwhile(NODE *), greturn(NODE *);
static SYMBOL *gtoplab(void);
static int labchk(NODE *);
static NODE *laststmt(NODE *);
#if 0
static void genadata();
static void gdo(), gfor(), gif(), gwhile(), greturn();
static SYMBOL *gtoplab();
static int labchk();
static NODE *laststmt();
#endif
/* ------------------------------------- */
/* generate code for statement */
/* ------------------------------------- */
extern void outstr();
void
genstmt(NODE *n)
{
VREG *muuo_ac;
if (n == NULL) return;
switch (n->Nop) {
case N_STATEMENT:
{ NODE *beg, *next;
if (n->Nleft && n->Nleft->Nop == N_DATA) { /* Check for auto inits */
genadata(n->Nleft); /* Yep, do them */
n = n->Nright; /* then move on to real statements */
}
for(beg = n; n != NULL; n = n->Nright) {
if(n->Nop != N_STATEMENT)
int_error("genstmt: bad stmt %N", n);
if(n->Nleft == NULL) continue;
/* Check out following stmt for possible optimizations */
if(n->Nright && (next = n->Nright->Nleft) != NULL && optgen) {
switch(next->Nop) {
/* Hack to encourage tail recursion */
case Q_RETURN: /* If next will be RETURN */
if(next->Nright == NULL) { /* and has no return val */
NODE *v; /* Then try to optimize */
if((v = laststmt(n->Nleft)) != NULL && v->Nop == N_FNCALL)
v->Nflag |= NF_RETEXPR;
}
break;
/* If next stmt is a GOTO, ensure that any jumps
* within current stmt to end of stmt will
* instead go directly to object of the GOTO.
* Avoids jumping to jumps...
* We do a similar hack for BREAK and CONTINUE,
* which are similar to GOTOs except that their
* destination is kept in variables global to the
* code generation routines.
*/
case Q_CASE: /* Not sure about this one yet */
case N_LABEL:
case Q_GOTO:
n->Nleft->Nendlab = next->Nxfsym;
break;
case Q_BREAK:
n->Nleft->Nendlab = brklabel;
break;
case Q_CONTINUE:
n->Nleft->Nendlab = looplabel;
break;
default:
; /* do nothing */
} /* end of Nop switch */
} /* end of next-stmt check */
/* Optimize label usage */
if(n->Nright == NULL /* If this is last stmt in list */
&& optgen)
n->Nleft->Nendlab = beg->Nendlab; /* Copy from 1st */
genstmt(n->Nleft);
}
break;
} /* end of N_STATEMENT case block */
case Q_CASE:
codlabel(n->Nxfsym); /* send forward label */
n->Nleft->Nendlab = n->Nendlab; /* propagate end label */
genstmt (n->Nleft); /* finish rest of body */
break;
case N_LABEL:
if (n->Nxfsym->Sname[0] == '%' && isdigit(n->Nxfsym->Sname[1]))
code_debugcall(n);
else
codgolab(n->Nxfsym); /* send goto label */
n->Nleft->Nendlab = n->Nendlab; /* propagate end label */
genstmt(n->Nleft); /* finish rest of body */
break;
case Q_BREAK: code6(P_JRST, NULL, brklabel); break;
case Q_GOTO: code6(P_JRST, NULL, n->Nxfsym); break;
case Q_CONTINUE: code6(P_JRST, NULL, looplabel); break;
case Q_DO: gdo(n); break;
case Q_FOR: gfor(n); break;
case Q_IF: gif(n); break;
case Q_RETURN: greturn(n); break;
case Q_SWITCH: gswitch(n); break;
case Q_WHILE: gwhile(n); break;
#if SYS_CSI /* Added 1/91 for in-line monitor calls; KAR */
case Q_MUUO:
muuo_ac = gmuuo(n);
vrfree(muuo_ac);
break;
#endif
case N_EXPRLIST: /* Same as expression stmt */
default: /* None of above, assume expression stmt */
genxrelease(n); /* Generate it and flush any result */
break;
}
}
/* Hack for statement optimization. Find last statement in list. */
static NODE *
laststmt(n)
NODE *n;
{
while(n && n->Nop == N_STATEMENT) {
while(n->Nright) n = n->Nright;
n = n->Nleft;
}
return(n);
}
/* GENADATA - Generate auto data initializations
** Should be called only for N_DATA nodes.
**
** Includes "gizlist" - Generate a struct/union/array constant.
** This can only happen for brace-enclosed initializers.
** Node will be a N_IZLIST, with Ntype set to desired type of the
** constant.
** For the time being, our approach is to chicken out by just inventing
** a new internal label and returning that. This label and the N_IZLIST
** are put together to form a N_LITIZ list and chained onto "litnodes"
** for eventual output as a static data literal.
*/
static void
genadata(n)
NODE *n;
{
if (n->Nop != N_DATA) {
int_error("genadata: node not N_DATA %N", n);
return;
}
#if SYS_CSI /* Bliss-like reg linkage */
if (Register_Id(n)) /* should never happen */
int_error ("genadata: register var of non-arithmetic type");
#endif
for (; n && n->Nop == N_DATA; n = n->Nright) {
if (n->Nleft != NULL && n->Nleft->Nright != NULL) {
/* Have an N_IZ node with initializer, process it. */
if (n->Nleft->Nright->Nop == N_IZLIST) {
/* A struct/union/array initializer! */
SYMBOL *s = n->Nleft->Nleft->Nid; /* Find ident */
NODE *l = n->Nleft->Nright; /* Point to N_IZLIST */
TYPE *t = l->Ntype; /* Find type of constant */
VREG *ra, *r;
/* Put izer node onto literal list for later emission */
litnodes = ndeflr(N_LITIZ, l, litnodes);
litnodes->Nendlab = newlabel(); /* Make label for it */
/* Get the literal and store into auto var. Note that the
** type used is that of literal, not the ident, and it is
** ignored except to find the size in words of the object.
** This takes care of union objects, which only need to
** init the first member (which may be smaller than some
** other members).
*/
r = vrget();
ra = vrget();
code3(P_MOVE, r, litnodes->Nendlab); /* Get lit's addr */
r = getmem(r, t, 0, 0); /* Get izer contents */
code13(P_MOVE, ra, (s->Svalue+1)-stackoffset); /* AUTO addr */
r = stomem(r, ra, sizetype(t), 0); /* Set up the store */
relflush(r); /* Done, flush reg */
continue;
}
/* Normal case, izer not a brace-enclosed list. Handle
** by turning the N_IZ into a Q_ASGN expression. Note the
** C type of the expression needs to be set (from the Q_IDENT).
*/
n->Nleft->Nop = Q_ASGN; /* Turn N_IZ into Q_ASGN */
n->Nleft->Ntype = n->Nleft->Nleft->Ntype; /* Set up type */
genxrelease(n->Nleft); /* Generate code, ignore value */
}
}
}
/* ---------------------- */
/* if statement */
/* ---------------------- */
static void
gif(n)
NODE *n;
{
SYMBOL *true, *false;
NODE *nthen, *nelse, *body, *l;
body = n->Nright;
nthen = body->Nleft;
nelse = body->Nright;
l = n->Nleft;
/* optimize if to a jump */
if (nelse == NULL) {
if (nthen == NULL) { /* no body of either kind?? */
genxrelease(l); /* yes, just produce condition */
return; /* and return */
} else if (optgen) switch (nthen->Nop) {
case Q_BREAK:
l->Nendlab = n->Nendlab;
gboolean(l, brklabel, 1);
return;
case Q_GOTO:
l->Nendlab = n->Nendlab;
gboolean(l, nthen->Nxfsym, 1);
return;
case Q_CONTINUE:
l->Nendlab = n->Nendlab;
gboolean(l, looplabel, 1);
return;
default:
; /* do nothing */
}
}
/* Try to optimize when conditional expression is a constant.
** We have to be careful about flushing the then/else clauses because
** control could jump into them using either case or goto labels.
** Hence the labchk() to see whether the parse tree contains such labels...
*/
if (l->Nop == N_ICONST && optgen) { /* If cond is constant */
if (l->Niconst && !labchk(nelse)) { /* if (1) & "else" flushable */
if (nthen) {
nthen->Nendlab = n->Nendlab;
genstmt(nthen);
}
return;
}
if (!l->Niconst && !labchk(nthen)) { /* if (0) & "then" flushable */
if (nelse) {
nelse->Nendlab = n->Nendlab;
genstmt(nelse);
}
return;
}
}
/* do unoptimized if statement - first get exit label */
true = ((n->Nendlab == NULL)? newlabel() : n->Nendlab);
/* then emit code for test and clauses */
if (nthen) {
if (nelse == NULL) false = true;
else switch (nelse->Nop) {
case Q_GOTO:
false = nelse->Nxfsym;
nelse = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -