OSDN Git Service

PR c/20187
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 12b0fbf..8e6a62b 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used by or related to instruction recognition.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
@@ -39,6 +39,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "output.h"
 #include "reload.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
@@ -107,22 +109,6 @@ init_recog (void)
   volatile_ok = 1;
 }
 
-/* Try recognizing the instruction INSN,
-   and return the code number that results.
-   Remember the code so that repeated calls do not
-   need to spend the time for actual rerecognition.
-
-   This function is the normal interface to instruction recognition.
-   The automatically-generated function `recog' is normally called
-   through this one.  (The only exception is in combine.c.)  */
-
-int
-recog_memoized_1 (rtx insn)
-{
-  if (INSN_CODE (insn) < 0)
-    INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
-  return INSN_CODE (insn);
-}
 \f
 /* Check that X is an insn-body for an `asm' with operands
    and that the operands mentioned in it are legitimate.  */
@@ -211,8 +197,7 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group)
   if (old == new || rtx_equal_p (old, new))
     return 1;
 
-  if (in_group == 0 && num_changes != 0)
-    abort ();
+  gcc_assert (in_group != 0 || num_changes == 0);
 
   *loc = new;
 
@@ -252,6 +237,46 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group)
     return apply_change_group ();
 }
 
+
+/* Function to be passed to for_each_rtx to test whether a piece of
+   RTL contains any mem/v.  */
+static int
+volatile_mem_p (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  return (MEM_P (*x) && MEM_VOLATILE_P (*x));
+}
+
+/* Same as validate_change, but doesn't support groups, and it accepts
+   volatile mems if they're already present in the original insn.  */
+
+int
+validate_change_maybe_volatile (rtx object, rtx *loc, rtx new)
+{
+  int result;
+
+  if (validate_change (object, loc, new, 0))
+    return 1;
+
+  if (volatile_ok
+      /* If there isn't a volatile MEM, there's nothing we can do.  */
+      || !for_each_rtx (&PATTERN (object), volatile_mem_p, 0)
+      /* Make sure we're not adding or removing volatile MEMs.  */
+      || for_each_rtx (loc, volatile_mem_p, 0)
+      || for_each_rtx (&new, volatile_mem_p, 0)
+      || !insn_invalid_p (object))
+    return 0;
+
+  volatile_ok = 1;
+
+  gcc_assert (!insn_invalid_p (object));
+
+  result = validate_change (object, loc, new, 0);
+
+  volatile_ok = 0;
+
+  return result;
+}
+
 /* This subroutine of apply_change_group verifies whether the changes to INSN
    were valid; i.e. whether INSN can still be recognized.  */
 
@@ -311,11 +336,11 @@ num_changes_pending (void)
   return num_changes;
 }
 
-/* Apply a group of changes previously issued with `validate_change'.
+/* Tentatively apply the changes numbered NUM and up.
    Return 1 if all changes are valid, zero otherwise.  */
 
-int
-apply_change_group (void)
+static int
+verify_changes (int num)
 {
   int i;
   rtx last_validated = NULL_RTX;
@@ -329,7 +354,7 @@ apply_change_group (void)
      we also require that the operands meet the constraints for
      the insn.  */
 
-  for (i = 0; i < num_changes; i++)
+  for (i = num; i < num_changes; i++)
     {
       rtx object = changes[i].object;
 
@@ -393,17 +418,38 @@ apply_change_group (void)
       last_validated = object;
     }
 
-  if (i == num_changes)
-    {
-      basic_block bb;
+  return (i == num_changes);
+}
+
+/* A group of changes has previously been issued with validate_change and
+   verified with verify_changes.  Update the BB_DIRTY flags of the affected
+   blocks, and clear num_changes.  */
+
+void
+confirm_change_group (void)
+{
+  int i;
+  basic_block bb;
+
+  for (i = 0; i < num_changes; i++)
+    if (changes[i].object
+       && INSN_P (changes[i].object)
+       && (bb = BLOCK_FOR_INSN (changes[i].object)))
+      bb->flags |= BB_DIRTY;
+
+  num_changes = 0;
+}
 
-      for (i = 0; i < num_changes; i++)
-       if (changes[i].object
-           && INSN_P (changes[i].object)
-           && (bb = BLOCK_FOR_INSN (changes[i].object)))
-         bb->flags |= BB_DIRTY;
+/* Apply a group of changes previously issued with `validate_change'.
+   If all changes are valid, call confirm_change_group and return 1,
+   otherwise, call cancel_changes and return 0.  */
 
-      num_changes = 0;
+int
+apply_change_group (void)
+{
+  if (verify_changes (0))
+    {
+      confirm_change_group ();
       return 1;
     }
   else
@@ -413,6 +459,7 @@ apply_change_group (void)
     }
 }
 
+
 /* Return the number of changes so far in the current group.  */
 
 int
@@ -489,9 +536,9 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object)
              && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS)
            {
              /* Verify that operands are really shared.  */
-             if (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) !=
-                 ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, j))))
-               abort ();
+             gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0)))
+                         == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP
+                                                             (x, 0, j))));
              validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)),
                                      from, to, object);
            }
@@ -937,8 +984,10 @@ general_operand (rtx op, enum machine_mode mode)
 
 #ifdef INSN_SCHEDULING
       /* On machines that have insn scheduling, we want all memory
-        reference to be explicit, so outlaw paradoxical SUBREGs.  */
-      if (MEM_P (sub)
+        reference to be explicit, so outlaw paradoxical SUBREGs.
+        However, we must allow them after reload so that they can
+        get cleaned up by cleanup_subreg_operands.  */
+      if (!reload_completed && MEM_P (sub)
          && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (sub)))
        return 0;
 #endif
@@ -975,14 +1024,11 @@ general_operand (rtx op, enum machine_mode mode)
        return 0;
 
       /* Use the mem's mode, since it will be reloaded thus.  */
-      mode = GET_MODE (op);
-      GO_IF_LEGITIMATE_ADDRESS (mode, y, win);
+      if (memory_address_p (GET_MODE (op), y))
+       return 1;
     }
 
   return 0;
-
- win:
-  return 1;
 }
 \f
 /* Return 1 if OP is a valid memory address for a memory reference
@@ -1570,8 +1616,7 @@ asm_operand_ok (rtx op, const char *constraint)
   int result = 0;
 
   /* Use constrain_operands after reload.  */
-  if (reload_completed)
-    abort ();
+  gcc_assert (!reload_completed);
 
   while (*constraint)
     {
@@ -2011,8 +2056,7 @@ extract_insn (rtx insn)
          /* This insn is an `asm' with operands.  */
 
          /* expand_asm_operands makes sure there aren't too many operands.  */
-         if (noperands > MAX_RECOG_OPERANDS)
-           abort ();
+         gcc_assert (noperands <= MAX_RECOG_OPERANDS);
 
          /* Now get the operand values and constraints out of the insn.  */
          decode_asm_operands (body, recog_data.operand,
@@ -2060,8 +2104,7 @@ extract_insn (rtx insn)
         : recog_data.constraints[i][0] == '+' ? OP_INOUT
         : OP_IN);
 
-  if (recog_data.n_alternatives > MAX_RECOG_ALTERNATIVES)
-    abort ();
+  gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES);
 }
 
 /* After calling extract_insn, you can use this function to extract some
@@ -2254,6 +2297,7 @@ constrain_operands (int strict)
 
   do
     {
+      int seen_earlyclobber_at = -1;
       int opno;
       int lose = 0;
       funny_match_index = 0;
@@ -2316,6 +2360,8 @@ constrain_operands (int strict)
 
              case '&':
                earlyclobber[opno] = 1;
+               if (seen_earlyclobber_at < 0)
+                 seen_earlyclobber_at = opno;
                break;
 
              case '0':  case '1':  case '2':  case '3':  case '4':
@@ -2564,8 +2610,10 @@ constrain_operands (int strict)
          /* See if any earlyclobber operand conflicts with some other
             operand.  */
 
-         if (strict > 0)
-           for (eopno = 0; eopno < recog_data.n_operands; eopno++)
+         if (strict > 0  && seen_earlyclobber_at >= 0)
+           for (eopno = seen_earlyclobber_at;
+                eopno < recog_data.n_operands;
+                eopno++)
              /* Ignore earlyclobber operands now in memory,
                 because we would often report failure when we have
                 two memory operands, one of which was formerly a REG.  */
@@ -2818,8 +2866,7 @@ static int peep2_current;
 rtx
 peep2_next_insn (int n)
 {
-  if (n >= MAX_INSNS_PER_PEEP2 + 1)
-    abort ();
+  gcc_assert (n < MAX_INSNS_PER_PEEP2 + 1);
 
   n += peep2_current;
   if (n >= MAX_INSNS_PER_PEEP2 + 1)
@@ -2836,15 +2883,13 @@ peep2_next_insn (int n)
 int
 peep2_regno_dead_p (int ofs, int regno)
 {
-  if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
-    abort ();
+  gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
 
   ofs += peep2_current;
   if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
     ofs -= MAX_INSNS_PER_PEEP2 + 1;
 
-  if (peep2_insn_data[ofs].insn == NULL_RTX)
-    abort ();
+  gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
 
   return ! REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno);
 }
@@ -2856,15 +2901,13 @@ peep2_reg_dead_p (int ofs, rtx reg)
 {
   int regno, n;
 
-  if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
-    abort ();
+  gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
 
   ofs += peep2_current;
   if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
     ofs -= MAX_INSNS_PER_PEEP2 + 1;
 
-  if (peep2_insn_data[ofs].insn == NULL_RTX)
-    abort ();
+  gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
 
   regno = REGNO (reg);
   n = hard_regno_nregs[regno][GET_MODE (reg)];
@@ -2894,8 +2937,8 @@ peep2_find_free_register (int from, int to, const char *class_str,
   HARD_REG_SET live;
   int i;
 
-  if (from >= MAX_INSNS_PER_PEEP2 + 1 || to >= MAX_INSNS_PER_PEEP2 + 1)
-    abort ();
+  gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
+  gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1);
 
   from += peep2_current;
   if (from >= MAX_INSNS_PER_PEEP2 + 1)
@@ -2904,8 +2947,7 @@ peep2_find_free_register (int from, int to, const char *class_str,
   if (to >= MAX_INSNS_PER_PEEP2 + 1)
     to -= MAX_INSNS_PER_PEEP2 + 1;
 
-  if (peep2_insn_data[from].insn == NULL_RTX)
-    abort ();
+  gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
   REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
 
   while (from != to)
@@ -2914,8 +2956,7 @@ peep2_find_free_register (int from, int to, const char *class_str,
 
       if (++from >= MAX_INSNS_PER_PEEP2 + 1)
        from = 0;
-      if (peep2_insn_data[from].insn == NULL_RTX)
-       abort ();
+      gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
       REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
       IOR_HARD_REG_SET (live, this_live);
     }
@@ -2987,7 +3028,6 @@ peep2_find_free_register (int from, int to, const char *class_str,
 void
 peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
 {
-  regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2];
   rtx insn, prev;
   regset live;
   int i;
@@ -2997,12 +3037,13 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
   bool changed;
 #endif
   bool do_cleanup_cfg = false;
+  bool do_global_life_update = false;
   bool do_rebuild_jump_labels = false;
 
   /* Initialize the regsets we're going to use.  */
   for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
-    peep2_insn_data[i].live_before = INITIALIZE_REG_SET (rs_heads[i]);
-  live = INITIALIZE_REG_SET (rs_heads[i]);
+    peep2_insn_data[i].live_before = ALLOC_REG_SET (&reg_obstack);
+  live = ALLOC_REG_SET (&reg_obstack);
 
 #ifdef HAVE_conditional_execution
   blocks = sbitmap_alloc (last_basic_block);
@@ -3015,6 +3056,8 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
   FOR_EACH_BB_REVERSE (bb)
     {
       struct propagate_block_info *pbi;
+      reg_set_iterator rsi;
+      unsigned int j;
 
       /* Indicate that all slots except the last holds invalid data.  */
       for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
@@ -3025,7 +3068,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
       peep2_current = MAX_INSNS_PER_PEEP2;
 
       /* Start up propagation.  */
-      COPY_REG_SET (live, bb->global_live_at_end);
+      COPY_REG_SET (live, bb->il.rtl->global_live_at_end);
       COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
 
 #ifdef HAVE_conditional_execution
@@ -3079,8 +3122,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
                          new_insn = NEXT_INSN (new_insn);
                        }
 
-                     if (new_insn == NULL_RTX)
-                       abort ();
+                     gcc_assert (new_insn != NULL_RTX);
 
                      CALL_INSN_FUNCTION_USAGE (new_insn)
                        = CALL_INSN_FUNCTION_USAGE (old_insn);
@@ -3092,7 +3134,6 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
                          {
                          case REG_NORETURN:
                          case REG_SETJMP:
-                         case REG_ALWAYS_RETURN:
                            REG_NOTES (new_insn)
                              = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
                                                   XEXP (note, 0),
@@ -3109,8 +3150,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
                          if (j >= MAX_INSNS_PER_PEEP2 + 1)
                            j -= MAX_INSNS_PER_PEEP2 + 1;
                          old_insn = peep2_insn_data[j].insn;
-                         if (CALL_P (old_insn))
-                           abort ();
+                         gcc_assert (!CALL_P (old_insn));
                        }
                      break;
                    }
@@ -3132,9 +3172,9 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
                  if (note || (was_call && nonlocal_goto_handler_labels))
                    {
                      edge eh_edge;
+                     edge_iterator ei;
 
-                     for (eh_edge = bb->succ; eh_edge
-                          ; eh_edge = eh_edge->succ_next)
+                     FOR_EACH_EDGE (eh_edge, ei, bb->succs)
                        if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
                          break;
 
@@ -3238,6 +3278,15 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
            break;
        }
 
+      /* Some peepholes can decide the don't need one or more of their
+        inputs.  If this happens, local life update is not enough.  */
+      EXECUTE_IF_AND_COMPL_IN_BITMAP (bb->il.rtl->global_live_at_start, live,
+                                     0, j, rsi)
+       {
+         do_global_life_update = true;
+         break;
+       }
+
       free_propagate_block_info (pbi);
     }
 
@@ -3254,8 +3303,10 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
   if (do_cleanup_cfg)
     {
       cleanup_cfg (0);
-      update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
+      do_global_life_update = true;
     }
+  if (do_global_life_update)
+    update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
 #ifdef HAVE_conditional_execution
   else
     {
@@ -3280,8 +3331,7 @@ store_data_bypass_p (rtx out_insn, rtx in_insn)
   rtx out_set, in_set;
 
   in_set = single_set (in_insn);
-  if (! in_set)
-    abort ();
+  gcc_assert (in_set);
 
   if (!MEM_P (SET_DEST (in_set)))
     return false;
@@ -3298,8 +3348,7 @@ store_data_bypass_p (rtx out_insn, rtx in_insn)
       int i;
 
       out_pat = PATTERN (out_insn);
-      if (GET_CODE (out_pat) != PARALLEL)
-       abort ();
+      gcc_assert (GET_CODE (out_pat) == PARALLEL);
 
       for (i = 0; i < XVECLEN (out_pat, 0); i++)
        {
@@ -3308,8 +3357,7 @@ store_data_bypass_p (rtx out_insn, rtx in_insn)
          if (GET_CODE (exp) == CLOBBER)
            continue;
 
-         if (GET_CODE (exp) != SET)
-           abort ();
+         gcc_assert (GET_CODE (exp) == SET);
 
          if (reg_mentioned_p (SET_DEST (exp), SET_DEST (in_set)))
            return false;
@@ -3332,9 +3380,8 @@ if_test_bypass_p (rtx out_insn, rtx in_insn)
   in_set = single_set (in_insn);
   if (! in_set)
     {
-      if (JUMP_P (in_insn) || CALL_P (in_insn))
-       return false;
-      abort ();
+      gcc_assert (JUMP_P (in_insn) || CALL_P (in_insn));
+      return false;
     }
 
   if (GET_CODE (SET_SRC (in_set)) != IF_THEN_ELSE)
@@ -3354,8 +3401,7 @@ if_test_bypass_p (rtx out_insn, rtx in_insn)
       int i;
 
       out_pat = PATTERN (out_insn);
-      if (GET_CODE (out_pat) != PARALLEL)
-       abort ();
+      gcc_assert (GET_CODE (out_pat) == PARALLEL);
 
       for (i = 0; i < XVECLEN (out_pat, 0); i++)
        {
@@ -3364,8 +3410,7 @@ if_test_bypass_p (rtx out_insn, rtx in_insn)
          if (GET_CODE (exp) == CLOBBER)
            continue;
 
-         if (GET_CODE (exp) != SET)
-           abort ();
+         gcc_assert (GET_CODE (exp) == SET);
 
          if (reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 1))
              || reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 2)))
@@ -3375,3 +3420,122 @@ if_test_bypass_p (rtx out_insn, rtx in_insn)
 
   return true;
 }
+\f
+static bool
+gate_handle_peephole2 (void)
+{
+  return (optimize > 0 && flag_peephole2);
+}
+
+static void
+rest_of_handle_peephole2 (void)
+{
+#ifdef HAVE_peephole2
+  peephole2_optimize (dump_file);
+#endif
+}
+
+struct tree_opt_pass pass_peephole2 =
+{
+  "peephole2",                          /* name */
+  gate_handle_peephole2,                /* gate */
+  rest_of_handle_peephole2,             /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_PEEPHOLE2,                         /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'z'                                   /* letter */
+};
+
+static void
+rest_of_handle_split_all_insns (void)
+{
+  split_all_insns (1);
+}
+
+struct tree_opt_pass pass_split_all_insns =
+{
+  NULL,                                 /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_split_all_insns,       /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  0,                                    /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,                                    /* todo_flags_finish */
+  0                                     /* letter */
+};
+
+/* The placement of the splitting that we do for shorten_branches
+   depends on whether regstack is used by the target or not.  */
+static bool
+gate_do_final_split (void)
+{
+#if defined (HAVE_ATTR_length) && !defined (STACK_REGS)
+  return 1;
+#else
+  return 0;
+#endif 
+}
+
+struct tree_opt_pass pass_split_for_shorten_branches =
+{
+  NULL,                                 /* name */
+  gate_do_final_split,                  /* gate */
+  split_all_insns_noflow,               /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_SHORTEN_BRANCH,                    /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,                                    /* todo_flags_finish */
+  0                                     /* letter */
+};
+
+
+static bool
+gate_handle_split_before_regstack (void)
+{
+#if defined (HAVE_ATTR_length) && defined (STACK_REGS)
+  /* If flow2 creates new instructions which need splitting
+     and scheduling after reload is not done, they might not be
+     split until final which doesn't allow splitting
+     if HAVE_ATTR_length.  */
+# ifdef INSN_SCHEDULING
+  return (optimize && !flag_schedule_insns_after_reload);
+# else
+  return (optimize);
+# endif
+#else
+  return 0;
+#endif
+}
+
+struct tree_opt_pass pass_split_before_regstack =
+{
+  NULL,                                 /* name */
+  gate_handle_split_before_regstack,    /* gate */
+  rest_of_handle_split_all_insns,       /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_SHORTEN_BRANCH,                    /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,                                    /* todo_flags_finish */
+  0                                     /* letter */
+};