/* * 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: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(stdout, p->n_rval, 1); else fputs(rnames[p->n_rval], 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 >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } }
/* * 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: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(stdout, p->n_rval, 1); else printf("%s", rnames[p->n_rval]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf(CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } }
/* * Structure assignment. */ static void stasg(NODE *p) { assert(p->n_right->n_rval == A1); /* A0 = dest, A1 = src, A2 = len */ printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize); if (p->n_left->n_op == OREG) { printf("\taddiu %s,%s," CONFMT "\t# dest address\n", rnames[A0], rnames[p->n_left->n_rval], p->n_left->n_lval); } else if (p->n_left->n_op == NAME) { printf("\tla %s,", rnames[A0]); adrput(stdout, p->n_left); printf("\n"); } printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); printf("\tjal %s\t# structure copy\n", exname("memcpy")); printf("\tnop\n"); printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); }
/* * 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) { switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][2]); break; case NAME: case OREG: setlval(p, getlval(p) + 4); adrput(stdout, p); setlval(p, getlval(p) - 4); break; case ICON: printf("#%d", (int)getlval(p)); break; default: comperr("upput bad op %d size %d", p->n_op, size); } }
/* * 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) { switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][2]); break; case NAME: case OREG: p->n_lval += 4; adrput(stdout, p); p->n_lval -= 4; break; case ICON: printf("#%d", (int)p->n_lval); break; default: comperr("upput bad op %d size %d", p->n_op, size); } }
void zzzcode(NODE *p, int c) { NODE *l; int pr, lr; 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 */ #ifdef notyet if (p->n_left->n_flags & FSTDCALL) break; #endif pr = p->n_qual; if (p->n_op == STCALL || p->n_op == USTCALL) pr += 4; if (p->n_flags & FFPPOP) printf(" fstp %%st(0)\n"); 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 'F': /* Structure argument */ if (p->n_stalign != 0) /* already on stack */ starg(p); break; case 'G': /* Floating point compare */ fcomp(p); break; case 'H': /* assign of longlong between regs */ rmove(DECRA(p->n_right->n_reg, 0), DECRA(p->n_left->n_reg, 0), LONGLONG); break; case 'I': /* float casts */ fcast(p); break; case 'J': /* convert unsigned long long to floating point */ ulltofp(p); break; case 'K': /* Load longlong reg into another reg */ rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG); 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) { llshft(p); break; } else if (p->n_op == MUL) { printf("\timull %%ecx, %%edx\n"); printf("\timull %%eax, %%esi\n"); printf("\taddl %%edx, %%esi\n"); printf("\tmull %%ecx\n"); printf("\taddl %%esi, %%edx\n"); break; } 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 == MOD && p->n_type == ULONGLONG) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else ch = 0, comperr("ZO"); #ifdef ELFABI printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n", ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]); #else printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n", ch, pr, rnames[ESP]); #endif break; case 'P': /* push hidden argument on stack */ 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 */ /* * With <= 16 bytes, put out mov's, otherwise use movsb/w/l. * esi/edi/ecx are available. * XXX should not need esi/edi if not rep movsX. * XXX can save one insn if src ptr in reg. */ switch (p->n_stsize) { case 1: expand(p, INAREG, " movb (%esi),%cl\n"); expand(p, INAREG, " movb %cl,AL\n"); break; case 2: expand(p, INAREG, " movw (%esi),%cx\n"); expand(p, INAREG, " movw %cx,AL\n"); break; case 4: expand(p, INAREG, " movl (%esi),%ecx\n"); expand(p, INAREG, " movl %ecx,AL\n"); break; default: expand(p, INAREG, " leal AL,%edi\n"); if (p->n_stsize <= 16 && (p->n_stsize & 3) == 0) { printf(" movl (%%esi),%%ecx\n"); printf(" movl %%ecx,(%%edi)\n"); printf(" movl 4(%%esi),%%ecx\n"); printf(" movl %%ecx,4(%%edi)\n"); if (p->n_stsize > 8) { printf(" movl 8(%%esi),%%ecx\n"); printf(" movl %%ecx,8(%%edi)\n"); } if (p->n_stsize == 16) { printf("\tmovl 12(%%esi),%%ecx\n"); printf("\tmovl %%ecx,12(%%edi)\n"); } } else { if (p->n_stsize > 4) { printf("\tmovl $%d,%%ecx\n", p->n_stsize >> 2); printf(" rep movsl\n"); } if (p->n_stsize & 2) printf(" movsw\n"); if (p->n_stsize & 1) printf(" movsb\n"); } break; } 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 */ expand(p, INAREG, "\tmovl AL,A2\n"); expand(p, INBREG, "\tmovb A2,A1\n"); #ifdef notdef /* cannot use freetemp() in instruction emission */ s = BITOOR(freetemp(1)); printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s); printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]); #endif 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); }
void zzzcode(NODE *p, int c) { NODE *l, *r; TWORD t; int m; char *ch; switch (c) { case 'N': /* logical ops, turned into 0-1 */ /* use register given by register 1 */ cbgen( 0, m=getlab2()); deflab( p->n_label ); printf( " clrl %s\n", rnames[getlr( p, '1' )->n_rval] ); deflab( m ); return; case 'A': /* Assign a constant directly to a memory position */ printf("\t"); if (p->n_type < LONG || ISPTR(p->n_type)) casg(p); else casg64(p); printf("\n"); break; case 'B': /* long long compare */ twollcomp(p); break; case 'C': /* num words pushed on arg stack */ printf("$%d", p->n_qual); break; case 'D': /* INCR and DECR */ zzzcode(p->n_left, 'A'); printf("\n "); #if 0 case 'E': /* INCR and DECR, FOREFF */ if (p->n_right->n_lval == 1) { printf("%s", (p->n_op == INCR ? "inc" : "dec") ); prtype(p->n_left); printf(" "); adrput(stdout, p->n_left); return; } printf("%s", (p->n_op == INCR ? "add" : "sub") ); prtype(p->n_left); printf("2 "); adrput(stdout, p->n_right); printf(","); adrput(p->n_left); return; #endif case 'F': /* register type of right operand */ { register NODE *n; register int ty; n = getlr( p, 'R' ); ty = n->n_type; if (x2debug) printf("->%d<-", ty); if ( ty==DOUBLE) printf("d"); else if ( ty==FLOAT ) printf("f"); else printf("l"); return; } case 'G': /* emit conversion instructions */ sconv(p); break; case 'J': /* jump or ret? */ { struct interpass *ip = DLIST_PREV((struct interpass *)p2env.epp, qelem); if (ip->type != IP_DEFLAB || ip->ip_lbl != getlr(p, 'L')->n_lval) expand(p, FOREFF, "jbr LL"); else printf("ret"); } break; case 'L': /* type of left operand */ case 'R': /* type of right operand */ { register NODE *n; n = getlr ( p, c); if (x2debug) printf("->%d<-", n->n_type); prtype(n); return; } case 'O': /* print out emulated ops */ expand(p, FOREFF, "\tmovq AR,-(%sp)\n"); expand(p, FOREFF, "\tmovq AL,-(%sp)\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 == MOD && p->n_type == ULONGLONG) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else if (p->n_op == MUL) ch = "mul"; else ch = 0, comperr("ZO %d", p->n_op); printf("\tcalls $4,__%sdi3\n", ch); break; case 'Z': /* complement mask for bit instr */ printf("$%Ld", ~p->n_right->n_lval); return; case 'U': /* 32 - n, for unsigned right shifts */ t = DEUNSIGN(p->n_left->n_type); m = t == CHAR ? 8 : t == SHORT ? 16 : 32; printf("$" CONFMT, m - p->n_right->n_lval); return; case 'T': /* rounded structure length for arguments */ { int size; size = p->n_stsize; SETOFF( size, 4); printf("$%d", size); return; } case 'S': /* structure assignment */ { register int size; size = p->n_stsize; l = r = NULL; /* XXX gcc */ if( p->n_op == STASG ){ l = p->n_left; r = p->n_right; } else if( p->n_op == STARG ){ /* store an arg into a temporary */ printf("\tsubl2 $%d,%%sp\n", size < 4 ? 4 : size); l = mklnode(OREG, 0, SP, INT); r = p->n_left; } else cerror( "STASG bad" ); if( r->n_op == ICON ) r->n_op = NAME; else if( r->n_op == REG ) r->n_op = OREG; else if( r->n_op != OREG ) cerror( "STASG-r" ); if (size != 0) { if( size <= 0 || size > 65535 ) cerror("structure size <0=0 or >65535"); switch(size) { case 1: printf(" movb "); break; case 2: printf(" movw "); break; case 4: printf(" movl "); break; case 8: printf(" movq "); break; default: printf(" movc3 $%d,", size); break; } adrput(stdout, r); printf(","); adrput(stdout, l); printf("\n"); } if( r->n_op == NAME ) r->n_op = ICON; else if( r->n_op == OREG ) r->n_op = REG; if (p->n_op == STARG) tfree(l); } break; default: comperr("illegal zzzcode '%c'", c); } }
/* * generate code by interpreting table entry */ void expand(NODE *p, int cookie, char *cp) { CONSZ val; #if 0 printf("expand\n"); fwalk(p, e2print, 0); #endif for( ; *cp; ++cp ){ switch( *cp ){ default: putchar(*cp); continue; /* this is the usual case... */ case 'Z': /* special machine dependent operations */ zzzcode( p, *++cp ); continue; case 'F': /* this line deleted if FOREFF is active */ if (cookie & FOREFF) { while (*cp && *cp != '\n') cp++; if (*cp == 0) return; } continue; case 'S': /* field size */ if (fldexpand(p, cookie, &cp)) continue; printf("%d", FLDSZ(p->n_rval)); continue; case 'H': /* field shift */ if (fldexpand(p, cookie, &cp)) continue; printf("%d", FLDSHF(p->n_rval)); continue; case 'M': /* field mask */ case 'N': /* complement of field mask */ if (fldexpand(p, cookie, &cp)) continue; val = 1; val <<= FLDSZ(p->n_rval); --val; val <<= FLDSHF(p->n_rval); adrcon( *cp=='M' ? val : ~val ); continue; case 'L': /* output special label field */ if (*++cp == 'C') printf(LABFMT, p->n_label); else printf(LABFMT, (int)getlval(getlr(p,*cp))); continue; case 'O': /* opcode string */ #ifdef FINDMOPS if (p->n_op == ASSIGN) hopcode(*++cp, p->n_right->n_op); else #endif hopcode( *++cp, p->n_op ); continue; case 'B': /* byte offset in word */ val = getlval(getlr(p,*++cp)); val = BYTEOFF(val); printf( CONFMT, val ); continue; case 'C': /* for constant value only */ conput(stdout, getlr( p, *++cp ) ); continue; case 'I': /* in instruction */ insput( getlr( p, *++cp ) ); continue; case 'A': /* address of */ adrput(stdout, getlr( p, *++cp ) ); continue; case 'U': /* for upper half of address, only */ upput(getlr(p, *++cp), SZLONG); continue; } } }
/* * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines */ static void fpemulop(NODE *p) { NODE *l = p->n_left; char *ch = NULL; if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; else if (p->n_op == SCONV && p->n_type == FLOAT) { if (l->n_type == DOUBLE) ch = "truncdfsf2"; else if (l->n_type == LDOUBLE) ch = "trunctfsf2"; else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/ else if (l->n_type == LONGLONG) ch = "floatdisf"; else if (l->n_type == LONG) ch = "floatsisf"; else if (l->n_type == ULONG) ch = "floatunsisf"; else if (l->n_type == INT) ch = "floatsisf"; else if (l->n_type == UNSIGNED) ch = "floatunsisf"; } else if (p->n_op == SCONV && p->n_type == DOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunsidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { if (l->n_type == FLOAT) ch = "extendsftf2"; else if (l->n_type == DOUBLE) ch = "extenddfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunssidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && p->n_type == LONGLONG) { if (l->n_type == FLOAT) ch = "fixsfdi"; else if (l->n_type == DOUBLE) ch = "fixdfdi"; else if (l->n_type == LDOUBLE) ch = "fixdfdi"; } else if (p->n_op == SCONV && p->n_type == LONG) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == ULONG) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } else if (p->n_op == SCONV && p->n_type == INT) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); if (p->n_op == SCONV) { if (l->n_type == FLOAT) { printf("\tmfc1 %s,", rnames[A0]); adrput(stdout, l); printf("\n\tnop\n"); } else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) { printf("\tmfc1 %s,", rnames[A1]); upput(l, 0); printf("\n\tnop\n"); printf("\tmfc1 %s,", rnames[A0]); adrput(stdout, l); printf("\n\tnop\n"); } } else { comperr("ZF: incomplete softfloat - put args in registers"); } printf("\tjal __%s\t# softfloat operation\n", exname(ch)); printf("\tnop\n"); if (p->n_op >= EQ && p->n_op <= GT) printf("\tcmp %s,0\n", rnames[V0]); }