/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to redistribute it freely, with the * following restrictions: * 1) No charge may be made other than reasonable charges for reproduction. * 2) Modified versions must be clearly marked as such. * 3) The authors are not responsible for any harmful consequences * of using this software, even if they result from defects in it. * * gen.c * * Generate code. * Includes main routine and code generation for unary nodes * and leafs. * Revised: Dec 1988 Joe Montgomery * * Revised gen.c to call externfunref to declare all functions XREF * * other modules: * Revised main.c to use Amiga File System Naming Conventions * Added ?,C,F switches. ? help * C force data,bss into Chip memory * F force data,bss into Fast memory * To be added -o switch to specify assembly output * Revised out.c to use MOTOROLA assembly directives in order * to be compatible with C.Gibbs a68k assembler & blink * Added END statement * Changed .comm label,size to label DC.x 0 * Revised d2.c so that externs are declared as XREF ----- * Revised g2.c & gen.c to declare all called functions XREF * (will need to change this to declare only external functions) * * * All changes labeled JMM * */ #include #include "param.h" #include "bstok.h" #include "tytok.h" #include "flags.h" #include "nodes.h" #include "gen.h" NODEP strsave; int cctest; static int reserve; static int tmpused; extern xflags[]; #define debug xflags['g'-'a'] #define FAIL 0 #define OKAY 1 #define isimmed(np) ((np)->g_flags & IMMEDID) #define isareg(np) ((np)->g_token == REGVAR && (np)->g_rno >= AREG) #define isdreg(np) ((np)->g_token == REGVAR && (np)->g_rno < AREG) #define istdreg(np) ((np)->g_token == REGVAR && (np)->g_rno < DRV_START) int cookflags[] = { 0, NOVAL_OK|CC_OK|IMMA_OK, /* FORSIDE */ IMMA_OK, /* FORPUSH */ CC_OK, /* FORCC */ IMMA_OK, /* FORIMA */ 0, /* FORADR */ IMMA_OK, /* FORINIT */ 0, /* IND0 */ 0, /* RETSTRU */ }; extern NODE *blktab; extern nmerrors; genx(np, cookie) register NODEP np; { int rv; if (np == NULL) return; if (nmerrors) goto bad; if (debug) { printf("GEN enter"); printnode(np); } untype(np); if (debug>1) { printf("after UNTYPE"); printnode(np); } tmpused = 0; gunk(np); if (tmpused && tmpused > blktab->b_tsize) blktab->b_tsize = tmpused; if (debug > 1) { printf("after gunk"); printnode(np); } order(np); reserve = 0; rv = eval(np, cookie); if (rv == OKAY && debug) { printf("GEN exit"); codeprint(np); } if (rv == OKAY) rv = cookmon(np, cookie); else error("couldnt eval node"); freenode(np); return rv; bad: freenode(np); return FAIL; } eval(np, cookie) register NODEP np; { int rv; np->g_r1 = np->g_r2 = -1; if (np == NULL) return FAIL; switch (np->g_type) { default: rv = b_eval(np, cookie); /* already did freetmps */ free1(np, np->n_left); free1(np, np->n_right); break; case EV_LEFT: rv = u_eval(np, cookie); freetmps(np); free1(np, np->n_left); break; case EV_NONE: rv = l_eval(np); break; } return rv; } u_eval(np, cookie) register NODEP np; { int subcook = FORADR; switch (np->g_token) { case STAR: subcook = FORIMA; break; case '!': subcook = FORCC; break; } if (eval(np->n_left, subcook) == FAIL) return FAIL; return u_sube(np, cookflags[cookie]); } u_sube(np, flags) register NODEP np; { register NODEP lp = np->n_left; long offs; int i; switch (np->g_token) { case '.': if (np->g_fldw) return fldget(np, flags); offs = np->g_offs; inherit(np); np->g_offs += offs; return OKAY; case STAR: if (isimmed(lp)) { inherit(np); np->g_flags &= ~IMMEDID; } else if (isareg(lp)) { indir(np, lp->g_rno); } else { /* NEED A temp */ if (lp->g_token == OREG && istemp(lp->g_rno)) i = lp->g_rno; else i = ralloc(AREG); addcode(np, "\tmove.l\tg_token == REGVAR) return FAIL; inherit(np); np->g_flags |= IMMEDID; if ((flags & IMMA_OK) == 0) imm_oreg(np); return OKAY; case '~': utemp(np); addcode(np, "\tnot.S\tA\n"); cc_hack(np); return OKAY; case UNARY '-': utemp(np); addcode(np, "\tneg.S\tA\n"); cc_hack(np); return OKAY; case TCONV: castgen(np); return OKAY; case PUSHER: /* must not be on left of assign or asn-op */ if ((lp->g_token != OREG && lp->g_token != REGVAR) || istemp(lp->g_rno) == 0) { inherit(np); return OKAY; } addcode(np, "\tmove.S\tg_ty == ET_A) { /* struct returned */ frc_ral(AREG); indir(np, AREG); } else { frc_ral(0); retreg(np, 0); } /* JMM ? added XREF statement. Note I use this regardless of whether the function is defined in the module or not. This is horrible and may cause problems. I will correct this when I can determine whether the function is defined in the current module or is an external reference. ? */ externfuncref(np); /* see out.c */ addcode(np, "\tjsr\tg_token = i + BR_TOK; } else { if (istdreg(lp)) i = lp->g_rno; else i = ralloc(0); retreg(np, i); if (!iscc(lp)) addcode(np, "n_name); return FAIL; } } holdcon(np) NODEP np; { np->g_bsize = np->g_offs; } retreg(np, rno) NODEP np; { np->g_token = REGVAR; np->g_rno = rno; } indir(np, rno) register NODEP np; { np->g_token = OREG; np->g_offs = 0; np->g_rno = rno; } inherit(np) register NODEP np; { NODEP lp = np->n_left; np->g_token = lp->g_token; np->g_offs = lp->g_offs; np->g_rno = lp->g_rno; np->g_flags |= CHILDNM | (lp->g_flags & IMMEDID); } extern FILE *output; cookmon(np, cookie) register NODEP np; { if (np == NULL) return FAIL; switch (cookie) { case FORCC: if (iscc(np)) { outcode(np); cctest = cctok(np); } else { if (np->g_token == ICON && isimmed(np)) { cctest = np->g_offs ? B_YES : B_NO; return OKAY; } outcode(np); outsub("Q", np); cctest = B_NE; } return OKAY; case FORINIT: if (anycode(np) == 0 && (np->g_flags & IMMEDID)) { out_a(np, output); return OKAY; } error("bad INIT expr"); return FAIL; case IND0: outcode(np); if (np->g_token != REGVAR || np->g_rno != 0) if (np->g_token == ICON && np->g_offs == 0 && isimmed(np)) outsub("\tclr.S\td0\n", np); else outsub("\tmove.S\tA,d0\n", np); return OKAY; case RETSTRU: outcode(np); strret(np); } outcode(np); return OKAY; } anycode(np) register NODEP np; { if (np->g_code) return 1; switch (np->g_type) { case EV_NONE: return 0; case EV_LEFT: return anycode(np->n_left); case EV_RIGHT: return anycode(np->n_right); case EV_LR: case EV_RL: return anycode(np->n_left) || anycode(np->n_right); } } l_eval(np) register NODEP np; { int l1; switch (np->g_token) { case ID: switch (np->g_sc) { default: /* EXTERN or HERE */ np->g_token = ONAME; np->g_offs = 0; if (np->n_name[0] != '%') nnmins(np, "_"); else /* hack for inline name */ strcpy(np->n_name, &np->n_name[1]); return OKAY; /* dont free n_nmx */ case K_STATIC: sprintf(np->n_name, "L%d", (int)np->g_offs); np->g_offs = 0; np->g_token = ONAME; break; case K_AUTO: np->g_rno = AREG+6; np->g_token = OREG; break; case K_REGISTER: np->g_token = REGVAR; break; } if (np->n_nmx) { freenode(np->n_nmx); np->n_nmx = NULL; } return OKAY; case ICON: np->g_flags |= IMMEDID; return OKAY; case FCON: np->g_flags |= IMMEDID; return OKAY; case SCON: np->g_flags |= IMMEDID; np->g_token = ONAME; l1 = new_lbl(); save_scon(np, l1); sprintf(np->n_name, "L%d", l1); return OKAY; case OREG: return OKAY; } return FAIL; } save_scon(np, lbl) NODEP np; { NODEP tp, copyone(); tp = copyone(np); tp->g_offs = lbl; if (np->n_nmx) { freenode(np->n_nmx); np->n_nmx = NULL; } putlist(&strsave, tp); } utemp(np) NODEP np; { NODEP lp = np->n_left; int i; if (lp->g_token == REGVAR && istemp(lp->g_rno)) { inherit(np); return; } i = ralloc(0); retreg(np, i); addcode(np, "\tmove.S\tg_r1 != -1) rfree(np->g_r1); if (np->g_r2 != -1) rfree(np->g_r2); } free1(np, cp) NODEP np, cp; { int cr; if (cp->g_token != OREG && cp->g_token != REGVAR) return; cr = cp->g_rno; if (np && cr == np->g_rno && (np->g_token == OREG || np->g_token == REGVAR)) return; if (istemp(cr)) rfree(cr); } istemp(rno) { return (rno < DRV_START || (rno >= AREG && rno < ARV_START)); } rfree(rno) { reserve &= ~(1<g_r1 == -1) np->g_r1 = i; else np->g_r2 = i; return i; } ralloc(type) { int starti, endi; register int i; if (type == AREG) { starti = AREG; endi = ARV_START; } else { starti = 0; endi = DRV_START; } for (i=starti; ib_size + tmpused; } /* fixes nodes with no code or aX is temp that are #d(aX) */ imm_oreg(np) NODEP np; { char *regnm(), buf[30]; int i; if (np->g_token != OREG) return; if ((np->g_flags & IMMEDID) == 0) return; np->g_flags &= ~IMMEDID; if (np->g_offs == 0) { /* #(a0) -> a0 */ np->g_token = REGVAR; return; } if (istemp(np->g_rno)) { holdcon(np); addcode(np, "\tadd\t#K,A\n"); np->g_token = REGVAR; return; } sprintf(buf, "\tlea\t%d(%s),A\n", (int)np->g_offs, regnm(np->g_rno)); addcode(np, buf); i = ralloc(AREG); retreg(np, i); } castgen(tp) register NODEP tp; { register NODEP np = tp->n_left; int sz = tp->g_sz; int i; if (np->g_token == ICON && isimmed(np)) { if (tp->g_ty == ET_F) { tp->g_token = FCON; *(float *)&tp->g_offs = (float)np->g_offs; tp->g_flags |= IMMEDID; } else { inherit(tp); i_exp(tp, np->g_sz, np->g_ty); squish(tp); } } else if (np->g_token == FCON && isimmed(np)) { if (tp->g_ty != ET_F) { tp->g_token = ICON; tp->g_offs = (long)*(float *)&np->g_offs; tp->g_flags |= IMMEDID; squish(tp); } else { inherit(tp); } } else if (sz > np->g_sz) { if (np->g_ty == ET_U) { i = ralloc(0); retreg(tp, i); addcode(tp, "\tclr.S\tA\n\tmove.g_sz == 1) addcode(tp, "\text.w\tA\n\text.l\tA\n"); else addcode(tp, "\text.S\tA\n"); } return; } else if (sz < np->g_sz) { switch (np->g_token) { case ONAME: case OREG: if (isimmed(np)) { smfudge: i = ralloc(0); retreg(tp, i); addcode(tp, "\tmove.g_offs = np->g_offs + (np->g_sz - sz); break; case REGVAR: if (sz == 1 && np->g_rno >= AREG) goto smfudge; /* fall through */ default: inherit(tp); } } else inherit(tp); } squish(np) NODEP np; { int neg; neg = (np->g_ty == ET_S && np->g_offs < 0); switch (np->g_sz) { case 1: if (neg) np->g_offs |= 0xffffff00L; else np->g_offs &= 0xff; break; case 2: if (neg) np->g_offs |= 0xffff0000L; else np->g_offs &= 0xffffL; break; } } i_exp(np, osz, oty) NODEP np; { long l; if (oty == ET_S && osz < np->g_sz) { l = np->g_offs; switch (osz) { case 1: l = (char) l; break; case 2: l = (short) l; break; } np->g_offs = l; } }