X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ffinal.c;h=0d19562acbf0742c7a8e6193a4e706b7e9411dc7;hb=9d33046c199ad03cc0ba1210be7bcfbbcb136254;hp=5b7ac3cb5bfb6f28b945abe456a2c2e8b3566d0e;hpb=380c66974cee2bb4a5281c8c11f3632bb21118e5;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/final.c b/gcc/final.c index 5b7ac3cb5bf..0d19562acbf 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1,13 +1,13 @@ /* Convert RTL to assembler code and output it, for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This is the final pass of the compiler. It looks at the rtl code for a function and outputs assembler code. @@ -72,6 +71,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "debug.h" #include "expr.h" #include "cfglayout.h" +#include "tree-pass.h" +#include "tree-flow.h" +#include "timevar.h" +#include "cgraph.h" +#include "coverage.h" +#include "df.h" +#include "vecprim.h" +#include "ggc.h" +#include "cfgloop.h" +#include "params.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -86,6 +95,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "dbxout.h" #endif +#ifdef SDB_DEBUGGING_INFO +#include "sdbout.h" +#endif + /* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a null default for it to save conditionalization later. */ #ifndef CC_STATUS_INIT @@ -99,19 +112,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Is the given character a logical line separator for the assembler? */ #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR -#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') +#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';') #endif #ifndef JUMP_TABLES_IN_TEXT_SECTION #define JUMP_TABLES_IN_TEXT_SECTION 0 #endif -#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP) -#define HAVE_READONLY_DATA_SECTION 1 -#else -#define HAVE_READONLY_DATA_SECTION 0 -#endif - /* Bitflags used by final_scan_insn. */ #define SEEN_BB 1 #define SEEN_NOTE 2 @@ -124,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; @@ -133,7 +146,14 @@ static int high_function_linenum; /* Filename of last NOTE. */ static const char *last_filename; -extern int length_unit_log; /* This is defined in insn-attrtab.c. */ +/* Override filename and line number. */ +static const char *override_filename; +static int override_linenum; + +/* Whether to force emission of a line note before the next insn. */ +static bool force_source_line = false; + +extern const int length_unit_log; /* This is defined in insn-attrtab.c. */ /* Nonzero while outputting an `asm' with operands. This means that inconsistencies are the user's fault, so don't die. @@ -165,29 +185,6 @@ CC_STATUS cc_status; CC_STATUS cc_prev_status; #endif -/* Indexed by hardware reg number, is 1 if that register is ever - used in the current function. - - In life_analysis, or in stupid_life_analysis, this is set - up to record the hard regs used explicitly. Reload adds - in the hard regs used for holding pseudo regs. Final uses - it to generate the code in the function prologue and epilogue - to save and restore registers as needed. */ - -char regs_ever_live[FIRST_PSEUDO_REGISTER]; - -/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm. - Unlike regs_ever_live, elements of this array corresponding to - eliminable regs like the frame pointer are set if an asm sets them. */ - -char regs_asm_clobbered[FIRST_PSEUDO_REGISTER]; - -/* 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; @@ -207,18 +204,16 @@ 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 rtx walk_alter_subreg (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); static tree get_mem_expr_from_op (rtx, int *); @@ -315,7 +310,7 @@ dbr_sequence_length (void) static int *insn_lengths; -varray_type insn_addresses_; +VEC(int,heap) *insn_addresses_; /* Max uid for which the above arrays are valid. */ static int insn_lengths_max_uid; @@ -375,10 +370,11 @@ init_insn_lengths (void) } /* Obtain the current length of an insn. If branch shortening has been done, - get its actual length. Otherwise, get its maximum length. */ - -int -get_attr_length (rtx insn ATTRIBUTE_UNUSED) + get its actual length. Otherwise, use FALLBACK_FN to calculate the + length. */ +static inline int +get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, + int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED) { #ifdef HAVE_ATTR_length rtx body; @@ -393,10 +389,11 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED) case NOTE: case BARRIER: case CODE_LABEL: + case DEBUG_INSN: return 0; case CALL_INSN: - length = insn_default_length (insn); + length = fallback_fn (insn); break; case JUMP_INSN: @@ -407,7 +404,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED) ADDR_VEC_ALIGN. */ } else - length = insn_default_length (insn); + length = fallback_fn (insn); break; case INSN: @@ -416,12 +413,12 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED) return 0; else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) - length = asm_insn_count (body) * insn_default_length (insn); + length = asm_insn_count (body) * fallback_fn (insn); else if (GET_CODE (body) == SEQUENCE) for (i = 0; i < XVECLEN (body, 0); i++) - length += get_attr_length (XVECEXP (body, 0, i)); + length += get_attr_length_1 (XVECEXP (body, 0, i), fallback_fn); else - length = insn_default_length (insn); + length = fallback_fn (insn); break; default: @@ -434,8 +431,26 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED) return length; #else /* not HAVE_ATTR_length */ return 0; +#define insn_default_length 0 +#define insn_min_length 0 #endif /* not HAVE_ATTR_length */ } + +/* Obtain the current length of an insn. If branch shortening has been done, + get its actual length. Otherwise, get its maximum length. */ +int +get_attr_length (rtx insn) +{ + return get_attr_length_1 (insn, insn_default_length); +} + +/* Obtain the current length of an insn. If branch shortening has been done, + get its actual length. Otherwise, get its minimum length. */ +int +get_attr_min_length (rtx insn) +{ + return get_attr_length_1 (insn, insn_min_length); +} /* Code to handle alignment inside shorten_branches. */ @@ -544,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 @@ -652,11 +677,16 @@ insn_current_reference_address (rtx branch) } #endif /* HAVE_ATTR_length */ -void +/* Compute branch alignments based on frequency information in the + CFG. */ + +unsigned int compute_alignments (void) { int log, max_skip, max_log; basic_block bb; + int freq_max = 0; + int freq_threshold = 0; if (label_align) { @@ -666,13 +696,25 @@ compute_alignments (void) max_labelno = max_label_num (); min_labelno = get_first_label_num (); - label_align = xcalloc (max_labelno - min_labelno + 1, - sizeof (struct label_alignment)); + label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1); /* If not optimizing or optimizing for size, don't assign any alignments. */ - if (! optimize || optimize_size) - return; + if (! optimize || optimize_function_for_size_p (cfun)) + return 0; + if (dump_file) + { + dump_flow_info (dump_file, TDF_DETAILS); + flow_loops_dump (dump_file, NULL, 1); + loop_optimizer_init (AVOID_CFG_MODIFICATIONS); + } + FOR_EACH_BB (bb) + if (bb->frequency > freq_max) + freq_max = bb->frequency; + freq_threshold = freq_max / PARAM_VALUE (PARAM_ALIGN_THRESHOLD); + + if (dump_file) + fprintf(dump_file, "freq_max: %i\n",freq_max); FOR_EACH_BB (bb) { rtx label = BB_HEAD (bb); @@ -681,8 +723,13 @@ compute_alignments (void) edge_iterator ei; if (!LABEL_P (label) - || probably_never_executed_bb_p (bb)) - continue; + || optimize_bb_for_size_p (bb)) + { + if (dump_file) + fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n", + bb->index, bb->frequency, bb->loop_father->num, bb->loop_depth); + continue; + } max_log = LABEL_ALIGN (label); max_skip = LABEL_ALIGN_MAX_SKIP; @@ -693,6 +740,18 @@ compute_alignments (void) else branch_frequency += EDGE_FREQUENCY (e); } + if (dump_file) + { + fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i fall %4i branch %4i", + bb->index, bb->frequency, bb->loop_father->num, + bb->loop_depth, + fallthru_frequency, branch_frequency); + if (!bb->loop_father->inner && bb->loop_father->num) + fprintf (dump_file, " inner_loop"); + if (bb->loop_father->header == bb) + fprintf (dump_file, " loop_header"); + fprintf (dump_file, "\n"); + } /* There are two purposes to align block with no fallthru incoming edge: 1) to avoid fetch stalls when branch destination is near cache boundary @@ -705,12 +764,14 @@ compute_alignments (void) when function is called. */ if (!has_fallthru - && (branch_frequency > BB_FREQ_MAX / 10 + && (branch_frequency > freq_threshold || (bb->frequency > bb->prev_bb->frequency * 10 && (bb->prev_bb->frequency <= ENTRY_BLOCK_PTR->frequency / 2)))) { log = JUMP_ALIGN (label); + if (dump_file) + fprintf(dump_file, " jump alignment added.\n"); if (max_log < log) { max_log = log; @@ -720,11 +781,14 @@ 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) - && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10 - && branch_frequency > fallthru_frequency * 2) + && optimize_bb_for_speed_p (bb) + && branch_frequency + fallthru_frequency > freq_threshold + && (branch_frequency + > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS))) { log = LOOP_ALIGN (label); + if (dump_file) + fprintf(dump_file, " internal loop alignment added.\n"); if (max_log < log) { max_log = log; @@ -734,7 +798,35 @@ compute_alignments (void) LABEL_TO_ALIGNMENT (label) = max_log; LABEL_TO_MAX_SKIP (label) = max_skip; } + + if (dump_file) + { + loop_optimizer_finalize (); + free_dominance_info (CDI_DOMINATORS); + } + return 0; } + +struct rtl_opt_pass pass_compute_alignments = +{ + { + RTL_PASS, + "alignments", /* name */ + NULL, /* gate */ + compute_alignments, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_rtl_sharing + | TODO_ggc_collect /* todo_flags_finish */ + } +}; + /* Make a pass over all insns and compute their actual lengths by shortening any branches of variable length if possible. */ @@ -771,8 +863,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) /* Free uid_shuid before reallocating it. */ free (uid_shuid); - - uid_shuid = xmalloc (max_uid * sizeof *uid_shuid); + + uid_shuid = XNEWVEC (int, max_uid); if (max_labelno != max_label_num ()) { @@ -785,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. */ @@ -811,16 +902,12 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_SHUID (insn) = i++; if (INSN_P (insn)) - { - /* reorg might make the first insn of a loop being run once only, - and delete the label in front of it. Then we want to apply - the loop alignment to the new label created by reorg, which - is separated by the former loop start insn from the - NOTE_INSN_LOOP_BEG. */ - } - else if (LABEL_P (insn)) + continue; + + if (LABEL_P (insn)) { rtx next; + bool next_is_jumptable; /* Merge in alignments computed by compute_alignments. */ log = LABEL_TO_ALIGNMENT (insn); @@ -830,30 +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 || !HAVE_READONLY_DATA_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; @@ -880,20 +967,20 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) #ifdef HAVE_ATTR_length /* Allocate the rest of the arrays. */ - insn_lengths = xmalloc (max_uid * sizeof (*insn_lengths)); + insn_lengths = XNEWVEC (int, max_uid); insn_lengths_max_uid = max_uid; /* Syntax errors can lead to labels being outside of the main insn stream. Initialize insn_addresses, so that we get reproducible results. */ INSN_ADDRESSES_ALLOC (max_uid); - varying_length = xcalloc (max_uid, sizeof (char)); + varying_length = XCNEWVEC (char, max_uid); /* Initialize uid_align. We scan instructions from end to start, and keep in align_tab[n] the last seen insn that does an alignment of at least n+1, i.e. the successor in the alignment chain for an insn that does / has a known alignment of n. */ - uid_align = xcalloc (max_uid, sizeof *uid_align); + uid_align = XCNEWVEC (rtx, max_uid); for (i = MAX_CODE_ALIGN; --i >= 0;) align_tab[i] = NULL_RTX; @@ -992,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; @@ -1002,7 +1089,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) { /* This only takes room if read-only data goes into the text section. */ - if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) + if (JUMP_TABLES_IN_TEXT_SECTION + || readonly_data_section == text_section) insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC) * GET_MODE_SIZE (GET_MODE (body))); @@ -1203,7 +1291,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, max_addr - rel_addr, body)); - if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) + if (JUMP_TABLES_IN_TEXT_SECTION + || readonly_data_section == text_section) { insn_lengths[uid] = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); @@ -1307,22 +1396,115 @@ 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); + templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); - for (; *template; template++) - if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n') + return asm_str_count (templ); +} +#endif + +/* 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 + names at compile time to those to be embedded in debug + information. */ +typedef struct debug_prefix_map +{ + const char *old_prefix; + const char *new_prefix; + size_t old_len; + size_t new_len; + struct debug_prefix_map *next; +} debug_prefix_map; + +/* Linked list of such structures. */ +debug_prefix_map *debug_prefix_maps; + + +/* Record a debug file prefix mapping. ARG is the argument to + -fdebug-prefix-map and must be of the form OLD=NEW. */ + +void +add_debug_prefix_map (const char *arg) +{ + debug_prefix_map *map; + const char *p; + + p = strchr (arg, '='); + if (!p) + { + error ("invalid argument %qs to -fdebug-prefix-map", arg); + return; + } + map = XNEW (debug_prefix_map); + map->old_prefix = xstrndup (arg, p - arg); + map->old_len = p - arg; + p++; + map->new_prefix = xstrdup (p); + map->new_len = strlen (p); + map->next = debug_prefix_maps; + debug_prefix_maps = map; +} + +/* Perform user-specified mapping of debug filename prefixes. Return + the new name corresponding to FILENAME. */ + +const char * +remap_debug_filename (const char *filename) +{ + debug_prefix_map *map; + char *s; + const char *name; + size_t name_len; + + for (map = debug_prefix_maps; map; map = map->next) + if (strncmp (filename, map->old_prefix, map->old_len) == 0) + break; + if (!map) + return filename; + name = filename + map->old_len; + name_len = strlen (name) + 1; + s = (char *) alloca (name_len + map->new_len); + memcpy (s, map->new_prefix, map->new_len); + memcpy (s + map->new_len, name, name_len); + 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 @@ -1343,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 @@ -1361,7 +1545,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, /* The Sun386i and perhaps other machines don't work right if the profiling code comes after the prologue. */ #ifdef PROFILE_BEFORE_PROLOGUE - if (current_function_profile) + if (crtl->profile) profile_function (file); #endif /* PROFILE_BEFORE_PROLOGUE */ @@ -1374,7 +1558,6 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, function. */ if (write_symbols) { - remove_unnecessary_notes (); reemit_insn_block_notes (); number_blocks (current_function_decl); /* We never actually put out begin/end notes for the top-level @@ -1383,6 +1566,15 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; } + if (warn_frame_larger_than + && get_frame_size () > frame_larger_than_size) + { + /* Issue a warning */ + warning (OPT_Wframe_larger_than_, + "the frame size of %wd bytes is larger than %wd bytes", + get_frame_size (), frame_larger_than_size); + } + /* First output the function prologue: code to set up the stack frame. */ targetm.asm_out.function_prologue (file, get_frame_size ()); @@ -1398,7 +1590,7 @@ static void profile_after_prologue (FILE *file ATTRIBUTE_UNUSED) { #ifndef PROFILE_BEFORE_PROLOGUE - if (current_function_profile) + if (crtl->profile) profile_function (file); #endif /* not PROFILE_BEFORE_PROLOGUE */ } @@ -1409,59 +1601,41 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) #ifndef NO_PROFILE_COUNTERS # define NO_PROFILE_COUNTERS 0 #endif -#if defined(ASM_OUTPUT_REG_PUSH) - int sval = current_function_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) { int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); - data_section (); + switch_to_section (data_section); ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no); assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); } - current_function_section (current_function_decl); + switch_to_section (current_function_section ()); -#if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) - 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 } @@ -1474,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 @@ -1502,33 +1678,6 @@ final (rtx first, FILE *file, int optimize) last_ignored_compare = 0; -#ifdef SDB_DEBUGGING_INFO - /* When producing SDB debugging info, delete troublesome line number - notes from inlined functions in other files as well as duplicate - line number notes. */ - if (write_symbols == SDB_DEBUG) - { - rtx last = 0; - for (insn = first; insn; insn = NEXT_INSN (insn)) - if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) - { - if (last != 0 -#ifdef USE_MAPPED_LOCATION - && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last) -#else - && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) - && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last) -#endif - ) - { - delete_insn (insn); /* Use delete_note. */ - continue; - } - last = insn; - } - } -#endif - for (insn = first; insn; insn = NEXT_INSN (insn)) { if (INSN_UID (insn) > max_uid) /* Find largest UID. */ @@ -1552,7 +1701,7 @@ final (rtx first, FILE *file, int optimize) CC_STATUS_INIT; /* Output the insns. */ - for (insn = NEXT_INSN (first); insn;) + for (insn = first; insn;) { #ifdef HAVE_ATTR_length if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ()) @@ -1619,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. @@ -1652,37 +1829,25 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, switch (GET_CODE (insn)) { case NOTE: - switch (NOTE_LINE_NUMBER (insn)) + switch (NOTE_KIND (insn)) { case NOTE_INSN_DELETED: - case NOTE_INSN_LOOP_BEG: - case NOTE_INSN_LOOP_END: - case NOTE_INSN_FUNCTION_END: - case NOTE_INSN_REPEATED_LINE_NUMBER: - case NOTE_INSN_EXPECTED_VALUE: break; case NOTE_INSN_SWITCH_TEXT_SECTIONS: - - /* The presence of this note indicates that this basic block - belongs in the "cold" section of the .o file. If we are - not already writing to the cold section we need to change - to it. */ - - if (last_text_section == in_text) - { - (*debug_hooks->switch_text_section) (); - unlikely_text_section (); - } + in_cold_section_p = !in_cold_section_p; +#ifdef DWARF2_UNWIND_INFO + if (dwarf2out_do_frame ()) + dwarf2out_switch_text_section (); else - { - (*debug_hooks->switch_text_section) (); - text_section (); - } +#endif + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->switch_text_section (); + + switch_to_section (current_function_section ()); break; - + case NOTE_INSN_BASIC_BLOCK: - #ifdef TARGET_UNWIND_INFO targetm.asm_out.unwind_emit (asm_out_file, insn); #endif @@ -1694,11 +1859,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB) { *seen |= SEEN_EMITTED; - last_filename = NULL; + force_source_line = true; } else *seen |= SEEN_BB; + discriminator = NOTE_BASIC_BLOCK (insn)->discriminator; + break; case NOTE_INSN_EH_REGION_BEG: @@ -1718,7 +1885,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) { *seen |= SEEN_EMITTED; - last_filename = NULL; + force_source_line = true; } else *seen |= SEEN_NOTE; @@ -1726,17 +1893,28 @@ 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) { *seen |= SEEN_EMITTED; - last_filename = NULL; + force_source_line = true; } else *seen |= SEEN_NOTE; @@ -1757,11 +1935,24 @@ 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; } + if (write_symbols == DBX_DEBUG + || write_symbols == SDB_DEBUG) + { + location_t *locus_ptr + = block_nonartificial_location (NOTE_BLOCK (insn)); + + if (locus_ptr != NULL) + { + override_filename = LOCATION_FILE (*locus_ptr); + override_linenum = LOCATION_LINE (*locus_ptr); + } + } break; case NOTE_INSN_BLOCK_END: @@ -1779,7 +1970,26 @@ 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) + { + tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn)); + location_t *locus_ptr + = block_nonartificial_location (outer_block); + + if (locus_ptr != NULL) + { + override_filename = LOCATION_FILE (*locus_ptr); + override_linenum = LOCATION_LINE (*locus_ptr); + } + else + { + override_filename = NULL; + override_linenum = 0; + } } break; @@ -1791,14 +2001,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_VAR_LOCATION: - (*debug_hooks->var_location) (insn); - break; - - case 0: + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); break; default: - gcc_assert (NOTE_LINE_NUMBER (insn) > 0); + gcc_unreachable (); break; } break; @@ -1835,83 +2043,49 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, } #ifdef HAVE_cc0 CC_STATUS_INIT; - /* If this label is reached from only one place, set the condition - codes from the instruction just before the branch. */ - - /* Disabled because some insns set cc_status in the C output code - and NOTICE_UPDATE_CC alone can set incorrect status. */ - if (0 /* optimize && LABEL_NUSES (insn) == 1*/) - { - rtx jump = LABEL_REFS (insn); - rtx barrier = prev_nonnote_insn (insn); - rtx prev; - /* If the LABEL_REFS field of this label has been set to point - at a branch, the predecessor of the branch is a regular - insn, and that branch is the only way to reach this label, - set the condition codes based on the branch and its - predecessor. */ - if (barrier && BARRIER_P (barrier) - && jump && JUMP_P (jump) - && (prev = prev_nonnote_insn (jump)) - && NONJUMP_INSN_P (prev)) - { - NOTICE_UPDATE_CC (PATTERN (prev), prev); - NOTICE_UPDATE_CC (PATTERN (jump), jump); - } - } #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; - 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 - current_function_section (current_function_decl); + 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); @@ -1923,7 +2097,11 @@ 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; + + /* Reset this early so it is correct for ASM statements. */ + current_insn_predicate = NULL_RTX; /* An INSN, JUMP_INSN or CALL_INSN. First check for special kinds that recog doesn't recognize. */ @@ -1958,15 +2136,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif if (! JUMP_TABLES_IN_TEXT_SECTION) - targetm.asm_out.function_rodata_section (current_function_decl); + switch_to_section (targetm.asm_out.function_rodata_section + (current_function_decl)); else - current_function_section (current_function_decl); + switch_to_section (current_function_section ()); - if (app_on) - { - 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) @@ -2018,16 +2193,16 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif #endif - current_function_section (current_function_decl); + switch_to_section (current_function_section ()); break; } /* 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) { @@ -2038,12 +2213,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if (string[0]) { - if (! app_on) - { - fputs (ASM_APP_ON, file); - app_on = 1; - } + expanded_location loc; + + app_enable (); + loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body)); + if (*loc.file && loc.line) + fprintf (asm_out_file, "%s %i \"%s\" 1\n", + ASM_COMMENT_START, loc.line, loc.file); fprintf (asm_out_file, "\t%s\n", string); +#if HAVE_AS_LINE_ZERO + if (*loc.file && loc.line) + fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START); +#endif } break; } @@ -2052,17 +2233,20 @@ 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; /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; /* Get out the operand values. */ - string = decode_asm_operands (body, ops, NULL, NULL, NULL); - /* Inhibit dieing on what would otherwise be compiler bugs. */ + string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc); + /* Inhibit dying on what would otherwise be compiler bugs. */ insn_noperands = noperands; this_is_asm_operands = insn; + expanded = expand_location (loc); #ifdef FINAL_PRESCAN_INSN FINAL_PRESCAN_INSN (insn, ops, insn_noperands); @@ -2071,23 +2255,26 @@ 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); output_asm_insn (string, ops); +#if HAVE_AS_LINE_ZERO + if (expanded.file && expanded.line) + fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START); +#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) { @@ -2164,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) @@ -2174,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) @@ -2192,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 @@ -2238,6 +2434,41 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, INSN_CODE (insn) = -1; } + /* If this is a conditional trap, maybe modify it if the cc's + are in a nonstandard state so that it accomplishes the same + thing that it would do straightforwardly if the cc's were + set up normally. */ + if (cc_status.flags != 0 + && NONJUMP_INSN_P (insn) + && GET_CODE (body) == TRAP_IF + && COMPARISON_P (TRAP_CONDITION (body)) + && XEXP (TRAP_CONDITION (body), 0) == cc0_rtx) + { + /* This function may alter the contents of its argument + and clear some of the cc_status.flags bits. + It may also return 1 meaning condition now always true + or -1 meaning condition now always false + or 2 meaning condition nontrivial but altered. */ + int result = alter_cond (TRAP_CONDITION (body)); + + /* If TRAP_CONDITION has become always false, delete the + instruction. */ + if (result == -1) + { + delete_insn (insn); + break; + } + + /* If TRAP_CONDITION has become always true, replace + TRAP_CONDITION with const_true_rtx. */ + if (result == 1) + TRAP_CONDITION (body) = const_true_rtx; + + /* Rerecognize the instruction if it has changed. */ + if (result != 0) + INSN_CODE (insn) = -1; + } + /* Make same adjustments to instructions that examine the condition codes without jumping and instructions that handle conditional moves (if this machine has either one). */ @@ -2356,12 +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)); - else - current_insn_predicate = NULL_RTX; -#endif #ifdef HAVE_cc0 cc_prev_status = cc_status; @@ -2382,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; @@ -2410,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 @@ -2425,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 @@ -2435,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 @@ -2456,23 +2724,54 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, return NEXT_INSN (insn); } -/* Output debugging info to the assembler file FILE - based on the NOTE-insn INSN, assumed to be a line number. */ +/* Return whether a source line note needs to be emitted before INSN. + 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 = insn_file (insn); - int linenum = insn_line (insn); + const char *filename; + int linenum; + + if (override_filename) + { + filename = override_filename; + linenum = override_linenum; + } + else + { + filename = insn_file (insn); + linenum = insn_line (insn); + } + + if (filename == NULL) + return false; - if (filename && (filename != last_filename || last_linenum != linenum)) + 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; } @@ -2483,6 +2782,7 @@ void cleanup_subreg_operands (rtx insn) { int i; + bool changed = false; extract_insn_cached (insn); for (i = 0; i < recog_data.n_operands; i++) { @@ -2492,22 +2792,30 @@ cleanup_subreg_operands (rtx insn) matches the else clause. Instead we test the underlying expression directly. */ if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG) - recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); + { + recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); + changed = true; + } else if (GET_CODE (recog_data.operand[i]) == PLUS || GET_CODE (recog_data.operand[i]) == MULT || MEM_P (recog_data.operand[i])) - recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); + recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i], &changed); } for (i = 0; i < recog_data.n_dups; i++) { if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG) - *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); + { + *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); + changed = true; + } else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS || GET_CODE (*recog_data.dup_loc[i]) == MULT || MEM_P (*recog_data.dup_loc[i])) - *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); + *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i], &changed); } + if (changed) + df_insn_rescan (insn); } /* If X is a SUBREG, replace it with a REG or a MEM, @@ -2542,16 +2850,23 @@ 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. */ - unsigned int regno = subreg_regno (x); - *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x)); + unsigned int regno; + HOST_WIDE_INT offset; + + regno = subreg_regno (x); + if (subreg_lowpart_p (x)) + offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y)); + else + offset = SUBREG_BYTE (x); + *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, offset); } } @@ -2561,7 +2876,7 @@ alter_subreg (rtx *xp) /* Do alter_subreg on all the SUBREGs contained in X. */ static rtx -walk_alter_subreg (rtx *xp) +walk_alter_subreg (rtx *xp, bool *changed) { rtx x = *xp; switch (GET_CODE (x)) @@ -2569,16 +2884,17 @@ walk_alter_subreg (rtx *xp) case PLUS: case MULT: case AND: - XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); - XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); + XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed); + XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1), changed); break; case MEM: case ZERO_EXTEND: - XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); + XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed); break; case SUBREG: + *changed = true; return alter_subreg (xp); default: @@ -2835,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); @@ -2892,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; @@ -2905,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 @@ -3017,7 +3333,7 @@ output_asm_insn (const char *template, rtx *operands) int letter = *p++; unsigned long opnum; char *endptr; - + opnum = strtoul (p, &endptr, 10); if (endptr == p) @@ -3038,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 @@ -3062,7 +3378,7 @@ output_asm_insn (const char *template, rtx *operands) { unsigned long opnum; char *endptr; - + opnum = strtoul (p, &endptr, 10); if (this_is_asm_operands && opnum >= insn_noperands) output_operand_lossage ("operand number out of range"); @@ -3111,7 +3427,7 @@ output_asm_label (rtx x) x = XEXP (x, 0); if (LABEL_P (x) || (NOTE_P (x) - && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) + && NOTE_KIND (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"); @@ -3119,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, @@ -3139,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 @@ -3148,7 +3503,8 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED) void output_address (rtx x) { - walk_alter_subreg (&x); + bool changed = false; + walk_alter_subreg (&x, &changed); PRINT_OPERAND_ADDRESS (asm_out_file, x); } @@ -3170,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 @@ -3206,9 +3565,11 @@ output_addr_const (FILE *file, rtx x) /* We can use %d if the number is one word and positive. */ if (CONST_DOUBLE_HIGH (x)) fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, - CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); + (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x), + (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); else if (CONST_DOUBLE_LOW (x) < 0) - fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); else fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); } @@ -3218,9 +3579,14 @@ output_addr_const (FILE *file, rtx x) output_operand_lossage ("floating constant misused"); break; + case CONST_FIXED: + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + (unsigned HOST_WIDE_INT) CONST_FIXED_VALUE_LOW (x)); + break; + 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) @@ -3230,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)); @@ -3246,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)); @@ -3261,6 +3627,7 @@ output_addr_const (FILE *file, rtx x) case ZERO_EXTEND: case SIGN_EXTEND: case SUBREG: + case TRUNCATE: output_addr_const (file, XEXP (x, 0)); break; @@ -3453,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)) { @@ -3595,7 +3962,7 @@ leaf_function_p (void) rtx insn; rtx link; - if (current_function_profile || profile_arc_flag) + if (crtl->profile || profile_arc_flag) return 0; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) @@ -3609,7 +3976,7 @@ leaf_function_p (void) && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } - for (link = current_function_epilogue_delay_list; + for (link = crtl->epilogue_delay_list; link; link = XEXP (link, 1)) { @@ -3636,7 +4003,7 @@ int final_forward_branch_p (rtx insn) { int insn_id, label_id; - + gcc_assert (uid_shuid); insn_id = INSN_SHUID (insn); label_id = INSN_SHUID (JUMP_LABEL (insn)); @@ -3666,11 +4033,11 @@ only_leaf_regs_used (void) const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if ((regs_ever_live[i] || global_regs[i]) + if ((df_regs_ever_live_p (i) || global_regs[i]) && ! permitted_reg_in_leaf_functions[i]) return 0; - if (current_function_uses_pic_offset_table + if (crtl->uses_pic_offset_table && pic_offset_table_rtx != 0 && REG_P (pic_offset_table_rtx) && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) @@ -3693,7 +4060,7 @@ leaf_renumber_regs (rtx first) for (insn = first; insn; insn = NEXT_INSN (insn)) if (INSN_P (insn)) leaf_renumber_regs_insn (PATTERN (insn)); - for (insn = current_function_epilogue_delay_list; + for (insn = crtl->epilogue_delay_list; insn; insn = XEXP (insn, 1)) if (INSN_P (XEXP (insn, 0))) @@ -3734,9 +4101,9 @@ leaf_renumber_regs_insn (rtx in_rtx) } newreg = LEAF_REG_REMAP (newreg); gcc_assert (newreg >= 0); - regs_ever_live[REGNO (in_rtx)] = 0; - regs_ever_live[newreg] = 1; - REGNO (in_rtx) = newreg; + df_set_regs_ever_live (REGNO (in_rtx), false); + df_set_regs_ever_live (newreg, true); + SET_REGNO (in_rtx, newreg); in_rtx->used = 1; } @@ -3812,7 +4179,7 @@ debug_flush_symbol_queue (void) for (i = 0; i < symbol_queue_index; ++i) { - /* If we pushed queued symbols then such symbols are must be + /* If we pushed queued symbols then such symbols must be output no matter what anyone else says. Specifically, we need to make sure dbxout_symbol() thinks the symbol was used and also we need to override TYPE_DECL_SUPPRESS_DEBUG @@ -3844,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; @@ -3862,3 +4228,270 @@ debug_free_queue (void) symbol_queue_size = 0; } } + +/* Turn the RTL into assembly. */ +static unsigned int +rest_of_handle_final (void) +{ + rtx x; + const char *fnname; + + /* Get the function's name, as described by its RTL. This may be + different from the DECL_NAME name used in the source file. */ + + x = DECL_RTL (current_function_decl); + gcc_assert (MEM_P (x)); + x = XEXP (x, 0); + gcc_assert (GET_CODE (x) == SYMBOL_REF); + fnname = XSTR (x, 0); + + assemble_start_function (current_function_decl, fnname); + final_start_function (get_insns (), asm_out_file, optimize); + final (get_insns (), asm_out_file, optimize); + final_end_function (); + +#ifdef TARGET_UNWIND_INFO + /* ??? The IA-64 ".handlerdata" directive must be issued before + the ".endp" directive that closes the procedure descriptor. */ + output_function_exception_table (fnname); +#endif + + assemble_end_function (current_function_decl, fnname); + +#ifndef TARGET_UNWIND_INFO + /* Otherwise, it feels unclean to switch sections in the middle. */ + output_function_exception_table (fnname); +#endif + + user_defined_section_attribute = false; + + /* Free up reg info memory. */ + free_reg_info (); + + if (! quiet_flag) + fflush (asm_out_file); + + /* 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); + 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), + decl_init_priority_lookup + (current_function_decl)); + if (DECL_STATIC_DESTRUCTOR (current_function_decl) + && targetm.have_ctors_dtors) + targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0), + decl_fini_priority_lookup + (current_function_decl)); + return 0; +} + +struct rtl_opt_pass pass_final = +{ + { + RTL_PASS, + "final", /* name */ + NULL, /* gate */ + rest_of_handle_final, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_FINAL, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_ggc_collect /* todo_flags_finish */ + } +}; + + +static unsigned int +rest_of_handle_shorten_branches (void) +{ + /* Shorten branches. */ + shorten_branches (get_insns ()); + return 0; +} + +struct rtl_opt_pass pass_shorten_branches = +{ + { + RTL_PASS, + "shorten", /* name */ + NULL, /* gate */ + rest_of_handle_shorten_branches, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_FINAL, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + } +}; + + +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 + body. If these remain pointing to the other insns, we end up preserving + whole RTL chain and attached detailed debug info in memory. */ + for (insn = get_insns (); insn; insn = next) + { + next = NEXT_INSN (insn); + NEXT_INSN (insn) = NULL; + PREV_INSN (insn) = NULL; + + 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, + 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 + + flag_rerun_cse_after_global_opts = 0; + reload_completed = 0; + epilogue_completed = 0; +#ifdef STACK_REGS + regstack_completed = 0; +#endif + + /* Clear out the insn_length contents now that they are no + longer valid. */ + init_insn_lengths (); + + /* Show no temporary slots allocated. */ + init_temp_slots (); + + free_bb_for_insn (); + + delete_tree_ssa (); + + if (targetm.binds_local_p (current_function_decl)) + { + 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 + = pref; + } + + /* Make sure volatile mem refs aren't considered valid operands for + arithmetic insns. We must call this here if this is a nested inline + function, since the above code leaves us in the init_recog state, + and the function context push/pop code does not save/restore volatile_ok. + + ??? Maybe it isn't necessary for expand_start_function to call this + anymore if we do it here? */ + + init_recog_no_volatile (); + + /* We're done with this function. Free up memory if we can. */ + free_after_parsing (cfun); + free_after_compilation (cfun); + return 0; +} + +struct rtl_opt_pass pass_clean_state = +{ + { + RTL_PASS, + "*clean_state", /* name */ + NULL, /* gate */ + rest_of_clean_state, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_FINAL, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + PROP_rtl, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +};