X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ffinal.c;h=7e1ae902477ef312a5447b3d89c63ef3420d6e45;hb=467fa2ada0cbc1b7b81db7567540e8e46dbca920;hp=2a9d40ba75424fdd3c4e3f7976e3f58f5a6578e4;hpb=9cb02f7567e731604fded7dc5c427484b82a5b55;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/final.c b/gcc/final.c index 2a9d40ba754..7e1ae902477 100644 --- a/gcc/final.c +++ b/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, 2005, 2006, 2007, 2008 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -58,20 +59,22 @@ along with GCC; see the file COPYING3. If not see #include "recog.h" #include "conditions.h" #include "flags.h" -#include "real.h" #include "hard-reg-set.h" #include "output.h" #include "except.h" #include "function.h" -#include "toplev.h" +#include "rtl-error.h" +#include "toplev.h" /* exact_log2, floor_log2 */ #include "reload.h" #include "intl.h" #include "basic-block.h" #include "target.h" +#include "targhooks.h" #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" @@ -86,9 +89,7 @@ along with GCC; see the file COPYING3. If not see declarations for e.g. AIX 4.x. */ #endif -#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) #include "dwarf2out.h" -#endif #ifdef DBX_DEBUGGING_INFO #include "dbxout.h" @@ -98,8 +99,8 @@ along with GCC; see the file COPYING3. If not see #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. */ +/* Most ports that aren't using cc0 don't need to define CC_STATUS_INIT. + So define a null default for it to save conditionalization later. */ #ifndef CC_STATUS_INIT #define CC_STATUS_INIT #endif @@ -130,6 +131,12 @@ rtx current_output_insn; /* Line number of last NOTE. */ static int last_linenum; +/* Last discriminator written to assembly. */ +static int last_discriminator; + +/* Discriminator of current block. */ +static int discriminator; + /* Highest line number in current block. */ static int high_block_linenum; @@ -197,23 +204,23 @@ 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 + +/* True if printing into -fdump-final-insns= dump. */ +bool final_insns_dump_p; #ifdef HAVE_ATTR_length static int asm_insn_count (rtx); #endif static void profile_function (FILE *); static void profile_after_prologue (FILE *); -static bool notice_source_line (rtx); +static bool notice_source_line (rtx, bool *); static rtx walk_alter_subreg (rtx *, bool *); static void output_asm_name (void); static void output_alternate_entry_point (FILE *, rtx); static tree get_mem_expr_from_op (rtx, int *); static void output_asm_operand_names (rtx *, int *, int); -static void output_operand (rtx, int); #ifdef LEAF_REGISTERS static void leaf_renumber_regs (rtx); #endif @@ -250,6 +257,13 @@ default_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED, { } +void +default_function_switched_text_sections (FILE *file ATTRIBUTE_UNUSED, + tree decl ATTRIBUTE_UNUSED, + bool new_is_cold ATTRIBUTE_UNUSED) +{ +} + /* Default target hook that outputs nothing to a stream. */ void no_asm_to_stream (FILE *file ATTRIBUTE_UNUSED) @@ -384,6 +398,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, case NOTE: case BARRIER: case CODE_LABEL: + case DEBUG_INSN: return 0; case CALL_INSN: @@ -491,33 +506,41 @@ get_attr_min_length (rtx insn) #define LABEL_ALIGN(LABEL) align_labels_log #endif -#ifndef LABEL_ALIGN_MAX_SKIP -#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip -#endif - #ifndef LOOP_ALIGN #define LOOP_ALIGN(LABEL) align_loops_log #endif -#ifndef LOOP_ALIGN_MAX_SKIP -#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip -#endif - #ifndef LABEL_ALIGN_AFTER_BARRIER #define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 #endif -#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP -#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 -#endif - #ifndef JUMP_ALIGN #define JUMP_ALIGN(LABEL) align_jumps_log #endif -#ifndef JUMP_ALIGN_MAX_SKIP -#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip -#endif +int +default_label_align_after_barrier_max_skip (rtx insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +int +default_loop_align_max_skip (rtx insn ATTRIBUTE_UNUSED) +{ + return align_loops_max_skip; +} + +int +default_label_align_max_skip (rtx insn ATTRIBUTE_UNUSED) +{ + return align_labels_max_skip; +} + +int +default_jump_align_max_skip (rtx insn ATTRIBUTE_UNUSED) +{ + return align_jumps_max_skip; +} #ifndef ADDR_VEC_ALIGN static int @@ -553,7 +576,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 @@ -664,7 +697,7 @@ insn_current_reference_address (rtx branch) /* Compute branch alignments based on frequency information in the CFG. */ -static unsigned int +unsigned int compute_alignments (void) { int log, max_skip, max_log; @@ -683,15 +716,15 @@ compute_alignments (void) label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1); /* If not optimizing or optimizing for size, don't assign any alignments. */ - if (! optimize || optimize_size) + if (! optimize || optimize_function_for_size_p (cfun)) return 0; if (dump_file) { dump_flow_info (dump_file, TDF_DETAILS); flow_loops_dump (dump_file, NULL, 1); - loop_optimizer_init (AVOID_CFG_MODIFICATIONS); } + loop_optimizer_init (AVOID_CFG_MODIFICATIONS); FOR_EACH_BB (bb) if (bb->frequency > freq_max) freq_max = bb->frequency; @@ -707,7 +740,7 @@ compute_alignments (void) edge_iterator ei; if (!LABEL_P (label) - || probably_never_executed_bb_p (bb)) + || optimize_bb_for_size_p (bb)) { if (dump_file) fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n", @@ -715,7 +748,7 @@ compute_alignments (void) continue; } max_log = LABEL_ALIGN (label); - max_skip = LABEL_ALIGN_MAX_SKIP; + max_skip = targetm.asm_out.label_align_max_skip (label); FOR_EACH_EDGE (e, ei, bb->preds) { @@ -759,13 +792,13 @@ compute_alignments (void) if (max_log < log) { max_log = log; - max_skip = JUMP_ALIGN_MAX_SKIP; + max_skip = targetm.asm_out.jump_align_max_skip (label); } } /* In case block is frequent and reached mostly by non-fallthru edge, align it. It is most likely a first block of loop. */ if (has_fallthru - && maybe_hot_bb_p (bb) + && optimize_bb_for_speed_p (bb) && branch_frequency + fallthru_frequency > freq_threshold && (branch_frequency > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS))) @@ -776,15 +809,15 @@ compute_alignments (void) if (max_log < log) { max_log = log; - max_skip = LOOP_ALIGN_MAX_SKIP; + max_skip = targetm.asm_out.loop_align_max_skip (label); } } LABEL_TO_ALIGNMENT (label) = max_log; LABEL_TO_MAX_SKIP (label) = max_skip; } - if (dump_file) - loop_optimizer_finalize (); + loop_optimizer_finalize (); + free_dominance_info (CDI_DOMINATORS); return 0; } @@ -798,7 +831,7 @@ struct rtl_opt_pass pass_compute_alignments = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -888,6 +921,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (LABEL_P (insn)) { rtx next; + bool next_is_jumptable; /* Merge in alignments computed by compute_alignments. */ log = LABEL_TO_ALIGNMENT (insn); @@ -897,31 +931,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 = targetm.asm_out.label_align_max_skip (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 - || readonly_data_section == text_section) - if (next && JUMP_P (next)) - { - rtx nextbody = PATTERN (next); - if (GET_CODE (nextbody) == ADDR_VEC - || GET_CODE (nextbody) == ADDR_DIFF_VEC) - { - log = ADDR_VEC_ALIGN (next); - if (max_log < log) - { - max_log = log; - max_skip = LABEL_ALIGN_MAX_SKIP; - } - } - } + if ((JUMP_TABLES_IN_TEXT_SECTION + || readonly_data_section == text_section) + && next_is_jumptable) + { + log = ADDR_VEC_ALIGN (next); + if (max_log < log) + { + max_log = log; + max_skip = targetm.asm_out.label_align_max_skip (insn); + } + } LABEL_TO_ALIGNMENT (insn) = max_log; LABEL_TO_MAX_SKIP (insn) = max_skip; max_log = 0; @@ -939,7 +972,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED) if (max_log < log) { max_log = log; - max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; + max_skip = targetm.asm_out.label_align_after_barrier_max_skip (label); } break; } @@ -1060,7 +1093,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; @@ -1378,13 +1411,23 @@ static int asm_insn_count (rtx body) { const char *templ; - int count = 1; if (GET_CODE (body) == ASM_INPUT) templ = XSTR (body, 0); else templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); + 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; @@ -1395,7 +1438,6 @@ asm_insn_count (rtx body) return count; } -#endif /* ??? This is probably the wrong place for these. */ /* Structure recording the mapping from source file and directory @@ -1430,10 +1472,10 @@ add_debug_prefix_map (const char *arg) return; } map = XNEW (debug_prefix_map); - map->old_prefix = ggc_alloc_string (arg, p - arg); + map->old_prefix = xstrndup (arg, p - arg); map->old_len = p - arg; p++; - map->new_prefix = ggc_strdup (p); + map->new_prefix = xstrdup (p); map->new_len = strlen (p); map->next = debug_prefix_maps; debug_prefix_maps = map; @@ -1451,7 +1493,7 @@ remap_debug_filename (const char *filename) size_t name_len; for (map = debug_prefix_maps; map; map = map->next) - if (strncmp (filename, map->old_prefix, map->old_len) == 0) + if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0) break; if (!map) return filename; @@ -1463,6 +1505,20 @@ remap_debug_filename (const char *filename) return ggc_strdup (s); } +/* Return true if DWARF2 debug info can be emitted for DECL. */ + +static bool +dwarf2_debug_info_emitted_p (tree decl) +{ + if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) + return false; + + if (DECL_IGNORED_P (decl)) + return false; + + return true; +} + /* Output assembler code for the start of a function, and initialize some of the variables in this file for the new function. The label for the function and associated @@ -1470,12 +1526,12 @@ remap_debug_filename (const char *filename) FIRST is the first insn of the rtl for the function being compiled. FILE is the file to write assembler code to. - OPTIMIZE is nonzero if we should eliminate redundant + OPTIMIZE_P is nonzero if we should eliminate redundant test and compare insns. */ void final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, - int optimize ATTRIBUTE_UNUSED) + int optimize_p ATTRIBUTE_UNUSED) { block_depth = 0; @@ -1483,15 +1539,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 #ifdef LEAF_REG_REMAP if (current_function_uses_only_leaf_regs) @@ -1500,14 +1556,12 @@ 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 (crtl->profile) + if (targetm.profile_before_prologue () && crtl->profile) profile_function (file); -#endif /* PROFILE_BEFORE_PROLOGUE */ -#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) +#if defined (HAVE_prologue) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (NULL_RTX, false); + dwarf2out_frame_debug_init (); #endif /* If debugging, assign block numbers to all of the blocks in this @@ -1545,10 +1599,8 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, static void profile_after_prologue (FILE *file ATTRIBUTE_UNUSED) { -#ifndef PROFILE_BEFORE_PROLOGUE - if (crtl->profile) + if (!targetm.profile_before_prologue () && crtl->profile) profile_function (file); -#endif /* not PROFILE_BEFORE_PROLOGUE */ } static void @@ -1557,12 +1609,14 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) #ifndef NO_PROFILE_COUNTERS # define NO_PROFILE_COUNTERS 0 #endif -#if defined(ASM_OUTPUT_REG_PUSH) - int sval = cfun->returns_struct; - rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); -#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) - int cxt = cfun->static_chain_decl != NULL; -#endif +#ifdef ASM_OUTPUT_REG_PUSH + rtx sval = NULL, chain = NULL; + + if (cfun->returns_struct) + sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), + true); + if (cfun->static_chain_decl) + chain = targetm.calls.static_chain (current_function_decl, true); #endif /* ASM_OUTPUT_REG_PUSH */ if (! NO_PROFILE_COUNTERS) @@ -1576,44 +1630,20 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) switch_to_section (current_function_section ()); -#if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) - { - ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); - } -#endif - -#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); -#else -#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - { - ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); - } -#endif +#ifdef ASM_OUTPUT_REG_PUSH + if (sval && REG_P (sval)) + ASM_OUTPUT_REG_PUSH (file, REGNO (sval)); + if (chain && REG_P (chain)) + ASM_OUTPUT_REG_PUSH (file, REGNO (chain)); #endif FUNCTION_PROFILER (file, current_function_funcdef_no); -#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); -#else -#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) - if (cxt) - { - ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); - } -#endif -#endif - -#if defined(ASM_OUTPUT_REG_PUSH) - if (sval && svrtx != NULL_RTX && REG_P (svrtx)) - { - ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); - } +#ifdef ASM_OUTPUT_REG_PUSH + if (chain && REG_P (chain)) + ASM_OUTPUT_REG_POP (file, REGNO (chain)); + if (sval && REG_P (sval)) + ASM_OUTPUT_REG_POP (file, REGNO (sval)); #endif } @@ -1626,32 +1656,86 @@ 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 } + +/* Dumper helper for basic block information. FILE is the assembly + output file, and INSN is the instruction being emitted. */ + +static void +dump_basic_block_info (FILE *file, rtx insn, basic_block *start_to_bb, + basic_block *end_to_bb, int bb_map_size, int *bb_seqn) +{ + basic_block bb; + + if (!flag_debug_asm) + return; + + if (INSN_UID (insn) < bb_map_size + && (bb = start_to_bb[INSN_UID (insn)]) != NULL) + { + edge e; + edge_iterator ei; + + fprintf (file, "%s BLOCK %d", ASM_COMMENT_START, bb->index); + if (bb->frequency) + fprintf (file, " freq:%d", bb->frequency); + if (bb->count) + fprintf (file, " count:" HOST_WIDEST_INT_PRINT_DEC, + bb->count); + fprintf (file, " seq:%d", (*bb_seqn)++); + fprintf (file, "\n%s PRED:", ASM_COMMENT_START); + FOR_EACH_EDGE (e, ei, bb->preds) + { + dump_edge_info (file, e, 0); + } + fprintf (file, "\n"); + } + if (INSN_UID (insn) < bb_map_size + && (bb = end_to_bb[INSN_UID (insn)]) != NULL) + { + edge e; + edge_iterator ei; + + fprintf (asm_out_file, "%s SUCC:", ASM_COMMENT_START); + FOR_EACH_EDGE (e, ei, bb->succs) + { + dump_edge_info (asm_out_file, e, 1); + } + fprintf (file, "\n"); + } +} + /* Output assembler code for some insns: all or part of a function. For description of args, see `final_start_function', above. */ void -final (rtx first, FILE *file, int optimize) +final (rtx first, FILE *file, int optimize_p) { rtx insn; int max_uid = 0; int seen = 0; + /* Used for -dA dump. */ + basic_block *start_to_bb = NULL; + basic_block *end_to_bb = NULL; + int bb_map_size = 0; + int bb_seqn = 0; + last_ignored_compare = 0; for (insn = first; insn; insn = NEXT_INSN (insn)) @@ -1661,7 +1745,7 @@ final (rtx first, FILE *file, int optimize) #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 && JUMP_P (insn)) + if (optimize_p && JUMP_P (insn)) { rtx lab = JUMP_LABEL (insn); if (lab && LABEL_NUSES (lab) == 1) @@ -1676,6 +1760,21 @@ final (rtx first, FILE *file, int optimize) CC_STATUS_INIT; + if (flag_debug_asm) + { + basic_block bb; + + bb_map_size = get_max_uid () + 1; + start_to_bb = XCNEWVEC (basic_block, bb_map_size); + end_to_bb = XCNEWVEC (basic_block, bb_map_size); + + FOR_EACH_BB_REVERSE (bb) + { + start_to_bb[INSN_UID (BB_HEAD (bb))] = bb; + end_to_bb[INSN_UID (BB_END (bb))] = bb; + } + } + /* Output the insns. */ for (insn = first; insn;) { @@ -1691,7 +1790,15 @@ final (rtx first, FILE *file, int optimize) insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); #endif /* HAVE_ATTR_length */ - insn = final_scan_insn (insn, file, optimize, 0, &seen); + dump_basic_block_info (file, insn, start_to_bb, end_to_bb, + bb_map_size, &bb_seqn); + insn = final_scan_insn (insn, file, optimize_p, 0, &seen); + } + + if (flag_debug_asm) + { + free (start_to_bb); + free (end_to_bb); } } @@ -1758,6 +1865,9 @@ call_from_call_insn (rtx insn) { default: gcc_unreachable (); + case COND_EXEC: + x = COND_EXEC_CODE (x); + break; case PARALLEL: x = XVECEXP (x, 0, 0); break; @@ -1784,7 +1894,7 @@ call_from_call_insn (rtx insn) first. */ rtx -final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, +final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, int nopeepholes ATTRIBUTE_UNUSED, int *seen) { #ifdef HAVE_cc0 @@ -1809,24 +1919,21 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, case NOTE_INSN_SWITCH_TEXT_SECTIONS: in_cold_section_p = !in_cold_section_p; -#ifdef DWARF2_UNWIND_INFO + if (dwarf2out_do_frame ()) dwarf2out_switch_text_section (); - else -#endif - (*debug_hooks->switch_text_section) (); + else if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->switch_text_section (); switch_to_section (current_function_section ()); + targetm.asm_out.function_switched_text_sections (asm_out_file, + current_function_decl, + in_cold_section_p); break; case NOTE_INSN_BASIC_BLOCK: -#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); + if (targetm.asm_out.unwind_emit) + targetm.asm_out.unwind_emit (asm_out_file, insn); if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB) { @@ -1836,6 +1943,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, else *seen |= SEEN_BB; + discriminator = NOTE_BASIC_BLOCK (insn)->discriminator; + break; case NOTE_INSN_EH_REGION_BEG: @@ -1863,12 +1972,22 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_EPILOGUE_BEG: +#if defined (HAVE_epilogue) + if (dwarf2out_do_frame ()) + dwarf2out_cfi_begin_epilogue (insn); +#endif + (*debug_hooks->begin_epilogue) (last_linenum, last_filename); targetm.asm_out.function_begin_epilogue (file); break; + case NOTE_INSN_CFA_RESTORE_STATE: + dwarf2out_frame_debug_restore_state (); + 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) { @@ -1894,7 +2013,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, high_block_linenum = last_linenum; /* Output debugging info about the symbol-block beginning. */ - (*debug_hooks->begin_block) (last_linenum, n); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->begin_block (last_linenum, n); /* Mark this block as output. */ TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; @@ -1928,7 +2048,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, --block_depth; gcc_assert (block_depth >= 0); - (*debug_hooks->end_block) (high_block_linenum, n); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->end_block (high_block_linenum, n); } if (write_symbols == DBX_DEBUG || write_symbols == SDB_DEBUG) @@ -1958,7 +2079,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case NOTE_INSN_VAR_LOCATION: - (*debug_hooks->var_location) (insn); + case NOTE_INSN_CALL_ARG_LOCATION: + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); break; default: @@ -1968,10 +2091,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, break; case BARRIER: -#if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) dwarf2out_frame_debug (insn, false); -#endif break; case CODE_LABEL: @@ -1997,62 +2118,49 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif } } -#ifdef HAVE_cc0 CC_STATUS_INIT; -#endif - if (LABEL_NAME (insn)) - (*debug_hooks->label) (insn); + if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn)) + debug_hooks->label (insn); - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); next = next_nonnote_insn (insn); - if (next != 0 && JUMP_P (next)) + /* If this label is followed by a jump-table, make sure we put + the label in the read-only section. Also possibly write the + label and jump table together. */ + if (next != 0 && JUMP_TABLE_DATA_P (next)) { - rtx nextbody = PATTERN (next); - - /* If this label is followed by a jump-table, - make sure we put the label in the read-only section. Also - possibly write the label and jump table together. */ - - if (GET_CODE (nextbody) == ADDR_VEC - || GET_CODE (nextbody) == ADDR_DIFF_VEC) - { #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) - /* In this case, the case vector is being moved by the - target, so don't output the label at all. Leave that - to the back end macros. */ + /* In this case, the case vector is being moved by the + target, so don't output the label at all. Leave that + to the back end macros. */ #else - if (! JUMP_TABLES_IN_TEXT_SECTION) - { - int log_align; + if (! JUMP_TABLES_IN_TEXT_SECTION) + { + int log_align; - switch_to_section (targetm.asm_out.function_rodata_section - (current_function_decl)); + switch_to_section (targetm.asm_out.function_rodata_section + (current_function_decl)); #ifdef ADDR_VEC_ALIGN - log_align = ADDR_VEC_ALIGN (next); + log_align = ADDR_VEC_ALIGN (next); #else - log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); + log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); #endif - ASM_OUTPUT_ALIGN (file, log_align); - } - else - switch_to_section (current_function_section ()); + ASM_OUTPUT_ALIGN (file, log_align); + } + else + switch_to_section (current_function_section ()); #ifdef ASM_OUTPUT_CASE_LABEL - ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), - next); + ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), + next); #else - targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); #endif #endif - break; - } + break; } if (LABEL_ALT_ENTRY_P (insn)) output_alternate_entry_point (file, insn); @@ -2065,11 +2173,11 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, rtx body = PATTERN (insn); int insn_code_number; const char *templ; + bool is_stmt; -#ifdef HAVE_conditional_execution /* Reset this early so it is correct for ASM statements. */ current_insn_predicate = NULL_RTX; -#endif + /* An INSN, JUMP_INSN or CALL_INSN. First check for special kinds that recog doesn't recognize. */ @@ -2108,11 +2216,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, else switch_to_section (current_function_section ()); - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) if (GET_CODE (body) == ADDR_VEC) @@ -2170,10 +2274,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, } /* Output this line note if it is the first or the last line note in a row. */ - if (notice_source_line (insn)) - { - (*debug_hooks->source_line) (last_linenum, last_filename); - } + if (!DECL_IGNORED_P (current_function_decl) + && notice_source_line (insn, &is_stmt)) + (*debug_hooks->source_line) (last_linenum, last_filename, + last_discriminator, is_stmt); if (GET_CODE (body) == ASM_INPUT) { @@ -2186,11 +2290,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, { expanded_location loc; - if (! app_on) - { - fputs (ASM_APP_ON, file); - app_on = 1; - } + app_enable (); loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body)); if (*loc.file && loc.line) fprintf (asm_out_file, "%s %i \"%s\" 1\n", @@ -2213,6 +2313,11 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, location_t loc; expanded_location expanded; + /* Make sure we flush any queued register saves in case this + clobbers affected registers. */ + if (dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn, false); + /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; @@ -2230,11 +2335,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* Output the insn using them. */ if (string[0]) { - if (! app_on) - { - fputs (ASM_APP_ON, file); - app_on = 1; - } + app_enable (); if (expanded.file && expanded.line) fprintf (asm_out_file, "%s %i \"%s\" 1\n", ASM_COMMENT_START, expanded.line, expanded.file); @@ -2245,15 +2346,15 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #endif } + if (targetm.asm_out.final_postscan_insn) + targetm.asm_out.final_postscan_insn (file, insn, ops, + insn_noperands); + this_is_asm_operands = 0; break; } - if (app_on) - { - fputs (ASM_APP_OFF, file); - app_on = 0; - } + app_disable (); if (GET_CODE (body) == SEQUENCE) { @@ -2264,11 +2365,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* Record the delay slots' frame information before the branch. This is needed for delayed calls: see execute_cfa_program(). */ -#if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) for (i = 1; i < XVECLEN (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 force the restoration of a comparison that was previously @@ -2324,15 +2423,19 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, and the next statement should reexamine the variable to compute the condition codes. */ - if (optimize) + if (optimize_p) { if (set && 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) @@ -2340,11 +2443,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) @@ -2358,9 +2468,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 @@ -2500,7 +2608,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, #ifdef HAVE_peephole /* Do machine-specific peephole optimizations if desired. */ - if (optimize && !flag_no_peephole && !nopeepholes) + if (optimize_p && !flag_no_peephole && !nopeepholes) { rtx next = peephole (insn); /* When peepholing, if there were notes within the peephole, @@ -2511,7 +2619,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, for (note = NEXT_INSN (insn); note != next; note = NEXT_INSN (note)) - final_scan_insn (note, file, optimize, nopeepholes, seen); + final_scan_insn (note, file, optimize_p, nopeepholes, seen); /* Put the notes in the proper position for a later rescan. For example, the SH target can do this @@ -2557,10 +2665,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); #endif -#ifdef HAVE_conditional_execution - if (GET_CODE (PATTERN (insn)) == COND_EXEC) + if (targetm.have_conditional_execution () + && GET_CODE (PATTERN (insn)) == COND_EXEC) current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); -#endif #ifdef HAVE_cc0 cc_prev_status = cc_status; @@ -2575,10 +2682,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, current_output_insn = debug_insn = insn; -#if defined (DWARF2_UNWIND_INFO) if (CALL_P (insn) && dwarf2out_do_frame ()) dwarf2out_frame_debug (insn, false); -#endif /* Find the proper template for this insn. */ templ = get_insn_template (insn_code_number, insn); @@ -2627,12 +2732,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, return new_rtx; } -#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 + if (targetm.asm_out.unwind_emit_before_insn + && targetm.asm_out.unwind_emit) + targetm.asm_out.unwind_emit (asm_out_file, insn); if (CALL_P (insn)) { @@ -2646,22 +2751,32 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, if (t) assemble_external (t); } + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); } /* Output assembler code from the template. */ output_asm_insn (templ, recog_data.operand); + /* 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 and call instructions. */ -#if defined (DWARF2_UNWIND_INFO) if (final_sequence == 0 #if !defined (HAVE_prologue) && !ACCUMULATE_OUTGOING_ARGS #endif && dwarf2out_do_frame ()) dwarf2out_frame_debug (insn, true); -#endif + + if (!targetm.asm_out.unwind_emit_before_insn + && targetm.asm_out.unwind_emit) + targetm.asm_out.unwind_emit (asm_out_file, insn); current_output_insn = debug_insn = 0; } @@ -2669,10 +2784,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, return NEXT_INSN (insn); } -/* Return whether a source line note needs to be emitted before INSN. */ +/* Return whether a source line note needs to be emitted before INSN. + Sets IS_STMT to TRUE if the line should be marked as a possible + breakpoint location. */ static bool -notice_source_line (rtx insn) +notice_source_line (rtx insn, bool *is_stmt) { const char *filename; int linenum; @@ -2688,18 +2805,33 @@ notice_source_line (rtx insn) linenum = insn_line (insn); } - if (filename - && (force_source_line - || filename != last_filename - || last_linenum != linenum)) + if (filename == NULL) + return false; + + if (force_source_line + || filename != last_filename + || last_linenum != linenum) { force_source_line = false; last_filename = filename; last_linenum = linenum; + last_discriminator = discriminator; + *is_stmt = true; high_block_linenum = MAX (last_linenum, high_block_linenum); high_function_linenum = MAX (last_linenum, high_function_linenum); return true; } + + if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator) + { + /* If the discriminator changed, but the line number did not, + output the line table entry with is_stmt false so the + debugger does not treat this as a breakpoint location. */ + last_discriminator = discriminator; + *is_stmt = false; + return true; + } + return false; } @@ -3079,7 +3211,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); @@ -3255,7 +3387,7 @@ output_asm_insn (const char *templ, rtx *operands) outputs an operand in a special way depending on the letter. Letters `acln' are implemented directly. Other letters are passed to `output_operand' so that - the PRINT_OPERAND macro can define them. */ + the TARGET_PRINT_OPERAND hook can define them. */ else if (ISALPHA (*p)) { int letter = *p++; @@ -3282,7 +3414,7 @@ output_asm_insn (const char *templ, 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 @@ -3321,12 +3453,10 @@ output_asm_insn (const char *templ, rtx *operands) c = *p; } /* % followed by punctuation: output something for that - punctuation character alone, with no operand. - The PRINT_OPERAND macro decides what is actually done. */ -#ifdef PRINT_OPERAND_PUNCT_VALID_P - else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p)) + punctuation character alone, with no operand. The + TARGET_PRINT_OPERAND hook decides what is actually done. */ + else if (targetm.asm_out.print_operand_punct_valid_p ((unsigned char) *p)) output_operand (NULL_RTX, *p++); -#endif else output_operand_lossage ("invalid %%-code"); break; @@ -3363,17 +3493,50 @@ 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, such as 'z' if the spec was `%z3'. CODE is 0 if there was no char between the % and the digits. When CODE is a non-letter, X is 0. The meanings of the letters are machine-dependent and controlled - by PRINT_OPERAND. */ + by TARGET_PRINT_OPERAND. */ -static void +void output_operand (rtx x, int code ATTRIBUTE_UNUSED) { if (x && GET_CODE (x) == SUBREG) @@ -3382,27 +3545,23 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED) /* 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); - 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); - } + targetm.asm_out.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 - using machine-dependent assembler syntax. - The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ +/* Print a memory reference operand for address X using + machine-dependent assembler syntax. */ void output_address (rtx x) { bool changed = false; walk_alter_subreg (&x, &changed); - PRINT_OPERAND_ADDRESS (asm_out_file, x); + targetm.asm_out.print_operand_address (asm_out_file, x); } /* Print an integer constant expression in assembler syntax. @@ -3423,7 +3582,7 @@ output_addr_const (FILE *file, rtx x) case SYMBOL_REF: if (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 @@ -3480,7 +3639,7 @@ output_addr_const (FILE *file, rtx x) case PLUS: /* Some assemblers need integer constants to appear last (eg masm). */ - if (GET_CODE (XEXP (x, 0)) == CONST_INT) + if (CONST_INT_P (XEXP (x, 0))) { output_addr_const (file, XEXP (x, 1)); if (INTVAL (XEXP (x, 0)) >= 0) @@ -3490,7 +3649,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)); @@ -3506,7 +3665,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)); @@ -3526,16 +3685,39 @@ output_addr_const (FILE *file, rtx x) break; default: -#ifdef OUTPUT_ADDR_CONST_EXTRA - OUTPUT_ADDR_CONST_EXTRA (file, x, fail); - break; + if (targetm.asm_out.output_addr_const_extra (file, x)) + break; - fail: -#endif output_operand_lossage ("invalid expression as operand"); } } +/* Output a quoted string. */ + +void +output_quoted_string (FILE *asm_file, const char *string) +{ +#ifdef OUTPUT_QUOTED_STRING + OUTPUT_QUOTED_STRING (asm_file, string); +#else + char c; + + putc ('\"', asm_file); + while ((c = *string++) != 0) + { + if (ISPRINT (c)) + { + if (c == '\"' || c == '\\') + putc ('\\', asm_file); + putc (c, asm_file); + } + else + fprintf (asm_file, "\\%03o", (unsigned char) c); + } + putc ('\"', asm_file); +#endif +} + /* A poor man's fprintf, with the added features of %I, %R, %L, and %U. %R prints the value of REGISTER_PREFIX. %L prints the value of LOCAL_LABEL_PREFIX. @@ -3714,7 +3896,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)) { @@ -3723,10 +3905,11 @@ split_double (rtx value, rtx *first, rtx *second) Sign extend each half to HOST_WIDE_INT. */ unsigned HOST_WIDE_INT low, high; unsigned HOST_WIDE_INT mask, sign_bit, sign_extend; + unsigned bits_per_word = BITS_PER_WORD; /* Set sign_bit to the most significant bit of a word. */ sign_bit = 1; - sign_bit <<= BITS_PER_WORD - 1; + sign_bit <<= bits_per_word - 1; /* Set mask so that all bits of the word are set. We could have used 1 << BITS_PER_WORD instead of basing the @@ -3749,7 +3932,7 @@ split_double (rtx value, rtx *first, rtx *second) /* Pick the higher word, shifted to the least significant bits, and sign-extend it. */ high = INTVAL (value); - high >>= BITS_PER_WORD - 1; + high >>= bits_per_word - 1; high >>= 1; high &= mask; if (high & sign_bit) @@ -4041,87 +4224,6 @@ leaf_renumber_regs_insn (rtx in_rtx) } } #endif - - -/* When -gused is used, emit debug info for only used symbols. But in - addition to the standard intercepted debug_hooks there are some direct - calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params. - Those routines may also be called from a higher level intercepted routine. So - to prevent recording data for an inner call to one of these for an intercept, - we maintain an intercept nesting counter (debug_nesting). We only save the - intercepted arguments if the nesting is 1. */ -int debug_nesting = 0; - -static tree *symbol_queue; -int symbol_queue_index = 0; -static int symbol_queue_size = 0; - -/* Generate the symbols for any queued up type symbols we encountered - while generating the type info for some originally used symbol. - This might generate additional entries in the queue. Only when - the nesting depth goes to 0 is this routine called. */ - -void -debug_flush_symbol_queue (void) -{ - int i; - - /* Make sure that additionally queued items are not flushed - prematurely. */ - - ++debug_nesting; - - for (i = 0; i < symbol_queue_index; ++i) - { - /* 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 - which may be set for outside reasons. */ - int saved_tree_used = TREE_USED (symbol_queue[i]); - int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]); - TREE_USED (symbol_queue[i]) = 1; - TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0; - -#ifdef DBX_DEBUGGING_INFO - dbxout_symbol (symbol_queue[i], 0); -#endif - - TREE_USED (symbol_queue[i]) = saved_tree_used; - TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug; - } - - symbol_queue_index = 0; - --debug_nesting; -} - -/* Queue a type symbol needed as part of the definition of a decl - symbol. These symbols are generated when debug_flush_symbol_queue() - is called. */ - -void -debug_queue_symbol (tree decl) -{ - if (symbol_queue_index >= symbol_queue_size) - { - symbol_queue_size += 10; - symbol_queue = XRESIZEVEC (tree, symbol_queue, symbol_queue_size); - } - - symbol_queue[symbol_queue_index++] = decl; -} - -/* Free symbol queue. */ -void -debug_free_queue (void) -{ - if (symbol_queue) - { - free (symbol_queue); - symbol_queue = NULL; - symbol_queue_size = 0; - } -} /* Turn the RTL into assembly. */ static unsigned int @@ -4144,19 +4246,13 @@ rest_of_handle_final (void) 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. */ + /* The IA-64 ".handlerdata" directive must be issued before the ".endp" + directive that closes the procedure descriptor. Similarly, for x64 SEH. + Otherwise it's not strictly necessary, but it doesn't hurt either. */ 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. */ @@ -4177,8 +4273,13 @@ rest_of_handle_final (void) *will* be routed past here. */ timevar_push (TV_SYMOUT); - (*debug_hooks->function_decl) (current_function_decl); + if (!DECL_IGNORED_P (current_function_decl)) + debug_hooks->function_decl (current_function_decl); timevar_pop (TV_SYMOUT); + + /* Release the blocks that are linked to DECL_INITIAL() to free the memory. */ + DECL_INITIAL (current_function_decl) = error_mark_node; + if (DECL_STATIC_CONSTRUCTOR (current_function_decl) && targetm.have_ctors_dtors) targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0), @@ -4196,7 +4297,7 @@ struct rtl_opt_pass pass_final = { { RTL_PASS, - NULL, /* name */ + "final", /* name */ NULL, /* gate */ rest_of_handle_final, /* execute */ NULL, /* sub */ @@ -4244,6 +4345,51 @@ 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: %m", + flag_dump_final_insns); + flag_dump_final_insns = NULL; + } + else + { + const char *aname; + struct cgraph_node *node = cgraph_get_node (current_function_decl); + + aname = (IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (current_function_decl))); + fprintf (final_output, "\n;; Function (%s) %s\n\n", aname, + node->frequency == NODE_FREQUENCY_HOT + ? " (hot)" + : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED + ? " (unlikely executed)" + : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE + ? " (executed once)" + : ""); + + flag_dump_noaddr = flag_dump_unnumbered = 1; + if (flag_compare_debug_opt || flag_compare_debug) + dump_flags |= TDF_NOUID; + final_insns_dump_p = true; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (LABEL_P (insn)) + INSN_UID (insn) = CODE_LABEL_NUMBER (insn); + else + { + if (NOTE_P (insn)) + set_block_for_insn (insn, NULL); + 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 @@ -4254,6 +4400,29 @@ rest_of_clean_state (void) next = NEXT_INSN (insn); NEXT_INSN (insn) = NULL; PREV_INSN (insn) = NULL; + + if (final_output + && (!NOTE_P (insn) || + (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION + && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_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; + final_insns_dump_p = false; + + if (fclose (final_output)) + { + error ("could not close final insn dump file %qs: %m", + flag_dump_final_insns); + flag_dump_final_insns = NULL; + } } /* In case the function was not output, @@ -4264,6 +4433,7 @@ rest_of_clean_state (void) sdbout_types (NULL_TREE); #endif + flag_rerun_cse_after_global_opts = 0; reload_completed = 0; epilogue_completed = 0; #ifdef STACK_REGS @@ -4279,7 +4449,12 @@ rest_of_clean_state (void) free_bb_for_insn (); - if (targetm.binds_local_p (current_function_decl)) + delete_tree_ssa (); + + /* We can reduce stack alignment on call site only when we are sure that + the function body just produced will be actually used in the final + executable. */ + if (decl_binds_to_current_def_p (current_function_decl)) { unsigned int pref = crtl->preferred_stack_boundary; if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary) @@ -4308,7 +4483,7 @@ struct rtl_opt_pass pass_clean_state = { { RTL_PASS, - NULL, /* name */ + "*clean_state", /* name */ NULL, /* gate */ rest_of_clean_state, /* execute */ NULL, /* sub */ @@ -4322,4 +4497,3 @@ struct rtl_opt_pass pass_clean_state = 0 /* todo_flags_finish */ } }; -