OSDN Git Service

Call scev_reset_htab when Graphite out-of-SSA has changed something.
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 7c79afb..a7a91e5 100644 (file)
@@ -1,6 +1,6 @@
 /* RTL simplification functions for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -30,12 +30,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
-#include "real.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "function.h"
 #include "expr.h"
 #include "toplev.h"
+#include "diagnostic-core.h"
 #include "output.h"
 #include "ggc.h"
 #include "target.h"
@@ -209,10 +209,11 @@ avoid_constant_pool_reference (rtx x)
 rtx
 delegitimize_mem_from_attrs (rtx x)
 {
+  /* MEMs without MEM_OFFSETs may have been offset, so we can't just
+     use their base addresses as equivalent.  */
   if (MEM_P (x)
       && MEM_EXPR (x)
-      && (!MEM_OFFSET (x)
-         || GET_CODE (MEM_OFFSET (x)) == CONST_INT))
+      && MEM_OFFSET (x))
     {
       tree decl = MEM_EXPR (x);
       enum machine_mode mode = GET_MODE (x);
@@ -265,8 +266,7 @@ delegitimize_mem_from_attrs (rtx x)
        {
          rtx newx;
 
-         if (MEM_OFFSET (x))
-           offset += INTVAL (MEM_OFFSET (x));
+         offset += INTVAL (MEM_OFFSET (x));
 
          newx = DECL_RTL (decl);
 
@@ -350,15 +350,14 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
   return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
 \f
-/* Replace all occurrences of OLD_RTX in X with FN (X', DATA), where X'
-   is an expression in X that is equal to OLD_RTX.  Canonicalize and
-   simplify the result.
-
-   If FN is null, assume FN (X', DATA) == copy_rtx (DATA).  */
+/* If FN is NULL, replace all occurrences of OLD_RTX in X with copy_rtx (DATA)
+   and simplify the result.  If FN is non-NULL, call this callback on each
+   X, if it returns non-NULL, replace X with its return value and simplify the
+   result.  */
 
 rtx
 simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
-                        rtx (*fn) (rtx, void *), void *data)
+                        rtx (*fn) (rtx, const_rtx, void *), void *data)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
@@ -368,17 +367,14 @@ simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
   rtvec vec, newvec;
   int i, j;
 
-  /* If X is OLD_RTX, return FN (X, DATA), with a null FN.  Otherwise,
-     if this is an expression, try to build a new expression, substituting
-     recursively.  If we can't do anything, return our input.  */
-
-  if (rtx_equal_p (x, old_rtx))
+  if (__builtin_expect (fn != NULL, 0))
     {
-      if (fn)
-       return fn (x, data);
-      else
-       return copy_rtx ((rtx) data);
+      newx = fn (x, old_rtx, data);
+      if (newx)
+       return newx;
     }
+  else if (rtx_equal_p (x, old_rtx))
+    return copy_rtx ((rtx) data);
 
   switch (GET_RTX_CLASS (code))
     {
@@ -1201,10 +1197,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          break;
 
        case FFS:
-         /* Don't use ffs here.  Instead, get low order bit and then its
-            number.  If arg0 is zero, this will return 0, as desired.  */
          arg0 &= GET_MODE_MASK (mode);
-         val = exact_log2 (arg0 & (- arg0)) + 1;
+         val = ffs_hwi (arg0);
          break;
 
        case CLZ:
@@ -1225,7 +1219,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
                val = GET_MODE_BITSIZE (mode);
            }
          else
-           val = exact_log2 (arg0 & -arg0);
+           val = ctz_hwi (arg0);
          break;
 
        case POPCOUNT:
@@ -1355,15 +1349,12 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 
        case FFS:
          hv = 0;
-         if (l1 == 0)
-           {
-             if (h1 == 0)
-               lv = 0;
-             else
-               lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1) + 1;
-           }
+         if (l1 != 0)
+           lv = ffs_hwi (l1);
+         else if (h1 != 0)
+           lv = HOST_BITS_PER_WIDE_INT + ffs_hwi (h1);
          else
-           lv = exact_log2 (l1 & -l1) + 1;
+           lv = 0;
          break;
 
        case CLZ:
@@ -1380,9 +1371,9 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
        case CTZ:
          hv = 0;
          if (l1 != 0)
-           lv = exact_log2 (l1 & -l1);
+           lv = ctz_hwi (l1);
          else if (h1 != 0)
-           lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1);
+           lv = HOST_BITS_PER_WIDE_INT + ctz_hwi (h1);
          else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, lv))
            lv = GET_MODE_BITSIZE (mode);
          break;
@@ -1486,10 +1477,10 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          d = t;
          break;
        case ABS:
-         d = REAL_VALUE_ABS (d);
+         d = real_value_abs (&d);
          break;
        case NEG:
-         d = REAL_VALUE_NEGATE (d);
+         d = real_value_negate (&d);
          break;
        case FLOAT_TRUNCATE:
          d = real_value_truncate (mode, d);
@@ -1774,44 +1765,42 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
        {
-         HOST_WIDE_INT coeff0h = 0, coeff1h = 0;
-         unsigned HOST_WIDE_INT coeff0l = 1, coeff1l = 1;
+         double_int coeff0, coeff1;
          rtx lhs = op0, rhs = op1;
 
+         coeff0 = double_int_one;
+         coeff1 = double_int_one;
+
          if (GET_CODE (lhs) == NEG)
            {
-             coeff0l = -1;
-             coeff0h = -1;
+             coeff0 = double_int_minus_one;
              lhs = XEXP (lhs, 0);
            }
          else if (GET_CODE (lhs) == MULT
                   && CONST_INT_P (XEXP (lhs, 1)))
            {
-             coeff0l = INTVAL (XEXP (lhs, 1));
-             coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+             coeff0 = shwi_to_double_int (INTVAL (XEXP (lhs, 1)));
              lhs = XEXP (lhs, 0);
            }
          else if (GET_CODE (lhs) == ASHIFT
                   && CONST_INT_P (XEXP (lhs, 1))
-                  && INTVAL (XEXP (lhs, 1)) >= 0
+                   && INTVAL (XEXP (lhs, 1)) >= 0
                   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
-             coeff0h = 0;
+             coeff0 = double_int_setbit (double_int_zero,
+                                         INTVAL (XEXP (lhs, 1)));
              lhs = XEXP (lhs, 0);
            }
 
          if (GET_CODE (rhs) == NEG)
            {
-             coeff1l = -1;
-             coeff1h = -1;
+             coeff1 = double_int_minus_one;
              rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == MULT
                   && CONST_INT_P (XEXP (rhs, 1)))
            {
-             coeff1l = INTVAL (XEXP (rhs, 1));
-             coeff1h = INTVAL (XEXP (rhs, 1)) < 0 ? -1 : 0;
+             coeff1 = shwi_to_double_int (INTVAL (XEXP (rhs, 1)));
              rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == ASHIFT
@@ -1819,8 +1808,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                   && INTVAL (XEXP (rhs, 1)) >= 0
                   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff1l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
-             coeff1h = 0;
+             coeff1 = double_int_setbit (double_int_zero,
+                                         INTVAL (XEXP (rhs, 1)));
              rhs = XEXP (rhs, 0);
            }
 
@@ -1828,12 +1817,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
            {
              rtx orig = gen_rtx_PLUS (mode, op0, op1);
              rtx coeff;
-             unsigned HOST_WIDE_INT l;
-             HOST_WIDE_INT h;
+             double_int val;
              bool speed = optimize_function_for_speed_p (cfun);
 
-             add_double (coeff0l, coeff0h, coeff1l, coeff1h, &l, &h);
-             coeff = immed_double_const (l, h, mode);
+             val = double_int_add (coeff0, coeff1);
+             coeff = immed_double_int_const (val, mode);
 
              tem = simplify_gen_binary (MULT, mode, lhs, coeff);
              return rtx_cost (tem, SET, speed) <= rtx_cost (orig, SET, speed)
@@ -1957,21 +1945,21 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
        {
-         HOST_WIDE_INT coeff0h = 0, negcoeff1h = -1;
-         unsigned HOST_WIDE_INT coeff0l = 1, negcoeff1l = -1;
+         double_int coeff0, negcoeff1;
          rtx lhs = op0, rhs = op1;
 
+         coeff0 = double_int_one;
+         negcoeff1 = double_int_minus_one;
+
          if (GET_CODE (lhs) == NEG)
            {
-             coeff0l = -1;
-             coeff0h = -1;
+             coeff0 = double_int_minus_one;
              lhs = XEXP (lhs, 0);
            }
          else if (GET_CODE (lhs) == MULT
                   && CONST_INT_P (XEXP (lhs, 1)))
            {
-             coeff0l = INTVAL (XEXP (lhs, 1));
-             coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+             coeff0 = shwi_to_double_int (INTVAL (XEXP (lhs, 1)));
              lhs = XEXP (lhs, 0);
            }
          else if (GET_CODE (lhs) == ASHIFT
@@ -1979,22 +1967,20 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                   && INTVAL (XEXP (lhs, 1)) >= 0
                   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
-             coeff0h = 0;
+             coeff0 = double_int_setbit (double_int_zero,
+                                         INTVAL (XEXP (lhs, 1)));
              lhs = XEXP (lhs, 0);
            }
 
          if (GET_CODE (rhs) == NEG)
            {
-             negcoeff1l = 1;
-             negcoeff1h = 0;
+             negcoeff1 = double_int_one;
              rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == MULT
                   && CONST_INT_P (XEXP (rhs, 1)))
            {
-             negcoeff1l = -INTVAL (XEXP (rhs, 1));
-             negcoeff1h = INTVAL (XEXP (rhs, 1)) <= 0 ? 0 : -1;
+             negcoeff1 = shwi_to_double_int (-INTVAL (XEXP (rhs, 1)));
              rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == ASHIFT
@@ -2002,8 +1988,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                   && INTVAL (XEXP (rhs, 1)) >= 0
                   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             negcoeff1l = -(((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)));
-             negcoeff1h = -1;
+             negcoeff1 = double_int_setbit (double_int_zero,
+                                            INTVAL (XEXP (rhs, 1)));
+             negcoeff1 = double_int_neg (negcoeff1);
              rhs = XEXP (rhs, 0);
            }
 
@@ -2011,12 +1998,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
            {
              rtx orig = gen_rtx_MINUS (mode, op0, op1);
              rtx coeff;
-             unsigned HOST_WIDE_INT l;
-             HOST_WIDE_INT h;
+             double_int val;
              bool speed = optimize_function_for_speed_p (cfun);
 
-             add_double (coeff0l, coeff0h, negcoeff1l, negcoeff1h, &l, &h);
-             coeff = immed_double_const (l, h, mode);
+             val = double_int_add (coeff0, negcoeff1);
+             coeff = immed_double_int_const (val, mode);
 
              tem = simplify_gen_binary (MULT, mode, lhs, coeff);
              return rtx_cost (tem, SET, speed) <= rtx_cost (orig, SET, speed)
@@ -2118,6 +2104,19 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       if (trueop1 == constm1_rtx)
        return simplify_gen_unary (NEG, mode, op0, mode);
 
+      if (GET_CODE (op0) == NEG)
+       {
+         rtx temp = simplify_unary_operation (NEG, mode, op1, mode);
+         if (temp)
+           return simplify_gen_binary (MULT, mode, XEXP (op0, 0), temp);
+       }
+      if (GET_CODE (op1) == NEG)
+       {
+         rtx temp = simplify_unary_operation (NEG, mode, op0, mode);
+         if (temp)
+           return simplify_gen_binary (MULT, mode, temp, XEXP (op1, 0));
+       }
+
       /* 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
         when the mode has signed zeros, since multiplying a negative
@@ -3278,141 +3277,124 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   /* We can fold some multi-word operations.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_WIDE_INT * 2
-      && (GET_CODE (op0) == CONST_DOUBLE || CONST_INT_P (op0))
-      && (GET_CODE (op1) == CONST_DOUBLE || CONST_INT_P (op1)))
+      && width == HOST_BITS_PER_DOUBLE_INT
+      && (CONST_DOUBLE_P (op0) || CONST_INT_P (op0))
+      && (CONST_DOUBLE_P (op1) || CONST_INT_P (op1)))
     {
-      unsigned HOST_WIDE_INT l1, l2, lv, lt;
-      HOST_WIDE_INT h1, h2, hv, ht;
+      double_int o0, o1, res, tmp;
 
-      if (GET_CODE (op0) == CONST_DOUBLE)
-       l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
-      else
-       l1 = INTVAL (op0), h1 = HWI_SIGN_EXTEND (l1);
-
-      if (GET_CODE (op1) == CONST_DOUBLE)
-       l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
-      else
-       l2 = INTVAL (op1), h2 = HWI_SIGN_EXTEND (l2);
+      o0 = rtx_to_double_int (op0);
+      o1 = rtx_to_double_int (op1);
 
       switch (code)
        {
        case MINUS:
          /* A - B == A + (-B).  */
-         neg_double (l2, h2, &lv, &hv);
-         l2 = lv, h2 = hv;
+         o1 = double_int_neg (o1);
 
          /* Fall through....  */
 
        case PLUS:
-         add_double (l1, h1, l2, h2, &lv, &hv);
+         res = double_int_add (o0, o1);
          break;
 
        case MULT:
-         mul_double (l1, h1, l2, h2, &lv, &hv);
+         res = double_int_mul (o0, o1);
          break;
 
        case DIV:
-         if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
-                                   &lv, &hv, &lt, &ht))
+         if (div_and_round_double (TRUNC_DIV_EXPR, 0,
+                                   o0.low, o0.high, o1.low, o1.high,
+                                   &res.low, &res.high,
+                                   &tmp.low, &tmp.high))
            return 0;
          break;
 
        case MOD:
-         if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
-                                   &lt, &ht, &lv, &hv))
+         if (div_and_round_double (TRUNC_DIV_EXPR, 0,
+                                   o0.low, o0.high, o1.low, o1.high,
+                                   &tmp.low, &tmp.high,
+                                   &res.low, &res.high))
            return 0;
          break;
 
        case UDIV:
-         if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
-                                   &lv, &hv, &lt, &ht))
+         if (div_and_round_double (TRUNC_DIV_EXPR, 1,
+                                   o0.low, o0.high, o1.low, o1.high,
+                                   &res.low, &res.high,
+                                   &tmp.low, &tmp.high))
            return 0;
          break;
 
        case UMOD:
-         if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
-                                   &lt, &ht, &lv, &hv))
+         if (div_and_round_double (TRUNC_DIV_EXPR, 1,
+                                   o0.low, o0.high, o1.low, o1.high,
+                                   &tmp.low, &tmp.high,
+                                   &res.low, &res.high))
            return 0;
          break;
 
        case AND:
-         lv = l1 & l2, hv = h1 & h2;
+         res = double_int_and (o0, o1);
          break;
 
        case IOR:
-         lv = l1 | l2, hv = h1 | h2;
+         res = double_int_ior (o0, o1);
          break;
 
        case XOR:
-         lv = l1 ^ l2, hv = h1 ^ h2;
+         res = double_int_xor (o0, o1);
          break;
 
        case SMIN:
-         if (h1 < h2
-             || (h1 == h2
-                 && ((unsigned HOST_WIDE_INT) l1
-                     < (unsigned HOST_WIDE_INT) l2)))
-           lv = l1, hv = h1;
-         else
-           lv = l2, hv = h2;
+         res = double_int_smin (o0, o1);
          break;
 
        case SMAX:
-         if (h1 > h2
-             || (h1 == h2
-                 && ((unsigned HOST_WIDE_INT) l1
-                     > (unsigned HOST_WIDE_INT) l2)))
-           lv = l1, hv = h1;
-         else
-           lv = l2, hv = h2;
+         res = double_int_smax (o0, o1);
          break;
 
        case UMIN:
-         if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
-             || (h1 == h2
-                 && ((unsigned HOST_WIDE_INT) l1
-                     < (unsigned HOST_WIDE_INT) l2)))
-           lv = l1, hv = h1;
-         else
-           lv = l2, hv = h2;
+         res = double_int_umin (o0, o1);
          break;
 
        case UMAX:
-         if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
-             || (h1 == h2
-                 && ((unsigned HOST_WIDE_INT) l1
-                     > (unsigned HOST_WIDE_INT) l2)))
-           lv = l1, hv = h1;
-         else
-           lv = l2, hv = h2;
+         res = double_int_umax (o0, o1);
          break;
 
        case LSHIFTRT:   case ASHIFTRT:
        case ASHIFT:
        case ROTATE:     case ROTATERT:
-         if (SHIFT_COUNT_TRUNCATED)
-           l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
-
-         if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
-           return 0;
-
-         if (code == LSHIFTRT || code == ASHIFTRT)
-           rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
-                          code == ASHIFTRT);
-         else if (code == ASHIFT)
-           lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
-         else if (code == ROTATE)
-           lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
-         else /* code == ROTATERT */
-           rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
+         {
+           unsigned HOST_WIDE_INT cnt;
+
+           if (SHIFT_COUNT_TRUNCATED)
+             o1 = double_int_zext (o1, GET_MODE_BITSIZE (mode));
+
+           if (!double_int_fits_in_uhwi_p (o1)
+               || double_int_to_uhwi (o1) >= GET_MODE_BITSIZE (mode))
+             return 0;
+
+           cnt = double_int_to_uhwi (o1);
+
+           if (code == LSHIFTRT || code == ASHIFTRT)
+             res = double_int_rshift (o0, cnt, GET_MODE_BITSIZE (mode),
+                                      code == ASHIFTRT);
+           else if (code == ASHIFT)
+             res = double_int_lshift (o0, cnt, GET_MODE_BITSIZE (mode),
+                                      true);
+           else if (code == ROTATE)
+             res = double_int_lrotate (o0, cnt, GET_MODE_BITSIZE (mode));
+           else /* code == ROTATERT */
+             res = double_int_rrotate (o0, cnt, GET_MODE_BITSIZE (mode));
+         }
          break;
 
        default:
          return 0;
        }
 
-      return immed_double_const (lv, hv, mode);
+      return immed_double_int_const (res, mode);
     }
 
   if (CONST_INT_P (op0) && CONST_INT_P (op1)