/* * NAME: optimize->stmt() * DESCRIPTION: optimize a statement */ node *opt_stmt(node *first, Uint *depth) { node *n, **m, **prev; Uint d; Uint d1, d2; int i; node *side; if (first == (node *) NULL) { *depth = 0; return (node *) NULL; } d = 0; prev = m = &first; for (;;) { n = ((*m)->type == N_PAIR) ? (*m)->l.left : *m; switch (n->type) { case N_BLOCK: n->l.left = opt_stmt(n->l.left, &d1); if (n->l.left == (node *) NULL) { n = (node *) NULL; } d = max2(d, d1); break; case N_CASE: n->l.left = opt_stmt(n->l.left, &d1); d = max2(d, d1); break; case N_COMPOUND: n->l.left = opt_stmt(n->l.left, &d1); if (n->l.left == (node *) NULL) { n = (node *) NULL; } else if (n->r.right != (node *) NULL) { n->r.right = opt_stmt(n->r.right, &d2); d1 = max2(d1, d2); } d = max2(d, d1); break; case N_DO: n->r.right = opt_stmt(n->r.right, &d1); side_start(&side, depth); d2 = opt_cond(&n->l.left, FALSE); d2 = max2(d2, side_end(&n->l.left, side, (node **) NULL, 0)); d = max3(d, d1, d2); break; case N_FOR: side_start(&side, depth); d1 = opt_cond(&n->l.left, FALSE); d1 = max2(d1, side_end(&n->l.left, side, (node **) NULL, 0)); i = opt_const(n->l.left); if (i == 0) { /* never */ n->r.right = opt_skip(n->r.right); if (n->r.right == (node *) NULL) { n->type = N_POP; n = opt_stmt(n, &d1); d = max2(d, d1); break; } } else if (i > 0) { /* always */ n->type = N_FOREVER; n = opt_stmt(n, &d1); d = max2(d, d1); break; } n->r.right = opt_stmt(n->r.right, &d2); d = max3(d, d1, d2); break; case N_FOREVER: if (n->l.left != (node *) NULL) { side_start(&side, depth); d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { n->l.left = (node *) NULL; } d1 = max2(d1, side_end(&n->l.left, side, (node **) NULL, 0)); if (d1 == 0) { n->l.left = (node *) NULL; } } else { d1 = 0; } n->r.right = opt_stmt(n->r.right, &d2); d = max3(d, d1, d2); break; case N_RLIMITS: side_start(&side, depth); d1 = opt_expr(&n->l.left->l.left, FALSE); d1 = max2(d1, side_end(&n->l.left->l.left, side, (node **) NULL, 0)); side_start(&side, depth); d2 = opt_expr(&n->l.left->r.right, FALSE); d2 = max2(d2, side_end(&n->l.left->r.right, side, (node **) NULL, 0)); d1 = max2(d1, d2 + 1); n->r.right = opt_stmt(n->r.right, &d2); d = max3(d, d1, d2); break; case N_CATCH: n->l.left = opt_stmt(n->l.left, &d1); if (n->l.left == (node *) NULL) { n = opt_stmt(opt_skip(n->r.right), &d1); d = max2(d, d1); } else { n->r.right = opt_stmt(n->r.right, &d2); d = max3(d, d1, d2); } break; case N_IF: side_start(&side, depth); d1 = opt_cond(&n->l.left, FALSE); d1 = max2(d1, side_end(&n->l.left, side, (node **) NULL, 0)); i = opt_const(n->l.left); if (i == 0) { n->r.right->l.left = opt_skip(n->r.right->l.left); } else if (i > 0) { n->r.right->r.right = opt_skip(n->r.right->r.right); } n->r.right->l.left = opt_stmt(n->r.right->l.left, &d2); d1 = max2(d1, d2); n->r.right->r.right = opt_stmt(n->r.right->r.right, &d2); if (n->r.right->l.left == (node *) NULL) { if (n->r.right->r.right == (node *) NULL) { n->type = N_POP; n = opt_stmt(n, &d1); d = max2(d, d1); break; } n->l.left = opt_not(n->l.left); n->r.right->l.left = n->r.right->r.right; n->r.right->r.right = (node *) NULL; } d = max3(d, d1, d2); break; case N_PAIR: n = opt_stmt(n, &d1); d = max2(d, d1); break; case N_POP: side_start(&side, depth); d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { n->l.left = (node *) NULL; } d = max3(d, d1, side_end(&n->l.left, side, (node **) NULL, 0)); if (n->l.left == (node *) NULL) { n = (node *) NULL; } break; case N_RETURN: side_start(&side, depth); d1 = opt_expr(&n->l.left, FALSE); d = max3(d, d1, side_end(&n->l.left, side, (node **) NULL, 0)); break; case N_SWITCH_INT: case N_SWITCH_RANGE: case N_SWITCH_STR: n->r.right->r.right = opt_stmt(n->r.right->r.right, &d1); if (n->r.right->r.right == (node *) NULL) { n = n->r.right; n->type = N_POP; n = opt_stmt(n, &d1); d = max2(d, d1); } else { side_start(&side, depth); d2 = opt_expr(&n->r.right->l.left, FALSE); d2 = max2(d2, side_end(&n->r.right->l.left, side, (node **) NULL, 0)); d = max3(d, d1, d2); } break; } if ((*m)->type == N_PAIR) { if (n == (node *) NULL) { *m = (*m)->r.right; } else { (*m)->l.left = n; if (n->flags & F_END) { n = opt_skip((*m)->r.right); if (n == (node *) NULL) { *m = (*m)->l.left; break; } (*m)->r.right = n; } prev = m; m = &(*m)->r.right; } } else { *m = n; if (n == (node *) NULL && prev != m) { *prev = (*prev)->l.left; } break; } } *depth = d; return first; }
static void opt_blk(struct block *b, int do_stmts) { struct slist *s; struct edge *p; int i; bpf_int32 aval, xval; #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. */ p = b->in_edges; if (p == 0) { /* * We have no predecessors, so everything is undefined * upon entry to this block. */ memset((char *)b->val, 0, sizeof(b->val)); } else { /* * Inherit values from our predecessors. * * First, get the values from the predecessor along the * first edge leading to this node. */ memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val)); /* * Now look at all the other nodes leading to this node. * If, for the predecessor along that edge, a register * has a different value from the one we have (i.e., * control paths are merging, and the merging paths * assign different values to that register), give the * register the undefined value of 0. */ 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]; xval = b->val[X_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 or index register with a * value that is already there, or if this block is a return, * eliminate all the statements. * * XXX - what if it does a store? * * XXX - why does it matter whether we use anything from this * block? If the accumulator or index register doesn't change * its value, isn't that OK even if we use that value? * * XXX - if we load the accumulator with a different value, * and the block ends with a conditional branch, we obviously * can't eliminate it, as the branch depends on that value. * For the index register, the conditional branch only depends * on the index register value if the test is against the index * register value rather than a constant; if nothing uses the * value we put into the index register, and we're not testing * against the index register's value, and there aren't any * other problems that would keep us from eliminating this * block, can we eliminate it? */ if (do_stmts && ((b->out_use == 0 && aval != 0 && b->val[A_ATOM] == aval && xval != 0 && b->val[X_ATOM] == xval) || 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; }