/* 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. * * gsub.c * * Various code generation subroutines * Includes generation of switches and * conversion of type lists to simple type,size. */ #include #include "param.h" #include "bstok.h" #include "tytok.h" #include "flags.h" #include "nodes.h" #include "gen.h" #define isimmed(np) ((np)->g_flags & IMMEDID) #define isareg(np) ((np)->g_token == REGVAR && (np)->g_rno >= AREG) extern cctest; extern xflags[]; #define debug xflags['s'-'a'] gen_brt(np, lbl) NODEP np; { p2_expr(&np); mustty(np, R_SCALAR); br_sub(np, 0, lbl); } gen_brf(np, lbl) NODEP np; { p2_expr(&np); mustty(np, R_SCALAR); br_sub(np, 1, lbl); } br_sub(np, rev, lbl) NODEP np; { int i; switch (np->e_token) { case DOUBLE '&': br_split(np, lbl, rev); return; case DOUBLE '|': br_split(np, lbl, 2+rev); return; } genx(np, FORCC); i = cctest; if (i) { if (rev) /* reverse truth */ i = (i&1) ? i+1 : i-1; out_b(i, lbl); } } br_split(np, lbl, n) NODEP np; { int nlbl; if (n == 0 || n == 3) nlbl = new_lbl(); else nlbl = lbl; br_sub(np->n_left, n<2, nlbl); br_sub(np->n_right, n&1, lbl); freeunit(np); if (nlbl != lbl) def_lbl(nlbl); } /* generate switch np - list of nodes with value,label pairs (sorted) dlbl - default label or -1 */ #undef min #undef max gen_switch(np, odlbl) NODEP np; { int n,min,max; int dlbl; register NODEP p; if (debug) { printf("gs %d ", odlbl); printnode(np); } /* if no default, make one! */ if (odlbl < 0) dlbl = new_lbl(); else dlbl = odlbl; n = 0; for (p=np; p; p=p->n_next) { if (n == 0) min = max = p->c_casev; else max = p->c_casev; n++; } if (n <= C_SIMPLE) simple_sw(np,odlbl); else if (n >= max/C_RATIO - min/C_RATIO) table_sw(np,dlbl,min,max); else { half_sw(np,dlbl,max/2+min/2,n); goto out; /* free already done */ } freenode(np); out: if (odlbl < 0) def_lbl(dlbl); } /* simple if-else type switch dlbl may be -1 -> fall through does not free np */ simple_sw(np, dlbl) register NODEP np; { while (np) { out_d0cmp(np->c_casev); out_b(B_EQ, np->c_casel); np = np->n_next; } if (dlbl >= 0) out_br(dlbl); } /* use table switch dlbl is not -1 does not free np */ table_sw(np, dlbl, min, max) NODEP np; { out_d0cmp(min); out_b(B_LT, dlbl); out_d0cmp(max); out_b(B_GT, dlbl); if (min) out_d0sub(min); out_tsw(); while (np) { while (min < np->c_casev) { out_tlbl(dlbl); min++; } out_tlbl(np->c_casel); min++; np = np->n_next; } } /* cut switch in half (by value) dlbl is not -1 will free np */ half_sw(np, dlbl, cut, n) NODEP np; { register NODEP p, last; int nlo, nhi; int l1; for (p=np; p->c_casev < cut; p = p->n_next) last = p; /* we KNOW both pieces are non-NULL ! */ last->n_next = NULL; last = p; nlo = 0; nhi = 0; for (p=np; p; p=p->n_next) nlo++; nhi = n - nlo; if (nhi == 1) { /* switch hi and low */ p = np; np = last; last = p; nlo = 1; nhi = n-1; } if (nlo == 1) { /* also nhi == 1 */ out_d0cmp(np->c_casev); out_b(B_EQ, np->c_casel); freenode(np); gen_switch(last, dlbl); return; } l1 = new_lbl(); out_d0cmp(cut); out_b(B_GE, l1); gen_switch(np, dlbl); def_lbl(l1); gen_switch(last, dlbl); } istempa(np) register NODEP np; { if (np->g_token == OREG && istemp(np->g_rno)) return 1; return 0; } strasn(np) NODEP np; { int r; long size; int chunk, l; char buf[40]; int lisa, risa; if (np->g_ty != ET_A) return 0; size = np->g_bsize; if (size <= 4) { /* pretend its scalar */ np->g_sz = size; return 0; } lisa = istempa(np->n_left); risa = istempa(np->n_right); if (lisa) r = np->n_left->g_rno; else r = ralloc(AREG); /* R0 */ indir(np, r); np->g_offs = -size; if (size & 3) chunk = 2; else chunk = 4; if (risa) np->g_r1 = np->n_right->g_rno; else tempr(np, AREG); /* R1 */ tempr(np, 0); /* R2 */ if (!lisa || np->n_left->g_offs) addcode(np, "\tlea\tn_right->g_offs) addcode(np, "\tlea\t>A,R1\n"); np->g_bsize = size/chunk - 1; addcode(np, "\tmove.w\t#K,R2\n"); l = new_lbl(); sprintf(buf, "'L%d:\tmove.%c\t(R1)+,(R0)+\n", l, chunk == 4 ? 'l' : 'w'); addcode(np, buf); sprintf(buf, "\tdbra\tR2,'L%d\n", l); addcode(np, buf); return 1; } extern funstrl; strret(np) NODEP np; { strsub(np, funstrl); } strpush(np) NODEP np; { strsub(np, 0); } strsub(np, tolbl) register NODEP np; { long size; int chunk, l; char buf[40]; char *frstr; size = np->g_bsize; if (size & 3) chunk = 2; else chunk = 4; tempr(np, 0); /* set up 'from' address */ if (np->g_token == OREG && istemp(np->g_rno)) { frstr = "R0"; if (np->g_offs) addcode(np, "\tlea\tA,R0\n"); } else { frstr = "a1"; addcode(np, "\tlea\tA,a1\n"); } /* set up 'to' address */ if (tolbl) { sprintf(buf, "\tmove.l\t#'L%d,a2\n", tolbl); addcode(np, buf); } else { sprintf(buf, "\tsub\t#%d,sp\n", (int)size); addcode(np, buf); addcode(np, "\tmove.l\tsp,a2\n"); } /* generate copy loop */ np->g_bsize = size/chunk - 1; addcode(np, "\tmove.w\t#K,R1\n"); l = new_lbl(); sprintf(buf, "'L%d:\tmove.%c\t(%s)+,(a2)+\n", l, chunk == 4 ? 'l' : 'w', frstr); addcode(np, buf); sprintf(buf, "\tdbra\tR1,'L%d\n", l); addcode(np, buf); } specasn(np, flags) NODEP np; { NODEP lp = np->n_left, rp = np->n_right; int r; if (rp->g_token == ICON && isimmed(rp)) { rinherit(np); if (rp->g_offs == 0 && !isareg(rp)) addcode(np, "\tclr.S\tA,g_token == OREG && isimmed(rp)) { rp->g_flags &= ~IMMEDID; if (isareg(lp)) { inherit(np); addcode(np, "\tlea\t>A,A\n"); } else { r = ralloc(AREG); retreg(np, r); addcode(np, "\tlea\t>A,A\n"); addcode(np, "\tmove.l\tA,n_tptr == NULL) { printf("? NULL untype "); return; } switch (np->e_type) { case E_BIN: untype(np->n_right); /* fall through */ case E_UNARY: if (np->e_token == '.' && np->e_fldw) { np->g_fldw = np->e_fldw; np->g_fldo = np->e_fldo; } else np->g_fldw = 0; untype(np->n_left); } get_tyinf(np); if ((np->n_flags & N_COPYT) == 0) freenode(np->n_tptr); np->n_tptr = NULL; /* is g_code */ np->g_betw = NULL; } static char bty[] = { ET_U, ET_U, ET_S, ET_S, ET_U, ET_S, ET_S, ET_F, ET_F, 0 }; static char bsz[] = { SIZE_C, SIZE_L, SIZE_L, SIZE_S, SIZE_U, SIZE_I, SIZE_C, SIZE_F, SIZE_D, 0 }; get_tyinf(np) register NODEP np; { NODEP tp = np->n_tptr; int n; long offs; offs = np->e_offs; /* inherit name,token,left,right,nmx from common and token, flags, type, sc from enode */ switch (tp->t_token) { case K_STRUCT: case K_UNION: np->g_bsize = tp->t_size; np->g_ty = ET_A; np->g_sz = 0; break; case '(': break; case STAR: np->g_ty = ET_U; np->g_sz = SIZE_P; break; default: n = tp->t_token-FIRST_BAS; np->g_ty = bty[n]; np->g_sz = bsz[n]; } np->g_offs = offs; /* different place */ } addcode(np, s) register NODEP np; char *s; { NODEP tp; int i, c; while (np->g_code) np = np->g_code; tp = allocnode(); np->g_code = tp; np->n_flags &= ~N_COPYT; i = strlen(s); if (i < NMXSIZE) { /* fits in one */ strcpy(tp->n_name, s); return; } /* need to split it */ i = NMXSIZE-1; c = s[i-1]; if (c == '<' || c == '>' || (c>='A' && c<='Z')) /* special */ i--; strncpy(tp->n_name, s, i); tp->n_name[i] = 0; addcode(tp, &s[i]); }