2004-06-17 Paolo Bonzini * 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; } } + } 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); +} + + +/* 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;