OSDN Git Service

PR fortran/26025
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index 6d99a92..d64f0c3 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert RTL to assembler code and output it, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -72,6 +72,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "debug.h"
 #include "expr.h"
 #include "cfglayout.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cgraph.h"
+#include "coverage.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -86,6 +90,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "dbxout.h"
 #endif
 
+#ifdef SDB_DEBUGGING_INFO
+#include "sdbout.h"
+#endif
+
 /* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
    null default for it to save conditionalization later.  */
 #ifndef CC_STATUS_INIT
@@ -106,12 +114,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
 
-#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
-#define HAVE_READONLY_DATA_SECTION 1
-#else
-#define HAVE_READONLY_DATA_SECTION 0
-#endif
-
 /* Bitflags used by final_scan_insn.  */
 #define SEEN_BB                1
 #define SEEN_NOTE      2
@@ -133,7 +135,10 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
-extern int length_unit_log; /* This is defined in insn-attrtab.c.  */
+/* Whether to force emission of a line note before the next insn.  */
+static bool force_source_line = false;
+
+extern const int length_unit_log; /* This is defined in insn-attrtab.c.  */
 
 /* Nonzero while outputting an `asm' with operands.
    This means that inconsistencies are the user's fault, so don't die.
@@ -375,10 +380,11 @@ init_insn_lengths (void)
 }
 
 /* Obtain the current length of an insn.  If branch shortening has been done,
-   get its actual length.  Otherwise, get its maximum length.  */
-
-int
-get_attr_length (rtx insn ATTRIBUTE_UNUSED)
+   get its actual length.  Otherwise, use FALLBACK_FN to calculate the
+   length.  */
+static inline int
+get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
+                  int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_ATTR_length
   rtx body;
@@ -396,7 +402,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
        return 0;
 
       case CALL_INSN:
-       length = insn_default_length (insn);
+       length = fallback_fn (insn);
        break;
 
       case JUMP_INSN:
@@ -407,7 +413,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
               ADDR_VEC_ALIGN.  */
          }
        else
-         length = insn_default_length (insn);
+         length = fallback_fn (insn);
        break;
 
       case INSN:
@@ -416,12 +422,12 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
          return 0;
 
        else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
-         length = asm_insn_count (body) * insn_default_length (insn);
+         length = asm_insn_count (body) * fallback_fn (insn);
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
            length += get_attr_length (XVECEXP (body, 0, i));
        else
-         length = insn_default_length (insn);
+         length = fallback_fn (insn);
        break;
 
       default:
@@ -434,8 +440,26 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
   return length;
 #else /* not HAVE_ATTR_length */
   return 0;
+#define insn_default_length 0
+#define insn_min_length 0
 #endif /* not HAVE_ATTR_length */
 }
+
+/* Obtain the current length of an insn.  If branch shortening has been done,
+   get its actual length.  Otherwise, get its maximum length.  */
+int
+get_attr_length (rtx insn)
+{
+  return get_attr_length_1 (insn, insn_default_length);
+}
+
+/* Obtain the current length of an insn.  If branch shortening has been done,
+   get its actual length.  Otherwise, get its minimum length.  */
+int
+get_attr_min_length (rtx insn)
+{
+  return get_attr_length_1 (insn, insn_min_length);
+}
 \f
 /* Code to handle alignment inside shorten_branches.  */
 
@@ -652,7 +676,10 @@ insn_current_reference_address (rtx branch)
 }
 #endif /* HAVE_ATTR_length */
 \f
-void
+/* Compute branch alignments based on frequency information in the
+   CFG.  */
+
+static unsigned int
 compute_alignments (void)
 {
   int log, max_skip, max_log;
@@ -666,12 +693,11 @@ compute_alignments (void)
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
-  label_align = xcalloc (max_labelno - min_labelno + 1,
-                        sizeof (struct label_alignment));
+  label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1);
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
   if (! optimize || optimize_size)
-    return;
+    return 0;
 
   FOR_EACH_BB (bb)
     {
@@ -734,7 +760,26 @@ compute_alignments (void)
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
+  return 0;
 }
+
+struct tree_opt_pass pass_compute_alignments =
+{
+  NULL,                                 /* name */
+  NULL,                                 /* gate */
+  compute_alignments,                   /* 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 */
+};
+
 \f
 /* Make a pass over all insns and compute their actual lengths by shortening
    any branches of variable length if possible.  */
@@ -771,8 +816,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
   /* Free uid_shuid before reallocating it.  */
   free (uid_shuid);
-  
-  uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
+
+  uid_shuid = XNEWVEC (int, max_uid);
 
   if (max_labelno != max_label_num ())
     {
@@ -811,14 +856,9 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
-       {
-         /* reorg might make the first insn of a loop being run once only,
-             and delete the label in front of it.  Then we want to apply
-             the loop alignment to the new label created by reorg, which
-             is separated by the former loop start insn from the
-            NOTE_INSN_LOOP_BEG.  */
-       }
-      else if (LABEL_P (insn))
+       continue;
+
+      if (LABEL_P (insn))
        {
          rtx next;
 
@@ -839,7 +879,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          next = next_nonnote_insn (insn);
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
-         if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+         if (JUMP_TABLES_IN_TEXT_SECTION
+             || readonly_data_section == text_section)
            if (next && JUMP_P (next))
              {
                rtx nextbody = PATTERN (next);
@@ -880,20 +921,20 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
-  insn_lengths = xmalloc (max_uid * sizeof (*insn_lengths));
+  insn_lengths = XNEWVEC (int, max_uid);
   insn_lengths_max_uid = max_uid;
   /* Syntax errors can lead to labels being outside of the main insn stream.
      Initialize insn_addresses, so that we get reproducible results.  */
   INSN_ADDRESSES_ALLOC (max_uid);
 
-  varying_length = xcalloc (max_uid, sizeof (char));
+  varying_length = XCNEWVEC (char, max_uid);
 
   /* Initialize uid_align.  We scan instructions
      from end to start, and keep in align_tab[n] the last seen insn
      that does an alignment of at least n+1, i.e. the successor
      in the alignment chain for an insn that does / has a known
      alignment of n.  */
-  uid_align = xcalloc (max_uid, sizeof *uid_align);
+  uid_align = XCNEWVEC (rtx, max_uid);
 
   for (i = MAX_CODE_ALIGN; --i >= 0;)
     align_tab[i] = NULL_RTX;
@@ -1002,7 +1043,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
        {
          /* This only takes room if read-only data goes into the text
             section.  */
-         if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+         if (JUMP_TABLES_IN_TEXT_SECTION
+             || readonly_data_section == text_section)
            insn_lengths[uid] = (XVECLEN (body,
                                          GET_CODE (body) == ADDR_DIFF_VEC)
                                 * GET_MODE_SIZE (GET_MODE (body)));
@@ -1203,7 +1245,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
              PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
                                                        max_addr - rel_addr,
                                                        body));
-             if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+             if (JUMP_TABLES_IN_TEXT_SECTION
+                 || readonly_data_section == text_section)
                {
                  insn_lengths[uid]
                    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
@@ -1374,7 +1417,6 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
      function.  */
   if (write_symbols)
     {
-      remove_unnecessary_notes ();
       reemit_insn_block_notes ();
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
@@ -1420,13 +1462,13 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
   if (! NO_PROFILE_COUNTERS)
     {
       int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
-      data_section ();
+      switch_to_section (data_section);
       ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
       targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
       assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
     }
 
-  current_function_section (current_function_decl);
+  switch_to_section (current_function_section ());
 
 #if defined(ASM_OUTPUT_REG_PUSH)
   if (sval && svrtx != NULL_RTX && REG_P (svrtx))
@@ -1655,34 +1697,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
       switch (NOTE_LINE_NUMBER (insn))
        {
        case NOTE_INSN_DELETED:
-       case NOTE_INSN_LOOP_BEG:
-       case NOTE_INSN_LOOP_END:
        case NOTE_INSN_FUNCTION_END:
        case NOTE_INSN_REPEATED_LINE_NUMBER:
        case NOTE_INSN_EXPECTED_VALUE:
          break;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
-         
-         /* The presence of this note indicates that this basic block
-            belongs in the "cold" section of the .o file.  If we are
-            not already writing to the cold section we need to change
-            to it.  */
-
-         if (last_text_section == in_text)
-           {
-             (*debug_hooks->switch_text_section) ();
-             unlikely_text_section ();
-           }
-         else
-           {
-             (*debug_hooks->switch_text_section) ();
-             text_section ();
-           }
+         in_cold_section_p = !in_cold_section_p;
+         (*debug_hooks->switch_text_section) ();
+         switch_to_section (current_function_section ());
          break;
-         
+
        case NOTE_INSN_BASIC_BLOCK:
-         
 #ifdef TARGET_UNWIND_INFO
          targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
@@ -1694,7 +1720,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
            {
              *seen |= SEEN_EMITTED;
-             last_filename = NULL;
+             force_source_line = true;
            }
          else
            *seen |= SEEN_BB;
@@ -1718,7 +1744,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
              *seen |= SEEN_EMITTED;
-             last_filename = NULL;
+             force_source_line = true;
            }
          else
            *seen |= SEEN_NOTE;
@@ -1736,7 +1762,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
              *seen |= SEEN_EMITTED;
-             last_filename = NULL;
+             force_source_line = true;
            }
          else
            *seen |= SEEN_NOTE;
@@ -1891,7 +1917,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                {
                  int log_align;
 
-                 targetm.asm_out.function_rodata_section (current_function_decl);
+                 switch_to_section (targetm.asm_out.function_rodata_section
+                                    (current_function_decl));
 
 #ifdef ADDR_VEC_ALIGN
                  log_align = ADDR_VEC_ALIGN (next);
@@ -1901,7 +1928,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                  ASM_OUTPUT_ALIGN (file, log_align);
                }
              else
-               current_function_section (current_function_decl);
+               switch_to_section (current_function_section ());
 
 #ifdef ASM_OUTPUT_CASE_LABEL
              ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
@@ -1925,6 +1952,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        int insn_code_number;
        const char *template;
 
+#ifdef HAVE_conditional_execution
+       /* Reset this early so it is correct for ASM statements.  */
+       current_insn_predicate = NULL_RTX;
+#endif
        /* An INSN, JUMP_INSN or CALL_INSN.
           First check for special kinds that recog doesn't recognize.  */
 
@@ -1958,9 +1989,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
 
            if (! JUMP_TABLES_IN_TEXT_SECTION)
-             targetm.asm_out.function_rodata_section (current_function_decl);
+             switch_to_section (targetm.asm_out.function_rodata_section
+                                (current_function_decl));
            else
-             current_function_section (current_function_decl);
+             switch_to_section (current_function_section ());
 
            if (app_on)
              {
@@ -2018,7 +2050,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
 #endif
 
-           current_function_section (current_function_decl);
+           switch_to_section (current_function_section ());
 
            break;
          }
@@ -2359,8 +2391,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #ifdef HAVE_conditional_execution
        if (GET_CODE (PATTERN (insn)) == COND_EXEC)
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
-       else
-         current_insn_predicate = NULL_RTX;
 #endif
 
 #ifdef HAVE_cc0
@@ -2456,8 +2486,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
   return NEXT_INSN (insn);
 }
 \f
-/* Output debugging info to the assembler file FILE
-   based on the NOTE-insn INSN, assumed to be a line number.  */
+/* Return whether a source line note needs to be emitted before INSN.  */
 
 static bool
 notice_source_line (rtx insn)
@@ -2465,8 +2494,12 @@ notice_source_line (rtx insn)
   const char *filename = insn_file (insn);
   int linenum = insn_line (insn);
 
-  if (filename && (filename != last_filename || last_linenum != linenum))
+  if (filename
+      && (force_source_line
+         || filename != last_filename
+         || last_linenum != linenum))
     {
+      force_source_line = false;
       last_filename = filename;
       last_linenum = linenum;
       high_block_linenum = MAX (last_linenum, high_block_linenum);
@@ -3017,7 +3050,7 @@ output_asm_insn (const char *template, rtx *operands)
            int letter = *p++;
            unsigned long opnum;
            char *endptr;
-           
+
            opnum = strtoul (p, &endptr, 10);
 
            if (endptr == p)
@@ -3062,7 +3095,7 @@ output_asm_insn (const char *template, rtx *operands)
          {
            unsigned long opnum;
            char *endptr;
-           
+
            opnum = strtoul (p, &endptr, 10);
            if (this_is_asm_operands && opnum >= insn_noperands)
              output_operand_lossage ("operand number out of range");
@@ -3636,7 +3669,7 @@ int
 final_forward_branch_p (rtx insn)
 {
   int insn_id, label_id;
-  
+
   gcc_assert (uid_shuid);
   insn_id = INSN_SHUID (insn);
   label_id = INSN_SHUID (JUMP_LABEL (insn));
@@ -3812,7 +3845,7 @@ debug_flush_symbol_queue (void)
 
   for (i = 0; i < symbol_queue_index; ++i)
     {
-      /* If we pushed queued symbols then such symbols are must be
+      /* If we pushed queued symbols then such symbols must be
          output no matter what anyone else says.  Specifically,
          we need to make sure dbxout_symbol() thinks the symbol was
          used and also we need to override TYPE_DECL_SUPPRESS_DEBUG
@@ -3862,3 +3895,192 @@ debug_free_queue (void)
       symbol_queue_size = 0;
     }
 }
+\f
+/* Turn the RTL into assembly.  */
+static unsigned int
+rest_of_handle_final (void)
+{
+  rtx x;
+  const char *fnname;
+
+  /* Get the function's name, as described by its RTL.  This may be
+     different from the DECL_NAME name used in the source file.  */
+
+  x = DECL_RTL (current_function_decl);
+  gcc_assert (MEM_P (x));
+  x = XEXP (x, 0);
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
+  fnname = XSTR (x, 0);
+
+  assemble_start_function (current_function_decl, fnname);
+  final_start_function (get_insns (), asm_out_file, optimize);
+  final (get_insns (), asm_out_file, optimize);
+  final_end_function ();
+
+#ifdef TARGET_UNWIND_INFO
+  /* ??? The IA-64 ".handlerdata" directive must be issued before
+     the ".endp" directive that closes the procedure descriptor.  */
+  output_function_exception_table ();
+#endif
+
+  assemble_end_function (current_function_decl, fnname);
+
+#ifndef TARGET_UNWIND_INFO
+  /* Otherwise, it feels unclean to switch sections in the middle.  */
+  output_function_exception_table ();
+#endif
+
+  user_defined_section_attribute = false;
+
+  if (! quiet_flag)
+    fflush (asm_out_file);
+
+  /* Release all memory allocated by flow.  */
+  free_basic_block_vars ();
+
+  /* Write DBX symbols if requested.  */
+
+  /* Note that for those inline functions where we don't initially
+     know for certain that we will be generating an out-of-line copy,
+     the first invocation of this routine (rest_of_compilation) will
+     skip over this code by doing a `goto exit_rest_of_compilation;'.
+     Later on, wrapup_global_declarations will (indirectly) call
+     rest_of_compilation again for those inline functions that need
+     to have out-of-line copies generated.  During that call, we
+     *will* be routed past here.  */
+
+  timevar_push (TV_SYMOUT);
+  (*debug_hooks->function_decl) (current_function_decl);
+  timevar_pop (TV_SYMOUT);
+  return 0;
+}
+
+struct tree_opt_pass pass_final =
+{
+  NULL,                                 /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_final,                 /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_FINAL,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  0                                     /* letter */
+};
+
+
+static unsigned int
+rest_of_handle_shorten_branches (void)
+{
+  /* Shorten branches.  */
+  shorten_branches (get_insns ());
+  return 0;
+}
+
+struct tree_opt_pass pass_shorten_branches =
+{
+  "shorten",                            /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_shorten_branches,      /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_FINAL,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  0                                     /* letter */
+};
+
+
+static unsigned int
+rest_of_clean_state (void)
+{
+  rtx insn, next;
+
+  /* It is very important to decompose the RTL instruction chain here:
+     debug information keeps pointing into CODE_LABEL insns inside the function
+     body.  If these remain pointing to the other insns, we end up preserving
+     whole RTL chain and attached detailed debug info in memory.  */
+  for (insn = get_insns (); insn; insn = next)
+    {
+      next = NEXT_INSN (insn);
+      NEXT_INSN (insn) = NULL;
+      PREV_INSN (insn) = NULL;
+    }
+
+  /* In case the function was not output,
+     don't leave any temporary anonymous types
+     queued up for sdb output.  */
+#ifdef SDB_DEBUGGING_INFO
+  if (write_symbols == SDB_DEBUG)
+    sdbout_types (NULL_TREE);
+#endif
+
+  reload_completed = 0;
+  epilogue_completed = 0;
+  flow2_completed = 0;
+  no_new_pseudos = 0;
+#ifdef STACK_REGS
+  regstack_completed = 0;
+#endif
+
+  /* Clear out the insn_length contents now that they are no
+     longer valid.  */
+  init_insn_lengths ();
+
+  /* Show no temporary slots allocated.  */
+  init_temp_slots ();
+
+  free_basic_block_vars ();
+  free_bb_for_insn ();
+
+
+  if (targetm.binds_local_p (current_function_decl))
+    {
+      int pref = cfun->preferred_stack_boundary;
+      if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
+        pref = cfun->stack_alignment_needed;
+      cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
+        = pref;
+    }
+
+  /* Make sure volatile mem refs aren't considered valid operands for
+     arithmetic insns.  We must call this here if this is a nested inline
+     function, since the above code leaves us in the init_recog state,
+     and the function context push/pop code does not save/restore volatile_ok.
+
+     ??? Maybe it isn't necessary for expand_start_function to call this
+     anymore if we do it here?  */
+
+  init_recog_no_volatile ();
+
+  /* We're done with this function.  Free up memory if we can.  */
+  free_after_parsing (cfun);
+  free_after_compilation (cfun);
+  return 0;
+}
+
+struct tree_opt_pass pass_clean_state =
+{
+  NULL,                                 /* name */
+  NULL,                                 /* gate */
+  rest_of_clean_state,                  /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_FINAL,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  PROP_rtl,                             /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,                                    /* todo_flags_finish */
+  0                                     /* letter */
+};
+