OSDN Git Service

Use ISO C90 prototypes.
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 3b85767..aa16af8 100644 (file)
@@ -53,6 +53,9 @@ static rtx neg_const_int (enum machine_mode, rtx);
 static int simplify_plus_minus_op_data_cmp (const void *, const void *);
 static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx,
                                rtx, int);
+static bool associative_constant_p (rtx);
+static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
+                                          rtx, rtx);
 \f
 /* Negate a CONST_INT rtx, truncating (because a conversion from a
    maximally negative number can overflow).  */
@@ -127,7 +130,7 @@ avoid_constant_pool_reference (rtx x)
 
   addr = XEXP (x, 0);
 
-  /* Call target hook to avoid the effects of -fpic etc...  */
+  /* Call target hook to avoid the effects of -fpic etc....  */
   addr = (*targetm.delegitimize_address) (addr);
 
   if (GET_CODE (addr) == LO_SUM)
@@ -646,24 +649,23 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
 
        case CLZ:
          hv = 0;
-         if (h1 == 0)
-           lv = GET_MODE_BITSIZE (mode) - floor_log2 (l1) - 1;
-         else
+         if (h1 != 0)
            lv = GET_MODE_BITSIZE (mode) - floor_log2 (h1) - 1
              - HOST_BITS_PER_WIDE_INT;
+         else if (l1 != 0)
+           lv = GET_MODE_BITSIZE (mode) - floor_log2 (l1) - 1;
+         else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, lv))
+           lv = GET_MODE_BITSIZE (mode);
          break;
 
        case CTZ:
          hv = 0;
-         if (l1 == 0)
-           {
-             if (h1 == 0)
-               lv = GET_MODE_BITSIZE (mode);
-             else
-               lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1);
-           }
-         else
+         if (l1 != 0)
            lv = exact_log2 (l1 & -l1);
+         else if (h1 != 0)
+           lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1);
+         else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, lv))
+           lv = GET_MODE_BITSIZE (mode);
          break;
 
        case POPCOUNT:
@@ -786,6 +788,8 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
   else
     {
       enum rtx_code reversed;
+      rtx temp;
+
       /* There are some simplifications we can do even if the operands
         aren't constant.  */
       switch (code)
@@ -799,14 +803,116 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
          if (mode == BImode && GET_RTX_CLASS (GET_CODE (op)) == '<'
              && ((reversed = reversed_comparison_code (op, NULL_RTX))
                  != UNKNOWN))
-           return gen_rtx_fmt_ee (reversed,
-                                  op_mode, XEXP (op, 0), XEXP (op, 1));
+           return simplify_gen_relational (reversed, op_mode, op_mode,
+                                           XEXP (op, 0), XEXP (op, 1));
+
+          /* (not (plus X -1)) can become (neg X).  */
+          if (GET_CODE (op) == PLUS
+             && XEXP (op, 1) == constm1_rtx)
+           return simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
+
+         /* Similarly, (not (neg X)) is (plus X -1).  */
+         if (GET_CODE (op) == NEG)
+           return plus_constant (XEXP (op, 0), -1);
+
+         /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
+         if (GET_CODE (op) == XOR
+             && GET_CODE (XEXP (op, 1)) == CONST_INT
+             && (temp = simplify_unary_operation (NOT, mode,
+                                                  XEXP (op, 1),
+                                                  mode)) != 0)
+           return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
+
+
+         /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for
+            operands other than 1, but that is not valid.  We could do a
+            similar simplification for (not (lshiftrt C X)) where C is
+            just the sign bit, but this doesn't seem common enough to
+            bother with.  */
+         if (GET_CODE (op) == ASHIFT
+             && XEXP (op, 0) == const1_rtx)
+           {
+             temp = simplify_gen_unary (NOT, mode, const1_rtx, mode);
+             return simplify_gen_binary (ROTATE, mode, temp, XEXP (op, 1));
+           }
+
+         /* If STORE_FLAG_VALUE is -1, (not (comparison X Y)) can be done
+            by reversing the comparison code if valid.  */
+         if (STORE_FLAG_VALUE == -1
+             && GET_RTX_CLASS (GET_CODE (op)) == '<'
+             && (reversed = reversed_comparison_code (op, NULL_RTX))
+                != UNKNOWN)
+           return simplify_gen_relational (reversed, op_mode, op_mode,
+                                           XEXP (op, 0), XEXP (op, 1));
+
+         /* (not (ashiftrt foo C)) where C is the number of bits in FOO
+            minus 1 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1,
+            so we can perform the above simplification.  */
+
+         if (STORE_FLAG_VALUE == -1
+             && GET_CODE (op) == ASHIFTRT
+             && GET_CODE (XEXP (op, 1)) == CONST_INT
+             && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+           return simplify_gen_relational (GE, mode, mode, XEXP (op, 0),
+                                           const0_rtx);
+
          break;
 
        case NEG:
          /* (neg (neg X)) == X.  */
          if (GET_CODE (op) == NEG)
            return XEXP (op, 0);
+
+         /* (neg (plus X 1)) can become (not X).  */
+         if (GET_CODE (op) == PLUS
+             && XEXP (op, 1) == const1_rtx)
+           return simplify_gen_unary (NOT, mode, XEXP (op, 0), mode);
+
+         /* Similarly, (neg (not X)) is (plus X 1).  */
+         if (GET_CODE (op) == NOT)
+           return plus_constant (XEXP (op, 0), 1);
+
+         /* (neg (minus X Y)) can become (minus Y X).  This transformation
+            isn't safe for modes with signed zeros, since if X and Y are
+            both +0, (minus Y X) is the same as (minus X Y).  If the
+            rounding mode is towards +infinity (or -infinity) then the two
+            expressions will be rounded differently.  */
+         if (GET_CODE (op) == MINUS
+             && !HONOR_SIGNED_ZEROS (mode)
+             && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+           return simplify_gen_binary (MINUS, mode, XEXP (op, 1),
+                                       XEXP (op, 0));
+
+         /* (neg (plus A B)) is canonicalized to (minus (neg A) B).  */
+         if (GET_CODE (op) == PLUS
+             && !HONOR_SIGNED_ZEROS (mode)
+             && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+           {
+             temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
+             return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1));
+           }
+
+         /* (neg (mult A B)) becomes (mult (neg A) B).
+            This works even for floating-point values.  */
+         if (GET_CODE (op) == MULT
+             && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+           {
+             temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
+             return simplify_gen_binary (MULT, mode, temp, XEXP (op, 1));
+           }
+
+         /* NEG commutes with ASHIFT since it is multiplication.  Only do
+            this if we can then eliminate the NEG (e.g., if the operand
+            is a constant).  */
+         if (GET_CODE (op) == ASHIFT)
+           {
+             temp = simplify_unary_operation (NEG, mode, XEXP (op, 0),
+                                              mode);
+             if (temp)
+               return simplify_gen_binary (ASHIFT, mode, temp,
+                                           XEXP (op, 1));
+           }
+
          break;
 
        case SIGN_EXTEND:
@@ -854,6 +960,72 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
     }
 }
 \f
+/* Subroutine of simplify_associative_operation.  Return true if rtx OP
+   is a suitable integer or floating point immediate constant.  */
+static bool
+associative_constant_p (rtx op)
+{
+  if (GET_CODE (op) == CONST_INT
+      || GET_CODE (op) == CONST_DOUBLE)
+    return true;
+  op = avoid_constant_pool_reference (op);
+  return GET_CODE (op) == CONST_INT
+        || GET_CODE (op) == CONST_DOUBLE;
+}
+
+/* Subroutine of simplify_binary_operation to simplify an associative
+   binary operation CODE with result mode MODE, operating on OP0 and OP1.
+   Return 0 if no simplification is possible.  */
+static rtx
+simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
+                               rtx op0, rtx op1)
+{
+  rtx tem;
+
+  /* Simplify (x op c1) op c2 as x op (c1 op c2).  */
+  if (GET_CODE (op0) == code
+      && associative_constant_p (op1)
+      && associative_constant_p (XEXP (op0, 1)))
+    {
+      tem = simplify_binary_operation (code, mode, XEXP (op0, 1), op1);
+      if (! tem)
+       return tem;
+      return simplify_gen_binary (code, mode, XEXP (op0, 0), tem);
+    }
+
+  /* Simplify (x op c1) op (y op c2) as (x op y) op (c1 op c2).  */
+  if (GET_CODE (op0) == code
+      && GET_CODE (op1) == code
+      && associative_constant_p (XEXP (op0, 1))
+      && associative_constant_p (XEXP (op1, 1)))
+    {
+      rtx c = simplify_binary_operation (code, mode,
+                                        XEXP (op0, 1), XEXP (op1, 1));
+      if (! c)
+       return 0;
+      tem = simplify_gen_binary (code, mode, XEXP (op0, 0), XEXP (op1, 0));
+      return simplify_gen_binary (code, mode, tem, c);
+    }
+
+  /* Canonicalize (x op c) op y as (x op y) op c.  */
+  if (GET_CODE (op0) == code
+      && associative_constant_p (XEXP (op0, 1)))
+    {
+      tem = simplify_gen_binary (code, mode, XEXP (op0, 0), op1);
+      return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
+    }
+
+  /* Canonicalize x op (y op c) as (x op y) op c.  */
+  if (GET_CODE (op1) == code
+      && associative_constant_p (XEXP (op1, 1)))
+    {
+      tem = simplify_gen_binary (code, mode, op0, XEXP (op1, 0));
+      return simplify_gen_binary (code, mode, tem, XEXP (op1, 1));
+    }
+
+  return 0;
+}
+
 /* Simplify a binary operation CODE with result mode MODE, operating on OP0
    and OP1.  Return 0 if no simplification is possible.
 
@@ -929,9 +1101,13 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
       f0 = real_value_truncate (mode, f0);
       f1 = real_value_truncate (mode, f1);
 
+      if (HONOR_SNANS (mode)
+         && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
+       return 0;
+
       if (code == DIV
-         && !MODE_HAS_INFINITIES (mode)
-         && REAL_VALUES_EQUAL (f1, dconst0))
+         && REAL_VALUES_EQUAL (f1, dconst0)
+         && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
        return 0;
 
       REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
@@ -968,7 +1144,7 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          neg_double (l2, h2, &lv, &hv);
          l2 = lv, h2 = hv;
 
-         /* .. fall through ...  */
+         /* Fall through....  */
 
        case PLUS:
          add_double (l1, h1, l2, h2, &lv, &hv);
@@ -1091,7 +1267,7 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          if (INTEGRAL_MODE_P (mode)
              && GET_CODE (op0) == NOT
              && trueop1 == const1_rtx)
-           return gen_rtx_NEG (mode, XEXP (op0, 0));
+           return simplify_gen_unary (NEG, mode, XEXP (op0, 0), mode);
 
          /* Handle both-operands-constant cases.  We can only add
             CONST_INTs to constants since the sum of relocatable symbols
@@ -1175,6 +1351,16 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
                      && GET_CODE (XEXP (op1, 0)) == PLUS))
              && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0)
            return tem;
+
+         /* Reassociate floating point addition only when the user
+            specifies unsafe math optimizations.  */
+         if (FLOAT_MODE_P (mode)
+             && flag_unsafe_math_optimizations)
+           {
+             tem = simplify_associative_operation (code, mode, op0, op1);
+             if (tem)
+               return tem;
+           }
          break;
 
        case COMPARE:
@@ -1226,11 +1412,11 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
             But if the mode has signed zeros, and does not round towards
             -infinity, then 0 - 0 is 0, not -0.  */
          if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
-           return gen_rtx_NEG (mode, op1);
+           return simplify_gen_unary (NEG, mode, op1, mode);
 
          /* (-1 - a) is ~a.  */
          if (trueop0 == constm1_rtx)
-           return gen_rtx_NOT (mode, op1);
+           return simplify_gen_unary (NOT, mode, op1, mode);
 
          /* Subtracting 0 has no effect unless the mode has signed zeros
             and supports rounding towards -infinity.  In such a case,
@@ -1340,11 +1526,7 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
 
        case MULT:
          if (trueop1 == constm1_rtx)
-           {
-             tem = simplify_unary_operation (NEG, mode, op0, mode);
-
-             return tem ? tem : gen_rtx_NEG (mode, op0);
-           }
+           return simplify_gen_unary (NEG, mode, op0, mode);
 
          /* Maybe simplify x * 0 to 0.  The reduction is not valid if
             x is NaN, since x * 0 is then also NaN.  Nor is it valid
@@ -1372,7 +1554,7 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              && (width <= HOST_BITS_PER_WIDE_INT
                  || val != HOST_BITS_PER_WIDE_INT - 1)
              && ! rtx_equal_function_value_matters)
-           return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
+           return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
 
          /* x*2 is x+x and x*(-1) is -x */
          if (GET_CODE (trueop1) == CONST_DOUBLE
@@ -1383,10 +1565,20 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
 
              if (REAL_VALUES_EQUAL (d, dconst2))
-               return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
+               return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0));
 
              if (REAL_VALUES_EQUAL (d, dconstm1))
-               return gen_rtx_NEG (mode, op0);
+               return simplify_gen_unary (NEG, mode, op0, mode);
+           }
+
+         /* Reassociate multiplication, but for floating point MULTs
+            only when the user specifies unsafe math optimizations.  */
+         if (! FLOAT_MODE_P (mode)
+             || flag_unsafe_math_optimizations)
+           {
+             tem = simplify_associative_operation (code, mode, op0, op1);
+             if (tem)
+               return tem;
            }
          break;
 
@@ -1405,6 +1597,9 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              && ! side_effects_p (op0)
              && GET_MODE_CLASS (mode) != MODE_CC)
            return constm1_rtx;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case XOR:
@@ -1413,10 +1608,13 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          if (GET_CODE (trueop1) == CONST_INT
              && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
                  == GET_MODE_MASK (mode)))
-           return gen_rtx_NOT (mode, op0);
+           return simplify_gen_unary (NOT, mode, op0, mode);
          if (trueop0 == trueop1 && ! side_effects_p (op0)
              && GET_MODE_CLASS (mode) != MODE_CC)
            return const0_rtx;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case AND:
@@ -1435,6 +1633,9 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              && ! side_effects_p (op0)
              && GET_MODE_CLASS (mode) != MODE_CC)
            return const0_rtx;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case UDIV:
@@ -1442,9 +1643,9 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
             below).  */
          if (GET_CODE (trueop1) == CONST_INT
              && (arg1 = exact_log2 (INTVAL (trueop1))) > 0)
-           return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
+           return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (arg1));
 
-         /* ... fall through ...  */
+         /* Fall through....  */
 
        case DIV:
          if (trueop1 == CONST1_RTX (mode))
@@ -1483,8 +1684,8 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              if (! REAL_VALUES_EQUAL (d, dconst0))
                {
                  REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
-                 return gen_rtx_MULT (mode, op0,
-                                      CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
+                 tem = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
+                 return simplify_gen_binary (MULT, mode, op0, tem);
                }
            }
          break;
@@ -1493,9 +1694,10 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          /* Handle modulus by power of two (mod with 1 handled below).  */
          if (GET_CODE (trueop1) == CONST_INT
              && exact_log2 (INTVAL (trueop1)) > 0)
-           return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
+           return simplify_gen_binary (AND, mode, op0,
+                                       GEN_INT (INTVAL (op1) - 1));
 
-         /* ... fall through ...  */
+         /* Fall through....  */
 
        case MOD:
          if ((trueop0 == const0_rtx || trueop1 == const1_rtx)
@@ -1512,7 +1714,7 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              && ! side_effects_p (op1))
            return op0;
 
-         /* ... fall through ...  */
+         /* Fall through....  */
 
        case ASHIFT:
        case LSHIFTRT:
@@ -1523,36 +1725,50 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          break;
 
        case SMIN:
-         if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (trueop1) == CONST_INT
+         if (width <= HOST_BITS_PER_WIDE_INT
+             && GET_CODE (trueop1) == CONST_INT
              && INTVAL (trueop1) == (HOST_WIDE_INT) 1 << (width -1)
              && ! side_effects_p (op0))
            return op1;
-         else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
+         if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
            return op0;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case SMAX:
-         if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (trueop1) == CONST_INT
+         if (width <= HOST_BITS_PER_WIDE_INT
+             && GET_CODE (trueop1) == CONST_INT
              && ((unsigned HOST_WIDE_INT) INTVAL (trueop1)
                  == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
              && ! side_effects_p (op0))
            return op1;
-         else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
+         if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
            return op0;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case UMIN:
          if (trueop1 == const0_rtx && ! side_effects_p (op0))
            return op1;
-         else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
+         if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
            return op0;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case UMAX:
          if (trueop1 == constm1_rtx && ! side_effects_p (op0))
            return op1;
-         else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
+         if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
            return op0;
+         tem = simplify_associative_operation (code, mode, op0, op1);
+         if (tem)
+           return tem;
          break;
 
        case SS_PLUS:
@@ -1903,7 +2119,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
   int first, negate, changed;
   int i, j;
 
-  memset ((char *) ops, 0, sizeof ops);
+  memset (ops, 0, 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
@@ -2905,10 +3121,12 @@ simplify_subreg (enum machine_mode outermode, rtx op,
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
       && REGNO (op) != ARG_POINTER_REGNUM
 #endif
-      && REGNO (op) != STACK_POINTER_REGNUM)
+      && REGNO (op) != STACK_POINTER_REGNUM
+      && subreg_offset_representable_p (REGNO (op), innermode,
+                                       byte, outermode))
     {
-      int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte),
-                                          0);
+      rtx tem = gen_rtx_SUBREG (outermode, op, byte);
+      int final_regno = subreg_hard_regno (tem, 0);
 
       /* ??? We do allow it if the current REG is not valid for
         its mode.  This is a kludge to work around how float/complex
@@ -3048,15 +3266,9 @@ simplify_rtx (rtx x)
                                       XEXP (x, 0), GET_MODE (XEXP (x, 0)));
     case 'c':
       if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
-       {
-         rtx tem;
+       return simplify_gen_binary (code, mode, XEXP (x, 1), XEXP (x, 0));
 
-         tem = XEXP (x, 0);
-         XEXP (x, 0) = XEXP (x, 1);
-         XEXP (x, 1) = tem;
-         return simplify_binary_operation (code, mode,
-                                           XEXP (x, 0), XEXP (x, 1));
-       }
+      /* Fall through....  */
 
     case '2':
       return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));