diff options
Diffstat (limited to 'usr.bin/pcc/arch/x86/local2.c')
-rw-r--r-- | usr.bin/pcc/arch/x86/local2.c | 1051 |
1 files changed, 1051 insertions, 0 deletions
diff --git a/usr.bin/pcc/arch/x86/local2.c b/usr.bin/pcc/arch/x86/local2.c new file mode 100644 index 00000000000..ec3c521a3db --- /dev/null +++ b/usr.bin/pcc/arch/x86/local2.c @@ -0,0 +1,1051 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:31 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 <ctype.h> +# include <string.h> + +void acon(NODE *p); +int argsize(NODE *p); + +static int stkpos; + +void +lineid(int l, char *fn) +{ + /* identify line l and file fn */ + printf("# line %d, file %s\n", l, fn); +} + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[7]; +static TWORD ftype; + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +static void +prtprolog(struct interpass_prolog *ipp, int addto) +{ + int i, j; + + printf(" pushl %%ebp\n"); + printf(" movl %%esp,%%ebp\n"); + if (addto) + printf(" subl $%d,%%esp\n", addto); + for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) + if (i & 1) + fprintf(stdout, " movl %s,-%d(%s)\n", + rnames[j], regoff[j], rnames[FPREG]); +} + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int i, j, addto; + + addto = p2maxautooff; + if (addto >= AUTOINIT/SZCHAR) + addto -= AUTOINIT/SZCHAR; + for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { + if (i & 1) { + addto += SZINT/SZCHAR; + regoff[j] = addto; + } + } + return addto; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + + ftype = ipp->ipp_type; + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf(" .align 4\n"); + printf("%s:\n", ipp->ipp_name); + /* + * We here know what register to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); + prtprolog(ipp, addto); +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i, j; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* return from function code */ + for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { + if (i & 1) + fprintf(stdout, " movl -%d(%s),%s\n", + regoff[j], rnames[FPREG], rnames[j]); + + } + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + printf(" movl 8(%%ebp),%%eax\n"); + printf(" leave\n"); + printf(" ret $4\n"); + } else { + printf(" leave\n"); + printf(" ret\n"); + } +} + +/* + * 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); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + 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, " cmpl UR,UL\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmpl AR,AL\n"); + cbgen(p->n_op, e); + deflab(s); +} + +/* + * Assign to a bitfield. + * Clumsy at least, but what to do? + */ +static void +bfasg(NODE *p) +{ + NODE *fn = p->n_left; + int shift = UPKFOFF(fn->n_rval); + int fsz = UPKFSZ(fn->n_rval); + int andval, tch = 0; + + /* get instruction size */ + switch (p->n_type) { + case CHAR: case UCHAR: tch = 'b'; break; + case SHORT: case USHORT: tch = 'w'; break; + case INT: case UNSIGNED: tch = 'l'; break; + default: comperr("bfasg"); + } + + /* put src into a temporary reg */ + fprintf(stdout, " mov%c ", tch); + adrput(stdout, getlr(p, 'R')); + fprintf(stdout, ","); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + + /* AND away the bits from dest */ + andval = ~(((1 << fsz) - 1) << shift); + fprintf(stdout, " and%c $%d,", tch, andval); + adrput(stdout, fn->n_left); + fprintf(stdout, "\n"); + + /* AND away unwanted bits from src */ + andval = ((1 << fsz) - 1); + fprintf(stdout, " and%c $%d,", tch, andval); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + + /* SHIFT left src number of bits */ + if (shift) { + fprintf(stdout, " sal%c $%d,", tch, shift); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + } + + /* OR in src to dest */ + fprintf(stdout, " or%c ", tch); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, ","); + adrput(stdout, fn->n_left); + fprintf(stdout, "\n"); +} + +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + FILE *fp = stdout; + + fprintf(fp, " subl $%d,%%esp\n", p->n_stsize); + fprintf(fp, " pushl $%d\n", p->n_stsize); + expand(p, 0, " pushl AL\n"); + expand(p, 0, " leal 8(%esp),A1\n"); + expand(p, 0, " pushl A1\n"); + fprintf(fp, " call memcpy\n"); + fprintf(fp, " addl $12,%%esp\n"); +} + +/* + * Compare two floating point numbers. + */ +static void +fcomp(NODE *p) +{ + + if (p->n_left->n_op == REG) { + if (p->n_su & DORIGHT) + expand(p, 0, " fxch\n"); + expand(p, 0, " fucompp\n"); /* emit compare insn */ + } else if (p->n_left->n_type == DOUBLE) + expand(p, 0, " fcompl AL\n"); /* emit compare insn */ + else if (p->n_left->n_type == FLOAT) + expand(p, 0, " fcomp AL\n"); /* emit compare insn */ + else + comperr("bad compare %p\n", p); + expand(p, 0, " fnstsw %ax\n"); /* move status reg to ax */ + + switch (p->n_op) { + case EQ: + expand(p, 0, " andb $64,%ah\n jne LC\n"); + break; + case NE: + expand(p, 0, " andb $64,%ah\n je LC\n"); + break; + case LE: + expand(p, 0, " andb $65,%ah\n cmpb $1,%ah\n jne LC\n"); + break; + case LT: + expand(p, 0, " andb $65,%ah\n je LC\n"); + break; + case GT: + expand(p, 0, " andb $1,%ah\n jne LC\n"); + break; + case GE: + expand(p, 0, " andb $65,%ah\n jne LC\n"); + break; + default: + comperr("fcomp op %d\n", p->n_op); + } +} + +/* + * Convert an unsigned long long to floating point number. + */ +static void +ulltofp(NODE *p) +{ + static int loadlab; + int jmplab; + + if (loadlab == 0) { + loadlab = getlab(); + expand(p, 0, " .data\n"); + printf(LABFMT ": .long 0,0x80000000,0x403f\n", loadlab); + expand(p, 0, " .text\n"); + } + jmplab = getlab(); + expand(p, 0, " pushl UL\n pushl AL\n"); + expand(p, 0, " fildq (%esp)\n"); + expand(p, 0, " addl $8,%esp\n"); + expand(p, 0, " cmpl $0,UL\n"); + printf(" jge " LABFMT "\n", jmplab); + printf(" fldt " LABFMT "\n", loadlab); + printf(" faddp %%st,%%st(1)\n"); + printf(LABFMT ":\n", jmplab); +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY || t == UNIONTY) + return p->n_stsize; + comperr("argsiz"); + return 0; +} + +void +zzzcode(NODE *p, int c) +{ + NODE *r, *l; + int pr, lr, s; + char *ch; + + switch (c) { + case 'A': /* swap st0 and st1 if right is evaluated second */ + if ((p->n_su & DORIGHT) == 0) { + if (logop(p->n_op)) + printf(" fxch\n"); + else + printf("r"); + } + break; + + case 'C': /* remove from stack after subroutine call */ + pr = p->n_qual; + if (p->n_op == STCALL || p->n_op == USTCALL) + pr += 4; + if (p->n_op == UCALL) + return; /* XXX remove ZC from UCALL */ + if (pr) + printf(" addl $%d, %s\n", pr, rnames[ESP]); + break; + + case 'D': /* Long long comparision */ + twollcomp(p); + break; + + case 'E': /* Assign to bitfield */ + bfasg(p); + break; + + case 'F': /* Structure argument */ + if (p->n_stalign != 0) /* already on stack */ + starg(p); + break; + + case 'G': /* Floating point compare */ + fcomp(p); + break; + + case 'J': /* convert unsigned long long to floating point */ + ulltofp(p); + break; + + case 'M': /* Output sconv move, if needed */ + l = getlr(p, 'L'); + /* XXX fixneed: regnum */ + pr = DECRA(p->n_reg, 0); + lr = DECRA(l->n_reg, 0); + if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) || + (pr == CL && lr == ECX) || (pr == DL && lr == EDX)) + ; + else + printf(" movb %%%cl,%s\n", + rnames[lr][2], rnames[pr]); + l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ + break; + + case 'N': /* output extended reg name */ + printf("%s", rnames[getlr(p, '1')->n_rval]); + break; + + case 'O': /* print out emulated ops */ + pr = 16; + if (p->n_op == RS || p->n_op == LS) { + expand(p, INAREG, "\tpushl AR\n"); + pr = 12; + } else + expand(p, INCREG, "\tpushl UR\n\tpushl AR\n"); + expand(p, INCREG, "\tpushl UL\n\tpushl AL\n"); + if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; + else if (p->n_op == DIV) ch = "div"; + else if (p->n_op == MUL) ch = "mul"; + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; + else if (p->n_op == MOD) ch = "mod"; + else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshr"; + else if (p->n_op == RS) ch = "ashr"; + else if (p->n_op == LS) ch = "ashl"; + else ch = 0, comperr("ZO"); + printf("\tcall __%sdi3\n\taddl $%d,%s\n", ch, pr, rnames[ESP]); + break; + + case 'P': /* push hidden argument on stack */ + r = (NODE *)p->n_sue; + printf("\tleal -%d(%%ebp),", stkpos); + adrput(stdout, getlr(p, '1')); + printf("\n\tpushl "); + adrput(stdout, getlr(p, '1')); + putchar('\n'); + break; + + case 'Q': /* emit struct assign */ + /* XXX - optimize for small structs */ + printf("\tpushl $%d\n", p->n_stsize); + expand(p, INAREG, "\tpushl AR\n"); + expand(p, INAREG, "\tleal AL,%eax\n\tpushl %eax\n"); + printf("\tcall memcpy\n"); + printf("\taddl $12,%%esp\n"); + break; + + case 'S': /* emit eventual move after cast from longlong */ + pr = DECRA(p->n_reg, 0); + lr = p->n_left->n_rval; + switch (p->n_type) { + case CHAR: + case UCHAR: + if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' && + rnames[pr][1] == rnames[lr][1]) + break; + if (rnames[lr][2] == 'x') { + printf("\tmovb %%%cl,%s\n", + rnames[lr][1], rnames[pr]); + break; + } + /* Must go via stack */ + s = BITOOR(freetemp(1)); + printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s); + printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]); +// comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]); + break; + + case SHORT: + case USHORT: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + printf("\tmovw %%%c%c,%%%s\n", + rnames[lr][1], rnames[lr][2], rnames[pr]+2); + break; + case INT: + case UNSIGNED: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + printf("\tmovl %%e%c%c,%s\n", + rnames[lr][1], rnames[lr][2], rnames[pr]); + break; + + default: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]); + break; + } + break; + + default: + comperr("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))) + 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; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +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, p %p", p); + } +} + +/*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 /= SZCHAR; + switch (p->n_op) { + case REG: + fprintf(stdout, "%%%s", &rnames[p->n_rval][3]); + 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 >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + /* 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); + } else + fprintf(io, CONFMT, p->n_lval); + return; + + case OREG: + r = p->n_rval; + if (p->n_lval) + fprintf(io, "%d", (int)p->n_lval); + if (R2TEST(r)) { + fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)], + rnames[R2UPK2(r)]); + } else + 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: + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + fprintf(io, "%%%c%c%c", rnames[p->n_rval][0], + rnames[p->n_rval][1], rnames[p->n_rval][2]); + break; + case SHORT: + case USHORT: + fprintf(io, "%%%s", &rnames[p->n_rval][2]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "je", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jl", /* jumpl */ + "jge", /* jumpge */ + "jg", /* jumpg */ + "jbe", /* jumple (jlequ) */ + "jb", /* jumpl (jlssu) */ + "jae", /* jumpge (jgequ) */ + "ja", /* 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); +} + +static void +fixcalls(NODE *p) +{ + /* Prepare for struct return by allocating bounce space on stack */ + switch (p->n_op) { + case STCALL: + case USTCALL: + if (p->n_stsize+p2autooff > stkpos) + stkpos = p->n_stsize+p2autooff; + break; + } +} + +/* + * Must store floats in memory if there are two function calls involved. + */ +static int +storefloat(struct interpass *ip, NODE *p) +{ + int l, r; + + switch (optype(p->n_op)) { + case BITYPE: + l = storefloat(ip, p->n_left); + r = storefloat(ip, p->n_right); + if (p->n_op == CM) + return 0; /* arguments, don't care */ + if (callop(p->n_op)) + return 1; /* found one */ +#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ + (p)->n_type == LDOUBLE) + if (ISF(p->n_left) && ISF(p->n_right) && l && r) { + /* must store one. store left */ + struct interpass *nip; + TWORD t = p->n_left->n_type; + NODE *ll; + int off; + + off = BITOOR(freetemp(szty(t))); + ll = mklnode(OREG, off, FPREG, t); + nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); + p->n_left = mklnode(OREG, off, FPREG, t); + DLIST_INSERT_BEFORE(ip, nip, qelem); + } + return l|r; + + case UTYPE: + l = storefloat(ip, p->n_left); + if (callop(p->n_op)) + l = 1; + return l; + default: + return 0; + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls); + storefloat(ip, ip->ip_node); + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2); +} + +void +myoptim(struct interpass *ip) +{ +} + +static char rl[] = + { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI }; +static char rh[] = + { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI }; + +void +rmove(int s, int d, TWORD t) +{ + int sl, sh, dl, dh; + + switch (t) { + case LONGLONG: + case ULONGLONG: +#if 1 + sl = rl[s-EAXEDX]; + sh = rh[s-EAXEDX]; + dl = rl[d-EAXEDX]; + dh = rh[d-EAXEDX]; + + /* sanity checks, remove when satisfied */ + if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 || + memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0) + comperr("rmove source error"); + if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 || + memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0) + comperr("rmove dest error"); +#define SW(x,y) { int i = x; x = y; y = i; } + if (sl == dh || sh == dl) { + /* Swap if moving to itself */ + SW(sl, sh); + SW(dl, dh); + } + if (sl != dl) + printf(" movl %s,%s\n", rnames[sl], rnames[dl]); + if (sh != dh) + printf(" movl %s,%s\n", rnames[sh], rnames[dh]); +#else + if (memcmp(rnames[s], rnames[d], 3) != 0) + printf(" movl %%%c%c%c,%%%c%c%c\n", + rnames[s][0],rnames[s][1],rnames[s][2], + rnames[d][0],rnames[d][1],rnames[d][2]); + if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0) + printf(" movl %%%c%c%c,%%%c%c%c\n", + rnames[s][3],rnames[s][4],rnames[s][5], + rnames[d][3],rnames[d][4],rnames[d][5]); +#endif + break; + case CHAR: + case UCHAR: + printf(" movb %s,%s\n", rnames[s], rnames[d]); + break; + case FLOAT: + case DOUBLE: + case LDOUBLE: +#ifdef notdef + /* a=b()*c(); will generate this */ + comperr("bad float rmove: %d %d", s, d); +#endif + break; + default: + printf(" movl %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[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + num += r[CLASSA]; + return num < 6; + case CLASSB: + num = r[CLASSA]; + num += 2*r[CLASSC]; + num += r[CLASSB]; + return num < 4; + case CLASSC: + num = r[CLASSA]; + num += r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + return num < 5; + case CLASSD: + return r[CLASSD] < DREGCNT; + } + return 0; /* XXX gcc */ +} + +char *rnames[] = { + "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp", + "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh", + "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx", + "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi", + "ebxesi", "ebxedi", "esiedi", + "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7", +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == CHAR || t == UCHAR) + return CLASSB; + if (t == LONGLONG || t == ULONGLONG) + return CLASSC; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return CLASSD; + return CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPCON: + if (o != ICON || p->n_name[0] || p->n_lval < 0) + break; + return SRDIR; + } + return SRNOPE; +} |