Beispiel #1
0
/*
 * NAME:	optimize->lvalue()
 * DESCRIPTION:	optimize an lvalue
 */
static Uint opt_lvalue(node *n)
{
    node *m;

    if (n->type == N_CAST) {
	n = n->l.left;
    }
    switch (n->type) {
    case N_INDEX:
	m = n->l.left;
	if (m->type == N_CAST) {
	    m = m->l.left;
	}
	switch (m->type) {
	case N_INDEX:
	    /* strarray[x][y] = 'c'; */
	    return max3(opt_expr(&m->l.left, FALSE),
			opt_expr(&m->r.right, FALSE) + 1,
			opt_expr(&n->r.right, FALSE) + 3);

	default:
	    return max2(opt_expr(&n->l.left, FALSE),
			opt_expr(&n->r.right, FALSE) + 1);
	}

    default:
	return 0;
    }
}
Beispiel #2
0
/*
 * NAME:	optimize->cond()
 * DESCRIPTION:	optimize a condition
 */
static Uint opt_cond(node **m, bool pop)
{
    Uint d;

    d = opt_expr(m, pop);
    if (*m != (node *) NULL && (*m)->type == N_TST) {
	*m = (*m)->l.left;
    }
    return d;
}
Beispiel #3
0
/*
 * NAME:	optimize->lvalue()
 * DESCRIPTION:	optimize an lvalue
 */
static Uint opt_lvalue(node *n)
{
    node *m;

    if (n->type == N_CAST) {
	n = n->l.left;
    }
    switch (n->type) {
    case N_GLOBAL:
	return 3;

    case N_INDEX:
	m = n->l.left;
	if (m->type == N_CAST) {
	    m = m->l.left;
	}
	switch (m->type) {
	case N_GLOBAL:
	    /* global_strval[x] = 'c'; */
	    return opt_expr(&n->r.right, FALSE) + 3;

	case N_INDEX:
	    /* strarray[x][y] = 'c'; */
	    return max3(opt_expr(&m->l.left, FALSE),
			opt_expr(&m->r.right, FALSE) + 1,
			opt_expr(&n->r.right, FALSE) + 4);

	default:
	    return max2(opt_expr(&n->l.left, FALSE),
			opt_expr(&n->r.right, FALSE) + 2);
	}

    default:
	return 2;
    }
}
Beispiel #4
0
/*
 * NAME:	optimize->binop()
 * DESCRIPTION:	optimize a binary operator expression
 */
static Uint opt_binop(node **m)
{
    node *n, *t;
    Uint d1, d2, d;
    Float f1, f2;

    n = *m;
    if (n->type == N_ADD && n->r.right->type == N_ADD &&
	n->l.left->mod == n->r.right->mod &&
	(n->mod == T_STRING || (n->mod & T_REF) != 0)) {
	/*
	 * a + (b + c) --> (a + b) + c
	 * the order in which these are added won't affect the final result
	 */
	t = n->l.left;
	n->l.left = n->r.right;
	n->r.right = n->l.left->r.right;
	n->l.left->r.right = n->l.left->l.left;
	n->l.left->l.left = t;
    }

    d1 = opt_expr(&n->l.left, FALSE);
    d2 = opt_expr(&n->r.right, FALSE);

    if (n->type == N_SUM) {
	if (n->l.left->type == N_RANGE) {
	    d1 = max2(d1, 3);
	} else if (n->l.left->type != N_SUM) {
	    d1++;
	}
	if (n->r.right->type == N_RANGE) {
	    d2 = max2(d2, 3);
	} else {
	    d2++;
	}
	return d1 + d2;
    }
    if (n->type == N_ADD) {
	if (n->r.right->type == N_STR &&
	    (n->l.left->type == N_ADD || n->l.left->type == N_SUM) &&
	    n->l.left->r.right->type == N_STR) {
	    /* (x + s1) + s2 */
	    node_tostr(n->r.right, str_add(n->l.left->r.right->l.string,
					   n->r.right->l.string));
	    n->l.left = n->l.left->l.left;
	    return d1;
	}

	if (n->l.left->mod == T_STRING || (n->l.left->mod & T_REF) != 0) {
	    /*
	     * see if the summand operator can be used
	     */
	    switch (n->l.left->type) {
	    case N_ADD:
		n->l.left->type = N_SUM;
		d1 += 2;			/* SUM_SIMPLE on both sides */
		if (n->l.left->l.left->type == N_RANGE) {
		    d1++;
		}
		n->type = N_SUM;
		if (n->r.right->type == N_RANGE) {
		    d2 = max2(d2, 3);		/* at least 3 */
		} else {
		    d2++;			/* add SUM_SIMPLE */
		}
		return d1 + d2;

	    case N_FUNC:
		if (n->l.left->r.number == kd_allocate ||
		    n->l.left->r.number == kd_allocate_int ||
		    n->l.left->r.number == kd_allocate_float) {
		    t = n->l.left->l.left->r.right;
		    if (t != (node *) NULL && t->type != N_PAIR &&
			t->type != N_SPREAD && t->mod == T_INT) {
			d1++;			/* add SUM_ALLOCATE */
			n->type = N_SUM;
			if (n->r.right->type == N_RANGE) {
			    d2 = max2(d2, 3);	/* at least 3 */
			} else {
			    d2++;		/* add SUM_SIMPLE */
			}
			return d1 + d2;
		    }
		}
		/* fall through */
	    default:
		if (n->r.right->type != N_RANGE && n->r.right->type != N_AGGR) {
		    if (n->r.right->type != N_FUNC ||
			(n->r.right->r.number != kd_allocate &&
			 n->r.right->r.number != kd_allocate_int &&
			 n->r.right->r.number != kd_allocate_float)) {
			break;
		    }
		    t = n->r.right->l.left->r.right;
		    if (t == (node *) NULL || t->type == N_PAIR ||
			t->type == N_SPREAD || t->mod != T_INT) {
			break;
		    }
		}
		/* fall through */
	    case N_AGGR:
		d1++;				/* add SUM_SIMPLE */
		n->type = N_SUM;
		if (n->r.right->type == N_RANGE) {
		    d2 = max2(d2, 3);		/* at least 3 */
		} else {
		    d2++;			/* add SUM_SIMPLE */
		}
		return d1 + d2;

	    case N_RANGE:
		d1 = max2(d1, 3);		/* at least 3 */
		/* fall through */
	    case N_SUM:
		n->type = N_SUM;
		if (n->r.right->type == N_RANGE) {
		    d2 = max2(d2, 3);		/* at least 3 */
		} else {
		    d2++;			/* add SUM_SIMPLE */
		}
		return d1 + d2;
	    }
	}
    }

    if (n->l.left->flags & F_CONST) {
	if (n->r.right->flags & F_CONST) {
	    /* c1 . c2 */
	    return opt_binconst(m);
	}
	switch (n->type) {
	case N_ADD:
	    if (!T_ARITHMETIC(n->l.left->mod) || !T_ARITHMETIC(n->r.right->mod))
	    {
		break;
	    }
	    /* fall through */
	case N_ADD_INT:
	case N_ADD_FLOAT:
	case N_AND:
	case N_AND_INT:
	case N_EQ:
	case N_EQ_INT:
	case N_EQ_FLOAT:
	case N_MULT:
	case N_MULT_INT:
	case N_MULT_FLOAT:
	case N_NE:
	case N_NE_INT:
	case N_NE_FLOAT:
	case N_OR:
	case N_OR_INT:
	case N_XOR:
	case N_XOR_INT:
	    /* swap constant to the right */
	    t = n->l.left;
	    n->l.left = n->r.right;
	    n->r.right = t;
	    d = d1;
	    d1 = d2;
	    d2 = d;
	    break;
	}
    }
    d = max2(d1, d2 + 1);

    if ((n->r.right->type == N_INT && n->r.right->l.number == 0 &&
	 n->l.left->mod == T_INT) ||
	(n->r.right->type == N_FLOAT && NFLT_ISZERO(n->r.right) &&
	 n->l.left->mod == T_FLOAT) ||
	(n->r.right->type == nil_node && n->r.right->l.number == 0 &&
	 n->l.left->mod != T_MIXED && T_POINTER(n->l.left->mod))) {
	/*
	 * int == 0, float == 0.0, ptr == nil
	 */
	switch (n->type) {
	case N_EQ:
	case N_EQ_INT:
	case N_EQ_FLOAT:
	    *m = opt_not(n->l.left);
	    return d1;

	case N_NE:
	case N_NE_INT:
	case N_NE_FLOAT:
	    *m = opt_tst(n->l.left);
	    return d1;
	}
    }

    if (T_ARITHMETIC(n->mod) && n->mod == n->l.left->mod &&
	n->mod == n->r.right->mod) {
	if (n->r.right->flags & F_CONST) {
	    /* x . c */
	    if ((n->type == n->l.left->type ||
		 (n->mod == T_INT && n->l.left->mod == T_INT &&
		  n->type == n->l.left->type + 1)) &&
		(n->l.left->r.right->flags & F_CONST)) {
		/* (x . c1) . c2 */
		switch (n->type) {
		case N_ADD_FLOAT:
		case N_SUB_FLOAT:
		    NFLT_GET(n->l.left->r.right, f1);
		    NFLT_GET(n->r.right, f2);
		    f1.add(f2);
		    NFLT_PUT(n->l.left->r.right, f1);
		    *m = n->l.left;
		    d = d1;
		    break;

		case N_ADD_INT:
		case N_SUB_INT:
		case N_LSHIFT_INT:
		case N_RSHIFT_INT:
		    n->l.left->r.right->l.number += n->r.right->l.number;
		    *m = n->l.left;
		    d = d1;
		    break;

		case N_AND_INT:
		    n->l.left->r.right->l.number &= n->r.right->l.number;
		    *m = n->l.left;
		    d = d1;
		    break;

		case N_DIV_FLOAT:
		case N_MULT_FLOAT:
		    NFLT_GET(n->l.left->r.right, f1);
		    NFLT_GET(n->r.right, f2);
		    f1.mult(f2);
		    NFLT_PUT(n->l.left->r.right, f1);
		    *m = n->l.left;
		    d = d1;
		    break;

		case N_DIV_INT:
		case N_MULT_INT:
		    n->l.left->r.right->l.number *= n->r.right->l.number;
		    *m = n->l.left;
		    d = d1;
		    break;

		case N_OR_INT:
		    n->l.left->r.right->l.number |= n->r.right->l.number;
		    *m = n->l.left;
		    d = d1;
		    break;

		case N_XOR_INT:
		    n->l.left->r.right->l.number ^= n->r.right->l.number;
		    *m = n->l.left;
		    d = d1;
		    break;
		}
	    } else {
		switch (n->type) {
		case N_ADD_FLOAT:
		    if (n->l.left->type == N_SUB_FLOAT) {
			if (n->l.left->l.left->type == N_FLOAT) {
			    /* (c1 - x) + c2 */
			    NFLT_GET(n->l.left->l.left, f1);
			    NFLT_GET(n->r.right, f2);
			    f1.add(f2);
			    NFLT_PUT(n->l.left->l.left, f1);
			    *m = n->l.left;
			    return d1;
			}
			if (n->l.left->r.right->type == N_FLOAT) {
			    /* (x - c1) + c2 */
			    NFLT_GET(n->l.left->r.right, f1);
			    NFLT_GET(n->r.right, f2);
			    f1.sub(f2);
			    NFLT_PUT(n->l.left->r.right, f1);
			    *m = n->l.left;
			    d = d1;
			}
		    }
		    break;

		case N_ADD_INT:
		    if (n->l.left->type == N_SUB ||
			n->l.left->type == N_SUB_INT) {
			if (n->l.left->l.left->type == N_INT) {
			    /* (c1 - x) + c2 */
			    n->l.left->l.left->l.number += n->r.right->l.number;
			    *m = n->l.left;
			    return d1;
			}
			if (n->l.left->r.right->type == N_INT) {
			    /* (x - c1) + c2 */
			    n->l.left->r.right->l.number -=
							n->r.right->l.number;
			    *m = n->l.left;
			    d = d1;
			}
		    }
		    break;

		case N_DIV_FLOAT:
		    if (n->l.left->type == N_MULT_FLOAT &&
			n->l.left->r.right->type == N_FLOAT &&
			!NFLT_ISZERO(n->r.right)) {
			/* (x * c1) / c2 */
			NFLT_GET(n->l.left->r.right, f1);
			NFLT_GET(n->r.right, f2);
			f1.div(f2);
			NFLT_PUT(n->l.left->r.right, f1);
			*m = n->l.left;
			d = d1;
		    }
		    break;

		case N_MULT_FLOAT:
		    if (n->l.left->type == N_DIV_FLOAT) {
			if (n->l.left->l.left->type == N_FLOAT) {
			    /* (c1 / x) * c2 */
			    NFLT_GET(n->l.left->l.left, f1);
			    NFLT_GET(n->r.right, f2);
			    f1.mult(f2);
			    NFLT_PUT(n->l.left->l.left, f1);
			    *m = n->l.left;
			    return d1;
			}
			if (n->l.left->r.right->type == N_FLOAT &&
			    !NFLT_ISZERO(n->l.left->r.right)) {
			    /* (x / c1) * c2 */
			    NFLT_GET(n->r.right, f1);
			    NFLT_GET(n->l.left->r.right, f2);
			    f1.div(f2);
			    NFLT_PUT(n->r.right, f1);
			    n->l.left = n->l.left->l.left;
			    d = d1;
			}
		    }
		    break;

		case N_SUB_FLOAT:
		    if (n->l.left->type == N_ADD_FLOAT &&
			n->l.left->r.right->type == N_FLOAT) {
			/* (x + c1) - c2 */
			NFLT_GET(n->l.left->r.right, f1);
			NFLT_GET(n->r.right, f2);
			f1.sub(f2);
			NFLT_PUT(n->l.left->r.right, f1);
			*m = n->l.left;
			d = d1;
		    }
		    break;

		case N_SUB_INT:
		    if (n->l.left->type == N_ADD_INT &&
			n->l.left->r.right->type == N_INT) {
			/* (x + c1) - c2 */
			n->l.left->r.right->l.number -= n->r.right->l.number;
			*m = n->l.left;
			d = d1;
		    }
		    break;
		}
	    }
	} else if (n->l.left->flags & F_CONST) {
	    /* c . x */
	    switch (n->type) {
	    case N_SUB_FLOAT:
		if (n->r.right->type == N_SUB_FLOAT) {
		    if (n->r.right->l.left->type == N_FLOAT) {
			/* c1 - (c2 - x) */
			NFLT_GET(n->l.left, f1);
			NFLT_GET(n->r.right->l.left, f2);
			f1.sub(f2);
			n->type = N_ADD;
			n->l.left = n->r.right->r.right;
			n->r.right = n->r.right->l.left;
			NFLT_PUT(n->r.right, f1);
			d = d2;
		    } else if (n->r.right->r.right->type == N_FLOAT) {
			/* c1 - (x - c2) */
			NFLT_GET(n->l.left, f1);
			NFLT_GET(n->r.right->r.right, f2);
			f1.add(f2);
			NFLT_PUT(n->l.left, f1);
			n->r.right = n->r.right->l.left;
			return d2 + 1;
		    }
		} else if (n->r.right->type == N_ADD_FLOAT &&
			   n->r.right->r.right->type == N_FLOAT) {
		    /* c1 - (x + c2) */
		    NFLT_GET(n->l.left, f1);
		    NFLT_GET(n->r.right->r.right, f2);
		    f1.sub(f2);
		    NFLT_PUT(n->l.left, f1);
		    n->r.right = n->r.right->l.left;
		    return d2 + 1;
		}
		break;

	    case N_SUB_INT:
		if ((n->r.right->type == N_SUB ||
		     n->r.right->type == N_SUB_INT)) {
		    if (n->r.right->l.left->type == N_INT) {
			/* c1 - (c2 - x) */
			n->r.right->l.left->l.number -= n->l.left->l.number;
			n->type = n->r.right->type;
			n->l.left = n->r.right->r.right;
			n->r.right = n->r.right->l.left;
			d = d2;
		    } else if (n->r.right->r.right->type == N_INT) {
			/* c1 - (x - c2) */
			n->l.left->l.number += n->r.right->r.right->l.number;
			n->r.right->r.right = n->r.right->l.left;
			n->r.right->l.left = n->l.left;
			*m = n->r.right;
			return d2 + 1;
		    }
		} else if (n->r.right->type == N_ADD_INT &&
			   n->r.right->r.right->type == N_INT) {
		    /* c1 - (x + c2) */
		    n->l.left->l.number -= n->r.right->r.right->l.number;
		    n->r.right = n->r.right->l.left;
		    return d2 + 1;
		}
		break;

	    case N_DIV_FLOAT:
		if (n->r.right->type == N_DIV_FLOAT) {
		    if (n->r.right->l.left->type == N_FLOAT &&
			!NFLT_ISZERO(n->r.right->l.left)) {
			/* c1 / (c2 / x) */
			NFLT_GET(n->l.left, f1);
			NFLT_GET(n->r.right->l.left, f2);
			f1.div(f2);
			n->type = N_MULT;
			n->l.left = n->r.right->r.right;
			n->r.right = n->r.right->l.left;
			NFLT_PUT(n->r.right, f1);
			d = d2;
		    } else if (n->r.right->r.right->type == N_FLOAT) {
			/* c1 / (x / c2) */
			NFLT_GET(n->l.left, f1);
			NFLT_GET(n->r.right->r.right, f2);
			f1.mult(f2);
			NFLT_PUT(n->l.left, f1);
			n->r.right = n->r.right->l.left;
			return d2 + 1;
		    }
		} else if (n->r.right->type == N_MULT_FLOAT &&
			   n->r.right->r.right->type == N_FLOAT &&
			   !NFLT_ISZERO(n->r.right->r.right)) {
		    /* c1 / (x * c2) */
		    NFLT_GET(n->l.left, f1);
		    NFLT_GET(n->r.right->r.right, f2);
		    f1.div(f2);
		    NFLT_PUT(n->l.left, f1);
		    n->r.right = n->r.right->l.left;
		    return d2 + 1;
		}
		break;
	    }
	}
	n = *m;

	if (T_ARITHMETIC(n->l.left->mod) && (n->r.right->flags & F_CONST)) {
	    switch (n->type) {
	    case N_ADD:
	    case N_ADD_FLOAT:
	    case N_SUB:
	    case N_SUB_FLOAT:
		if (NFLT_ISZERO(n->r.right)) {
		    *m = n->l.left;
		    d = d1;
		}
		break;

	    case N_ADD_INT:
	    case N_SUB_INT:
	    case N_LSHIFT_INT:
	    case N_RSHIFT_INT:
	    case N_XOR_INT:
		if (n->r.right->l.number == 0) {
		    *m = n->l.left;
		    d = d1;
		}
		break;

	    case N_AND_INT:
		if (n->r.right->l.number == 0) {
		    n->type = N_COMMA;
		    return opt_expr(m, FALSE);
		}
		if (n->r.right->l.number == -1) {
		    *m = n->l.left;
		    d = d1;
		}
		break;

	    case N_MULT:
	    case N_MULT_FLOAT:
		if (NFLT_ISZERO(n->r.right)) {
		    n->type = N_COMMA;
		    return opt_expr(m, FALSE);
		}
		/* fall through */
	    case N_DIV:
	    case N_DIV_FLOAT:
		if (NFLT_ISONE(n->r.right)) {
		    *m = n->l.left;
		    d = d1;
		}
		break;

	    case N_MULT_INT:
		if (n->r.right->l.number == 0) {
		    n->type = N_COMMA;
		    return opt_expr(m, FALSE);
		}
		/* fall through */
	    case N_DIV_INT:
		if (n->r.right->l.number == 1) {
		    *m = n->l.left;
		    d = d1;
		}
		break;

	    case N_MOD_INT:
		if (n->r.right->l.number == 1) {
		    n->r.right->l.number = 0;
		    n->type = N_COMMA;
		    return opt_expr(m, FALSE);
		}
		break;

	    case N_OR_INT:
		if (n->r.right->l.number == -1) {
		    n->type = N_COMMA;
		    return opt_expr(m, FALSE);
		}
		if (n->r.right->l.number == 0) {
		    *m = n->l.left;
		    d = d1;
		}
		break;
	    }
	}
    }

    return d;
}
Beispiel #5
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;
}
Beispiel #6
0
/*
 * NAME:	optimize->expr()
 * DESCRIPTION:	optimize an expression
 */
static Uint opt_expr(node **m, bool pop)
{
    Uint d1, d2, i;
    node *n;
    node **oldside, *side;
    Uint olddepth;

    n = *m;
    switch (n->type) {
    case N_FLOAT:
    case N_GLOBAL:
    case N_INT:
    case N_LOCAL:
    case N_STR:
    case N_NIL:
	return !pop;

    case N_TOINT:
    case N_CAST:
	return opt_expr(&n->l.left, FALSE);

    case N_NEG:
    case N_UMIN:
	return max2(opt_expr(&n->l.left, FALSE), 2);

    case N_CATCH:
	oldside = side_start(&side, &olddepth);
	d1 = opt_expr(&n->l.left, TRUE);
	if (d1 == 0) {
	    n->l.left = (node *) NULL;
	}
	d1 = max2(d1, side_end(&n->l.left, side, oldside, olddepth));
	if (d1 == 0) {
	    *m = node_nil();
	    (*m)->line = n->line;
	    return !pop;
	}
	return d1;

    case N_TOFLOAT:
	if (n->l.left->mod != T_INT) {
	    return opt_expr(&n->l.left, FALSE);
	}
	/* fall through */
    case N_NOT:
    case N_TST:
	if (pop) {
	    *m = n->l.left;
	    return opt_expr(m, TRUE);
	}
	return opt_expr(&n->l.left, FALSE);

    case N_TOSTRING:
	if (pop && (n->l.left->mod == T_INT || n->l.left->mod == T_FLOAT)) {
	    *m = n->l.left;
	    return opt_expr(m, TRUE);
	}
	return opt_expr(&n->l.left, FALSE);

    case N_LVALUE:
	return opt_lvalue(n->l.left);

    case N_ADD_EQ_1:
    case N_ADD_EQ_1_INT:
    case N_ADD_EQ_1_FLOAT:
    case N_SUB_EQ_1:
    case N_SUB_EQ_1_INT:
    case N_SUB_EQ_1_FLOAT:
	return opt_lvalue(n->l.left) + 1;

    case N_MIN_MIN:
	if (pop) {
	    n->type = N_SUB_EQ_1;
	}
	return opt_lvalue(n->l.left) + 1;

    case N_MIN_MIN_INT:
	if (pop) {
	    n->type = N_SUB_EQ_1_INT;
	}
	return opt_lvalue(n->l.left) + 1;

    case N_MIN_MIN_FLOAT:
	if (pop) {
	    n->type = N_SUB_EQ_1_FLOAT;
	}
	return opt_lvalue(n->l.left) + 1;

    case N_PLUS_PLUS:
	if (pop) {
	    n->type = N_ADD_EQ_1;
	}
	return opt_lvalue(n->l.left) + 1;

    case N_PLUS_PLUS_INT:
	if (pop) {
	    n->type = N_ADD_EQ_1_INT;
	}
	return opt_lvalue(n->l.left) + 1;

    case N_PLUS_PLUS_FLOAT:
	if (pop) {
	    n->type = N_ADD_EQ_1_FLOAT;
	}
	return opt_lvalue(n->l.left) + 1;

    case N_FUNC:
	m = &n->l.left->r.right;
	n = *m;
	if (n == (node *) NULL) {
	    return 1;
	}

	d1 = 0;
	for (i = 0; n->type == N_PAIR; ) {
	    oldside = side_start(&side, &olddepth);
	    d2 = opt_expr(&n->l.left, FALSE);
	    d1 = max3(d1, i + d2,
		      i + side_end(&n->l.left, side, oldside, olddepth));
	    m = &n->r.right;
	    n = n->l.left;
	    i += (n->type == N_LVALUE ||
		  (n->type == N_COMMA && n->r.right->type == N_LVALUE)) ? 6 : 1;
	    n = *m;
	}
	if (n->type == N_SPREAD) {
	    m = &n->l.left;
	}
	oldside = side_start(&side, &olddepth);
	d2 = opt_expr(m, FALSE);
	d1 = max3(d1, i + d2, i + side_end(m, side, oldside, olddepth));
	n = *m;
	if (n->type == N_LVALUE ||
	    (n->type == N_COMMA && n->r.right->type == N_LVALUE)) {
	    d1 += 2;
	}
	return d1;

    case N_INSTANCEOF:
	return opt_expr(&n->l.left, FALSE) + 1;

    case N_GE:
    case N_GT:
    case N_LE:
    case N_LT:
	if (n->l.left->mod != n->r.right->mod) {
	    return max2(opt_expr(&n->l.left, FALSE),
			opt_expr(&n->r.right, FALSE) + 1);
	}
	/* fall through */
    case N_EQ:
    case N_NE:
	if (pop) {
	    d1 = opt_expr(&n->l.left, TRUE);
	    if (d1 == 0) {
		*m = n->r.right;
		return opt_expr(m, TRUE);
	    }
	    d2 = opt_expr(&n->r.right, TRUE);
	    if (d2 == 0) {
		*m = n->l.left;
		return d1;
	    }
	    n->type = N_COMMA;
	    side_add(m, d1);
	    return d2;
	}
	return opt_binop(m);

    case N_DIV_INT:
    case N_MOD_INT:
	if (n->r.right->type == N_INT && n->r.right->l.number == 0) {
	    d1 = opt_binop(m);
	    return (d1 == 1) ? !pop : d1;
	}
	/* fall through */
    case N_ADD_INT:
    case N_ADD_FLOAT:
    case N_AND_INT:
    case N_DIV_FLOAT:
    case N_EQ_INT:
    case N_EQ_FLOAT:
    case N_GE_INT:
    case N_GE_FLOAT:
    case N_GT_INT:
    case N_GT_FLOAT:
    case N_LE_INT:
    case N_LE_FLOAT:
    case N_LSHIFT_INT:
    case N_LT_INT:
    case N_LT_FLOAT:
    case N_MULT_INT:
    case N_MULT_FLOAT:
    case N_NE_INT:
    case N_NE_FLOAT:
    case N_OR_INT:
    case N_RSHIFT_INT:
    case N_SUB_INT:
    case N_SUB_FLOAT:
    case N_XOR_INT:
	if (pop) {
	    d1 = opt_expr(&n->l.left, TRUE);
	    if (d1 == 0) {
		*m = n->r.right;
		return opt_expr(m, TRUE);
	    }
	    d2 = opt_expr(&n->r.right, TRUE);
	    if (d2 == 0) {
		*m = n->l.left;
		return d1;
	    }
	    n->type = N_COMMA;
	    side_add(m, d1);
	    return d2;
	}
	/* fall through */
    case N_ADD:
    case N_AND:
    case N_DIV:
    case N_LSHIFT:
    case N_MOD:
    case N_MULT:
    case N_OR:
    case N_RSHIFT:
    case N_SUB:
    case N_SUM:
    case N_XOR:
	d1 = opt_binop(m);
	return (d1 == 1) ? !pop : d1;

    case N_INDEX:
	if (n->l.left->type == N_STR && n->r.right->type == N_INT) {
	    if (n->r.right->l.number < 0 ||
		n->r.right->l.number >= (long) n->l.left->l.string->len) {
		return 2;
	    }
	    node_toint(n, (Int) str_index(n->l.left->l.string,
					  (long) n->r.right->l.number));
	    return !pop;
	}
	if (n->l.left->type == N_FUNC && n->r.right->mod == T_INT) {
	    if (n->l.left->r.number == kd_status) {
		n->type = N_FUNC;
		if (n->l.left->l.left->r.right != (node *) NULL) {
		    /* status(obj)[i] */
		    n = n->l.left;
		    n->type = N_STR;
		    n->r.right = n->l.left;
		    n->l.string = n->l.left->l.string;
		    n = n->r.right;
		    n->type = N_PAIR;
		    n->l.left = n->r.right;
		    n->r.right = (*m)->r.right;
		    (*m)->r.number = ((long) KFCALL << 24) | KF_STATUSO_IDX;
		} else {
		    /* status()[i] */
		    n->l.left = n->l.left->l.left;
		    n->l.left->r.right = n->r.right;
		    n->r.number = ((long) KFCALL << 24) | KF_STATUS_IDX;
		}
		return opt_expr(m, pop);
	    }
	    if (n->l.left->r.number == kd_call_trace) {
		/* call_trace()[i] */
		n->type = N_FUNC;
		n->l.left = n->l.left->l.left;
		n->l.left->r.right = n->r.right;
		n->r.number = ((long) KFCALL << 24) | KF_CALLTR_IDX;
		return opt_expr(m, pop);
	    }
	}
	return max3(opt_expr(&n->l.left, FALSE),
		    opt_expr(&n->r.right, FALSE) + 1, 3);

    case N_ADD_EQ:
    case N_ADD_EQ_INT:
    case N_ADD_EQ_FLOAT:
    case N_AND_EQ:
    case N_AND_EQ_INT:
    case N_DIV_EQ:
    case N_DIV_EQ_INT:
    case N_DIV_EQ_FLOAT:
    case N_LSHIFT_EQ:
    case N_LSHIFT_EQ_INT:
    case N_MOD_EQ:
    case N_MOD_EQ_INT:
    case N_MULT_EQ:
    case N_MULT_EQ_INT:
    case N_MULT_EQ_FLOAT:
    case N_OR_EQ:
    case N_OR_EQ_INT:
    case N_RSHIFT_EQ:
    case N_RSHIFT_EQ_INT:
    case N_SUB_EQ:
    case N_SUB_EQ_INT:
    case N_SUB_EQ_FLOAT:
    case N_SUM_EQ:
    case N_XOR_EQ:
    case N_XOR_EQ_INT:
	return opt_asgnexp(m, pop);

    case N_ASSIGN:
	if (n->l.left->type == N_AGGR) {
	    d2 = 0;
	    for (n = n->l.left->l.left; n->type == N_PAIR; n = n->r.right) {
		d1 = opt_lvalue(n->l.left);
		d2 += 2 + ((d1 < 4) ? d1 : 4);
	    }
	    d1 = opt_lvalue(n);
	    d2 += 2 + ((d1 < 4) ? d1 : 4);
	    return d2 + max2(2, opt_expr(&(*m)->r.right, FALSE));
	} else {
	    d1 = opt_lvalue(n->l.left);
	    return max2(d1, ((d1 < 4) ? d1 : 4) + opt_expr(&n->r.right, FALSE));
	}

    case N_COMMA:
	side_add(m, opt_expr(&n->l.left, TRUE));
	return opt_expr(m, pop);

    case N_LAND:
	d1 = opt_cond(&n->l.left, FALSE);
	if (n->l.left->flags & F_CONST) {
	    if (!opt_ctest(n->l.left)) {
		/* false && x */
		*m = n->l.left;
		return !pop;
	    }
	    /* true && x */
	    n->type = N_TST;
	    n->l.left = n->r.right;
	    return opt_expr(m, pop);
	}

	oldside = side_start(&side, &olddepth);
	d2 = opt_cond(&n->r.right, pop);
	if (d2 == 0) {
	    n->r.right = (node *) NULL;
	}
	d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth));
	if (d2 == 0) {
	    *m = n->l.left;
	    return opt_expr(m, TRUE);
	}
	if (n->r.right->flags & F_CONST) {
	    if (pop) {
		*m = n->l.left;
		return opt_expr(m, TRUE);
	    }
	    if (!opt_ctest(n->r.right)) {
		/* x && false */
		n->type = N_COMMA;
		return opt_expr(m, FALSE);
	    }
	    /* x && true */
	    n->type = N_TST;
	    return d1;
	}
	if (n->r.right->type == N_COMMA) {
	    n = n->r.right;
	    if ((n->r.right->flags & F_CONST) && !opt_ctest(n->r.right)) {
		/* x && (y, false) --> (x && y, false) */
		(*m)->r.right = n->l.left;
		n->l.left = *m;
		*m = n;
		return opt_expr(m, pop);
	    }
	}
	return max2(d1, d2);

    case N_LOR:
	d1 = opt_cond(&n->l.left, FALSE);
	if (n->l.left->flags & F_CONST) {
	    if (opt_ctest(n->l.left)) {
		/* true || x */
		*m = n->l.left;
		return !pop;
	    }
	    /* false || x */
	    n->type = N_TST;
	    n->l.left = n->r.right;
	    return opt_expr(m, pop);
	}

	oldside = side_start(&side, &olddepth);
	d2 = opt_cond(&n->r.right, pop);
	if (d2 == 0) {
	    n->r.right = (node *) NULL;
	}
	d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth));
	if (d2 == 0) {
	    *m = n->l.left;
	    return opt_expr(m, TRUE);
	}
	if (n->r.right->flags & F_CONST) {
	    if (pop) {
		*m = n->l.left;
		return opt_expr(m, TRUE);
	    }
	    if (opt_ctest(n->r.right)) {
		/* x || true */
		n->type = N_COMMA;
		return opt_expr(m, FALSE);
	    }
	    /* x || false */
	    n->type = N_TST;
	    return d1;
	}
	if (n->r.right->type == N_COMMA) {
	    n = n->r.right;
	    if ((n->r.right->flags & F_CONST) && opt_ctest(n->r.right)) {
		/* x || (y, true) --> (x || y, true) */
		(*m)->r.right = n->l.left;
		n->l.left = *m;
		*m = n;
		return opt_expr(m, pop);
	    }
	}
	return max2(d1, d2);

    case N_QUEST:
	i = opt_cond(&n->l.left, FALSE);
	if (n->l.left->flags & F_CONST) {
	    if (opt_ctest(n->l.left)) {
		*m = n->r.right->l.left;
	    } else {
		*m = n->r.right->r.right;
	    }
	    return opt_expr(m, pop);
	}
	if (n->l.left->type == N_COMMA && (n->l.left->r.right->flags & F_CONST))
	{
	    side_add(&n->l.left, i);
	    if (opt_ctest(n->l.left)) {
		*m = n->r.right->l.left;
	    } else {
		*m = n->r.right->r.right;
	    }
	    return opt_expr(m, pop);
	}

	n = n->r.right;
	oldside = side_start(&side, &olddepth);
	d1 = opt_expr(&n->l.left, pop);
	if (d1 == 0) {
	    n->l.left = (node *) NULL;
	}
	d1 = max2(d1, side_end(&n->l.left, side, oldside, olddepth));
	if (d1 == 0) {
	    n->l.left = (node *) NULL;
	}
	oldside = side_start(&side, &olddepth);
	d2 = opt_expr(&n->r.right, pop);
	if (d2 == 0) {
	    n->r.right = (node *) NULL;
	}
	d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth));
	if (d2 == 0) {
	    n->r.right = (node *) NULL;
	}
	return max3(i, d1, d2);

    case N_RANGE:
	d1 = opt_expr(&n->l.left, FALSE);
	d2 = 1;
	if (n->r.right->l.left != (node *) NULL) {
	    d2 = opt_expr(&n->r.right->l.left, FALSE);
	    if ((n->l.left->mod == T_STRING || (n->l.left->mod & T_REF) != 0) &&
		n->r.right->l.left->type == N_INT &&
		n->r.right->l.left->l.number == 0) {
		/*
		 * str[0 .. x] or arr[0 .. x]
		 */
		n->r.right->l.left = (node *) NULL;
		d2 = 1;
	    } else {
		d1 = max2(d1, d2 + 1);
		d2 = 2;
	    }
	}
	if (n->r.right->r.right != (node *) NULL) {
	    d1 = max2(d1, d2 + opt_expr(&n->r.right->r.right, FALSE));
	}
	if (n->l.left->type == N_STR) {
	    long from, to;

	    if (n->r.right->l.left == (node *) NULL) {
		from = 0;
	    } else {
		if (n->r.right->l.left->type != N_INT) {
		    return d1;
		}
		from = n->r.right->l.left->l.number;
	    }
	    if (n->r.right->r.right == (node *) NULL) {
		to = n->l.left->l.string->len - 1;
	    } else {
		if (n->r.right->r.right->type != N_INT) {
		    return d1;
		}
		to = n->r.right->r.right->l.number;
	    }
	    if (from >= 0 && from <= to + 1 &&
		to < (long) n->l.left->l.string->len) {
		node_tostr(n, str_range(n->l.left->l.string, from, to));
		return !pop;
	    }
	    return d1;
	}
	return max2(d1, 3);

    case N_AGGR:
	if (n->mod == T_MAPPING) {
	    n = n->l.left;
	    if (n == (node *) NULL) {
		return 1;
	    }

	    d1 = 0;
	    for (i = 0; n->type == N_PAIR; i += 2) {
		oldside = side_start(&side, &olddepth);
		d2 = opt_expr(&n->l.left->l.left, FALSE);
		d1 = max3(d1, i + d2, i + side_end(&n->l.left->l.left,
						   side, oldside, olddepth));
		oldside = side_start(&side, &olddepth);
		d2 = opt_expr(&n->l.left->r.right, FALSE);
		d1 = max3(d1, i + 1 + d2,
			  i + 1 + side_end(&n->l.left->r.right, side, oldside,
					   olddepth));
		n = n->r.right;
	    }
	    oldside = side_start(&side, &olddepth);
	    d2 = opt_expr(&n->l.left, FALSE);
	    d1 = max3(d1, i + d2,
		      i + side_end(&n->l.left, side, oldside, olddepth));
	    oldside = side_start(&side, &olddepth);
	    d2 = opt_expr(&n->r.right, FALSE);
	    return max3(d1, i + 1 + d2,
			i + 1 + side_end(&n->r.right, side, oldside, olddepth));
	} else {
	    m = &n->l.left;
	    n = *m;
	    if (n == (node *) NULL) {
		return 1;
	    }

	    d1 = 0;
	    for (i = 0; n->type == N_PAIR; i++) {
		oldside = side_start(&side, &olddepth);
		d2 = opt_expr(&n->l.left, FALSE);
		d1 = max3(d1, i + d2,
			  i + side_end(&n->l.left, side, oldside, olddepth));
		m = &n->r.right;
		n = *m;
	    }
	    oldside = side_start(&side, &olddepth);
	    d2 = opt_expr(m, FALSE);
	    return max3(d1, i + d2, i + side_end(m, side, oldside, olddepth));
	}
    }

# ifdef DEBUG
    fatal("unknown expression type %d", n->type);
# endif
    return 0;
}
Beispiel #7
0
/*
 * NAME:	optimize->asgnexp()
 * DESCRIPTION:	optimize an assignment expression
 */
static Uint opt_asgnexp(node **m, bool pop)
{
    node *n, *t;
    Uint d1, d2;

    n = *m;
    d2 = opt_expr(&n->r.right, FALSE);

    if ((n->r.right->type == N_INT || n->r.right->type == N_FLOAT) &&
	n->l.left->mod == n->r.right->mod) {
	switch (n->type) {
	case N_ADD_EQ:
	case N_ADD_EQ_FLOAT:
	    if (NFLT_ISZERO(n->r.right)) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (NFLT_ISONE(n->r.right)) {
		n->type = N_ADD_EQ_1_FLOAT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (NFLT_ISMONE(n->r.right)) {
		n->type = N_SUB_EQ_1_FLOAT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_ADD_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == 1) {
		n->type = N_ADD_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (n->r.right->l.number == -1) {
		n->type = N_SUB_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_AND_EQ_INT:
	    if (n->r.right->l.number == 0) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == -1) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_MULT_EQ:
	case N_MULT_EQ_FLOAT:
	    if (NFLT_ISZERO(n->r.right)) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    /* fall through */
	case N_DIV_EQ:
	case N_DIV_EQ_FLOAT:
	    if (NFLT_ISONE(n->r.right)) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_MULT_EQ_INT:
	    if (n->r.right->l.number == 0) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    /* fall through */
	case N_DIV_EQ_INT:
	    if (n->r.right->l.number == 1) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_LSHIFT_EQ_INT:
	case N_RSHIFT_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_MOD_EQ_INT:
	    if (n->r.right->l.number == 1) {
		n->type = N_ASSIGN;
		n->r.right->l.number = 0;
		return opt_expr(m, pop);
	    }
	    break;

	case N_OR_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == -1) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    break;

	case N_SUB_EQ:
	case N_SUB_EQ_FLOAT:
	    if (NFLT_ISZERO(n->r.right)) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (NFLT_ISONE(n->r.right)) {
		n->type = N_SUB_EQ_1_FLOAT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (NFLT_ISMONE(n->r.right)) {
		n->type = N_ADD_EQ_1_FLOAT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_SUB_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == 1) {
		n->type = N_SUB_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (n->r.right->l.number == -1) {
		n->type = N_ADD_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_XOR_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;
	}
    }

    d1 = opt_lvalue(n->l.left) + 1;

    if (n->type == N_SUM_EQ) {
	d1++;
	return max2(d1, ((d1 < 6) ? d1 : 6) + d2);
    }
    if (n->type == N_ADD_EQ &&
	(n->mod == T_STRING || (n->mod & T_REF) != 0) &&
	(n->r.right->mod == T_STRING || (n->r.right->mod & T_REF) != 0 ||
	 n->r.right->type == N_RANGE)) {
	/*
	 * see if the summand operator can be used
	 */
	switch (n->r.right->type) {
	case N_ADD:
	    n->r.right->type = N_SUM;
	    d2 += 2;				/* SUM_SIMPLE on both sides */
	    if (n->r.right->l.left->type == N_RANGE) {
		d1++;
	    }
	    n->type = N_SUM_EQ;
	    d1++;				/* add SUM_SIMPLE */
	    return max2(d1, ((d1 < 6) ? d1 : 6) + d2);

	case N_AGGR:
	    d2++;				/* add SUM_SIMPLE */
	    n->type = N_SUM_EQ;
	    d1++;				/* add SUM_SIMPLE */
	    return max2(d1, ((d1 < 6) ? d1 : 6) + d2);

	case N_RANGE:
	    d2 = max2(d2, 3);			/* at least 3 */
	    /* fall through */
	case N_SUM:
	    n->type = N_SUM_EQ;
	    d1++;				/* add SUM_SIMPLE */
	    return max2(d1, ((d1 < 6) ? d1 : 6) + d2);

	case N_FUNC:
	    if (n->r.right->r.number == kd_allocate ||
		n->r.right->r.number == kd_allocate_int ||
		n->r.right->r.number == kd_allocate_float) {
		t = n->r.right->l.left->r.right;
		if (t != (node *) NULL && t->type != N_PAIR &&
		    t->type != N_SPREAD && t->mod == T_INT) {
		    d2++;			/* add SUM_ALLOCATE */
		    n->type = N_SUM_EQ;
		    d1++;			/* add SUM_SIMPLE */
		    return max2(d1, ((d1 < 6) ? d1 : 6) + d2);
		}
	    }
	    break;
	}
    }

    return max2(d1, ((d1 < 5) ? d1 : 5) + d2);
}
Beispiel #8
0
static bool
opt_expr (struct predicate **eval_treep)
{
  struct predlist regex_list={NULL,NULL}, name_list={NULL,NULL};
  struct predlist cbo_list[NumEvaluationCosts];
  int i;
  struct predicate *curr;
  struct predicate **prevp;	/* Address of `curr' node. */
  struct predicate **last_sidep; /* Last predicate with side effects. */
  PRED_FUNC pred_func;
  enum predicate_type p_type;
  bool has_side_effects = false; /* Return value. */
  enum predicate_precedence prev_prec, /* precedence of last BI_OP in branch */
			    biop_prec; /* topmost BI_OP precedence in branch */

  if (eval_treep == NULL || *eval_treep == NULL)
    return (false);

  for (i=0; i<NumEvaluationCosts; i++)
    predlist_init (&cbo_list[i]);

  /* Set up to normalize tree as a left-linked list of ANDs or ORs.
     Set `curr' to the leftmost node, `prevp' to its address, and
     `pred_func' to the predicate type of its parent. */
  prevp = eval_treep;
  prev_prec = AND_PREC;
  curr = *prevp;
  while (curr->pred_left != NULL)
    {
      prevp = &curr->pred_left;
      prev_prec = curr->p_prec;	/* must be a BI_OP */
      curr = curr->pred_left;
    }

  /* Link in the appropriate BI_OP for the last expression, if needed. */
  if (curr->p_type != BI_OP)
    set_new_parent (curr, prev_prec, prevp);

  if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
    {
      /* Normalized tree. */
      fprintf (stderr, "Normalized Eval Tree:\n");
      print_tree (stderr, *eval_treep, 0);
    }

  /* Rearrange the predicates. */
  prevp = eval_treep;
  biop_prec = NO_PREC; /* not COMMA_PREC */
  if ((*prevp) && (*prevp)->p_type == BI_OP)
    biop_prec = (*prevp)->p_prec;
  while ((curr = *prevp) != NULL)
    {
      /* If there is a BI_OP of different precedence from the first
	 in the pred_left chain, create a new parent of the
	 original precedence, link the new parent to the left of the
	 previous and link CURR to the right of the new parent.
	 This preserves the precedence of expressions in the tree
	 in case we rearrange them. */
      if (curr->p_type == BI_OP)
	{
          if (curr->p_prec != biop_prec)
	    curr = set_new_parent (curr, biop_prec, prevp);
	}

      /* See which predicate type we have. */
      p_type = curr->pred_right->p_type;
      pred_func = curr->pred_right->pred_func;


      switch (p_type)
	{
	case NO_TYPE:
	case PRIMARY_TYPE:
	  /* Don't rearrange the arguments of the comma operator, it is
	     not commutative.  */
	  if (biop_prec == COMMA_PREC)
	    break;

	  /* If this predicate has no side effects, consider reordering it. */
	  if (!curr->pred_right->side_effects)
	    {
	      bool reorder;

	      /* If it's one of our special primaries, move it to the
		 front of the list for that primary. */
	      if (predicate_is_cost_free (curr->pred_right))
		{
		  if (options.debug_options & DebugTreeOpt)
		    {
		      fprintf (stderr, "-O%d: promoting cheap predicate ",
			       (int)options.optimisation_level);
		      print_predicate (stderr, curr->pred_right);
		      fprintf (stderr, " into name_list\n");
		    }
		  predlist_insert (&name_list, curr, prevp);
		  continue;
		}

	      if (pred_func == pred_regex)
		{
		  predlist_insert (&regex_list, curr, prevp);
		  continue;
		}

	      reorder = ((options.optimisation_level > 1)
			 && (NeedsType == curr->pred_right->p_cost
			     || NeedsInodeNumber == curr->pred_right->p_cost)
			 && !curr->pred_right->need_stat) ||
		(options.optimisation_level > 2);

	      if (reorder)
		{
		  if (options.debug_options & DebugTreeOpt)
		    {
		      fprintf (stderr, "-O%d: categorising predicate ",
			       (int)options.optimisation_level);
		      print_predicate (stderr, curr->pred_right);
		      fprintf (stderr, " by cost (%s)\n",
			       cost_name(curr->pred_right->p_cost));
		    }
		  predlist_insert (&cbo_list[curr->pred_right->p_cost], curr, prevp);
		  continue;
		}
	    }

	  break;

	case UNI_OP:
	  /* For NOT, check the expression trees below the NOT. */
	  curr->pred_right->side_effects
	    = opt_expr (&curr->pred_right->pred_right);
	  break;

	case BI_OP:
	  /* For nested 'AND' or 'OR', recurse (AND/OR form layers on
	     the left of the tree), and continue scanning this level
	     of 'AND' or 'OR'. */
	  curr->pred_right->side_effects = opt_expr (&curr->pred_right);
	  break;

	  /* At this point, get_expr and scan_rest have already removed
	     all of the user's parentheses. */

	default:
	  error (EXIT_FAILURE, 0, _("oops -- invalid expression type!"));
	  break;
	}

      if (curr->pred_right->side_effects == true)
	{
	  last_sidep = prevp;

	  /* Incorporate lists and reset list pointers for this group.  */
	  merge_lists (cbo_list, NumEvaluationCosts, &name_list, &regex_list, last_sidep);
	  has_side_effects = true;
	}

      prevp = &curr->pred_left;
    }

  /* Do final list merges. */
  last_sidep = prevp;
  merge_lists (cbo_list, NumEvaluationCosts, &name_list, &regex_list, last_sidep);
  return has_side_effects;
}
Beispiel #9
0
struct predicate*
build_expression_tree (int argc, char *argv[], int end_of_leading_options)
{
  const struct parser_table *parse_entry; /* Pointer to the parsing table entry for this expression. */
  char *predicate_name;		/* Name of predicate being parsed. */
  struct predicate *cur_pred;
  const struct parser_table *entry_close, *entry_print, *entry_open;
  int i, oldi;

  predicates = NULL;

  /* Find where in ARGV the predicates begin by skipping the list of
   * start points.  As a side effect, also figure out which is the
   * first and last start point.
   */
  start_points = argv + end_of_leading_options;
  for (i = end_of_leading_options; i < argc && !looks_like_expression(argv[i], true); i++)
    {
      ++num_start_points;
    }

  /* Enclose the expression in `( ... )' so a default -print will
     apply to the whole expression. */
  entry_open  = find_parser ("(");
  entry_close = find_parser (")");
  entry_print = find_parser ("print");
  assert (entry_open  != NULL);
  assert (entry_close != NULL);
  assert (entry_print != NULL);

  parse_openparen (entry_open, argv, &argc);
  last_pred->p_name = "(";
  predicates->artificial = true;
  parse_begin_user_args (argv, argc, last_pred, predicates);
  pred_sanity_check (last_pred);

  /* Build the input order list. */
  while (i < argc )
    {
      state.already_issued_stat_error_msg = false;
      if (!looks_like_expression (argv[i], false))
	{
	  error (0, 0, _("paths must precede expression: %s"), argv[i]);
	  usage (stderr, 1, NULL);
	}

      predicate_name = argv[i];
      parse_entry = find_parser (predicate_name);
      if (parse_entry == NULL)
	{
	  /* Command line option not recognized */
	  error (EXIT_FAILURE, 0, _("unknown predicate `%s'"), predicate_name);
	}

      /* We have recognised a test of the form -foo.  Eat that,
       * unless it is a predicate like -newerXY.
       */
      if (parse_entry->type != ARG_SPECIAL_PARSE)
	{
	  i++;
	}
      oldi = i;
      if (!(*(parse_entry->parser_func)) (parse_entry, argv, &i))
	{
	  if (argv[i])
	    {
	      if ( (ARG_SPECIAL_PARSE == parse_entry->type) && (i == oldi) )
		{
		  /* The special parse function spat out the
		   * predicate.  It must be invalid, or not tasty.
		   */
		  error (EXIT_FAILURE, 0, _("invalid predicate `%s'"),
			 predicate_name);
		}
	      else
		{
		  error (EXIT_FAILURE, 0, _("invalid argument `%s' to `%s'"),
			 argv[i], predicate_name);
		}
	    }
	  else
	    {
	      /* Command line option requires an argument */
	      error (EXIT_FAILURE, 0,
		     _("missing argument to `%s'"), predicate_name);
	    }
	}
      else
	{
	  last_pred->p_name = predicate_name;

	  /* If the parser consumed an argument, save it. */
	  if (i != oldi)
	    last_pred->arg_text = argv[oldi];
	  else
	    last_pred->arg_text = NULL;
	}
      pred_sanity_check(last_pred);
      pred_sanity_check(predicates); /* XXX: expensive */
    }
  parse_end_user_args (argv, argc, last_pred, predicates);
  if (predicates->pred_next == NULL)
    {
      /* No predicates that do something other than set a global variable
	 were given; remove the unneeded initial `(' and add `-print'. */
      cur_pred = predicates;
      predicates = last_pred = predicates->pred_next;
      free (cur_pred);
      parse_print (entry_print, argv, &argc);
      last_pred->p_name = "-print";
      pred_sanity_check(last_pred);
      pred_sanity_check(predicates); /* XXX: expensive */
    }
  else if (!default_prints (predicates->pred_next))
    {
      /* One or more predicates that produce output were given;
	 remove the unneeded initial `('. */
      cur_pred = predicates;
      predicates = predicates->pred_next;
      pred_sanity_check (predicates); /* XXX: expensive */
      free (cur_pred);
    }
  else
    {
      /* `( user-supplied-expression ) -print'. */
      parse_closeparen (entry_close, argv, &argc);
      last_pred->p_name = ")";
      last_pred->artificial = true;
      pred_sanity_check (last_pred);
      parse_print (entry_print, argv, &argc);
      last_pred->p_name = "-print";
      last_pred->artificial = true;
      pred_sanity_check (last_pred);
      pred_sanity_check (predicates); /* XXX: expensive */
    }

  if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
    {
      fprintf (stderr, "Predicate List:\n");
      print_list (stderr, predicates);
    }

  /* do a sanity check */
  check_option_combinations (predicates);
  pred_sanity_check (predicates);

  /* Done parsing the predicates.  Build the evaluation tree. */
  cur_pred = predicates;
  eval_tree = get_expr (&cur_pred, NO_PREC, NULL);
  calculate_derived_rates (eval_tree);

  /* Check if we have any left-over predicates (this fixes
   * Debian bug #185202).
   */
  if (cur_pred != NULL)
    {
      /* cur_pred->p_name is often NULL here */
      if (pred_is (cur_pred, pred_closeparen))
	{
	  /* e.g. "find \( -true \) \)" */
	  error (EXIT_FAILURE, 0, _("you have too many ')'"));
	}
      else
	{
	  if (cur_pred->p_name)
	    error (EXIT_FAILURE, 0,
		   _("unexpected extra predicate '%s'"), cur_pred->p_name);
	  else
	    error (EXIT_FAILURE, 0, _("unexpected extra predicate"));
	}
    }

  if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
    {
      fprintf (stderr, "Eval Tree:\n");
      print_tree (stderr, eval_tree, 0);
    }

  estimate_costs (eval_tree);

  /* Rearrange the eval tree in optimal-predicate order. */
  opt_expr (&eval_tree);

  /* Check that the tree is in normalised order (opt_expr does this) */
  check_normalization (eval_tree, true);

  do_arm_swaps (eval_tree);

  /* Check that the tree is still in normalised order */
  check_normalization (eval_tree, true);

  if (options.debug_options & (DebugExpressionTree|DebugTreeOpt))
    {
      fprintf (stderr, "Optimized Eval Tree:\n");
      print_tree (stderr, eval_tree, 0);
      fprintf (stderr, "Optimized command line:\n");
      print_optlist (stderr, eval_tree);
      fprintf (stderr, "\n");
    }

  return eval_tree;
}
Beispiel #10
0
/*
 * NAME:	optimize->asgnexp()
 * DESCRIPTION:	optimize an assignment expression
 */
static Uint opt_asgnexp(node **m, bool pop)
{
    node *n;
    Uint d1, d2;

    n = *m;
    d2 = opt_expr(&n->r.right, FALSE);

    if ((n->r.right->type == N_INT || n->r.right->type == N_FLOAT) &&
	n->l.left->mod == n->r.right->mod) {
	switch (n->type) {
	case N_ADD_EQ:
	    if (NFLT_ISZERO(n->r.right)) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (NFLT_ISONE(n->r.right)) {
		n->type = N_ADD_EQ_1;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (NFLT_ISMONE(n->r.right)) {
		n->type = N_SUB_EQ_1;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_ADD_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == 1) {
		n->type = N_ADD_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (n->r.right->l.number == -1) {
		n->type = N_SUB_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_AND_EQ_INT:
	    if (n->r.right->l.number == 0) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == -1) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_MULT_EQ:
	    if (NFLT_ISZERO(n->r.right)) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    /* fall through */
	case N_DIV_EQ:
	    if (NFLT_ISONE(n->r.right)) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_MULT_EQ_INT:
	    if (n->r.right->l.number == 0) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    /* fall through */
	case N_DIV_EQ_INT:
	    if (n->r.right->l.number == 1) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_LSHIFT_EQ_INT:
	case N_RSHIFT_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;

	case N_MOD_EQ_INT:
	    if (n->r.right->l.number == 1) {
		n->type = N_ASSIGN;
		n->r.right->l.number = 0;
		return opt_expr(m, pop);
	    }
	    break;

	case N_OR_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == -1) {
		n->type = N_ASSIGN;
		return opt_expr(m, pop);
	    }
	    break;

	case N_SUB_EQ:
	    if (NFLT_ISZERO(n->r.right)) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (NFLT_ISONE(n->r.right)) {
		n->type = N_SUB_EQ_1;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (NFLT_ISMONE(n->r.right)) {
		n->type = N_ADD_EQ_1;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_SUB_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    if (n->r.right->l.number == 1) {
		n->type = N_SUB_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    if (n->r.right->l.number == -1) {
		n->type = N_ADD_EQ_1_INT;
		return opt_lvalue(n->l.left) + 1;
	    }
	    break;

	case N_XOR_EQ_INT:
	    if (n->r.right->l.number == 0) {
		*m = n->l.left;
		return opt_expr(m, pop);
	    }
	    break;
	}
    }

    d1 = opt_lvalue(n->l.left) + 1;

    if (n->type == N_SUM_EQ) {
	d1++;
	return max2(d1, ((d1 < 5) ? d1 : 5) + d2);
    }
    if (n->type == N_ADD_EQ &&
	(n->mod == T_STRING || (n->mod & T_REF) != 0) &&
	(n->r.right->mod == T_STRING || (n->r.right->mod & T_REF) != 0 ||
	 n->r.right->type == N_RANGE)) {
	/*
	 * see if the summand operator can be used
	 */
	switch (n->r.right->type) {
	case N_ADD:
	    n->r.right->type = N_SUM;
	    d2 += 2;				/* (-2) on both sides */
	    if (n->r.right->l.left->type == N_RANGE) {
		d1++;
	    }
	    n->type = N_SUM_EQ;
	    d1++;				/* add (-2) */
	    return max2(d1, ((d1 < 5) ? d1 : 5) + d2);

	case N_AGGR:
	    d2++;				/* add (-2) */
	    n->type = N_SUM_EQ;
	    d1++;				/* add (-2) */
	    return max2(d1, ((d1 < 5) ? d1 : 5) + d2);

	case N_RANGE:
	    d2 = max2(d2, 3);			/* at least 3 */
	    /* fall through */
	case N_SUM:
	    n->type = N_SUM_EQ;
	    d1++;				/* add (-2) */
	    return max2(d1, ((d1 < 5) ? d1 : 5) + d2);
	}
    }

    return max2(d1, ((d1 < 4) ? d1 : 4) + d2);
}