home *** CD-ROM | disk | FTP | other *** search
- #
- /*
-
- C compiler, part 2
-
-
- */
-
- #include "c1h.c"
-
- char maprel[] { EQUAL, NEQUAL, GREATEQ, GREAT, LESSEQ,
- LESS, GREATQP, GREATP, LESSEQP, LESSP
- };
-
- char notrel[] { NEQUAL, EQUAL, GREAT, GREATEQ, LESS,
- LESSEQ, GREATP, GREATQP, LESSP, LESSEQP
- };
-
- struct tconst czero { CON, INT, 0, 0};
- struct tconst cone { CON, INT, 0, 1};
- struct tconst fczero { SFCON, DOUBLE, 0, 0 };
-
- struct table *cregtab;
-
- int nreg 3;
- int isn 10000;
- int namsiz 8;
-
- main(argc, argv)
- char *argv[];
- {
- extern fout;
-
- if (argc<4) {
- error("Arg count");
- exit(1);
- }
- if(fopen(argv[1], ascbuf)<0) {
- error("Missing temp file");
- exit(1);
- }
- if ((fout = creat(argv[3], 0666)) < 0) {
- error("Can't create %s", argv[3]);
- exit(1);
- }
- spacep = treespace;
- getree();
- /*
- * If any floating-point instructions
- * were used, generate a reference which
- * pulls in the floating-point part of printf.
- */
- if (nfloat)
- printf(".globl fltused\n");
- /*
- * tack on the string file.
- */
- close(ascbuf[0]);
- if (fopen(argv[2], ascbuf)<0) {
- error("Missing temp file");
- exit(1);
- }
- printf(".globl\n.data\n");
- getree();
- flush();
- exit(nerror!=0);
- }
-
- /*
- * Given a tree, a code table, and a
- * count of available registers, find the code table
- * for the appropriate operator such that the operands
- * are of the right type and the number of registers
- * required is not too large.
- * Return a ptr to the table entry or 0 if none found.
- */
- char *match(atree, table, nrleft)
- struct tnode *atree;
- struct table *table;
- {
- int op, d1, d2, t1, t2, dope;
- struct tnode *p2;
- register struct tnode *p1, *tree;
- register struct optab *opt;
-
- if ((tree=atree)==0)
- return(0);
- if (table==lsptab)
- table = sptab;
- if ((op = tree->op)==0)
- return(0);
- dope = opdope[op];
- if ((dope&LEAF) == 0)
- p1 = tree->tr1;
- else
- p1 = tree;
- t1 = p1->type;
- d1 = dcalc(p1, nrleft);
- if ((dope&BINARY)!=0) {
- p2 = tree->tr2;
- /*
- * If a subtree starts off with a conversion operator,
- * try for a match with the conversion eliminated.
- * E.g. int = double can be done without generating
- * the converted int in a register by
- * movf double,fr0; movfi fr0,int .
- */
- if(opdope[p1->op]&CNVRT && (opdope[p2->op]&CNVRT)==0) {
- tree->tr1 = p1->tr1;
- if (opt = match(tree, table, nrleft))
- return(opt);
- tree->tr1 = p1;
- } else if (opdope[p2->op]&CNVRT && (opdope[p1->op]&CNVRT)==0) {
- tree->tr2 = p2->tr1;
- if (opt = match(tree, table, nrleft))
- return(opt);
- tree->tr2 = p2;
- }
- t2 = p2->type;
- d2 = dcalc(p2, nrleft);
- }
- for (; table->op!=op; table++)
- if (table->op==0)
- return(0);
- for (opt = table->tabp; opt->tabdeg1!=0; opt++) {
- if (d1 > (opt->tabdeg1&077)
- || (opt->tabdeg1 >= 0100 && (p1->op != STAR)))
- continue;
- if (notcompat(p1, opt->tabtyp1, op)) {
- continue;
- }
- if ((opdope[op]&BINARY)!=0 && p2!=0) {
- if (d2 > (opt->tabdeg2&077)
- || (opt->tabdeg2 >= 0100) && (p2->op != STAR) )
- continue;
- if (notcompat(p2,opt->tabtyp2, 0))
- continue;
- }
- return(opt);
- }
- return(0);
- }
-
- /*
- * Given a tree, a code table, and a register,
- * produce code to evaluate the tree with the appropriate table.
- * Registers reg and upcan be used.
- * If there is a value, it is desired that it appear in reg.
- * The routine returns the register in which the value actually appears.
- * This routine must work or there is an error.
- * If the table called for is cctab, sptab, or efftab,
- * and tree can't be done using the called-for table,
- * another try is made.
- * If the tree can't be compiled using cctab, regtab is
- * used and a "tst" instruction is produced.
- * If the tree can't be compiled using sptab,
- * regtab is used and the register is pushed on the stack.
- * If the tree can't be compiled using efftab,
- * just use regtab.
- * Regtab must succeed or an "op not found" error results.
- *
- * A number of special cases are recognized, and
- * there is an interaction with the optimizer routines.
- */
- rcexpr(atree, atable, reg)
- struct tnode *atree;
- struct table *atable;
- {
- register r;
- int modf, nargs, recurf;
- register struct tnode *tree;
- register struct table *table;
-
- table = atable;
- recurf = 0;
- if (reg<0) {
- recurf++;
- reg = ~reg;
- if (reg>=020) {
- reg =- 020;
- recurf++;
- }
- }
- if((tree=atree)==0)
- return(0);
- switch (tree->op) {
-
- /*
- * A conditional branch
- */
- case CBRANCH:
- cbranch(optim(tree->btree), tree->lbl, tree->cond, 0);
- return(0);
-
- /*
- * An initializing expression
- */
- case INIT:
- if (tree->tr1->op == AMPER)
- tree->tr1 = tree->tr1->tr1;
- if (tree->tr1->op==NAME)
- pname(tree->tr1);
- else if (tree->tr1==CON)
- psoct(tree->tr1->value);
- else
- error("Illegal initialization");
- putchar('\n');
- return(0);
-
- /*
- * Put the value of an expression in r0,
- * for a switch or a return
- */
- case RFORCE:
- if((r=rcexpr(tree->tr1, regtab, reg)) != 0)
- printf("mov%c r%d,r0\n", isfloat(tree->tr1), r);
- return(0);
-
- /*
- * sequential execution
- */
- case COMMA:
- rcexpr(tree->tr1, efftab, reg);
- atree = tree = tree->tr2;
- break;
-
- /*
- * In the generated &~ operator,
- * fiddle things so a PDP-11 "bit"
- * instruction will be produced when cctab is used.
- */
- case NAND:
- if (table==cctab) {
- tree->op = TAND;
- tree->tr2 = optim(block(1, COMPL, INT, 0, tree->tr2));
- }
- break;
-
-
- /*
- * Handle a subroutine call. It has to be done
- * here because if cexpr got called twice, the
- * arguments might be compiled twice.
- * There is also some fiddling so the
- * first argument, in favorable circumstances,
- * goes to (sp) instead of -(sp), reducing
- * the amount of stack-popping.
- */
- case CALL:
- r = 0;
- nargs = 0;
- modf = 0;
- if (tree->tr1->op!=NAME) { /* get nargs right */
- nargs++;
- nstack++;
- }
- tree = tree->tr2;
- if(tree->op) {
- while (tree->op==COMMA) {
- r =+ comarg(tree->tr2, &modf);
- tree = tree->tr1;
- nargs++;
- }
- r =+ comarg(tree, &modf);
- nargs++;
- }
- tree = atree;
- tree->op = CALL2;
- if (modf && tree->tr1->op==NAME && tree->tr1->class==EXTERN)
- tree->op = CALL1;
- cexpr(tree, regtab, reg);
- popstk(r);
- nstack =- nargs;
- if (table==efftab || table==regtab)
- return(0);
- r = 0;
- goto fixup;
-
- /*
- * Longs need special treatment.
- */
- case ASLSH:
- case LSHIFT:
- if (tree->type==LONG) {
- if (tree->tr2->op==ITOL)
- tree->tr2 = tree->tr2->tr1;
- if (tree->op==ASLSH)
- tree->op = ASLSHL;
- else
- tree->op = LLSHIFT;
- }
- break;
-
- /*
- * Try to change * and / to shifts.
- */
- case TIMES:
- case DIVIDE:
- case ASTIMES:
- case ASDIV:
- tree = pow2(tree);
- }
- /*
- * Try to find postfix ++ and -- operators that can be
- * pulled out and done after the rest of the expression
- */
- if (table!=cctab && table!=cregtab && recurf<2
- && (opdope[tree->op]&LEAF)==0) {
- if (r=delay(&atree, table, reg)) {
- tree = atree;
- table = efftab;
- reg = r-1;
- }
- }
- /*
- * Basically, try to reorder the computation
- * so reg = x+y is done as reg = x; reg =+ y
- */
- if (recurf==0 && reorder(&atree, table, reg)) {
- if (table==cctab && atree->op==NAME)
- return(reg);
- }
- tree = atree;
- if (table==efftab && tree->op==NAME)
- return(reg);
- if ((r=cexpr(tree, table, reg))>=0)
- return(r);
- if (table!=regtab) {
- if((r=cexpr(tree, regtab, reg))>=0) {
- fixup:
- modf = isfloat(tree);
- if (table==sptab || table==lsptab) {
- if (tree->type==LONG) {
- printf("mov\tr%d,-(sp)\n",r+1);
- nstack++;
- }
- printf("mov%c r%d,%c(sp)\n", modf, r,
- table==sptab? '-':0);
- nstack++;
- }
- if (table==cctab)
- printf("tst%c r%d\n", modf, r);
- return(r);
- }
- }
- if (tree->op>0 && tree->op<RFORCE && opntab[tree->op])
- error("No code table for op: %s", opntab[tree->op]);
- else
- error("No code table for op %d", tree->op);
- return(reg);
- }
-
- /*
- * Try to compile the tree with the code table using
- * registers areg and up. If successful,
- * return the register where the value actually ended up.
- * If unsuccessful, return -1.
- *
- * Most of the work is the macro-expansion of the
- * code table.
- */
- cexpr(atree, table, areg)
- struct tnode *atree;
- struct table *table;
- {
- int c, r;
- register struct tnode *p, *p1, *tree;
- struct table *ctable;
- struct tnode *p2;
- char *string;
- int reg, reg1, rreg, flag, opd;
- char *opt;
-
- tree = atree;
- reg = areg;
- p1 = tree->tr2;
- c = tree->op;
- opd = opdope[c];
- /*
- * When the value of a relational or a logical expression is
- * desired, more work must be done.
- */
- if ((opd&RELAT||c==LOGAND||c==LOGOR||c==EXCLA) && table!=cctab) {
- cbranch(tree, c=isn++, 1, reg);
- rcexpr(&czero, table, reg);
- branch(isn, 0);
- label(c);
- rcexpr(&cone, table, reg);
- label(isn++);
- return(reg);
- }
- if(c==QUEST) {
- if (table==cctab)
- return(-1);
- cbranch(tree->tr1, c=isn++, 0, reg);
- flag = nstack;
- rreg = rcexpr(p1->tr1, table, reg);
- nstack = flag;
- branch(r=isn++, 0);
- label(c);
- reg = rcexpr(p1->tr2, table, rreg);
- if (rreg!=reg)
- printf("mov%c r%d,r%d\n",
- isfloat(tree),reg,rreg);
- label(r);
- return(rreg);
- }
- reg = oddreg(tree, reg);
- reg1 = reg+1;
- /*
- * long values take 2 registers.
- */
- if (tree->type==LONG && tree->op!=ITOL)
- reg1++;
- /*
- * Leaves of the expression tree
- */
- if ((r = chkleaf(tree, table, reg)) >= 0)
- return(r);
- /*
- * x + (-1) is better done as x-1.
- */
-
- if ((tree->op==PLUS||tree->op==ASPLUS) &&
- (p1=tree->tr2)->op == CON && p1->value == -1) {
- p1->value = 1;
- tree->op =+ (MINUS-PLUS);
- }
- if (table==cregtab)
- table = regtab;
- /*
- * The following peculiar code depends on the fact that
- * if you just want the codition codes set, efftab
- * will generate the right code unless the operator is
- * postfix ++ or --. Unravelled, if the table is
- * cctab and the operator is not special, try first
- * for efftab; if the table isn't, if the operator is,
- * or the first match fails, try to match
- * with the table actually asked for.
- */
- if (table!=cctab || c==INCAFT || c==DECAFT
- || (opt = match(tree, efftab, nreg-reg)) == 0)
- if ((opt=match(tree, table, nreg-reg))==0)
- return(-1);
- string = opt->tabstring;
- p1 = tree->tr1;
- p2 = 0;
- if (opdope[tree->op]&BINARY)
- p2 = tree->tr2;
- loop:
- /*
- * The 0200 bit asks for a tab.
- */
- if ((c = *string++) & 0200) {
- c =& 0177;
- putchar('\t');
- }
- switch (c) {
-
- case '\0':
- if (!isfloat(tree))
- if (tree->op==DIVIDE || tree->op==ASDIV)
- reg--;
- return(reg);
-
- /* A1 */
- case 'A':
- p = p1;
- goto adr;
-
- /* A2 */
- case 'B':
- p = p2;
- goto adr;
-
- adr:
- c = 0;
- if (*string=='\'') {
- c = 1;
- string++;
- } else if (*string=='+') {
- c = 2;
- string++;
- }
- pname(p, c);
- goto loop;
-
- /* I */
- case 'M':
- if ((c = *string)=='\'')
- string++;
- else
- c = 0;
- prins(tree->op, c, instab);
- goto loop;
-
- /* B1 */
- case 'C':
- if ((opd&LEAF) != 0)
- p = tree;
- else
- p = p1;
- goto pbyte;
-
- /* BF */
- case 'P':
- p = tree;
- goto pb1;
-
- /* B2 */
- case 'D':
- p = p2;
- pbyte:
- if (p->type==CHAR)
- putchar('b');
- pb1:
- if (isfloat(p))
- putchar('f');
- goto loop;
-
- /* BE */
- case 'L':
- if (p1->type==CHAR || p2->type==CHAR)
- putchar('b');
- p = tree;
- goto pb1;
-
- /* F */
- case 'G':
- p = p1;
- flag = 01;
- goto subtre;
-
- /* S */
- case 'K':
- p = p2;
- flag = 02;
- goto subtre;
-
- /* H */
- case 'H':
- p = tree;
- flag = 04;
-
- subtre:
- ctable = regtab;
- c = *string++ - 'A';
- if (*string=='!') {
- string++;
- c =| 020; /* force right register */
- }
- if ((c&02)!=0)
- ctable = sptab;
- if ((c&04)!=0)
- ctable = cctab;
- if ((flag&01) && ctable==regtab && (c&01)==0
- && (tree->op==DIVIDE||tree->op==MOD
- || tree->op==ASDIV||tree->op==ASMOD))
- ctable = cregtab;
- if ((c&01)!=0) {
- p = p->tr1;
- if(collcon(p) && ctable!=sptab) {
- if (p->op==STAR)
- p = p->tr1;
- p = p->tr1;
- }
- }
- if (table==lsptab && ctable==sptab)
- ctable = lsptab;
- if (c&010)
- r = reg1;
- else
- if (opdope[p->op]&LEAF || p->degree < 2)
- r = reg;
- else
- r = areg;
- rreg = rcexpr(p, ctable, r);
- if (ctable!=regtab && ctable!=cregtab)
- goto loop;
- if (c&010) {
- if (c&020 && rreg!=reg1)
- printf("mov%c r%d,r%d\n",
- isfloat(tree),rreg,reg1);
- else
- reg1 = rreg;
- } else if (rreg!=reg)
- if ((c&020)==0 && oddreg(tree, 0)==0 && (flag&04 ||
- flag&01
- && xdcalc(p2, nreg-rreg-1) <= (opt->tabdeg2&077)
- || flag&02
- && xdcalc(p1,nreg-rreg-1) <= (opt->tabdeg1&077))) {
- reg = rreg;
- reg1 = rreg+1;
- } else
- printf("mov%c\tr%d,r%d\n",
- isfloat(tree), rreg, reg);
- goto loop;
-
- /* R */
- case 'I':
- r = reg;
- if (*string=='-') {
- string++;
- r--;
- }
- goto preg;
-
- /* R1 */
- case 'J':
- r = reg1;
- preg:
- if (*string=='+') {
- string++;
- r++;
- }
- if (r>nreg)
- error("Register overflow: simplify expression");
- printf("r%d", r);
- goto loop;
-
- case '-': /* check -(sp) */
- if (*string=='(') {
- nstack++;
- if (table!=lsptab)
- putchar('-');
- goto loop;
- }
- break;
-
- case ')': /* check (sp)+ */
- putchar(')');
- if (*string=='+')
- nstack--;
- goto loop;
-
- /* #1 */
- case '#':
- p = p1->tr1;
- goto nmbr;
-
- /* #2 */
- case '"':
- p = p2->tr1;
-
- nmbr:
- if(collcon(p)) {
- if (p->op==STAR) {
- printf("*");
- p = p->tr1;
- }
- if ((p = p->tr2)->op == CON) {
- if (p->value)
- psoct(p->value);
- } else if (p->op==AMPER)
- pname(p->tr1, 0);
- }
- goto loop;
-
- case 'T': /* "tst R" if 1st op not in cctab */
- if (dcalc(p1, 5)>12 && !match(p1, cctab, 10))
- printf("tst r%d\n", reg);
- goto loop;
- case 'V': /* adc or sbc as required for longs */
- switch(tree->op) {
- case PLUS:
- case ASPLUS:
- case INCBEF:
- case INCAFT:
- printf("adc");
- break;
-
- case MINUS:
- case ASMINUS:
- case NEG:
- case DECBEF:
- case DECAFT:
- printf("sbc");
- break;
-
- default:
- while ((c = *string++)!='\n' && c!='\0');
- break;
- }
- goto loop;
- }
- putchar(c);
- goto loop;
- }
-
- /*
- * This routine just calls sreorder (below)
- * on the subtrees and then on the tree itself.
- * It returns non-zero if anything changed.
- */
- reorder(treep, table, reg)
- struct tnode **treep;
- struct table *table;
- {
- register r, r1;
- register struct tnode *p;
-
- p = *treep;
- if (opdope[p->op]&LEAF)
- return(0);
- r1 = 0;
- while(sreorder(&p->tr1, table, reg))
- r1++;
- if (opdope[p->op]&BINARY)
- while(sreorder(&p->tr2, table, reg))
- r1++;
- r = 0;
- while (sreorder(treep, table, reg))
- r++;
- *treep = optim(*treep);
- return(r);
- }
-
- /*
- * Basically this routine carries out two kinds of optimization.
- * First, it observes that "x + (reg = y)" where actually
- * the = is any assignment op is better done as "reg=y; x+reg".
- * In this case rcexpr is called to do the first part and the
- * tree is modified so the name of the register
- * replaces the assignment.
- * Moreover, expressions like "reg = x+y" are best done as
- * "reg = x; reg =+ y" (so long as "reg" and "y" are not the same!).
- */
- sreorder(treep, table, reg)
- struct tnode **treep;
- struct table *table;
- {
- register struct tnode *p, *p1;
-
- p = *treep;
- if (opdope[p->op]&LEAF)
- return(0);
- if (p->op==PLUS)
- if (reorder(&p->tr2, table, reg))
- *treep = p = optim(p);
- p1 = p->tr1;
- if (p->op==STAR || p->op==PLUS) {
- if (reorder(&p->tr1, table, reg))
- *treep = p = optim(p);
- p1 = p->tr1;
- }
- if (p1->op==NAME) switch(p->op) {
- case ASLSH:
- case ASRSH:
- case ASSIGN:
- if (p1->class != REG || isfloat(p->tr2))
- return(0);
- if (p->op==ASSIGN) switch (p->tr2->op) {
- case TIMES:
- case DIVIDE:
- if (!ispow2(p->tr2))
- break;
- p->tr2 = pow2(p->tr2);
- case PLUS:
- case MINUS:
- case AND:
- case NAND:
- case OR:
- case EXOR:
- case LSHIFT:
- case RSHIFT:
- p1 = p->tr2->tr2;
- if (xdcalc(p1) > 12
- || p1->op==NAME
- &&(p1->nloc==p->tr1->nloc
- || p1->regno==p->tr1->nloc))
- return(0);
- p1 = p->tr2;
- p->tr2 = p1->tr1;
- if (p1->tr1->op!=NAME
- || p1->tr1->class!=REG
- || p1->tr1->nloc!=p->tr1->nloc)
- rcexpr(p, efftab, reg);
- p->tr2 = p1->tr2;
- p->op = p1->op + ASPLUS - PLUS;
- *treep = p;
- return(1);
- }
- goto OK;
-
- case ASTIMES:
- case ASDIV:
- if (!ispow2(p))
- return(0);
- case ASPLUS:
- case ASMINUS:
- case ASSAND:
- case ASSNAND:
- case ASOR:
- case ASXOR:
- case DECBEF:
- case INCBEF:
- OK:
- if (table==cctab||table==cregtab)
- reg =+ 020;
- rcexpr(optim(p), efftab, ~reg);
- *treep = p1;
- return(1);
- }
- return(0);
- }
-
- /*
- * Delay handles postfix ++ and --
- * It observes that "x + y++" is better
- * treated as "x + y; y++".
- * If the operator is ++ or -- itself,
- * it calls rcexpr to load the operand, letting
- * the calling instance of rcexpr to do the
- * ++ using efftab.
- * Otherwise it uses sdelay to search for inc/dec
- * among the operands.
- */
- delay(treep, table, reg)
- struct tnode **treep;
- {
- register struct tnode *p, *p1;
- register r;
-
- p = *treep;
- if (table!=efftab && (p->op==INCAFT||p->op==DECAFT)
- && p->tr1->op==NAME) {
- return(1+rcexpr(p->tr1, table, reg));
- }
- p1 = 0;
- if (opdope[p->op]&BINARY)
- p1 = sdelay(&p->tr2);
- if (p1==0)
- p1 = sdelay(&p->tr1);
- if (p1) {
- r = rcexpr(optim(p), table, reg);
- *treep = p1;
- return(r+1);
- }
- return(0);
- }
-
- sdelay(ap)
- struct tnode **ap;
- {
- register struct tnode *p, *p1;
-
- p = *ap;
- if ((p->op==INCAFT||p->op==DECAFT) && p->tr1->op==NAME) {
- *ap = ncopy(p->tr1);
- return(p);
- }
- if (p->op==STAR || p->op==PLUS)
- if (p1=sdelay(&p->tr1))
- return(p1);
- if (p->op==PLUS)
- return(sdelay(&p->tr2));
- return(0);
- }
-
- /*
- * Copy a tree node for a register variable.
- * Used by sdelay because if *reg-- is turned
- * into *reg; reg-- the *reg will in turn
- * be changed to some offset class, accidentally
- * modifying the reg--.
- */
- ncopy(ap)
- struct tname *ap;
- {
- register struct tname *p;
-
- p = ap;
- if (p->class!=REG)
- return(p);
- return(block(3, NAME, p->type, p->elsize, p->tr1,
- p->offset, p->nloc));
- }
-
- /*
- * If the tree can be immediately loaded into a register,
- * produce code to do so and return success.
- */
- chkleaf(atree, table, reg)
- struct tnode *atree;
- {
- struct tnode lbuf;
- register struct tnode *tree;
-
- tree = atree;
- if (tree->op!=STAR && dcalc(tree, nreg-reg) > 12)
- return(-1);
- lbuf.op = LOAD;
- lbuf.type = tree->type;
- lbuf.degree = tree->degree;
- lbuf.tr1 = tree;
- return(rcexpr(&lbuf, table, reg));
- }
-
- /*
- * Compile a function argument.
- * If the stack is currently empty, put it in (sp)
- * rather than -(sp); this will save a pop.
- * Return the number of bytes pushed,
- * for future popping.
- */
- comarg(atree, flagp)
- int *flagp;
- {
- register struct tnode *tree;
- register retval;
-
- tree = atree;
- if (nstack || isfloat(tree) || tree->type==LONG) {
- rcexpr(tree, sptab, 0);
- retval = arlength(tree->type);
- } else {
- (*flagp)++;
- rcexpr(tree, lsptab, 0);
- retval = 0;
- }
- return(retval);
- }
-