Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/old/kcc/ccgen.c
There are 8 other files named ccgen.c in the archive. Click here to see a list.
/* <KCC.CC>CCGEN.C.76, 28-May-85 11:02:14, Edit by KRONJ */
/*  Update to new PDP-10 op syms (no longer tied to node op / token / ASCII) */
/* <KCC.CC>CCGEN.C.66, 16-Mar-85 07:40:22, Edit by KRONJ */
/*  Missing parens in genrelease() */
/* <KCC.CC>CCGEN.C.61, 11-Mar-85 08:48:27, Edit by KRONJ */
/*  genrelease() must unstack structures now instead of $SPOP */
/* <KCC.CC>CCGEN.C.60, 10-Mar-85 14:45:41, Edit by KRONJ */
/*  Parser now deals with stackrefs */
/*  This avoids problem of code at top of loop, ref later in loop */
/* <KCC.CC>CCGEN.C.59, 10-Mar-85 12:31:07, Edit by KRONJ */
/*  Fix up array[] = {...} nelts here rather than duplicating code in ccdecl */
/* <KCC.CC>CCGEN.C.56, 21-Feb-85 14:12:29, Edit by SATZ */
/*  Move stub to ccdump where it belongs */
/* <KCC.CC>CCGEN.C.55, 21-Feb-85 12:35:17, Edit by SATZ */
/*  add stub module for dumping the intermediate code for debugging */
/* <KCC.CC>CCGEN.C.54, 18-Feb-85 19:50:20, Edit by SATZ */
/*  Don't emit BLOCK 0 any more. It will be declared extern */
/* <KCC.CC>CCGEN.C.53, 18-Feb-85 19:04:35, Edit by SATZ */
/*  0 is a legal value for the BLOCK pseudo op since you may want */
/*  to generate a symbol for the symbol table */
/* <KCC.CC>CCGEN.C.52, 18-Feb-85 13:55:11, Edit by SATZ */
/*  Generate fatal errors if attempt to output 0 or less BLOCK pseudo op */
/* <KCC.CC>CCGEN.C.51,  2-Jan-85 15:22:19, Edit by KRONJ */
/*  init litstrings rather than maxlit */
/* <KCC.CC>CCGEN.C.50,  2-Jan-85 12:28:07, Edit by KRONJ */
/*  use offsets stored in SMEM rather than those in member symbol */
/* <KCC.CC>CCGEN.C.48,  1-Jan-85 18:17:12, Edit by KRONJ */
/*  more complicated way of getting struct member list */
/* <KCC.CC>CCGEN.C.47, 31-Dec-84 18:13:53, Edit by KRONJ */
/*  clean up a bit more */
/* <KCC.CC>CCGEN.C.34, 31-Dec-84 10:37:28, Edit by KRONJ */
/*  colon after emitted label in gizexpr */
/* <KCC.CC>CCGEN.C.31, 30-Dec-84 22:13:27, Edit by KRONJ */
/*  Rework initialization to a closer approximation of correctness */
/* <KCC.CC>CCGEN.C.30, 29-Dec-84 23:48:53, Edit by KRONJ */
/*  Clean up initialization of one var with bracketed initialization. */
/*  In particular, don't think we're chaining through some structure */
/*  because of a variable left unset to stack garbage. */
/* SCORE:<KCC.CC>CCGEN.C.8, 27-Jul-84 23:36:08, Edit by KRONJ */
/*  Initialize register allocation rover for every new function */

/* ccgen.c -- Code generator TOPS-20   (C) 1981  K. Chen */

#include "cc.h"
#include "ccgen.h"

struct TY *findtype();
/* -------------------------------------- */
/*      main entry to code generator      */
/* -------------------------------------- */

gencode(n)
struct NODE *n;
{
    if (!eflag) {
	if (debug)
	    dumpcode(n);
	switch (n->nop) {
	    case DATA:
		dataseg();
		gendata(n); 
		break;
	    case FUNCTION:
		codeseg();
		genbody(n);
	    }
    }
    maxnode = 0;
}
/* ---------------------------------------------------- */
/*      common initizalization for code generation      */
/* ---------------------------------------------------- */

inicode()
{
    previous = NULL;
    litstrings = NULL;
    looplabel = brklabel = NULL;
    stackoffset = maxcode = mincode = 0;
    iniregs();
}
/* ----------------------------------- */
/*      generate data definitions      */
/* ----------------------------------- */

gendata(n)
struct NODE *n;
{
    struct SYMBOL *s;

    if (n->left != NULL) gendata(n->left); /* recursively do all vars */
    n = n->right;			/* look at this one */
    if (n->nop != IZ) return;		/* if not an initialization, give up */
    s = n->left->nid;			/* get symbol */
    n = n->right;			/* and initializer body for it */
    gizsym(s);				/* make label for variable */
    giz(n, s->sptr, s);			/* perform the initialization */
}
/* ---------------------------- */
/*      initializer symbol      */
/* ---------------------------- */

gizsym(sym)
struct SYMBOL *sym;
{
    char sn[32];

    switch(sym->sclass) {
    case SISTATIC:
    case SSSTATIC:
	outsym(sym->sval.ssym->sname);
	break;

    default:
	outsym(sym->sname);
    }
    outc(':');
}
/* --------------------------------------- */
/*      emit component of initializer      */
/* --------------------------------------- */

giz(n, t, s)
node n;
struct TY *t;
struct SYMBOL *s;
{
    node gizarray();

    if (n == NULL) return giznull(t);	/* nothing there, just make block */

    switch (t->ttype) {
    case ARRAY:
    case STRUCT:
	if (gizarray(n, t, s) != NULL) error(EINIT, s->sname);
	return;				/* init array, make sure all used */

    default:				/* initializing simple var */
	return gizword(n, t, s);	/* make just one word */
    }
}
/* ------------------------------------------ */
/*      emit initialization for one word      */
/* ------------------------------------------ */

gizword(n, t, s)
node n;
struct TY *t;
struct SYMBOL *s;
{
    switch (n->nop) {
    case IZLIST:			/* something in brackets? */
	if (n->right != NULL) error(EINIT, s->sname); /* no more than one */
	n = n->left;			/* just use inner part */
	return gizword(n, t, s);	/* try again */

    case ICONST:			/* integer */
	if (t->ttype != FLOAT && t->ttype != DOUBLE) { /* wants to be float? */
	    tab();			/* just integer constant, tab before */
	    outnum(n->niconst);		/* send number off */
	    nl();			/* new line */
	    return;
	}
	n->nmantissa = n->niconst;	/* float, set mantissa */
	n->nexponent = 0;		/* and exponent */
	n->nop = DCONST;		/* for floating point constant */
    case DCONST:
	fprintf (out, "\t%dE%d\n", n->nmantissa, n->nexponent);
	if (t->ttype == DOUBLE) outstr("\t0\n"); /* second word for double */
	return;

    default:
	gizexpr(n, t);			/* not a constant, make at runtime */
	return;
    }
}
/* -------------------------- */
/*      null initializer      */
/* -------------------------- */

giznull(t)
struct TY *t;
{
    int i;

    if ((i = tsize(t)) > 0)
	fprintf(out, "\tBLOCK\t%o\n", i);
    else if (i < 0)
	fatal(EBBLOCK, i);
}
/* -------------------------------- */
/*      initializer expression      */
/* -------------------------------- */

gizexpr(n, t)
node n;
struct TY *t;
{
    struct SYMBOL *loc, *lnk;
    struct vreg *r, *genstmt();

    loc = newlabel (0);			/* get and emit label */
    giznull (t);			/* emit space for it */

    codeseg();
    inicode();				/* initialize for code generation */
    lnk = newlabel (0);			/* get and emit label for link */
    outstr ("\tBLOCK\t1\n");		/* make space for link */

    r = genstmt (n);			/* make code for expression */
    code6 ((t->ttype == DOUBLE? DMOVEM : MOVEM), r, loc); /* put it in place */
    release (r);			/* done with the register */
    code6 (SKIP+ISSKIP+SKPE, SCRREG, lnk); /* see if have more inits to do */
    code7 (JRST, 0, NULL, 1, SCRREG);	/* do, chain to the next */
    code5 (POPJ, SP);			/* don't, return to runtimes */
    gend();				/* emit literals if any */

    outstr ("\t.LINK\t1,");		/* start making link pseudo-op */
    outsym (lnk->sname);		/* linking through top of routine */
    nl();				/* finish it off */
    dataseg();				/* back to data */

    freelabel (loc);			/* no longer need labels */
    freelabel (lnk);			/* so give them back to freelist */
}
/* ------------------------------------- */
/*      initializer array or struct      */
/* ------------------------------------- */

node gizarray(n, t, s)
node n;
struct TY *t;
struct SYMBOL *s;
{
    struct SMEM *sm;
    int nelts, o, b, w, gap, i;
    node gizclist();

    if (chararray(t)) {			/* char array? */
	if (gizchar(n, t, s, 0) != 0) nl(); /* yes, handle and finish line */
	return NULL;			/* nothing is left over */
    }

    if (n->nop != IZLIST) {		/* just one thing to use */
	if (tsize(t) != 1) error(EINIT, s->sname); /* so just one to fill */
	gizword(n, t, s);		/* call one word filler */
	return NULL;			/* no list, so nothing left in list */
    }

    sm = SMEMS(t);			/* find structure member list */
    if (sm == NULL) {			/* array? */
	if ((nelts = t->tsize) <= 0) nelts = -1; /* get num elements */
	t = t->tptr;			/* use member type from now on */
    } else nelts = -1;			/* no limit on elements */

    w = -1;				/* not initialized any fields yet */

    while (n != NULL && nelts != 0) {	/* until done with init or array */
	if (sm != NULL) {		/* if we're in struct */

	    /*
	    ** Deal with initializations of bit fields.
	    ** We use the FAIL BYTE pseudo-op, which does almost
	    ** exactly what we want.  We have to watch out for
	    ** multiple words of bit fields in a row, and running
	    ** out of fillers in the middle.  Currently fields
	    ** can only be initialized to constant values
	    ** (which is probably better than other C implementations anyway).
	    */

	    if ((o = sm->smoffset) < 0 && n != NULL) {
		outstr("\tBYTE");	/* yes, start making word */
		b = 36;			/* on bit zero */
		w = (- o) >> 12;	/* but only in this word */
		while (n != NULL && sm != NULL &&
		       (o = sm->smoffset) < 0 && (- o) >> 12 == w) {
		    if (n->left->nop != ICONST) /* not const? */
			error(ECONST);	/* complain - can't handle expr here */
		    o = (- o) & 07777;	/* extract P and S fields */
		    gap = o >> 6;	/* P field */
		    o = o & 077;	/* and S field */
		    gap = b - (gap + o); /* get space between */
		    if (gap != 0) fprintf(out, " (%d) 0", gap);
		    fprintf(out, " (%d) %o", o, n->left->niconst);
		    b -= gap + o;	/* adjust bit pos for emitted field */
		    sm = sm->smnext;	/* move on to next field */
		    n = n->right;	/* and next initializer */
		}
		nl();			/* all done with word of bit fields */
		if (sm == NULL) break;	/* no more members, exit loop */
		continue;		/* otherwise retry top of loop */
	    }
	    t = sm->smem->sptr;		/* set type for this field */
	    if ((sm = sm->smnext) == NULL) nelts = 0; /* all done? */
	} else nelts--;			/* not struct, count off member */

	/*
	** Initializing array, substructure, or simple member.
	**
	** If it is an array or struct, and the first item on
	** the initializer list is not itself a list, then we
	** call gizarray recursively and set our pointer to its
	** return value, which is the portion of our list unused
	** by the array or struct.
	**
	** If the first item is a list or if we are initializing a
	** simple member, we merely call giz for the first item,
	** and set our pointer to be the next item in the list.
	*/

	if (n->left->nop != IZLIST && (t->ttype == STRUCT || t->ttype == ARRAY)
	    && !chararray(t))
	    n = gizarray(n, t, s);	/* unbracketed subarray, use list */
	else if (n->left->nop == ICONST && chararray(t))
	    n = gizclist(n, t, s);	/* unbracketed bunch of chars */
	else {
	    giz(n->left, t, s);		/* simple var, initialize it */
	    n = n->right;		/* and move on in initializer */
	}
    }

    /*
    ** Fix up size of array.
    **
    ** At this point if we started with array[], then nelts is -1-x
    ** where x is the number of elements actually initialized.
    ** Fix up the type of our symbol to have the real count.
    */

    if (s->sptr->tsize == 0 && s->sptr->tptr == t)
	s->sptr = findtype (s->sptr->ttype, -nelts-1, t);

    /*
    ** Fill out remains of initializer.
    **
    ** We might have run off the end of our initializer before coming to
    ** the end of the array or structure we were initializing.  In that
    ** case, we are supposed to fill the rest with zeros; this is done
    ** by counting how much space we have and making a BLOCK that long.
    */

    if (nelts > 0)
	if ((i = tsize(t)) >= 0)
	    fprintf(out, "\tBLOCK\t%o\n", nelts * i);
	else
	    fatal(EBBLOCK, nelts*i);
    nelts = 0;				/* finish array, no struct left */
    while (sm != NULL) {		/* or is there? */
	if ((o = sm->smoffset) > 0)	/* word field? */
	    nelts += tsize (sm->smem->sptr); /* count space off */
	else if ((- o) >> 12 != w) {	/* unseen bit field? */
	    nelts++;			/* only takes one word */
	    w = (- o) >> 12;		/* don't count other fields again */
	}
	sm = sm->smnext;		/* move on in struct */
    }
    if (nelts > 0) fprintf(out, "\tBLOCK\t%o\n", nelts);
    return n;				/* return left over portion of init */
}
/* ----------------------------------------- */
/*      initializer char list in struct      */
/* ----------------------------------------- */

node gizclist(n, t, s)
node n;
struct TY *t;
struct SYMBOL *s;
{
    node ret, root = n;			/* start of array */
    int bcount = bsize(t);		/* how many bytes to strip off */

    while (--bcount > 0 && n != NULL) n = n->right; /* move on through list */
    if (n == NULL) ret = NULL;		/* nothing after the array */
    else {
	ret = n->right;			/* get remainder for gizarray */
	n->right = NULL;		/* tie off root string for gizchar */
    }
    if (gizchar(root, t, s, 0) != 0) nl(); /* initialize char array */
    return ret;				/* return rest back to gizarray */
}
/* -------------------------------- */
/*      initializer char array      */
/* -------------------------------- */

gizchar(n, t, s, o)
node n;
struct TY *t;
struct SYMBOL *s;
int o;
{
    int b = bsize(t);

    switch (n->nop) {
    case SCONST:
	while (n->nsclen-- > 0) {	/* for all of string */
	    o = outbyt(*n->nsconst++, o); /* output byte */
	    b--;			/* and count it off */
	}
	break;

    case IZLIST:
	while (n != NULL) {		/* until we run off our list */
	    if (n->left->nop == ICONST) {
		o = outbyt(n->left->niconst, o); /* output constant byte */
		b--;			/* count off */
	    } else if (t->tptr->ttype == ARRAY) {
		o = gizchar(n->left, t->tptr, s, o); /* run through subarray */
		b -= bsize(t->tptr);	/* count off subarray bytes */
	    } else error(EINIT, s->sname); /* strangeness for non-subarray */
	    n = n->right;		/* move on in list */
	}
	break;

    default:
	error(EINIT, s->sname);		/* unknown initialization */
    }

    /*
    ** Now we know how many chars we sent, so if this was a char[]
    ** we can fill out the details.  We also take the opportunity to
    ** complain if we overstuffed the array.
    */

    if (b < 0) {
	if (t->tsize > 0) error(EINIT, s->sname); /* too many chars */
	else if (s->sptr == t) {
	    s->sptr = findtype (t->ttype,
				(bsize (t->tptr) - b - 1) / bsize (t->tptr),
				t->tptr);
	    b += bsize (s->sptr);	/* may need to fill out */
	}
    }

    /*
    ** Initialization done, fill out rest of array.
    ** Our array might be a subarray of some other char array,
    ** so we must be prepared to leave a ragged end.
    */

    if (b > 0) {			/* not enough chars */
	while (o > 0 && b > 0) {	/* until at a word boundary */
	    o = outbyt(0, o);		/* add filler */
	    b--;			/* counting off */
	}
	if (b > 3) {			/* if some words left */
	    fprintf(out, "\tBLOCK\t%o\n", b / 4); /* make that many words */
	    b %= 4;			/* keep only remainder */
	}
	while (b-- > 0) o = outbyt(0, o); /* fill some more */
    }
    return o;				/* return offset to caller */
}
/* ---------------------------------------- */
/*      output byte in char array init      */
/* ---------------------------------------- */

int outbyt(b,o)
{
    if (o == 0) outstr("\tBYTE (9) ");	/* start of line */
    else outc(',');			/* or continuation byte */
    outnum(b);				/* the byte itself */
    if (o == 3) {
	nl();				/* last byte, send end of line */
	return 0;			/* and start next time on new line */
    }
    return o+1;				/* more to come, count off */
}
/* --------------------------------------- */
/*      number of bytes in char array      */
/* --------------------------------------- */

bsize(t)
struct TY *t;
{
    struct TY *tt;
    int b;

    tt = t;				/* set up */
    b = 1;				/* to find total num bytes in array */
    while (tt->ttype == ARRAY) {
	b *= tt->tsize;			/* multiplying for each index */
	tt = tt->tptr;			/* of the array structure */
    }
    return b;
}
/* --------------------------------------- */
/*      generate local label constant      */
/* --------------------------------------- */

clabel(l)
{
    code6 (IFIW, 0, l);
}
/* ------------------------------------- */
/*      generate code for statement      */
/* ------------------------------------- */

struct vreg *
genstmt(n)
node n;
{
    node rv;
    struct vreg *r, *gaddress(), *gconst(), *coerce(), *gunary(), *gternary(),
	*gcall(), *gassign(), *gbinop(), *glogical(), *gident();
    void genrelease();

    if (n == NULL) return NULL;
    switch (n->nop) {
    case DATA:
	if (n->left != NULL) genstmt (n->left);
	if (n->right != NULL && n->right->right != NULL) {
	    r = genstmt (n->right->right);
	    code4 (MOVEM, r, gaddress (n->right->left));
	    relflush (r);		/* release and drop spurious MOVEs */
	}
	return NULL;

    case ICONST:
    case DCONST:
    case SCONST:
	return gconst (n);

    case CASE:
	emitlabel (n->nflag);		/* send forward label */
	n->left->endlab = n->endlab;	/* propagate end label */
	genrelease (n->left);		/* finish rest of body */
	return NULL;

    case LABEL:
	emitgoto (n->nflag);		/* send goto label */
	n->left->endlab = n->endlab;	/* propagate end label */
	genrelease (n->left);		/* finish rest of body */
	return NULL;

    case STATEMENT:
	if (n->left) {
	    if (n->right) {
		switch(n->left->nop) {
		case RETURN:
		    rv = n->right;
		    while (rv->nop == STATEMENT) rv = rv->left;
		    if (n->left->right == NULL && rv->nop == FNCALL)
			rv->nflag |= RETEXPR;
		    break;
		case LABEL:
		case GOTO:
		case CASE:
		    n->right->endlab = (struct SYMBOL *) n->left->nflag;
		    break;
		case BREAK:
		    n->right->endlab = brklabel;
		    break;
		case CONTINUE:
		    n->right->endlab = looplabel;
		    break;
		}
		genrelease(n->right);
	    }
	    n->left->endlab = n->endlab;
	    genrelease(n->left);
	} else if (n->right) {
	    n->right->endlab = n->endlab;
	    genrelease(n->right);
	}
	return NULL;

    case COERCE:
	return coerce(n);

    case UNDEF:
	return NULL;

    case FNCALL:
	return gcall(n);

    default:
	switch (tok[n->nop].ttype) {
	case ASOP: return gassign(n);
	case BINOP: return gbinop(n);
	case BOOLOP: case BOOLUN:  return glogical(n);
	case PRIMARY: return gident(n);
	case UNOP: return gunary(n);
	case TERNARY: return gternary(n);
	}
    }

    switch (n->nop) {
    case BREAK:
	code6(JRST, 0, brklabel);
	break;
    case GOTO:
	code6(JRST, 0, n->nflag);
	break;
    case CONTINUE:
	code6(JRST, 0, looplabel);
	break;
    case DO:
	gdo(n);
	break;
    case FOR:
	gfor(n);
	break;
    case IF:
	gif(n);
	break;
    case RETURN:
	greturn(n);
	break;
    case SWITCH:
	gswitch(n);
	break;
    case WHILE:
	gwhile(n);
	break;
    case EXPRESS:
	genrelease(n->left);
	return genstmt(n->right);
    default:
	emsg(ECGEN, n->nop);
    }
    return NULL;
}
/* ------------------------------------------ */
/*      generate code for valueless stmt      */
/* ------------------------------------------ */

void genrelease (n)
node n;
{
    int siz;

    switch (n->nop) {
    case INC:				/* pre-increment is one less */
	n->nop = PINC;			/* instruction than post-increment, */
	break;				/* so if we don't need the result */
    case DEC:				/* use the more efficient form. */
	n->nop = PDEC;			/* (more efficient even for ptrs */
	break;				/* as lets us optimize out move). */
    }

    if ((n->ntype->ttype == STRUCT || n->ntype->ttype == UNION)
	&& (siz = tsize (n->ntype)) > 2) {
	(void) genstmt (n);		/* stack structure */
	code8 (ADJSP, SP, - siz);	/* and unstack it */
	stackoffset -= siz;		/* remember where we end up on stack */
    } else relflush (genstmt (n));	/* one or two regs, make and drop */
}
/*
** Flush no-longer-wanted register value
** Called by genrelease() and by genstmt() for DATA ops.
*/

relflush (reg)
struct vreg *reg;
{
    int r = realreg (reg);		/* get physical register */
    pcode p, before();

    release (reg);			/* now release reg or reg pair */

    if (optimize) for (p = previous; p != NULL; p = before (p)) {
	if (p->pop == ADJSP) continue; /* skip back across ADJSP */
	else if (p->pop != MOVE || p->preg != r) break; /* not flushable */
	else {
	    p->pop = NOP;		/* drop pointless NOP */
	    fixprev();		/* fix up for drop */
	}
    }
}
/* ---------------------------- */
/*      generate code body      */
/* ---------------------------- */

genbody(n)
struct NODE *n;
{
    inicode();				/* start making code */
    glabel (n->left->left->nid->sname);
    if (maxauto) {
	code8 (ADJSP, SP, maxauto);
	stackoffset += maxauto;
    }
    genrelease (n->right);
    gend();
}