/* * Check how to walk further down. * Merge with swmatch()? * sh - shape for return value (register class). * p - node (for this leg) * shape - given shape for this leg * cookie - cookie given for parent node * rew - * go - switch key for traversing down * returns register class. */ static int shswitch(int sh, NODE *p, int shape, int cookie, int rew, int go) { int lsh; F2DEBUG(("shswitch: p=%p, shape=%s, ", p, prcook(shape))); F2DEBUG(("cookie=%s, rew=0x%x, go=%s\n", prcook(cookie), rew, srtyp[go])); switch (go) { case SRDIR: /* direct match, just clear su */ (void)swmatch(p, 0, 0); break; case SROREG: /* call offstar to prepare for OREG conversion */ (void)swmatch(p, shape, SROREG); break; case SRREG: /* call geninsn() to get value into register */ lsh = shape & (FORCC | INREGS); if (rew && cookie != FOREFF) lsh &= (cookie & (FORCC | INREGS)); lsh = swmatch(p, lsh, SRREG); if (rew) sh = lsh; break; } return sh; }
/* * Find a leaf type node that puts the value into a register. */ int findleaf(NODE *p, int cookie) { extern int *qtable[]; struct optab *q = NULL; /* XXX gcc */ int i, sh; int *ixp; F2DEBUG(("findleaf p %p (%s)\n", p, prcook(cookie))); F2WALK(p); ixp = qtable[p->n_op]; for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("findleaf: ixp %d\n", ixp[i])); if (!acceptable(q)) /* target-dependent filter */ continue; if ((q->visit & cookie) == 0) continue; /* wrong registers */ if (ttype(p->n_type, q->rtype) == 0 || ttype(p->n_type, q->ltype) == 0) continue; /* Types must be correct */ F2DEBUG(("findleaf got types, rshape %s\n", prcook(q->rshape))); if (chcheck(p, q->rshape, 0) != SRDIR) continue; if (q->needs & REWRITE) break; /* Done here */ break; } if (ixp[i] < 0) { F2DEBUG(("findleaf failed\n")); if (setuni(p, cookie)) return FRETRY; return FFAIL; } F2DEBUG(("findleaf entry %d\n", ixp[i])); sh = ffs(cookie & q->visit & INREGS)-1; F2DEBUG(("findleaf: node %p (%s)\n", p, prcook(1 << sh))); p->n_su = MKIDX(ixp[i], 0); SCLASS(p->n_su, sh); return sh; }
/* * Convert a node to REG or OREG. * Shape is register class where we want the result. * Returns register class if register nodes. * If w is: (should be shapes) * - SRREG - result in register, call geninsn(). * - SROREG - create OREG; call offstar(). * - 0 - clear su, walk down. */ static int swmatch(NODE *p, int shape, int w) { int rv = 0; F2DEBUG(("swmatch: p=%p, shape=%s, w=%s\n", p, prcook(shape), srtyp[w])); switch (w) { case SRREG: rv = geninsn(p, shape); break; case SROREG: /* should be here only if op == UMUL */ if (p->n_op != UMUL && p->n_op != FLD) comperr("swmatch %p", p); if (p->n_op == FLD) { offstar(p->n_left->n_left, shape); p->n_left->n_su = 0; } else offstar(p->n_left, shape); p->n_su = 0; rv = ffs(shape)-1; break; case 0: if (optype(p->n_op) == BITYPE) swmatch(p->n_right, 0, 0); if (optype(p->n_op) != LTYPE) swmatch(p->n_left, 0, 0); p->n_su = 0; } return rv; }
/* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p,%s)\n", p, prcook(cookie)); if (p->n_left->n_op == FLD && !isreg(p->n_left->n_left)) { NODE *l, *r; int reg; geninsn(p->n_left->n_left, INAREG); reg = DECRA(p->n_left->n_left->n_reg, 0); l = tcopy(p->n_left->n_left); p->n_left->n_left->n_op = REG; p->n_left->n_left->n_rval = reg; p->n_left->n_left->n_lval = 0; r = tcopy(p->n_left->n_left); geninsn(p->n_left, INAREG); l = mkbinode(ASSIGN, l, r, l->n_type); geninsn(l, INAREG); return (1); } return (0); }
/* setup for unary operator */ int setuni(NODE *p, int cookie) { if (x2debug) printf("setuni(%p,%s)\n", p, prcook(cookie)); return 0; }
/* * 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; }
/* * Search for an UMUL table entry that can turn an indirect node into * a move from an OREG. */ int findumul(NODE *p, int cookie) { extern int *qtable[]; struct optab *q = NULL; /* XXX gcc */ int i, shl = 0, shr = 0, sh; int *ixp; F2DEBUG(("findumul p %p (%s)\n", p, prcook(cookie))); F2WALK(p); ixp = qtable[p->n_op]; for (i = 0; ixp[i] >= 0; i++) { q = &table[ixp[i]]; F2DEBUG(("findumul: ixp %d\n", ixp[i])); if (!acceptable(q)) /* target-dependent filter */ continue; if ((q->visit & cookie) == 0) continue; /* wrong registers */ if (ttype(p->n_type, q->rtype) == 0) continue; /* Types must be correct */ F2DEBUG(("findumul got types, rshape %s\n", prcook(q->rshape))); /* * Try to create an OREG of the node. * Fake left even though it's right node, * to be sure of conversion if going down left. */ if ((shl = chcheck(p, q->rshape, 0)) == SRNOPE) continue; shr = 0; if (q->needs & REWRITE) break; /* Done here */ F2DEBUG(("findumul got shape %s\n", srtyp[shl])); break; /* XXX search better matches */ } if (ixp[i] < 0) { F2DEBUG(("findumul failed\n")); if (setuni(p, cookie)) return FRETRY; return FFAIL; } F2DEBUG(("findumul entry %d(%s %s)\n", ixp[i], srtyp[shl], srtyp[shr])); sh = shswitch(-1, p, q->rshape, cookie, q->rewrite & RLEFT, shl); if (sh == -1) sh = ffs(cookie & q->visit & INREGS)-1; F2DEBUG(("findumul: node %p (%s)\n", p, prcook(1 << sh))); p->n_su = MKIDX(ixp[i], 0); SCLASS(p->n_su, sh); return sh; }
/* * 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; }
/* * 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 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; }
/* * 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; }