optimize.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,806 行 · 第 1/3 页
C
1,806 行
next = this_op(s->next); if (next == 0) break; last = next; if (s->s.code == StmOp && next->s.code == LdmXOp && s->s.k == next->s.k) { done = 0; next->s.code = TaxOp; } if (s->s.code == LdIOp && next->s.code == TaxOp) { s->s.code = LdXIOp; next->s.code = TxaOp; done = 0; } /* * This is an ugly special case, but it happens * when you say tcp[k] or udp[k] where k is a constant. */ if (s->s.code == LdIOp && next->s.code == LdxmsOp) { struct slist *add, *tax, *ild; add = this_op(next->next); if (add == 0 || add->s.code != AddXOp) break; tax = this_op(add->next); if (tax == 0 || tax->s.code != TaxOp) break; ild = this_op(tax->next); if (ild == 0 || (ild->s.code != ILdOp && ild->s.code != ILdHOp && ild->s.code != ILdBOp)) break; /* * XXX We need to check that X is not * subsequently used. We know we can eliminate the * accumaltor modifications since it is defined * by the last stmt of this sequence. * * We want to turn this sequence: * * (004) ldi #0x2 {s} * (005) ldxms [14] {next} * (006) addx {add} * (007) tax {tax} * (008) ild [x+0] {ild} * * into this sequence: * * (004) nop * (005) ldxms [14] * (006) nop * (007) nop * (008) ild [x+2] * * The nops get removed later. */ ild->s.k += s->s.k; s->s.code = NopOp; add->s.code = NopOp; tax->s.code = NopOp; done = 0; } s = next; } /* * If we have a subtract to do a comparsion, and the X register * is a known constant, we can merge this value into the * comparison. */ if (last->s.code == SubXOp && !REGELEM(b->out_use, A_REGNO)) { val = b->val[X_REGNO]; if (vmap[val].is_const) { b->s.k += vmap[val].const_val; last->s.code = NopOp; done = 0; } } /* * Likewise, a constant subtract can be simplified. */ else if (last->s.code == SubIOp && !REGELEM(b->out_use, A_REGNO)) { b->s.k += last->s.k; last->s.code = NopOp; done = 0; } /* * If the accumulator is a known constant, we can compute the * comparison result. */ val = b->val[A_REGNO]; if (vmap[val].is_const) { v = vmap[val].const_val; switch (b->s.code) { case EQOp: v = v == b->s.k; break; case GTOp: v = v > b->s.k; break; case GEOp: v = v >= b->s.k; break; default: abort(); } if (b->jf != b->jt) done = 0; if (v) b->jf = b->jt; else b->jt = b->jf; }}static inline enum bpf_codeopadjust(code, diff) enum bpf_code code; int diff;{ return (enum bpf_code)((int)code - diff);}/* * Update compute the symbolic value of expression of 's', and update * anything it defines in the value table 'val'. If 'alter' is true, * do various optimizations. This code would be cleaner if symblic * evaluation and code transformations weren't folded together. */static voidopt_stmt(s, val, alter) struct stmt *s; long val[]; int alter;{ long v; switch (s->code) { case LdOp: case LdHOp: case LdBOp: v = F(s->code, s->k, 0L); vstore(s, &val[A_REGNO], v, alter); break; case ILdOp: case ILdHOp: case ILdBOp: v = val[X_REGNO]; if (alter && vmap[v].is_const) { s->code = opadjust(s->code, (int)ILdOp - (int)LdOp); s->k += vmap[v].const_val; v = F(s->code, s->k, 0L); done = 0; } else v = F(s->code, s->k, v); vstore(s, &val[A_REGNO], v, alter); break; case LdLenOp: v = F(s->code, 0L, 0L); vstore(s, &val[A_REGNO], v, alter); break; case LdIOp: v = K(s->k); vstore(s, &val[A_REGNO], v, alter); break; case LdXIOp: v = K(s->k); vstore(s, &val[X_REGNO], v, alter); break; case LdxmsOp: v = F(s->code, s->k, 0L); vstore(s, &val[X_REGNO], v, alter); break; case NegOp: if (alter && vmap[val[A_REGNO]].is_const) { s->code = LdIOp; s->k = -vmap[val[A_REGNO]].const_val; val[A_REGNO] = K(s->k); } else val[A_REGNO] = F(s->code, val[A_REGNO], 0L); break; case AddIOp: case SubIOp: case MulIOp: case DivIOp: case AndIOp: case OrIOp: case LshIOp: case RshIOp: if (alter && vmap[val[A_REGNO]].is_const) { fold_op(s, val[A_REGNO], K(s->k)); val[A_REGNO] = K(s->k); } else val[A_REGNO] = F(s->code, val[A_REGNO], K(s->k)); break; case AddXOp: case SubXOp: case MulXOp: case DivXOp: case AndXOp: case OrXOp: case LshXOp: case RshXOp: if (alter && vmap[val[X_REGNO]].is_const) { if (vmap[val[A_REGNO]].is_const) { fold_op(s, val[A_REGNO], val[X_REGNO]); val[A_REGNO] = K(s->k); } else { s->code = opadjust(s->code, (int)AddXOp - (int)AddIOp); s->k = vmap[val[X_REGNO]].const_val; done = 0; val[A_REGNO] = F(s->code, val[A_REGNO], K(s->k)); } break; } /* * Check if we're doing something to an accumulator * that is 0, and simplify. This may nnot seem like * much of a simplification but it could open up further * optimizations. * XXX We could also check for mul by 1, and -1, etc. */ if (alter && vmap[val[A_REGNO]].is_const && vmap[val[A_REGNO]].const_val == 0) { if (s->code == AddXOp || s->code == OrXOp || s->code == LshXOp || s->code == RshXOp) { s->code = TxaOp; vstore(s, &val[A_REGNO], val[X_REGNO], alter); break; } else if (s->code == MulXOp || s->code == DivXOp || s->code == AndXOp) { s->code = LdIOp; s->k = 0; vstore(s, &val[A_REGNO], K(s->k), alter); break; } else if (s->code == NegOp) { s->code = NopOp; break; } } val[A_REGNO] = F(s->code, val[A_REGNO], val[X_REGNO]); break; case TxaOp: vstore(s, &val[A_REGNO], val[X_REGNO], alter); break; case LdmOp: v = val[s->k]; if (alter && vmap[v].is_const) { s->code = LdIOp; s->k = vmap[v].const_val; done = 0; } vstore(s, &val[A_REGNO], v, alter); break; case TaxOp: vstore(s, &val[X_REGNO], val[A_REGNO], alter); break; case LdmXOp: v = val[s->k]; if (alter && vmap[v].is_const) { s->code = LdXIOp; s->k = vmap[v].const_val; done = 0; } vstore(s, &val[X_REGNO], v, alter); break; case StmOp: vstore(s, &val[s->k], val[A_REGNO], alter); break; case StmXOp: vstore(s, &val[s->k], val[X_REGNO], alter); break; }}/* * Allocation for blist nodes is done cheaply by mallocing the * max we will need before the optimization passes. There is a * linear bound on the number required. */static struct blist *blist_base;static struct blist *next_blist;static voidopt_deadstores(b) struct block *b;{ struct slist *s; int i, regno; struct stmt *last[N_MEMWORDS]; bzero((char *)last, sizeof last); for (s = b->stmts; s; s = s->next) { regno = reguse(&s->s); if (regno >= 0) { if (regno == AX_REGNO) { last[X_REGNO] = 0; last[A_REGNO] = 0; } else last[regno] = 0; } regno = regdef(&s->s); if (regno >= 0) { if (last[regno]) { done = 0; last[regno]->code = NopOp; } last[regno] = &s->s; } } for (i = 0; i < N_MEMWORDS; ++i) if (last[i] && !REGELEM(b->out_use, i) && i != A_REGNO) { last[i]->code = NopOp; done = 0; }}static voidopt_blk(b, do_stmts) struct block *b;{ struct slist *s; struct blist *p; int i; long aval; /* * Initialize the register values. * If we have no predecessors, everything is undefined. * Otherwise, we inherent our values from our predecessors. * If any register has an ambiguous value (i.e. control paths are * merging) give it the undefined value of 0. */ p = b->pred; if (p == 0) bzero((char *)b->val, sizeof(b->val)); else { bcopy((char *)p->blk->val, (char *)b->val, sizeof(b->val)); while (p = p->next) { for (i = 0; i < N_MEMWORDS; ++i) if (b->val[i] != p->blk->val[i]) b->val[i] = 0; } } aval = b->val[A_REGNO]; for (s = b->stmts; s; s = s->next) opt_stmt(&s->s, b->val, do_stmts); /* * This is a special case: if we don't use anything from this * block, and we load the accumulator with value that is * already there, eliminate all the statements. */ if (do_stmts && b->out_use == 0 && aval != 0 && b->val[A_REGNO] == aval) b->stmts = 0; else { opt_peep(b); opt_deadstores(b); }}/* * Return true if any register that is used on exit from 'succ', has * an exit value that is different from the corresponding exit value * from 'b'. */static int use_conflict(b, succ) struct block *b, *succ;{ int regno; regset uset = succ->out_use; if (uset == 0) return 0; for (regno = 0; regno < N_MEMWORDS; ++regno) if (REGELEM(uset, regno)) if (b->val[regno] != succ->val[regno]) return 1; return 0;}static voidopt_j(b, which) struct block *b; int which;{ int k; struct block **br; struct block *target; struct block *ancestor; struct block *next; nodeset dom, closure; int sense; /* * Don't bother checking if b is a leaf, since we * are never called that way. */ if (which) { br = &b->jt; target = b->jt; } else { br = &b->jf; target = b->jf; } dom = b->dom; closure = b->closure; top: /* * If we hit a leaf, stop. Otherwise, * try to move down another level. */ if (target->jt == 0) { *br = target; return; } if (target->jt == target->jf) { /* * Common branch targets can be eliminated, provided * there is no a data dependency. */ if (!use_conflict(b, target->jt)) { done = 0; target = target->jt; goto top; } else { *br = target; return; } } for (k = 0; k < n_blocks; ++k) { if (!NS_MEMBER(dom, k)) continue; ancestor = blocks[k]; if (target->val[A_REGNO] != ancestor->val[A_REGNO]) /* * Ignore blocks that do not load the same values. */ continue; if (ancestor == b) /* * The ancestor happens to be the node whose edge * is being moved (i.e. there are two consective * nodes that compute the same thing). The sense * of this branch is given by the branch of the * node we are optimizing. */ sense = which; else if (NS_MEMBER(closure, ancestor->jt->id)) /* * We can reach the node we are optimizing * along the true branch of the ancestor. * Either we know we came down the true branch, * or we might also be able to reach this node * from the false branch. In the latter case, * we cannot do anything. */ if (NS_MEMBER(closure, ancestor->jf->id)) continue; else sense = 1; else if (NS_MEMBER(closure, ancestor->jf->id)) /* * The false branch must have been taken. * (We ruled out the true branch above.) */ sense = 0; else /* XXX * If we cannot reach the current node from its * dominator, the code is broken. We can eliminate * the test above. */ abort(); if (target->s.code == ancestor->s.code) { if (target->s.code != EQOp) continue; if (ancestor->s.k == target->s.k) /* * The operands are the same, so the * result is true if a true branch was * taken to get here, otherwise false. */ next = sense ? target->jt : target->jf; else { if (!sense) /* * We do not know the outcome * if we had a false comparison * and the operands are * different. */ continue; /* * If this is a true comparison but the * operands were different, then the * current must be false. */ next = target->jf; } if (use_conflict(b, next)) /* * There is a data dependency between that * will be invalidated if we move this edge. */ continue; target = next; /* * Moved a branch, so do another pass. */ done = 0; goto top; } } /* * Went through all the dominators of the last block * but couldn't move down. */ *br = target;}static voidor_pullup(b) struct block *b;{ int val, at_top; struct block *pull; struct block **diffp, **samep; struct blist *plist; plist = b->pred; if (plist == 0) return; /* * Make sure each predecessor loads the same value. */ val = plist->blk->val[A_REGNO]; for (plist = plist->next; plist; plist = plist->next) if (val != plist->blk->val[A_REGNO]) return; if (b->pred->blk->jt == b) diffp = &b->pred->blk->jt; else diffp = &b->pred->blk->jf; at_top = 1; while (1) { if (*diffp == 0) return; if ((*diffp)->jt != b->jt) return; if (!NS_MEMBER((*diffp)->dom, b->id))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?