Index: rtlanal.c =================================================================== --- rtlanal.c (revision 196633) +++ rtlanal.c (working copy) @@ -3076,21 +3076,21 @@ regno_use_in (unsigned int regno, rtx x) return NULL_RTX; } /* Return a value indicating whether OP, an operand of a commutative operation, is preferred as the first or second operand. The higher the value, the stronger the preference for being the first operand. We use negative values to indicate a preference for the first operand and positive values for the second operand. */ -int +static int commutative_operand_precedence (rtx op) { enum rtx_code code = GET_CODE (op); /* Constants always come the second operand. Prefer "nice" constants. */ if (code == CONST_INT) return -8; if (code == CONST_DOUBLE) return -7; if (code == CONST_FIXED) @@ -3138,28 +3138,43 @@ commutative_operand_precedence (rtx op) case RTX_UNARY: /* Then prefer NEG and NOT. */ if (code == NEG || code == NOT) return 1; default: return 0; } } +/* Return < 0 if it is necessary to swap operands of commutative operation + in order to canonicalize expression, > 0 if it is wrong to swap the + operands, and 0 if we don't know. */ + +int +compare_commutative_operands_precedence (rtx x, rtx y) +{ + int px = commutative_operand_precedence (x); + int py = commutative_operand_precedence (y); + if (px != py) + return px - py; + + /* Use some arbitrary order to avoid pattern explosion. */ + return (int) GET_CODE (x) - (int) GET_CODE (y); +} + /* Return 1 iff it is necessary to swap operands of commutative operation in order to canonicalize expression. */ bool swap_commutative_operands_p (rtx x, rtx y) { - return (commutative_operand_precedence (x) - < commutative_operand_precedence (y)); + return compare_commutative_operands_precedence (x, y) < 0; } /* Return 1 if X is an autoincrement side effect and the register is not the stack pointer. */ int auto_inc_p (const_rtx x) { switch (GET_CODE (x)) { case PRE_INC: Index: optabs.c =================================================================== --- optabs.c (revision 196633) +++ optabs.c (working copy) @@ -1285,33 +1285,29 @@ expand_simple_binop (enum machine_mode m rtx op1, rtx target, int unsignedp, enum optab_methods methods) { optab binop = code_to_optab (code); gcc_assert (binop); return expand_binop (mode, binop, op0, op1, target, unsignedp, methods); } /* Return whether OP0 and OP1 should be swapped when expanding a commutative - binop. Order them according to commutative_operand_precedence and, if - possible, try to put TARGET or a pseudo first. */ + binop. Order them according to compare_commutative_operands_precedence and, + if possible, try to put TARGET or a pseudo first. */ static bool swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1) { - int op0_prec = commutative_operand_precedence (op0); - int op1_prec = commutative_operand_precedence (op1); + int cmp = compare_commutative_operands_precedence (op0, op1); - if (op0_prec < op1_prec) - return true; - - if (op0_prec > op1_prec) - return false; + if (cmp != 0) + return cmp < 0; /* With equal precedence, both orders are ok, but it is better if the first operand is TARGET, or if both TARGET and OP0 are pseudos. */ if (target == 0 || REG_P (target)) return (REG_P (op1) && !REG_P (op0)) || target == op1; else return rtx_equal_p (op1, target); } /* Return true if BINOPTAB implements a shift operation. */ Index: simplify-rtx.c =================================================================== --- simplify-rtx.c (revision 196633) +++ simplify-rtx.c (working copy) @@ -2076,22 +2076,24 @@ simplify_associative_operation (enum rtx if (! swap_commutative_operands_p (op1, op0)) return simplify_gen_binary (code, mode, op1, op0); tem = op0; op0 = op1; op1 = tem; } if (GET_CODE (op0) == code) { - /* Canonicalize "(x op c) op y" as "(x op y) op c". */ - if (swap_commutative_operands_p (XEXP (op0, 1), op1)) + /* Canonicalize "(x op c) op y" as "(x op y) op c". + GET_CODE != code is here to avoid an infinite recursion. */ + if (GET_CODE (XEXP (op0, 1)) != code + && swap_commutative_operands_p (XEXP (op0, 1), op1)) { tem = simplify_gen_binary (code, mode, XEXP (op0, 0), op1); return simplify_gen_binary (code, mode, tem, XEXP (op0, 1)); } /* Attempt to simplify "(a op b) op c" as "a op (b op c)". */ tem = simplify_binary_operation (code, mode, XEXP (op0, 1), op1); if (tem != 0) return simplify_gen_binary (code, mode, XEXP (op0, 0), tem); @@ -4158,26 +4160,24 @@ simplify_const_binary_operation (enum rt struct simplify_plus_minus_op_data { rtx op; short neg; }; static bool simplify_plus_minus_op_data_cmp (rtx x, rtx y) { - int result; + int result = compare_commutative_operands_precedence (x, y); - result = (commutative_operand_precedence (y) - - commutative_operand_precedence (x)); if (result) - return result > 0; + return result < 0; /* Group together equal REGs to do more simplification. */ if (REG_P (x) && REG_P (y)) return REGNO (x) > REGNO (y); else return false; } static rtx simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, Index: rtl.h =================================================================== --- rtl.h (revision 196633) +++ rtl.h (working copy) @@ -2015,21 +2015,21 @@ extern rtx get_call_rtx_from (rtx); extern HOST_WIDE_INT get_integer_term (const_rtx); extern rtx get_related_value (const_rtx); extern bool offset_within_block_p (const_rtx, HOST_WIDE_INT); extern void split_const (rtx, rtx *, rtx *); extern bool unsigned_reg_p (rtx); extern int reg_mentioned_p (const_rtx, const_rtx); extern int count_occurrences (const_rtx, const_rtx, int); extern int reg_referenced_p (const_rtx, const_rtx); extern int reg_used_between_p (const_rtx, const_rtx, const_rtx); extern int reg_set_between_p (const_rtx, const_rtx, const_rtx); -extern int commutative_operand_precedence (rtx); +extern int compare_commutative_operands_precedence (rtx, rtx); extern bool swap_commutative_operands_p (rtx, rtx); extern int modified_between_p (const_rtx, const_rtx, const_rtx); extern int no_labels_between_p (const_rtx, const_rtx); extern int modified_in_p (const_rtx, const_rtx); extern int reg_set_p (const_rtx, const_rtx); extern rtx single_set_2 (const_rtx, const_rtx); extern int multiple_sets (const_rtx); extern int set_noop_p (const_rtx); extern int noop_move_p (const_rtx); extern rtx find_last_value (rtx, rtx *, rtx, int);