static void starg(NODE *p) { int sz = p->n_stsize; int subsz = (p->n_stsize + 3) & ~3; int fr, tr, cr; fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */ cr = regno(getlr(p, '1')); /* count reg (number of words) */ tr = regno(getlr(p, '2')); /* to reg (stack) */ /* Sub from stack and put in toreg */ printf(" sub.l #%d,%%sp\n", subsz); printf(" move.l %%sp,%s\n", rnames[tr]); /* Gen an even copy start */ if (sz & 1) expand(p, INBREG, " move.b (A2)+,(AL)+\n"); if (sz & 2) expand(p, INBREG, " move.w (A2)+,(AL)+\n"); sz -= (sz & ~3); /* if more than 4 words, use loop, otherwise output instructions */ if (sz > 16) { printf(" move.l #%d,%s\n", sz/4, rnames[cr]); expand(p, INBREG, "1: move.l (A2)+,(AL)+\n"); expand(p, INBREG, " dec.l A1\n"); expand(p, INBREG, " jne 1b\n"); } else { if (sz > 12) expand(p, INBREG, " move.l (A2)+,(AL)+\n"), sz -= 4; if (sz > 8) expand(p, INBREG, " move.l (A2)+,(AL)+\n"), sz -= 4; if (sz > 4) expand(p, INBREG, " move.l (A2)+,(AL)+\n"), sz -= 4; if (sz == 4) expand(p, INBREG, " move.l (A2)+,(AL)+\n"); } }
void zzzcode(NODE *p, int c) { TWORD t = p->n_type; char *s; switch (c) { case 'L': t = p->n_left->n_type; /* FALLTHROUGH */ case 'A': s = (t == CHAR || t == UCHAR ? "b" : t == SHORT || t == USHORT ? "w" : t == FLOAT ? "s" : t == DOUBLE ? "d" : t == LDOUBLE ? "x" : "l"); printf("%s", s); break; case 'B': if (p->n_qual) printf(" add.l #%d,%%sp\n", (int)p->n_qual); break; case 'C': /* jsr or bsr.l XXX - type of CPU? */ printf("%s", kflag ? "bsr.l" : "jsr"); break; case 'F': /* Emit float branches */ switch (p->n_op) { case GT: s = "fjnle"; break; case GE: s = "fjnlt"; break; case LE: s = "fjngt"; break; case LT: s = "fjnge"; break; case NE: s = "fjne"; break; case EQ: s = "fjeq"; break; default: comperr("ZF"); s = 0; } printf("%s " LABFMT "\n", s, p->n_label); break; case 'P': printf(" lea -%d(%%fp),%%a0\n", stkpos); break; case 'Q': /* struct assign */ printf(" move.l %d,-(%%sp)\n", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); expand(p, INAREG, " move.l AR,-(%sp)\n"); expand(p, INAREG, " move.l AL,-(%sp)\n"); printf(" jsr memcpy\n"); printf(" add.l #12,%%sp\n"); break; case 'S': /* struct arg */ starg(p); break; case '2': if (regno(getlr(p, '2')) != regno(getlr(p, 'L'))) expand(p, INAREG, " fmove.x AL,A2\n"); break; default: comperr("zzzcode %c", c); } }
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) { struct attr *ap; 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 GCC_COMPAT if (attr_find(p->n_left->n_ap, GCC_ATYP_STDCALL)) break; #endif pr = p->n_qual; if (attr_find(p->n_ap, ATTR_I386_FPPOP)) 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]); #if defined(os_openbsd) ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (p->n_op == STCALL && (ap->iarg(0) == 1 || ap->iarg(0) == 2 || ap->iarg(0) == 4 || ap->iarg(0) == 8)) { /* save on stack */ printf("\tmovl %%eax,-%d(%%ebp)\n", stkpos); printf("\tmovl %%edx,-%d(%%ebp)\n", stkpos+4); printf("\tleal -%d(%%ebp),%%eax\n", stkpos); } #endif break; case 'D': /* Long long comparision */ twollcomp(p); break; case 'F': /* Structure argument */ 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 'Q': /* emit struct assign */ /* * Put out some combination of movs{b,w,l} * esi/edi/ecx are available. */ expand(p, INAREG, " leal AL,%edi\n"); ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0) < 32) { int i = ap->iarg(0) >> 2; while (i) { expand(p, INAREG, " movsl\n"); i--; } } else {
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); } }
static void sconv(NODE *p) { NODE *l = p->n_left; TWORD ts, td; int o; /* * Source node may be in register or memory. * Result is always in register. */ ts = l->n_type; if (ISPTR(ts)) ts = UNSIGNED; td = p->n_type; ts = ts < LONG ? ts-2 : ts-4; td = td < LONG ? td-2 : td-4; o = scary[ts][td]; switch (o) { case MLE: case MLZ: expand(p, INAREG|INBREG, "\tmovl\tAL,A1\n"); break; case MVD: if (l->n_op == REG && regno(l) == regno(getlr(p, '1'))) break; /* unneccessary move */ expand(p, INAREG|INBREG, "\tmovZR\tAL,A1\n"); break; case CSE: expand(p, INAREG|INBREG, "\tcvtZLl\tAL,A1\n"); break; case CVT: expand(p, INAREG|INBREG, "\tcvtZLZR\tAL,A1\n"); break; case MZE: expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n"); break; case MVZ: expand(p, INAREG|INBREG, "\tmovzZLZR\tAL,A1\n"); break; case MZC: expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n"); expand(p, INAREG|INBREG, "\tcvtlZR\tA1,A1\n"); break; case 'I': /* unsigned to double */ expand(p, INAREG|INBREG, "\tcvtld\tAL,A1\n"); printf("\tjgeq\t1f\n"); expand(p, INAREG|INBREG, "\taddd2\t$0d4.294967296e+9,A1\n"); printf("1:\n"); break; default: comperr("unsupported conversion %d", o); } switch (o) { case MLE: case CSE: expand(p, INBREG, "\tashl\t$-31,A1,U1\n"); break; case MLZ: case MZE: expand(p, INAREG|INBREG, "\tclrl\tU1\n"); break; } }
void zzzcode(NODE *p, int c) { struct attr *ap; NODE *l; int pr, lr; char *ch; char sv; 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 notdef if (p->n_left->n_flags & FSTDCALL) break; #endif pr = p->n_qual; if (attr_find(p->n_ap, ATTR_I86_FPPOP)) printf(" fstp st(0)\n"); if (p->n_op == UCALL) return; /* XXX remove ZC from UCALL */ if (pr) { if (pr == 2) printf(" inc sp\n inc sp\n"); else printf(" add sp,#%d\n", pr); } break; case 'D': /* Long comparision */ twollcomp(p); break; case 'F': /* Structure argument */ starg(p); break; case 'G': /* Floating point compare */ fcomp(p); break; case 'H': /* assign of long 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 long 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 == AX) || (pr == BL && lr == BX) || (pr == CL && lr == CX) || (pr == DL && lr == DX)) ; else printf(" mov %s, %cL\n", rnames[pr], rnames[lr][1]); 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 = 8; sv = 'l'; #if 0 if (p->n_op == RS || p->n_op == LS) { llshft(p); break; } #endif if (p->n_op != RS && p->n_op != LS) { /* For 64bit we will need to push pointers not u64 */ expand(p, INCREG, "\tpush UR\n\tpush AR\n"); expand(p, INCREG, "\tpush UL\n\tpush AL\n"); } else { /* AR is a BREG so this goes wrong.. need an AREG but putting an AREG in the table rule makes the compiler shit itself - FIXME */ expand(p, INAREG, "\tpush AR\n"); expand(p, INCREG, "\tpush UL\n\tpush AL\n"); pr = 6; } if (p->n_type == LONGLONG || p->n_type == ULONGLONG) sv = 'L'; if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "udiv"; else if (p->n_op == MUL && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "umul"; 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 == ULONG || p->n_type == ULONGLONG)) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else if (p->n_op == LS) ch = "ls"; else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "rs"; else if (p->n_op == RS) ch = "urs"; else ch = 0, comperr("ZO"); printf("\tcall " EXPREFIX "__%c%sdi3\n\tadd %s,#%d\n", sv, ch, rnames[SP], pr); break; case 'P': /* typeless right hand */ suppress_type = 1; break; case 'Q': /* emit struct assign */ /* * Put out some combination of movs{b,w} * si/di/cx are available. * FIXME: review es: and direction flag implications */ expand(p, INAREG, " lea al,di\n"); ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0) < 32) { int i = ap->iarg(0) >> 1; while (i) { expand(p, INAREG, " movsw\n"); i--; } } else {
/* * Find a UNARY op that satisfy the needs. * For now, the destination is always a register. * Both source and dest types must match, but only source (left) * shape is of interest. */ int finduni(NODE *p, int cookie) { extern int *qtable[]; struct optab *q; NODE *l, *r; int i, shl = 0, num = 4; int *ixp, idx = 0; int sh; F2DEBUG(("finduni tree: %s\n", prcook(cookie))); F2WALK(p); l = getlr(p, 'L'); if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) r = p; else r = getlr(p, 'R'); ixp = qtable[p->n_op]; for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("finduni: ixp %d\n", ixp[i])); if (!acceptable(q)) /* target-dependent filter */ continue; if (ttype(l->n_type, q->ltype) == 0) continue; /* Type must be correct */ F2DEBUG(("finduni got left type\n")); if (ttype(r->n_type, q->rtype) == 0) continue; /* Type must be correct */ F2DEBUG(("finduni got types\n")); if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE) continue; F2DEBUG(("finduni got shapes %d\n", shl)); if ((cookie & q->visit) == 0) /* check correct return value */ continue; /* XXX - should check needs */ /* avoid clobbering of longlived regs */ /* let register allocator coalesce */ if ((q->rewrite & RLEFT) && (shl == SRDIR) /* && isreg(l) */) shl = SRREG; F2DEBUG(("finduni got cookie\n")); if (q->needs & REWRITE) break; /* Done here */ if (shl >= num) continue; num = shl; idx = ixp[i]; if (shl == SRDIR) break; } if (num == 4) { F2DEBUG(("finduni failed\n")); } else F2DEBUG(("finduni entry %d(%s)\n", idx, srtyp[num])); if (num == 4) { if (setuni(p, cookie)) return FRETRY; return FFAIL; } q = &table[idx]; sh = shswitch(-1, p->n_left, q->lshape, cookie, q->rewrite & RLEFT, num); if (sh == -1) sh = ffs(cookie & q->visit & INREGS)-1; if (sh == -1) sh = 0; F2DEBUG(("finduni: node %p (%s)\n", p, prcook(1 << sh))); p->n_su = MKIDX(idx, 0); SCLASS(p->n_su, sh); return sh; }
/* * Find a matching assign op. * * Level assignment for priority: * left right prio * - - - * direct direct 1 * direct REG 2 * direct OREG 3 * OREG direct 4 * OREG REG 5 * OREG OREG 6 */ int findasg(NODE *p, int cookie) { extern int *qtable[]; struct optab *q; int i, sh, shl, shr, lvl = 10; NODE *l, *r; int *ixp; struct optab *qq = NULL; /* XXX gcc */ int idx = 0, gol = 0, gor = 0; shl = shr = 0; F2DEBUG(("findasg tree: %s\n", prcook(cookie))); F2WALK(p); ixp = qtable[p->n_op]; l = getlr(p, 'L'); r = getlr(p, 'R'); for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("findasg: ixp %d\n", ixp[i])); if (!acceptable(q)) /* target-dependent filter */ continue; if (ttype(l->n_type, q->ltype) == 0 || ttype(r->n_type, q->rtype) == 0) continue; /* Types must be correct */ if ((cookie & q->visit) == 0) continue; /* must get a result */ F2DEBUG(("findasg got types\n")); #ifdef mach_pdp11 /* XXX - check for other targets too */ if (p->n_op == STASG && ISPTR(l->n_type)) { /* Accept lvalue to be in register */ /* if struct assignment is given a pointer */ if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE) continue; } else #endif { if ((shl = tshape(l, q->lshape)) == SRNOPE) continue; if (shl == SRREG) continue; } F2DEBUG(("findasg lshape %d\n", shl)); F2WALK(l); if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE) continue; F2DEBUG(("findasg rshape %d\n", shr)); F2WALK(r); if (q->needs & REWRITE) break; /* Done here */ if (lvl <= (shl + shr)) continue; lvl = shl + shr; qq = q; idx = ixp[i]; gol = shl; gor = shr; } if (lvl == 10) { F2DEBUG(("findasg failed\n")); if (setasg(p, cookie)) return FRETRY; return FFAIL; } F2DEBUG(("findasg entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor])); sh = -1; sh = shswitch(sh, p->n_left, qq->lshape, cookie, qq->rewrite & RLEFT, gol); sh = shswitch(sh, p->n_right, qq->rshape, cookie, qq->rewrite & RRIGHT, gor); #ifdef mach_pdp11 /* XXX all targets? */ lvl = 0; if (cookie == FOREFF) lvl = RVEFF, sh = 0; else if (cookie == FORCC) lvl = RVCC, sh = 0; else if (sh == -1) { sh = ffs(cookie & qq->visit & INREGS)-1; #ifdef PCC_DEBUG if (sh == -1) comperr("findasg bad shape"); #endif SCLASS(lvl,sh); } else SCLASS(lvl,sh); p->n_su = MKIDX(idx, lvl); #else if (sh == -1) { if (cookie == FOREFF) sh = 0; else sh = ffs(cookie & qq->visit & INREGS)-1; } F2DEBUG(("findasg: node %p class %d\n", p, sh)); p->n_su = MKIDX(idx, 0); SCLASS(p->n_su, sh); #endif /* mach_pdp11 */ #ifdef FINDMOPS p->n_su &= ~ISMOPS; #endif return sh; }
/* * Find the best relation op for matching the two trees it has. * This is a sub-version of the function findops() above. * The instruction with the lowest grading is emitted. * * Level assignment for priority: * left right prio * - - - * direct direct 1 * direct OREG 2 # make oreg * OREG direct 2 # make oreg * OREG OREG 2 # make both oreg * direct REG 3 # put in reg * OREG REG 3 # put in reg, make oreg * REG direct 3 # put in reg * REG OREG 3 # put in reg, make oreg * REG REG 4 # put both in reg */ int relops(NODE *p) { extern int *qtable[]; struct optab *q; int i, shl = 0, shr = 0, sh; NODE *l, *r; int *ixp, idx = 0; int lvl = 10, gol = 0, gor = 0; F2DEBUG(("relops tree:\n")); F2WALK(p); l = getlr(p, 'L'); r = getlr(p, 'R'); ixp = qtable[p->n_op]; for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("relops: ixp %d\n", ixp[i])); if (!acceptable(q)) /* target-dependent filter */ continue; if (ttype(l->n_type, q->ltype) == 0 || ttype(r->n_type, q->rtype) == 0) continue; /* Types must be correct */ F2DEBUG(("relops got types\n")); if ((shl = chcheck(l, q->lshape, 0)) == SRNOPE) continue; F2DEBUG(("relops lshape %d\n", shl)); F2WALK(p); if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE) continue; F2DEBUG(("relops rshape %d\n", shr)); F2WALK(p); if (q->needs & REWRITE) break; /* Done here */ if (lvl <= (shl + shr)) continue; lvl = shl + shr; idx = ixp[i]; gol = shl; gor = shr; } if (lvl == 10) { F2DEBUG(("relops failed\n")); if (setbin(p)) return FRETRY; return FFAIL; } F2DEBUG(("relops entry %d(%s %s)\n", idx, srtyp[gol], srtyp[gor])); q = &table[idx]; (void)shswitch(-1, p->n_left, q->lshape, INREGS, q->rewrite & RLEFT, gol); (void)shswitch(-1, p->n_right, q->rshape, INREGS, q->rewrite & RRIGHT, gor); sh = 0; if (q->rewrite & RLEFT) sh = ffs(q->lshape & INREGS)-1; else if (q->rewrite & RRIGHT) sh = ffs(q->rshape & INREGS)-1; F2DEBUG(("relops: node %p\n", p)); p->n_su = MKIDX(idx, 0); SCLASS(p->n_su, sh); return 0; }
/* * Find the best instruction to evaluate the given tree. * Best is to match both subnodes directly, second-best is if * subnodes must be evaluated into OREGs, thereafter if nodes * must be put into registers. * Whether 2-op instructions or 3-op is preferred is depending on in * which order they are found in the table. * mtchno is set to the count of regs needed for its legs. */ int findops(NODE *p, int cookie) { extern int *qtable[]; struct optab *q, *qq = NULL; int i, shl, shr, *ixp, sh; int lvl = 10, idx = 0, gol = 0, gor = 0; NODE *l, *r; F2DEBUG(("findops node %p (%s)\n", p, prcook(cookie))); F2WALK(p); ixp = qtable[p->n_op]; l = getlr(p, 'L'); r = getlr(p, 'R'); for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("findop: ixp %d str %s\n", ixp[i], q->cstring)); if (!acceptable(q)) /* target-dependent filter */ continue; if (ttype(l->n_type, q->ltype) == 0 || ttype(r->n_type, q->rtype) == 0) continue; /* Types must be correct */ if ((cookie & q->visit) == 0) continue; /* must get a result */ F2DEBUG(("findop got types\n")); if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE) continue; F2DEBUG(("findop lshape %s\n", srtyp[shl])); F2WALK(l); if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE) continue; F2DEBUG(("findop rshape %s\n", srtyp[shr])); F2WALK(r); /* Help register assignment after SSA by preferring */ /* 2-op insns instead of 3-ops */ if (xssa && (q->rewrite & RLEFT) == 0 && shl == SRDIR) shl = SRREG; if (q->needs & REWRITE) break; /* Done here */ if (lvl <= (shl + shr)) continue; lvl = shl + shr; qq = q; idx = ixp[i]; gol = shl; gor = shr; } if (lvl == 10) { F2DEBUG(("findops failed\n")); if (setbin(p)) return FRETRY; return FFAIL; } F2DEBUG(("findops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor])); sh = -1; #ifdef mach_pdp11 if (cookie == FORCC && p->n_op != AND) /* XXX - fix */ cookie = INREGS; #else if (cookie == FORCC) cookie = INREGS; #endif sh = shswitch(sh, p->n_left, qq->lshape, cookie, qq->rewrite & RLEFT, gol); sh = shswitch(sh, p->n_right, qq->rshape, cookie, qq->rewrite & RRIGHT, gor); if (sh == -1) { if (cookie == FOREFF || cookie == FORCC) sh = 0; else sh = ffs(cookie & qq->visit & INREGS)-1; } F2DEBUG(("findops: node %p sh %d (%s)\n", p, sh, prcook(1 << sh))); p->n_su = MKIDX(idx, 0); SCLASS(p->n_su, sh); return sh; }
/* * 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; } } }
/* * Try to find constructs like "a = a + 1;" and match them together * with instructions like "incl a" or "addl $1,a". * * Level assignment for priority: * left right prio * - - - * direct direct 1 * direct REG 2 * direct OREG 3 * OREG direct 4 * OREG REG 5 * OREG OREG 6 */ int findmops(NODE *p, int cookie) { extern int *qtable[]; struct optab *q; int i, sh, shl, shr, lvl = 10; NODE *l, *r; int *ixp; struct optab *qq = NULL; /* XXX gcc */ int idx = 0, gol = 0, gor = 0; shl = shr = 0; F2DEBUG(("findmops tree: %s\n", prcook(cookie))); F2WALK(p); l = getlr(p, 'L'); r = getlr(p, 'R'); /* See if this is a usable tree to work with */ /* Currently only check for leaves */ if (optype(r->n_op) != BITYPE || treecmp(l, r->n_left) == 0) return FFAIL; F2DEBUG(("findmops is useable\n")); /* We can try to find a match. Use right op */ ixp = qtable[r->n_op]; l = getlr(r, 'L'); r = getlr(r, 'R'); for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("findmops: ixp %d\n", ixp[i])); if (!acceptable(q)) /* target-dependent filter */ continue; if (ttype(l->n_type, q->ltype) == 0 || ttype(r->n_type, q->rtype) == 0) continue; /* Types must be correct */ F2DEBUG(("findmops got types\n")); switch (cookie) { case FOREFF: if ((q->visit & FOREFF) == 0) continue; /* Not only for side effects */ break; case FORCC: if ((q->visit & FORCC) == 0) continue; /* Not only for side effects */ break; default: if ((cookie & q->visit) == 0) continue; /* Won't match requested shape */ if (((cookie & INREGS & q->lshape) == 0) || !isreg(l)) continue; /* Bad return register */ break; } F2DEBUG(("findmops cookie\n")); /* * left shape must match left node. */ if ((shl = tshape(l, q->lshape)) != SRDIR && (shl != SROREG)) continue; F2DEBUG(("findmops lshape %s\n", srtyp[shl])); F2WALK(l); if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE) continue; F2DEBUG(("findmops rshape %s\n", srtyp[shr])); /* * Only allow RLEFT. XXX */ if ((q->rewrite & (RLEFT|RRIGHT)) != RLEFT) continue; F2DEBUG(("rewrite OK\n")); F2WALK(r); if (q->needs & REWRITE) break; /* Done here */ if (lvl <= (shl + shr)) continue; lvl = shl + shr; qq = q; idx = ixp[i]; gol = shl; gor = shr; } if (lvl == 10) return FFAIL; F2DEBUG(("findmops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor])); /* * Now we're here and have a match. left is semi-direct and * right may be anything. */ sh = -1; sh = shswitch(sh, p->n_left, qq->lshape, cookie, qq->rewrite & RLEFT, gol); sh = shswitch(sh, r, qq->rshape, cookie, 0, gor); if (sh == -1) { if (cookie & (FOREFF|FORCC)) sh = 0; else sh = ffs(cookie & qq->visit & INREGS)-1; } F2DEBUG(("findmops done: node %p class %d\n", p, sh)); /* Trickery: Set table index on assign to op instead */ /* gencode() will remove useless nodes */ p->n_su = MKIDX(idx, 0); p->n_su |= ISMOPS; /* XXX tell gencode to reduce the right tree */ SCLASS(p->n_su, sh); return sh; }
/* Add $ptr to the records. Called in mallfuncs context. */ static void *garbage(void *ptr, size_t size, int intracall) { struct ero_st *mem; unsigned i, top, bottom; if (!ptr) /* malloc() failed, don't record. */ return NULL; /* Update the counters whether we can make a record or not. */ NAllocations++; Allocated += size; if (Peak < Allocated) Peak = Allocated; /* We are permitted to clobber errno because our caller * is going to return with success. */ if (!Ero_pool && !(Ero_pool = new_ero_pool())) return ptr; mem = Ero_pool; Ero_pool = Ero_pool->next; mem->next = Memories; Memories = mem; NMemories++; mem->ptr = ptr; mem->size = size; mem->karma = 0; IF_THREAD_SAFE(mem->tid = gettid()); mem->backtrace = NULL; if (!Backtrace_depth) goto skip_backtrace; if (!Backtraces && !(Backtraces = new_backtraces())) goto skip_backtrace; mem->backtrace = Backtraces; /* We're called through fun() -> malloc() -> garbage(), * ignore the top two frames. The bottom two frames * are below main(), ignore them too. */ top = 2; if (intracall) /* An accountant function called another hook, ignore that too. */ top++; #ifndef CONFIG_FAST_UNWIND /* Try getting the backtrace until $addrs is large enough. * Start with a large buffer to get away with as few retries * as possible. */ bottom = 2; for (i = Backtrace_depth > 0 ? top+Backtrace_depth : 100; ; i += 100) { unsigned depth; void *addrs[i]; struct backtrace_st *next; if ((depth = backtrace(addrs, i)) >= i && Backtrace_depth < 0) /* $addrs was too small. */ continue; if (depth > top) { /* Ignore $top frames. */ depth -= top; if (top+depth < i && depth > bottom) /* If we got the full backtrace also ignore * the $bottom frames. */ depth -= bottom; } else /* Don't ignore anyhing. */ top = 0; /* Add the backtrace to $mem. If #depth is larger than the CAPACITY * of backtrace_st chain up more. */ for (;;) { int more; unsigned n; n = CAPACITY(Backtraces->addrs); more = n < depth; if (n > depth) n = depth; memcpy(Backtraces->addrs, &addrs[top], sizeof(addrs[0]) * n); if (!more) { /* NULL-pad the unused $addrs, so compare_backtraces() won't * tell apart identical backtraces because of garbage. */ memset(&Backtraces->addrs[n], 0, sizeof(Backtraces->addrs[0]) * (CAPACITY(Backtraces->addrs)-n)); break; } if (!Backtraces->next && !(Backtraces->next = new_backtraces())) /* The bottom of the backtrace will be lost. */ break; Backtraces = Backtraces->next; top += n; depth -= n; } /* for */ next = Backtraces->next; Backtraces->next = NULL; Backtraces = next; break; } /* for */ #else /* CONFIG_FAST_UNWIND */ /* We need to be able to store at least $top addresses. * If not, ignoring top/bottom frames may break. */ ASSERT(CAPACITY(Backtraces->addrs) >= 3); /* arf leaves less junk at the bottom than backtrace(). */ bottom = 1; do { unsigned depth; void const *sseg; void const *const *fp, *lr; struct backtrace_st *prev, *next; /* We don't know beforehand the depth of the backtrace, * so store the addresses in $Backtraces as we unwind * the stack iteratively. */ prev = NULL; sseg = NULL; fp = __builtin_frame_address(0); for (i = depth = 0; ; i++, depth++) { if (!(fp = getlr(fp, &lr, &sseg)) || (Backtrace_depth > 0 && depth >= Backtrace_depth)) { /* End of backtrace, ignore the bottom frames if we can. */ if (!fp && !top && depth > bottom) { if (i <= bottom) { /* The addresses in $Backtraces are all ignored, * discard the whole page. */ Backtraces = prev; i += CAPACITY(Backtraces->addrs) - bottom; } else i -= bottom; } /* Zero out the unused slots (which can be 0). */ memset(&Backtraces->addrs[i], 0, sizeof(Backtraces->addrs[0]) * (CAPACITY(Backtraces->addrs)-i)); break; } if (depth == top) /* Time to ignore $top. */ i = depth = top = 0; else if (i >= CAPACITY(Backtraces->addrs)) { /* $Backtraces is full, get a new page. */ if (!Backtraces->next && !(Backtraces->next = new_backtraces())) break; prev = Backtraces; Backtraces = Backtraces->next; i = 0; } Backtraces->addrs[i] = lr; } /* for */ /* NULL-terminate $mem->backtaces and dequeue the tail * from $Backtraces. */ next = Backtraces->next; Backtraces->next = NULL; Backtraces = next; } while (0); #endif /* CONFIG_FAST_UNWIND */ skip_backtrace: return ptr; } /* garbage */