diff options
Diffstat (limited to 'usr.bin/pcc/m16c/order.c')
-rw-r--r-- | usr.bin/pcc/m16c/order.c | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/usr.bin/pcc/m16c/order.c b/usr.bin/pcc/m16c/order.c new file mode 100644 index 00000000000..756bf747c07 --- /dev/null +++ b/usr.bin/pcc/m16c/order.c @@ -0,0 +1,600 @@ +/* $OpenBSD: order.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" +# include <strings.h> + +int canaddr(NODE *); + +/* + * should the assignment op p be stored, + * given that it lies as the right operand of o + * (or the left, if o==UNARY MUL) + */ +/* +void +stoasg(NODE *p, int o) +{ + if (x2debug) + printf("stoasg(%p, %o)\n", p, o); +} +*/ +/* should we delay the INCR or DECR operation p */ +int +deltest(NODE *p) +{ + return 0; +} + +/* + * Check if p can be autoincremented. + * XXX - nothing can be autoincremented for now. + */ +int +autoincr(NODE *p) +{ + return 0; +} + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + */ +int +offstar(NODE *p, int shape) +{ + if (x2debug) + printf("offstar(%p)\n", p); + + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( p->n_right->n_op == ICON ){ + geninsn(p->n_left, INBREG); + p->n_su = -1; + return 1; + } + } + geninsn(p, INBREG); + return 0; +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p) +{ +// NODE *l = p->n_left; + +#ifdef PCC_DEBUG + if (x2debug) { + printf("shumul(%p)\n", p); + fwalk(p, e2print, 0); + } +#endif + + /* Can only generate OREG of BREGs (or FB) */ + if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB)) + return SOREG; +#if 0 + if ((p->n_op == PLUS || p->n_op == MINUS) && + (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) && + p->n_right->n_op == ICON) + return SOREG; + return 0; +#else + return SOREG; +#endif +} + +/* + * Rewrite increment/decrement operation. + */ +int +setincr(NODE *p) +{ + if (x2debug) + printf("setincr(%p)\n", p); + + return(0); +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +#if 0 +/* + * register allocation for instructions with special preferences. + */ +regcode +regalloc(NODE *p, struct optab *q, int wantreg) +{ + regcode regc; + + if (q->op == DIV || q->op == MOD) { + /* + * 16-bit div. + */ + if (regblk[R0] & 1 || regblk[R2] & 1) + comperr("regalloc: needed regs inuse, node %p", p); + if (p->n_su & DORIGHT) { + regc = alloregs(p->n_right, A0); + if (REGNUM(regc) != A0) { + p->n_right = movenode(p->n_right, A0); + if ((p->n_su & RMASK) == ROREG) { + p->n_su &= ~RMASK; + p->n_su |= RREG; + p->n_right->n_su &= ~LMASK; + p->n_right->n_su |= LOREG; + } + freeregs(regc); + regblk[A0] |= 1; + } + } + regc = alloregs(p->n_left, R0); + if (REGNUM(regc) != R0) { + p->n_left = movenode(p->n_left, R0); + freeregs(regc); + regblk[R0] |= 1; + } + if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) { + regc = alloregs(p->n_right, A0); + if (REGNUM(regc) != A0) { + p->n_right = movenode(p->n_right, A0); + if ((p->n_su & RMASK) == ROREG) { + p->n_su &= ~RMASK; + p->n_su |= RREG; + p->n_right->n_su &= ~LMASK; + p->n_right->n_su |= LOREG; + } + } + } + regblk[A0] &= ~1; + regblk[R0] &= ~1; + regblk[R2] &= ~1; + if (q->op == DIV) { + MKREGC(regc, R0, 1); + regblk[R0] |= 1; + } else { + MKREGC(regc, R2, 1); + regblk[R2] |= 1; + } + } else + comperr("regalloc"); + p->n_rall = REGNUM(regc); + return regc; +} +#endif + +/* + * Special handling of some instruction register allocation. + * - left is the register that left node wants. + * - right is the register that right node wants. + * - res is in which register the result will end up. + * - mask is registers that will be clobbered. + * + * XXX - Fix this function + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + + case DIV: + case MOD: + if(q->ltype & (TINT|TSHORT)){ + static struct rspecial s[] = { + { NRES, R0 }, { NRES, R2}, { 0 } }; + return s; + } + /* + else if(q->ltype & TCHAR) { + static struct rspecial s[] = { + { NRES, R0L }, { NRES, R0H}, { 0 } }; + return s; + }*/ + break; + + case MUL: + /* + if(q->ltype & (TINT|TSHORT)){ + static struct rspecial s[] = { + { NRES, R0 }, { NRES, R2}, { 0 } }; + return s; + }*/ + comperr("multiplication not implemented"); + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + + +/* + * Splitup a function call and give away its arguments first. + * Calling convention used ("normal" in IAR syntax) is: + * - 1-byte parameters in R0L if possible, otherwise in R0H. + * - 2-byte pointers in A0. + * - 2-byte non-pointers in R0 if no byte-size arguments are found in + * in the first 6 bytes of parameters, otherwise R2 or at last A0. + * - 4-byte parameters in R2R0. + */ +void +gencall(NODE *p, NODE *prev) +{ + NODE *n = 0; /* XXX gcc */ + static int storearg(NODE *); + int o = p->n_op; + int ty = optype(o); + + if (ty == LTYPE) + return; + + switch (o) { + case CALL: + /* swap arguments on some hardop-converted insns */ + /* Normal call, just push args and be done with it */ + p->n_op = UCALL; +//printf("call\n"); + /* Check if left can be evaluated directly */ + if (p->n_left->n_op == UMUL) { + TWORD t = p->n_left->n_type; + int k = BITOOR(freetemp(szty(t))); + NODE *n = mklnode(OREG, k, FB, t); + NODE *q = tcopy(n); + pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t))); + p->n_left = q; + } + gencall(p->n_left, p); + p->n_rval = storearg(p->n_right); +//printf("end call\n"); + break; + + case UFORTCALL: + case FORTCALL: + comperr("FORTCALL"); + + case USTCALL: + case STCALL: + /* + * Structure return. Look at the node above + * to decide about buffer address: + * - FUNARG, allocate space on stack, don't remove. + * - nothing, allocate space on stack and remove. + * - STASG, get the address of the left side as arg. + * - FORCE, this ends up in a return, get supplied addr. + * (this is not pretty, but what to do?) + */ + if (prev == NULL || prev->n_op == FUNARG) { + /* Create nodes to generate stack space */ + n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT), + mkbinode(MINUS, mklnode(REG, 0, STKREG, INT), + mklnode(ICON, p->n_stsize, 0, INT), INT), INT); +//printf("stsize %d\n", p->n_stsize); + pass2_compile(ipnode(n)); + } else if (prev->n_op == STASG) { + n = prev->n_left; + if (n->n_op == UMUL) + n = nfree(n); + else if (n->n_op == NAME) { + n->n_op = ICON; /* Constant reference */ + n->n_type = INCREF(n->n_type); + } else + comperr("gencall stasg"); + } else if (prev->n_op == FORCE) { + ; /* do nothing here */ + } else { + comperr("gencall bad op %d", prev->n_op); + } + + /* Deal with standard arguments */ + gencall(p->n_left, p); + if (o == STCALL) { + p->n_op = USTCALL; + p->n_rval = storearg(p->n_right); + } else + p->n_rval = 0; + /* push return struct address */ + if (prev == NULL || prev->n_op == FUNARG) { + n = mklnode(REG, 0, STKREG, INT); + if (p->n_rval) + n = mkbinode(PLUS, n, + mklnode(ICON, p->n_rval, 0, INT), INT); + pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); + if (prev == NULL) + p->n_rval += p->n_stsize/4; + } else if (prev->n_op == FORCE) { + /* return value for this function */ + n = mklnode(OREG, 8, FPREG, INT); + pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); + p->n_rval++; + } else { + pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); + n = p; + *prev = *p; + nfree(n); + } +//printf("end stcall\n"); + break; + + default: + if (ty != UTYPE) + gencall(p->n_right, p); + gencall(p->n_left, p); + break; + } +} + +/* + * Create separate node trees for function arguments. + * This is partly ticky, the strange calling convention + * may cause a bunch of code reorganization here. + */ +static int +storearg(NODE *p) +{ + NODE *n, *q, **narry; + int nch, k, i, nn, rary[4]; + int r0l, r0h, r2, a0, stk, sz; + TWORD t; + int maxrargs = 0; + + if (p->n_op == CM) + maxrargs = p->n_stalign; + + /* count the arguments */ + for (i = 1, q = p; q->n_op == CM; q = q->n_left) + i++; + nn = i; + + /* allocate array to store arguments */ + narry = tmpalloc(sizeof(NODE *)*nn); + + /* enter nodes into array */ + for (q = p; q->n_op == CM; q = q->n_left) + narry[--i] = q->n_right; + narry[--i] = q; + + /* free CM nodes */ + for (q = p; q->n_op == CM; ) { + n = q->n_left; + nfree(q); + q = n; + } + + /* count char args */ + r0l = r0h = r2 = a0 = 0; + for (sz = nch = i = 0; i < nn && i < 6; i++) { + TWORD t = narry[i]->n_type; + if (sz >= 6) + break; + if (t == CHAR || t == UCHAR) { + nch++; + sz++; + } else if ((t >= SHORT && t <= UNSIGNED) || + t > BTMASK || t == FLOAT) { + sz += 2; + } else /* long, double */ + sz += 4; + + } + + /* + * Now the tricky part. The parameters that should be on stack + * must be found and pushed first, then the register parameters. + * For the latter, be sure that evaluating them do not use any + * registers where argument values already are inserted. + * XXX - function pointers? + * XXX foo(long a, char b) ??? + */ + for (stk = 0; stk < 4; stk++) { + TWORD t; + + if (stk == nn) + break; + t = narry[stk]->n_type; + if (ISFTN(DECREF(t))) + t = LONG; + switch (t) { + case CHAR: case UCHAR: + if (r0l) { + if (r0h) + break; + rary[stk] = R2; /* char talk for 'R0H' */ + r0h = 1; + } else { + rary[stk] = R0; + r0l = 1; + } + continue; + + case INT: case UNSIGNED: + if (r0l || nch) { + if (r2) { + if (a0) + break; + rary[stk] = A0; + a0 = 1; + } else { + rary[stk] = R2; + r2 = 1; + } + } else { + rary[stk] = R0; + r0l = r0h = 1; + } + continue; + + case LONG: case ULONG: + if (r0l || r2) + break; + rary[stk] = R0; + r0l = r0h = r2 = 1; + continue; + + default: + if (ISPTR(narry[stk]->n_type) && + !ISFTN(DECREF(narry[stk]->n_type))) { + if (a0) { + if (r0l || nch) { + if (r2) + break; + rary[stk] = R2; + r2 = 1; + } else { + rary[stk] = R0; + r0l = r0h = 1; + } + } else { + rary[stk] = A0; + a0 = 1; + } + continue; + } + break; + } + break; + } + + /* + * The arguments that must be on stack are stk->nn args. + * Argument 0->stk-1 should be put in the rary[] register. + */ + for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */ + NODE nod; + pass2_compile(ipnode(mkunode(FUNARG, + narry[i], 0, narry[i]->n_type))); + nod.n_type = narry[i]->n_type; + sz += tlen(&nod); + } + /* if param cannot be addressed directly, evaluate and put on stack */ + for (i = 0; i < stk; i++) { + + if (canaddr(narry[i])) + continue; + t = narry[i]->n_type; + k = BITOOR(freetemp(szty(t))); + n = mklnode(OREG, k, FB, t); + q = tcopy(n); + pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t))); + narry[i] = q; + } + /* move args to registers */ + for (i = 0; i < stk; i++) { + t = narry[i]->n_type; + pass2_compile(ipnode(mkbinode(ASSIGN, + mklnode(REG, 0, rary[i], t), narry[i], t))); + } + return sz; +} + +/* + * Tell if a register can hold a specific datatype. + */ +#if 0 +int +mayuse(int reg, TWORD type) +{ + return 1; /* Everything is OK */ +} +#endif + +#ifdef TAILCALL +void +mktailopt(struct interpass *ip1, struct interpass *ip2) +{ + extern int earlylab; + extern char *cftname; + char *fn; + NODE *p; + + p = ip1->ip_node->n_left->n_left; + if (p->n_op == ICON) { + fn = p->n_name; + /* calling ourselves */ + p = ip1->ip_node->n_left; + if (p->n_op == CALL) { + if (storearg(p->n_right)) + comperr("too many args: fix mktailopt"); + p->n_op = UCALL; + } + tfree(ip1->ip_node); + p = ip2->ip_node->n_left; + if (strcmp(fn, cftname)) { + /* Not us, must generate fake prologue */ + ip1->type = IP_ASM; + ip1->ip_asm = "mov.w FB,SP\n\tpop.w FB"; + pass2_compile(ip1); + p->n_lval = p->n_rval = 0; + p->n_name = fn; + } else + p->n_lval = earlylab; + } else { + pass2_compile(ip1); + } + pass2_compile(ip2); +} +#endif |