Exemple #1
0
/*
 * 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;
}
Exemple #2
0
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;
}