OSDN Git Service

Merge remote-tracking branch 'gnu/gcc-4_6-branch' into rework
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 323633e..743f72c 100644 (file)
@@ -1,7 +1,7 @@
 /* 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, 2009, 2010
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #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"
@@ -188,7 +188,8 @@ avoid_constant_pool_reference (rtx x)
       /* 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))
+      if ((offset != 0 || cmode != GET_MODE (x))
+         && offset >= 0 && offset < GET_MODE_SIZE (cmode))
         {
           rtx tem = simplify_subreg (GET_MODE (x), c, cmode, offset);
           if (tem && CONSTANT_P (tem))
@@ -208,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);
@@ -264,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);
 
@@ -686,13 +687,13 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1));
        }
 
-      /* (neg (mult A B)) becomes (mult (neg A) B).
+      /* (neg (mult A B)) becomes (mult A (neg 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));
+         temp = simplify_gen_unary (NEG, mode, XEXP (op, 1), mode);
+         return simplify_gen_binary (MULT, mode, XEXP (op, 0), temp);
        }
 
       /* NEG commutes with ASHIFT since it is multiplication.  Only do
@@ -812,7 +813,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          than HOST_BITS_PER_WIDE_INT.  */
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && COMPARISON_P (op)
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
+         && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
        return rtl_hooks.gen_lowpart_no_emit (mode, op);
       break;
 
@@ -911,7 +912,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          || ((GET_MODE_BITSIZE (GET_MODE (op))
               <= HOST_BITS_PER_WIDE_INT)
              && ((nonzero_bits (op, GET_MODE (op))
-                  & ((HOST_WIDE_INT) 1
+                  & ((unsigned HOST_WIDE_INT) 1
                      << (GET_MODE_BITSIZE (GET_MODE (op)) - 1)))
                  == 0)))
        return op;
@@ -1009,6 +1010,42 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
        return rtl_hooks.gen_lowpart_no_emit (mode, op);
 
+      /* (sign_extend:M (sign_extend:N <X>)) is (sign_extend:M <X>).
+        (sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>).  */
+      if (GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND)
+       {
+         gcc_assert (GET_MODE_BITSIZE (mode)
+                     > GET_MODE_BITSIZE (GET_MODE (op)));
+         return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0),
+                                    GET_MODE (XEXP (op, 0)));
+       }
+
+      /* (sign_extend:M (ashiftrt:N (ashift <X> (const_int I)) (const_int I)))
+        is (sign_extend:M (subreg:O <X>)) if there is mode with
+        GET_MODE_BITSIZE (N) - I bits.
+        (sign_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
+        is similarly (zero_extend:M (subreg:O <X>)).  */
+      if ((GET_CODE (op) == ASHIFTRT || GET_CODE (op) == LSHIFTRT)
+         && GET_CODE (XEXP (op, 0)) == ASHIFT
+         && CONST_INT_P (XEXP (op, 1))
+         && XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
+         && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
+       {
+         enum machine_mode tmode
+           = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
+                            - INTVAL (XEXP (op, 1)), MODE_INT, 1);
+         gcc_assert (GET_MODE_BITSIZE (mode)
+                     > GET_MODE_BITSIZE (GET_MODE (op)));
+         if (tmode != BLKmode)
+           {
+             rtx inner =
+               rtl_hooks.gen_lowpart_no_emit (tmode, XEXP (XEXP (op, 0), 0));
+             return simplify_gen_unary (GET_CODE (op) == ASHIFTRT
+                                        ? SIGN_EXTEND : ZERO_EXTEND,
+                                        mode, inner, tmode);
+           }
+       }
+
 #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       /* As we do not know which address space the pointer is refering to,
         we can do this only if the target does not support different pointer
@@ -1035,6 +1072,31 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
        return rtl_hooks.gen_lowpart_no_emit (mode, op);
 
+      /* (zero_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>).  */
+      if (GET_CODE (op) == ZERO_EXTEND)
+       return simplify_gen_unary (ZERO_EXTEND, mode, XEXP (op, 0),
+                                  GET_MODE (XEXP (op, 0)));
+
+      /* (zero_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
+        is (zero_extend:M (subreg:O <X>)) if there is mode with
+        GET_MODE_BITSIZE (N) - I bits.  */
+      if (GET_CODE (op) == LSHIFTRT
+         && GET_CODE (XEXP (op, 0)) == ASHIFT
+         && CONST_INT_P (XEXP (op, 1))
+         && XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
+         && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
+       {
+         enum machine_mode tmode
+           = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
+                            - INTVAL (XEXP (op, 1)), MODE_INT, 1);
+         if (tmode != BLKmode)
+           {
+             rtx inner =
+               rtl_hooks.gen_lowpart_no_emit (tmode, XEXP (XEXP (op, 0), 0));
+             return simplify_gen_unary (ZERO_EXTEND, mode, inner, tmode);
+           }
+       }
+
 #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       /* As we do not know which address space the pointer is refering to,
         we can do this only if the target does not support different pointer
@@ -1196,10 +1258,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:
@@ -1220,7 +1280,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:
@@ -1270,7 +1330,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
              val = arg0;
            }
          else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-           val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
+           val = arg0 & ~((unsigned HOST_WIDE_INT) (-1)
+                          << GET_MODE_BITSIZE (op_mode));
          else
            return 0;
          break;
@@ -1289,10 +1350,12 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
            {
              val
-               = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
-             if (val
-                 & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
-               val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
+               = arg0 & ~((unsigned HOST_WIDE_INT) (-1)
+                          << GET_MODE_BITSIZE (op_mode));
+             if (val & ((unsigned HOST_WIDE_INT) 1
+                        << (GET_MODE_BITSIZE (op_mode) - 1)))
+               val
+                 -= (unsigned HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
            }
          else
            return 0;
@@ -1350,15 +1413,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:
@@ -1375,9 +1435,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;
@@ -1448,9 +1508,9 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
            {
              lv = l1 & GET_MODE_MASK (op_mode);
              if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
-                 && (lv & ((HOST_WIDE_INT) 1
+                 && (lv & ((unsigned HOST_WIDE_INT) 1
                            << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
-               lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
+               lv -= (unsigned HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
 
              hv = HWI_SIGN_EXTEND (lv);
            }
@@ -1467,7 +1527,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
     }
 
   else if (GET_CODE (op) == CONST_DOUBLE
-          && SCALAR_FLOAT_MODE_P (mode))
+          && SCALAR_FLOAT_MODE_P (mode)
+          && SCALAR_FLOAT_MODE_P (GET_MODE (op)))
     {
       REAL_VALUE_TYPE d, t;
       REAL_VALUE_FROM_CONST_DOUBLE (d, op);
@@ -1481,16 +1542,19 @@ 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);
          break;
        case FLOAT_EXTEND:
-         /* All this does is change the mode.  */
+         /* All this does is change the mode, unless changing
+            mode class.  */
+         if (GET_MODE_CLASS (mode) != GET_MODE_CLASS (GET_MODE (op)))
+           real_convert (&d, mode, &d);
          break;
        case FIX:
          real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
@@ -1556,13 +1620,14 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          /* Test against the signed lower bound.  */
          if (width > HOST_BITS_PER_WIDE_INT)
            {
-             th = (HOST_WIDE_INT) -1 << (width - HOST_BITS_PER_WIDE_INT - 1);
+             th = (unsigned HOST_WIDE_INT) (-1)
+                  << (width - HOST_BITS_PER_WIDE_INT - 1);
              tl = 0;
            }
          else
            {
              th = -1;
-             tl = (HOST_WIDE_INT) -1 << (width - 1);
+             tl = (unsigned HOST_WIDE_INT) (-1) << (width - 1);
            }
          real_from_integer (&t, VOIDmode, tl, th, 0);
          if (REAL_VALUES_LESS (x, t))
@@ -2108,6 +2173,41 @@ 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 op1 is a MULT as well and simplify_unary_operation
+            just moved the NEG to the second operand, simplify_gen_binary
+            below could through simplify_associative_operation move
+            the NEG around again and recurse endlessly.  */
+         if (temp
+             && GET_CODE (op1) == MULT
+             && GET_CODE (temp) == MULT
+             && XEXP (op1, 0) == XEXP (temp, 0)
+             && GET_CODE (XEXP (temp, 1)) == NEG
+             && XEXP (op1, 1) == XEXP (XEXP (temp, 1), 0))
+           temp = NULL_RTX;
+         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 op0 is a MULT as well and simplify_unary_operation
+            just moved the NEG to the second operand, simplify_gen_binary
+            below could through simplify_associative_operation move
+            the NEG around again and recurse endlessly.  */
+         if (temp
+             && GET_CODE (op0) == MULT
+             && GET_CODE (temp) == MULT
+             && XEXP (op0, 0) == XEXP (temp, 0)
+             && GET_CODE (XEXP (temp, 1)) == NEG
+             && XEXP (op0, 1) == XEXP (XEXP (temp, 1), 0))
+           temp = NULL_RTX;
+         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
@@ -2127,7 +2227,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       /* Convert multiply by constant power of two into shift unless
         we are still generating RTL.  This test is a kludge.  */
       if (CONST_INT_P (trueop1)
-         && (val = exact_log2 (INTVAL (trueop1))) >= 0
+         && (val = exact_log2 (UINTVAL (trueop1))) >= 0
          /* If the mode is larger than the host word size, and the
             uppermost bit is set, then this isn't a power of two due
             to implicit sign extension.  */
@@ -2190,10 +2290,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       break;
 
     case IOR:
-      if (trueop1 == const0_rtx)
+      if (trueop1 == CONST0_RTX (mode))
        return op0;
       if (CONST_INT_P (trueop1)
-         && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
+         && ((UINTVAL (trueop1) & GET_MODE_MASK (mode))
              == GET_MODE_MASK (mode)))
        return op1;
       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
@@ -2208,7 +2308,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
       if (CONST_INT_P (op1)
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
+         && (nonzero_bits (op0, mode) & ~UINTVAL (op1)) == 0)
        return op1;
 
       /* Canonicalize (X & C1) | C2.  */
@@ -2297,12 +2397,12 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && GET_CODE (op0) == AND
          && CONST_INT_P (XEXP (op0, 1))
          && CONST_INT_P (op1)
-         && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
+         && (UINTVAL (XEXP (op0, 1)) & UINTVAL (op1)) != 0)
        return simplify_gen_binary (IOR, mode,
                                    simplify_gen_binary
                                          (AND, mode, XEXP (op0, 0),
-                                          GEN_INT (INTVAL (XEXP (op0, 1))
-                                                   & ~INTVAL (op1))),
+                                          GEN_INT (UINTVAL (XEXP (op0, 1))
+                                                   & ~UINTVAL (op1))),
                                    op1);
 
       /* If OP0 is (ashiftrt (plus ...) C), it might actually be
@@ -2332,10 +2432,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       break;
 
     case XOR:
-      if (trueop1 == const0_rtx)
+      if (trueop1 == CONST0_RTX (mode))
        return op0;
       if (CONST_INT_P (trueop1)
-         && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
+         && ((UINTVAL (trueop1) & GET_MODE_MASK (mode))
              == GET_MODE_MASK (mode)))
        return simplify_gen_unary (NOT, mode, op0, mode);
       if (rtx_equal_p (trueop0, trueop1)
@@ -2479,7 +2579,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && CONST_INT_P (trueop1)
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
-             & INTVAL (trueop1)) == 0)
+             & UINTVAL (trueop1)) == 0)
        {
          enum machine_mode imode = GET_MODE (XEXP (op0, 0));
          tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
@@ -2560,8 +2660,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
         (A +- N) & M -> A & M.  */
       if (CONST_INT_P (trueop1)
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && ~INTVAL (trueop1)
-         && (INTVAL (trueop1) & (INTVAL (trueop1) + 1)) == 0
+         && ~UINTVAL (trueop1)
+         && (UINTVAL (trueop1) & (UINTVAL (trueop1) + 1)) == 0
          && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS))
        {
          rtx pmop[2];
@@ -2571,7 +2671,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          pmop[1] = XEXP (op0, 1);
 
          if (CONST_INT_P (pmop[1])
-             && (INTVAL (pmop[1]) & INTVAL (trueop1)) == 0)
+             && (UINTVAL (pmop[1]) & UINTVAL (trueop1)) == 0)
            return simplify_gen_binary (AND, mode, pmop[0], op1);
 
          for (which = 0; which < 2; which++)
@@ -2581,14 +2681,14 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                {
                case AND:
                  if (CONST_INT_P (XEXP (tem, 1))
-                     && (INTVAL (XEXP (tem, 1)) & INTVAL (trueop1))
-                     == INTVAL (trueop1))
+                     && (UINTVAL (XEXP (tem, 1)) & UINTVAL (trueop1))
+                     == UINTVAL (trueop1))
                    pmop[which] = XEXP (tem, 0);
                  break;
                case IOR:
                case XOR:
                  if (CONST_INT_P (XEXP (tem, 1))
-                     && (INTVAL (XEXP (tem, 1)) & INTVAL (trueop1)) == 0)
+                     && (UINTVAL (XEXP (tem, 1)) & UINTVAL (trueop1)) == 0)
                    pmop[which] = XEXP (tem, 0);
                  break;
                default:
@@ -2634,7 +2734,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
        return rtl_hooks.gen_lowpart_no_emit (mode, op0);
       /* Convert divide by power of two into shift.  */
       if (CONST_INT_P (trueop1)
-         && (val = exact_log2 (INTVAL (trueop1))) > 0)
+         && (val = exact_log2 (UINTVAL (trueop1))) > 0)
        return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val));
       break;
 
@@ -2678,10 +2778,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                }
            }
        }
-      else
+      else if (SCALAR_INT_MODE_P (mode))
        {
          /* 0/x is 0 (or x&0 if x has side-effects).  */
-         if (trueop0 == CONST0_RTX (mode))
+         if (trueop0 == CONST0_RTX (mode)
+             && !cfun->can_throw_non_call_exceptions)
            {
              if (side_effects_p (op1))
                return simplify_gen_binary (AND, mode, op1, trueop0);
@@ -2716,7 +2817,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
        }
       /* Implement modulus by power of two as AND.  */
       if (CONST_INT_P (trueop1)
-         && exact_log2 (INTVAL (trueop1)) > 0)
+         && exact_log2 (UINTVAL (trueop1)) > 0)
        return simplify_gen_binary (AND, mode, op0,
                                    GEN_INT (INTVAL (op1) - 1));
       break;
@@ -2747,7 +2848,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
        return op0;
       /* Rotating ~0 always results in ~0.  */
       if (CONST_INT_P (trueop0) && width <= HOST_BITS_PER_WIDE_INT
-         && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode)
+         && UINTVAL (trueop0) == GET_MODE_MASK (mode)
          && ! side_effects_p (op1))
        return op0;
     canonicalize_shift:
@@ -2793,7 +2894,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case SMIN:
       if (width <= HOST_BITS_PER_WIDE_INT
          && CONST_INT_P (trueop1)
-         && INTVAL (trueop1) == (HOST_WIDE_INT) 1 << (width -1)
+         && UINTVAL (trueop1) == (unsigned HOST_WIDE_INT) 1 << (width -1)
          && ! side_effects_p (op0))
        return op1;
       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
@@ -2806,8 +2907,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case SMAX:
       if (width <= HOST_BITS_PER_WIDE_INT
          && CONST_INT_P (trueop1)
-         && ((unsigned HOST_WIDE_INT) INTVAL (trueop1)
-             == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
+         && (UINTVAL (trueop1) == GET_MODE_MASK (mode) >> 1)
          && ! side_effects_p (op0))
        return op1;
       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
@@ -3268,141 +3368,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)
@@ -3416,16 +3499,16 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
       if (width < HOST_BITS_PER_WIDE_INT)
         {
-          arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
-          arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
+          arg0 &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+          arg1 &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
 
           arg0s = arg0;
-          if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
-           arg0s |= ((HOST_WIDE_INT) (-1) << width);
+          if (arg0s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
+           arg0s |= ((unsigned HOST_WIDE_INT) (-1) << width);
 
          arg1s = arg1;
-         if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
-           arg1s |= ((HOST_WIDE_INT) (-1) << width);
+         if (arg1s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
+           arg1s |= ((unsigned HOST_WIDE_INT) (-1) << width);
        }
       else
        {
@@ -3451,7 +3534,8 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
        case DIV:
          if (arg1s == 0
-             || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
+             || ((unsigned HOST_WIDE_INT) arg0s
+                 == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
                  && arg1s == -1))
            return 0;
          val = arg0s / arg1s;
@@ -3459,7 +3543,8 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
        case MOD:
          if (arg1s == 0
-             || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
+             || ((unsigned HOST_WIDE_INT) arg0s
+                 == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
                  && arg1s == -1))
            return 0;
          val = arg0s % arg1s;
@@ -3467,7 +3552,8 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
        case UDIV:
          if (arg1 == 0
-             || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
+             || ((unsigned HOST_WIDE_INT) arg0s
+                 == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
                  && arg1s == -1))
            return 0;
          val = (unsigned HOST_WIDE_INT) arg0 / arg1;
@@ -3475,7 +3561,8 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
        case UMOD:
          if (arg1 == 0
-             || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
+             || ((unsigned HOST_WIDE_INT) arg0s
+                 == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
                  && arg1s == -1))
            return 0;
          val = (unsigned HOST_WIDE_INT) arg0 % arg1;
@@ -3514,7 +3601,7 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
          /* Sign-extend the result for arithmetic right shifts.  */
          if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-           val |= ((HOST_WIDE_INT) -1) << (width - arg1);
+           val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
          break;
 
        case ROTATERT:
@@ -4091,10 +4178,20 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
     {
       rtx x = XEXP (op0, 0);
       rtx c = XEXP (op0, 1);
+      enum rtx_code invcode = op0code == PLUS ? MINUS : PLUS;
+      rtx tem = simplify_gen_binary (invcode, cmp_mode, op1, c);
+
+      /* Detect an infinite recursive condition, where we oscillate at this
+        simplification case between:
+           A + B == C  <--->  C - B == A,
+        where A, B, and C are all constants with non-simplifiable expressions,
+        usually SYMBOL_REFs.  */
+      if (GET_CODE (tem) == invcode
+         && CONSTANT_P (x)
+         && rtx_equal_p (c, XEXP (tem, 1)))
+       return NULL_RTX;
 
-      c = simplify_gen_binary (op0code == PLUS ? MINUS : PLUS,
-                              cmp_mode, op1, c);
-      return simplify_gen_relational (code, mode, cmp_mode, x, c);
+      return simplify_gen_relational (code, mode, cmp_mode, x, tem);
     }
 
   /* (ne:SI (zero_extract:SI FOO (const_int 1) BAR) (const_int 0))) is
@@ -4394,14 +4491,14 @@ simplify_const_relational_operation (enum rtx_code code,
         we have to sign or zero-extend the values.  */
       if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
        {
-         l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
-         l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
+         l0u &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+         l1u &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
 
-         if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
-           l0s |= ((HOST_WIDE_INT) (-1) << width);
+         if (l0s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
+           l0s |= ((unsigned HOST_WIDE_INT) (-1) << width);
 
-         if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
-           l1s |= ((HOST_WIDE_INT) (-1) << width);
+         if (l1s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
+           l1s |= ((unsigned HOST_WIDE_INT) (-1) << width);
        }
       if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
        h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
@@ -4554,8 +4651,9 @@ simplify_const_relational_operation (enum rtx_code code,
            {
              int sign_bitnum = GET_MODE_BITSIZE (mode) - 1;
              int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
-                             && (INTVAL (inner_const)
-                                 & ((HOST_WIDE_INT) 1 << sign_bitnum)));
+                             && (UINTVAL (inner_const)
+                                 & ((unsigned HOST_WIDE_INT) 1
+                                    << sign_bitnum)));
 
              switch (code)
                {
@@ -4644,6 +4742,8 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
                            rtx op2)
 {
   unsigned int width = GET_MODE_BITSIZE (mode);
+  bool any_change = false;
+  rtx tem;
 
   /* VOIDmode means "infinite" precision.  */
   if (width == 0)
@@ -4651,6 +4751,31 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
 
   switch (code)
     {
+    case FMA:
+      /* Simplify negations around the multiplication.  */
+      /* -a * -b + c  =>  a * b + c.  */
+      if (GET_CODE (op0) == NEG)
+       {
+         tem = simplify_unary_operation (NEG, mode, op1, mode);
+         if (tem)
+           op1 = tem, op0 = XEXP (op0, 0), any_change = true;
+       }
+      else if (GET_CODE (op1) == NEG)
+       {
+         tem = simplify_unary_operation (NEG, mode, op0, mode);
+         if (tem)
+           op0 = tem, op1 = XEXP (op1, 0), any_change = true;
+       }
+
+      /* Canonicalize the two multiplication operands.  */
+      /* a * -b + c  =>  -b * a + c.  */
+      if (swap_commutative_operands_p (op0, op1))
+       tem = op0, op0 = op1, op1 = tem, any_change = true;
+
+      if (any_change)
+       return gen_rtx_FMA (mode, op0, op1, op2);
+      return NULL_RTX;
+
     case SIGN_EXTRACT:
     case ZERO_EXTRACT:
       if (CONST_INT_P (op0)
@@ -4660,22 +4785,22 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
          && width <= (unsigned) HOST_BITS_PER_WIDE_INT)
        {
          /* Extracting a bit-field from a constant */
-         HOST_WIDE_INT val = INTVAL (op0);
+         unsigned HOST_WIDE_INT val = UINTVAL (op0);
 
          if (BITS_BIG_ENDIAN)
-           val >>= (GET_MODE_BITSIZE (op0_mode)
-                    - INTVAL (op2) - INTVAL (op1));
+           val >>= GET_MODE_BITSIZE (op0_mode) - INTVAL (op2) - INTVAL (op1);
          else
            val >>= INTVAL (op2);
 
          if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
            {
              /* First zero-extend.  */
-             val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
+             val &= ((unsigned HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
              /* If desired, propagate sign bit.  */
              if (code == SIGN_EXTRACT
-                 && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
-               val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
+                 && (val & ((unsigned HOST_WIDE_INT) 1 << (INTVAL (op1) - 1)))
+                    != 0)
+               val |= ~ (((unsigned HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
            }
 
          /* Clear the bits that don't belong in our mode,
@@ -4683,9 +4808,9 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
             So we get either a reasonable negative value or a reasonable
             unsigned value for this mode.  */
          if (width < HOST_BITS_PER_WIDE_INT
-             && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-                 != ((HOST_WIDE_INT) (-1) << (width - 1))))
-           val &= ((HOST_WIDE_INT) 1 << width) - 1;
+             && ((val & ((unsigned HOST_WIDE_INT) (-1) << (width - 1)))
+                 != ((unsigned HOST_WIDE_INT) (-1) << (width - 1))))
+           val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
 
          return gen_int_mode (val, mode);
        }
@@ -5043,10 +5168,10 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
            for (i = 0;
                 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
                 i += value_bit)
-             lo |= (HOST_WIDE_INT)(*vp++ & value_mask) << i;
+             lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
            for (; i < elem_bitsize; i += value_bit)
-             hi |= ((HOST_WIDE_INT)(*vp++ & value_mask)
-                    << (i - HOST_BITS_PER_WIDE_INT));
+             hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
+                    << (i - HOST_BITS_PER_WIDE_INT);
 
            /* immed_double_const doesn't call trunc_int_for_mode.  I don't
               know why.  */
@@ -5099,9 +5224,9 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
            for (i = 0;
                 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
                 i += value_bit)
-             f.data.low |= (HOST_WIDE_INT)(*vp++ & value_mask) << i;
+             f.data.low |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
            for (; i < elem_bitsize; i += value_bit)
-             f.data.high |= ((HOST_WIDE_INT)(*vp++ & value_mask)
+             f.data.high |= ((unsigned HOST_WIDE_INT)(*vp++ & value_mask)
                             << (i - HOST_BITS_PER_WIDE_INT));
 
            elems[elem] = CONST_FIXED_FROM_FIXED_VALUE (f, outer_submode);
@@ -5429,6 +5554,31 @@ simplify_subreg (enum machine_mode outermode, rtx op,
                                   : byte + shifted_bytes));
     }
 
+  /* If we have a lowpart SUBREG of a right shift of MEM, make a new MEM
+     and try replacing the SUBREG and shift with it.  Don't do this if
+     the MEM has a mode-dependent address or if we would be widening it.  */
+
+  if ((GET_CODE (op) == LSHIFTRT
+       || GET_CODE (op) == ASHIFTRT)
+      && MEM_P (XEXP (op, 0))
+      && CONST_INT_P (XEXP (op, 1))
+      && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (GET_MODE (op))
+      && (INTVAL (XEXP (op, 1)) % GET_MODE_BITSIZE (outermode)) == 0
+      && INTVAL (XEXP (op, 1)) > 0
+      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (innermode)
+      && ! mode_dependent_address_p (XEXP (XEXP (op, 0), 0))
+      && ! MEM_VOLATILE_P (XEXP (op, 0))
+      && byte == subreg_lowpart_offset (outermode, innermode)
+      && (GET_MODE_SIZE (outermode) >= UNITS_PER_WORD
+         || WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN))
+    {
+      int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
+      return adjust_address_nv (XEXP (op, 0), outermode,
+                               (WORDS_BIG_ENDIAN
+                                ? byte - shifted_bytes
+                                : byte + shifted_bytes));
+    }
+
   return NULL_RTX;
 }