From: rth Date: Fri, 12 May 2000 16:26:15 +0000 (+0000) Subject: * Makefile.in (final.o): Depend on BASIC_BLOCK_H. X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=74b0991dfaf52eb1f152e64b4afc0d1cb05ddc28 * Makefile.in (final.o): Depend on BASIC_BLOCK_H. * final.c (final_end_function): Use app_disable. Rearrange note handling into a switch. Emit deleted labels. (output_asm_label): Generate label strings for deleted labels. * flow.c (tail_recursion_label_list): New. (find_basic_blocks_1): Set label_value_list directly. Collect list of tail recursion labels from call_placeholders. Don't add deleted labels to the label value list. (cleanup_cfg): Use free_EXPR_LIST_list. (flow_delete_insn_chain): Turn non-removable labels into notes. (flow_delete_block): Don't disable deleting the block because of a non-removable label. (tail_recursion_label_p): New. (merge_blocks_move_predecessor_nojumps): Don't disable the merge because of a label. (merge_blocks_move_successor_nojumps): Likewise. Also move a jump table. (merge_blocks): Disable a merge because of tail recursion labels. * ifcvt.c (merge_if_block): Don't disable a merge because of a label. Use a more accurate measure of not merging the join block. (find_if_block): Don't disable conversion because of a label. (find_if_case_1, find_if_case_2): Likewise. * jump.c (duplicate_loop_exit_test): Preserve the kind of list element when copying. (squeeze_notes): Also leave EH notes. (mark_jump_label): Ignore deleted labels. Use an INSN_LIST for REG_LABEL notes. (delete_insn): Preserve LABEL_NAME in NOTE_SOURCE_FILE when deleting a label. * print-rtl.c (print_rtx): Print NOTE_SOURCE_FILE for NOTE_INSN_DELETED_LABEL. Print `[# deleted]' for a label_ref referring to a deleted label. Convert tail handling to a switch. * rtl.def (CODE_LABEL): Rearrange elements to be compatible with NOTE for NOTE_INSN_DELETED_LABEL. (NOTE): Fix commentary. * rtl.h (REG_LABEL): Update commentary wrt INSN_LIST. (REG_CC_SETTER, REG_CC_USER, REG_LIBCALL): Likewise. (CODE_LABEL_NUMBER, LABEL_NAME): Update index. (LABEL_NUSES, LABEL_REFS): Likewise. * unroll.c (copy_loop_body): Don't copy NOTE_INSN_DELETED_LABEL. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33876 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 456338e8ae2..d5ff1679f75 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,46 @@ +2000-05-12 Richard Henderson + + * Makefile.in (final.o): Depend on BASIC_BLOCK_H. + * final.c (final_end_function): Use app_disable. Rearrange note + handling into a switch. Emit deleted labels. + (output_asm_label): Generate label strings for deleted labels. + * flow.c (tail_recursion_label_list): New. + (find_basic_blocks_1): Set label_value_list directly. Collect list + of tail recursion labels from call_placeholders. Don't add deleted + labels to the label value list. + (cleanup_cfg): Use free_EXPR_LIST_list. + (flow_delete_insn_chain): Turn non-removable labels into notes. + (flow_delete_block): Don't disable deleting the block because of + a non-removable label. + (tail_recursion_label_p): New. + (merge_blocks_move_predecessor_nojumps): Don't disable the merge + because of a label. + (merge_blocks_move_successor_nojumps): Likewise. Also move a + jump table. + (merge_blocks): Disable a merge because of tail recursion labels. + * ifcvt.c (merge_if_block): Don't disable a merge because of a label. + Use a more accurate measure of not merging the join block. + (find_if_block): Don't disable conversion because of a label. + (find_if_case_1, find_if_case_2): Likewise. + * jump.c (duplicate_loop_exit_test): Preserve the kind of list + element when copying. + (squeeze_notes): Also leave EH notes. + (mark_jump_label): Ignore deleted labels. Use an INSN_LIST for + REG_LABEL notes. + (delete_insn): Preserve LABEL_NAME in NOTE_SOURCE_FILE when + deleting a label. + * print-rtl.c (print_rtx): Print NOTE_SOURCE_FILE for + NOTE_INSN_DELETED_LABEL. Print `[# deleted]' for a label_ref + referring to a deleted label. Convert tail handling to a switch. + * rtl.def (CODE_LABEL): Rearrange elements to be compatible with NOTE + for NOTE_INSN_DELETED_LABEL. + (NOTE): Fix commentary. + * rtl.h (REG_LABEL): Update commentary wrt INSN_LIST. + (REG_CC_SETTER, REG_CC_USER, REG_LIBCALL): Likewise. + (CODE_LABEL_NUMBER, LABEL_NAME): Update index. + (LABEL_NUSES, LABEL_REFS): Likewise. + * unroll.c (copy_loop_body): Don't copy NOTE_INSN_DELETED_LABEL. + 2000-05-12 Zack Weinberg * fixinc/fixfixes.c (IO_use_fix, IO_defn_fix, CTRL_use_fix, diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 0ad11fb118d..3da7dee8447 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1374,7 +1374,7 @@ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \ $(REGS_H) $(RECOG_H) conditions.h insn-config.h insn-attr.h function.h \ real.h output.h hard-reg-set.h insn-flags.h insn-codes.h gstab.h except.h \ xcoffout.h defaults.h toplev.h reload.h dwarfout.h dwarf2out.h sdbout.h \ - dbxout.h + dbxout.h $(BASIC_BLOCK_H) recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) function.h $(BASIC_BLOCK_H) \ $(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \ insn-flags.h insn-codes.h real.h toplev.h output.h resource.h diff --git a/gcc/final.c b/gcc/final.c index c207cfb1d5d..02dc418a35f 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -68,6 +68,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "reload.h" #include "intl.h" +#include "basic-block.h" /* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */ #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) @@ -1782,11 +1783,7 @@ final_end_function (first, file, optimize) FILE *file; int optimize ATTRIBUTE_UNUSED; { - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); #ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) @@ -2082,218 +2079,243 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) if (prescan > 0) break; - /* Align the beginning of a loop, for higher speed - on certain machines. */ + switch (NOTE_LINE_NUMBER (insn)) + { + case NOTE_INSN_DELETED: + case NOTE_INSN_LOOP_BEG: + case NOTE_INSN_LOOP_END: + case NOTE_INSN_LOOP_CONT: + case NOTE_INSN_LOOP_VTOP: + case NOTE_INSN_FUNCTION_END: + case NOTE_INSN_SETJMP: + case NOTE_INSN_REPEATED_LINE_NUMBER: + case NOTE_INSN_RANGE_BEG: + case NOTE_INSN_RANGE_END: + case NOTE_INSN_LIVE: + case NOTE_INSN_EXPECTED_VALUE: + break; - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) - break; /* This used to depend on optimize, but that was bogus. */ - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) - break; + case NOTE_INSN_BASIC_BLOCK: + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s basic block %d\n", + ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); + break; - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG - && ! exceptions_via_longjmp) - { - ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_EH_HANDLER (insn)); - if (! flag_new_exceptions) - add_eh_table_entry (NOTE_EH_HANDLER (insn)); + case NOTE_INSN_EH_REGION_BEG: + if (! exceptions_via_longjmp) + { + ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_EH_HANDLER (insn)); + if (! flag_new_exceptions) + add_eh_table_entry (NOTE_EH_HANDLER (insn)); #ifdef ASM_OUTPUT_EH_REGION_BEG - ASM_OUTPUT_EH_REGION_BEG (file, NOTE_EH_HANDLER (insn)); + ASM_OUTPUT_EH_REGION_BEG (file, NOTE_EH_HANDLER (insn)); #endif + } break; - } - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END - && ! exceptions_via_longjmp) - { - ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_EH_HANDLER (insn)); - if (flag_new_exceptions) - add_eh_table_entry (NOTE_EH_HANDLER (insn)); + case NOTE_INSN_EH_REGION_END: + if (! exceptions_via_longjmp) + { + ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_EH_HANDLER (insn)); + if (flag_new_exceptions) + add_eh_table_entry (NOTE_EH_HANDLER (insn)); #ifdef ASM_OUTPUT_EH_REGION_END - ASM_OUTPUT_EH_REGION_END (file, NOTE_EH_HANDLER (insn)); + ASM_OUTPUT_EH_REGION_END (file, NOTE_EH_HANDLER (insn)); #endif + } break; - } - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END) - { + case NOTE_INSN_PROLOGUE_END: #ifdef FUNCTION_END_PROLOGUE FUNCTION_END_PROLOGUE (file); #endif profile_after_prologue (file); break; - } + case NOTE_INSN_EPILOGUE_BEG: #ifdef FUNCTION_BEGIN_EPILOGUE - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG) - { FUNCTION_BEGIN_EPILOGUE (file); - break; - } #endif + break; - if (write_symbols == NO_DEBUG) - break; - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) - { + case NOTE_INSN_FUNCTION_BEG: + if (write_symbols == NO_DEBUG) + break; #if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO) /* MIPS stabs require the parameter descriptions to be after the function entry point rather than before. */ if (write_symbols == SDB_DEBUG) - sdbout_begin_function (last_linenum); + { + app_disable (); + sdbout_begin_function (last_linenum); + } else #endif #ifdef DWARF_DEBUGGING_INFO /* This outputs a marker where the function body starts, so it must be after the prologue. */ if (write_symbols == DWARF_DEBUG) - dwarfout_begin_function (); + { + app_disable (); + dwarfout_begin_function (); + } #endif break; - } - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) - break; /* An insn that was "deleted" */ - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG - && (debug_info_level == DINFO_LEVEL_NORMAL + + case NOTE_INSN_BLOCK_BEG: + if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE || write_symbols == DWARF_DEBUG - || write_symbols == DWARF2_DEBUG)) - { - int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); + || write_symbols == DWARF2_DEBUG) + { + int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); - ++block_depth; - high_block_linenum = last_linenum; + app_disable (); + ++block_depth; + high_block_linenum = last_linenum; - /* Output debugging info about the symbol-block beginning. */ + /* Output debugging info about the symbol-block beginning. */ #ifdef SDB_DEBUGGING_INFO - if (write_symbols == SDB_DEBUG) - sdbout_begin_block (file, last_linenum, n); + if (write_symbols == SDB_DEBUG) + sdbout_begin_block (file, last_linenum, n); #endif #ifdef XCOFF_DEBUGGING_INFO - if (write_symbols == XCOFF_DEBUG) - xcoffout_begin_block (file, last_linenum, n); + if (write_symbols == XCOFF_DEBUG) + xcoffout_begin_block (file, last_linenum, n); #endif #ifdef DBX_DEBUGGING_INFO - if (write_symbols == DBX_DEBUG) - ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", n); + if (write_symbols == DBX_DEBUG) + ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", n); #endif #ifdef DWARF_DEBUGGING_INFO - if (write_symbols == DWARF_DEBUG) - dwarfout_begin_block (n); + if (write_symbols == DWARF_DEBUG) + dwarfout_begin_block (n); #endif #ifdef DWARF2_DEBUGGING_INFO - if (write_symbols == DWARF2_DEBUG) - dwarf2out_begin_block (n); + if (write_symbols == DWARF2_DEBUG) + dwarf2out_begin_block (n); #endif - /* Mark this block as output. */ - TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; - } - else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END - && (debug_info_level == DINFO_LEVEL_NORMAL - || debug_info_level == DINFO_LEVEL_VERBOSE - || write_symbols == DWARF_DEBUG - || write_symbols == DWARF2_DEBUG)) - { - int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); + /* Mark this block as output. */ + TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; + } + break; - /* End of a symbol-block. */ + case NOTE_INSN_BLOCK_END: + if (debug_info_level == DINFO_LEVEL_NORMAL + || debug_info_level == DINFO_LEVEL_VERBOSE + || write_symbols == DWARF_DEBUG + || write_symbols == DWARF2_DEBUG) + { + int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); - --block_depth; - if (block_depth < 0) - abort (); + app_disable (); + + /* End of a symbol-block. */ + --block_depth; + if (block_depth < 0) + abort (); #ifdef XCOFF_DEBUGGING_INFO - if (write_symbols == XCOFF_DEBUG) - xcoffout_end_block (file, high_block_linenum, n); + if (write_symbols == XCOFF_DEBUG) + xcoffout_end_block (file, high_block_linenum, n); #endif #ifdef DBX_DEBUGGING_INFO - if (write_symbols == DBX_DEBUG) - ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", n); + if (write_symbols == DBX_DEBUG) + ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", n); #endif #ifdef SDB_DEBUGGING_INFO - if (write_symbols == SDB_DEBUG) - sdbout_end_block (file, high_block_linenum, n); + if (write_symbols == SDB_DEBUG) + sdbout_end_block (file, high_block_linenum, n); #endif #ifdef DWARF_DEBUGGING_INFO - if (write_symbols == DWARF_DEBUG) - dwarfout_end_block (n); + if (write_symbols == DWARF_DEBUG) + dwarfout_end_block (n); #endif #ifdef DWARF2_DEBUGGING_INFO - if (write_symbols == DWARF2_DEBUG) - dwarf2out_end_block (n); + if (write_symbols == DWARF2_DEBUG) + dwarf2out_end_block (n); #endif - } - else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL - && (debug_info_level == DINFO_LEVEL_NORMAL - || debug_info_level == DINFO_LEVEL_VERBOSE)) - { + } + break; + + case NOTE_INSN_DELETED_LABEL: + /* Emit the label. We may have deleted the CODE_LABEL because + the label could be proved to be unreachable, though still + referenced (in the form of having its address taken. */ + /* ??? Figure out how not to do this unconditionally. This + interferes with bundling on LIW targets. */ + ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); + + if (debug_info_level == DINFO_LEVEL_NORMAL + || debug_info_level == DINFO_LEVEL_VERBOSE) + { #ifdef DWARF_DEBUGGING_INFO - if (write_symbols == DWARF_DEBUG) - dwarfout_label (insn); + if (write_symbols == DWARF_DEBUG) + dwarfout_label (insn); #endif #ifdef DWARF2_DEBUGGING_INFO - if (write_symbols == DWARF2_DEBUG) - dwarf2out_label (insn); + if (write_symbols == DWARF2_DEBUG) + dwarf2out_label (insn); #endif - } - else if (NOTE_LINE_NUMBER (insn) > 0) - /* This note is a line-number. */ - { - register rtx note; + } + break; -#if 0 /* This is what we used to do. */ - output_source_line (file, insn); -#endif - int note_after = 0; + default: + if (NOTE_LINE_NUMBER (insn) <= 0) + abort (); - /* If there is anything real after this note, - output it. If another line note follows, omit this one. */ - for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note)) - { - if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL) - break; - /* These types of notes can be significant - so make sure the preceding line number stays. */ - else if (GET_CODE (note) == NOTE - && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG - || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END - || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG)) - break; - else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0) - { - /* Another line note follows; we can delete this note - if no intervening line numbers have notes elsewhere. */ - int num; - for (num = NOTE_LINE_NUMBER (insn) + 1; - num < NOTE_LINE_NUMBER (note); - num++) - if (line_note_exists[num]) - break; - - if (num >= NOTE_LINE_NUMBER (note)) - note_after = 1; + /* This note is a line-number. */ + { + register rtx note; + int note_after = 0; + + /* If there is anything real after this note, output it. + If another line note follows, omit this one. */ + for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note)) + { + if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL) break; - } - } - /* Output this line note - if it is the first or the last line note in a row. */ - if (!note_after) - output_source_line (file, insn); + /* These types of notes can be significant + so make sure the preceding line number stays. */ + else if (GET_CODE (note) == NOTE + && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG + || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END + || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG)) + break; + else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0) + { + /* Another line note follows; we can delete this note + if no intervening line numbers have notes elsewhere. */ + int num; + for (num = NOTE_LINE_NUMBER (insn) + 1; + num < NOTE_LINE_NUMBER (note); + num++) + if (line_note_exists[num]) + break; + + if (num >= NOTE_LINE_NUMBER (note)) + note_after = 1; + break; + } + } + + /* Output this line note if it is the first or the last line + note in a row. */ + if (!note_after) + output_source_line (file, insn); + } + break; } break; case BARRIER: #if defined (DWARF2_UNWIND_INFO) - /* If we push arguments, we need to check all insns for stack - adjustments. */ - if (!ACCUMULATE_OUTGOING_ARGS && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + /* If we push arguments, we need to check all insns for stack + adjustments. */ + if (!ACCUMULATE_OUTGOING_ARGS && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn); #endif break; @@ -3544,8 +3566,10 @@ output_asm_label (x) char buf[256]; if (GET_CODE (x) == LABEL_REF) - ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); - else if (GET_CODE (x) == CODE_LABEL) + x = XEXP (x, 0); + if (GET_CODE (x) == CODE_LABEL + || (GET_CODE (x) == NOTE + && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); else output_operand_lossage ("`%l' operand isn't a label"); diff --git a/gcc/flow.c b/gcc/flow.c index 1bea9c2959f..a8573e1642a 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -253,6 +253,7 @@ varray_type basic_block_for_insn; bit of surgery to be able to use or co-opt the routines in jump. */ static rtx label_value_list; +static rtx tail_recursion_label_list; /* Holds information for tracking conditional register life information. */ struct reg_cond_life_info @@ -307,7 +308,7 @@ struct propagate_block_info /* Forward declarations */ static int count_basic_blocks PARAMS ((rtx)); -static rtx find_basic_blocks_1 PARAMS ((rtx)); +static void find_basic_blocks_1 PARAMS ((rtx)); static void clear_edges PARAMS ((void)); static void make_edges PARAMS ((rtx)); static void make_label_edge PARAMS ((sbitmap *, basic_block, @@ -325,6 +326,7 @@ static void delete_eh_regions PARAMS ((void)); static int can_delete_note_p PARAMS ((rtx)); static void expunge_block PARAMS ((basic_block)); static int can_delete_label_p PARAMS ((rtx)); +static int tail_recursion_label_p PARAMS ((rtx)); static int merge_blocks_move_predecessor_nojumps PARAMS ((basic_block, basic_block)); static int merge_blocks_move_successor_nojumps PARAMS ((basic_block, @@ -437,7 +439,7 @@ find_basic_blocks (f, nregs, file) VARRAY_BB_INIT (basic_block_info, n_basic_blocks, "basic_block_info"); - label_value_list = find_basic_blocks_1 (f); + find_basic_blocks_1 (f); /* Record the block to which an insn belongs. */ /* ??? This should be done another way, by which (perhaps) a label is @@ -535,7 +537,7 @@ count_basic_blocks (f) Collect and return a list of labels whose addresses are taken. This will be used in make_edges for use with computed gotos. */ -static rtx +static void find_basic_blocks_1 (f) rtx f; { @@ -543,7 +545,8 @@ find_basic_blocks_1 (f) int i = 0; rtx bb_note = NULL_RTX; rtx eh_list = NULL_RTX; - rtx label_value_list = NULL_RTX; + rtx lvl = NULL_RTX; + rtx trll = NULL_RTX; rtx head = NULL_RTX; rtx end = NULL_RTX; @@ -667,6 +670,12 @@ find_basic_blocks_1 (f) int region = (note ? INTVAL (XEXP (note, 0)) : 1); int call_has_abnormal_edge = 0; + /* If this is a call placeholder, record its tail recursion + label, if any. */ + if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER + && XEXP (PATTERN (insn), 3) != NULL_RTX) + trll = alloc_EXPR_LIST (0, XEXP (PATTERN (insn), 3), trll); + /* If there is an EH region or rethrow, we have an edge. */ if ((eh_list && region > 0) || find_reg_note (insn, REG_EH_RETHROW, NULL_RTX)) @@ -724,15 +733,16 @@ find_basic_blocks_1 (f) rtx lab = XEXP (note, 0), next; if (lab == eh_return_stub_label) - ; + ; else if ((next = next_nonnote_insn (lab)) != NULL && GET_CODE (next) == JUMP_INSN && (GET_CODE (PATTERN (next)) == ADDR_VEC || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)) ; + else if (GET_CODE (lab) == NOTE) + ; else - label_value_list - = alloc_EXPR_LIST (0, XEXP (note, 0), label_value_list); + lvl = alloc_EXPR_LIST (0, XEXP (note, 0), lvl); } } } @@ -745,7 +755,8 @@ find_basic_blocks_1 (f) if (i != n_basic_blocks) abort (); - return label_value_list; + label_value_list = lvl; + tail_recursion_label_list = trll; } /* Tidy the CFG by deleting unreachable code and whatnot. */ @@ -761,7 +772,8 @@ cleanup_cfg (f) mark_critical_edges (); /* Kill the data we won't maintain. */ - label_value_list = NULL_RTX; + free_EXPR_LIST_list (&label_value_list); + free_EXPR_LIST_list (&tail_recursion_label_list); } /* Create a new basic block consisting of the instructions between @@ -1853,8 +1865,14 @@ flow_delete_insn_chain (start, finish) next = NEXT_INSN (start); if (GET_CODE (start) == NOTE && !can_delete_note_p (start)) ; - else if (GET_CODE (start) == CODE_LABEL && !can_delete_label_p (start)) - ; + else if (GET_CODE (start) == CODE_LABEL + && ! can_delete_label_p (start)) + { + const char *name = LABEL_NAME (start); + PUT_CODE (start, NOTE); + NOTE_LINE_NUMBER (start) = NOTE_INSN_DELETED_LABEL; + NOTE_SOURCE_FILE (start) = name; + } else next = flow_delete_insn (start); @@ -1910,20 +1928,6 @@ flow_delete_block (b) } prev = &XEXP (x, 1); } - - /* This label may be referenced by code solely for its value, or - referenced by static data, or something. We have determined - that it is not reachable, but cannot delete the label itself. - Save code space and continue to delete the balance of the block, - along with properly updating the cfg. */ - if (!can_delete_label_p (insn)) - { - /* If we've only got one of these, skip the whole deleting - insns thing. */ - if (insn == b->end) - goto no_delete_insns; - insn = NEXT_INSN (insn); - } } /* Include any jump table following the basic block. */ @@ -1944,8 +1948,6 @@ flow_delete_block (b) /* Selectively delete the entire chain. */ flow_delete_insn_chain (insn, end); - no_delete_insns: - /* Remove the edges into and out of this block. Note that there may indeed be edges in, if we are removing an unreachable loop. */ { @@ -2063,6 +2065,19 @@ can_delete_label_p (label) return 1; } +static int +tail_recursion_label_p (label) + rtx label; +{ + rtx x; + + for (x = tail_recursion_label_list; x ; x = XEXP (x, 1)) + if (label == XEXP (x, 0)) + return 1; + + return 0; +} + /* Blocks A and B are to be merged into a single block A. The insns are already contiguous, hence `nomove'. */ @@ -2180,19 +2195,10 @@ merge_blocks_move_predecessor_nojumps (a, b) start = a->head; end = a->end; - /* We want to delete the BARRIER after the end of the insns we are - going to move. If we don't find a BARRIER, then do nothing. This - can happen in some cases if we have labels we can not delete. - - Similarly, do nothing if we can not delete the label at the start - of the target block. */ barrier = next_nonnote_insn (end); - if (GET_CODE (barrier) != BARRIER - || (GET_CODE (b->head) == CODE_LABEL - && ! can_delete_label_p (b->head))) - return 0; - else - flow_delete_insn (barrier); + if (GET_CODE (barrier) != BARRIER) + abort (); + flow_delete_insn (barrier); /* Move block and loop notes out of the chain so that we do not disturb their order. @@ -2240,20 +2246,23 @@ merge_blocks_move_successor_nojumps (a, b) start = b->head; end = b->end; + barrier = NEXT_INSN (end); - /* We want to delete the BARRIER after the end of the insns we are - going to move. If we don't find a BARRIER, then do nothing. This - can happen in some cases if we have labels we can not delete. + /* Recognize a jump table following block B. */ + if (GET_CODE (barrier) == CODE_LABEL + && NEXT_INSN (barrier) + && GET_CODE (NEXT_INSN (barrier)) == JUMP_INSN + && (GET_CODE (PATTERN (NEXT_INSN (barrier))) == ADDR_VEC + || GET_CODE (PATTERN (NEXT_INSN (barrier))) == ADDR_DIFF_VEC)) + { + end = NEXT_INSN (barrier); + barrier = NEXT_INSN (end); + } - Similarly, do nothing if we can not delete the label at the start - of the target block. */ - barrier = next_nonnote_insn (end); - if (GET_CODE (barrier) != BARRIER - || (GET_CODE (b->head) == CODE_LABEL - && ! can_delete_label_p (b->head))) - return 0; - else - flow_delete_insn (barrier); + /* There had better have been a barrier there. Delete it. */ + if (GET_CODE (barrier) != BARRIER) + abort (); + flow_delete_insn (barrier); /* Move block and loop notes out of the chain so that we do not disturb their order. @@ -2287,17 +2296,17 @@ merge_blocks (e, b, c) edge e; basic_block b, c; { + /* If C has a tail recursion label, do not merge. There is no + edge recorded from the call_placeholder back to this label, as + that would make optimize_sibling_and_tail_recursive_calls more + complex for no gain. */ + if (GET_CODE (c->head) == CODE_LABEL + && tail_recursion_label_p (c->head)) + return 0; + /* If B has a fallthru edge to C, no need to move anything. */ if (e->flags & EDGE_FALLTHRU) { - /* If a label still appears somewhere and we cannot delete the label, - then we cannot merge the blocks. The edge was tidied already. */ - - rtx insn, stop = NEXT_INSN (c->head); - for (insn = NEXT_INSN (b->end); insn != stop; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CODE_LABEL && !can_delete_label_p (insn)) - return 0; - merge_blocks_nomove (b, c); if (rtl_dump_file) diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 8c2ddee0fbf..aa54390e73a 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1275,37 +1275,8 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) get their addresses taken. */ if (else_bb) { - if (LABEL_NUSES (else_bb->head) == 0 - && ! LABEL_PRESERVE_P (else_bb->head) - && ! LABEL_NAME (else_bb->head)) - { - /* We can merge the ELSE. */ - merge_blocks_nomove (combo_bb, else_bb); - num_removed_blocks++; - } - else - { - /* We cannot merge the ELSE. */ - - /* Properly rewire the edge out of the now combined - TEST-THEN block to point here. */ - remove_edge (combo_bb->succ); - if (combo_bb->succ || else_bb->pred) - abort (); - make_edge (NULL, combo_bb, else_bb, EDGE_FALLTHRU); - - /* Remove the jump and cruft from the end of the TEST-THEN block. */ - tidy_fallthru_edge (combo_bb->succ, combo_bb, else_bb); - - /* Make sure we update life info properly. */ - SET_UPDATE_LIFE(combo_bb); - if (else_bb->global_live_at_end) - COPY_REG_SET (else_bb->global_live_at_start, - else_bb->global_live_at_end); - - /* The ELSE is the new combo block. */ - combo_bb = else_bb; - } + merge_blocks_nomove (combo_bb, else_bb); + num_removed_blocks++; } /* If there was no join block reported, that means it was not adjacent @@ -1325,12 +1296,11 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) abort (); } - /* The JOIN block had a label. It may have had quite a number - of other predecessors too, but probably not. See if we can - merge this with the others. */ - else if (LABEL_NUSES (join_bb->head) == 0 - && ! LABEL_PRESERVE_P (join_bb->head) - && ! LABEL_NAME (join_bb->head)) + /* The JOIN block may have had quite a number of other predecessors too. + Since we've already merged the TEST, THEN and ELSE blocks, we should + have only one remaining edge from our if-then-else diamond. If there + is more than one remaining edge, it must come from elsewhere. */ + else if (join_bb->pred->pred_next == NULL) { /* We can merge the JOIN. */ if (combo_bb->global_live_at_end) @@ -1438,11 +1408,6 @@ find_if_block (test_bb, then_edge, else_edge) || (then_succ->flags & EDGE_COMPLEX)) return FALSE; - /* The THEN block may not start with a label, as might happen with an - unused user label that has had its address taken. */ - if (GET_CODE (then_bb->head) == CODE_LABEL) - return FALSE; - /* If the THEN block's successor is the other edge out of the TEST block, then we have an IF-THEN combo without an ELSE. */ if (then_succ->dest == else_bb) @@ -1600,10 +1565,6 @@ find_if_case_1 (test_bb, then_edge, else_edge) if (then_bb->pred->pred_next != NULL) return FALSE; - /* THEN has no label. */ - if (GET_CODE (then_bb->head) == CODE_LABEL) - return FALSE; - /* ELSE follows THEN. (??? could be moved) */ if (else_bb->index != then_bb->index + 1) return FALSE; @@ -1674,12 +1635,6 @@ find_if_case_2 (test_bb, then_edge, else_edge) if (else_bb->pred->pred_next != NULL) return FALSE; - /* ELSE has a label we can delete. */ - if (LABEL_NUSES (else_bb->head) > 1 - || LABEL_PRESERVE_P (else_bb->head) - || LABEL_NAME (else_bb->head)) - return FALSE; - /* ELSE is predicted or SUCC(ELSE) postdominates THEN. */ note = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX); if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) diff --git a/gcc/jump.c b/gcc/jump.c index baffdf03b7b..4296759545f 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -1262,10 +1262,19 @@ duplicate_loop_exit_test (loop_start) make them. */ for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) != REG_LABEL) - REG_NOTES (copy) - = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link), - XEXP (link, 0), - REG_NOTES (copy))); + { + if (GET_CODE (link) == EXPR_LIST) + REG_NOTES (copy) + = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link), + XEXP (link, 0), + REG_NOTES (copy))); + else + REG_NOTES (copy) + = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link), + XEXP (link, 0), + REG_NOTES (copy))); + } + if (reg_map && REG_NOTES (copy)) replace_regs (REG_NOTES (copy), reg_map, max_reg, 1); break; @@ -1345,8 +1354,8 @@ duplicate_loop_exit_test (loop_start) return 1; } -/* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, and - loop-end notes between START and END out before START. Assume that +/* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end, + eh-beg, eh-end notes between START and END out before START. Assume that END is not such a note. START may be such a note. Returns the value of the new starting insn, which may be different if the original start was such a note. */ @@ -1367,7 +1376,9 @@ squeeze_notes (start, end) || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP)) + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) { if (insn == start) start = next; @@ -2389,6 +2400,12 @@ mark_jump_label (x, insn, cross_jump, in_mem) rtx note; rtx next; + /* Ignore remaining references to unreachable labels that + have been deleted. */ + if (GET_CODE (label) == NOTE + && NOTE_LINE_NUMBER (label) == NOTE_INSN_DELETED_LABEL) + break; + if (GET_CODE (label) != CODE_LABEL) abort (); @@ -2449,7 +2466,7 @@ mark_jump_label (x, insn, cross_jump, in_mem) is no longer valid because of the more accurate cfg we build in find_basic_blocks -- it no longer pessimizes code when it finds a REG_LABEL note. */ - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (insn)); } } @@ -2755,9 +2772,10 @@ delete_insn (insn) dont_really_delete = 1; else if (! dont_really_delete) { + const char *name = LABEL_NAME (insn); PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL; - NOTE_SOURCE_FILE (insn) = 0; + NOTE_SOURCE_FILE (insn) = name; dont_really_delete = 1; } } diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index 140ac36bdb7..d8008380215 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -210,6 +210,13 @@ print_rtx (in_rtx) indent -= 2; break; + case NOTE_INSN_DELETED_LABEL: + if (NOTE_SOURCE_FILE (in_rtx)) + fprintf (outfile, " (\"%s\")", NOTE_SOURCE_FILE (in_rtx)); + else + fprintf (outfile, " \"\""); + break; + default: { const char * const str = X0STR (in_rtx, i); @@ -334,11 +341,25 @@ print_rtx (in_rtx) rtx sub = XEXP (in_rtx, i); enum rtx_code subc = GET_CODE (sub); - if (GET_CODE (in_rtx) == LABEL_REF && subc != CODE_LABEL) - goto do_e; + if (GET_CODE (in_rtx) == LABEL_REF) + { + if (subc == NOTE + && NOTE_LINE_NUMBER (sub) == NOTE_INSN_DELETED_LABEL) + { + if (flag_dump_unnumbered) + fprintf (outfile, " [# deleted]"); + else + fprintf (outfile, " [%d deleted]", INSN_UID (sub)); + sawclose = 0; + break; + } + + if (subc != CODE_LABEL) + goto do_e; + } if (flag_dump_unnumbered) - fputc ('#', outfile); + fputs (" #", outfile); else fprintf (outfile, " %d", INSN_UID (sub)); } @@ -372,34 +393,43 @@ print_rtx (in_rtx) abort (); } - if (GET_CODE (in_rtx) == MEM) - fprintf (outfile, " %d", MEM_ALIAS_SET (in_rtx)); + switch (GET_CODE (in_rtx)) + { + case MEM: + fprintf (outfile, " %d", MEM_ALIAS_SET (in_rtx)); + break; #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && MAX_LONG_DOUBLE_TYPE_SIZE == 64 - if (GET_CODE (in_rtx) == CONST_DOUBLE && FLOAT_MODE_P (GET_MODE (in_rtx))) - { - double val; - REAL_VALUE_FROM_CONST_DOUBLE (val, in_rtx); - fprintf (outfile, " [%.16g]", val); - } + case CONST_DOUBLE: + if (FLOAT_MODE_P (GET_MODE (in_rtx))) + { + double val; + REAL_VALUE_FROM_CONST_DOUBLE (val, in_rtx); + fprintf (outfile, " [%.16g]", val); + } + break; #endif - if (GET_CODE (in_rtx) == CODE_LABEL) - { + case CODE_LABEL: fprintf (outfile, " [%d uses]", LABEL_NUSES (in_rtx)); if (LABEL_ALTERNATE_NAME (in_rtx)) fprintf (outfile, " [alternate name: %s]", LABEL_ALTERNATE_NAME (in_rtx)); + break; + + case CALL_PLACEHOLDER: + for (tem = XEXP (in_rtx, 0); tem != 0; tem = NEXT_INSN (tem)) + if (GET_CODE (tem) == CALL_INSN) + { + fprintf (outfile, " "); + print_rtx (tem); + break; + } + break; + + default: + break; } - - if (GET_CODE (in_rtx) == CALL_PLACEHOLDER) - for (tem = XEXP (in_rtx, 0); tem != 0; tem = NEXT_INSN (tem)) - if (GET_CODE (tem) == CALL_INSN) - { - fprintf (outfile, " "); - print_rtx (tem); - break; - } if (dump_for_graph && (is_insn || GET_CODE (in_rtx) == NOTE diff --git a/gcc/rtl.def b/gcc/rtl.def index cbfd892bc67..97df5373e3e 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -413,21 +413,16 @@ DEF_RTL_EXPR(BARRIER, "barrier", "iuu", 'x') /* Holds a label that is followed by instructions. Operand: - 3: is a number that is unique in the entire compilation. - 4: is the user-given name of the label, if any. - 5: is used in jump.c for the use-count of the label. - 6: is used in flow.c to point to the chain of label_ref's to this label. + 3: is used in jump.c for the use-count of the label. + 4: is used in flow.c to point to the chain of label_ref's to this label. + 5: is a number that is unique in the entire compilation. + 6: is the user-given name of the label, if any. 7: is the alternate label name. */ -DEF_RTL_EXPR(CODE_LABEL, "code_label", "iuuis00s", 'x') +DEF_RTL_EXPR(CODE_LABEL, "code_label", "iuu00iss", 'x') /* Say where in the code a source line starts, for symbol table's sake. - Contains a filename and a line number. Line numbers <= 0 are special: - 0 is used in a dummy placed at the front of every function - just so there will never be a need to delete the first insn; - -1 indicates a dummy; insns to be deleted by flow analysis and combining - are really changed to NOTEs with a number of -1. - -2 means beginning of a name binding contour; output N_LBRAC. - -3 means end of a contour; output N_RBRAC. */ + Contains a filename and a line number. Line numbers <= 0 are special; + See enum note_insn in rtl.h. */ DEF_RTL_EXPR(NOTE, "note", "iuu0n", 'x') /* ---------------------------------------------------------------------- diff --git a/gcc/rtl.h b/gcc/rtl.h index 815cb0dc041..ccd143ecf02 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -417,7 +417,7 @@ enum reg_note appear on an insn which copies a register parameter to a pseudo-register, if there is a memory address which could be used to hold that pseudo-register throughout the function. */ - REG_EQUIV, + REG_EQUIV, /* Like REG_EQUIV except that the destination is only momentarily equal to the specified rtx. Therefore, it cannot be used for substitution; @@ -437,7 +437,8 @@ enum reg_note REG_RETVAL, /* The inverse of REG_RETVAL: it goes on the first insn of the library call - and points at the one that has the REG_RETVAL. */ + and points at the one that has the REG_RETVAL. This note is also an + INSN_LIST. */ REG_LIBCALL, /* The register is always nonnegative during the containing loop. This is @@ -459,11 +460,13 @@ enum reg_note we permit putting a cc0-setting insn in the delay slot of a branch as long as only one copy of the insn exists. In that case, these notes point from one to the other to allow code generation to determine what - any require information and to properly update CC_STATUS. */ + any require information and to properly update CC_STATUS. These notes + are INSN_LISTs. */ REG_CC_SETTER, REG_CC_USER, /* Points to a CODE_LABEL. Used by non-JUMP_INSNs to say that the - CODE_LABEL contained in the REG_LABEL note is used by the insn. */ + CODE_LABEL contained in the REG_LABEL note is used by the insn. + This note is an INSN_LIST. */ REG_LABEL, /* REG_DEP_ANTI and REG_DEP_OUTPUT are used in LOG_LINKS to represent @@ -544,7 +547,7 @@ extern const char * const reg_note_name[]; /* The label-number of a code-label. The assembler label is made from `L' and the label-number printed in decimal. Label numbers are unique in a compilation. */ -#define CODE_LABEL_NUMBER(INSN) XINT(INSN, 3) +#define CODE_LABEL_NUMBER(INSN) XINT(INSN, 5) #define LINE_NUMBER NOTE @@ -664,11 +667,11 @@ extern const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS]; /* The name of a label, in case it corresponds to an explicit label in the input source code. */ -#define LABEL_NAME(RTX) XCSTR(RTX, 4, CODE_LABEL) +#define LABEL_NAME(RTX) XCSTR(RTX, 6, CODE_LABEL) /* In jump.c, each label contains a count of the number of LABEL_REFs that point at it, so unused labels can be deleted. */ -#define LABEL_NUSES(RTX) XCINT(RTX, 5, CODE_LABEL) +#define LABEL_NUSES(RTX) XCINT(RTX, 3, CODE_LABEL) /* Associate a name with a CODE_LABEL. */ #define LABEL_ALTERNATE_NAME(RTX) XCSTR(RTX, 7, CODE_LABEL) @@ -687,8 +690,8 @@ extern const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS]; /* Once basic blocks are found in flow.c, each CODE_LABEL starts a chain that goes through all the LABEL_REFs that jump to that label. - The chain eventually winds up at the CODE_LABEL; it is circular. */ -#define LABEL_REFS(LABEL) XCEXP(LABEL, 6, CODE_LABEL) + The chain eventually winds up at the CODE_LABEL: it is circular. */ +#define LABEL_REFS(LABEL) XCEXP(LABEL, 4, CODE_LABEL) /* This is the field in the LABEL_REF through which the circular chain of references to a particular label is linked. diff --git a/gcc/unroll.c b/gcc/unroll.c index 6ecef324612..82d2d69d836 100644 --- a/gcc/unroll.c +++ b/gcc/unroll.c @@ -2207,6 +2207,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration, this new block. */ if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK && ((NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)