OSDN Git Service

* tree.c (free_lang_data_in_one_sizepos): New inline function.
[pf3gnuchains/gcc-fork.git] / gcc / lower-subreg.c
index 908b10e..3301a9d 100644 (file)
@@ -1,5 +1,5 @@
 /* Decompose multiword subregs.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>
                  Ian Lance Taylor <iant@google.com>
 
@@ -7,7 +7,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -35,8 +34,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "recog.h"
 #include "bitmap.h"
 #include "expr.h"
+#include "except.h"
 #include "regs.h"
 #include "tree-pass.h"
+#include "df.h"
 
 #ifdef STACK_GROWS_DOWNWARD
 # undef STACK_GROWS_DOWNWARD
@@ -224,11 +225,9 @@ enum classify_move_insn
 {
   /* Not a simple move from one location to another.  */
   NOT_SIMPLE_MOVE,
-  /* A simple move from one pseudo-register to another with no
-     REG_RETVAL note.  */
+  /* A simple move from one pseudo-register to another.  */
   SIMPLE_PSEUDO_REG_MOVE,
-  /* A simple move involving a non-pseudo-register, or from one
-     pseudo-register to another with a REG_RETVAL note.  */
+  /* A simple move involving a non-pseudo-register.  */
   SIMPLE_MOVE
 };
 
@@ -280,6 +279,18 @@ find_decomposable_subregs (rtx *px, void *data)
          bitmap_set_bit (decomposable_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
+         && !MODES_TIEABLE_P (GET_MODE (x), GET_MODE (inner)))
+       {
+         bitmap_set_bit (non_decomposable_context, regno);
+         return -1;
+       }
     }
   else if (REG_P (x))
     {
@@ -291,10 +302,10 @@ find_decomposable_subregs (rtx *px, void *data)
 
         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 from one pseudo-register to another, with no REG_RETVAL
-        note, 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
+        copy from one pseudo-register to another, 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
@@ -350,7 +361,6 @@ decompose_register (unsigned int regno)
   reg = regno_reg_rtx[regno];
 
   regno_reg_rtx[regno] = NULL_RTX;
-  clear_reg_info_regno (regno);
 
   words = GET_MODE_SIZE (GET_MODE (reg));
   words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
@@ -513,66 +523,40 @@ resolve_subreg_use (rtx *px, void *data)
     {
       /* 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.  */
-      gcc_assert (!insn);
+        happen inside notes, multiword shift or zero-extend
+        instructions.  */
       return 1;
     }
 
   return 0;
 }
 
-/* If there is a REG_LIBCALL note on OLD_START, move it to NEW_START,
-   and link the corresponding REG_RETVAL note to NEW_START.  */
-
-static void
-move_libcall_note (rtx old_start, rtx new_start)
-{
-  rtx note0, note1, end;
-
-  note0 = find_reg_note (old_start, REG_LIBCALL, NULL);
-  if (note0 == NULL_RTX)
-    return;
-
-  remove_note (old_start, note0);
-  end = XEXP (note0, 0);
-  note1 = find_reg_note (end, REG_RETVAL, NULL);
-
-  XEXP (note0, 1) = REG_NOTES (new_start);
-  REG_NOTES (new_start) = note0;
-  XEXP (note1, 0) = new_start;
-}
-
-/* Remove any REG_RETVAL note, the corresponding REG_LIBCALL note, and
-   any markers for a no-conflict block.  We have decomposed the
-   registers so the non-conflict is now obvious.  */
+/* This is called via for_each_rtx.  Look for SUBREGs which can be
+   decomposed and decomposed REGs that need copying.  */
 
-static void
-remove_retval_note (rtx insn1)
+static int
+adjust_decomposed_uses (rtx *px, void *data ATTRIBUTE_UNUSED)
 {
-  rtx note0, insn0, note1, insn;
-
-  note1 = find_reg_note (insn1, REG_RETVAL, NULL);
-  if (note1 == NULL_RTX)
-    return;
-
-  insn0 = XEXP (note1, 0);
-  note0 = find_reg_note (insn0, REG_LIBCALL, NULL);
+  rtx x = *px;
 
-  remove_note (insn0, note0);
-  remove_note (insn1, note1);
+  if (x == NULL_RTX)
+    return 0;
 
-  for (insn = insn0; insn != insn1; insn = NEXT_INSN (insn))
+  if (resolve_subreg_p (x))
     {
-      while (1)
-       {
-         rtx note;
+      x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
+                                  SUBREG_BYTE (x));
 
-         note = find_reg_note (insn, REG_NO_CONFLICT, NULL);
-         if (note == NULL_RTX)
-           break;
-         remove_note (insn, note);
-       }
+      if (x)
+       *px = x;
+      else
+       x = copy_rtx (*px);
     }
+
+  if (resolve_reg_p (x))
+    *px = copy_rtx (x);
+
+  return 0;
 }
 
 /* Resolve any decomposed registers which appear in register notes on
@@ -586,31 +570,33 @@ resolve_reg_notes (rtx insn)
   note = find_reg_equal_equiv_note (insn);
   if (note)
     {
+      int old_count = num_validated_changes ();
       if (for_each_rtx (&XEXP (note, 0), resolve_subreg_use, NULL))
-       {
-         remove_note (insn, note);
-         remove_retval_note (insn);
-       }
+       remove_note (insn, note);
+      else
+       if (old_count != num_validated_changes ())
+         df_notes_rescan (insn);
     }
 
   pnote = &REG_NOTES (insn);
   while (*pnote != NULL_RTX)
     {
-      bool delete = false;
+      bool del = false;
 
       note = *pnote;
       switch (REG_NOTE_KIND (note))
        {
-       case REG_NO_CONFLICT:
+       case REG_DEAD:
+       case REG_UNUSED:
          if (resolve_reg_p (XEXP (note, 0)))
-           delete = true;
+           del = true;
          break;
 
        default:
          break;
        }
 
-      if (delete)
+      if (del)
        *pnote = XEXP (note, 1);
       else
        pnote = &XEXP (note, 1);
@@ -807,7 +793,7 @@ resolve_simple_move (rtx set, rtx insn)
       unsigned int i;
 
       if (REG_P (dest) && !HARD_REGISTER_NUM_P (REGNO (dest)))
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, dest));
+       emit_clobber (dest);
 
       for (i = 0; i < words; ++i)
        emit_move_insn (simplify_gen_subreg_concatn (word_mode, dest,
@@ -837,10 +823,10 @@ resolve_simple_move (rtx set, rtx insn)
   insns = get_insns ();
   end_sequence ();
 
+  copy_reg_eh_region_note_forward (insn, insns, NULL_RTX);
+
   emit_insn_before (insns, insn);
 
-  move_libcall_note (insn, insns);
-  remove_retval_note (insn);
   delete_insn (insn);
 
   return insns;
@@ -869,6 +855,7 @@ resolve_clobber (rtx pat, rtx insn)
                         simplify_gen_subreg_concatn (word_mode, reg,
                                                      orig_mode, 0),
                         0);
+  df_insn_rescan (insn);
   gcc_assert (ret != 0);
 
   for (i = words - 1; i > 0; --i)
@@ -881,6 +868,8 @@ resolve_clobber (rtx pat, rtx insn)
       emit_insn_after (x, insn);
     }
 
+  resolve_reg_notes (insn);
+
   return true;
 }
 
@@ -895,19 +884,187 @@ resolve_use (rtx pat, rtx insn)
       delete_insn (insn);
       return true;
     }
+
+  resolve_reg_notes (insn);
+
   return false;
 }
 
+/* A VAR_LOCATION can be simplified.  */
+
+static void
+resolve_debug (rtx insn)
+{
+  for_each_rtx (&PATTERN (insn), adjust_decomposed_uses, NULL_RTX);
+
+  df_insn_rescan (insn);
+
+  resolve_reg_notes (insn);
+}
+
+/* Checks if INSN is a decomposable multiword-shift or zero-extend and
+   sets the decomposable_context bitmap accordingly.  A non-zero value
+   is returned if a decomposable insn has been found.  */
+
+static int
+find_decomposable_shift_zext (rtx insn)
+{
+  rtx set;
+  rtx op;
+  rtx op_operand;
+
+  set = single_set (insn);
+  if (!set)
+    return 0;
+
+  op = SET_SRC (set);
+  if (GET_CODE (op) != ASHIFT
+      && GET_CODE (op) != LSHIFTRT
+      && GET_CODE (op) != ZERO_EXTEND)
+    return 0;
+
+  op_operand = XEXP (op, 0);
+  if (!REG_P (SET_DEST (set)) || !REG_P (op_operand)
+      || HARD_REGISTER_NUM_P (REGNO (SET_DEST (set)))
+      || HARD_REGISTER_NUM_P (REGNO (op_operand))
+      || !SCALAR_INT_MODE_P (GET_MODE (op)))
+    return 0;
+
+  if (GET_CODE (op) == ZERO_EXTEND)
+    {
+      if (GET_MODE (op_operand) != word_mode
+         || GET_MODE_BITSIZE (GET_MODE (op)) != 2 * BITS_PER_WORD)
+       return 0;
+    }
+  else /* left or right shift */
+    {
+      if (!CONST_INT_P (XEXP (op, 1))
+         || INTVAL (XEXP (op, 1)) < BITS_PER_WORD
+         || GET_MODE_BITSIZE (GET_MODE (op_operand)) != 2 * BITS_PER_WORD)
+       return 0;
+    }
+
+  bitmap_set_bit (decomposable_context, REGNO (SET_DEST (set)));
+
+  if (GET_CODE (op) != ZERO_EXTEND)
+    bitmap_set_bit (decomposable_context, REGNO (op_operand));
+
+  return 1;
+}
+
+/* Decompose a more than word wide shift (in INSN) of a multiword
+   pseudo or a multiword zero-extend of a wordmode pseudo into a move
+   and 'set to zero' insn.  Return a pointer to the new insn when a
+   replacement was done.  */
+
+static rtx
+resolve_shift_zext (rtx insn)
+{
+  rtx set;
+  rtx op;
+  rtx op_operand;
+  rtx insns;
+  rtx src_reg, dest_reg, dest_zero;
+  int src_reg_num, dest_reg_num, offset1, offset2, src_offset;
+
+  set = single_set (insn);
+  if (!set)
+    return NULL_RTX;
+
+  op = SET_SRC (set);
+  if (GET_CODE (op) != ASHIFT
+      && GET_CODE (op) != LSHIFTRT
+      && GET_CODE (op) != ZERO_EXTEND)
+    return NULL_RTX;
+
+  op_operand = XEXP (op, 0);
+
+  if (!resolve_reg_p (SET_DEST (set)) && !resolve_reg_p (op_operand))
+    return NULL_RTX;
+
+  /* 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
+     endian machines this is register 0.  */
+  src_reg_num = GET_CODE (op) == LSHIFTRT ? 1 : 0;
+
+  if (WORDS_BIG_ENDIAN
+      && GET_MODE_SIZE (GET_MODE (op_operand)) > UNITS_PER_WORD)
+    src_reg_num = 1 - src_reg_num;
+
+  if (GET_CODE (op) == ZERO_EXTEND)
+    dest_reg_num = WORDS_BIG_ENDIAN ? 1 : 0;
+  else
+    dest_reg_num = 1 - src_reg_num;
+
+  offset1 = UNITS_PER_WORD * dest_reg_num;
+  offset2 = UNITS_PER_WORD * (1 - dest_reg_num);
+  src_offset = UNITS_PER_WORD * src_reg_num;
+
+  if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
+    {
+      offset1 += UNITS_PER_WORD - 1;
+      offset2 += UNITS_PER_WORD - 1;
+      src_offset += UNITS_PER_WORD - 1;
+    }
+
+  start_sequence ();
+
+  dest_reg = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
+                                          GET_MODE (SET_DEST (set)),
+                                          offset1);
+  dest_zero = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
+                                           GET_MODE (SET_DEST (set)),
+                                           offset2);
+  src_reg = simplify_gen_subreg_concatn (word_mode, op_operand,
+                                         GET_MODE (op_operand),
+                                         src_offset);
+  if (GET_CODE (op) != ZERO_EXTEND)
+    {
+      int shift_count = INTVAL (XEXP (op, 1));
+      if (shift_count > BITS_PER_WORD)
+       src_reg = expand_shift (GET_CODE (op) == ASHIFT ?
+                               LSHIFT_EXPR : RSHIFT_EXPR,
+                               word_mode, src_reg,
+                               build_int_cst (NULL_TREE,
+                                              shift_count - BITS_PER_WORD),
+                               dest_reg, 1);
+    }
+
+  if (dest_reg != src_reg)
+    emit_move_insn (dest_reg, src_reg);
+  emit_move_insn (dest_zero, CONST0_RTX (word_mode));
+  insns = get_insns ();
+
+  end_sequence ();
+
+  emit_insn_before (insns, insn);
+
+  if (dump_file)
+    {
+      rtx 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));
+      fprintf (dump_file, "\n");
+    }
+
+  delete_insn (insn);
+  return insns;
+}
+
 /* Look for registers which are always accessed via word-sized SUBREGs
    or via copies.  Decompose these registers into several word-sized
    pseudo-registers.  */
 
 static void
-decompose_multiword_subregs (bool update_life)
+decompose_multiword_subregs (void)
 {
   unsigned int max;
   basic_block bb;
 
+  if (df)
+    df_set_flags (DF_DEFER_INSN_RESCAN);
+
   max = max_reg_num ();
 
   /* First see if there are any multi-word pseudo-registers.  If there
@@ -954,6 +1111,9 @@ decompose_multiword_subregs (bool update_life)
              || GET_CODE (PATTERN (insn)) == USE)
            continue;
 
+         if (find_decomposable_shift_zext (insn))
+           continue;
+
          recog_memoized (insn);
          extract_insn (insn);
 
@@ -963,34 +1123,8 @@ decompose_multiword_subregs (bool update_life)
            cmi = NOT_SIMPLE_MOVE;
          else
            {
-             bool retval;
-
-             retval = find_reg_note (insn, REG_RETVAL, NULL_RTX) != NULL_RTX;
-
-             if (find_pseudo_copy (set) && !retval)
+             if (find_pseudo_copy (set))
                cmi = SIMPLE_PSEUDO_REG_MOVE;
-             else if (retval
-                      && REG_P (SET_SRC (set))
-                      && HARD_REGISTER_P (SET_SRC (set)))
-               {
-                 rtx note;
-
-                 /* We don't want to decompose an assignment which
-                    copies the value returned by a libcall to a
-                    pseudo-register.  Doing that will lose the RETVAL
-                    note with no real gain.  */
-                 cmi = NOT_SIMPLE_MOVE;
-
-                 /* If we have a RETVAL note, there should be an
-                    EQUAL note.  We don't want to decompose any
-                    registers which that EQUAL note refers to
-                    directly.  If we do, we will no longer know the
-                    value of the libcall.  */
-                 note = find_reg_equal_equiv_note (insn);
-                 if (note != NULL_RTX)
-                   for_each_rtx (&XEXP (note, 0), find_decomposable_subregs,
-                                 &cmi);
-               }
              else
                cmi = SIMPLE_MOVE;
            }
@@ -1020,17 +1154,16 @@ decompose_multiword_subregs (bool update_life)
   bitmap_and_compl_into (decomposable_context, non_decomposable_context);
   if (!bitmap_empty_p (decomposable_context))
     {
-      int hold_no_new_pseudos = no_new_pseudos;
-      int max_regno = max_reg_num ();
-      sbitmap blocks;
+      sbitmap sub_blocks;
+      unsigned int i;
+      sbitmap_iterator sbi;
       bitmap_iterator iter;
       unsigned int regno;
 
       propagate_pseudo_copies ();
 
-      no_new_pseudos = 0;
-      blocks = sbitmap_alloc (last_basic_block);
-      sbitmap_zero (blocks);
+      sub_blocks = sbitmap_alloc (last_basic_block);
+      sbitmap_zero (sub_blocks);
 
       EXECUTE_IF_SET_IN_BITMAP (decomposable_context, 0, regno, iter)
        decompose_register (regno);
@@ -1041,26 +1174,18 @@ decompose_multiword_subregs (bool update_life)
 
          FOR_BB_INSNS (bb, insn)
            {
-             rtx next, pat;
-             bool changed;
+             rtx pat;
 
              if (!INSN_P (insn))
                continue;
 
-             next = NEXT_INSN (insn);
-             changed = false;
-
              pat = PATTERN (insn);
              if (GET_CODE (pat) == CLOBBER)
-               {
-                 if (resolve_clobber (pat, insn))
-                   changed = true;
-               }
+               resolve_clobber (pat, insn);
              else if (GET_CODE (pat) == USE)
-               {
-                 if (resolve_use (pat, insn))
-                   changed = true;
-               }
+               resolve_use (pat, insn);
+             else if (DEBUG_INSN_P (insn))
+               resolve_debug (insn);
              else
                {
                  rtx set;
@@ -1073,12 +1198,41 @@ decompose_multiword_subregs (bool update_life)
                  if (set)
                    {
                      rtx orig_insn = insn;
+                     bool cfi = control_flow_insn_p (insn);
+
+                     /* We can end up splitting loads to multi-word pseudos
+                        into separate loads to machine word size pseudos.
+                        When this happens, we first had one load that can
+                        throw, and after resolve_simple_move we'll have a
+                        bunch of loads (at least two).  All those loads may
+                        trap if we can have non-call exceptions, so they
+                        all will end the current basic block.  We split the
+                        block after the outer loop over all insns, but we
+                        make sure here that we will be able to split the
+                        basic block and still produce the correct control
+                        flow graph for it.  */
+                     gcc_assert (!cfi
+                                 || (flag_non_call_exceptions
+                                     && can_throw_internal (insn)));
 
                      insn = resolve_simple_move (set, insn);
                      if (insn != orig_insn)
                        {
-                         changed = true;
+                         recog_memoized (insn);
+                         extract_insn (insn);
 
+                         if (cfi)
+                           SET_BIT (sub_blocks, bb->index);
+                       }
+                   }
+                 else
+                   {
+                     rtx decomposed_shift;
+
+                     decomposed_shift = resolve_shift_zext (insn);
+                     if (decomposed_shift != NULL_RTX)
+                       {
+                         insn = decomposed_shift;
                          recog_memoized (insn);
                          extract_insn (insn);
                        }
@@ -1099,31 +1253,47 @@ decompose_multiword_subregs (bool update_life)
                          int dup_num = recog_data.dup_num[i];
                          rtx *px = recog_data.operand_loc[dup_num];
 
-                         validate_change (insn, pl, *px, 1);
+                         validate_unshare_change (insn, pl, *px, 1);
                        }
 
                      i = apply_change_group ();
                      gcc_assert (i);
-
-                     changed = true;
                    }
                }
+           }
+       }
+
+      /* If we had insns to split that caused control flow insns in the middle
+        of a basic block, split those blocks now.  Note that we only handle
+        the case where splitting a load has caused multiple possibly trapping
+        loads to appear.  */
+      EXECUTE_IF_SET_IN_SBITMAP (sub_blocks, 0, i, sbi)
+       {
+         rtx insn, end;
+         edge fallthru;
+
+         bb = BASIC_BLOCK (i);
+         insn = BB_HEAD (bb);
+         end = BB_END (bb);
 
-             if (changed)
+         while (insn != end)
+           {
+             if (control_flow_insn_p (insn))
                {
-                 SET_BIT (blocks, bb->index);
-                 reg_scan_update (insn, next, max_regno);
+                 /* Split the block after insn.  There will be a fallthru
+                    edge, which is OK so we keep it.  We have to create the
+                    exception edges ourselves.  */
+                 fallthru = split_block (bb, insn);
+                 rtl_make_eh_edge (NULL, bb, BB_END (bb));
+                 bb = fallthru->dest;
+                 insn = BB_HEAD (bb);
                }
+             else
+               insn = NEXT_INSN (insn);
            }
        }
 
-      no_new_pseudos = hold_no_new_pseudos;
-
-      if (update_life)
-       update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
-                         PROP_DEATH_NOTES);
-
-      sbitmap_free (blocks);
+      sbitmap_free (sub_blocks);
     }
 
   {
@@ -1135,7 +1305,7 @@ decompose_multiword_subregs (bool update_life)
        BITMAP_FREE (b);
   }
 
-  VEC_free (bitmap, heap, reg_copy_graph);  
+  VEC_free (bitmap, heap, reg_copy_graph);
 
   BITMAP_FREE (decomposable_context);
   BITMAP_FREE (non_decomposable_context);
@@ -1154,7 +1324,7 @@ gate_handle_lower_subreg (void)
 static unsigned int
 rest_of_handle_lower_subreg (void)
 {
-  decompose_multiword_subregs (false);
+  decompose_multiword_subregs ();
   return 0;
 }
 
@@ -1163,13 +1333,15 @@ rest_of_handle_lower_subreg (void)
 static unsigned int
 rest_of_handle_lower_subreg2 (void)
 {
-  decompose_multiword_subregs (true);
+  decompose_multiword_subregs ();
   return 0;
 }
 
-struct tree_opt_pass pass_lower_subreg =
+struct rtl_opt_pass pass_lower_subreg =
 {
-  "subreg",                            /* name */
+ {
+  RTL_PASS,
+  "subreg1",                           /* name */
   gate_handle_lower_subreg,             /* gate */
   rest_of_handle_lower_subreg,          /* execute */
   NULL,                                 /* sub */
@@ -1181,12 +1353,15 @@ struct tree_opt_pass pass_lower_subreg =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'u'                                   /* letter */
+  TODO_ggc_collect |
+  TODO_verify_flow                      /* todo_flags_finish */
+ }
 };
 
-struct tree_opt_pass pass_lower_subreg2 =
+struct rtl_opt_pass pass_lower_subreg2 =
 {
+ {
+  RTL_PASS,
   "subreg2",                           /* name */
   gate_handle_lower_subreg,             /* gate */
   rest_of_handle_lower_subreg2,          /* execute */
@@ -1198,7 +1373,9 @@ struct tree_opt_pass pass_lower_subreg2 =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'U'                                   /* letter */
+  TODO_ggc_collect |
+  TODO_verify_flow                      /* todo_flags_finish */
+ }
 };