📄 ccgen.c
字号:
/* CCGEN.C - Generate code for parse-tree data declarations
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.221, 25-Apr-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.84, 8-Aug-1985
**
** Original version (C) 1981 K. Chen
*/
#include "cc.h"
#include "ccgen.h"
#include "ccchar.h"
#include <string.h>
/* Imported (external) functions used herein */
extern void ridlsym(SYMBOL *); /* CCSYM */
extern SYMBOL *newlabel(void);
extern void freelabel(SYMBOL *);
extern INT sizearray(TYPE *), sizetype(TYPE *); /* CCSYM */
extern int elembsize(TYPE *);
extern void code5(int, VREG *),
code6(int, VREG *, SYMBOL *), codemdx(int, int, SYMBOL *, INT, int),
code00 (int, int, int), code12 (int, VREG *, INT),
code8(int, VREG *, INT), flushcode(void); /* CCCODE */
extern VREG *vrget(void);
extern void genstmt(NODE *);
extern void genxrelease(NODE *);
extern void /* CCOUT */
outmidef(SYMBOL *), outmiref(SYMBOL *), outid(char *),
outptr(SYMBOL *, int, INT), outscon(char *, int, int),
outlab(SYMBOL *), outnum(INT), outnl(void),
outstr(char *);
extern int /* CCOUT */
outflt(int, INT *, int), codeseg(void), dataseg(void), prevseg(int);
extern void vrinit(void); /* CCREG.C */
extern void vrendchk (void);
extern void vrfree (VREG *);
extern
void outiprolog (void); /* FW 2A(52) */
#if SYS_CSI
extern void outpghdr(void), outprolog(SYMBOL *); /* CCOUT */
#endif
/* Exported functions defined here */
void gencode(NODE *n); /* Called by CC mainline */
/* Internal Functions */
static void inicode(void),
endcode(void),
gendata(NODE *),
genfunct(NODE *),
gliterals(void),
giz(NODE *, TYPE *, SYMBOL *),
gizword(NODE *, TYPE *, SYMBOL *),
giznull(TYPE *),
gizexpr(NODE *, TYPE *);
static int gizptr(NODE *);
static INT gizconst(NODE *);
static void gizlist(NODE *, TYPE *, SYMBOL *);
static void gizbytes(NODE *, TYPE *, SYMBOL *, int);
static void bytbeg(int),
wdalign(void),
outval(long),
outbyte(long, int),
outzbs(INT),
outzwds(INT);
static INT bytend(void);
#if 0
static void inicode(), endcode(), gendata(), genfunct(), gliterals();
static void giz(), gizword(), giznull(), gizexpr();
static int gizptr(), gizconst();
static void gizlist();
static void gizbytes();
static void bytbeg(), wdalign(), outval(), outbyte(),
outzbs(), outzwds();
static INT bytend();
#endif
/* OUT data emission vars. */
static int bsiz; /* 0 if in word mode, else byte size in bits */
static int bpw; /* # bytes per word */
static int bpos; /* P of last byte deposited (TGSIZ_WORD at beg of wd)*/
static INT savlct; /* Saved loc ctr at start of byte mode */
static INT locctr; /* Location counter (only for tracking # wds output) */
/* GENCODE - Generate code/data from parse-tree node
*/
void
gencode(NODE *n)
{
if (n) /* Ignore null stmts/defs */
switch (n->Nop) {
case N_DATA:
if (!nerrors) gendata(n); /* Generate data definition */
break;
case N_FUNCTION:
if (!nerrors) genfunct(n); /* Generate function instrs */
ridlsym((SYMBOL *)NULL); /* Flush any local symbols */
break;
default:
int_error("gencode: bad node %N", n);
}
}
/*
* genfunct ()
*
* - Generate machine instruction code for function
*/
static
void
genfunct (NODE* n)
{
extern
int _word_cnt; /* KAR-2/91, from CCOUT # wds in function */
int i;
VREG* r;
isr = 0;
if (n->Nleft->Nright) /* Any local-scope static data defs? */
gendata(n->Nleft->Nright); /* Yes, generate them first */
codeseg (); /* Ensure in code segment */
inicode (); /* Start making code */
if (mlist)
{
/* Emit definitions for register variables. */
for (i = 0; i < _reg_count; i++)
{
putc ('\t', out);
outid (Reg_Id[i]->Sname);
putc ('=', out);
outnum (i + r_maxnopreserve + 1); /* FW 2A(47) */
putc ('\n', out);
}
}
outmidef(n->Nleft->Nleft->Nid); /* Output function label */
if (curfn != n->Nleft->Nleft->Nid)
int_error("Bad funct Nid \"%S\"", n->Nleft->Nleft->Nid);
if (n->Nleft->Nleft->Nid->Sflags & TF_INTERRUPT)
{ /* FW 2A(52) */
isr = 1;
outiprolog ();
}
if (profbliss) /* for BLISS profiler */
outprolog (curfn); /* added 09/15/89 by MVS */
if (n->Nreg <= R_PRESERVE_COUNT) /* Reg linkage */
{
for (i = 0; i < n->Nreg; i++)
{
/* Push preserved registers for all functions except main () */
if (!fn_main)
{
code00 (P_PUSH, R_SP, i + r_maxnopreserve + 1); /* FW 2A(47) */
++stackoffset;
oline++;
}
/* Initialize all reg parameters (often optimized away later) */
if (Reg_Id[i]->Sclass == SC_RARG)
{
r_preserve = i + r_maxnopreserve + 1; /* FW 2A(47) */
r = vrget();
/* ex: MOVE argc,-1(SP) */
code12(P_MOVE, r, -(Reg_Id[i]->Svalue) - stackoffset);
vrfree(r);
}
}
}
if (maxauto)
{ /* If any auto vars, */
code8(P_ADJSP, VR_SP, maxauto); /* make room for them on stack */
stackoffset += maxauto; /* and remember stack bumped */
}
genstmt (n->Nright); /* Generate code for body */
endcode (); /* Wrap up code */
if (vrbfun)
fprintf (outmsgs, "%d words\n", _word_cnt);
_word_cnt = 0;
if (mlist && (oline > HDR_LINES))
outpghdr();
}
/* INICODE - Common code generation inits
*/
static void
inicode(void)
{
previous = NULL;
litstrings = NULL;
litnodes = NULL;
looplabel = brklabel = NULL;
stackoffset = maxcode = mincode = 0;
vrinit();
}
/* ENDCODE - Common code generation wrap-ups
*/
static void
endcode(void)
{
flushcode(); /* Flush out peephole buffer */
gliterals(); /* Generate any accumulated literals */
vrendchk(); /* Check to make sure no regs active */
}
/* GENDATA - Generate data definitions
**
** This routine is only called to process static-extent data definitions
** of global or local scope, as opposed to local-extent (automatic) defs
** which are generated by genadata() in CCGEN1.
** Note that the Ntype of the symbol's Q_IDENT node is never examined here;
** the symbol's Stype is used instead. They are identical except for
** array and function names, when the Ntype is "pointer to <Stype>".
*/
static void
gendata(NODE *n)
{
NODE *var;
SYMBOL *s;
for (; n != NULL; n = n->Nright) {
if (n->Nop != N_DATA) {
int_error("gendata: bad N_DATA %N", n);
break;
}
if ((var = n->Nleft) != NULL) { /* For each item on N_DATA list */
TYPE *t;
if (var->Nop != N_IZ) {
int_error("gendata: bad datum %N", n);
break;
}
s = var->Nleft->Nid; /* get symbol */
for (t = s->Stype; t->Tspec == TS_ARRAY; t = t->Tsubt)
; /* Get to bottom of array */
if (!tisanyvolat(t) && tisconst(t)) /* If obj can be pure, */
codeseg(); /* put it in pure code seg */
else dataseg(); /* Else ensure in data seg */
outmidef(s); /* make label for variable */
giz(var->Nright, s->Stype, s); /* do the initialization */
}
}
gliterals(); /* Put literals into code (pure) segment */
}
/* GLITERALS - Emit all accumulated literals
** Forces use of code segment as literals are expected to be pure,
** although this is not mandatory.
*/
static void
gliterals(void)
{
if (litstrings || litnodes) {
codeseg();
flushcode(); /* Make sure all code forced out */
}
/* Do node literals first since they may generate more string literals! */
while (litnodes != NULL) {
outlab(litnodes->Nendlab); /* Emit internal label */
giz(litnodes->Nleft, litnodes->Nleft->Ntype, litnodes->Nendlab);
freelabel(litnodes->Nendlab);
litnodes = litnodes->Nright;
}
while (litstrings != NULL) { /* Output literal strings */
outlab(litstrings->Nsclab); /* Emit generated label */
freelabel(litstrings->Nsclab); /* and then can free it. */
outtab(); /* spaced out from string. */
outscon(litstrings->Nsconst, /* Output string literal, */
litstrings->Nsclen, /* this long */
elembsize(litstrings->Ntype)); /* of this bytesize. */
outnl(); /* End with final newline */
litstrings = litstrings->Nscnext; /* chain through list */
}
}
/* GIZ - Generate initialization value for an object
*/
static void
giz(NODE *n, TYPE *t, SYMBOL *s)
{
if (n == NULL) {
giznull(t); /* nothing there, just make block */
return;
}
switch (t->Tspec) {
case TS_ARRAY:
case TS_STRUCT:
case TS_UNION:
gizlist(n, t, s);
return;
default: /* initializing simple object */
gizword(n, t, s); /* make just one or two words */
return;
}
}
/* GIZWORD - emit initialization for a simple var (not array or structure)
** This closely follows the nisconst() routine in CCDECL which
** checked for legality while parsing.
*/
static void
gizword(NODE *n, TYPE *t, SYMBOL *s)
{
if (n->Nop == N_IZLIST) { /* something in brackets? */
if (n->Nright != NULL) /* no more than one allowed */
int_error("gizword: izer mismatch for %S %N", s, n);
gizword(n->Nleft, t, s); /* Just use inner part */
} else
if (!gizconst(n)) /* Try new stuff. If not constant, */
gizexpr(n, t); /* sigh, make at runtime. */
}
/* GIZCONST - Returns true if expression is an allowable initializer constant,
** with appropriate code generated. Otherwise, caller must generate.
*/
/* Return value indicates something about the type of constant: */
#define CT_NOTCON 0 /* not a constant, caller must generate. */
#define CT_CON 1 /* definitely a constant (arith, or a cast pointer) */
#define CT_ADDR 2 /* address of some kind */
#define CT_FUNC 3 /* function address (cannot add or sub from this) */
static struct pointerval {
SYMBOL *pv_id; /* Identifier (if any) */
INT pv_off; /* Offset from identifier (words or bytes) */
int pv_bsize; /* Byte size of pointer (0 = word) */
} pv;
static INT
gizconst(NODE *e)
{
INT res;
switch(e->Nop) {
case N_ICONST:
if (tisbyte(e->Ntype)) { /* Special handling for byte vals */
res = e->Niconst & ((1<<tbitsize(e->Ntype))-1); /* Mask off */
res <<= (TGSIZ_WORD % tbitsize(e->Ntype)); /* Shift */
outval(res);
return CT_CON;
}
/* Normal word value, drop through */
case N_PCONST:
#if __MSDOS__
if (e->Ntype->Tflag & TF_UNSIGN)
unsign_int = 1; /* used in outnum() called by outval() */
outval(e->Niconst); /* Just emit integer constant */
unsign_int = 0;
#else
outval(e->Niconst); /* Just emit integer constant */
#endif
return CT_CON; /* Say simple constant generated */
case N_FCONST: /* Invoke rtn from CCOUT */
locctr += outflt(e->Ntype->Tspec, (INT *)&e->Nfconst, 0);
return CT_CON; /* Say simple constant generated */
/* Only the most likely cast conversions are supported here,
** the others aren't common enough to be worth the
** extra trouble.
*/
case N_CAST:
if (e->Ncast == CAST_NONE)
return gizconst(e->Nleft); /*Most trivial cast just pass on */
else if (e->Ncast != CAST_PT_PT)
return CT_NOTCON; /* Not a constant */
/* Drop through to check for ptr (most likely cast) */
default:
if (e->Ntype->Tspec == TS_PTR) { /* Is this a pointer? */
pv.pv_id = NULL; /* Initialize arg struct */
pv.pv_off = pv.pv_bsize = 0;
if ((res = gizptr(e)) != 0) { /* Fill in the struct */
/* Won, output pointer word. */
outtab(); /* Won, output it. */
outptr(pv.pv_id, pv.pv_bsize, pv.pv_off);
outnl();
++locctr;
return res;
}
}
}
return CT_NOTCON; /* Must generate instructions */
}
/* GIZPTR - auxiliary for GIZCONST */
static int
gizptr(NODE *n)
{
INT addoff, off;
int i;
TYPE *t;
switch (n->Nop) {
case N_CAST:
switch ((int) n->Ncast) {
case CAST_PT_PT: /* Only ptr-ptr supported */
i = gizptr(n->Nleft); /* Get values for operand */
if (i == CT_FUNC /* Function addr? If so, */
&& n->Ntype->Tspec == TS_PTR /* and converting to */
&& n->Ntype->Tsubt->Tspec == TS_FUNCT) /* same, */
return CT_FUNC; /* No further conv needed! */
if (i != 2) /* Only normal addrs allowed now */
return CT_NOTCON;
/* First see whether a conversion is actually needed */
i = elembsize(n->Ntype); /* Desired bytesize of ptr */
if (i == 0) { /* Casting to (void *)? */
if (tischarpointer(n->Nleft->Ntype)) /* from (char*)?*/
return CT_ADDR; /* Yes, no change */
i = TGSIZ_CHAR; /* Else cvt to this bsize */
} else if (!elembsize(n->Nleft->Ntype)) { /* fm (void*)? */
if (tischarpointer(n->Ntype)) /* to (char*)?*/
return CT_ADDR; /* Yes, no change */
}
if (i >= TGSIZ_WORD) i = 0;
if (i == pv.pv_bsize) /* If already OK, */
return CT_ADDR; /* just return success */
/* Different sizes. Check to see if boundaries match.
** This takes care of 9<->18 bit conversions
** (as well as any others)
*/
if (i && pv.pv_bsize) { /* Both are byte ptrs? */
if (pv.pv_bsize < i && (i%pv.pv_bsize == 0)) {
pv.pv_off /= (i/pv.pv_bsize);
pv.pv_bsize = i;
return CT_ADDR;
}
if (i < pv.pv_bsize && (pv.pv_bsize%i == 0)) {
pv.pv_off *= (pv.pv_bsize/i);
pv.pv_bsize = i;
return CT_ADDR;
}
}
/* Odd sizes. First must always cvt to a word pointer */
if (pv.pv_bsize) {
pv.pv_off /= (TGSIZ_WORD/pv.pv_bsize);
pv.pv_bsize = 0;
}
/* Casting to byte ptr of some kind? */
if (i && (i < TGSIZ_WORD)) {
pv.pv_off *= (TGSIZ_WORD/i);
pv.pv_bsize = i;
}
return CT_ADDR;
default: /* Only ptr-to-ptr supported for now */
break;
}
return CT_NOTCON;
case N_SCONST:
pv.pv_id = n->Nsclab = newlabel(); /* Get fwd lab for later use */
n->Nscnext = litstrings; /* Link on string stack */
litstrings = n; /* Now on stack */
pv.pv_bsize = elembsize(n->Ntype); /* Set bsize */
return CT_ADDR; /* Say address generated */
case Q_IDENT:
/* Identifier. See documentation for Q_IDENT in cctoks.h
** for explanation of this method of testing.
*/
pv.pv_id = n->Nid; /* Remember it */
switch (n->Nid->Stype->Tspec) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -