📄 optimize.c
字号:
register struct slist *s;
register int atom;
struct stmt *last[N_ATOMS];
memset((char *)last, 0, sizeof last);
for (s = b->stmts; s != 0; s = s->next)
deadstmt(&s->s, last);
deadstmt(&b->s, last);
for (atom = 0; atom < N_ATOMS; ++atom)
if (last[atom] && !ATOMELEM(b->out_use, atom)) {
last[atom]->code = NOP;
done = 0;
}
}
static void
opt_blk(b, do_stmts)
struct block *b;
int do_stmts;
{
struct slist *s;
struct edge *p;
int i;
bpf_int32 aval;
#if 0
for (s = b->stmts; s && s->next; s = s->next)
if (BPF_CLASS(s->s.code) == BPF_JMP) {
do_stmts = 0;
break;
}
#endif
/*
* Initialize the atom 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->in_edges;
if (p == 0)
memset((char *)b->val, 0, sizeof(b->val));
else {
memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val));
while ((p = p->next) != NULL) {
for (i = 0; i < N_ATOMS; ++i)
if (b->val[i] != p->pred->val[i])
b->val[i] = 0;
}
}
aval = b->val[A_ATOM];
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, or if this block is a return,
* eliminate all the statements.
*/
if (do_stmts &&
((b->out_use == 0 && aval != 0 &&b->val[A_ATOM] == aval) ||
BPF_CLASS(b->s.code) == BPF_RET)) {
if (b->stmts != 0) {
b->stmts = 0;
done = 0;
}
} else {
opt_peep(b);
opt_deadstores(b);
}
/*
* Set up values for branch optimizer.
*/
if (BPF_SRC(b->s.code) == BPF_K)
b->oval = K(b->s.k);
else
b->oval = b->val[X_ATOM];
b->et.code = b->s.code;
b->ef.code = -b->s.code;
}
/*
* 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 atom;
atomset use = succ->out_use;
if (use == 0)
return 0;
for (atom = 0; atom < N_ATOMS; ++atom)
if (ATOMELEM(use, atom))
if (b->val[atom] != succ->val[atom])
return 1;
return 0;
}
static struct block *
fold_edge(child, ep)
struct block *child;
struct edge *ep;
{
int sense;
int aval0, aval1, oval0, oval1;
int code = ep->code;
if (code < 0) {
code = -code;
sense = 0;
} else
sense = 1;
if (child->s.code != code)
return 0;
aval0 = child->val[A_ATOM];
oval0 = child->oval;
aval1 = ep->pred->val[A_ATOM];
oval1 = ep->pred->oval;
if (aval0 != aval1)
return 0;
if (oval0 == oval1)
/*
* The operands are identical, so the
* result is true if a true branch was
* taken to get here, otherwise false.
*/
return sense ? JT(child) : JF(child);
if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
/*
* At this point, we only know the comparison if we
* came down the true branch, and it was an equality
* comparison with a constant. We rely on the fact that
* distinct constants have distinct value numbers.
*/
return JF(child);
return 0;
}
static void
opt_j(ep)
struct edge *ep;
{
register int i, k;
register struct block *target;
if (JT(ep->succ) == 0)
return;
if (JT(ep->succ) == JF(ep->succ)) {
/*
* Common branch targets can be eliminated, provided
* there is no data dependency.
*/
if (!use_conflict(ep->pred, ep->succ->et.succ)) {
done = 0;
ep->succ = JT(ep->succ);
}
}
/*
* For each edge dominator that matches the successor of this
* edge, promote the edge successor to the its grandchild.
*
* XXX We violate the set abstraction here in favor a reasonably
* efficient loop.
*/
top:
for (i = 0; i < edgewords; ++i) {
register bpf_u_int32 x = ep->edom[i];
while (x != 0) {
k = ffs(x) - 1;
x &=~ (1 << k);
k += i * BITS_PER_WORD;
target = fold_edge(ep->succ, edges[k]);
/*
* Check that there is no data dependency between
* nodes that will be violated if we move the edge.
*/
if (target != 0 && !use_conflict(ep->pred, target)) {
done = 0;
ep->succ = target;
if (JT(target) != 0)
/*
* Start over unless we hit a leaf.
*/
goto top;
return;
}
}
}
}
static void
or_pullup(b)
struct block *b;
{
int val, at_top;
struct block *pull;
struct block **diffp, **samep;
struct edge *ep;
ep = b->in_edges;
if (ep == 0)
return;
/*
* Make sure each predecessor loads the same value.
* XXX why?
*/
val = ep->pred->val[A_ATOM];
for (ep = ep->next; ep != 0; ep = ep->next)
if (val != ep->pred->val[A_ATOM])
return;
if (JT(b->in_edges->pred) == b)
diffp = &JT(b->in_edges->pred);
else
diffp = &JF(b->in_edges->pred);
at_top = 1;
while (1) {
if (*diffp == 0)
return;
if (JT(*diffp) != JT(b))
return;
if (!SET_MEMBER((*diffp)->dom, b->id))
return;
if ((*diffp)->val[A_ATOM] != val)
break;
diffp = &JF(*diffp);
at_top = 0;
}
samep = &JF(*diffp);
while (1) {
if (*samep == 0)
return;
if (JT(*samep) != JT(b))
return;
if (!SET_MEMBER((*samep)->dom, b->id))
return;
if ((*samep)->val[A_ATOM] == val)
break;
/* XXX Need to check that there are no data dependencies
between dp0 and dp1. Currently, the code generator
will not produce such dependencies. */
samep = &JF(*samep);
}
#ifdef notdef
/* XXX This doesn't cover everything. */
for (i = 0; i < N_ATOMS; ++i)
if ((*samep)->val[i] != pred->val[i])
return;
#endif
/* Pull up the node. */
pull = *samep;
*samep = JF(pull);
JF(pull) = *diffp;
/*
* At the top of the chain, each predecessor needs to point at the
* pulled up node. Inside the chain, there is only one predecessor
* to worry about.
*/
if (at_top) {
for (ep = b->in_edges; ep != 0; ep = ep->next) {
if (JT(ep->pred) == b)
JT(ep->pred) = pull;
else
JF(ep->pred) = pull;
}
}
else
*diffp = pull;
done = 0;
}
static void
and_pullup(b)
struct block *b;
{
int val, at_top;
struct block *pull;
struct block **diffp, **samep;
struct edge *ep;
ep = b->in_edges;
if (ep == 0)
return;
/*
* Make sure each predecessor loads the same value.
*/
val = ep->pred->val[A_ATOM];
for (ep = ep->next; ep != 0; ep = ep->next)
if (val != ep->pred->val[A_ATOM])
return;
if (JT(b->in_edges->pred) == b)
diffp = &JT(b->in_edges->pred);
else
diffp = &JF(b->in_edges->pred);
at_top = 1;
while (1) {
if (*diffp == 0)
return;
if (JF(*diffp) != JF(b))
return;
if (!SET_MEMBER((*diffp)->dom, b->id))
return;
if ((*diffp)->val[A_ATOM] != val)
break;
diffp = &JT(*diffp);
at_top = 0;
}
samep = &JT(*diffp);
while (1) {
if (*samep == 0)
return;
if (JF(*samep) != JF(b))
return;
if (!SET_MEMBER((*samep)->dom, b->id))
return;
if ((*samep)->val[A_ATOM] == val)
break;
/* XXX Need to check that there are no data dependencies
between diffp and samep. Currently, the code generator
will not produce such dependencies. */
samep = &JT(*samep);
}
#ifdef notdef
/* XXX This doesn't cover everything. */
for (i = 0; i < N_ATOMS; ++i)
if ((*samep)->val[i] != pred->val[i])
return;
#endif
/* Pull up the node. */
pull = *samep;
*samep = JT(pull);
JT(pull) = *diffp;
/*
* At the top of the chain, each predecessor needs to point at the
* pulled up node. Inside the chain, there is only one predecessor
* to worry about.
*/
if (at_top) {
for (ep = b->in_edges; ep != 0; ep = ep->next) {
if (JT(ep->pred) == b)
JT(ep->pred) = pull;
else
JF(ep->pred) = pull;
}
}
else
*diffp = pull;
done = 0;
}
static void
opt_blks(root, do_stmts)
struct block *root;
int do_stmts;
{
int i, maxlevel;
struct block *p;
init_val();
maxlevel = root->level;
find_inedges(root);
for (i = maxlevel; i >= 0; --i)
for (p = levels[i]; p; p = p->link)
opt_blk(p, do_stmts);
if (do_stmts)
/*
* No point trying to move branches; it can't possibly
* make a difference at this point.
*/
return;
for (i = 1; i <= maxlevel; ++i) {
for (p = levels[i]; p; p = p->link) {
opt_j(&p->et);
opt_j(&p->ef);
}
}
find_inedges(root);
for (i = 1; i <= maxlevel; ++i) {
for (p = levels[i]; p; p = p->link) {
or_pullup(p);
and_pullup(p);
}
}
}
static inline void
link_inedge(parent, child)
struct edge *parent;
struct block *child;
{
parent->next = child->in_edges;
child->in_edges = parent;
}
static void
find_inedges(root)
struct block *root;
{
int i;
struct block *b;
for (i = 0; i < n_blocks; ++i)
blocks[i]->in_edges = 0;
/*
* Traverse the graph, adding each edge to the predecessor
* list of its successors. Skip the leaves (i.e. level 0).
*/
for (i = root->level; i > 0; --i) {
for (b = levels[i]; b != 0; b = b->link) {
link_inedge(&b->et, JT(b));
link_inedge(&b->ef, JF(b));
}
}
}
static void
opt_root(b)
struct block **b;
{
struct slist *tmp, *s;
s = (*b)->stmts;
(*b)->stmts = 0;
while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
*b = JT(*b);
tmp = (*b)->stmts;
if (tmp != 0)
sappend(s, tmp);
(*b)->stmts = s;
/*
* If the root node is a return, then there is no
* point executing any statements (since the bpf machine
* has no side effects).
*/
if (BPF_CLASS((*b)->s.code) == BPF_RET)
(*b)->stmts = 0;
}
static void
opt_loop(root, do_stmts)
struct block *root;
int do_stmts;
{
#ifdef BDEBUG
if (dflag > 1) {
printf("opt_loop(root, %d) begin\n", do_stmts);
opt_dump(root);
}
#endif
do {
done = 1;
find_levels(root);
find_dom(root);
find_closure(root);
find_ud(root);
find_edom(root);
opt_blks(root, do_stmts);
#ifdef BDEBUG
if (dflag > 1) {
printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, done);
opt_dump(root);
}
#endif
} while (!done);
}
/*
* Optimize the filter code in its dag representation.
*/
void
bpf_optimize(rootp)
struct block **rootp;
{
struct block *root;
root = *rootp;
opt_init(root);
opt_loop(root, 0);
opt_loop(root, 1);
intern_blocks(root);
#ifdef BDEBUG
if (dflag > 1) {
printf("after intern_blocks()\n");
opt_dump(root);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -