]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lower-subreg.c
rs6000: New iterator CCEITHER
[thirdparty/gcc.git] / gcc / lower-subreg.c
index e67bc35648bceb039eef1959d50a491f3c9b7875..4f68a7381b750fe160bb5436b2601d4ec572cc7c 100644 (file)
@@ -1,5 +1,5 @@
 /* Decompose multiword subregs.
-   Copyright (C) 2007-2013 Free Software Foundation, Inc.
+   Copyright (C) 2007-2019 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>
                  Ian Lance Taylor <iant@google.com>
 
@@ -22,31 +22,25 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "machmode.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
 #include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "memmodel.h"
 #include "tm_p.h"
-#include "flags.h"
+#include "expmed.h"
 #include "insn-config.h"
-#include "obstack.h"
-#include "basic-block.h"
+#include "emit-rtl.h"
 #include "recog.h"
-#include "bitmap.h"
+#include "cfgrtl.h"
+#include "cfgbuild.h"
 #include "dce.h"
 #include "expr.h"
-#include "except.h"
-#include "regs.h"
 #include "tree-pass.h"
-#include "df.h"
 #include "lower-subreg.h"
-
-#ifdef STACK_GROWS_DOWNWARD
-# undef STACK_GROWS_DOWNWARD
-# define STACK_GROWS_DOWNWARD 1
-#else
-# define STACK_GROWS_DOWNWARD 0
-#endif
+#include "rtl-iter.h"
+#include "target.h"
 
 
 /* Decompose multi-word pseudo-registers into individual
@@ -85,7 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 static bitmap decomposable_context;
 
 /* Bit N in this bitmap is set if regno N is used in a context in
-   which it can not be decomposed.  */
+   which it cannot be decomposed.  */
 static bitmap non_decomposable_context;
 
 /* Bit N in this bitmap is set if regno N is used in a subreg
@@ -109,6 +103,19 @@ struct target_lower_subreg *this_target_lower_subreg
 #define choices \
   this_target_lower_subreg->x_choices
 
+/* Return true if MODE is a mode we know how to lower.  When returning true,
+   store its byte size in *BYTES and its word size in *WORDS.  */
+
+static inline bool
+interesting_mode_p (machine_mode mode, unsigned int *bytes,
+                   unsigned int *words)
+{
+  if (!GET_MODE_SIZE (mode).is_constant (bytes))
+    return false;
+  *words = CEIL (*bytes, UNITS_PER_WORD);
+  return true;
+}
+
 /* RTXes used while computing costs.  */
 struct cost_rtxes {
   /* Source and target registers.  */
@@ -130,13 +137,13 @@ struct cost_rtxes {
 
 static int
 shift_cost (bool speed_p, struct cost_rtxes *rtxes, enum rtx_code code,
-           enum machine_mode mode, int op1)
+           machine_mode mode, int op1)
 {
   PUT_CODE (rtxes->shift, code);
   PUT_MODE (rtxes->shift, mode);
   PUT_MODE (rtxes->source, mode);
-  XEXP (rtxes->shift, 1) = GEN_INT (op1);
-  return set_src_cost (rtxes->shift, speed_p);
+  XEXP (rtxes->shift, 1) = gen_int_shift_amount (mode, op1);
+  return set_src_cost (rtxes->shift, mode, speed_p);
 }
 
 /* For each X in the range [0, BITS_PER_WORD), set SPLITTING[X]
@@ -204,11 +211,11 @@ compute_costs (bool speed_p, struct cost_rtxes *rtxes)
 
   for (i = 0; i < MAX_MACHINE_MODE; i++)
     {
-      enum machine_mode mode = (enum machine_mode) i;
-      int factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-      if (factor > 1)
+      machine_mode mode = (machine_mode) i;
+      unsigned int size, factor;
+      if (interesting_mode_p (mode, &size, &factor) && factor > 1)
        {
-         int mode_move_cost;
+         unsigned int mode_move_cost;
 
          PUT_MODE (rtxes->target, mode);
          PUT_MODE (rtxes->source, mode);
@@ -240,7 +247,7 @@ compute_costs (bool speed_p, struct cost_rtxes *rtxes)
       /* The only case here to check to see if moving the upper part with a
         zero is cheaper than doing the zext itself.  */
       PUT_MODE (rtxes->source, word_mode);
-      zext_cost = set_src_cost (rtxes->zext, speed_p);
+      zext_cost = set_src_cost (rtxes->zext, twice_word_mode, speed_p);
 
       if (LOG_COSTS)
        fprintf (stderr, "%s %s: original cost %d, split cost %d + %d\n",
@@ -273,11 +280,11 @@ init_lower_subreg (void)
 
   memset (this_target_lower_subreg, 0, sizeof (*this_target_lower_subreg));
 
-  twice_word_mode = GET_MODE_2XWIDER_MODE (word_mode);
+  twice_word_mode = GET_MODE_2XWIDER_MODE (word_mode).require ();
 
-  rtxes.target = gen_rtx_REG (word_mode, FIRST_PSEUDO_REGISTER);
-  rtxes.source = gen_rtx_REG (word_mode, FIRST_PSEUDO_REGISTER + 1);
-  rtxes.set = gen_rtx_SET (VOIDmode, rtxes.target, rtxes.source);
+  rtxes.target = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+  rtxes.source = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 2);
+  rtxes.set = gen_rtx_SET (rtxes.target, rtxes.source);
   rtxes.zext = gen_rtx_ZERO_EXTEND (twice_word_mode, rtxes.source);
   rtxes.shift = gen_rtx_ASHIFT (twice_word_mode, rtxes.source, const0_rtx);
 
@@ -313,6 +320,24 @@ simple_move_operand (rtx x)
   return true;
 }
 
+/* If X is an operator that can be treated as a simple move that we
+   can split, then return the operand that is operated on.  */
+
+static rtx
+operand_for_swap_move_operator (rtx x)
+{
+  /* A word sized rotate of a register pair is equivalent to swapping
+     the registers in the register pair.  */
+  if (GET_CODE (x) == ROTATE
+      && GET_MODE (x) == twice_word_mode
+      && simple_move_operand (XEXP (x, 0))
+      && CONST_INT_P (XEXP (x, 1))
+      && INTVAL (XEXP (x, 1)) == BITS_PER_WORD)
+    return XEXP (x, 0);
+
+  return NULL_RTX;
+}
+
 /* If INSN is a single set between two objects that we want to split,
    return the single set.  SPEED_P says whether we are optimizing
    INSN for speed or size.
@@ -321,11 +346,11 @@ simple_move_operand (rtx x)
    is called.  */
 
 static rtx
-simple_move (rtx insn, bool speed_p)
+simple_move (rtx_insn *insn, bool speed_p)
 {
-  rtx x;
+  rtx x, op;
   rtx set;
-  enum machine_mode mode;
+  machine_mode mode;
 
   if (recog_data.n_operands != 2)
     return NULL_RTX;
@@ -341,6 +366,9 @@ simple_move (rtx insn, bool speed_p)
     return NULL_RTX;
 
   x = SET_SRC (set);
+  if ((op = operand_for_swap_move_operator (x)) != NULL_RTX)
+    x = op;
+
   if (x != recog_data.operand[0] && x != recog_data.operand[1])
     return NULL_RTX;
   /* For the src we can handle ASM_OPERANDS, and it is beneficial for
@@ -356,8 +384,7 @@ simple_move (rtx insn, bool speed_p)
      size.  */
   mode = GET_MODE (SET_DEST (set));
   if (!SCALAR_INT_MODE_P (mode)
-      && (mode_for_size (GET_MODE_SIZE (mode) * BITS_PER_UNIT, MODE_INT, 0)
-         == BLKmode))
+      && !int_mode_for_size (GET_MODE_BITSIZE (mode), 0).exists ())
     return NULL_RTX;
 
   /* Reject PARTIAL_INT modes.  They are used for processor specific
@@ -380,9 +407,13 @@ find_pseudo_copy (rtx set)
 {
   rtx dest = SET_DEST (set);
   rtx src = SET_SRC (set);
+  rtx op;
   unsigned int rd, rs;
   bitmap b;
 
+  if ((op = operand_for_swap_move_operator (src)) != NULL_RTX)
+    src = op;
+
   if (!REG_P (dest) || !REG_P (src))
     return false;
 
@@ -412,10 +443,7 @@ find_pseudo_copy (rtx set)
 static void
 propagate_pseudo_copies (void)
 {
-  bitmap queue, propagate;
-
-  queue = BITMAP_ALLOC (NULL);
-  propagate = BITMAP_ALLOC (NULL);
+  auto_bitmap queue, propagate;
 
   bitmap_copy (queue, decomposable_context);
   do
@@ -436,13 +464,10 @@ propagate_pseudo_copies (void)
       bitmap_ior_into (decomposable_context, propagate);
     }
   while (!bitmap_empty_p (queue));
-
-  BITMAP_FREE (queue);
-  BITMAP_FREE (propagate);
 }
 
 /* A pointer to one of these values is passed to
-   find_decomposable_subregs via for_each_rtx.  */
+   find_decomposable_subregs.  */
 
 enum classify_move_insn
 {
@@ -454,120 +479,131 @@ enum classify_move_insn
   SIMPLE_MOVE
 };
 
-/* This is called via for_each_rtx.  If we find a SUBREG which we
-   could use to decompose a pseudo-register, set a bit in
-   DECOMPOSABLE_CONTEXT.  If we find an unadorned register which is
-   not a simple pseudo-register copy, DATA will point at the type of
-   move, and we set a bit in DECOMPOSABLE_CONTEXT or
-   NON_DECOMPOSABLE_CONTEXT as appropriate.  */
+/* If we find a SUBREG in *LOC which we could use to decompose a
+   pseudo-register, set a bit in DECOMPOSABLE_CONTEXT.  If we find an
+   unadorned register which is not a simple pseudo-register copy,
+   DATA will point at the type of move, and we set a bit in
+   DECOMPOSABLE_CONTEXT or NON_DECOMPOSABLE_CONTEXT as appropriate.  */
 
-static int
-find_decomposable_subregs (rtx *px, void *data)
+static void
+find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
 {
-  enum classify_move_insn *pcmi = (enum classify_move_insn *) data;
-  rtx x = *px;
-
-  if (x == NULL_RTX)
-    return 0;
-
-  if (GET_CODE (x) == SUBREG)
+  subrtx_var_iterator::array_type array;
+  FOR_EACH_SUBRTX_VAR (iter, array, *loc, NONCONST)
     {
-      rtx inner = SUBREG_REG (x);
-      unsigned int regno, outer_size, inner_size, outer_words, inner_words;
-
-      if (!REG_P (inner))
-       return 0;
-
-      regno = REGNO (inner);
-      if (HARD_REGISTER_NUM_P (regno))
-       return -1;
+      rtx x = *iter;
+      if (GET_CODE (x) == SUBREG)
+       {
+         rtx inner = SUBREG_REG (x);
+         unsigned int regno, outer_size, inner_size, outer_words, inner_words;
 
-      outer_size = GET_MODE_SIZE (GET_MODE (x));
-      inner_size = GET_MODE_SIZE (GET_MODE (inner));
-      outer_words = (outer_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
-      inner_words = (inner_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+         if (!REG_P (inner))
+           continue;
 
-      /* We only try to decompose single word subregs of multi-word
-        registers.  When we find one, we return -1 to avoid iterating
-        over the inner register.
+         regno = REGNO (inner);
+         if (HARD_REGISTER_NUM_P (regno))
+           {
+             iter.skip_subrtxes ();
+             continue;
+           }
 
-        ??? This doesn't allow, e.g., DImode subregs of TImode values
-        on 32-bit targets.  We would need to record the way the
-        pseudo-register was used, and only decompose if all the uses
-        were the same number and size of pieces.  Hopefully this
-        doesn't happen much.  */
+         if (!interesting_mode_p (GET_MODE (x), &outer_size, &outer_words)
+             || !interesting_mode_p (GET_MODE (inner), &inner_size,
+                                     &inner_words))
+           continue;
 
-      if (outer_words == 1 && inner_words > 1)
-       {
-         bitmap_set_bit (decomposable_context, regno);
-         return -1;
-       }
+         /* We only try to decompose single word subregs of multi-word
+            registers.  When we find one, we return -1 to avoid iterating
+            over the inner register.
+
+            ??? This doesn't allow, e.g., DImode subregs of TImode values
+            on 32-bit targets.  We would need to record the way the
+            pseudo-register was used, and only decompose if all the uses
+            were the same number and size of pieces.  Hopefully this
+            doesn't happen much.  */
+
+         if (outer_words == 1
+             && inner_words > 1
+             /* Don't allow to decompose floating point subregs of
+                multi-word pseudos if the floating point mode does
+                not have word size, because otherwise we'd generate
+                a subreg with that floating mode from a different
+                sized integral pseudo which is not allowed by
+                validate_subreg.  */
+             && (!FLOAT_MODE_P (GET_MODE (x))
+                 || outer_size == UNITS_PER_WORD))
+           {
+             bitmap_set_bit (decomposable_context, regno);
+             iter.skip_subrtxes ();
+             continue;
+           }
 
-      /* If this is a cast from one mode to another, where the modes
-        have the same size, and they are not tieable, then mark this
-        register as non-decomposable.  If we decompose it we are
-        likely to mess up whatever the backend is trying to do.  */
-      if (outer_words > 1
-         && outer_size == inner_size
-         && !MODES_TIEABLE_P (GET_MODE (x), GET_MODE (inner)))
-       {
-         bitmap_set_bit (non_decomposable_context, regno);
-         bitmap_set_bit (subreg_context, regno);
-         return -1;
+         /* If this is a cast from one mode to another, where the modes
+            have the same size, and they are not tieable, then mark this
+            register as non-decomposable.  If we decompose it we are
+            likely to mess up whatever the backend is trying to do.  */
+         if (outer_words > 1
+             && outer_size == inner_size
+             && !targetm.modes_tieable_p (GET_MODE (x), GET_MODE (inner)))
+           {
+             bitmap_set_bit (non_decomposable_context, regno);
+             bitmap_set_bit (subreg_context, regno);
+             iter.skip_subrtxes ();
+             continue;
+           }
        }
-    }
-  else if (REG_P (x))
-    {
-      unsigned int regno;
-
-      /* We will see an outer SUBREG before we see the inner REG, so
-        when we see a plain REG here it means a direct reference to
-        the register.
-
-        If this is not a simple copy from one location to another,
-        then we can not decompose this register.  If this is a simple
-        copy we want to decompose, and the mode is right,
-        then we mark the register as decomposable.
-        Otherwise we don't say anything about this register --
-        it could be decomposed, but whether that would be
-        profitable depends upon how it is used elsewhere.
-
-        We only set bits in the bitmap for multi-word
-        pseudo-registers, since those are the only ones we care about
-        and it keeps the size of the bitmaps down.  */
-
-      regno = REGNO (x);
-      if (!HARD_REGISTER_NUM_P (regno)
-         && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+      else if (REG_P (x))
        {
-         switch (*pcmi)
+         unsigned int regno, size, words;
+
+         /* We will see an outer SUBREG before we see the inner REG, so
+            when we see a plain REG here it means a direct reference to
+            the register.
+
+            If this is not a simple copy from one location to another,
+            then we cannot decompose this register.  If this is a simple
+            copy we want to decompose, and the mode is right,
+            then we mark the register as decomposable.
+            Otherwise we don't say anything about this register --
+            it could be decomposed, but whether that would be
+            profitable depends upon how it is used elsewhere.
+
+            We only set bits in the bitmap for multi-word
+            pseudo-registers, since those are the only ones we care about
+            and it keeps the size of the bitmaps down.  */
+
+         regno = REGNO (x);
+         if (!HARD_REGISTER_NUM_P (regno)
+             && interesting_mode_p (GET_MODE (x), &size, &words)
+             && words > 1)
            {
-           case NOT_SIMPLE_MOVE:
-             bitmap_set_bit (non_decomposable_context, regno);
-             break;
-           case DECOMPOSABLE_SIMPLE_MOVE:
-             if (MODES_TIEABLE_P (GET_MODE (x), word_mode))
-               bitmap_set_bit (decomposable_context, regno);
-             break;
-           case SIMPLE_MOVE:
-             break;
-           default:
-             gcc_unreachable ();
+             switch (*pcmi)
+               {
+               case NOT_SIMPLE_MOVE:
+                 bitmap_set_bit (non_decomposable_context, regno);
+                 break;
+               case DECOMPOSABLE_SIMPLE_MOVE:
+                 if (targetm.modes_tieable_p (GET_MODE (x), word_mode))
+                   bitmap_set_bit (decomposable_context, regno);
+                 break;
+               case SIMPLE_MOVE:
+                 break;
+               default:
+                 gcc_unreachable ();
+               }
            }
        }
-    }
-  else if (MEM_P (x))
-    {
-      enum classify_move_insn cmi_mem = NOT_SIMPLE_MOVE;
+      else if (MEM_P (x))
+       {
+         enum classify_move_insn cmi_mem = NOT_SIMPLE_MOVE;
 
-      /* Any registers used in a MEM do not participate in a
-        SIMPLE_MOVE or DECOMPOSABLE_SIMPLE_MOVE.  Do our own recursion
-        here, and return -1 to block the parent's recursion.  */
-      for_each_rtx (&XEXP (x, 0), find_decomposable_subregs, &cmi_mem);
-      return -1;
+         /* Any registers used in a MEM do not participate in a
+            SIMPLE_MOVE or DECOMPOSABLE_SIMPLE_MOVE.  Do our own recursion
+            here, and return -1 to block the parent's recursion.  */
+         find_decomposable_subregs (&XEXP (x, 0), &cmi_mem);
+         iter.skip_subrtxes ();
+       }
     }
-
-  return 0;
 }
 
 /* Decompose REGNO into word-sized components.  We smash the REG node
@@ -579,15 +615,15 @@ static void
 decompose_register (unsigned int regno)
 {
   rtx reg;
-  unsigned int words, i;
+  unsigned int size, words, i;
   rtvec v;
 
   reg = regno_reg_rtx[regno];
 
   regno_reg_rtx[regno] = NULL_RTX;
 
-  words = GET_MODE_SIZE (GET_MODE (reg));
-  words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (!interesting_mode_p (GET_MODE (reg), &size, &words))
+    gcc_unreachable ();
 
   v = rtvec_alloc (words);
   for (i = 0; i < words; ++i)
@@ -608,39 +644,44 @@ decompose_register (unsigned int regno)
 /* Get a SUBREG of a CONCATN.  */
 
 static rtx
-simplify_subreg_concatn (enum machine_mode outermode, rtx op,
-                        unsigned int byte)
+simplify_subreg_concatn (machine_mode outermode, rtx op, poly_uint64 orig_byte)
 {
-  unsigned int inner_size;
-  enum machine_mode innermode, partmode;
+  unsigned int outer_size, outer_words, inner_size, inner_words;
+  machine_mode innermode, partmode;
   rtx part;
   unsigned int final_offset;
+  unsigned int byte;
+
+  innermode = GET_MODE (op);
+  if (!interesting_mode_p (outermode, &outer_size, &outer_words)
+      || !interesting_mode_p (innermode, &inner_size, &inner_words))
+    gcc_unreachable ();
 
+  /* Must be constant if interesting_mode_p passes.  */
+  byte = orig_byte.to_constant ();
   gcc_assert (GET_CODE (op) == CONCATN);
-  gcc_assert (byte % GET_MODE_SIZE (outermode) == 0);
+  gcc_assert (byte % outer_size == 0);
 
-  innermode = GET_MODE (op);
-  gcc_assert (byte < GET_MODE_SIZE (innermode));
-  gcc_assert (GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (innermode));
+  gcc_assert (byte < inner_size);
+  if (outer_size > inner_size)
+    return NULL_RTX;
 
-  inner_size = GET_MODE_SIZE (innermode) / XVECLEN (op, 0);
+  inner_size /= XVECLEN (op, 0);
   part = XVECEXP (op, 0, byte / inner_size);
   partmode = GET_MODE (part);
 
+  final_offset = byte % inner_size;
+  if (final_offset + outer_size > inner_size)
+    return NULL_RTX;
+
   /* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
      regular CONST_VECTORs.  They have vector or integer modes, depending
      on the capabilities of the target.  Cope with them.  */
   if (partmode == VOIDmode && VECTOR_MODE_P (innermode))
     partmode = GET_MODE_INNER (innermode);
   else if (partmode == VOIDmode)
-    {
-      enum mode_class mclass = GET_MODE_CLASS (innermode);
-      partmode = mode_for_size (inner_size * BITS_PER_UNIT, mclass, 0);
-    }
-
-  final_offset = byte % inner_size;
-  if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
-    return NULL_RTX;
+    partmode = mode_for_size (inner_size * BITS_PER_UNIT,
+                             GET_MODE_CLASS (innermode), 0).require ();
 
   return simplify_gen_subreg (outermode, part, partmode, final_offset);
 }
@@ -648,8 +689,8 @@ simplify_subreg_concatn (enum machine_mode outermode, rtx op,
 /* Wrapper around simplify_gen_subreg which handles CONCATN.  */
 
 static rtx
-simplify_gen_subreg_concatn (enum machine_mode outermode, rtx op,
-                            enum machine_mode innermode, unsigned int byte)
+simplify_gen_subreg_concatn (machine_mode outermode, rtx op,
+                            machine_mode innermode, unsigned int byte)
 {
   rtx ret;
 
@@ -661,9 +702,9 @@ simplify_gen_subreg_concatn (enum machine_mode outermode, rtx op,
     {
       rtx op2;
 
-      if ((GET_MODE_SIZE (GET_MODE (op))
-          == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
-         && SUBREG_BYTE (op) == 0)
+      if (known_eq (GET_MODE_SIZE (GET_MODE (op)),
+                   GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
+         && known_eq (SUBREG_BYTE (op), 0))
        return simplify_gen_subreg_concatn (outermode, SUBREG_REG (op),
                                            GET_MODE (SUBREG_REG (op)), byte);
 
@@ -672,10 +713,8 @@ simplify_gen_subreg_concatn (enum machine_mode outermode, rtx op,
       if (op2 == NULL_RTX)
        {
          /* We don't handle paradoxical subregs here.  */
-         gcc_assert (GET_MODE_SIZE (outermode)
-                     <= GET_MODE_SIZE (GET_MODE (op)));
-         gcc_assert (GET_MODE_SIZE (GET_MODE (op))
-                     <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))));
+         gcc_assert (!paradoxical_subreg_p (outermode, GET_MODE (op)));
+         gcc_assert (!paradoxical_subreg_p (op));
          op2 = simplify_subreg_concatn (outermode, SUBREG_REG (op),
                                         byte + SUBREG_BYTE (op));
          gcc_assert (op2 != NULL_RTX);
@@ -696,10 +735,7 @@ simplify_gen_subreg_concatn (enum machine_mode outermode, rtx op,
      resolve_simple_move will ask for the high part of the paradoxical
      subreg, which does not have a value.  Just return a zero.  */
   if (ret == NULL_RTX
-      && GET_CODE (op) == SUBREG
-      && SUBREG_BYTE (op) == 0
-      && (GET_MODE_SIZE (innermode)
-         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)))))
+      && paradoxical_subreg_p (op))
     return CONST0_RTX (outermode);
 
   gcc_assert (ret != NULL_RTX);
@@ -726,81 +762,49 @@ resolve_subreg_p (rtx x)
   return resolve_reg_p (SUBREG_REG (x));
 }
 
-/* This is called via for_each_rtx.  Look for SUBREGs which need to be
-   decomposed.  */
+/* Look for SUBREGs in *LOC which need to be decomposed.  */
 
-static int
-resolve_subreg_use (rtx *px, void *data)
+static bool
+resolve_subreg_use (rtx *loc, rtx insn)
 {
-  rtx insn = (rtx) data;
-  rtx x = *px;
-
-  if (x == NULL_RTX)
-    return 0;
-
-  if (resolve_subreg_p (x))
+  subrtx_ptr_iterator::array_type array;
+  FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
     {
-      x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
-                                  SUBREG_BYTE (x));
-
-      /* It is possible for a note to contain a reference which we can
-        decompose.  In this case, return 1 to the caller to indicate
-        that the note must be removed.  */
-      if (!x)
+      rtx *loc = *iter;
+      rtx x = *loc;
+      if (resolve_subreg_p (x))
        {
-         gcc_assert (!insn);
-         return 1;
-       }
+         x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
+                                      SUBREG_BYTE (x));
 
-      validate_change (insn, px, x, 1);
-      return -1;
-    }
-
-  if (resolve_reg_p (x))
-    {
-      /* Return 1 to the caller to indicate that we found a direct
-        reference to a register which is being decomposed.  This can
-        happen inside notes, multiword shift or zero-extend
-        instructions.  */
-      return 1;
-    }
-
-  return 0;
-}
-
-/* This is called via for_each_rtx.  Look for SUBREGs which can be
-   decomposed and decomposed REGs that need copying.  */
-
-static int
-adjust_decomposed_uses (rtx *px, void *data ATTRIBUTE_UNUSED)
-{
-  rtx x = *px;
-
-  if (x == NULL_RTX)
-    return 0;
-
-  if (resolve_subreg_p (x))
-    {
-      x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
-                                  SUBREG_BYTE (x));
+         /* It is possible for a note to contain a reference which we can
+            decompose.  In this case, return 1 to the caller to indicate
+            that the note must be removed.  */
+         if (!x)
+           {
+             gcc_assert (!insn);
+             return true;
+           }
 
-      if (x)
-       *px = x;
-      else
-       x = copy_rtx (*px);
+         validate_change (insn, loc, x, 1);
+         iter.skip_subrtxes ();
+       }
+      else if (resolve_reg_p (x))
+       /* Return 1 to the caller to indicate that we found a direct
+          reference to a register which is being decomposed.  This can
+          happen inside notes, multiword shift or zero-extend
+          instructions.  */
+       return true;
     }
 
-  if (resolve_reg_p (x))
-    *px = copy_rtx (x);
-
-  return 0;
+  return false;
 }
 
 /* Resolve any decomposed registers which appear in register notes on
    INSN.  */
 
 static void
-resolve_reg_notes (rtx insn)
+resolve_reg_notes (rtx_insn *insn)
 {
   rtx *pnote, note;
 
@@ -808,7 +812,7 @@ resolve_reg_notes (rtx insn)
   if (note)
     {
       int old_count = num_validated_changes ();
-      if (for_each_rtx (&XEXP (note, 0), resolve_subreg_use, NULL))
+      if (resolve_subreg_use (&XEXP (note, 0), NULL_RTX))
        remove_note (insn, note);
       else
        if (old_count != num_validated_changes ())
@@ -851,9 +855,10 @@ can_decompose_p (rtx x)
 
       if (HARD_REGISTER_NUM_P (regno))
        {
-         unsigned int byte, num_bytes;
+         unsigned int byte, num_bytes, num_words;
 
-         num_bytes = GET_MODE_SIZE (GET_MODE (x));
+         if (!interesting_mode_p (GET_MODE (x), &num_bytes, &num_words))
+           return false;
          for (byte = 0; byte < num_bytes; byte += UNITS_PER_WORD)
            if (simplify_subreg_regno (regno, GET_MODE (x), byte, word_mode) < 0)
              return false;
@@ -866,23 +871,40 @@ can_decompose_p (rtx x)
   return true;
 }
 
+/* OPND is a concatn operand this is used with a simple move operator.
+   Return a new rtx with the concatn's operands swapped.  */
+
+static rtx
+resolve_operand_for_swap_move_operator (rtx opnd)
+{
+  gcc_assert (GET_CODE (opnd) == CONCATN);
+  rtx concatn = copy_rtx (opnd);
+  rtx op0 = XVECEXP (concatn, 0, 0);
+  rtx op1 = XVECEXP (concatn, 0, 1);
+  XVECEXP (concatn, 0, 0) = op1;
+  XVECEXP (concatn, 0, 1) = op0;
+  return concatn;
+}
+
 /* Decompose the registers used in a simple move SET within INSN.  If
    we don't change anything, return INSN, otherwise return the start
    of the sequence of moves.  */
 
-static rtx
-resolve_simple_move (rtx set, rtx insn)
+static rtx_insn *
+resolve_simple_move (rtx set, rtx_insn *insn)
 {
-  rtx src, dest, real_dest, insns;
-  enum machine_mode orig_mode, dest_mode;
-  unsigned int words;
+  rtx src, dest, real_dest, src_op;
+  rtx_insn *insns;
+  machine_mode orig_mode, dest_mode;
+  unsigned int orig_size, words;
   bool pushing;
 
   src = SET_SRC (set);
   dest = SET_DEST (set);
   orig_mode = GET_MODE (dest);
 
-  words = (GET_MODE_SIZE (orig_mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (!interesting_mode_p (orig_mode, &orig_size, &words))
+    gcc_unreachable ();
   gcc_assert (words > 1);
 
   start_sequence ();
@@ -894,11 +916,27 @@ resolve_simple_move (rtx set, rtx insn)
 
   real_dest = NULL_RTX;
 
+  if ((src_op = operand_for_swap_move_operator (src)) != NULL_RTX)
+    {
+      if (resolve_reg_p (dest))
+       {
+         /* DEST is a CONCATN, so swap its operands and strip
+            SRC's operator.  */
+         dest = resolve_operand_for_swap_move_operator (dest);
+         src = src_op;
+       }
+      else if (resolve_reg_p (src_op))
+       {
+         /* SRC is an operation on a CONCATN, so strip the operator and
+            swap the CONCATN's operands.  */
+         src = resolve_operand_for_swap_move_operator (src_op);
+       }
+    }
+
   if (GET_CODE (src) == SUBREG
       && resolve_reg_p (SUBREG_REG (src))
-      && (SUBREG_BYTE (src) != 0
-         || (GET_MODE_SIZE (orig_mode)
-             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))))
+      && (maybe_ne (SUBREG_BYTE (src), 0)
+         || maybe_ne (orig_size, GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))))
     {
       real_dest = dest;
       dest = gen_reg_rtx (orig_mode);
@@ -911,11 +949,12 @@ resolve_simple_move (rtx set, rtx insn)
 
   if (GET_CODE (dest) == SUBREG
       && resolve_reg_p (SUBREG_REG (dest))
-      && (SUBREG_BYTE (dest) != 0
-         || (GET_MODE_SIZE (orig_mode)
-             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))))
+      && (maybe_ne (SUBREG_BYTE (dest), 0)
+         || maybe_ne (orig_size,
+                      GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))))
     {
-      rtx reg, minsn, smove;
+      rtx reg, smove;
+      rtx_insn *minsn;
 
       reg = gen_reg_rtx (orig_mode);
       minsn = emit_move_insn (reg, src);
@@ -943,16 +982,16 @@ resolve_simple_move (rtx set, rtx insn)
   /* It's possible for the code to use a subreg of a decomposed
      register while forming an address.  We need to handle that before
      passing the address to emit_move_insn.  We pass NULL_RTX as the
-     insn parameter to resolve_subreg_use because we can not validate
+     insn parameter to resolve_subreg_use because we cannot validate
      the insn yet.  */
   if (MEM_P (src) || MEM_P (dest))
     {
       int acg;
 
       if (MEM_P (src))
-       for_each_rtx (&XEXP (src, 0), resolve_subreg_use, NULL_RTX);
+       resolve_subreg_use (&XEXP (src, 0), NULL_RTX);
       if (MEM_P (dest))
-       for_each_rtx (&XEXP (dest, 0), resolve_subreg_use, NULL_RTX);
+       resolve_subreg_use (&XEXP (dest, 0), NULL_RTX);
       acg = apply_change_group ();
       gcc_assert (acg);
     }
@@ -968,19 +1007,19 @@ resolve_simple_move (rtx set, rtx insn)
 
       reg = gen_reg_rtx (orig_mode);
 
-#ifdef AUTO_INC_DEC
-      {
-       rtx move = emit_move_insn (reg, src);
-       if (MEM_P (src))
-         {
-           rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
-           if (note)
-             add_reg_note (move, REG_INC, XEXP (note, 0));
-         }
-      }
-#else
-      emit_move_insn (reg, src);
-#endif
+      if (AUTO_INC_DEC)
+       {
+         rtx_insn *move = emit_move_insn (reg, src);
+         if (MEM_P (src))
+           {
+             rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
+             if (note)
+               add_reg_note (move, REG_INC, XEXP (note, 0));
+           }
+       }
+      else
+       emit_move_insn (reg, src);
+
       src = reg;
     }
 
@@ -1002,11 +1041,7 @@ resolve_simple_move (rtx set, rtx insn)
       if (real_dest == NULL_RTX)
        real_dest = dest;
       if (!SCALAR_INT_MODE_P (dest_mode))
-       {
-         dest_mode = mode_for_size (GET_MODE_SIZE (dest_mode) * BITS_PER_UNIT,
-                                    MODE_INT, 0);
-         gcc_assert (dest_mode != BLKmode);
-       }
+       dest_mode = int_mode_for_mode (dest_mode).require ();
       dest = gen_reg_rtx (dest_mode);
       if (REG_P (real_dest))
        REG_ATTRS (dest) = REG_ATTRS (real_dest);
@@ -1016,7 +1051,7 @@ resolve_simple_move (rtx set, rtx insn)
     {
       unsigned int i, j, jinc;
 
-      gcc_assert (GET_MODE_SIZE (orig_mode) % UNITS_PER_WORD == 0);
+      gcc_assert (orig_size % UNITS_PER_WORD == 0);
       gcc_assert (GET_CODE (XEXP (dest, 0)) != PRE_MODIFY);
       gcc_assert (GET_CODE (XEXP (dest, 0)) != POST_MODIFY);
 
@@ -1062,7 +1097,8 @@ resolve_simple_move (rtx set, rtx insn)
 
   if (real_dest != NULL_RTX)
     {
-      rtx mdest, minsn, smove;
+      rtx mdest, smove;
+      rtx_insn *minsn;
 
       if (dest_mode == orig_mode)
        mdest = dest;
@@ -1070,15 +1106,13 @@ resolve_simple_move (rtx set, rtx insn)
        mdest = simplify_gen_subreg (orig_mode, dest, GET_MODE (dest), 0);
       minsn = emit_move_insn (real_dest, mdest);
 
-#ifdef AUTO_INC_DEC
-  if (MEM_P (real_dest)
+  if (AUTO_INC_DEC && MEM_P (real_dest)
       && !(resolve_reg_p (real_dest) || resolve_subreg_p (real_dest)))
     {
       rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
       if (note)
        add_reg_note (minsn, REG_INC, XEXP (note, 0));
     }
-#endif
 
       smove = single_set (minsn);
       gcc_assert (smove != NULL_RTX);
@@ -1108,11 +1142,11 @@ resolve_simple_move (rtx set, rtx insn)
    component registers.  Return whether we changed something.  */
 
 static bool
-resolve_clobber (rtx pat, rtx insn)
+resolve_clobber (rtx pat, rtx_insn *insn)
 {
   rtx reg;
-  enum machine_mode orig_mode;
-  unsigned int words, i;
+  machine_mode orig_mode;
+  unsigned int orig_size, words, i;
   int ret;
 
   reg = XEXP (pat, 0);
@@ -1120,8 +1154,8 @@ resolve_clobber (rtx pat, rtx insn)
     return false;
 
   orig_mode = GET_MODE (reg);
-  words = GET_MODE_SIZE (orig_mode);
-  words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (!interesting_mode_p (orig_mode, &orig_size, &words))
+    gcc_unreachable ();
 
   ret = validate_change (NULL_RTX, &XEXP (pat, 0),
                         simplify_gen_subreg_concatn (word_mode, reg,
@@ -1149,7 +1183,7 @@ resolve_clobber (rtx pat, rtx insn)
    whether we changed something.  */
 
 static bool
-resolve_use (rtx pat, rtx insn)
+resolve_use (rtx pat, rtx_insn *insn)
 {
   if (resolve_reg_p (XEXP (pat, 0)) || resolve_subreg_p (XEXP (pat, 0)))
     {
@@ -1165,9 +1199,26 @@ resolve_use (rtx pat, rtx insn)
 /* A VAR_LOCATION can be simplified.  */
 
 static void
-resolve_debug (rtx insn)
+resolve_debug (rtx_insn *insn)
 {
-  for_each_rtx (&PATTERN (insn), adjust_decomposed_uses, NULL_RTX);
+  subrtx_ptr_iterator::array_type array;
+  FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
+    {
+      rtx *loc = *iter;
+      rtx x = *loc;
+      if (resolve_subreg_p (x))
+       {
+         x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
+                                      SUBREG_BYTE (x));
+
+         if (x)
+           *loc = x;
+         else
+           x = copy_rtx (*loc);
+       }
+      if (resolve_reg_p (x))
+       *loc = copy_rtx (x);
+    }
 
   df_insn_rescan (insn);
 
@@ -1180,7 +1231,7 @@ resolve_debug (rtx insn)
    if INSN is decomposable.  */
 
 static bool
-find_decomposable_shift_zext (rtx insn, bool speed_p)
+find_decomposable_shift_zext (rtx_insn *insn, bool speed_p)
 {
   rtx set;
   rtx op;
@@ -1236,33 +1287,36 @@ find_decomposable_shift_zext (rtx insn, bool speed_p)
    and 'set to zero' insn.  Return a pointer to the new insn when a
    replacement was done.  */
 
-static rtx
-resolve_shift_zext (rtx insn)
+static rtx_insn *
+resolve_shift_zext (rtx_insn *insn)
 {
   rtx set;
   rtx op;
   rtx op_operand;
-  rtx insns;
+  rtx_insn *insns;
   rtx src_reg, dest_reg, dest_upper, upper_src = NULL_RTX;
   int src_reg_num, dest_reg_num, offset1, offset2, src_offset;
+  scalar_int_mode inner_mode;
 
   set = single_set (insn);
   if (!set)
-    return NULL_RTX;
+    return NULL;
 
   op = SET_SRC (set);
   if (GET_CODE (op) != ASHIFT
       && GET_CODE (op) != LSHIFTRT
       && GET_CODE (op) != ASHIFTRT
       && GET_CODE (op) != ZERO_EXTEND)
-    return NULL_RTX;
+    return NULL;
 
   op_operand = XEXP (op, 0);
+  if (!is_a <scalar_int_mode> (GET_MODE (op_operand), &inner_mode))
+    return NULL;
 
   /* We can tear this operation apart only if the regs were already
      torn apart.  */
   if (!resolve_reg_p (SET_DEST (set)) && !resolve_reg_p (op_operand))
-    return NULL_RTX;
+    return NULL;
 
   /* src_reg_num is the number of the word mode register which we
      are operating on.  For a left shift and a zero_extend on little
@@ -1270,8 +1324,7 @@ resolve_shift_zext (rtx insn)
   src_reg_num = (GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFTRT)
                ? 1 : 0;
 
-  if (WORDS_BIG_ENDIAN
-      && GET_MODE_SIZE (GET_MODE (op_operand)) > UNITS_PER_WORD)
+  if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
     src_reg_num = 1 - src_reg_num;
 
   if (GET_CODE (op) == ZERO_EXTEND)
@@ -1326,7 +1379,7 @@ resolve_shift_zext (rtx insn)
 
   if (dump_file)
     {
-      rtx in;
+      rtx_insn *in;
       fprintf (dump_file, "; Replacing insn: %d with insns: ", INSN_UID (insn));
       for (in = insns; in != insn; in = NEXT_INSN (in))
        fprintf (dump_file, "%d ", INSN_UID (in));
@@ -1366,17 +1419,18 @@ dump_shift_choices (enum rtx_code code, bool *splitting)
 static void
 dump_choices (bool speed_p, const char *description)
 {
-  unsigned int i;
+  unsigned int size, factor, i;
 
   fprintf (dump_file, "Choices when optimizing for %s:\n", description);
 
   for (i = 0; i < MAX_MACHINE_MODE; i++)
-    if (GET_MODE_SIZE (i) > UNITS_PER_WORD)
+    if (interesting_mode_p ((machine_mode) i, &size, &factor)
+       && factor > 1)
       fprintf (dump_file, "  %s mode %s for copy lowering.\n",
               choices[speed_p].move_modes_to_split[i]
               ? "Splitting"
               : "Skipping",
-              GET_MODE_NAME ((enum machine_mode) i));
+              GET_MODE_NAME ((machine_mode) i));
 
   fprintf (dump_file, "  %s mode %s for zero_extend lowering.\n",
           choices[speed_p].splitting_zext ? "Splitting" : "Skipping",
@@ -1426,7 +1480,7 @@ decompose_multiword_subregs (bool decompose_copies)
     for (i = FIRST_PSEUDO_REGISTER; i < max; ++i)
       if (regno_reg_rtx[i] != NULL)
        {
-         enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
+         machine_mode mode = GET_MODE (regno_reg_rtx[i]);
          if (choices[false].move_modes_to_split[(int) mode]
              || choices[true].move_modes_to_split[(int) mode])
            {
@@ -1463,9 +1517,9 @@ decompose_multiword_subregs (bool decompose_copies)
   memset (reg_copy_graph.address (), 0, sizeof (bitmap) * max);
 
   speed_p = optimize_function_for_speed_p (cfun);
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
-      rtx insn;
+      rtx_insn *insn;
 
       FOR_BB_INSNS (bb, insn)
        {
@@ -1507,9 +1561,7 @@ decompose_multiword_subregs (bool decompose_copies)
          n = recog_data.n_operands;
          for (i = 0; i < n; ++i)
            {
-             for_each_rtx (&recog_data.operand[i],
-                           find_decomposable_subregs,
-                           &cmi);
+             find_decomposable_subregs (&recog_data.operand[i], &cmi);
 
              /* We handle ASM_OPERANDS as a special case to support
                 things like x86 rdtsc which returns a DImode value.
@@ -1529,7 +1581,6 @@ decompose_multiword_subregs (bool decompose_copies)
   bitmap_and_compl_into (decomposable_context, non_decomposable_context);
   if (!bitmap_empty_p (decomposable_context))
     {
-      sbitmap sub_blocks;
       unsigned int i;
       sbitmap_iterator sbi;
       bitmap_iterator iter;
@@ -1537,15 +1588,15 @@ decompose_multiword_subregs (bool decompose_copies)
 
       propagate_pseudo_copies ();
 
-      sub_blocks = sbitmap_alloc (last_basic_block);
+      auto_sbitmap sub_blocks (last_basic_block_for_fn (cfun));
       bitmap_clear (sub_blocks);
 
       EXECUTE_IF_SET_IN_BITMAP (decomposable_context, 0, regno, iter)
        decompose_register (regno);
 
-      FOR_EACH_BB (bb)
+      FOR_EACH_BB_FN (bb, cfun)
        {
-         rtx insn;
+         rtx_insn *insn;
 
          FOR_BB_INSNS (bb, insn)
            {
@@ -1572,7 +1623,7 @@ decompose_multiword_subregs (bool decompose_copies)
                  set = simple_move (insn, speed_p);
                  if (set)
                    {
-                     rtx orig_insn = insn;
+                     rtx_insn *orig_insn = insn;
                      bool cfi = control_flow_insn_p (insn);
 
                      /* We can end up splitting loads to multi-word pseudos
@@ -1602,7 +1653,7 @@ decompose_multiword_subregs (bool decompose_copies)
                    }
                  else
                    {
-                     rtx decomposed_shift;
+                     rtx_insn *decomposed_shift;
 
                      decomposed_shift = resolve_shift_zext (insn);
                      if (decomposed_shift != NULL_RTX)
@@ -1614,9 +1665,7 @@ decompose_multiword_subregs (bool decompose_copies)
                    }
 
                  for (i = recog_data.n_operands - 1; i >= 0; --i)
-                   for_each_rtx (recog_data.operand_loc[i],
-                                 resolve_subreg_use,
-                                 insn);
+                   resolve_subreg_use (recog_data.operand_loc[i], insn);
 
                  resolve_reg_notes (insn);
 
@@ -1644,10 +1693,10 @@ decompose_multiword_subregs (bool decompose_copies)
         loads to appear.  */
       EXECUTE_IF_SET_IN_BITMAP (sub_blocks, 0, i, sbi)
        {
-         rtx insn, end;
+         rtx_insn *insn, *end;
          edge fallthru;
 
-         bb = BASIC_BLOCK (i);
+         bb = BASIC_BLOCK_FOR_FN (cfun, i);
          insn = BB_HEAD (bb);
          end = BB_END (bb);
 
@@ -1667,8 +1716,6 @@ decompose_multiword_subregs (bool decompose_copies)
                insn = NEXT_INSN (insn);
            }
        }
-
-      sbitmap_free (sub_blocks);
     }
 
   {
@@ -1687,32 +1734,8 @@ decompose_multiword_subregs (bool decompose_copies)
   BITMAP_FREE (subreg_context);
 }
 \f
-/* Gate function for lower subreg pass.  */
-
-static bool
-gate_handle_lower_subreg (void)
-{
-  return flag_split_wide_types != 0;
-}
-
 /* Implement first lower subreg pass.  */
 
-static unsigned int
-rest_of_handle_lower_subreg (void)
-{
-  decompose_multiword_subregs (false);
-  return 0;
-}
-
-/* Implement second lower subreg pass.  */
-
-static unsigned int
-rest_of_handle_lower_subreg2 (void)
-{
-  decompose_multiword_subregs (true);
-  return 0;
-}
-
 namespace {
 
 const pass_data pass_data_lower_subreg =
@@ -1720,14 +1743,12 @@ const pass_data pass_data_lower_subreg =
   RTL_PASS, /* type */
   "subreg1", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
   TV_LOWER_SUBREG, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_verify_flow, /* todo_flags_finish */
+  0, /* todo_flags_finish */
 };
 
 class pass_lower_subreg : public rtl_opt_pass
@@ -1738,8 +1759,12 @@ public:
   {}
 
   /* opt_pass methods: */
-  bool gate () { return gate_handle_lower_subreg (); }
-  unsigned int execute () { return rest_of_handle_lower_subreg (); }
+  virtual bool gate (function *) { return flag_split_wide_types != 0; }
+  virtual unsigned int execute (function *)
+    {
+      decompose_multiword_subregs (false);
+      return 0;
+    }
 
 }; // class pass_lower_subreg
 
@@ -1751,6 +1776,8 @@ make_pass_lower_subreg (gcc::context *ctxt)
   return new pass_lower_subreg (ctxt);
 }
 
+/* Implement second lower subreg pass.  */
+
 namespace {
 
 const pass_data pass_data_lower_subreg2 =
@@ -1758,15 +1785,12 @@ const pass_data pass_data_lower_subreg2 =
   RTL_PASS, /* type */
   "subreg2", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
   TV_LOWER_SUBREG, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  ( TODO_df_finish | TODO_verify_rtl_sharing
-    | TODO_verify_flow ), /* todo_flags_finish */
+  TODO_df_finish, /* todo_flags_finish */
 };
 
 class pass_lower_subreg2 : public rtl_opt_pass
@@ -1777,8 +1801,12 @@ public:
   {}
 
   /* opt_pass methods: */
-  bool gate () { return gate_handle_lower_subreg (); }
-  unsigned int execute () { return rest_of_handle_lower_subreg2 (); }
+  virtual bool gate (function *) { return flag_split_wide_types != 0; }
+  virtual unsigned int execute (function *)
+    {
+      decompose_multiword_subregs (true);
+      return 0;
+    }
 
 }; // class pass_lower_subreg2