OSDN Git Service

PR target/21723
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index c6b0ec8..ae1fea7 100644 (file)
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
@@ -145,6 +145,7 @@ avoid_constant_pool_reference (rtx x)
 {
   rtx c, tmp, addr;
   enum machine_mode cmode;
+  HOST_WIDE_INT offset = 0;
 
   switch (GET_CODE (x))
     {
@@ -173,26 +174,40 @@ avoid_constant_pool_reference (rtx x)
   /* Call target hook to avoid the effects of -fpic etc....  */
   addr = targetm.delegitimize_address (addr);
 
+  /* Split the address into a base and integer offset.  */
+  if (GET_CODE (addr) == CONST
+      && GET_CODE (XEXP (addr, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
+    {
+      offset = INTVAL (XEXP (XEXP (addr, 0), 1));
+      addr = XEXP (XEXP (addr, 0), 0);
+    }
+
   if (GET_CODE (addr) == LO_SUM)
     addr = XEXP (addr, 1);
 
-  if (GET_CODE (addr) != SYMBOL_REF
-      || ! CONSTANT_POOL_ADDRESS_P (addr))
-    return x;
-
-  c = get_pool_constant (addr);
-  cmode = get_pool_mode (addr);
-
-  /* If we're accessing the constant in a different mode than it was
-     originally stored, attempt to fix that up via subreg simplifications.
-     If that fails we have no choice but to return the original memory.  */
-  if (cmode != GET_MODE (x))
+  /* If this is a constant pool reference, we can turn it into its
+     constant and hope that simplifications happen.  */
+  if (GET_CODE (addr) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (addr))
     {
-      c = simplify_subreg (GET_MODE (x), c, cmode, 0);
-      return c ? c : x;
+      c = get_pool_constant (addr);
+      cmode = get_pool_mode (addr);
+
+      /* If we're accessing the constant in a different mode than it was
+         originally stored, attempt to fix that up via subreg simplifications.
+         If that fails we have no choice but to return the original memory.  */
+      if (offset != 0 || cmode != GET_MODE (x))
+        {
+          rtx tem = simplify_subreg (GET_MODE (x), c, cmode, offset);
+          if (tem && CONSTANT_P (tem))
+            return tem;
+        }
+      else
+        return c;
     }
 
-  return c;
+  return x;
 }
 \f
 /* Make a unary operation by first seeing if it folds and otherwise making
@@ -570,7 +585,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         target mode is the same as the variable's promotion.  */
       if (GET_CODE (op) == SUBREG
          && SUBREG_PROMOTED_VAR_P (op)
-         && SUBREG_PROMOTED_UNSIGNED_P (op)
+         && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
          && GET_MODE (XEXP (op, 0)) == mode)
        return XEXP (op, 0);
 
@@ -829,9 +844,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          gcc_unreachable ();
        }
 
-      val = trunc_int_for_mode (val, mode);
-
-      return GEN_INT (val);
+      return gen_int_mode (val, mode);
     }
 
   /* We can do some operations on integer CONST_DOUBLEs.  Also allow
@@ -1257,46 +1270,69 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
         have X (if C is 2 in the example above).  But don't make
         something more expensive than we had before.  */
 
-      if (! FLOAT_MODE_P (mode))
+      if (SCALAR_INT_MODE_P (mode))
        {
-         HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+         HOST_WIDE_INT coeff0h = 0, coeff1h = 0;
+         unsigned HOST_WIDE_INT coeff0l = 1, coeff1l = 1;
          rtx lhs = op0, rhs = op1;
 
          if (GET_CODE (lhs) == NEG)
-           coeff0 = -1, lhs = XEXP (lhs, 0);
+           {
+             coeff0l = -1;
+             coeff0h = -1;
+             lhs = XEXP (lhs, 0);
+           }
          else if (GET_CODE (lhs) == MULT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
-           coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+           {
+             coeff0l = INTVAL (XEXP (lhs, 1));
+             coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+             lhs = XEXP (lhs, 0);
+           }
          else if (GET_CODE (lhs) == ASHIFT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
                   && INTVAL (XEXP (lhs, 1)) >= 0
                   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0h = 0;
              lhs = XEXP (lhs, 0);
            }
 
          if (GET_CODE (rhs) == NEG)
-           coeff1 = -1, rhs = XEXP (rhs, 0);
+           {
+             coeff1l = -1;
+             coeff1h = -1;
+             rhs = XEXP (rhs, 0);
+           }
          else if (GET_CODE (rhs) == MULT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
            {
-             coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+             coeff1l = INTVAL (XEXP (rhs, 1));
+             coeff1h = INTVAL (XEXP (rhs, 1)) < 0 ? -1 : 0;
+             rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == ASHIFT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
                   && INTVAL (XEXP (rhs, 1)) >= 0
                   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+             coeff1l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+             coeff1h = 0;
              rhs = XEXP (rhs, 0);
            }
 
          if (rtx_equal_p (lhs, rhs))
            {
              rtx orig = gen_rtx_PLUS (mode, op0, op1);
-             tem = simplify_gen_binary (MULT, mode, lhs,
-                                        GEN_INT (coeff0 + coeff1));
+             rtx coeff;
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
+
+             add_double (coeff0l, coeff0h, coeff1l, coeff1h, &l, &h);
+             coeff = immed_double_const (l, h, mode);
+
+             tem = simplify_gen_binary (MULT, mode, lhs, coeff);
              return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
                ? tem : 0;
            }
@@ -1405,48 +1441,69 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
         have X (if C is 2 in the example above).  But don't make
         something more expensive than we had before.  */
 
-      if (! FLOAT_MODE_P (mode))
+      if (SCALAR_INT_MODE_P (mode))
        {
-         HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+         HOST_WIDE_INT coeff0h = 0, negcoeff1h = -1;
+         unsigned HOST_WIDE_INT coeff0l = 1, negcoeff1l = -1;
          rtx lhs = op0, rhs = op1;
 
          if (GET_CODE (lhs) == NEG)
-           coeff0 = -1, lhs = XEXP (lhs, 0);
+           {
+             coeff0l = -1;
+             coeff0h = -1;
+             lhs = XEXP (lhs, 0);
+           }
          else if (GET_CODE (lhs) == MULT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
            {
-             coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+             coeff0l = INTVAL (XEXP (lhs, 1));
+             coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+             lhs = XEXP (lhs, 0);
            }
          else if (GET_CODE (lhs) == ASHIFT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
                   && INTVAL (XEXP (lhs, 1)) >= 0
                   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0h = 0;
              lhs = XEXP (lhs, 0);
            }
 
          if (GET_CODE (rhs) == NEG)
-           coeff1 = - 1, rhs = XEXP (rhs, 0);
+           {
+             negcoeff1l = 1;
+             negcoeff1h = 0;
+             rhs = XEXP (rhs, 0);
+           }
          else if (GET_CODE (rhs) == MULT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
            {
-             coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+             negcoeff1l = -INTVAL (XEXP (rhs, 1));
+             negcoeff1h = INTVAL (XEXP (rhs, 1)) <= 0 ? 0 : -1;
+             rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == ASHIFT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
                   && INTVAL (XEXP (rhs, 1)) >= 0
                   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+             negcoeff1l = -(((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)));
+             negcoeff1h = -1;
              rhs = XEXP (rhs, 0);
            }
 
          if (rtx_equal_p (lhs, rhs))
            {
              rtx orig = gen_rtx_MINUS (mode, op0, op1);
-             tem = simplify_gen_binary (MULT, mode, lhs,
-                                        GEN_INT (coeff0 - coeff1));
+             rtx coeff;
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
+
+             add_double (coeff0l, coeff0h, negcoeff1l, negcoeff1h, &l, &h);
+             coeff = immed_double_const (l, h, mode);
+
+             tem = simplify_gen_binary (MULT, mode, lhs, coeff);
              return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
                ? tem : 0;
            }
@@ -1533,6 +1590,16 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              || val != HOST_BITS_PER_WIDE_INT - 1))
        return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
 
+      /* Likewise for multipliers wider than a word.  */
+      else if (GET_CODE (trueop1) == CONST_DOUBLE
+              && (GET_MODE (trueop1) == VOIDmode
+                  || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
+              && GET_MODE (op0) == mode
+              && CONST_DOUBLE_LOW (trueop1) == 0
+              && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
+       return simplify_gen_binary (ASHIFT, mode, op0,
+                                   GEN_INT (val + HOST_BITS_PER_WIDE_INT));
+
       /* x*2 is x+x and x*(-1) is -x */
       if (GET_CODE (trueop1) == CONST_DOUBLE
          && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT
@@ -1572,7 +1639,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
           || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
          && ! side_effects_p (op0)
-         && GET_MODE_CLASS (mode) != MODE_CC)
+         && SCALAR_INT_MODE_P (mode))
        return constm1_rtx;
       tem = simplify_associative_operation (code, mode, op0, op1);
       if (tem)
@@ -1589,7 +1656,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       if (trueop0 == trueop1
          && ! side_effects_p (op0)
          && GET_MODE_CLASS (mode) != MODE_CC)
-       return const0_rtx;
+        return CONST0_RTX (mode);
 
       /* Canonicalize XOR of the most significant bit to PLUS.  */
       if ((GET_CODE (op1) == CONST_INT
@@ -1613,8 +1680,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       break;
 
     case AND:
-      if (trueop1 == const0_rtx && ! side_effects_p (op0))
-       return const0_rtx;
+      if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
+       return trueop1;
       /* If we are turning off bits already known off in OP0, we need
         not do an AND.  */
       if (GET_CODE (trueop1) == CONST_INT
@@ -1629,7 +1696,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
           || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
          && ! side_effects_p (op0)
          && GET_MODE_CLASS (mode) != MODE_CC)
-       return const0_rtx;
+       return CONST0_RTX (mode);
 
       /* Transform (and (extend X) C) into (zero_extend (and X C)) if
         there are no nonzero bits of C outside of X's mode.  */
@@ -1700,26 +1767,20 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
     case UDIV:
       /* 0/x is 0 (or x&0 if x has side-effects).  */
-      if (trueop0 == const0_rtx)
-       return side_effects_p (op1)
-         ? simplify_gen_binary (AND, mode, op1, const0_rtx)
-         : const0_rtx;
-         /* x/1 is x.  */
-         if (trueop1 == const1_rtx)
-           {
-             /* Handle narrowing UDIV.  */
-             rtx x = gen_lowpart_common (mode, op0);
-             if (x)
-               return x;
-             if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
-               return gen_lowpart_SUBREG (mode, op0);
-             return op0;
-           }
-         /* Convert divide by power of two into shift.  */
-         if (GET_CODE (trueop1) == CONST_INT
-             && (val = exact_log2 (INTVAL (trueop1))) > 0)
-           return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val));
-         break;
+      if (trueop0 == CONST0_RTX (mode))
+       {
+         if (side_effects_p (op1))
+           return simplify_gen_binary (AND, mode, op1, trueop0);
+         return trueop0;
+       }
+      /* x/1 is x.  */
+      if (trueop1 == CONST1_RTX (mode))
+       return rtl_hooks.gen_lowpart_no_emit (mode, op0);
+      /* Convert divide by power of two into shift.  */
+      if (GET_CODE (trueop1) == CONST_INT
+         && (val = exact_log2 (INTVAL (trueop1))) > 0)
+       return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val));
+      break;
 
     case DIV:
       /* Handle floating point and integers separately.  */
@@ -1764,28 +1825,19 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       else
        {
          /* 0/x is 0 (or x&0 if x has side-effects).  */
-         if (trueop0 == const0_rtx)
-           return side_effects_p (op1)
-             ? simplify_gen_binary (AND, mode, op1, const0_rtx)
-             : const0_rtx;
-         /* x/1 is x.  */
-         if (trueop1 == const1_rtx)
+         if (trueop0 == CONST0_RTX (mode))
            {
-             /* Handle narrowing DIV.  */
-             rtx x = gen_lowpart_common (mode, op0);
-             if (x)
-               return x;
-             if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
-               return gen_lowpart_SUBREG (mode, op0);
-             return op0;
+             if (side_effects_p (op1))
+               return simplify_gen_binary (AND, mode, op1, trueop0);
+             return trueop0;
            }
+         /* x/1 is x.  */
+         if (trueop1 == CONST1_RTX (mode))
+           return rtl_hooks.gen_lowpart_no_emit (mode, op0);
          /* x/-1 is -x.  */
          if (trueop1 == constm1_rtx)
            {
-             rtx x = gen_lowpart_common (mode, op0);
-             if (!x)
-               x = (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
-                 ? gen_lowpart_SUBREG (mode, op0) : op0;
+             rtx x = rtl_hooks.gen_lowpart_no_emit (mode, op0);
              return simplify_gen_unary (NEG, mode, x, mode);
            }
        }
@@ -1793,34 +1845,42 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
     case UMOD:
       /* 0%x is 0 (or x&0 if x has side-effects).  */
-      if (trueop0 == const0_rtx)
-       return side_effects_p (op1)
-         ? simplify_gen_binary (AND, mode, op1, const0_rtx)
-         : const0_rtx;
-         /* x%1 is 0 (of x&0 if x has side-effects).  */
-         if (trueop1 == const1_rtx)
-           return side_effects_p (op0)
-             ? simplify_gen_binary (AND, mode, op0, const0_rtx)
-             : const0_rtx;
-         /* Implement modulus by power of two as AND.  */
-         if (GET_CODE (trueop1) == CONST_INT
-             && exact_log2 (INTVAL (trueop1)) > 0)
-           return simplify_gen_binary (AND, mode, op0,
-                                       GEN_INT (INTVAL (op1) - 1));
-         break;
+      if (trueop0 == CONST0_RTX (mode))
+       {
+         if (side_effects_p (op1))
+           return simplify_gen_binary (AND, mode, op1, trueop0);
+         return trueop0;
+       }
+      /* x%1 is 0 (of x&0 if x has side-effects).  */
+      if (trueop1 == CONST1_RTX (mode))
+       {
+         if (side_effects_p (op0))
+           return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
+         return CONST0_RTX (mode);
+       }
+      /* Implement modulus by power of two as AND.  */
+      if (GET_CODE (trueop1) == CONST_INT
+         && exact_log2 (INTVAL (trueop1)) > 0)
+       return simplify_gen_binary (AND, mode, op0,
+                                   GEN_INT (INTVAL (op1) - 1));
+      break;
 
     case MOD:
       /* 0%x is 0 (or x&0 if x has side-effects).  */
-      if (trueop0 == const0_rtx)
-       return side_effects_p (op1)
-         ? simplify_gen_binary (AND, mode, op1, const0_rtx)
-         : const0_rtx;
-         /* x%1 and x%-1 is 0 (or x&0 if x has side-effects).  */
-         if (trueop1 == const1_rtx || trueop1 == constm1_rtx)
-           return side_effects_p (op0)
-             ? simplify_gen_binary (AND, mode, op0, const0_rtx)
-             : const0_rtx;
-         break;
+      if (trueop0 == CONST0_RTX (mode))
+       {
+         if (side_effects_p (op1))
+           return simplify_gen_binary (AND, mode, op1, trueop0);
+         return trueop0;
+       }
+      /* x%1 and x%-1 is 0 (or x&0 if x has side-effects).  */
+      if (trueop1 == CONST1_RTX (mode) || trueop1 == constm1_rtx)
+       {
+         if (side_effects_p (op0))
+           return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
+         return CONST0_RTX (mode);
+       }
+      break;
 
     case ROTATERT:
     case ROTATE:
@@ -1835,9 +1895,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
     case ASHIFT:
     case LSHIFTRT:
-      if (trueop1 == const0_rtx)
+      if (trueop1 == CONST0_RTX (mode))
        return op0;
-      if (trueop0 == const0_rtx && ! side_effects_p (op1))
+      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
        return op0;
       break;
 
@@ -1869,7 +1929,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       break;
 
     case UMIN:
-      if (trueop1 == const0_rtx && ! side_effects_p (op0))
+      if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
        return op1;
       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
        return op0;
@@ -2491,8 +2551,7 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
          gcc_unreachable ();
        }
 
-      val = trunc_int_for_mode (val, mode);
-      return GEN_INT (val);
+      return gen_int_mode (val, mode);
     }
 
   return NULL_RTX;
@@ -2885,7 +2944,7 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
          /* If op0 is a comparison, extract the comparison arguments form it.  */
          if (code == NE)
            {
-             if (GET_MODE (op0) == cmp_mode)
+             if (GET_MODE (op0) == mode)
                return simplify_rtx (op0);
              else
                return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,