public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-)
@ 2004-07-05 10:37 Paolo Bonzini
  2004-07-05 13:31 ` Paolo Bonzini
  2004-07-08  5:30 ` Richard Henderson
  0 siblings, 2 replies; 5+ messages in thread
From: Paolo Bonzini @ 2004-07-05 10:37 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 788 bytes --]

Now that rest_of_compilation is not used anymore outside the pass 
manager, it becomes more interesting to get rid of it.  Thus this patch 
which completely streamlines its operation into a series of 
rest_of_handle_* functions.

This is huge but mostly cut&paste, the only "interesting" change is the 
removal of current_function_nothrow which can be replaced with 
TREE_NOTHROW (current_function_decl).

The next step will be unifying the two dump file managers, so that in 
the meanwhile we'll also gain switches like -fdump-rtl-combine.

Bootstrapped/regtested i686-pc-linux-gnu, checked with a cross to 
sparc-sun-solaris2.8 that the assembly for combine.c stays the same.

Ok for mainline?  This patch is the most invasive I have in my tree, and 
I'd like to get it flushed.

Paolo

[-- Attachment #2: rest-of-compilation-reorg.patch --]
[-- Type: text/plain, Size: 47534 bytes --]

2004-06-17  Paolo Bonzini  <bonzini@gnu.org>

	* dwarf2out.c (dwarf2out_begin_prologue): Use TREE_NOTHROW.
	* except.c (set_nothrow_function_flags): Set TREE_NOTHROW.
	* explow.h (optimize_save_area_alloca): Do not accept parameters.
	* function.c (current_function_nothrow): Remove.
	* output.h (current_function_nothrow): Remove.
	* passes.c (rest_of_handle_final): Handle symout.
	(rest_of_handle_new_regalloc, rest_of_handle_old_regalloc):
	Push timevar here.
	(rest_of_handle_sched): Break out SMS.  Remove ifs for
	flag_schedule_insns and flag_modulo_sched.
	(rest_of_handle_addressof, rest_of_handle_cse2): Garbage
	collect at the end.
	(rest_of_handle_gcse2): Put under timevar TV_RELOAD_CSE_REGS.
	(rest_of_handle_partition_blocks, rest_of_handle_sms,
	rest_of_handle_if_after_reload, rest_of_handle_peephole2,
	rest_of_handle_mode_switching, rest_of_handle_jump,
	rest_of_handle_guess_branch_prob, rest_of_handle_eh,
	rest_of_handle_jump2, rest_of_handle_postreload,
	rest_of_handle_flow2, rest_of_clean_state,
	rest_of_handle_shorten_branches,
	rest_of_handle_prologue_epilogue,
	rest_of_handle_branch_target_load_optimize): New.
	(rest_of_compilation): Call the above.  Remove ggc_collect
	calls moved to rest_of_handle_*.
	* rtl.h (optimize_save_area_alloca): Do not accept parameters.
	* config/arm/arm.c (arm_compute_func_type): Use TREE_NOTHROW.

Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.528
diff -u -r1.528 dwarf2out.c
--- dwarf2out.c	4 Jul 2004 08:06:54 -0000	1.528
+++ dwarf2out.c	5 Jul 2004 09:47:39 -0000
@@ -2406,7 +2406,7 @@
   fde->dw_fde_end = NULL;
   fde->dw_fde_cfi = NULL;
   fde->funcdef_number = current_function_funcdef_no;
-  fde->nothrow = current_function_nothrow;
+  fde->nothrow = TREE_NOTHROW (current_function_decl);
   fde->uses_eh_lsda = cfun->uses_eh_lsda;
   fde->all_throwers_are_sibcalls = cfun->all_throwers_are_sibcalls;
 
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.c,v
retrieving revision 1.276
diff -u -r1.276 except.c
--- except.c	18 Jun 2004 01:20:51 -0000	1.276
+++ except.c	5 Jul 2004 09:47:40 -0000
@@ -3166,6 +3166,11 @@
   if (! INSN_P (insn))
     return false;
 
+  if (GET_CODE (insn) == JUMP_INSN
+      && GET_CODE (PATTERN (insn)) == RESX
+      && XINT (PATTERN (insn), 0) > 0)
+    return can_throw_internal_1 (XINT (PATTERN (insn), 0));
+
   if (GET_CODE (insn) == INSN
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
     insn = XVECEXP (PATTERN (insn), 0, 0);
@@ -3188,14 +3193,14 @@
   return can_throw_external_1 (INTVAL (XEXP (note, 0)));
 }
 
-/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
+/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls.  */
 
 void
 set_nothrow_function_flags (void)
 {
   rtx insn;
 
-  current_function_nothrow = 1;
+  TREE_NOTHROW (current_function_decl) = 1;
 
   /* Assume cfun->all_throwers_are_sibcalls until we encounter
      something that can throw an exception.  We specifically exempt
@@ -3211,7 +3216,7 @@
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (can_throw_external (insn))
       {
-	current_function_nothrow = 0;
+        TREE_NOTHROW (current_function_decl) = 0;
 
 	if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
 	  {
@@ -3224,7 +3229,7 @@
        insn = XEXP (insn, 1))
     if (can_throw_external (insn))
       {
-	current_function_nothrow = 0;
+        TREE_NOTHROW (current_function_decl) = 0;
 
 	if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
 	  {
@@ -3232,6 +3237,7 @@
 	    return;
 	  }
       }
+
 }
 
 \f
Index: except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.h,v
retrieving revision 1.76
diff -u -r1.76 except.h
--- except.h	4 Jun 2004 12:31:26 -0000	1.76
+++ except.h	5 Jul 2004 09:47:40 -0000
@@ -99,7 +99,7 @@
 extern bool can_throw_external_1 (int);
 extern bool can_throw_external (rtx);
 
-/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
+/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls.  */
 extern void set_nothrow_function_flags (void);
 
 /* After initial rtl generation, call back to finish generating
Index: explow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/explow.c,v
retrieving revision 1.130
diff -u -r1.130 explow.c
--- explow.c	4 Jul 2004 08:06:54 -0000	1.130
+++ explow.c	5 Jul 2004 09:47:40 -0000
@@ -1110,11 +1110,11 @@
    frame, thus causing a crash if a longjmp unwinds to it.  */
 
 void
-optimize_save_area_alloca (rtx insns)
+optimize_save_area_alloca (void)
 {
   rtx insn;
 
-  for (insn = insns; insn; insn = NEXT_INSN(insn))
+  for (insn = get_insns (); insn; insn = NEXT_INSN(insn))
     {
       rtx note;
 
Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.543
diff -u -r1.543 function.c
--- function.c	5 Jul 2004 04:24:40 -0000	1.543
+++ function.c	5 Jul 2004 09:47:41 -0000
@@ -103,11 +103,6 @@
    compiler passes.  */
 int current_function_is_leaf;
 
-/* Nonzero if function being compiled doesn't contain any instructions
-   that can throw an exception.  This is set prior to final.  */
-
-int current_function_nothrow;
-
 /* Nonzero if function being compiled doesn't modify the stack pointer
    (ignoring the prologue and epilogue).  This is only valid after
    life_analysis has run.  */
Index: output.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/output.h,v
retrieving revision 1.141
diff -u -r1.141 output.h
--- output.h	19 May 2004 02:11:41 -0000	1.141
+++ output.h	5 Jul 2004 09:47:42 -0000
@@ -399,11 +399,6 @@
 
 extern int current_function_is_leaf;
 
-/* Nonzero if function being compiled doesn't contain any instructions
-   that can throw an exception.  This is set prior to final.  */
-
-extern int current_function_nothrow;
-
 /* Nonzero if function being compiled doesn't modify the stack pointer
    (ignoring the prologue and epilogue).  This is only valid after
    life_analysis has run.  */
Index: passes.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/passes.c,v
retrieving revision 2.28
diff -u -r2.28 passes.c
--- passes.c	4 Jul 2004 08:06:54 -0000	2.28
+++ passes.c	5 Jul 2004 09:47:42 -0000
@@ -472,9 +472,24 @@
     /* Release all memory held by regsets now.  */
     regset_release_memory ();
   }
-  timevar_pop (TV_FINAL);
+
+  /* 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);
 
   ggc_collect ();
+  timevar_pop (TV_FINAL);
 }
 
 #ifdef DELAY_SLOTS
@@ -488,9 +503,10 @@
   dbr_schedule (get_insns (), dump_file);
 
   close_dump_file (DFI_dbr, print_rtl, get_insns ());
-  timevar_pop (TV_DBR_SCHED);
 
   ggc_collect ();
+
+  timevar_pop (TV_DBR_SCHED);
 }
 #endif
 
@@ -532,9 +548,9 @@
     }
 
   close_dump_file (DFI_stack, print_rtl_with_bb, get_insns ());
-  timevar_pop (TV_REG_STACK);
 
   ggc_collect ();
+  timevar_pop (TV_REG_STACK);
 }
 #endif
 
@@ -551,7 +567,7 @@
   timevar_pop (TV_VAR_TRACKING);
 }
 
-/* Machine independent reorg pass.  */
+/* Machine dependent reorg pass.  */
 static void
 rest_of_handle_machine_reorg (void)
 {
@@ -561,9 +577,9 @@
   targetm.machine_dependent_reorg ();
 
   close_dump_file (DFI_mach, print_rtl, get_insns ());
-  timevar_pop (TV_MACH_DEP);
 
   ggc_collect ();
+  timevar_pop (TV_MACH_DEP);
 }
 
 
@@ -574,17 +590,14 @@
 {
   int failure;
 
+  timevar_push (TV_LOCAL_ALLOC);
+  open_dump_file (DFI_lreg, current_function_decl);
+
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
   reg_alloc ();
 
   timevar_pop (TV_LOCAL_ALLOC);
-  if (dump_file_tbl[DFI_lreg].enabled)
-    {
-      timevar_push (TV_DUMP);
-
-      close_dump_file (DFI_lreg, NULL, NULL);
-      timevar_pop (TV_DUMP);
-    }
+  close_dump_file (DFI_lreg, NULL, NULL);
 
   /* XXX clean up the whole mess to bring live info in shape again.  */
   timevar_push (TV_GLOBAL_ALLOC);
@@ -595,14 +608,14 @@
 
   timevar_pop (TV_GLOBAL_ALLOC);
 
+  ggc_collect ();
+
   if (dump_file_tbl[DFI_greg].enabled)
     {
       timevar_push (TV_DUMP);
-
       dump_global_regs (dump_file);
-
-      close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
       timevar_pop (TV_DUMP);
+      close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
     }
 
   if (failure)
@@ -621,6 +634,9 @@
   int failure;
   int rebuild_notes;
 
+  timevar_push (TV_LOCAL_ALLOC);
+  open_dump_file (DFI_lreg, current_function_decl);
+
   /* Allocate the reg_renumber array.  */
   allocate_reg_info (max_regno, FALSE, TRUE);
 
@@ -630,7 +646,7 @@
 
   allocate_initial_values (reg_equiv_memory_loc);
 
-  regclass (get_insns (), max_reg_num (), dump_file);
+  regclass (get_insns (), max_reg_num(), dump_file);
   rebuild_notes = local_alloc ();
 
   timevar_pop (TV_LOCAL_ALLOC);
@@ -651,14 +667,13 @@
   if (dump_file_tbl[DFI_lreg].enabled)
     {
       timevar_push (TV_DUMP);
-
       dump_flow_info (dump_file);
       dump_local_alloc (dump_file);
-
-      close_dump_file (DFI_lreg, print_rtl_with_bb, get_insns ());
       timevar_pop (TV_DUMP);
     }
 
+  close_dump_file (DFI_lreg, print_rtl_with_bb, get_insns ());
+
   ggc_collect ();
 
   timevar_push (TV_GLOBAL_ALLOC);
@@ -675,18 +690,19 @@
       failure = reload (get_insns (), 0);
     }
 
-  timevar_pop (TV_GLOBAL_ALLOC);
-
   if (dump_file_tbl[DFI_greg].enabled)
     {
       timevar_push (TV_DUMP);
-
       dump_global_regs (dump_file);
+      timevar_pop (TV_DUMP);
 
       close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
-      timevar_pop (TV_DUMP);
     }
 
+  ggc_collect ();
+
+  timevar_pop (TV_GLOBAL_ALLOC);
+
   return failure;
 }
 
@@ -738,52 +754,65 @@
   close_dump_file (DFI_bbro, print_rtl_with_bb, get_insns ());
 }
 
+/* Partition hot and cold basic blocks.  */
+static void
+rest_of_handle_partition_blocks (void)
+{
+  no_new_pseudos = 0;
+  partition_hot_cold_basic_blocks ();
+  allocate_reg_life_data ();
+  update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, 
+		    PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES);
+  no_new_pseudos = 1;
+}
+
 #ifdef INSN_SCHEDULING
 /* Run instruction scheduler.  */
+/* Perform SMS module scheduling.  */
 static void
-rest_of_handle_sched (void)
+rest_of_handle_sms (void)
 {
   timevar_push (TV_SMS);
-  if (optimize > 0 && flag_modulo_sched)
-    {
+  open_dump_file (DFI_sms, current_function_decl);
+
+  /* We want to be able to create new pseudos.  */
+  no_new_pseudos = 0;
+  sms_schedule (dump_file);
+  close_dump_file (DFI_sms, print_rtl, get_insns ());
 
-      /* Perform SMS module scheduling.  */
-      open_dump_file (DFI_sms, current_function_decl);
 
-      /* We want to be able to create new pseudos.  */
-      no_new_pseudos = 0;
-      sms_schedule (dump_file);
-      close_dump_file (DFI_sms, print_rtl, get_insns ());
-
-
-      /* Update the life information, because we add pseudos.  */
-      max_regno = max_reg_num ();
-      allocate_reg_info (max_regno, FALSE, FALSE);
-      update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
-					(PROP_DEATH_NOTES
-					 | PROP_KILL_DEAD_CODE
-					 | PROP_SCAN_DEAD_CODE));
-      no_new_pseudos = 1;
-    }
+  /* Update the life information, because we add pseudos.  */
+  max_regno = max_reg_num ();
+  allocate_reg_info (max_regno, FALSE, FALSE);
+  update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
+				    (PROP_DEATH_NOTES
+				     | PROP_KILL_DEAD_CODE
+				     | PROP_SCAN_DEAD_CODE));
+  no_new_pseudos = 1;
+
+  ggc_collect ();
   timevar_pop (TV_SMS);
+}
+
+/* Run instruction scheduler.  */
+static void
+rest_of_handle_sched (void)
+{
   timevar_push (TV_SCHED);
 
   /* Print function header into sched dump now
      because doing the sched analysis makes some of the dump.  */
-  if (optimize > 0 && flag_schedule_insns)
-    {
-      open_dump_file (DFI_sched, current_function_decl);
+  open_dump_file (DFI_sched, current_function_decl);
 
-      /* Do control and data sched analysis,
-	 and write some of the results to dump file.  */
+  /* Do control and data sched analysis,
+     and write some of the results to dump file.  */
 
-      schedule_insns (dump_file);
+  schedule_insns (dump_file);
 
-      close_dump_file (DFI_sched, print_rtl_with_bb, get_insns ());
-    }
-  timevar_pop (TV_SCHED);
+  close_dump_file (DFI_sched, print_rtl_with_bb, get_insns ());
 
   ggc_collect ();
+  timevar_pop (TV_SCHED);
 }
 
 /* Run second scheduling pass after reload.  */
@@ -810,15 +839,17 @@
     schedule_insns (dump_file);
 
   close_dump_file (DFI_sched2, print_rtl_with_bb, get_insns ());
-  timevar_pop (TV_SCHED2);
 
   ggc_collect ();
+
+  timevar_pop (TV_SCHED2);
 }
 #endif
 
 static void
 rest_of_handle_gcse2 (void)
 {
+  timevar_push (TV_RELOAD_CSE_REGS);
   open_dump_file (DFI_gcse2, current_function_decl);
 
   gcse_after_reload_main (get_insns (), dump_file);
@@ -831,6 +862,8 @@
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
+
+  timevar_pop (TV_RELOAD_CSE_REGS);
 }
 
 /* Register allocation pre-pass, to reduce number of moves necessary
@@ -841,13 +874,13 @@
   timevar_push (TV_REGMOVE);
   open_dump_file (DFI_regmove, current_function_decl);
 
-  regmove_optimize (get_insns (), max_reg_num (), dump_file);
+  regmove_optimize (get_insns (), max_reg_num(), dump_file);
 
   cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
   close_dump_file (DFI_regmove, print_rtl_with_bb, get_insns ());
-  timevar_pop (TV_REGMOVE);
 
   ggc_collect ();
+  timevar_pop (TV_REGMOVE);
 }
 
 /* Run tracer.  */
@@ -867,22 +900,25 @@
 static void
 rest_of_handle_if_conversion (void)
 {
+  timevar_push (TV_IFCVT);
   open_dump_file (DFI_ce1, current_function_decl);
+
   if (flag_if_conversion)
     {
-      timevar_push (TV_IFCVT);
       if (dump_file)
 	dump_flow_info (dump_file);
       cleanup_cfg (CLEANUP_EXPENSIVE);
       reg_scan (get_insns (), max_reg_num (), 0);
       if_convert (0);
-      timevar_pop (TV_IFCVT);
     }
+
   timevar_push (TV_JUMP);
   cleanup_cfg (CLEANUP_EXPENSIVE);
   reg_scan (get_insns (), max_reg_num (), 0);
   timevar_pop (TV_JUMP);
+
   close_dump_file (DFI_ce1, print_rtl_with_bb, get_insns ());
+  timevar_pop (TV_IFCVT);
 }
 
 /* Rerun if-conversion, as combine may have simplified things enough
@@ -902,6 +938,23 @@
 }
 
 static void
+rest_of_handle_if_after_reload (void)
+{
+  timevar_push (TV_IFCVT2);
+  open_dump_file (DFI_ce3, current_function_decl);
+
+  /* Last attempt to optimize CFG, as scheduling, peepholing and insn
+     splitting possibly introduced more crossjumping opportunities.  */
+  cleanup_cfg (CLEANUP_EXPENSIVE
+	       | CLEANUP_UPDATE_LIFE 
+	       | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
+  if (flag_if_conversion2)
+    if_convert (1);
+  close_dump_file (DFI_ce3, print_rtl_with_bb, get_insns ());
+  timevar_pop (TV_IFCVT2);
+}
+
+static void
 rest_of_handle_web (void)
 {
   open_dump_file (DFI_web, current_function_decl);
@@ -920,6 +973,7 @@
 rest_of_handle_branch_prob (void)
 {
   struct loops loops;
+
   timevar_push (TV_BRANCH_PROB);
   open_dump_file (DFI_bp, current_function_decl);
 
@@ -1026,7 +1080,7 @@
   rebuild_jump_labels_after_combine
     = combine_instructions (get_insns (), max_reg_num ());
 
-  /* Combining get_insns () may have turned an indirect jump into a
+  /* Combining insns may have turned an indirect jump into a
      direct jump.  Rebuild the JUMP_LABEL fields of jumping
      instructions.  */
   if (rebuild_jump_labels_after_combine)
@@ -1059,7 +1113,6 @@
     cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
 		 | CLEANUP_LOG_LINKS
 		 | (flag_thread_jumps ? CLEANUP_THREADING : 0));
-  timevar_pop (TV_FLOW);
 
   if (extra_warnings)
     {
@@ -1093,6 +1146,7 @@
 rest_of_handle_cse (void)
 {
   int tem;
+
   open_dump_file (DFI_cse, current_function_decl);
   if (dump_file)
     dump_flow_info (dump_file);
@@ -1117,6 +1171,8 @@
 
   timevar_pop (TV_CSE);
   close_dump_file (DFI_cse, print_rtl_with_bb, get_insns ());
+
+  ggc_collect ();
 }
 
 /* Run second CSE pass after loop optimizations.  */
@@ -1124,6 +1180,7 @@
 rest_of_handle_cse2 (void)
 {
   int tem;
+
   timevar_push (TV_CSE2);
   open_dump_file (DFI_cse2, current_function_decl);
   if (dump_file)
@@ -1149,8 +1206,9 @@
     }
   reg_scan (get_insns (), max_reg_num (), 0);
   close_dump_file (DFI_cse2, print_rtl_with_bb, get_insns ());
-  ggc_collect ();
   timevar_pop (TV_CSE2);
+
+  ggc_collect ();
 }
 
 /* Perform global cse.  */
@@ -1159,6 +1217,7 @@
 {
   int save_csb, save_cfj;
   int tem2 = 0, tem;
+
   timevar_push (TV_GCSE);
   open_dump_file (DFI_gcse, current_function_decl);
 
@@ -1258,9 +1317,9 @@
 
   /* Loop can create trivially dead instructions.  */
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
+  find_basic_blocks (get_insns (), max_reg_num (), dump_file);
   close_dump_file (DFI_loop, print_rtl, get_insns ());
   timevar_pop (TV_LOOP);
-  find_basic_blocks (get_insns (), max_reg_num (), dump_file);
 
   ggc_collect ();
 }
@@ -1330,91 +1389,63 @@
   ggc_collect ();
 }
 
-/* This is called from finish_function (within langhooks.parse_file)
-   after each top-level definition is parsed.
-   It is supposed to compile that function or variable
-   and output the assembler code for it.
-   After we return, the tree storage is freed.  */
-
-void
-rest_of_compilation (void)
+static void
+rest_of_handle_branch_target_load_optimize (void)
 {
-  /* There's no need to defer outputting this function any more; we
-     know we want to output it.  */
-  DECL_DEFER_OUTPUT (current_function_decl) = 0;
-
-  /* There's no need to defer outputting this function any more; we
-     know we want to output it.  */
-  DECL_DEFER_OUTPUT (current_function_decl) = 0;
+  static int warned = 0;
 
-  /* Register rtl specific functions for cfg.  */
-  rtl_register_cfg_hooks ();
-
-  /* Now that we're out of the frontend, we shouldn't have any more
-     CONCATs anywhere.  */
-  generating_concat_p = 0;
-
-  /* When processing delayed functions, prepare_function_start() won't
-     have been run to re-initialize it.  */
-  cse_not_expected = ! optimize;
-
-  finalize_block_changes ();
-
-  /* Dump the rtl code if we are dumping rtl.  */
-  if (open_dump_file (DFI_rtl, current_function_decl))
-    close_dump_file (DFI_rtl, print_rtl, get_insns ());
-
-  /* Convert from NOTE_INSN_EH_REGION style notes, and do other
-     sorts of eh initialization.  Delay this until after the
-     initial rtl dump so that we can see the original nesting.  */
-  convert_from_eh_region_ranges ();
-
-  /* If we're emitting a nested function, make sure its parent gets
-     emitted as well.  Doing otherwise confuses debug info.  */
-  {
-    tree parent;
-    for (parent = DECL_CONTEXT (current_function_decl);
-	 parent != NULL_TREE;
-	 parent = get_containing_scope (parent))
-      if (TREE_CODE (parent) == FUNCTION_DECL)
-	TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1;
-  }
-
-  /* We are now committed to emitting code for this function.  Do any
-     preparation, such as emitting abstract debug info for the inline
-     before it gets mangled by optimization.  */
-  if (cgraph_function_possibly_inlined_p (current_function_decl))
-    (*debug_hooks->outlining_inline_function) (current_function_decl);
+  /* Leave this a warning for now so that it is possible to experiment
+     with running this pass twice.  In 3.6, we should either make this
+     an error, or use separate dump files.  */
+  if (flag_branch_target_load_optimize
+      && flag_branch_target_load_optimize2
+      && !warned)
+    {
+      warning ("branch target register load optimization is not intended "
+	       "to be run twice");
 
-  /* Remove any notes we don't need.  That will make iterating
-     over the instruction sequence faster, and allow the garbage
-     collector to reclaim the memory used by the notes.  */
-  remove_unnecessary_notes ();
+      warned = 1;
+    }
 
+  open_dump_file (DFI_branch_target_load, current_function_decl);
+  branch_target_load_optimize (epilogue_completed);
+  close_dump_file (DFI_branch_target_load, print_rtl_with_bb, get_insns ());
   ggc_collect ();
+}
 
-  /* Initialize some variables used by the optimizers.  */
-  init_function_for_compilation ();
+#ifdef OPTIMIZE_MODE_SWITCHING
+static void
+rest_of_handle_mode_switching (void)
+{
+  timevar_push (TV_MODE_SWITCH);
 
-  TREE_ASM_WRITTEN (current_function_decl) = 1;
+  no_new_pseudos = 0;
+  optimize_mode_switching (NULL);
+  no_new_pseudos = 1;
 
-  /* Now that integrate will no longer see our rtl, we need not
-     distinguish between the return value of this function and the
-     return value of called functions.  Also, we can remove all SETs
-     of subregs of hard registers; they are only here because of
-     integrate.  Also, we can now initialize pseudos intended to
-     carry magic hard reg data throughout the function.  */
-  rtx_equal_function_value_matters = 0;
-  purge_hard_subreg_sets (get_insns ());
+  timevar_pop (TV_MODE_SWITCH);
+}
+#endif
 
-  /* Early return if there were errors.  We can run afoul of our
-     consistency checks, and there's not really much point in fixing them.  */
-  if (rtl_dump_and_exit || flag_syntax_only || errorcount || sorrycount)
-    goto exit_rest_of_compilation;
+static void
+rest_of_handle_jump (void)
+{
+  ggc_collect ();
 
   timevar_push (TV_JUMP);
   open_dump_file (DFI_sibling, current_function_decl);
 
+  /* ??? We may get caled either via tree_rest_of_compilation when the CFG
+     is already built or directly (for instance from coverage code).
+     The direct callers shall be updated.  */
+  if (!basic_block_info)
+    {
+      init_flow ();
+      rebuild_jump_labels (get_insns ());
+      find_exception_handler_labels ();
+      find_basic_blocks (get_insns (), max_reg_num (), dump_file);
+    }
+
   /* ??? We may get called either via tree_rest_of_compilation when the CFG
      is already built or directly (for instance from coverage code).
      The direct callers shall be updated.  */
@@ -1427,9 +1458,14 @@
     }
   delete_unreachable_blocks ();
 #ifdef ENABLE_CHECKING
-  verify_flow_info();
+  verify_flow_info ();
 #endif
+  timevar_pop (TV_JUMP);
+}
 
+static void
+rest_of_handle_guess_branch_prob (void)
+{
   /* Turn NOTE_INSN_PREDICTIONs into branch predictions.  */
   if (flag_guess_branch_prob)
     {
@@ -1437,12 +1473,11 @@
       note_prediction_to_br_prob ();
       timevar_pop (TV_BRANCH_PROB);
     }
+}
 
-  timevar_pop (TV_JUMP);
-
-  if (cfun->tail_call_emit)
-    fixup_tail_calls ();
-
+static void
+rest_of_handle_eh (void)
+{
   insn_locators_initialize ();
   /* Complete generation of exception handling code.  */
   if (doing_eh (0))
@@ -1455,35 +1490,81 @@
       close_dump_file (DFI_eh, print_rtl, get_insns ());
       timevar_pop (TV_JUMP);
     }
+}
 
-  /* Delay emitting hard_reg_initial_value sets until after EH landing pad
-     generation, which might create new sets.  */
-  emit_initial_value_sets ();
 
-#ifdef FINALIZE_PIC
-  /* If we are doing position-independent code generation, now
-     is the time to output special prologues and epilogues.
-     We do not want to do this earlier, because it just clutters
-     up inline functions with meaningless insns.  */
-  if (flag_pic)
-    FINALIZE_PIC;
-#endif
+static void
+rest_of_handle_prologue_epilogue (void)
+{
+  if (optimize && !flow2_completed)
+    cleanup_cfg (CLEANUP_EXPENSIVE);
 
-  /* Copy any shared structure that should not be shared.  */
-  unshare_all_rtl ();
+  /* On some machines, the prologue and epilogue code, or parts thereof,
+     can be represented as RTL.  Doing so lets us schedule insns between
+     it and the rest of the code and also allows delayed branch
+     scheduling to operate in the epilogue.  */
+  thread_prologue_and_epilogue_insns (get_insns ());
+  epilogue_completed = 1;
+
+  if (optimize && flow2_completed)
+    life_analysis (dump_file, PROP_POSTRELOAD);
+}
 
-#ifdef SETJMP_VIA_SAVE_AREA
-  /* This must be performed before virtual register instantiation.
-     Please be aware that everything in the compiler that can look
-     at the RTL up to this point must understand that REG_SAVE_AREA
-     is just like a use of the REG contained inside.  */
-  if (current_function_calls_alloca)
-    optimize_save_area_alloca (get_insns ());
+static void
+rest_of_handle_stack_adjustments (void)
+{
+  life_analysis (dump_file, PROP_POSTRELOAD);
+  cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
+	       | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
+    
+  /* This is kind of a heuristic.  We need to run combine_stack_adjustments
+     even for machines with possibly nonzero RETURN_POPS_ARGS
+     and ACCUMULATE_OUTGOING_ARGS.  We expect that only ports having
+     push instructions will have popping returns.  */
+#ifndef PUSH_ROUNDING
+  if (!ACCUMULATE_OUTGOING_ARGS)
 #endif
+    combine_stack_adjustments ();
+}
 
-  /* Instantiate all virtual registers.  */
-  instantiate_virtual_regs ();
+static void
+rest_of_handle_flow2 (void)
+{
+  timevar_push (TV_FLOW2);
+  open_dump_file (DFI_flow2, current_function_decl);
 
+  /* Re-create the death notes which were deleted during reload.  */
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
+
+  /* If optimizing, then go ahead and split insns now.  */
+#ifndef STACK_REGS
+  if (optimize > 0)
+#endif
+    split_all_insns (0);
+
+  if (flag_branch_target_load_optimize)
+    rest_of_handle_branch_target_load_optimize ();
+
+  if (!targetm.late_rtl_prologue_epilogue)
+    rest_of_handle_prologue_epilogue ();
+
+  if (optimize)
+    rest_of_handle_stack_adjustments ();
+
+  flow2_completed = 1;
+
+  close_dump_file (DFI_flow2, print_rtl_with_bb, get_insns ());
+  timevar_pop (TV_FLOW2);
+
+  ggc_collect ();
+}
+
+
+static void
+rest_of_handle_jump2 (void)
+{
   open_dump_file (DFI_jump, current_function_decl);
 
   /* Always do one jump optimization pass to ensure that JUMP_LABEL fields
@@ -1497,7 +1578,7 @@
     expected_value_to_br_prob ();
 
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
-  reg_scan (get_insns(), max_reg_num (), 0);
+  reg_scan (get_insns (), max_reg_num (), 0);
   if (dump_file)
     dump_flow_info (dump_file);
   cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
@@ -1507,8 +1588,6 @@
 
   purge_line_number_notes (get_insns ());
 
-  close_dump_file (DFI_jump, print_rtl, get_insns ());
-
   if (optimize)
     cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
 
@@ -1518,17 +1597,231 @@
      maximum instruction UID, so if we can reduce the maximum UID
      we'll save big on memory.  */
   renumber_insns (dump_file);
-  timevar_pop (TV_JUMP);
 
   close_dump_file (DFI_jump, print_rtl_with_bb, get_insns ());
+  timevar_pop (TV_JUMP);
 
   ggc_collect ();
+}
+
+#ifdef HAVE_peephole2
+static void
+rest_of_handle_peephole2 (void)
+{
+  timevar_push (TV_PEEPHOLE2);
+  open_dump_file (DFI_peephole2, current_function_decl);
+
+  peephole2_optimize (dump_file);
+
+  close_dump_file (DFI_peephole2, print_rtl_with_bb, get_insns ());
+  timevar_pop (TV_PEEPHOLE2);
+}
+#endif
+
+static void
+rest_of_handle_postreload (void)
+{
+  timevar_push (TV_RELOAD_CSE_REGS);
+  open_dump_file (DFI_postreload, current_function_decl);
+
+  /* Do a very simple CSE pass over just the hard registers.  */
+  reload_cse_regs (get_insns ());
+  /* reload_cse_regs can eliminate potentially-trapping MEMs.
+     Remove any EH edges associated with them.  */
+  if (flag_non_call_exceptions)
+    purge_all_dead_edges (0);
+
+  close_dump_file (DFI_postreload, print_rtl_with_bb, get_insns ());
+  timevar_pop (TV_RELOAD_CSE_REGS);
+}
+
+static void
+rest_of_handle_shorten_branches (void)
+{
+  /* Shorten branches.  */
+  timevar_push (TV_SHORTEN_BRANCH);
+  shorten_branches (get_insns ());
+  timevar_pop (TV_SHORTEN_BRANCH);
+}
+
+static void
+rest_of_clean_state (void)
+{
+  coverage_end_function ();
+
+  /* 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;
+
+  timevar_push (TV_FINAL);
+
+  /* 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 ();
+
+  timevar_pop (TV_FINAL);
+
+  if (targetm.binds_local_p (current_function_decl))
+    {
+      int pref = cfun->preferred_stack_boundary;
+      if (cfun->recursive_call_emit
+          && 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
+     (from final.c), 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);
+}
+\f
+
+/* This is called from finish_function (within langhooks.parse_file)
+   after each top-level definition is parsed.
+   It is supposed to compile that function or variable
+   and output the assembler code for it.
+   After we return, the tree storage is freed.  */
+
+void
+rest_of_compilation (void)
+{
+  /* There's no need to defer outputting this function any more; we
+     know we want to output it.  */
+  DECL_DEFER_OUTPUT (current_function_decl) = 0;
+
+  /* Register rtl specific functions for cfg.  */
+  rtl_register_cfg_hooks ();
+
+  /* Now that we're out of the frontend, we shouldn't have any more
+     CONCATs anywhere.  */
+  generating_concat_p = 0;
+
+  /* When processing delayed functions, prepare_function_start() won't
+     have been run to re-initialize it.  */
+  cse_not_expected = ! optimize;
+
+  finalize_block_changes ();
+
+  /* Dump the rtl code if we are dumping rtl.  */
+  if (open_dump_file (DFI_rtl, current_function_decl))
+    close_dump_file (DFI_rtl, print_rtl, get_insns ());
+
+  /* Convert from NOTE_INSN_EH_REGION style notes, and do other
+     sorts of eh initialization.  Delay this until after the
+     initial rtl dump so that we can see the original nesting.  */
+  convert_from_eh_region_ranges ();
+
+  /* If we're emitting a nested function, make sure its parent gets
+     emitted as well.  Doing otherwise confuses debug info.  */
+  {
+    tree parent;
+    for (parent = DECL_CONTEXT (current_function_decl);
+	 parent != NULL_TREE;
+	 parent = get_containing_scope (parent))
+      if (TREE_CODE (parent) == FUNCTION_DECL)
+	TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1;
+  }
+
+  /* We are now committed to emitting code for this function.  Do any
+     preparation, such as emitting abstract debug info for the inline
+     before it gets mangled by optimization.  */
+  if (cgraph_function_possibly_inlined_p (current_function_decl))
+    (*debug_hooks->outlining_inline_function) (current_function_decl);
+
+  /* Remove any notes we don't need.  That will make iterating
+     over the instruction sequence faster, and allow the garbage
+     collector to reclaim the memory used by the notes.  */
+  remove_unnecessary_notes ();
+
+  /* Initialize some variables used by the optimizers.  */
+  init_function_for_compilation ();
+
+  TREE_ASM_WRITTEN (current_function_decl) = 1;
+
+  /* Now that integrate will no longer see our rtl, we need not
+     distinguish between the return value of this function and the
+     return value of called functions.  Also, we can remove all SETs
+     of subregs of hard registers; they are only here because of
+     integrate.  Also, we can now initialize pseudos intended to
+     carry magic hard reg data throughout the function.
+
+     FIXME: All this looks thoroughly obsolete... maybe we can
+     get rid of both these lines unconditionally?  */
+  rtx_equal_function_value_matters = 0;
+  purge_hard_subreg_sets (get_insns ());
+
+  /* Early return if there were errors.  We can run afoul of our
+     consistency checks, and there's not really much point in fixing them.  */
+  if (rtl_dump_and_exit || flag_syntax_only || errorcount || sorrycount)
+    goto exit_rest_of_compilation;
+
+  rest_of_handle_jump ();
+  rest_of_handle_guess_branch_prob ();
+
+  if (cfun->tail_call_emit)
+    fixup_tail_calls ();
+
+  rest_of_handle_eh ();
+
+  /* Delay emitting hard_reg_initial_value sets until after EH landing pad
+     generation, which might create new sets.  */
+  emit_initial_value_sets ();
+
+#ifdef FINALIZE_PIC
+  /* If we are doing position-independent code generation, now
+     is the time to output special prologues and epilogues.
+     We do not want to do this earlier, because it just clutters
+     up inline functions with meaningless insns.  */
+  if (flag_pic)
+    FINALIZE_PIC;
+#endif
+
+  /* Copy any shared structure that should not be shared.  */
+  unshare_all_rtl ();
+
+#ifdef SETJMP_VIA_SAVE_AREA
+  /* This must be performed before virtual register instantiation.
+     Please be aware that everything in the compiler that can look
+     at the RTL up to this point must understand that REG_SAVE_AREA
+     is just like a use of the REG contained inside.  */
+  if (current_function_calls_alloca)
+    optimize_save_area_alloca ();
+#endif
+
+  /* Instantiate all virtual registers.  */
+  instantiate_virtual_regs ();
+
+  rest_of_handle_jump2 ();
 
   if (optimize > 0)
     rest_of_handle_cse ();
 
-  ggc_collect ();
-
   if (optimize > 0)
     {
       if (flag_gcse)
@@ -1542,7 +1835,6 @@
     }
 
   timevar_push (TV_FLOW);
-
   rest_of_handle_cfg ();
 
   if (!flag_tree_based_profiling
@@ -1566,42 +1858,36 @@
   if (optimize > 0)
     rest_of_handle_if_conversion ();
 
-  if (flag_tracer)
+  if (optimize > 0 && flag_tracer)
     rest_of_handle_tracer ();
 
   if (optimize > 0
       && flag_loop_optimize2)
     rest_of_handle_loop2 ();
 
-  if (flag_web)
+  if (optimize > 0 && flag_web)
     rest_of_handle_web ();
 
-  if (flag_rerun_cse_after_loop)
+  if (optimize > 0 && flag_rerun_cse_after_loop)
     rest_of_handle_cse2 ();
 
   cse_not_expected = 1;
 
   rest_of_handle_life ();
+  timevar_pop (TV_FLOW);
 
   if (optimize > 0)
     rest_of_handle_combine ();
 
-  if (flag_if_conversion)
+  if (optimize > 0 && flag_if_conversion)
     rest_of_handle_if_after_combine ();
 
   /* The optimization to partition hot/cold basic blocks into separate
      sections of the .o file does not work well with exception handling.
      Don't call it if there are exceptions.  */
 
-  if (flag_reorder_blocks_and_partition && !flag_exceptions)
-    {
-      no_new_pseudos = 0;
-      partition_hot_cold_basic_blocks ();
-      allocate_reg_life_data ();
-      update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, 
-			PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES);
-      no_new_pseudos = 1;
-    }
+  if (optimize > 0 && flag_reorder_blocks_and_partition && !flag_exceptions)
+    rest_of_handle_partition_blocks ();
 
   if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
     rest_of_handle_regmove ();
@@ -1611,13 +1897,7 @@
   split_all_insns (1);
 
 #ifdef OPTIMIZE_MODE_SWITCHING
-  timevar_push (TV_MODE_SWITCH);
-
-  no_new_pseudos = 0;
-  optimize_mode_switching (NULL);
-  no_new_pseudos = 1;
-
-  timevar_pop (TV_MODE_SWITCH);
+  rest_of_handle_mode_switching ();
 #endif
 
   /* Any of the several passes since flow1 will have munged register
@@ -1626,7 +1906,11 @@
   recompute_reg_usage (get_insns (), !optimize_size);
 
 #ifdef INSN_SCHEDULING
-  rest_of_handle_sched ();
+  if (optimize > 0 && flag_modulo_sched)
+    rest_of_handle_sms ();
+
+  if (flag_schedule_insns)
+    rest_of_handle_sched ();
 #endif
 
   /* Determine if the current function is a leaf before running reload
@@ -1634,9 +1918,6 @@
      epilogue thus changing register elimination offsets.  */
   current_function_is_leaf = leaf_function_p ();
 
-  timevar_push (TV_LOCAL_ALLOC);
-  open_dump_file (DFI_lreg, current_function_decl);
-
   if (flag_new_regalloc)
     {
       if (rest_of_handle_new_regalloc ())
@@ -1648,117 +1929,21 @@
 	goto exit_rest_of_compilation;
     }
 
-  ggc_collect ();
-
-  open_dump_file (DFI_postreload, current_function_decl);
-
-  /* Do a very simple CSE pass over just the hard registers.  */
   if (optimize > 0)
-    {
-      timevar_push (TV_RELOAD_CSE_REGS);
-      reload_cse_regs (get_insns ());
-      /* reload_cse_regs can eliminate potentially-trapping MEMs.
-	 Remove any EH edges associated with them.  */
-      if (flag_non_call_exceptions)
-	purge_all_dead_edges (0);
-      timevar_pop (TV_RELOAD_CSE_REGS);
-    }
-
-  close_dump_file (DFI_postreload, print_rtl_with_bb, get_insns ());
+    rest_of_handle_postreload ();
 
   if (optimize > 0 && flag_gcse_after_reload)
     rest_of_handle_gcse2 ();
 
-  /* Re-create the death notes which were deleted during reload.  */
-  timevar_push (TV_FLOW2);
-  open_dump_file (DFI_flow2, current_function_decl);
-
-#ifdef ENABLE_CHECKING
-  verify_flow_info ();
-#endif
-
-  /* If optimizing, then go ahead and split get_insns () now.  */
-#ifndef STACK_REGS
-  if (optimize > 0)
-#endif
-    split_all_insns (0);
-
-    if (flag_branch_target_load_optimize)
-      {
-	open_dump_file (DFI_branch_target_load, current_function_decl);
-
-	branch_target_load_optimize (/*after_prologue_epilogue_gen=*/false);
-
-	close_dump_file (DFI_branch_target_load, print_rtl_with_bb, get_insns ());
-
-	ggc_collect ();
-      }
-
-  if (! targetm.late_rtl_prologue_epilogue)
-    {
-      if (optimize)
-	cleanup_cfg (CLEANUP_EXPENSIVE);
-
-      /* On some machines, the prologue and epilogue code, or parts thereof,
-	 can be represented as RTL.  Doing so lets us schedule insns between
-	 it and the rest of the code and also allows delayed branch
-	 scheduling to operate in the epilogue.  */
-      thread_prologue_and_epilogue_insns (get_insns ());
-      epilogue_completed = 1;
-    }
-
-  if (optimize)
-    {
-      life_analysis (dump_file, PROP_POSTRELOAD);
-      cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
-		   | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
-
-      /* This is kind of a heuristic.  We need to run combine_stack_adjustments
-         even for machines with possibly nonzero RETURN_POPS_ARGS
-         and ACCUMULATE_OUTGOING_ARGS.  We expect that only ports having
-         push instructions will have popping returns.  */
-#ifndef PUSH_ROUNDING
-      if (!ACCUMULATE_OUTGOING_ARGS)
-#endif
-	combine_stack_adjustments ();
-
-      ggc_collect ();
-    }
-
-  flow2_completed = 1;
-
-  close_dump_file (DFI_flow2, print_rtl_with_bb, get_insns ());
-  timevar_pop (TV_FLOW2);
+  rest_of_handle_flow2 ();
 
 #ifdef HAVE_peephole2
   if (optimize > 0 && flag_peephole2)
-    {
-      timevar_push (TV_PEEPHOLE2);
-      open_dump_file (DFI_peephole2, current_function_decl);
-
-      peephole2_optimize (dump_file);
-
-      close_dump_file (DFI_peephole2, print_rtl_with_bb, get_insns ());
-      timevar_pop (TV_PEEPHOLE2);
-    }
+    rest_of_handle_peephole2 ();
 #endif
 
-  open_dump_file (DFI_ce3, current_function_decl);
-  if (optimize)
-    /* Last attempt to optimize CFG, as scheduling, peepholing and insn
-       splitting possibly introduced more crossjumping opportunities.  */
-    cleanup_cfg (CLEANUP_EXPENSIVE
-		 | CLEANUP_UPDATE_LIFE 
-		 | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
-  if (flag_if_conversion2)
-    {
-      timevar_push (TV_IFCVT2);
-
-      if_convert (1);
-
-      timevar_pop (TV_IFCVT2);
-    }
-  close_dump_file (DFI_ce3, print_rtl_with_bb, get_insns ());
+  if (optimize > 0)
+    rest_of_handle_if_after_reload ();
 
   if (optimize > 0)
     {
@@ -1769,22 +1954,7 @@
     }
 
   if (flag_branch_target_load_optimize2)
-    {
-      /* Leave this a warning for now so that it is possible to experiment
-	 with running this pass twice.  In 3.6, we should either make this
-	 an error, or use separate dump files.  */
-      if (flag_branch_target_load_optimize)
-	warning ("branch target register load optimization is not intended "
-		 "to be run twice");
-
-      open_dump_file (DFI_branch_target_load, current_function_decl);
-
-      branch_target_load_optimize (/*after_prologue_epilogue_gen=*/true);
-
-      close_dump_file (DFI_branch_target_load, print_rtl_with_bb, get_insns ());
-
-      ggc_collect ();
-    }
+    rest_of_handle_branch_target_load_optimize ();
 
 #ifdef LEAF_REGISTERS
   current_function_uses_only_leaf_regs
@@ -1792,16 +1962,7 @@
 #endif
 
   if (targetm.late_rtl_prologue_epilogue)
-    {
-      /* On some machines, the prologue and epilogue code, or parts thereof,
-	 can be represented as RTL.  Doing so lets us schedule insns between
-	 it and the rest of the code and also allows delayed branch
-	 scheduling to operate in the epilogue.  */
-      thread_prologue_and_epilogue_insns (get_insns ());
-      epilogue_completed = 1;
-      if (optimize)
-	life_analysis (dump_file, PROP_POSTRELOAD);
-    }
+    rest_of_handle_prologue_epilogue ();
 
 #ifdef INSN_SCHEDULING
   if (optimize > 0 && flag_schedule_insns_after_reload)
@@ -1827,7 +1988,7 @@
   cleanup_barriers ();
 
 #ifdef DELAY_SLOTS
-  if (optimize > 0 && flag_delayed_branch)
+  if (flag_delayed_branch)
     rest_of_handle_delay_slots ();
 #endif
 
@@ -1839,88 +2000,15 @@
 
   convert_to_eh_region_ranges ();
 
-  /* Shorten branches.  */
-  timevar_push (TV_SHORTEN_BRANCH);
-  shorten_branches (get_insns ());
-  timevar_pop (TV_SHORTEN_BRANCH);
+  rest_of_handle_shorten_branches ();
 
   set_nothrow_function_flags ();
-  if (current_function_nothrow)
-    /* Now we know that this can't throw; set the flag for the benefit
-       of other functions later in this translation unit.  */
-    TREE_NOTHROW (current_function_decl) = 1;
 
   rest_of_handle_final ();
 
-  /* 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);
-
  exit_rest_of_compilation:
 
-  coverage_end_function ();
-
-  /* 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;
-
-  timevar_push (TV_FINAL);
-
-  /* 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 ();
-
-  timevar_pop (TV_FINAL);
-
-  if (targetm.binds_local_p (current_function_decl))
-    {
-      int pref = cfun->preferred_stack_boundary;
-      if (cfun->recursive_call_emit
-          && 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
-     (from final.c), 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);
+  rest_of_clean_state ();
 }
 
 void
@@ -1934,23 +2022,18 @@
 void
 finish_optimization_passes (void)
 {
+  timevar_push (TV_DUMP);
   if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
     {
-      timevar_push (TV_DUMP);
       open_dump_file (DFI_bp, NULL);
-
       end_branch_prob ();
-
       close_dump_file (DFI_bp, NULL, NULL_RTX);
-      timevar_pop (TV_DUMP);
     }
 
   if (optimize > 0 && open_dump_file (DFI_combine, NULL))
     {
-      timevar_push (TV_DUMP);
       dump_combine_total_stats (dump_file);
       close_dump_file (DFI_combine, NULL, NULL_RTX);
-      timevar_pop (TV_DUMP);
     }
 
   dump_file = cgraph_dump_file;
@@ -1975,6 +2058,7 @@
 	  }
     }
 
+  timevar_pop (TV_DUMP);
 }
 
 bool
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.487
diff -u -r1.487 rtl.h
--- rtl.h	5 Jul 2004 07:22:45 -0000	1.487
+++ rtl.h	5 Jul 2004 09:47:42 -0000
@@ -1581,7 +1581,7 @@
 extern HOST_WIDE_INT trunc_int_for_mode	(HOST_WIDE_INT, enum machine_mode);
 extern rtx plus_constant_wide (rtx, HOST_WIDE_INT);
 extern rtx plus_constant_for_output_wide (rtx, HOST_WIDE_INT);
-extern void optimize_save_area_alloca (rtx);
+extern void optimize_save_area_alloca (void);
 
 /* In emit-rtl.c */
 extern rtvec gen_rtvec (int, ...);
Index: config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.370
diff -u -r1.370 arm.c
--- config/arm/arm.c	4 Jul 2004 08:07:01 -0000	1.370
+++ config/arm/arm.c	5 Jul 2004 09:47:46 -0000
@@ -1111,7 +1111,7 @@
      register values that will never be needed again.  This optimization
      was added to speed up context switching in a kernel application.  */
   if (optimize > 0
-      && current_function_nothrow
+      && TREE_NOTHROW (current_function_decl)
       && TREE_THIS_VOLATILE (current_function_decl))
     type |= ARM_FT_VOLATILE;
   

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Updated PATCH] rest_of_compilation reorg (-2 steps to using the   pass manager everywhere :-)
  2004-07-05 10:37 [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-) Paolo Bonzini
@ 2004-07-05 13:31 ` Paolo Bonzini
  2004-07-08  5:30 ` Richard Henderson
  1 sibling, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2004-07-05 13:31 UTC (permalink / raw)
  To: gcc-patches

> diff -u -r1.276 except.c
> --- except.c	18 Jun 2004 01:20:51 -0000	1.276
> +++ except.c	5 Jul 2004 09:47:40 -0000
> @@ -3166,6 +3166,11 @@
>    if (! INSN_P (insn))
>      return false;
>  
> +  if (GET_CODE (insn) == JUMP_INSN
> +      && GET_CODE (PATTERN (insn)) == RESX
> +      && XINT (PATTERN (insn), 0) > 0)
> +    return can_throw_internal_1 (XINT (PATTERN (insn), 0));
> +
>    if (GET_CODE (insn) == INSN
>        && GET_CODE (PATTERN (insn)) == SEQUENCE)
>      insn = XVECEXP (PATTERN (insn), 0, 0);

This hunk is extraneous to the patch.

Paolo

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-)
  2004-07-05 10:37 [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-) Paolo Bonzini
  2004-07-05 13:31 ` Paolo Bonzini
@ 2004-07-08  5:30 ` Richard Henderson
  2004-07-08  6:35   ` Zack Weinberg
  1 sibling, 1 reply; 5+ messages in thread
From: Richard Henderson @ 2004-07-08  5:30 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: GCC Patches

On Mon, Jul 05, 2004 at 11:58:35AM +0200, Paolo Bonzini wrote:
> -  regmove_optimize (get_insns (), max_reg_num (), dump_file);
> +  regmove_optimize (get_insns (), max_reg_num(), dump_file);

Whitespace error.

Otherwise ok.


r~

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-)
  2004-07-08  5:30 ` Richard Henderson
@ 2004-07-08  6:35   ` Zack Weinberg
  2004-07-08  6:56     ` Richard Henderson
  0 siblings, 1 reply; 5+ messages in thread
From: Zack Weinberg @ 2004-07-08  6:35 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Paolo Bonzini, GCC Patches

Richard Henderson <rth@redhat.com> writes:

> On Mon, Jul 05, 2004 at 11:58:35AM +0200, Paolo Bonzini wrote:
>> -  regmove_optimize (get_insns (), max_reg_num (), dump_file);
>> +  regmove_optimize (get_insns (), max_reg_num(), dump_file);
>
> Whitespace error.
>
> Otherwise ok.

Um.  Is it just me, or is relying on global variables to hold the
content of the function to be optimized a step in the wrong direction?

zw

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-)
  2004-07-08  6:35   ` Zack Weinberg
@ 2004-07-08  6:56     ` Richard Henderson
  0 siblings, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2004-07-08  6:56 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: Paolo Bonzini, GCC Patches

On Wed, Jul 07, 2004 at 11:05:53PM -0700, Zack Weinberg wrote:
> Um.  Is it just me, or is relying on global variables to hold the
> content of the function to be optimized a step in the wrong direction?

It's just you.  We have LOTS of variables that hold the content of
the function.  Hoisting just one or two into an argument buys nothing.


r~

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2004-07-08  6:33 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-07-05 10:37 [Updated PATCH] rest_of_compilation reorg (-2 steps to using the pass manager everywhere :-) Paolo Bonzini
2004-07-05 13:31 ` Paolo Bonzini
2004-07-08  5:30 ` Richard Henderson
2004-07-08  6:35   ` Zack Weinberg
2004-07-08  6:56     ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).