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);
