X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Ffinal.c;h=0d19562acbf0742c7a8e6193a4e706b7e9411dc7;hp=ccef70f00f1e3f1f51a944bc1154ff5da3962e93;hb=09bb92cc6c04baa4484a5e1a60cdf2a5e62bc9a7;hpb=18d50ae6ff193b3e8af71e41353850749036283b diff --git a/gcc/final.c b/gcc/final.c index ccef70f00f1..0d19562acbf 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1,6 +1,6 @@ /* Convert RTL to assembler code and output it, for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GCC. @@ -72,6 +72,7 @@ along with GCC; see the file COPYING3. If not see #include "expr.h" #include "cfglayout.h" #include "tree-pass.h" +#include "tree-flow.h" #include "timevar.h" #include "cgraph.h" #include "coverage.h" @@ -130,6 +131,12 @@ rtx current_output_insn; /* Line number of last NOTE. */ static int last_linenum; +/* Last discriminator written to assembly. */ +static int last_discriminator; + +/* Discriminator of current block. */ +static int discriminator; + /* Highest line number in current block. */ static int high_block_linenum; @@ -178,12 +185,6 @@ CC_STATUS cc_status; CC_STATUS cc_prev_status; #endif -/* Nonzero means current function must be given a frame pointer. - Initialized in function.c to 0. Set only in reload1.c as per - the needs of the function. */ - -int frame_pointer_needed; - /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */ static int block_depth; @@ -203,17 +204,15 @@ rtx final_sequence; static int dialect_number; #endif -#ifdef HAVE_conditional_execution /* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ rtx current_insn_predicate; -#endif #ifdef HAVE_ATTR_length static int asm_insn_count (rtx); #endif static void profile_function (FILE *); static void profile_after_prologue (FILE *); -static bool notice_source_line (rtx); +static bool notice_source_line (rtx, bool *); static rtx walk_alter_subreg (rtx *, bool *); static void output_asm_name (void); static void output_alternate_entry_point (FILE *, rtx); @@ -390,6 +389,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, case NOTE: case BARRIER: case CODE_LABEL: + case DEBUG_INSN: return 0; case CALL_INSN: @@ -416,7 +416,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, length = asm_insn_count (body) * fallback_fn (insn); else if (GET_CODE (body) == SEQUENCE) for (i = 0; i < XVECLEN (body, 0); i++) - length += get_attr_length (XVECEXP (body, 0, i)); + length += get_attr_length_1 (XVECEXP (body, 0, i), fallback_fn); else length = fallback_fn (insn); break; @@ -559,7 +559,17 @@ static int min_labelno, max_labelno; int label_to_alignment (rtx label) { - return LABEL_TO_ALIGNMENT (label); + if (CODE_LABEL_NUMBER (label) <= max_labelno) + return LABEL_TO_ALIGNMENT (label); + return 0; +} + +int +label_to_max_skip (rtx label) +{ + if (CODE_LABEL_NUMBER (label) <= max_labelno) + return LABEL_TO_MAX_SKIP (label); + return 0; } #ifdef HAVE_ATTR_length @@ -670,7 +680,7 @@ insn_current_reference_address (rtx branch) /* Compute branch alignments based on frequency information in the CFG. */ -static unsigned int +unsigned int compute_alignments (void) { int log, max_skip, max_log; @@ -689,7 +699,7 @@ compute_alignments (void) label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1); /* If not optimizing or optimizing for size, don't assign any alignments. */ - if (! optimize || optimize_size) + if (! optimize || optimize_function_for_size_p (cfun)) return 0; if (dump_file) @@ -713,7 +723,7 @@ compute_alignments (void) edge_iterator ei; if (!LABEL_P (label) - || probably_never_executed_bb_p (bb)) + || optimize_bb_for_size_p (bb)) { if (dump_file) fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n", @@ -771,7 +781,7 @@ compute_alignments (void) /* In case block is frequent and reached mostly by non-fallthru edge, align it. It is most likely a first block of loop. */ if (has_fallthru - && maybe_hot_bb_p (bb) + && optimize_bb_for_speed_p (bb) && branch_frequency + fallthru_frequency > freq_threshold && (branch_frequency > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS))) @@ -790,7 +800,10 @@ compute_alignments (void) } if (dump_file) - loop_optimizer_finalize (); + { + loop_optimizer_finalize (); + free_dominance_info (CDI_DOMINATORS); + } return 0; } @@ -804,7 +817,7 @@ struct rtl_opt_pass pass_compute_alignments = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -864,8 +877,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) n_labels = max_labelno - min_labelno + 1; n_old_labels = old - min_labelno + 1; - label_align = xrealloc (label_align, - n_labels * sizeof (struct label_alignment)); + label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels); /* Range of labels grows monotonically in the function. Failing here means that the initialization of array got lost. */ @@ -895,6 +907,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (LABEL_P (insn)) { rtx next; + bool next_is_jumptable; /* Merge in alignments computed by compute_alignments. */ log = LABEL_TO_ALIGNMENT (insn); @@ -904,31 +917,30 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) max_skip = LABEL_TO_MAX_SKIP (insn); } - log = LABEL_ALIGN (insn); - if (max_log < log) + next = next_nonnote_insn (insn); + next_is_jumptable = next && JUMP_TABLE_DATA_P (next); + if (!next_is_jumptable) { - max_log = log; - max_skip = LABEL_ALIGN_MAX_SKIP; + log = LABEL_ALIGN (insn); + if (max_log < log) + { + max_log = log; + max_skip = LABEL_ALIGN_MAX_SKIP; + } } - next = next_nonnote_insn (insn); /* ADDR_VECs only take room if read-only data goes into the text section. */ - if (JUMP_TABLES_IN_TEXT_SECTION - || readonly_data_section == text_section) - if (next && JUMP_P (next)) - { - rtx nextbody = PATTERN (next); - if (GET_CODE (nextbody) == ADDR_VEC - || GET_CODE (nextbody) == ADDR_DIFF_VEC) - { - log = ADDR_VEC_ALIGN (next); - if (max_log < log) - { - max_log = log; - max_skip = LABEL_ALIGN_MAX_SKIP; - } - } - } + if ((JUMP_TABLES_IN_TEXT_SECTION + || readonly_data_section == text_section) + && next_is_jumptable) + { + log = ADDR_VEC_ALIGN (next); + if (max_log < log) + { + max_log = log; + max_skip = LABEL_ALIGN_MAX_SKIP; + } + } LABEL_TO_ALIGNMENT (insn) = max_log; LABEL_TO_MAX_SKIP (insn) = max_skip; max_log = 0; @@ -1067,7 +1079,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid]; if (NOTE_P (insn) || BARRIER_P (insn) - || LABEL_P (insn)) + || LABEL_P (insn) || DEBUG_INSN_P(insn)) continue; if (INSN_DELETED_P (insn)) continue; @@ -1384,22 +1396,34 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) static int asm_insn_count (rtx body) { - const char *template; - int count = 1; + const char *templ; if (GET_CODE (body) == ASM_INPUT) - template = XSTR (body, 0); + templ = XSTR (body, 0); else - template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); + templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); + + return asm_str_count (templ); +} +#endif - for (; *template; template++) - if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template, template) - || *template == '\n') +/* Return the number of machine instructions likely to be generated for the + inline-asm template. */ +int +asm_str_count (const char *templ) +{ + int count = 1; + + if (!*templ) + return 0; + + for (; *templ; templ++) + if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ) + || *templ == '\n') count++; return count; } -#endif /* ??? This is probably the wrong place for these. */ /* Structure recording the mapping from source file and directory @@ -1434,10 +1458,10 @@ add_debug_prefix_map (const char *arg) return; } map = XNEW (debug_prefix_map); - map->old_prefix = ggc_alloc_string (arg, p - arg); + map->old_prefix = xstrndup (arg, p - arg); map->old_len = p - arg; p++; - map->new_prefix = ggc_strdup (p); + map->new_prefix = xstrdup (p); map->new_len = strlen (p); map->next = debug_prefix_maps; debug_prefix_maps = map; @@ -1467,6 +1491,20 @@ remap_debug_filename (const char *filename) return ggc_strdup (s); } +/* Return true if DWARF2 debug info can be emitted for DECL. */ + +static bool +dwarf2_debug_info_emitted_p (tree decl) +{ + if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) + return false; + + if (DECL_IGNORED_P (decl)) + return false; + + return true; +} + /* Output assembler code for the start of a function, and initialize some of the variables in this file for the new function. The label for the function and associated @@ -1487,13 +1525,15 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, last_filename = locator_file (prologue_locator); last_linenum = locator_line (prologue_locator); + last_discriminator = discriminator = 0; high_block_linenum = high_function_linenum = last_linenum; - (*debug_hooks->begin_prologue) (last_linenum, last_filename); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->begin_prologue (last_linenum, last_filename); #if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO) - if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) + if (!dwarf2_debug_info_emitted_p (current_function_decl)) dwarf2out_begin_prologue (0, NULL); #endif @@ -1561,12 +1601,14 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) #ifndef NO_PROFILE_COUNTERS # define NO_PROFILE_COUNTERS 0 #endif -#if defined(ASM_OUTPUT_REG_PUSH) - int sval = cfun->returns_struct; - rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); -#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) - int cxt = cfun->static_chain_decl != NULL; -#endif +#ifdef ASM_OUTPUT_REG_PUSH + rtx sval = NULL, chain = NULL; + + if (cfun->returns_struct) + sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), + true); + if (cfun->static_chain_decl) + chain = targetm.calls.static_chain (current_function_decl, true); #endif /* ASM_OUTPUT_REG_PUSH */ if (! NO_PROFILE_COUNTERS) @@ -1580,44 +1622,20 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) switch_to_section (current_function_section ()); -#if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) - { - ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); - } -#endif - -#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); -#else -#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - { - ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); - } -#endif +#ifdef ASM_OUTPUT_REG_PUSH + if (sval && REG_P (sval)) + ASM_OUTPUT_REG_PUSH (file, REGNO (sval)); + if (chain && REG_P (chain)) + ASM_OUTPUT_REG_PUSH (file, REGNO (chain)); #endif FUNCTION_PROFILER (file, current_function_funcdef_no); -#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); -#else -#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - { - ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); - } -#endif -#endif - -#if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) - { - ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); - } +#ifdef ASM_OUTPUT_REG_PUSH + if (chain && REG_P (chain)) + ASM_OUTPUT_REG_POP (file, REGNO (chain)); + if (sval && REG_P (sval)) + ASM_OUTPUT_REG_POP (file, REGNO (sval)); #endif } @@ -1630,17 +1648,19 @@ final_end_function (void) { app_disable (); - (*debug_hooks->end_function) (high_function_linenum); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->end_function (high_function_linenum); /* Finally, output the function epilogue: code to restore the stack frame and return to the caller. */ targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ()); /* And debug output. */ - (*debug_hooks->end_epilogue) (last_linenum, last_filename); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->end_epilogue (last_linenum, last_filename); #if defined (DWARF2_UNWIND_INFO) - if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG + if (!dwarf2_debug_info_emitted_p (current_function_decl) && dwarf2out_do_frame ()) dwarf2out_end_epilogue (last_linenum, last_filename); #endif @@ -1748,6 +1768,34 @@ output_alternate_entry_point (FILE *file, rtx insn) } } +/* Given a CALL_INSN, find and return the nested CALL. */ +static rtx +call_from_call_insn (rtx insn) +{ + rtx x; + gcc_assert (CALL_P (insn)); + x = PATTERN (insn); + + while (GET_CODE (x) != CALL) + { + switch (GET_CODE (x)) + { + default: + gcc_unreachable (); + case COND_EXEC: + x = COND_EXEC_CODE (x); + break; + case PARALLEL: + x = XVECEXP (x, 0, 0); + break; + case SET: + x = XEXP (x, 1); + break; + } + } + return x; +} + /* The final scan for one insn, INSN. Args are same as in `final', except that INSN is the insn being scanned. @@ -1793,7 +1841,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, dwarf2out_switch_text_section (); else #endif - (*debug_hooks->switch_text_section) (); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->switch_text_section (); switch_to_section (current_function_section ()); break; @@ -1815,6 +1864,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, else *seen |= SEEN_BB; + discriminator = NOTE_BASIC_BLOCK (insn)->discriminator; + break; case NOTE_INSN_EH_REGION_BEG: @@ -1842,12 +1893,23 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_EPILOGUE_BEG: +#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_epilogue) + if (dwarf2out_do_frame ()) + dwarf2out_begin_epilogue (insn); +#endif targetm.asm_out.function_begin_epilogue (file); break; + case NOTE_INSN_CFA_RESTORE_STATE: +#if defined (DWARF2_UNWIND_INFO) + dwarf2out_frame_debug_restore_state (); +#endif + break; + case NOTE_INSN_FUNCTION_BEG: app_disable (); - (*debug_hooks->end_prologue) (last_linenum, last_filename); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->end_prologue (last_linenum, last_filename); if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) { @@ -1873,7 +1935,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, high_block_linenum = last_linenum; /* Output debugging info about the symbol-block beginning. */ - (*debug_hooks->begin_block) (last_linenum, n); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->begin_block (last_linenum, n); /* Mark this block as output. */ TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; @@ -1907,7 +1970,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, --block_depth; gcc_assert (block_depth >= 0); - (*debug_hooks->end_block) (high_block_linenum, n); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->end_block (high_block_linenum, n); } if (write_symbols == DBX_DEBUG || write_symbols == SDB_DEBUG) @@ -1937,7 +2001,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_VAR_LOCATION: - (*debug_hooks->var_location) (insn); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); break; default: @@ -1980,58 +2045,47 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, CC_STATUS_INIT; #endif - if (LABEL_NAME (insn)) - (*debug_hooks->label) (insn); + if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn)) + debug_hooks->label (insn); - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); next = next_nonnote_insn (insn); - if (next != 0 && JUMP_P (next)) + /* If this label is followed by a jump-table, make sure we put + the label in the read-only section. Also possibly write the + label and jump table together. */ + if (next != 0 && JUMP_TABLE_DATA_P (next)) { - rtx nextbody = PATTERN (next); - - /* If this label is followed by a jump-table, - make sure we put the label in the read-only section. Also - possibly write the label and jump table together. */ - - if (GET_CODE (nextbody) == ADDR_VEC - || GET_CODE (nextbody) == ADDR_DIFF_VEC) - { #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) - /* In this case, the case vector is being moved by the - target, so don't output the label at all. Leave that - to the back end macros. */ + /* In this case, the case vector is being moved by the + target, so don't output the label at all. Leave that + to the back end macros. */ #else - if (! JUMP_TABLES_IN_TEXT_SECTION) - { - int log_align; + if (! JUMP_TABLES_IN_TEXT_SECTION) + { + int log_align; - switch_to_section (targetm.asm_out.function_rodata_section - (current_function_decl)); + switch_to_section (targetm.asm_out.function_rodata_section + (current_function_decl)); #ifdef ADDR_VEC_ALIGN - log_align = ADDR_VEC_ALIGN (next); + log_align = ADDR_VEC_ALIGN (next); #else - log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); + log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); #endif - ASM_OUTPUT_ALIGN (file, log_align); - } - else - switch_to_section (current_function_section ()); + ASM_OUTPUT_ALIGN (file, log_align); + } + else + switch_to_section (current_function_section ()); #ifdef ASM_OUTPUT_CASE_LABEL - ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), - next); + ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), + next); #else - targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); #endif #endif - break; - } + break; } if (LABEL_ALT_ENTRY_P (insn)) output_alternate_entry_point (file, insn); @@ -2043,12 +2097,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { rtx body = PATTERN (insn); int insn_code_number; - const char *template; + const char *templ; + bool is_stmt; -#ifdef HAVE_conditional_execution /* Reset this early so it is correct for ASM statements. */ current_insn_predicate = NULL_RTX; -#endif + /* An INSN, JUMP_INSN or CALL_INSN. First check for special kinds that recog doesn't recognize. */ @@ -2087,11 +2141,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, else switch_to_section (current_function_section ()); - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) if (GET_CODE (body) == ADDR_VEC) @@ -2149,10 +2199,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, } /* Output this line note if it is the first or the last line note in a row. */ - if (notice_source_line (insn)) - { - (*debug_hooks->source_line) (last_linenum, last_filename); - } + if (!DECL_IGNORED_P (current_function_decl) + && notice_source_line (insn, &is_stmt)) + (*debug_hooks->source_line) (last_linenum, last_filename, + last_discriminator, is_stmt); if (GET_CODE (body) == ASM_INPUT) { @@ -2165,11 +2215,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { expanded_location loc; - if (! app_on) - { - fputs (ASM_APP_ON, file); - app_on = 1; - } + app_enable (); loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body)); if (*loc.file && loc.line) fprintf (asm_out_file, "%s %i \"%s\" 1\n", @@ -2187,7 +2233,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if (asm_noperands (body) >= 0) { unsigned int noperands = asm_noperands (body); - rtx *ops = alloca (noperands * sizeof (rtx)); + rtx *ops = XALLOCAVEC (rtx, noperands); const char *string; location_t loc; expanded_location expanded; @@ -2209,11 +2255,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* Output the insn using them. */ if (string[0]) { - if (! app_on) - { - fputs (ASM_APP_ON, file); - app_on = 1; - } + app_enable (); if (expanded.file && expanded.line) fprintf (asm_out_file, "%s %i \"%s\" 1\n", ASM_COMMENT_START, expanded.line, expanded.file); @@ -2224,15 +2266,15 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif } + if (targetm.asm_out.final_postscan_insn) + targetm.asm_out.final_postscan_insn (file, insn, ops, + insn_noperands); + this_is_asm_operands = 0; break; } - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); if (GET_CODE (body) == SEQUENCE) { @@ -2309,9 +2351,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, && GET_CODE (SET_DEST (set)) == CC0 && insn != last_ignored_compare) { + rtx src1, src2; if (GET_CODE (SET_SRC (set)) == SUBREG) SET_SRC (set) = alter_subreg (&SET_SRC (set)); - else if (GET_CODE (SET_SRC (set)) == COMPARE) + + src1 = SET_SRC (set); + src2 = NULL_RTX; + if (GET_CODE (SET_SRC (set)) == COMPARE) { if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG) XEXP (SET_SRC (set), 0) @@ -2319,11 +2365,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG) XEXP (SET_SRC (set), 1) = alter_subreg (&XEXP (SET_SRC (set), 1)); + if (XEXP (SET_SRC (set), 1) + == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0)))) + src2 = XEXP (SET_SRC (set), 0); } if ((cc_status.value1 != 0 - && rtx_equal_p (SET_SRC (set), cc_status.value1)) + && rtx_equal_p (src1, cc_status.value1)) || (cc_status.value2 != 0 - && rtx_equal_p (SET_SRC (set), cc_status.value2))) + && rtx_equal_p (src1, cc_status.value2)) + || (src2 != 0 && cc_status.value1 != 0 + && rtx_equal_p (src2, cc_status.value1)) + || (src2 != 0 && cc_status.value2 != 0 + && rtx_equal_p (src2, cc_status.value2))) { /* Don't delete insn if it has an addressing side-effect. */ if (! FIND_REG_INC_NOTE (insn, NULL_RTX) @@ -2337,9 +2390,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, } } } -#endif -#ifdef HAVE_cc0 /* If this is a conditional branch, maybe modify it if the cc's are in a nonstandard state so that it accomplishes the same thing that it would @@ -2536,10 +2587,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); #endif -#ifdef HAVE_conditional_execution - if (GET_CODE (PATTERN (insn)) == COND_EXEC) + if (targetm.have_conditional_execution () + && GET_CODE (PATTERN (insn)) == COND_EXEC) current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); -#endif #ifdef HAVE_cc0 cc_prev_status = cc_status; @@ -2560,12 +2610,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif /* Find the proper template for this insn. */ - template = get_insn_template (insn_code_number, insn); + templ = get_insn_template (insn_code_number, insn); /* If the C code returns 0, it means that it is a jump insn which follows a deleted test insn, and that test insn needs to be reinserted. */ - if (template == 0) + if (templ == 0) { rtx prev; @@ -2588,12 +2638,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* If the template is the string "#", it means that this insn must be split. */ - if (template[0] == '#' && template[1] == '\0') + if (templ[0] == '#' && templ[1] == '\0') { - rtx new = try_split (body, insn, 0); + rtx new_rtx = try_split (body, insn, 0); /* If we didn't split the insn, go away. */ - if (new == insn && PATTERN (new) == body) + if (new_rtx == insn && PATTERN (new_rtx) == body) fatal_insn ("could not split insn", insn); #ifdef HAVE_ATTR_length @@ -2603,7 +2653,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, gcc_unreachable (); #endif - return new; + return new_rtx; } #ifdef TARGET_UNWIND_INFO @@ -2613,8 +2663,48 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, targetm.asm_out.unwind_emit (asm_out_file, insn); #endif + if (CALL_P (insn)) + { + rtx x = call_from_call_insn (insn); + x = XEXP (x, 0); + if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + tree t; + x = XEXP (x, 0); + t = SYMBOL_REF_DECL (x); + if (t) + assemble_external (t); + } + } + /* Output assembler code from the template. */ - output_asm_insn (template, recog_data.operand); + output_asm_insn (templ, recog_data.operand); + + /* Record point-of-call information for ICF debugging. */ + if (flag_enable_icf_debug && CALL_P (insn)) + { + rtx x = call_from_call_insn (insn); + x = XEXP (x, 0); + if (x && MEM_P (x)) + { + if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + tree t; + x = XEXP (x, 0); + t = SYMBOL_REF_DECL (x); + if (t) + (*debug_hooks->direct_call) (t); + } + else + (*debug_hooks->virtual_call) (INSN_UID (insn)); + } + } + + /* Some target machines need to postscan each insn after + it is output. */ + if (targetm.asm_out.final_postscan_insn) + targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand, + recog_data.n_operands); /* If necessary, report the effect that the instruction has on the unwind info. We've already done this for delay slots @@ -2634,10 +2724,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, return NEXT_INSN (insn); } -/* Return whether a source line note needs to be emitted before INSN. */ +/* Return whether a source line note needs to be emitted before INSN. + Sets IS_STMT to TRUE if the line should be marked as a possible + breakpoint location. */ static bool -notice_source_line (rtx insn) +notice_source_line (rtx insn, bool *is_stmt) { const char *filename; int linenum; @@ -2653,18 +2745,33 @@ notice_source_line (rtx insn) linenum = insn_line (insn); } - if (filename - && (force_source_line - || filename != last_filename - || last_linenum != linenum)) + if (filename == NULL) + return false; + + if (force_source_line + || filename != last_filename + || last_linenum != linenum) { force_source_line = false; last_filename = filename; last_linenum = linenum; + last_discriminator = discriminator; + *is_stmt = true; high_block_linenum = MAX (last_linenum, high_block_linenum); high_function_linenum = MAX (last_linenum, high_function_linenum); return true; } + + if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator) + { + /* If the discriminator changed, but the line number did not, + output the line table entry with is_stmt false so the + debugger does not treat this as a breakpoint location. */ + last_discriminator = discriminator; + *is_stmt = false; + return true; + } + return false; } @@ -2743,11 +2850,11 @@ alter_subreg (rtx *xp) } else { - rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), + rtx new_rtx = simplify_subreg (GET_MODE (x), y, GET_MODE (y), SUBREG_BYTE (x)); - if (new != 0) - *xp = new; + if (new_rtx != 0) + *xp = new_rtx; else if (REG_P (y)) { /* Simplify_subreg can't handle some REG cases, but we have to. */ @@ -3044,7 +3151,7 @@ get_mem_expr_from_op (rtx op, int *paddressp) && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp))) return expr; - while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY + while (UNARY_P (op) || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH) op = XEXP (op, 0); @@ -3101,7 +3208,7 @@ output_asm_operand_names (rtx *operands, int *oporder, int nops) of the operand, with no other punctuation. */ void -output_asm_insn (const char *template, rtx *operands) +output_asm_insn (const char *templ, rtx *operands) { const char *p; int c; @@ -3114,11 +3221,11 @@ output_asm_insn (const char *template, rtx *operands) /* An insn may return a null string template in a case where no assembler code is needed. */ - if (*template == 0) + if (*templ == 0) return; memset (opoutput, 0, sizeof opoutput); - p = template; + p = templ; putc ('\t', asm_out_file); #ifdef ASM_OUTPUT_OPCODE @@ -3247,7 +3354,7 @@ output_asm_insn (const char *template, rtx *operands) } else if (letter == 'n') { - if (GET_CODE (operands[opnum]) == CONST_INT) + if (CONST_INT_P (operands[opnum])) fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, - INTVAL (operands[opnum])); else @@ -3328,6 +3435,40 @@ output_asm_label (rtx x) assemble_name (asm_out_file, buf); } +/* Helper rtx-iteration-function for mark_symbol_refs_as_used and + output_operand. Marks SYMBOL_REFs as referenced through use of + assemble_external. */ + +static int +mark_symbol_ref_as_used (rtx *xp, void *dummy ATTRIBUTE_UNUSED) +{ + rtx x = *xp; + + /* If we have a used symbol, we may have to emit assembly + annotations corresponding to whether the symbol is external, weak + or has non-default visibility. */ + if (GET_CODE (x) == SYMBOL_REF) + { + tree t; + + t = SYMBOL_REF_DECL (x); + if (t) + assemble_external (t); + + return -1; + } + + return 0; +} + +/* Marks SYMBOL_REFs in x as referenced through use of assemble_external. */ + +void +mark_symbol_refs_as_used (rtx x) +{ + for_each_rtx (&x, mark_symbol_ref_as_used, NULL); +} + /* Print operand X using machine-dependent assembler syntax. The macro PRINT_OPERAND is defined just to control this function. CODE is a non-digit that preceded the operand-number in the % spec, @@ -3348,6 +3489,11 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED) gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER); PRINT_OPERAND (asm_out_file, x, code); + + if (x == NULL_RTX) + return; + + for_each_rtx (&x, mark_symbol_ref_as_used, NULL); } /* Print a memory reference operand for address X @@ -3380,7 +3526,10 @@ output_addr_const (FILE *file, rtx x) case SYMBOL_REF: if (SYMBOL_REF_DECL (x)) - mark_decl_referenced (SYMBOL_REF_DECL (x)); + { + mark_decl_referenced (SYMBOL_REF_DECL (x)); + assemble_external (SYMBOL_REF_DECL (x)); + } #ifdef ASM_OUTPUT_SYMBOL_REF ASM_OUTPUT_SYMBOL_REF (file, x); #else @@ -3437,7 +3586,7 @@ output_addr_const (FILE *file, rtx x) case PLUS: /* Some assemblers need integer constants to appear last (eg masm). */ - if (GET_CODE (XEXP (x, 0)) == CONST_INT) + if (CONST_INT_P (XEXP (x, 0))) { output_addr_const (file, XEXP (x, 1)); if (INTVAL (XEXP (x, 0)) >= 0) @@ -3447,7 +3596,7 @@ output_addr_const (FILE *file, rtx x) else { output_addr_const (file, XEXP (x, 0)); - if (GET_CODE (XEXP (x, 1)) != CONST_INT + if (!CONST_INT_P (XEXP (x, 1)) || INTVAL (XEXP (x, 1)) >= 0) fprintf (file, "+"); output_addr_const (file, XEXP (x, 1)); @@ -3463,7 +3612,7 @@ output_addr_const (FILE *file, rtx x) output_addr_const (file, XEXP (x, 0)); fprintf (file, "-"); - if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0) + if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0) || GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) output_addr_const (file, XEXP (x, 1)); @@ -3671,7 +3820,7 @@ asm_fprintf (FILE *file, const char *p, ...) void split_double (rtx value, rtx *first, rtx *second) { - if (GET_CODE (value) == CONST_INT) + if (CONST_INT_P (value)) { if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) { @@ -4062,8 +4211,7 @@ debug_queue_symbol (tree decl) if (symbol_queue_index >= symbol_queue_size) { symbol_queue_size += 10; - symbol_queue = xrealloc (symbol_queue, - symbol_queue_size * sizeof (tree)); + symbol_queue = XRESIZEVEC (tree, symbol_queue, symbol_queue_size); } symbol_queue[symbol_queue_index++] = decl; @@ -4135,8 +4283,13 @@ rest_of_handle_final (void) *will* be routed past here. */ timevar_push (TV_SYMOUT); - (*debug_hooks->function_decl) (current_function_decl); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->function_decl (current_function_decl); timevar_pop (TV_SYMOUT); + + /* Release the blocks that are linked to DECL_INITIAL() to free the memory. */ + DECL_INITIAL (current_function_decl) = error_mark_node; + if (DECL_STATIC_CONSTRUCTOR (current_function_decl) && targetm.have_ctors_dtors) targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0), @@ -4154,7 +4307,7 @@ struct rtl_opt_pass pass_final = { { RTL_PASS, - NULL, /* name */ + "final", /* name */ NULL, /* gate */ rest_of_handle_final, /* execute */ NULL, /* sub */ @@ -4202,6 +4355,43 @@ static unsigned int rest_of_clean_state (void) { rtx insn, next; + FILE *final_output = NULL; + int save_unnumbered = flag_dump_unnumbered; + int save_noaddr = flag_dump_noaddr; + + if (flag_dump_final_insns) + { + final_output = fopen (flag_dump_final_insns, "a"); + if (!final_output) + { + error ("could not open final insn dump file %qs: %s", + flag_dump_final_insns, strerror (errno)); + flag_dump_final_insns = NULL; + } + else + { + const char *aname; + + aname = (IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (current_function_decl))); + fprintf (final_output, "\n;; Function (%s) %s\n\n", aname, + cfun->function_frequency == FUNCTION_FREQUENCY_HOT + ? " (hot)" + : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED + ? " (unlikely executed)" + : ""); + + flag_dump_noaddr = flag_dump_unnumbered = 1; + if (flag_compare_debug_opt || flag_compare_debug) + dump_flags |= TDF_NOUID; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (LABEL_P (insn)) + INSN_UID (insn) = CODE_LABEL_NUMBER (insn); + else + INSN_UID (insn) = 0; + } + } /* It is very important to decompose the RTL instruction chain here: debug information keeps pointing into CODE_LABEL insns inside the function @@ -4212,6 +4402,28 @@ rest_of_clean_state (void) next = NEXT_INSN (insn); NEXT_INSN (insn) = NULL; PREV_INSN (insn) = NULL; + + if (final_output + && (!NOTE_P (insn) || + (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION + && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG + && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END + && NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE))) + print_rtl_single (final_output, insn); + + } + + if (final_output) + { + flag_dump_noaddr = save_noaddr; + flag_dump_unnumbered = save_unnumbered; + + if (fclose (final_output)) + { + error ("could not close final insn dump file %qs: %s", + flag_dump_final_insns, strerror (errno)); + flag_dump_final_insns = NULL; + } } /* In case the function was not output, @@ -4222,6 +4434,7 @@ rest_of_clean_state (void) sdbout_types (NULL_TREE); #endif + flag_rerun_cse_after_global_opts = 0; reload_completed = 0; epilogue_completed = 0; #ifdef STACK_REGS @@ -4237,9 +4450,11 @@ rest_of_clean_state (void) free_bb_for_insn (); + delete_tree_ssa (); + if (targetm.binds_local_p (current_function_decl)) { - int pref = crtl->preferred_stack_boundary; + unsigned int pref = crtl->preferred_stack_boundary; if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary) pref = crtl->stack_alignment_needed; cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary @@ -4266,7 +4481,7 @@ struct rtl_opt_pass pass_clean_state = { { RTL_PASS, - NULL, /* name */ + "*clean_state", /* name */ NULL, /* gate */ rest_of_clean_state, /* execute */ NULL, /* sub */ @@ -4280,4 +4495,3 @@ struct rtl_opt_pass pass_clean_state = 0 /* todo_flags_finish */ } }; -