From 96b0e48171bd78e46cef4bd5d6caf4385e603f66 Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Mon, 8 Mar 1993 16:57:16 -0500 Subject: [PATCH] (cse_gen_binary, simplify_plus_minus): New functions. (find_best_addr): Use cse_gen_binary. (simplify_binary_operation, fold_rtx): Likewise. Remove most special-cases for PLUS and MINUS and call simplify_plus_minus instead. Clean up some tests for FP. From-SVN: r3680 --- gcc/cse.c | 464 +++++++++++++++++++++++++++++------------------------- 1 file changed, 249 insertions(+), 215 deletions(-) diff --git a/gcc/cse.c b/gcc/cse.c index 51f8887f38d..e2bb7ae1456 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -612,6 +612,10 @@ static void find_best_addr PROTO((rtx, rtx *)); static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *, enum machine_mode *, enum machine_mode *)); +static rtx cse_gen_binary PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); +static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); static rtx fold_rtx PROTO((rtx, rtx)); static rtx equiv_constant PROTO((rtx)); static void record_jump_equiv PROTO((rtx, int)); @@ -2649,11 +2653,7 @@ find_best_addr (insn, loc) && (GET_CODE (p->exp) == REG || exp_equiv_p (p->exp, p->exp, 1, 0))) { - rtx new = simplify_binary_operation (GET_CODE (*loc), Pmode, - p->exp, c); - - if (new == 0) - new = gen_rtx (GET_CODE (*loc), Pmode, p->exp, c); + rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c); if ((ADDRESS_COST (new) < best_addr_cost || (ADDRESS_COST (new) == best_addr_cost @@ -3248,6 +3248,7 @@ simplify_binary_operation (code, mode, op0, op1) register HOST_WIDE_INT arg0, arg1, arg0s, arg1s; HOST_WIDE_INT val; int width = GET_MODE_BITSIZE (mode); + rtx tem; /* Relational operations don't work here. We must know the mode of the operands in order to do the comparison correctly. @@ -3448,85 +3449,33 @@ simplify_binary_operation (code, mode, op0, op1) if (op1 == CONST0_RTX (mode)) return op0; - /* Strip off any surrounding CONSTs. They don't matter in any of - the cases below. */ - if (GET_CODE (op0) == CONST) - op0 = XEXP (op0, 0); - if (GET_CODE (op1) == CONST) - op1 = XEXP (op1, 0); - /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */ if (GET_CODE (op0) == NEG) - { - rtx tem = simplify_binary_operation (MINUS, mode, - op1, XEXP (op0, 0)); - return tem ? tem : gen_rtx (MINUS, mode, op1, XEXP (op0, 0)); - } + return cse_gen_binary (MINUS, mode, op1, XEXP (op0, 0)); else if (GET_CODE (op1) == NEG) - { - rtx tem = simplify_binary_operation (MINUS, mode, - op0, XEXP (op1, 0)); - return tem ? tem : gen_rtx (MINUS, mode, op0, XEXP (op1, 0)); - } - - /* Don't use the associative law for floating point. - The inaccuracy makes it nonassociative, - and subtle programs can break if operations are associated. */ - if (GET_MODE_CLASS (mode) != MODE_INT) - break; - - /* (a - b) + b -> a, similarly a + (b - a) -> a */ - if (GET_CODE (op0) == MINUS - && rtx_equal_p (XEXP (op0, 1), op1) && ! side_effects_p (op1)) - return XEXP (op0, 0); + return cse_gen_binary (MINUS, mode, op0, XEXP (op1, 0)); - if (GET_CODE (op1) == MINUS - && rtx_equal_p (XEXP (op1, 1), op0) && ! side_effects_p (op0)) - return XEXP (op1, 0); + /* Handle both-operands-constant cases. We can only add + CONST_INTs to constants since the sum of relocatable symbols + can't be handled by most assemblers. */ - /* (c1 - a) + c2 becomes (c1 + c2) - a. */ - if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == MINUS - && GET_CODE (XEXP (op0, 0)) == CONST_INT) - { - rtx tem = simplify_binary_operation (PLUS, mode, op1, - XEXP (op0, 0)); + if (CONSTANT_P (op0) && GET_CODE (op1) == CONST_INT) + return plus_constant (op0, INTVAL (op1)); + else if (CONSTANT_P (op1) && GET_CODE (op0) == CONST_INT) + return plus_constant (op1, INTVAL (op0)); - return tem ? gen_rtx (MINUS, mode, tem, XEXP (op0, 1)) : 0; - } + /* If one of the operands is a PLUS or a MINUS, see if we can + simplify this by the associative law. + Don't use the associative law for floating point. + The inaccuracy makes it nonassociative, + and subtle programs can break if operations are associated. */ - /* Handle both-operands-constant cases. */ - if (CONSTANT_P (op0) && CONSTANT_P (op1) - && GET_CODE (op0) != CONST_DOUBLE - && GET_CODE (op1) != CONST_DOUBLE - && GET_MODE_CLASS (mode) == MODE_INT) - { - if (GET_CODE (op1) == CONST_INT) - return plus_constant (op0, INTVAL (op1)); - else if (GET_CODE (op0) == CONST_INT) - return plus_constant (op1, INTVAL (op0)); - else - break; -#if 0 /* No good, because this can produce the sum of two relocatable - symbols, in an assembler instruction. Most UNIX assemblers can't - handle that. */ - else - return gen_rtx (CONST, mode, - gen_rtx (PLUS, mode, - GET_CODE (op0) == CONST - ? XEXP (op0, 0) : op0, - GET_CODE (op1) == CONST - ? XEXP (op1, 0) : op1)); -#endif - } - else if (GET_CODE (op1) == CONST_INT - && GET_CODE (op0) == PLUS - && (CONSTANT_P (XEXP (op0, 0)) - || CONSTANT_P (XEXP (op0, 1)))) - /* constant + (variable + constant) - can result if an index register is made constant. - We simplify this by adding the constants. - If we did not, it would become an invalid address. */ - return plus_constant (op0, INTVAL (op1)); + if ((GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS + || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS) + && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0) + return tem; break; case COMPARE: @@ -3550,159 +3499,45 @@ simplify_binary_operation (code, mode, op0, op1) /* None of these optimizations can be done for IEEE floating point. */ if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT - && GET_MODE_CLASS (mode) != MODE_INT) + && GET_MODE_CLASS (mode) != MODE_INT + && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) break; /* We can't assume x-x is 0 even with non-IEEE floating point. */ if (rtx_equal_p (op0, op1) && ! side_effects_p (op0) - && GET_MODE_CLASS (mode) != MODE_FLOAT) + && GET_MODE_CLASS (mode) != MODE_FLOAT + && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) return const0_rtx; /* Change subtraction from zero into negation. */ if (op0 == CONST0_RTX (mode)) return gen_rtx (NEG, mode, op1); + /* (-1 - a) is ~a. */ + if (op0 == constm1_rtx) + return gen_rtx (NOT, mode, op1); + /* Subtracting 0 has no effect. */ if (op1 == CONST0_RTX (mode)) return op0; - /* Strip off any surrounding CONSTs. They don't matter in any of - the cases below. */ - if (GET_CODE (op0) == CONST) - op0 = XEXP (op0, 0); - if (GET_CODE (op1) == CONST) - op1 = XEXP (op1, 0); - /* (a - (-b)) -> (a + b). */ if (GET_CODE (op1) == NEG) - { - rtx tem = simplify_binary_operation (PLUS, mode, - op0, XEXP (op1, 0)); - return tem ? tem : gen_rtx (PLUS, mode, op0, XEXP (op1, 0)); - } + return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 0)); - /* Don't use the associative law for floating point. + /* If one of the operands is a PLUS or a MINUS, see if we can + simplify this by the associative law. + Don't use the associative law for floating point. The inaccuracy makes it nonassociative, and subtle programs can break if operations are associated. */ - if (GET_MODE_CLASS (mode) != MODE_INT) - break; - /* (a + b) - a -> b, and (b - (a + b)) -> -a */ - if (GET_CODE (op0) == PLUS - && rtx_equal_p (XEXP (op0, 0), op1) - && ! side_effects_p (op1)) - return XEXP (op0, 1); - else if (GET_CODE (op0) == PLUS - && rtx_equal_p (XEXP (op0, 1), op1) - && ! side_effects_p (op1)) - return XEXP (op0, 0); - - if (GET_CODE (op1) == PLUS - && rtx_equal_p (XEXP (op1, 0), op0) - && ! side_effects_p (op0)) - { - rtx tem = simplify_unary_operation (NEG, mode, XEXP (op1, 1), - mode); - - return tem ? tem : gen_rtx (NEG, mode, XEXP (op1, 1)); - } - else if (GET_CODE (op1) == PLUS - && rtx_equal_p (XEXP (op1, 1), op0) - && ! side_effects_p (op0)) - { - rtx tem = simplify_unary_operation (NEG, mode, XEXP (op1, 0), - mode); - - return tem ? tem : gen_rtx (NEG, mode, XEXP (op1, 0)); - } - - /* a - (a - b) -> b */ - if (GET_CODE (op1) == MINUS && rtx_equal_p (op0, XEXP (op1, 0)) - && ! side_effects_p (op0)) - return XEXP (op1, 1); - - /* (a +/- b) - (a +/- c) can be simplified. Do variants of - this involving commutativity. The most common case is - (a + C1) - (a + C2), but it's not hard to do all the cases. */ - if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS) - && (GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)) - { - rtx lhs0 = XEXP (op0, 0), lhs1 = XEXP (op0, 1); - rtx rhs0 = XEXP (op1, 0), rhs1 = XEXP (op1, 1); - int lhs_neg = GET_CODE (op0) == MINUS; - int rhs_neg = GET_CODE (op1) == MINUS; - rtx lhs = 0, rhs = 0; - - /* Set LHS and RHS to the two different terms. */ - if (rtx_equal_p (lhs0, rhs0) && ! side_effects_p (lhs0)) - lhs = lhs1, rhs = rhs1; - else if (! rhs_neg && rtx_equal_p (lhs0, rhs1) - && ! side_effects_p (lhs0)) - lhs = lhs1, rhs = rhs0; - else if (! lhs_neg && rtx_equal_p (lhs1, rhs0) - && ! side_effects_p (lhs1)) - lhs = lhs0, rhs = rhs1; - else if (! lhs_neg && ! rhs_neg && rtx_equal_p (lhs1, rhs1) - && ! side_effects_p (lhs1)) - lhs = lhs0, rhs = rhs0; - - /* The RHS is the operand of a MINUS, so its negation - status should be complemented. */ - rhs_neg = ! rhs_neg; - - /* If we found two values equal, form the sum or difference - of the remaining two terms. */ - if (lhs) - { - rtx tem = simplify_binary_operation (lhs_neg == rhs_neg - ? PLUS : MINUS, - mode, - lhs_neg ? rhs : lhs, - lhs_neg ? lhs : rhs); - if (tem == 0) - tem = gen_rtx (lhs_neg == rhs_neg - ? PLUS : MINUS, - mode, lhs_neg ? rhs : lhs, - lhs_neg ? lhs : rhs); - - /* If both sides negated, negate result. */ - if (lhs_neg && rhs_neg) - { - rtx tem1 - = simplify_unary_operation (NEG, mode, tem, mode); - if (tem1 == 0) - tem1 = gen_rtx (NEG, mode, tem); - tem = tem1; - } - - return tem; - } - - return 0; - } - - /* c1 - (a + c2) becomes (c1 - c2) - a. */ - if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == PLUS - && GET_CODE (XEXP (op1, 1)) == CONST_INT) - { - rtx tem = simplify_binary_operation (MINUS, mode, op0, - XEXP (op1, 1)); - - return tem ? gen_rtx (MINUS, mode, tem, XEXP (op1, 0)) : 0; - } - - /* c1 - (c2 - a) becomes (c1 - c2) + a. */ - if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == MINUS - && GET_CODE (XEXP (op1, 0)) == CONST_INT) - { - rtx tem = simplify_binary_operation (MINUS, mode, op0, - XEXP (op1, 0)); - - return (tem && GET_CODE (tem) == CONST_INT - ? plus_constant (XEXP (op1, 1), INTVAL (tem)) - : 0); - } + if ((GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS + || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS) + && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0) + return tem; /* Don't let a relocatable value get a negative coeff. */ if (GET_CODE (op1) == CONST_INT) @@ -3712,7 +3547,7 @@ simplify_binary_operation (code, mode, op0, op1) case MULT: if (op1 == constm1_rtx) { - rtx tem = simplify_unary_operation (NEG, mode, op0, mode); + tem = simplify_unary_operation (NEG, mode, op0, mode); return tem ? tem : gen_rtx (NEG, mode, op0); } @@ -4092,6 +3927,209 @@ simplify_binary_operation (code, mode, op0, op1) return GEN_INT (val); } +/* Simplify a PLUS or MINUS, at least one of whose operands may be another + PLUS or MINUS. + + Rather than test for specific case, we do this by a brute-force method + and do all possible simplifications until no more changes occur. Then + we rebuild the operation. */ + +static rtx +simplify_plus_minus (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + rtx ops[8]; + int negs[8]; + rtx result, tem; + int n_ops = 2; + int i, j; + int first = 1, negate = 0, changed; + + bzero (ops, sizeof ops); + + /* Set up the two operands and then expand them until nothing has been + changed. If we run out of room in our array, give up; this should + almost never happen. */ + + ops[0] = op0, ops[1] = op1, negs[0] = 0, negs[1] = (code == MINUS); + + changed = 1; + while (changed) + { + changed = 0; + + for (i = 0; i < n_ops; i++) + switch (GET_CODE (ops[i])) + { + case PLUS: + case MINUS: + if (n_ops == 7) + return 0; + + ops[n_ops] = XEXP (ops[i], 1); + negs[n_ops++] = GET_CODE (ops[i]) == MINUS ? !negs[i] : negs[i]; + ops[i] = XEXP (ops[i], 0); + changed = 1; + break; + + case NEG: + ops[i] = XEXP (ops[i], 0); + negs[i] = ! negs[i]; + changed = 1; + break; + + case CONST: + ops[i] = XEXP (ops[i], 0); + changed = 1; + break; + + case NOT: + /* ~a -> (-a - 1) */ + if (n_ops != 7) + { + ops[n_ops] = constm1_rtx; + negs[n_ops++] = ! negs[i]; + ops[i] = XEXP (ops[i], 0); + negs[i] = ! negs[i]; + changed = 1; + } + break; + + case CONST_INT: + if (negs[i]) + ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1; + break; + } + } + + /* If we only have two operands, we can't do anything. */ + if (n_ops <= 2) + return 0; + + /* Now simplify each pair of operands until nothing changes. The first + time through just simplify constants against each other. */ + + changed = 1; + while (changed) + { + changed = first; + + for (i = 0; i < n_ops - 1; i++) + for (j = i + 1; j < n_ops; j++) + if (ops[i] != 0 && ops[j] != 0 + && (! first || (CONSTANT_P (ops[i]) && CONSTANT_P (ops[j])))) + { + rtx lhs = ops[i], rhs = ops[j]; + enum rtx_code ncode = PLUS; + + if (negs[i] && ! negs[j]) + lhs = ops[j], rhs = ops[i], ncode = MINUS; + else if (! negs[i] && negs[j]) + ncode = MINUS; + + tem = simplify_binary_operation (ncode, mode, lhs, rhs); + if (tem) + { + ops[i] = tem, ops[j] = 0; + negs[i] = negs[i] && negs[j]; + if (GET_CODE (tem) == NEG) + ops[i] = XEXP (tem, 0), negs[i] = ! negs[i]; + + if (GET_CODE (ops[i]) == CONST_INT && negs[i]) + ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0; + changed = 1; + } + } + + first = 0; + } + + /* Pack all the operands to the lower-numbered entries and give up if + we didn't reduce the number of operands we had. */ + for (i = 0, j = 0; j < n_ops; j++) + if (ops[j] != 0) + ops[i] = ops[j], negs[i++] = negs[j]; + + if (i >= n_ops) + return 0; + + n_ops = i; + + /* If we have a CONST_INT, put it last. */ + for (i = 0; i < n_ops - 1; i++) + if (GET_CODE (ops[i]) == CONST_INT) + { + tem = ops[n_ops - 1], ops[n_ops - 1] = ops[i] , ops[i] = tem; + j = negs[n_ops - 1], negs[n_ops - 1] = negs[i], negs[i] = j; + } + + /* Put a non-negated operand first. If there aren't any, make all + operands positive and negate the whole thing later. */ + for (i = 0; i < n_ops && negs[i]; i++) + ; + + if (i == n_ops) + { + for (i = 0; i < n_ops; i++) + negs[i] = 0; + negate = 1; + } + else if (i != 0) + { + tem = ops[0], ops[0] = ops[i], ops[i] = tem; + j = negs[0], negs[0] = negs[i], negs[i] = j; + } + + /* Now make the result by performing the requested operations. */ + result = ops[0]; + for (i = 1; i < n_ops; i++) + result = cse_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]); + + return negate ? gen_rtx (NEG, mode, result) : result; +} + +/* Make a binary operation by properly ordering the operands and + seeing if the expression folds. */ + +static rtx +cse_gen_binary (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + rtx tem; + + /* Put complex operands first and constants second if commutative. */ + if (GET_RTX_CLASS (code) == 'c' + && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT) + || (GET_RTX_CLASS (GET_CODE (op0)) == 'o' + && GET_RTX_CLASS (GET_CODE (op1)) != 'o') + || (GET_CODE (op0) == SUBREG + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o' + && GET_RTX_CLASS (GET_CODE (op1)) != 'o'))) + tem = op0, op0 = op1, op1 = tem; + + /* If this simplifies, do it. */ + tem = simplify_binary_operation (code, mode, op0, op1); + + if (tem) + return tem; + + /* Handle addition and subtraction of CONST_INT specially. Otherwise, + just form the operation. */ + + if (code == PLUS && GET_CODE (op1) == CONST_INT + && GET_MODE (op0) != VOIDmode) + return plus_constant (op0, INTVAL (op1)); + else if (code == MINUS && GET_CODE (op1) == CONST_INT + && GET_MODE (op0) != VOIDmode) + return plus_constant (op0, - INTVAL (op1)); + else + return gen_rtx (code, mode, op0, op1); +} + /* Like simplify_binary_operation except used for relational operators. MODE is the mode of the operands, not that of the result. */ @@ -5241,11 +5279,7 @@ fold_rtx (x, insn) if (! reg_mentioned_p (folded_arg0, y)) y = fold_rtx (y, insn); - new = simplify_binary_operation (code, mode, y, new_const); - if (new) - return new; - - return gen_rtx (code, mode, y, new_const); + return cse_gen_binary (code, mode, y, new_const); } } -- 2.30.2