diff options
author | kan <kan@FreeBSD.org> | 2007-05-19 02:12:21 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2007-05-19 02:12:21 +0000 |
commit | cadd557b2c028e9d17846ceb76b7abe3b967db5d (patch) | |
tree | b4d827b7febdefd02ed5f510413d9d8c8f76ab39 /contrib/gcc/final.c | |
parent | cbd790c8d27189110c36da6503196f44d88a5860 (diff) | |
download | FreeBSD-src-cadd557b2c028e9d17846ceb76b7abe3b967db5d.zip FreeBSD-src-cadd557b2c028e9d17846ceb76b7abe3b967db5d.tar.gz |
FreeBSD uses unchanged versions of this files.
Diffstat (limited to 'contrib/gcc/final.c')
-rw-r--r-- | contrib/gcc/final.c | 814 |
1 files changed, 516 insertions, 298 deletions
diff --git a/contrib/gcc/final.c b/contrib/gcc/final.c index dd5b64e..d64f0c3 100644 --- a/contrib/gcc/final.c +++ b/contrib/gcc/final.c @@ -1,6 +1,7 @@ /* 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 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +17,8 @@ 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. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ /* This is the final pass of the compiler. It looks at the rtl code for a function and outputs assembler code. @@ -71,6 +72,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "debug.h" #include "expr.h" #include "cfglayout.h" +#include "tree-pass.h" +#include "timevar.h" +#include "cgraph.h" +#include "coverage.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -85,6 +90,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 @@ -105,12 +114,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #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 @@ -132,10 +135,13 @@ 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. */ +/* 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 abort. + This means that inconsistencies are the user's fault, so don't die. The precise value is the insn being output, to pass to error_for_asm. */ rtx this_is_asm_operands; @@ -374,10 +380,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; @@ -395,7 +402,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED) return 0; case CALL_INSN: - length = insn_default_length (insn); + length = fallback_fn (insn); break; case JUMP_INSN: @@ -406,7 +413,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED) ADDR_VEC_ALIGN. */ } else - length = insn_default_length (insn); + length = fallback_fn (insn); break; case INSN: @@ -415,12 +422,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)); else - length = insn_default_length (insn); + length = fallback_fn (insn); break; default: @@ -433,8 +440,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. */ @@ -625,7 +650,7 @@ insn_current_reference_address (rtx branch) seq = NEXT_INSN (PREV_INSN (branch)); seq_uid = INSN_UID (seq); - if (GET_CODE (branch) != JUMP_INSN) + if (!JUMP_P (branch)) /* This can happen for example on the PA; the objective is to know the offset to address something in front of the start of the function. Thus, we can treat it like a backward branch. @@ -651,7 +676,10 @@ insn_current_reference_address (rtx branch) } #endif /* HAVE_ATTR_length */ -void +/* Compute branch alignments based on frequency information in the + CFG. */ + +static unsigned int compute_alignments (void) { int log, max_skip, max_log; @@ -665,26 +693,26 @@ 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; + return 0; FOR_EACH_BB (bb) { rtx label = BB_HEAD (bb); int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; edge e; + edge_iterator ei; - if (GET_CODE (label) != CODE_LABEL + if (!LABEL_P (label) || probably_never_executed_bb_p (bb)) continue; max_log = LABEL_ALIGN (label); max_skip = LABEL_ALIGN_MAX_SKIP; - for (e = bb->pred; e; e = e->pred_next) + FOR_EACH_EDGE (e, ei, bb->preds) { if (e->flags & EDGE_FALLTHRU) has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); @@ -732,7 +760,26 @@ compute_alignments (void) LABEL_TO_ALIGNMENT (label) = max_log; LABEL_TO_MAX_SKIP (label) = max_skip; } + return 0; } + +struct tree_opt_pass pass_compute_alignments = +{ + NULL, /* name */ + NULL, /* gate */ + compute_alignments, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + /* Make a pass over all insns and compute their actual lengths by shortening any branches of variable length if possible. */ @@ -767,7 +814,10 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) /* Compute maximum UID and allocate label_align / uid_shuid. */ max_uid = get_max_uid (); - uid_shuid = xmalloc (max_uid * sizeof *uid_shuid); + /* Free uid_shuid before reallocating it. */ + free (uid_shuid); + + uid_shuid = XNEWVEC (int, max_uid); if (max_labelno != max_label_num ()) { @@ -783,10 +833,9 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) label_align = xrealloc (label_align, n_labels * sizeof (struct label_alignment)); - /* Range of labels grows monotonically in the function. Abort here + /* Range of labels grows monotonically in the function. Failing here means that the initialization of array got lost. */ - if (n_old_labels > n_labels) - abort (); + gcc_assert (n_old_labels <= n_labels); memset (label_align + n_old_labels, 0, (n_labels - n_old_labels) * sizeof (struct label_alignment)); @@ -807,14 +856,9 @@ 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 (GET_CODE (insn) == CODE_LABEL) + continue; + + if (LABEL_P (insn)) { rtx next; @@ -832,11 +876,12 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) max_log = log; max_skip = LABEL_ALIGN_MAX_SKIP; } - next = NEXT_INSN (insn); + 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 && GET_CODE (next) == JUMP_INSN) + 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 @@ -855,13 +900,13 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) max_log = 0; max_skip = 0; } - else if (GET_CODE (insn) == BARRIER) + else if (BARRIER_P (insn)) { rtx label; for (label = insn; label && ! INSN_P (label); label = NEXT_INSN (label)) - if (GET_CODE (label) == CODE_LABEL) + if (LABEL_P (label)) { log = LABEL_ALIGN_AFTER_BARRIER (insn); if (max_log < log) @@ -876,20 +921,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; @@ -898,7 +943,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) { int uid = INSN_UID (seq); int log; - log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0); + log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0); uid_align[uid] = align_tab[0]; if (log) { @@ -925,13 +970,12 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) int min_align; addr_diff_vec_flags flags; - if (GET_CODE (insn) != JUMP_INSN + if (!JUMP_P (insn) || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) continue; pat = PATTERN (insn); len = XVECLEN (pat, 1); - if (len <= 0) - abort (); + gcc_assert (len > 0); min_align = MAX_CODE_ALIGN; for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--) { @@ -950,10 +994,11 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (min_align > LABEL_TO_ALIGNMENT (lab)) min_align = LABEL_TO_ALIGNMENT (lab); } - XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab); - XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab); + XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab); + XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab); insn_shuid = INSN_SHUID (insn); rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0)); + memset (&flags, 0, sizeof (flags)); flags.min_align = min_align; flags.base_after_vec = rel > insn_shuid; flags.min_after_vec = min > insn_shuid; @@ -974,7 +1019,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) insn_lengths[uid] = 0; - if (GET_CODE (insn) == CODE_LABEL) + if (LABEL_P (insn)) { int log = LABEL_TO_ALIGNMENT (insn); if (log) @@ -987,8 +1032,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid]; - if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER - || GET_CODE (insn) == CODE_LABEL) + if (NOTE_P (insn) || BARRIER_P (insn) + || LABEL_P (insn)) continue; if (INSN_DELETED_P (insn)) continue; @@ -998,7 +1043,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))); @@ -1079,7 +1125,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) uid = INSN_UID (insn); - if (GET_CODE (insn) == CODE_LABEL) + if (LABEL_P (insn)) { int log = LABEL_TO_ALIGNMENT (insn); if (log > insn_current_align) @@ -1104,7 +1150,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) INSN_ADDRESSES (uid) = insn_current_address; #ifdef CASE_VECTOR_SHORTEN_MODE - if (optimize && GET_CODE (insn) == JUMP_INSN + if (optimize && JUMP_P (insn) && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) { rtx body = PATTERN (insn); @@ -1199,7 +1245,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))); @@ -1214,7 +1261,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (! (varying_length[uid])) { - if (GET_CODE (insn) == INSN + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; @@ -1236,7 +1283,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) continue; } - if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; @@ -1344,7 +1391,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, (*debug_hooks->begin_prologue) (last_linenum, last_filename); -#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) +#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO) if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) dwarf2out_begin_prologue (0, NULL); #endif @@ -1363,14 +1410,13 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, #if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (NULL_RTX); + dwarf2out_frame_debug (NULL_RTX, false); #endif /* If debugging, assign block numbers to all of the blocks in this 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 @@ -1380,7 +1426,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, } /* First output the function prologue: code to set up the stack frame. */ - (*targetm.asm_out.function_prologue) (file, get_frame_size ()); + targetm.asm_out.function_prologue (file, get_frame_size ()); /* If the machine represents the prologue as RTL, the profiling code must be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ @@ -1409,23 +1455,23 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) 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 = current_function_needs_context; + int cxt = cfun->static_chain_decl != NULL; #endif #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); + targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no); assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); } - function_section (current_function_decl); + switch_to_section (current_function_section ()); #if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG) + if (sval && svrtx != NULL_RTX && REG_P (svrtx)) ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); #endif @@ -1456,7 +1502,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) #endif #if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG) + if (sval && svrtx != NULL_RTX && REG_P (svrtx)) ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); #endif } @@ -1474,7 +1520,7 @@ final_end_function (void) /* 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 ()); + targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ()); /* And debug output. */ (*debug_hooks->end_epilogue) (last_linenum, last_filename); @@ -1487,18 +1533,10 @@ final_end_function (void) } /* Output assembler code for some insns: all or part of a function. - For description of args, see `final_start_function', above. - - PRESCAN is 1 if we are not really outputting, - just scanning as if we were outputting. - Prescanning deletes and rearranges insns just like ordinary output. - PRESCAN is -2 if we are outputting after having prescanned. - In this case, don't try to delete or rearrange insns - because that has already been done. - Prescanning is done only on certain machines. */ + For description of args, see `final_start_function', above. */ void -final (rtx first, FILE *file, int optimize, int prescan) +final (rtx first, FILE *file, int optimize) { rtx insn; int max_uid = 0; @@ -1514,13 +1552,16 @@ final (rtx first, FILE *file, int optimize, int prescan) { rtx last = 0; for (insn = first; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) + if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) { - if ((RTX_INTEGRATED_P (insn) - && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) - || (last != 0 - && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) - && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) + 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; @@ -1537,7 +1578,7 @@ final (rtx first, FILE *file, int optimize, int prescan) #ifdef HAVE_cc0 /* If CC tracking across branches is enabled, record the insn which jumps to each branch only reached from one place. */ - if (optimize && GET_CODE (insn) == JUMP_INSN) + if (optimize && JUMP_P (insn)) { rtx lab = JUMP_LABEL (insn); if (lab && LABEL_NUSES (lab) == 1) @@ -1560,16 +1601,14 @@ final (rtx first, FILE *file, int optimize, int prescan) { /* This can be triggered by bugs elsewhere in the compiler if new insns are created after init_insn_lengths is called. */ - if (GET_CODE (insn) == NOTE) - insn_current_address = -1; - else - abort (); + gcc_assert (NOTE_P (insn)); + insn_current_address = -1; } else insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); #endif /* HAVE_ATTR_length */ - insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen); + insn = final_scan_insn (insn, file, optimize, 0, &seen); } } @@ -1583,12 +1622,11 @@ get_insn_template (int code, rtx insn) case INSN_OUTPUT_FORMAT_MULTI: return insn_data[code].output.multi[which_alternative]; case INSN_OUTPUT_FORMAT_FUNCTION: - if (insn == NULL) - abort (); + gcc_assert (insn); return (*insn_data[code].output.function) (recog_data.operand, insn); default: - abort (); + gcc_unreachable (); } } @@ -1609,7 +1647,7 @@ output_alternate_entry_point (FILE *file, rtx insn) ASM_WEAKEN_LABEL (file, name); #endif case LABEL_GLOBAL_ENTRY: - (*targetm.asm_out.globalize_label) (file, name); + targetm.asm_out.globalize_label (file, name); case LABEL_STATIC_ENTRY: #ifdef ASM_OUTPUT_TYPE_DIRECTIVE ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); @@ -1619,7 +1657,7 @@ output_alternate_entry_point (FILE *file, rtx insn) case LABEL_NORMAL: default: - abort (); + gcc_unreachable (); } } @@ -1639,12 +1677,12 @@ output_alternate_entry_point (FILE *file, rtx insn) rtx final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, - int prescan, int nopeepholes ATTRIBUTE_UNUSED, - int *seen) + int nopeepholes ATTRIBUTE_UNUSED, int *seen) { #ifdef HAVE_cc0 rtx set; #endif + rtx next; insn_counter++; @@ -1656,26 +1694,25 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, switch (GET_CODE (insn)) { case NOTE: - if (prescan > 0) - break; - switch (NOTE_LINE_NUMBER (insn)) { case NOTE_INSN_DELETED: - case NOTE_INSN_LOOP_BEG: - case NOTE_INSN_LOOP_END: - case NOTE_INSN_LOOP_END_TOP_COND: - case NOTE_INSN_LOOP_CONT: - case NOTE_INSN_LOOP_VTOP: case NOTE_INSN_FUNCTION_END: case NOTE_INSN_REPEATED_LINE_NUMBER: case NOTE_INSN_EXPECTED_VALUE: break; + case NOTE_INSN_SWITCH_TEXT_SECTIONS: + in_cold_section_p = !in_cold_section_p; + (*debug_hooks->switch_text_section) (); + switch_to_section (current_function_section ()); + break; + case NOTE_INSN_BASIC_BLOCK: -#ifdef IA64_UNWIND_INFO - IA64_UNWIND_EMIT (asm_out_file, insn); +#ifdef TARGET_UNWIND_INFO + targetm.asm_out.unwind_emit (asm_out_file, insn); #endif + if (flag_debug_asm) fprintf (asm_out_file, "\t%s basic block %d\n", ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); @@ -1683,7 +1720,7 @@ 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; @@ -1701,13 +1738,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_PROLOGUE_END: - (*targetm.asm_out.function_end_prologue) (file); + targetm.asm_out.function_end_prologue (file); profile_after_prologue (file); if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) { *seen |= SEEN_EMITTED; - last_filename = NULL; + force_source_line = true; } else *seen |= SEEN_NOTE; @@ -1715,7 +1752,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_EPILOGUE_BEG: - (*targetm.asm_out.function_begin_epilogue) (file); + targetm.asm_out.function_begin_epilogue (file); break; case NOTE_INSN_FUNCTION_BEG: @@ -1725,7 +1762,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; @@ -1735,7 +1772,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case NOTE_INSN_BLOCK_BEG: if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE - || write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG || write_symbols == VMS_DEBUG) @@ -1757,7 +1793,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case NOTE_INSN_BLOCK_END: if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE - || write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG || write_symbols == VMS_DEBUG) @@ -1768,8 +1803,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* End of a symbol-block. */ --block_depth; - if (block_depth < 0) - abort (); + gcc_assert (block_depth >= 0); (*debug_hooks->end_block) (high_block_linenum, n); } @@ -1782,12 +1816,15 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); break; + case NOTE_INSN_VAR_LOCATION: + (*debug_hooks->var_location) (insn); + break; + case 0: break; default: - if (NOTE_LINE_NUMBER (insn) <= 0) - abort (); + gcc_assert (NOTE_LINE_NUMBER (insn) > 0); break; } break; @@ -1795,7 +1832,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case BARRIER: #if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + dwarf2out_frame_debug (insn, false); #endif break; @@ -1839,18 +1876,16 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, 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 && GET_CODE (barrier) == BARRIER - && jump && GET_CODE (jump) == JUMP_INSN + if (barrier && BARRIER_P (barrier) + && jump && JUMP_P (jump) && (prev = prev_nonnote_insn (jump)) - && GET_CODE (prev) == INSN) + && NONJUMP_INSN_P (prev)) { NOTICE_UPDATE_CC (PATTERN (prev), prev); NOTICE_UPDATE_CC (PATTERN (jump), jump); } } #endif - if (prescan > 0) - break; if (LABEL_NAME (insn)) (*debug_hooks->label) (insn); @@ -1860,10 +1895,11 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, fputs (ASM_APP_OFF, file); app_on = 0; } - if (NEXT_INSN (insn) != 0 - && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) + + next = next_nonnote_insn (insn); + if (next != 0 && JUMP_P (next)) { - rtx nextbody = PATTERN (NEXT_INSN (insn)); + 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 @@ -1881,23 +1917,24 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { int log_align; - readonly_data_section (); + switch_to_section (targetm.asm_out.function_rodata_section + (current_function_decl)); #ifdef ADDR_VEC_ALIGN - log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn)); + log_align = ADDR_VEC_ALIGN (next); #else log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); #endif ASM_OUTPUT_ALIGN (file, log_align); } else - function_section (current_function_decl); + switch_to_section (current_function_section ()); #ifdef ASM_OUTPUT_CASE_LABEL ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), - NEXT_INSN (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; @@ -1906,7 +1943,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if (LABEL_ALT_ENTRY_P (insn)) output_alternate_entry_point (file, insn); else - (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn)); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); break; default: @@ -1914,8 +1951,11 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, rtx body = PATTERN (insn); int insn_code_number; const char *template; - rtx note; +#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. */ @@ -1924,17 +1964,19 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; #ifdef HAVE_cc0 - /* If there is a REG_CC_SETTER note on this insn, it means that - the setting of the condition code was done in the delay slot - of the insn that branched here. So recover the cc status - from the insn that set it. */ + { + /* If there is a REG_CC_SETTER note on this insn, it means that + the setting of the condition code was done in the delay slot + of the insn that branched here. So recover the cc status + from the insn that set it. */ - note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); - if (note) - { - NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); - cc_prev_status = cc_status; - } + rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); + if (note) + { + NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); + cc_prev_status = cc_status; + } + } #endif /* Detect insns that are really jump-tables @@ -1946,8 +1988,11 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, int vlen, idx; #endif - if (prescan > 0) - break; + if (! JUMP_TABLES_IN_TEXT_SECTION) + switch_to_section (targetm.asm_out.function_rodata_section + (current_function_decl)); + else + switch_to_section (current_function_section ()); if (app_on) { @@ -1961,7 +2006,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef ASM_OUTPUT_ADDR_VEC ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); #else - abort (); + gcc_unreachable (); #endif } else @@ -1969,7 +2014,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef ASM_OUTPUT_ADDR_DIFF_VEC ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); #else - abort (); + gcc_unreachable (); #endif } #else @@ -1982,7 +2027,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ASM_OUTPUT_ADDR_VEC_ELT (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); #else - abort (); + gcc_unreachable (); #endif } else @@ -1994,7 +2039,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); #else - abort (); + gcc_unreachable (); #endif } } @@ -2005,7 +2050,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif #endif - function_section (current_function_decl); + switch_to_section (current_function_section ()); break; } @@ -2022,8 +2067,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; - if (prescan > 0) - break; if (string[0]) { @@ -2046,12 +2089,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; - if (prescan > 0) - break; /* Get out the operand values. */ string = decode_asm_operands (body, ops, NULL, NULL, NULL); - /* Inhibit aborts on what would otherwise be compiler bugs. */ + /* Inhibit dieing on what would otherwise be compiler bugs. */ insn_noperands = noperands; this_is_asm_operands = insn; @@ -2074,7 +2115,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; } - if (prescan <= 0 && app_on) + if (app_on) { fputs (ASM_APP_OFF, file); app_on = 0; @@ -2084,10 +2125,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { /* A delayed-branch sequence */ int i; - rtx next; - if (prescan > 0) - break; final_sequence = body; /* Record the delay slots' frame information before the branch. @@ -2095,7 +2133,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) for (i = 1; i < XVECLEN (body, 0); i++) - dwarf2out_frame_debug (XVECEXP (body, 0, i)); + dwarf2out_frame_debug (XVECEXP (body, 0, i), false); #endif /* The first insn in this SEQUENCE might be a JUMP_INSN that will @@ -2103,7 +2141,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, thought unnecessary. If that happens, cancel this sequence and cause that insn to be restored. */ - next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen); + next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen); if (next != XVECEXP (body, 0, 1)) { final_sequence = 0; @@ -2117,7 +2155,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* We loop in case any instruction in a delay slot gets split. */ do - insn = final_scan_insn (insn, file, 0, prescan, 1, seen); + insn = final_scan_insn (insn, file, 0, 1, seen); while (insn != next); } #ifdef DBR_OUTPUT_SEQEND @@ -2130,7 +2168,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, called function. Hence we don't preserve any CC-setting actions in these insns and the CC must be marked as being clobbered by the function. */ - if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) + if (CALL_P (XVECEXP (body, 0, 0))) { CC_STATUS_INIT; } @@ -2188,20 +2226,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, } #endif -#ifndef STACK_REGS - /* Don't bother outputting obvious no-ops, even without -O. - This optimization is fast and doesn't interfere with debugging. - Don't do this if the insn is in a delay slot, since this - will cause an improper number of delay insns to be written. */ - if (final_sequence == 0 - && prescan >= 0 - && GET_CODE (insn) == INSN && GET_CODE (body) == SET - && GET_CODE (SET_SRC (body)) == REG - && GET_CODE (SET_DEST (body)) == REG - && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) - break; -#endif - #ifdef HAVE_cc0 /* If this is a conditional branch, maybe modify it if the cc's are in a nonstandard state @@ -2209,15 +2233,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, do straightforwardly if the cc's were set up normally. */ if (cc_status.flags != 0 - && GET_CODE (insn) == JUMP_INSN + && JUMP_P (insn) && GET_CODE (body) == SET && SET_DEST (body) == pc_rtx && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE - && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' - && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx - /* This is done during prescan; it is not done again - in final scan when prescan has been done. */ - && prescan >= 0) + && COMPARISON_P (XEXP (SET_SRC (body), 0)) + && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx) { /* This function may alter the contents of its argument and clear some of the cc_status.flags bits. @@ -2258,7 +2279,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { rtx cond_rtx, then_rtx, else_rtx; - if (GET_CODE (insn) != JUMP_INSN + if (!JUMP_P (insn) && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) { cond_rtx = XEXP (SET_SRC (set), 0); @@ -2317,14 +2338,16 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, emit them before the peephole. */ if (next != 0 && next != NEXT_INSN (insn)) { - rtx prev = PREV_INSN (insn); + rtx note, prev = PREV_INSN (insn); for (note = NEXT_INSN (insn); note != next; note = NEXT_INSN (note)) - final_scan_insn (note, file, optimize, prescan, nopeepholes, seen); + final_scan_insn (note, file, optimize, nopeepholes, seen); - /* In case this is prescan, put the notes - in proper position for later rescan. */ + /* Put the notes in the proper position for a later + rescan. For example, the SH target can do this + when generating a far jump in a delayed branch + sequence. */ note = NEXT_INSN (insn); PREV_INSN (note) = prev; NEXT_INSN (prev) = note; @@ -2368,8 +2391,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef HAVE_conditional_execution if (GET_CODE (PATTERN (insn)) == COND_EXEC) current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); - else - current_insn_predicate = NULL_RTX; #endif #ifdef HAVE_cc0 @@ -2386,8 +2407,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, current_output_insn = debug_insn = insn; #if defined (DWARF2_UNWIND_INFO) - if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + if (CALL_P (insn) && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn, false); #endif /* Find the proper template for this insn. */ @@ -2400,8 +2421,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { rtx prev; - if (prev_nonnote_insn (insn) != last_ignored_compare) - abort (); + gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare); /* We have already processed the notes between the setter and the user. Make sure we don't process them again, this is @@ -2411,7 +2431,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, prev != last_ignored_compare; prev = PREV_INSN (prev)) { - if (GET_CODE (prev) == NOTE) + if (NOTE_P (prev)) delete_insn (prev); /* Use delete_note. */ } @@ -2432,55 +2452,41 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* This instruction should have been split in shorten_branches, to ensure that we would have valid length info for the splitees. */ - abort (); + gcc_unreachable (); #endif return new; } - if (prescan > 0) - break; - -#ifdef IA64_UNWIND_INFO - IA64_UNWIND_EMIT (asm_out_file, insn); +#ifdef TARGET_UNWIND_INFO + /* ??? This will put the directives in the wrong place if + get_insn_template outputs assembly directly. However calling it + before get_insn_template breaks if the insns is split. */ + targetm.asm_out.unwind_emit (asm_out_file, insn); #endif - /* Output assembler code from the template. */ + /* Output assembler code from the template. */ output_asm_insn (template, recog_data.operand); /* If necessary, report the effect that the instruction has on the unwind info. We've already done this for delay slots and call instructions. */ #if defined (DWARF2_UNWIND_INFO) - if (GET_CODE (insn) == INSN + if (final_sequence == 0 #if !defined (HAVE_prologue) && !ACCUMULATE_OUTGOING_ARGS #endif - && final_sequence == 0 && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + dwarf2out_frame_debug (insn, true); #endif -#if 0 - /* It's not at all clear why we did this and doing so used to - interfere with tests that used REG_WAS_0 notes, which are - now gone, so let's try with this out. */ - - /* Mark this insn as having been output. */ - INSN_DELETED_P (insn) = 1; -#endif - - /* Emit information for vtable gc. */ - note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX); - current_output_insn = debug_insn = 0; } } 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. */ static bool notice_source_line (rtx insn) @@ -2488,8 +2494,12 @@ notice_source_line (rtx insn) const char *filename = insn_file (insn); int linenum = insn_line (insn); - if (filename && (filename != last_filename || last_linenum != linenum)) + if (filename + && (force_source_line + || filename != last_filename + || last_linenum != linenum)) { + force_source_line = false; last_filename = filename; last_linenum = linenum; high_block_linenum = MAX (last_linenum, high_block_linenum); @@ -2518,7 +2528,7 @@ cleanup_subreg_operands (rtx insn) recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); else if (GET_CODE (recog_data.operand[i]) == PLUS || GET_CODE (recog_data.operand[i]) == MULT - || GET_CODE (recog_data.operand[i]) == MEM) + || MEM_P (recog_data.operand[i])) recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); } @@ -2528,7 +2538,7 @@ cleanup_subreg_operands (rtx insn) *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS || GET_CODE (*recog_data.dup_loc[i]) == MULT - || GET_CODE (*recog_data.dup_loc[i]) == MEM) + || MEM_P (*recog_data.dup_loc[i])) *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); } } @@ -2544,8 +2554,25 @@ alter_subreg (rtx *xp) /* simplify_subreg does not remove subreg from volatile references. We are required to. */ - if (GET_CODE (y) == MEM) - *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x)); + if (MEM_P (y)) + { + int offset = SUBREG_BYTE (x); + + /* For paradoxical subregs on big-endian machines, SUBREG_BYTE + contains 0 instead of the proper offset. See simplify_subreg. */ + if (offset == 0 + && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x))) + { + int difference = GET_MODE_SIZE (GET_MODE (y)) + - GET_MODE_SIZE (GET_MODE (x)); + if (WORDS_BIG_ENDIAN) + offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += difference % UNITS_PER_WORD; + } + + *xp = adjust_address (y, GET_MODE (x), offset); + } else { rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), @@ -2553,14 +2580,12 @@ alter_subreg (rtx *xp) if (new != 0) *xp = new; - /* Simplify_subreg can't handle some REG cases, but we have to. */ - else if (GET_CODE (y) == REG) + else if (REG_P (y)) { - unsigned int regno = subreg_hard_regno (x, 1); + /* 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)); } - else - abort (); } return *xp; @@ -2576,11 +2601,13 @@ 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)); break; case MEM: + case ZERO_EXTEND: XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); break; @@ -2709,7 +2736,7 @@ alter_cond (rtx cond) switch (GET_CODE (cond)) { default: - abort (); + gcc_unreachable (); case NE: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); @@ -2759,17 +2786,17 @@ alter_cond (rtx cond) In an `asm', it's the user's fault; otherwise, the compiler's fault. */ void -output_operand_lossage (const char *msgid, ...) +output_operand_lossage (const char *cmsgid, ...) { char *fmt_string; char *new_message; const char *pfx_str; va_list ap; - va_start (ap, msgid); + va_start (ap, cmsgid); - pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: "; - asprintf (&fmt_string, "%s%s", pfx_str, _(msgid)); + pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: "; + asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid)); vasprintf (&new_message, fmt_string, ap); if (this_is_asm_operands) @@ -2820,9 +2847,9 @@ get_mem_expr_from_op (rtx op, int *paddressp) *paddressp = 0; - if (GET_CODE (op) == REG) + if (REG_P (op)) return REG_EXPR (op); - else if (GET_CODE (op) != MEM) + else if (!MEM_P (op)) return 0; if (MEM_EXPR (op) != 0) @@ -2841,8 +2868,8 @@ 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)) == '1' - || GET_RTX_CLASS (GET_CODE (op)) == '2') + while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY + || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH) op = XEXP (op, 0); expr = get_mem_expr_from_op (op, &inner_addressp); @@ -3021,61 +3048,66 @@ output_asm_insn (const char *template, rtx *operands) else if (ISALPHA (*p)) { int letter = *p++; - c = atoi (p); + unsigned long opnum; + char *endptr; + + opnum = strtoul (p, &endptr, 10); - if (! ISDIGIT (*p)) - output_operand_lossage ("operand number missing after %%-letter"); - else if (this_is_asm_operands - && (c < 0 || (unsigned int) c >= insn_noperands)) + if (endptr == p) + output_operand_lossage ("operand number missing " + "after %%-letter"); + else if (this_is_asm_operands && opnum >= insn_noperands) output_operand_lossage ("operand number out of range"); else if (letter == 'l') - output_asm_label (operands[c]); + output_asm_label (operands[opnum]); else if (letter == 'a') - output_address (operands[c]); + output_address (operands[opnum]); else if (letter == 'c') { - if (CONSTANT_ADDRESS_P (operands[c])) - output_addr_const (asm_out_file, operands[c]); + if (CONSTANT_ADDRESS_P (operands[opnum])) + output_addr_const (asm_out_file, operands[opnum]); else - output_operand (operands[c], 'c'); + output_operand (operands[opnum], 'c'); } else if (letter == 'n') { - if (GET_CODE (operands[c]) == CONST_INT) + if (GET_CODE (operands[opnum]) == CONST_INT) fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, - - INTVAL (operands[c])); + - INTVAL (operands[opnum])); else { putc ('-', asm_out_file); - output_addr_const (asm_out_file, operands[c]); + output_addr_const (asm_out_file, operands[opnum]); } } else - output_operand (operands[c], letter); + output_operand (operands[opnum], letter); - if (!opoutput[c]) - oporder[ops++] = c; - opoutput[c] = 1; + if (!opoutput[opnum]) + oporder[ops++] = opnum; + opoutput[opnum] = 1; - while (ISDIGIT (c = *p)) - p++; + p = endptr; + c = *p; } /* % followed by a digit outputs an operand the default way. */ else if (ISDIGIT (*p)) { - c = atoi (p); - if (this_is_asm_operands - && (c < 0 || (unsigned int) c >= insn_noperands)) + 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"); else - output_operand (operands[c], 0); + output_operand (operands[opnum], 0); - if (!opoutput[c]) - oporder[ops++] = c; - opoutput[c] = 1; + if (!opoutput[opnum]) + oporder[ops++] = opnum; + opoutput[opnum] = 1; - while (ISDIGIT (c = *p)) - p++; + p = endptr; + c = *p; } /* % followed by punctuation: output something for that punctuation character alone, with no operand. @@ -3110,12 +3142,12 @@ output_asm_label (rtx x) if (GET_CODE (x) == LABEL_REF) x = XEXP (x, 0); - if (GET_CODE (x) == CODE_LABEL - || (GET_CODE (x) == NOTE + if (LABEL_P (x) + || (NOTE_P (x) && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); else - output_operand_lossage ("`%%l' operand isn't a label"); + output_operand_lossage ("'%%l' operand isn't a label"); assemble_name (asm_out_file, buf); } @@ -3136,11 +3168,8 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED) if (x && GET_CODE (x) == SUBREG) x = alter_subreg (&x); - /* If X is a pseudo-register, abort now rather than writing trash to the - assembler file. */ - - if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) - abort (); + /* X must not be a pseudo reg. */ + gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER); PRINT_OPERAND (asm_out_file, x, code); } @@ -3173,6 +3202,8 @@ output_addr_const (FILE *file, rtx x) break; case SYMBOL_REF: + if (SYMBOL_REF_DECL (x)) + mark_decl_referenced (SYMBOL_REF_DECL (x)); #ifdef ASM_OUTPUT_SYMBOL_REF ASM_OUTPUT_SYMBOL_REF (file, x); #else @@ -3437,7 +3468,7 @@ asm_fprintf (FILE *file, const char *p, ...) ASM_FPRINTF_EXTENSIONS (file, argptr, p) #endif default: - abort (); + gcc_unreachable (); } break; @@ -3584,8 +3615,8 @@ split_double (rtx value, rtx *first, rtx *second) } #endif - *first = GEN_INT ((HOST_WIDE_INT) l[0]); - *second = GEN_INT ((HOST_WIDE_INT) l[1]); + *first = GEN_INT (l[0]); + *second = GEN_INT (l[1]); } } @@ -3602,12 +3633,12 @@ leaf_function_p (void) for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { - if (GET_CODE (insn) == CALL_INSN + if (CALL_P (insn) && ! SIBLING_CALL_P (insn)) return 0; - if (GET_CODE (insn) == INSN + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE - && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN + && CALL_P (XVECEXP (PATTERN (insn), 0, 0)) && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } @@ -3617,12 +3648,12 @@ leaf_function_p (void) { insn = XEXP (link, 0); - if (GET_CODE (insn) == CALL_INSN + if (CALL_P (insn) && ! SIBLING_CALL_P (insn)) return 0; - if (GET_CODE (insn) == INSN + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE - && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN + && CALL_P (XVECEXP (PATTERN (insn), 0, 0)) && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } @@ -3638,13 +3669,12 @@ int final_forward_branch_p (rtx insn) { int insn_id, label_id; - if (!uid_shuid) - abort (); + + gcc_assert (uid_shuid); insn_id = INSN_SHUID (insn); label_id = INSN_SHUID (JUMP_LABEL (insn)); /* We've hit some insns that does not have id information available. */ - if (!insn_id || !label_id) - abort (); + gcc_assert (insn_id && label_id); return insn_id < label_id; } @@ -3675,7 +3705,7 @@ only_leaf_regs_used (void) if (current_function_uses_pic_offset_table && pic_offset_table_rtx != 0 - && GET_CODE (pic_offset_table_rtx) == REG + && REG_P (pic_offset_table_rtx) && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) return 0; @@ -3719,7 +3749,7 @@ leaf_renumber_regs_insn (rtx in_rtx) renumbered_regs would be 1 for an output-register; they */ - if (GET_CODE (in_rtx) == REG) + if (REG_P (in_rtx)) { int newreg; @@ -3736,8 +3766,7 @@ leaf_renumber_regs_insn (rtx in_rtx) return; } newreg = LEAF_REG_REMAP (newreg); - if (newreg < 0) - abort (); + gcc_assert (newreg >= 0); regs_ever_live[REGNO (in_rtx)] = 0; regs_ever_live[newreg] = 1; REGNO (in_rtx) = newreg; @@ -3780,7 +3809,7 @@ leaf_renumber_regs_insn (rtx in_rtx) break; default: - abort (); + gcc_unreachable (); } } #endif @@ -3816,7 +3845,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 @@ -3866,3 +3895,192 @@ 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 (); +#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 (); +#endif + + user_defined_section_attribute = false; + + if (! quiet_flag) + fflush (asm_out_file); + + /* Release all memory allocated by flow. */ + free_basic_block_vars (); + + /* Write DBX symbols if requested. */ + + /* Note that for those inline functions where we don't initially + know for certain that we will be generating an out-of-line copy, + the first invocation of this routine (rest_of_compilation) will + skip over this code by doing a `goto exit_rest_of_compilation;'. + Later on, wrapup_global_declarations will (indirectly) call + rest_of_compilation again for those inline functions that need + to have out-of-line copies generated. During that call, we + *will* be routed past here. */ + + timevar_push (TV_SYMOUT); + (*debug_hooks->function_decl) (current_function_decl); + timevar_pop (TV_SYMOUT); + return 0; +} + +struct tree_opt_pass pass_final = +{ + NULL, /* 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 */ + 0 /* letter */ +}; + + +static unsigned int +rest_of_handle_shorten_branches (void) +{ + /* Shorten branches. */ + shorten_branches (get_insns ()); + return 0; +} + +struct tree_opt_pass pass_shorten_branches = +{ + "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 */ + 0 /* letter */ +}; + + +static unsigned int +rest_of_clean_state (void) +{ + rtx insn, next; + + /* 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; + } + + /* In case the function was not output, + don't leave any temporary anonymous types + queued up for sdb output. */ +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_types (NULL_TREE); +#endif + + reload_completed = 0; + epilogue_completed = 0; + flow2_completed = 0; + no_new_pseudos = 0; +#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_basic_block_vars (); + free_bb_for_insn (); + + + if (targetm.binds_local_p (current_function_decl)) + { + int pref = cfun->preferred_stack_boundary; + if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary) + pref = cfun->stack_alignment_needed; + cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary + = pref; + } + + /* Make sure volatile mem refs aren't considered valid operands for + arithmetic insns. We must call this here if this is a nested inline + function, since the above code leaves us in the init_recog state, + 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 tree_opt_pass pass_clean_state = +{ + NULL, /* 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 */ + 0 /* letter */ +}; + |