diff options
Diffstat (limited to 'gcc/simplify-rtx.c')
-rw-r--r-- | gcc/simplify-rtx.c | 104 |
1 files changed, 63 insertions, 41 deletions
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 521fecf566e..ca8310d1556 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -59,7 +59,6 @@ along with GCC; see the file COPYING3. If not see static rtx neg_const_int (machine_mode, const_rtx); static bool plus_minus_operand_p (const_rtx); -static bool simplify_plus_minus_op_data_cmp (rtx, rtx); static rtx simplify_plus_minus (enum rtx_code, machine_mode, rtx, rtx); static rtx simplify_immed_subreg (machine_mode, rtx, machine_mode, unsigned int); @@ -4049,20 +4048,10 @@ simplify_const_binary_operation (enum rtx_code code, machine_mode mode, -/* Simplify a PLUS or MINUS, at least one of whose operands may be another - PLUS or MINUS. +/* Return a positive integer if X should sort after Y. The value + returned is 1 if and only if X and Y are both regs. */ - 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. */ - -struct simplify_plus_minus_op_data -{ - rtx op; - short neg; -}; - -static bool +static int simplify_plus_minus_op_data_cmp (rtx x, rtx y) { int result; @@ -4070,20 +4059,33 @@ simplify_plus_minus_op_data_cmp (rtx x, rtx y) result = (commutative_operand_precedence (y) - commutative_operand_precedence (x)); if (result) - return result > 0; + return result + result; /* Group together equal REGs to do more simplification. */ if (REG_P (x) && REG_P (y)) return REGNO (x) > REGNO (y); - else - return false; + + return 0; } +/* Simplify and canonicalize 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. + + May return NULL_RTX when no changes were made. */ + static rtx simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, rtx op1) { - struct simplify_plus_minus_op_data ops[16]; + struct simplify_plus_minus_op_data + { + rtx op; + short neg; + } ops[16]; rtx result, tem; int n_ops = 2; int changed, n_constants, canonicalized = 0; @@ -4124,7 +4126,18 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, ops[i].op = XEXP (this_op, 0); changed = 1; - canonicalized |= this_neg || i != n_ops - 2; + /* If this operand was negated then we will potentially + canonicalize the expression. Similarly if we don't + place the operands adjacent we're re-ordering the + expression and thus might be performing a + canonicalization. Ignore register re-ordering. + ??? It might be better to shuffle the ops array here, + but then (plus (plus (A, B), plus (C, D))) wouldn't + be seen as non-canonical. */ + if (this_neg + || (i != n_ops - 2 + && !(REG_P (ops[i].op) && REG_P (ops[n_ops - 1].op)))) + canonicalized = 1; break; case NEG: @@ -4145,7 +4158,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, ops[n_ops].neg = this_neg; n_ops++; changed = 1; - canonicalized = 1; + canonicalized = 1; } break; @@ -4158,7 +4171,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, ops[i].op = XEXP (this_op, 0); ops[i].neg = !this_neg; changed = 1; - canonicalized = 1; + canonicalized = 1; } break; @@ -4169,7 +4182,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, ops[i].op = neg_const_int (mode, this_op); ops[i].neg = 0; changed = 1; - canonicalized = 1; + canonicalized = 1; } break; @@ -4213,23 +4226,29 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, } /* Now simplify each pair of operands until nothing changes. */ - do + while (1) { /* Insertion sort is good enough for a small array. */ for (i = 1; i < n_ops; i++) - { - struct simplify_plus_minus_op_data save; - j = i - 1; - if (!simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op)) + { + struct simplify_plus_minus_op_data save; + int cmp; + + j = i - 1; + cmp = simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op); + if (cmp <= 0) continue; + /* Just swapping registers doesn't count as canonicalization. */ + if (cmp != 1) + canonicalized = 1; - canonicalized = 1; - save = ops[i]; - do + save = ops[i]; + do ops[j + 1] = ops[j]; - while (j-- && simplify_plus_minus_op_data_cmp (ops[j].op, save.op)); - ops[j + 1] = save; - } + while (j-- + && simplify_plus_minus_op_data_cmp (ops[j].op, save.op) > 0); + ops[j + 1] = save; + } changed = 0; for (i = n_ops - 1; i > 0; i--) @@ -4258,7 +4277,8 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs; tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs; - tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs); + tem = simplify_binary_operation (ncode, mode, tem_lhs, + tem_rhs); if (tem && !CONSTANT_P (tem)) tem = gen_rtx_CONST (GET_MODE (tem), tem); @@ -4296,20 +4316,22 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, } } - /* If nothing changed, fail. */ - if (!canonicalized) - return NULL_RTX; + if (!changed) + break; /* Pack all the operands to the lower-numbered entries. */ for (i = 0, j = 0; j < n_ops; j++) - if (ops[j].op) - { + if (ops[j].op) + { ops[i] = ops[j]; i++; - } + } n_ops = i; } - while (changed); + + /* If nothing changed, fail. */ + if (!canonicalized) + return NULL_RTX; /* Create (minus -C X) instead of (neg (const (plus X C))). */ if (n_ops == 2 |