home *** CD-ROM | disk | FTP | other *** search
- /* 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 <stdio.h>
- #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;
- }
-
- char chunkch[] = {0, 'b', 'w', 0, 'l'};
-
- strasn(np)
- NODEP np;
- {
- int r;
- long count, i;
- int chunk, l;
- char buf[40];
- int lisa, risa, rissp;
- int useloop;
-
- if (np->g_ty != ET_A)
- return 0;
-
- count = np->g_bsize;
- chunk = np->g_sz;
- if (count == 1) {
- return 0;
- }
-
- useloop = count > 3;
-
- lisa = istempa(np->n_left);
- risa = istempa(np->n_right);
- rissp = (np->n_right->g_token == PUSHER);
-
- if (lisa)
- r = np->n_left->g_rno;
- else
- r = ralloc(AREG); /* R0 */
- indir(np, r);
- np->g_offs = -(count*chunk);
-
- if (risa)
- np->g_r1 = np->n_right->g_rno;
- else if (rissp)
- np->g_r1 = AREG+7;
- else
- tempr(np, AREG); /* R1 */
- if (useloop)
- tempr(np, 0); /* R2 */
-
- if (!lisa || np->n_left->g_offs)
- addcode(np, "\tlea\t<A,R0\n");
- if (!(risa||rissp) || np->n_right->g_offs)
- addcode(np, "\tlea\t>A,R1\n");
-
- if (useloop) {
- sprintf(buf, "\tmove.w\t#%d,R2\n", (int)(count-1));
- addcode(np, buf);
- l = new_lbl();
- sprintf(buf, "'L%d:\tmove.%c\t(R1)+,(R0)+\n",l,chunkch[chunk]);
- addcode(np, buf);
- sprintf(buf, "\tdbra\tR2,'L%d\n", l);
- addcode(np, buf);
- } else for (i=0; i<count; i++) {
- sprintf(buf, "\tmove.%c\t(R1)+,(R0)+\n", chunkch[chunk]);
- addcode(np, buf);
- }
-
- if (chunk == 1 && count & 1 && rissp)
- addcode(np, "\tmove.b\t(sp)+,R2\n");
-
- return 1;
- }
-
- strret(np)
- NODEP np;
- {
- extern funstrl;
-
- strsub(np, funstrl);
- }
-
- strpush(np)
- NODEP np;
- {
- return strsub(np, 0);
- }
-
- strxpush(np)
- NODEP np;
- {
- strsub(np, -1);
- }
-
- strsub(np, tolbl)
- register NODEP np;
- {
- long count, i;
- int chunk, l;
- char buf[40];
- char *frstr;
- register NODEP tp;
- int useloop;
-
- count = np->g_bsize;
- chunk = np->g_sz;
- if (chunk == 1 && count & 1 && tolbl <= 0)
- count++;
-
- useloop = count > 3;
-
- if (useloop && np->g_r2 == -1)
- np->g_r2 = ralloc(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 if (tolbl == -1 && (tp = np->n_left) &&
- tp->g_token == OREG && istemp(tp->g_rno) &&
- tp->g_offs == 0) {
- frstr = "R1";
- np->g_r1 = tp->g_rno;
- } else {
- frstr = "R1";
- if (np->g_r1 == -1)
- np->g_r1 = ralloc(AREG);
- if (tolbl == -1)
- addcode(np, "\tlea\t<A,R1\n");
- else
- addcode(np, "\tlea\tA,R1\n");
- }
-
- /* set up 'to' address */
- if (tolbl > 0) {
- sprintf(buf, "\tmove.l\t#'L%d,H\n", tolbl);
- addcode(np, buf);
- } else {
- sprintf(buf, "\tsub\t#%d,sp\n", (int)(count*chunk));
- addcode(np, buf);
- addcode(np, "\tmove.l\tsp,H\n");
- }
-
- /* generate copy loop */
- if (useloop) {
- sprintf(buf, "\tmove.w\t#%d,R2\n", (int)(count-1));
- addcode(np, buf);
- l = new_lbl();
- sprintf(buf, "'L%d:\tmove.%c\t(%s)+,(H)+\n", l, chunkch[chunk],
- frstr);
- addcode(np, buf);
- sprintf(buf, "\tdbra\tR2,'L%d\n", l);
- addcode(np, buf);
- } else for (i=0; i<count; i++) {
- sprintf(buf, "\tmove.%c\t(%s)+,(H)+\n", chunkch[chunk],
- frstr);
- addcode(np, buf);
- }
-
- return count*chunk;
- }
-
- 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)
- addcode(np, isareg(lp) ? "\tsub.S\t<A,<A\n"
- : "\tclr.S\t<A\n");
- else
- addcode(np, "\tmove.S\t>A,<A\n");
- return 1;
- }
- if (rp->g_token == OREG && isimmed(rp)) {
- rp->g_flags &= ~IMMEDID;
- if (isareg(lp)) {
- inherit(np);
- addcode(np, "\tlea\t>A,A\n");
- } else if (rp->g_offs == 0) {
- retreg(np, rp->g_rno);
- addcode(np, "\tmove.l\tA,<A\n");
- } else {
- if (istemp(rp->g_rno))
- r = rp->g_rno;
- else
- r = ralloc(AREG);
- retreg(np, r);
- addcode(np, "\tlea\t>A,A\n");
- addcode(np, "\tmove.l\tA,<A\n");
- }
- return 1;
- }
- return 0;
- }
-
- untype(np)
- register NODEP np;
- {
- if (np == NULL || np->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_ty = ET_A;
- /* determine copy chunk size and number of chunks */
- if (tp->t_aln & 1) {
- if (tp->t_size & 1)
- fatal("aligned struct with odd size");
- if (tp->t_size & 2) {
- np->g_bsize = tp->t_size >> 1;
- np->g_sz = 2;
- } else {
- np->g_bsize = tp->t_size >> 2;
- np->g_sz = 4;
- }
- } else {
- np->g_bsize = tp->t_size;
- np->g_sz = 1;
- }
- 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]);
- }
-