/* * 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); } }
/* * Compare two trees; return 1 if equal and 0 if not. */ int treecmp(NODE *p1, NODE *p2) { if (p1->n_op != p2->n_op) return 0; switch (p1->n_op) { case SCONV: case UMUL: return treecmp(p1->n_left, p2->n_left); case OREG: if (getlval(p1) != getlval(p2) || p1->n_rval != p2->n_rval) return 0; break; case NAME: case ICON: if (strcmp(p1->n_name, p2->n_name)) return 0; /* FALLTHROUGH */ if (getlval(p1) != getlval(p2)) return 0; break; case TEMP: #ifdef notyet /* SSA will put assignment in separate register */ /* Help out by accepting different regs here */ if (xssa) break; #endif case REG: if (p1->n_rval != p2->n_rval) return 0; break; case LS: case RS: case PLUS: case MINUS: case MUL: case DIV: if (treecmp(p1->n_left, p2->n_left) == 0 || treecmp(p1->n_right, p2->n_right) == 0) return 0; break; default: return 0; } return 1; }
/* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } if (r->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_op == PLUS) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(r->n_left) == 0) (void)geninsn(r->n_left, INAREG); return; } } (void)geninsn(p, INAREG); }
void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (getlval(p)) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput"); } }
void adrput(FILE *io, NODE *p) { int r; /* output an address, with offsets, from p */ switch (p->n_op) { case NAME: if (getlval(p)) fprintf(io, CONFMT "%s", getlval(p), *p->n_name ? "+" : ""); if (p->n_name[0]) printf("%s", p->n_name); else comperr("adrput"); return; case OREG: r = p->n_rval; if (getlval(p)) fprintf(io, CONFMT "%s", getlval(p), *p->n_name ? "+" : ""); if (p->n_name[0]) printf("%s", p->n_name); if (R2TEST(r)) { int r1 = R2UPK1(r); int r2 = R2UPK2(r); int sh = R2UPK3(r); fprintf(io, "(%s,%s,%d)", r1 == MAXREGS ? "" : rnames[r1], r2 == MAXREGS ? "" : rnames[r2], sh); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { fprintf(io, "#" CONFMT, getlval(p) >> 32); } else {
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 (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); return; case OREG: if (getlval(p)) fprintf(io, "%d", (int) getlval(p)); fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(io, p->n_rval, 0); else fputs(rnames[p->n_rval], io); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } }
/* * 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); } }
/* * Take integer absolute value. * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1))) */ static NODE * builtin_abs(const struct bitable *bt, NODE *a) { NODE *p, *q, *r, *t, *t2, *t3; int tmp1, tmp2, shift; if (a->n_type != INT) a = cast(a, INT, 0); if (a->n_op == ICON) { if (getlval(a) < 0) setlval(a, -getlval(a)); p = a; } else { t = tempnode(0, a->n_type, a->n_df, a->n_ap); tmp1 = regno(t); p = buildtree(ASSIGN, t, a); t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1; q = buildtree(RS, t, bcon(shift)); t2 = tempnode(0, a->n_type, a->n_df, a->n_ap); tmp2 = regno(t2); q = buildtree(ASSIGN, t2, q); t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); r = buildtree(MINUS, buildtree(ER, t, t2), t3); p = buildtree(COMOP, p, buildtree(COMOP, q, r)); } return p; }
static void shiftop(NODE *p) { NODE *r = p->n_right; TWORD ty = p->n_type; if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tsrl A1,AL,"); printf(CONFMT "\t# 64-bit left-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tsll U1,UL,AR\n"); expand(p, INBREG, "\tor U1,U1,A1\n"); expand(p, INBREG, "\tsll A1,AL,AR\n"); } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); expand(p, INBREG, "\tsll U1,AL,"); printf(CONFMT "\n", getlval(r) - 32); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); expand(p, INBREG, "\tli U1,0\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tsll U1,UL,"); printf(CONFMT "\t# 64-bit right-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tsrl A1,AL,AR\n"); expand(p, INBREG, "\tor A1,A1,U1\n"); if (ty == LONGLONG) expand(p, INBREG, "\tsra U1,UL,AR\n"); else expand(p, INBREG, "\tsrl U1,UL,AR\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { if (ty == LONGLONG) { expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n"); expand(p, INBREG, "\tsra A1,UL,"); }else { expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n"); expand(p, INBREG, "\tsrl A1,UL,"); } printf(CONFMT "\n", getlval(r) - 32); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n"); expand(p, INBREG, "\tli U1,0\n"); } else { comperr("shiftop"); } }
/* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; if (o != ICON || p->n_name[0] != 0) return SRNOPE; switch(shape) { case SPCON: if ((getlval(p) & ~0xffff) == 0) return SRDIR; break; } return SRNOPE; }
/* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { NODE *p, *r; if (x2debug) printf("myormake(%p)\n", q); p = q->n_left; if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_left->n_op == REG && r->n_left->n_op == REG) { q->n_op = OREG; setlval(q, 0); q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); tfree(p); } }
void conput(FILE *fp, NODE *p) { long val = getlval(p); if (p->n_type <= UCHAR) val &= 255; else if (p->n_type <= USHORT) val &= 65535; switch (p->n_op) { case ICON: fprintf(fp, "%ld", val); if (p->n_name[0]) printf("+%s", p->n_name); break; default: comperr("illegal conput, p %p", p); } }
/* * 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], attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); if (p->n_left->n_op == OREG) { printf("\taddiu %s,%s," CONFMT "\t# dest address\n", rnames[A0], rnames[p->n_left->n_rval], getlval(p->n_left)); } 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]); }
/* * If we're big endian, then all OREG loads of a type * larger than the destination, must have the * offset changed to point to the correct bytes in memory. */ static void offchg(NODE *p, void *arg) { NODE *l; if (p->n_op != SCONV) return; l = p->n_left; if (l->n_op != OREG) return; switch (l->n_type) { case SHORT: case USHORT: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l) + 1); break; case LONG: case ULONG: case INT: case UNSIGNED: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 3)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 2)); break; case LONGLONG: case ULONGLONG: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 7)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 6)); else if (DEUNSIGN(p->n_type) == INT || DEUNSIGN(p->n_type) == LONG) setlval(l, getlval(l + 4)); break; default: comperr("offchg: unknown type"); break; } }
/* * return true if shape is appropriate for the node p * * Return values: * SRNOPE Cannot match this shape. * SRDIR Direct match, may or may not traverse down. * SRREG Will match if put in a regster XXX - kill this? */ int tshape(NODE *p, int shape) { int o, mask; o = p->n_op; #ifdef PCC_DEBUG if (s2debug) printf("tshape(%p, %s) op = %s\n", p, prcook(shape), opst[o]); #endif if (shape & SPECIAL) { switch (shape) { case SZERO: case SONE: case SMONE: case SSCON: case SCCON: if (o != ICON || p->n_name[0]) return SRNOPE; if (getlval(p)== 0 && shape == SZERO) return SRDIR; if (getlval(p) == 1 && shape == SONE) return SRDIR; if (getlval(p) == -1 && shape == SMONE) return SRDIR; if (getlval(p) > -257 && getlval(p) < 256 && shape == SCCON) return SRDIR; if (getlval(p) > -32769 && getlval(p) < 32768 && shape == SSCON) return SRDIR; return SRNOPE; case SSOREG: /* non-indexed OREG */ if (o == OREG && !R2TEST(p->n_rval)) return SRDIR; return SRNOPE; default: return (special(p, shape)); } } if (shape & SANY) return SRDIR; if ((shape&INTEMP) && shtemp(p)) /* XXX remove? */ return SRDIR; if ((shape&SWADD) && (o==NAME||o==OREG)) if (BYTEOFF(getlval(p))) return SRNOPE; switch (o) { case NAME: if (shape & SNAME) return SRDIR; break; case ICON: case FCON: if (shape & SCON) return SRDIR; break; case FLD: if (shape & SFLD) return flshape(p->n_left); break; case CCODES: if (shape & SCC) return SRDIR; break; case REG: case TEMP: mask = PCLASS(p); if (shape & mask) return SRDIR; break; case OREG: if (shape & SOREG) return SRDIR; break; case UMUL: #if 0 if (shumul(p->n_left) & shape) return SROREG; /* Calls offstar to traverse down */ break; #else return shumul(p->n_left, shape); #endif } return SRNOPE; }
/* * 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; } } }