/* $Id: local2.c,v 1.1.1.2 2007/10/27 14:43:32 ragge 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 void acon(NODE *p); int argsize(NODE *p); void genargs(NODE *p); static int ftlab1, ftlab2; void deflab(int label) { printf(LABFMT ":\n", label); } static TWORD ftype; static int addto; void prologue(struct interpass_prolog *ipp) { ftype = ipp->ipp_type; #if 0 if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR) comperr("fix prologue register savings", ipp->ipp_regs); #endif printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); if (ipp->ipp_vis) printf(" PUBLIC %s\n", ipp->ipp_name); printf("%s:\n", ipp->ipp_name); #if 0 if (xsaveip) { /* Optimizer running, save space on stack */ addto = (p2maxautooff - AUTOINIT)/SZCHAR; printf(" enter #%d\n", addto); } else { #endif /* non-optimized code, jump to epilogue for code generation */ ftlab1 = getlab(); ftlab2 = getlab(); printf(" jmp.w " LABFMT "\n", ftlab1); deflab(ftlab2); } /* * End of block. */ void eoftn(struct interpass_prolog *ipp) { #if 0 if (ipp->ipp_regs != MINRVAR) comperr("fix eoftn register savings %x", ipp->ipp_regs); #endif // if (xsaveip == 0) addto = (p2maxautooff - AUTOINIT)/SZCHAR; /* return from function code */ //deflab(ipp->ipp_ip.ip_lbl); //XXX - is this necessary? /* If retval is a pointer and not a function pointer, put in A0 */ if (ISPTR(DECREF(ipp->ipp_type)) && !ISFTN(DECREF(DECREF(ipp->ipp_type)))) printf(" mov.w r0,a0\n"); /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) { comperr("fix struct return in eoftn"); } else printf(" exitd\n"); /* Prolog code */ // if (xsaveip == 0) { deflab(ftlab1); printf(" enter #%d\n", addto); printf(" jmp.w " LABFMT "\n", ftlab2); //} } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s.%c", str, f); } char * rnames[] = { /* keyed to register number tokens */ "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l", "r1h", "r1l", }; /* * Return the size (in bytes) of some types. */ int tlen(p) NODE *p; { switch(p->n_type) { case CHAR: case UCHAR: return(1); case INT: case UNSIGNED: case FLOAT: return 2; case DOUBLE: case LONG: case ULONG: return 4; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, " cmp.w UR,UL\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, " cmp.w AR,AL\n"); cbgen(p->n_op, e); deflab(s); } void zzzcode(NODE *p, int c) { NODE *l; switch (c) { case 'A': /* print negative shift constant */ p = getlr(p, 'R'); if (p->n_op != ICON) comperr("ZA bad use"); p->n_lval = -p->n_lval; adrput(stdout, p); p->n_lval = -p->n_lval; break; case 'B': if (p->n_rval) printf(" add.b #%d,%s\n", p->n_rval, rnames[STKREG]); break; case 'C': /* Print label address */ p = p->n_left; if (p->n_lval) printf(LABFMT, (int)p->n_lval); else printf("%s", p->n_name); break; case 'D': /* copy function pointers */ l = p->n_left; printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n", p->n_right->n_name, rnames[l->n_rval+1], p->n_right->n_name, rnames[l->n_rval]); break; case 'E': /* double-reg printout */ /* XXX - always r0r2 here */ printf("%s%s", rnames[R0], rnames[R2]); break; case 'F': /* long comparisions */ twollcomp(p); break; case 'G': printf("R0R2"); break; case 'H': /* push 32-bit address (for functions) */ printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n", p->n_left->n_name, p->n_left->n_name); break; case 'I': /* push 32-bit address (for functions) */ l = p->n_left; printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n", (int)l->n_lval, rnames[l->n_rval], (int)l->n_lval+2, rnames[l->n_rval]); break; default: comperr("bad zzzcode %c", c); } } /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left) == SRDIR)) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = p->n_lval; switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput"); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZINT; switch (p->n_op) { case REG: fputs(rnames[p->n_rval + 1], stdout); break; case NAME: case OREG: p->n_lval += size; adrput(stdout, p); p->n_lval -= size; break; case ICON: fprintf(stdout, "#" CONFMT, p->n_lval >> 16); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') fputs(p->n_name, io); if (p->n_lval != 0) fprintf(io, "+" CONFMT, p->n_lval); return; case OREG: if (p->n_lval) fprintf(io, "%d", (int)p->n_lval); fprintf(io, "[%s]", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ fputc('#', io); conput(io, p); return; case MOVE: case REG: /*if (DEUNSIGN(p->n_type) == CHAR) { fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1', (p->n_rval & 1) ? 'H' : 'L'); } else*/ fprintf(io, "%s", rnames[p->n_rval]); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "jeq", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jlt", /* jumpl */ "jge", /* jumpge */ "jgt", /* jumpg */ "jleu", /* jumple (jlequ) */ "jltu", /* jumpl (jlssu) */ "jgeu", /* jumpge (jgequ) */ "jgtu", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); } #if 0 void mygenregs(NODE *p) { if (p->n_op == MINUS && p->n_type == DOUBLE && (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) { p->n_su |= DORIGHT; } /* Must walk down correct node first for logops to work */ if (p->n_op != CBRANCH) return; p = p->n_left; if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG)) return; p->n_su &= ~DORIGHT; } #endif struct hardops hardops[] = { { PLUS, FLOAT, "?F_ADD_L04" }, { MUL, LONG, "?L_MUL_L03" }, { MUL, ULONG, "?L_MUL_L03" }, { DIV, LONG, "?SL_DIV_L03" }, { DIV, ULONG, "?UL_DIV_L03" }, { MOD, LONG, "?SL_MOD_L03" }, { MOD, ULONG, "?UL_MOD_L03" }, { RS, LONGLONG, "__ashrdi3" }, { RS, ULONGLONG, "__lshrdi3" }, { LS, LONGLONG, "__ashldi3" }, { LS, ULONGLONG, "__ashldi3" }, { 0 }, }; int special(NODE *p, int shape) { switch (shape) { case SFTN: if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) { if (p->n_op == NAME || p->n_op == OREG) return SRDIR; else return SRREG; } break; } return SRNOPE; } void myreader(NODE *p) { NODE *q, *r, *s, *right; if (optype(p->n_op) == LTYPE) return; if (optype(p->n_op) != UTYPE) myreader(p->n_right); myreader(p->n_left); switch (p->n_op) { case PLUS: case MINUS: if (p->n_type != LONG && p->n_type != ULONG) break; if (p->n_right->n_op == NAME || p->n_right->n_op == OREG) break; /* Must convert right into OREG */ right = p->n_right; q = mklnode(OREG, BITOOR(freetemp(szty(right->n_type))), FPREG, right->n_type); s = mkbinode(ASSIGN, q, right, right->n_type); r = talloc(); *r = *q; p->n_right = r; pass2_compile(ipnode(s)); break; } } void rmove(int s, int d, TWORD t) { switch (t) { case CHAR: case UCHAR: printf(" mov.b %s,%s\n", rnames[s], rnames[d]); break; default: printf(" mov.w %s,%s\n", rnames[s], rnames[d]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; switch (c) { case CLASSA: num = r[CLASSA]; num += r[CLASSC]; return num < 4; case CLASSB: num = r[CLASSB]; return num < 2; case CLASSC: num = 2*r[CLASSA]; num += r[CLASSC]; return num < 4; } return 0; /* XXX gcc */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == CHAR || t == UCHAR) return CLASSC; if(ISPTR(t)) return CLASSB; return CLASSA; } static int sizen; /* XXX: Fix this. */ static int argsiz(NODE *p) { TWORD t = p->n_type; if (t < LONGLONG || t > MAXTYPES) return 4; if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) return 8; if (t == LDOUBLE) return 12; if (t == STRTY) return p->n_stsize; comperr("argsiz"); return 0; } /* * Calculate argument sizes. * XXX: Fix this. */ void lastcall(NODE *p) { sizen = 0; for (p = p->n_right; p->n_op == CM; p = p->n_left) sizen += argsiz(p->n_right); sizen += argsiz(p); }