Mercurial > hg > CbC > CbC_gcc
diff gcc/final.c @ 132:d34655255c78
update gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 10:21:07 +0900 |
parents | 84e7813d76e9 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/final.c Thu Oct 25 08:08:40 2018 +0900 +++ b/gcc/final.c Thu Oct 25 10:21:07 2018 +0900 @@ -1,5 +1,5 @@ /* Convert RTL to assembler code and output it, for GNU compiler. - Copyright (C) 1987-2017 Free Software Foundation, Inc. + Copyright (C) 1987-2018 Free Software Foundation, Inc. This file is part of GCC. @@ -92,8 +92,6 @@ #include "dbxout.h" #endif -#include "sdbout.h" - /* 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 @@ -112,6 +110,7 @@ /* Bitflags used by final_scan_insn. */ #define SEEN_NOTE 1 #define SEEN_EMITTED 2 +#define SEEN_NEXT_VIEW 4 /* Last insn processed by final_scan_insn. */ static rtx_insn *debug_insn; @@ -123,12 +122,20 @@ /* Column number of last NOTE. */ static int last_columnnum; -/* Last discriminator written to assembly. */ +/* Discriminator written to assembly. */ static int last_discriminator; -/* Discriminator of current block. */ +/* Discriminator to be written to assembly for current instruction. + Note: actual usage depends on loc_discriminator_kind setting. */ static int discriminator; +/* Discriminator identifying current basic block among others sharing + the same locus. */ +static int bb_discriminator; + +/* Basic block discriminator for previous instruction. */ +static int last_bb_discriminator; + /* Highest line number in current block. */ static int high_block_linenum; @@ -198,7 +205,7 @@ /* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ rtx current_insn_predicate; -/* True if printing into -fdump-final-insns= dump. */ +/* True if printing into -fdump-final-insns= dump. */ bool final_insns_dump_p; /* True if profile_function should be called, but hasn't been called yet. */ @@ -328,15 +335,9 @@ for each insn we'll call the alignment chain of this insn in the following comments. */ -struct label_alignment -{ - short alignment; - short max_skip; -}; - static rtx *uid_align; static int *uid_shuid; -static struct label_alignment *label_align; +static vec<align_flags> label_align; /* Indicate that branch shortening hasn't yet been done. */ @@ -474,11 +475,11 @@ address mod X to one mod Y, which is Y - X. */ #ifndef LABEL_ALIGN -#define LABEL_ALIGN(LABEL) align_labels_log +#define LABEL_ALIGN(LABEL) align_labels #endif #ifndef LOOP_ALIGN -#define LOOP_ALIGN(LABEL) align_loops_log +#define LOOP_ALIGN(LABEL) align_loops #endif #ifndef LABEL_ALIGN_AFTER_BARRIER @@ -486,33 +487,9 @@ #endif #ifndef JUMP_ALIGN -#define JUMP_ALIGN(LABEL) align_jumps_log +#define JUMP_ALIGN(LABEL) align_jumps #endif -int -default_label_align_after_barrier_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED) -{ - return 0; -} - -int -default_loop_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED) -{ - return align_loops_max_skip; -} - -int -default_label_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED) -{ - return align_labels_max_skip; -} - -int -default_jump_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED) -{ - return align_jumps_max_skip; -} - #ifndef ADDR_VEC_ALIGN static int final_addr_vec_align (rtx_jump_table_data *addr_vec) @@ -537,27 +514,16 @@ static int min_labelno, max_labelno; #define LABEL_TO_ALIGNMENT(LABEL) \ - (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment) - -#define LABEL_TO_MAX_SKIP(LABEL) \ - (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip) + (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno]) /* For the benefit of port specific code do this also as a function. */ -int +align_flags label_to_alignment (rtx 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; + return align_flags (); } /* The differences in addresses @@ -605,8 +571,8 @@ align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid]; if (uid_shuid[uid] > end_shuid) break; - known_align_log = LABEL_TO_ALIGNMENT (align_label); - new_align = 1 << known_align_log; + align_flags alignment = LABEL_TO_ALIGNMENT (align_label); + new_align = 1 << alignment.levels[0].log; if (new_align < known_align) continue; fuzz += (-align_addr ^ growth) & (new_align - known_align); @@ -663,26 +629,19 @@ } } -/* Compute branch alignments based on frequency information in the - CFG. */ +/* Compute branch alignments based on CFG profile. */ unsigned int compute_alignments (void) { - int log, max_skip, max_log; basic_block bb; - int freq_max = 0; - int freq_threshold = 0; - - if (label_align) - { - free (label_align); - label_align = 0; - } + align_flags max_alignment; + + label_align.truncate (0); max_labelno = max_label_num (); min_labelno = get_first_label_num (); - label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1); + label_align.safe_grow_cleared (max_labelno - min_labelno + 1); /* If not optimizing or optimizing for size, don't assign any alignments. */ if (! optimize || optimize_function_for_size_p (cfun)) @@ -695,17 +654,19 @@ flow_loops_dump (dump_file, NULL, 1); } loop_optimizer_init (AVOID_CFG_MODIFICATIONS); - FOR_EACH_BB_FN (bb, cfun) - if (bb->frequency > freq_max) - freq_max = bb->frequency; - freq_threshold = freq_max / PARAM_VALUE (PARAM_ALIGN_THRESHOLD); + profile_count count_threshold = cfun->cfg->count_max.apply_scale + (1, PARAM_VALUE (PARAM_ALIGN_THRESHOLD)); if (dump_file) - fprintf (dump_file, "freq_max: %i\n",freq_max); + { + fprintf (dump_file, "count_max: "); + cfun->cfg->count_max.dump (dump_file); + fprintf (dump_file, "\n"); + } FOR_EACH_BB_FN (bb, cfun) { rtx_insn *label = BB_HEAD (bb); - int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; + bool has_fallthru = 0; edge e; edge_iterator ei; @@ -714,34 +675,40 @@ { if (dump_file) fprintf (dump_file, - "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n", - bb->index, bb->frequency, bb->loop_father->num, + "BB %4i loop %2i loop_depth %2i skipped.\n", + bb->index, + bb->loop_father->num, bb_loop_depth (bb)); continue; } - max_log = LABEL_ALIGN (label); - max_skip = targetm.asm_out.label_align_max_skip (label); + max_alignment = LABEL_ALIGN (label); + profile_count fallthru_count = profile_count::zero (); + profile_count branch_count = profile_count::zero (); FOR_EACH_EDGE (e, ei, bb->preds) { if (e->flags & EDGE_FALLTHRU) - has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); + has_fallthru = 1, fallthru_count += e->count (); else - branch_frequency += EDGE_FREQUENCY (e); + branch_count += e->count (); } if (dump_file) { - fprintf (dump_file, "BB %4i freq %4i loop %2i loop_depth" - " %2i fall %4i branch %4i", - bb->index, bb->frequency, bb->loop_father->num, - bb_loop_depth (bb), - fallthru_frequency, branch_frequency); + fprintf (dump_file, "BB %4i loop %2i loop_depth" + " %2i fall ", + bb->index, bb->loop_father->num, + bb_loop_depth (bb)); + fallthru_count.dump (dump_file); + fprintf (dump_file, " branch "); + branch_count.dump (dump_file); if (!bb->loop_father->inner && bb->loop_father->num) fprintf (dump_file, " inner_loop"); if (bb->loop_father->header == bb) fprintf (dump_file, " loop_header"); fprintf (dump_file, "\n"); } + if (!fallthru_count.initialized_p () || !branch_count.initialized_p ()) + continue; /* There are two purposes to align block with no fallthru incoming edge: 1) to avoid fetch stalls when branch destination is near cache boundary @@ -754,19 +721,16 @@ when function is called. */ if (!has_fallthru - && (branch_frequency > freq_threshold - || (bb->frequency > bb->prev_bb->frequency * 10 - && (bb->prev_bb->frequency - <= ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency / 2)))) + && (branch_count > count_threshold + || (bb->count > bb->prev_bb->count.apply_scale (10, 1) + && (bb->prev_bb->count + <= ENTRY_BLOCK_PTR_FOR_FN (cfun) + ->count.apply_scale (1, 2))))) { - log = JUMP_ALIGN (label); + align_flags alignment = JUMP_ALIGN (label); if (dump_file) fprintf (dump_file, " jump alignment added.\n"); - if (max_log < log) - { - max_log = log; - max_skip = targetm.asm_out.jump_align_max_skip (label); - } + max_alignment = align_flags::max (max_alignment, alignment); } /* In case block is frequent and reached mostly by non-fallthru edge, align it. It is most likely a first block of loop. */ @@ -774,21 +738,17 @@ && !(single_succ_p (bb) && single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun)) && optimize_bb_for_speed_p (bb) - && branch_frequency + fallthru_frequency > freq_threshold - && (branch_frequency - > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS))) + && branch_count + fallthru_count > count_threshold + && (branch_count + > fallthru_count.apply_scale + (PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS), 1))) { - log = LOOP_ALIGN (label); + align_flags alignment = LOOP_ALIGN (label); if (dump_file) fprintf (dump_file, " internal loop alignment added.\n"); - if (max_log < log) - { - max_log = log; - max_skip = targetm.asm_out.loop_align_max_skip (label); - } + max_alignment = align_flags::max (max_alignment, alignment); } - LABEL_TO_ALIGNMENT (label) = max_log; - LABEL_TO_MAX_SKIP (label) = max_skip; + LABEL_TO_ALIGNMENT (label) = max_alignment; } loop_optimizer_finalize (); @@ -798,7 +758,7 @@ /* Grow the LABEL_ALIGN array after new labels are created. */ -static void +static void grow_label_align (void) { int old = max_labelno; @@ -810,14 +770,11 @@ n_labels = max_labelno - min_labelno + 1; n_old_labels = old - min_labelno + 1; - label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels); + label_align.safe_grow_cleared (n_labels); /* Range of labels grows monotonically in the function. Failing here means that the initialization of array got lost. */ gcc_assert (n_old_labels <= n_labels); - - memset (label_align + n_old_labels, 0, - (n_labels - n_old_labels) * sizeof (struct label_alignment)); } /* Update the already computed alignment information. LABEL_PAIRS is a vector @@ -835,10 +792,7 @@ FOR_EACH_VEC_ELT (label_pairs, i, iter) if (i & 1) - { - LABEL_TO_ALIGNMENT (label) = LABEL_TO_ALIGNMENT (iter); - LABEL_TO_MAX_SKIP (label) = LABEL_TO_MAX_SKIP (iter); - } + LABEL_TO_ALIGNMENT (label) = LABEL_TO_ALIGNMENT (iter); else label = iter; } @@ -896,15 +850,12 @@ rtx_insn *insn; int max_uid; int i; - int max_log; - int max_skip; -#define MAX_CODE_ALIGN 16 rtx_insn *seq; int something_changed = 1; char *varying_length; rtx body; int uid; - rtx align_tab[MAX_CODE_ALIGN]; + rtx align_tab[MAX_CODE_ALIGN + 1]; /* Compute maximum UID and allocate label_align / uid_shuid. */ max_uid = get_max_uid (); @@ -919,17 +870,14 @@ /* Initialize label_align and set up uid_shuid to be strictly monotonically rising with insn order. */ - /* We use max_log here to keep track of the maximum alignment we want to + /* We use alignment here to keep track of the maximum alignment we want to impose on the next CODE_LABEL (or the current one if we are processing the CODE_LABEL itself). */ - max_log = 0; - max_skip = 0; + align_flags max_alignment; for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) { - int log; - INSN_SHUID (insn) = i++; if (INSN_P (insn)) continue; @@ -937,22 +885,14 @@ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn)) { /* Merge in alignments computed by compute_alignments. */ - log = LABEL_TO_ALIGNMENT (label); - if (max_log < log) - { - max_log = log; - max_skip = LABEL_TO_MAX_SKIP (label); - } + align_flags alignment = LABEL_TO_ALIGNMENT (label); + max_alignment = align_flags::max (max_alignment, alignment); rtx_jump_table_data *table = jump_table_for_label (label); if (!table) { - log = LABEL_ALIGN (label); - if (max_log < log) - { - max_log = log; - max_skip = targetm.asm_out.label_align_max_skip (label); - } + align_flags alignment = LABEL_ALIGN (label); + max_alignment = align_flags::max (max_alignment, alignment); } /* ADDR_VECs only take room if read-only data goes into the text section. */ @@ -960,17 +900,11 @@ || readonly_data_section == text_section) && table) { - log = ADDR_VEC_ALIGN (table); - if (max_log < log) - { - max_log = log; - max_skip = targetm.asm_out.label_align_max_skip (label); - } + align_flags alignment = align_flags (ADDR_VEC_ALIGN (table)); + max_alignment = align_flags::max (max_alignment, alignment); } - LABEL_TO_ALIGNMENT (label) = max_log; - LABEL_TO_MAX_SKIP (label) = max_skip; - max_log = 0; - max_skip = 0; + LABEL_TO_ALIGNMENT (label) = max_alignment; + max_alignment = align_flags (); } else if (BARRIER_P (insn)) { @@ -980,12 +914,9 @@ label = NEXT_INSN (label)) if (LABEL_P (label)) { - log = LABEL_ALIGN_AFTER_BARRIER (insn); - if (max_log < log) - { - max_log = log; - max_skip = targetm.asm_out.label_align_after_barrier_max_skip (label); - } + align_flags alignment + = align_flags (LABEL_ALIGN_AFTER_BARRIER (insn)); + max_alignment = align_flags::max (max_alignment, alignment); break; } } @@ -1009,18 +940,19 @@ alignment of n. */ uid_align = XCNEWVEC (rtx, max_uid); - for (i = MAX_CODE_ALIGN; --i >= 0;) + for (i = MAX_CODE_ALIGN + 1; --i >= 0;) align_tab[i] = NULL_RTX; seq = get_last_insn (); for (; seq; seq = PREV_INSN (seq)) { int uid = INSN_UID (seq); int log; - log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0); + log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq).levels[0].log : 0); uid_align[uid] = align_tab[0]; if (log) { /* Found an alignment label. */ + gcc_checking_assert (log < MAX_CODE_ALIGN + 1); uid_align[uid] = align_tab[log]; for (i = log - 1; i >= 0; i--) align_tab[i] = seq; @@ -1071,8 +1003,10 @@ max = shuid; max_lab = lab; } - if (min_align > LABEL_TO_ALIGNMENT (lab)) - min_align = LABEL_TO_ALIGNMENT (lab); + + int label_alignment = LABEL_TO_ALIGNMENT (lab).levels[0].log; + if (min_align > label_alignment) + min_align = label_alignment; } XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab); XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab); @@ -1106,7 +1040,7 @@ if (LABEL_P (insn)) { - int log = LABEL_TO_ALIGNMENT (insn); + int log = LABEL_TO_ALIGNMENT (insn).levels[0].log; if (log) { int align = 1 << log; @@ -1214,7 +1148,7 @@ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn)) { - int log = LABEL_TO_ALIGNMENT (label); + int log = LABEL_TO_ALIGNMENT (label).levels[0].log; #ifdef CASE_VECTOR_SHORTEN_MODE /* If the mode of a following jump table was changed, we @@ -1289,7 +1223,7 @@ prev = PREV_INSN (prev)) if (varying_length[INSN_UID (prev)] & 2) { - rel_align = LABEL_TO_ALIGNMENT (prev); + rel_align = LABEL_TO_ALIGNMENT (prev).levels[0].log; break; } @@ -1501,72 +1435,6 @@ return count; } -/* ??? This is probably the wrong place for these. */ -/* Structure recording the mapping from source file and directory - names at compile time to those to be embedded in debug - information. */ -struct debug_prefix_map -{ - const char *old_prefix; - const char *new_prefix; - size_t old_len; - size_t new_len; - struct debug_prefix_map *next; -}; - -/* Linked list of such structures. */ -static debug_prefix_map *debug_prefix_maps; - - -/* Record a debug file prefix mapping. ARG is the argument to - -fdebug-prefix-map and must be of the form OLD=NEW. */ - -void -add_debug_prefix_map (const char *arg) -{ - debug_prefix_map *map; - const char *p; - - p = strchr (arg, '='); - if (!p) - { - error ("invalid argument %qs to -fdebug-prefix-map", arg); - return; - } - map = XNEW (debug_prefix_map); - map->old_prefix = xstrndup (arg, p - arg); - map->old_len = p - arg; - p++; - map->new_prefix = xstrdup (p); - map->new_len = strlen (p); - map->next = debug_prefix_maps; - debug_prefix_maps = map; -} - -/* Perform user-specified mapping of debug filename prefixes. Return - the new name corresponding to FILENAME. */ - -const char * -remap_debug_filename (const char *filename) -{ - debug_prefix_map *map; - char *s; - const char *name; - size_t name_len; - - for (map = debug_prefix_maps; map; map = map->next) - if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0) - break; - if (!map) - return filename; - name = filename + map->old_len; - name_len = strlen (name) + 1; - s = (char *) alloca (name_len + map->new_len); - memcpy (s, map->new_prefix, map->new_len); - memcpy (s + map->new_len, name, name_len); - return ggc_strdup (s); -} - /* Return true if DWARF2 debug info can be emitted for DECL. */ static bool @@ -1646,7 +1514,6 @@ { tree cur_block = DECL_INITIAL (cfun->decl); rtx_insn *insn; - rtx_note *note; insn = get_insns (); for (; insn; insn = NEXT_INSN (insn)) @@ -1654,17 +1521,30 @@ tree this_block; /* Prevent lexical blocks from straddling section boundaries. */ - if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) - { - for (tree s = cur_block; s != DECL_INITIAL (cfun->decl); - s = BLOCK_SUPERCONTEXT (s)) - { - rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn); - NOTE_BLOCK (note) = s; - note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn); - NOTE_BLOCK (note) = s; - } - } + if (NOTE_P (insn)) + switch (NOTE_KIND (insn)) + { + case NOTE_INSN_SWITCH_TEXT_SECTIONS: + { + for (tree s = cur_block; s != DECL_INITIAL (cfun->decl); + s = BLOCK_SUPERCONTEXT (s)) + { + rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn); + NOTE_BLOCK (note) = s; + note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn); + NOTE_BLOCK (note) = s; + } + } + break; + + case NOTE_INSN_BEGIN_STMT: + case NOTE_INSN_INLINE_ENTRY: + this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn)); + goto set_cur_block_to_this_block; + + default: + continue; + } if (!active_insn_p (insn)) continue; @@ -1685,6 +1565,7 @@ this_block = choose_inner_scope (this_block, insn_scope (body->insn (i))); } + set_cur_block_to_this_block: if (! this_block) { if (INSN_LOCATION (insn) == UNKNOWN_LOCATION) @@ -1701,7 +1582,7 @@ } /* change_scope emits before the insn, not after. */ - note = emit_note (NOTE_INSN_DELETED); + rtx_note *note = emit_note (NOTE_INSN_DELETED); change_scope (note, cur_block, DECL_INITIAL (cfun->decl)); delete_insn (note); @@ -1740,6 +1621,67 @@ return 0; } +/* Arrange for us to emit a source location note before any further + real insns or section changes, by setting the SEEN_NEXT_VIEW bit in + *SEEN, as long as we are keeping track of location views. The bit + indicates we have referenced the next view at the current PC, so we + have to emit it. This should be called next to the var_location + debug hook. */ + +static inline void +set_next_view_needed (int *seen) +{ + if (debug_variable_location_views) + *seen |= SEEN_NEXT_VIEW; +} + +/* Clear the flag in *SEEN indicating we need to emit the next view. + This should be called next to the source_line debug hook. */ + +static inline void +clear_next_view_needed (int *seen) +{ + *seen &= ~SEEN_NEXT_VIEW; +} + +/* Test whether we have a pending request to emit the next view in + *SEEN, and emit it if needed, clearing the request bit. */ + +static inline void +maybe_output_next_view (int *seen) +{ + if ((*seen & SEEN_NEXT_VIEW) != 0) + { + clear_next_view_needed (seen); + (*debug_hooks->source_line) (last_linenum, last_columnnum, + last_filename, last_discriminator, + false); + } +} + +/* We want to emit param bindings (before the first begin_stmt) in the + initial view, if we are emitting views. To that end, we may + consume initial notes in the function, processing them in + final_start_function, before signaling the beginning of the + prologue, rather than in final. + + We don't test whether the DECLs are PARM_DECLs: the assumption is + that there will be a NOTE_INSN_BEGIN_STMT marker before any + non-parameter NOTE_INSN_VAR_LOCATION. It's ok if the marker is not + there, we'll just have more variable locations bound in the initial + view, which is consistent with their being bound without any code + that would give them a value. */ + +static inline bool +in_initial_view_p (rtx_insn *insn) +{ + return (!DECL_IGNORED_P (current_function_decl) + && debug_variable_location_views + && insn && GET_CODE (insn) == NOTE + && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION + || NOTE_KIND (insn) == NOTE_INSN_DELETED)); +} + /* 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 @@ -1747,12 +1689,15 @@ FIRST is the first insn of the rtl for the function being compiled. FILE is the file to write assembler code to. + SEEN should be initially set to zero, and it may be updated to + indicate we have references to the next location view, that would + require us to emit it at the current PC. OPTIMIZE_P is nonzero if we should eliminate redundant test and compare insns. */ -void -final_start_function (rtx_insn *first, FILE *file, - int optimize_p ATTRIBUTE_UNUSED) +static void +final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen, + int optimize_p ATTRIBUTE_UNUSED) { block_depth = 0; @@ -1764,14 +1709,28 @@ last_linenum = LOCATION_LINE (prologue_location); last_columnnum = LOCATION_COLUMN (prologue_location); last_discriminator = discriminator = 0; + last_bb_discriminator = bb_discriminator = 0; high_block_linenum = high_function_linenum = last_linenum; if (flag_sanitize & SANITIZE_ADDRESS) asan_function_start (); + rtx_insn *first = *firstp; + if (in_initial_view_p (first)) + { + do + { + final_scan_insn (first, file, 0, 0, seen); + first = NEXT_INSN (first); + } + while (in_initial_view_p (first)); + *firstp = first; + } + if (!DECL_IGNORED_P (current_function_decl)) - debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename); + debug_hooks->begin_prologue (last_linenum, last_columnnum, + last_filename); if (!dwarf2_debug_info_emitted_p (current_function_decl)) dwarf2out_begin_prologue (0, 0, NULL); @@ -1828,14 +1787,15 @@ TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; } - if (warn_frame_larger_than - && get_frame_size () > frame_larger_than_size) - { + unsigned HOST_WIDE_INT min_frame_size + = constant_lower_bound (get_frame_size ()); + if (min_frame_size > (unsigned HOST_WIDE_INT) warn_frame_larger_than_size) + { /* Issue a warning */ warning (OPT_Wframe_larger_than_, - "the frame size of %wd bytes is larger than %wd bytes", - get_frame_size (), frame_larger_than_size); - } + "the frame size of %wu bytes is larger than %wu bytes", + min_frame_size, warn_frame_larger_than_size); + } /* First output the function prologue: code to set up the stack frame. */ targetm.asm_out.function_prologue (file); @@ -1846,6 +1806,17 @@ profile_after_prologue (file); } +/* This is an exported final_start_function_1, callable without SEEN. */ + +void +final_start_function (rtx_insn *first, FILE *file, + int optimize_p ATTRIBUTE_UNUSED) +{ + int seen = 0; + final_start_function_1 (&first, file, &seen, optimize_p); + gcc_assert (seen == 0); +} + static void profile_after_prologue (FILE *file ATTRIBUTE_UNUSED) { @@ -1944,8 +1915,6 @@ 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.initialized_p ()) { fprintf (file, ", count:"); @@ -1977,11 +1946,10 @@ /* Output assembler code for some insns: all or part of a function. For description of args, see `final_start_function', above. */ -void -final (rtx_insn *first, FILE *file, int optimize_p) +static void +final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p) { rtx_insn *insn, *next; - int seen = 0; /* Used for -dA dump. */ basic_block *start_to_bb = NULL; @@ -2041,6 +2009,9 @@ } else insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); + /* final can be seen as an iteration of shorten_branches that + does nothing (since a fixed point has already been reached). */ + insn_last_address = insn_current_address; } dump_basic_block_info (file, insn, start_to_bb, end_to_bb, @@ -2048,6 +2019,8 @@ insn = final_scan_insn (insn, file, optimize_p, 0, &seen); } + maybe_output_next_view (&seen); + if (flag_debug_asm) { free (start_to_bb); @@ -2064,9 +2037,26 @@ delete_insn (insn); } } + +/* This is an exported final_1, callable without SEEN. */ + +void +final (rtx_insn *first, FILE *file, int optimize_p) +{ + /* Those that use the internal final_start_function_1/final_1 API + skip initial debug bind notes in final_start_function_1, and pass + the modified FIRST to final_1. But those that use the public + final_start_function/final APIs, final_start_function can't move + FIRST because it's not passed by reference, so if they were + skipped there, skip them again here. */ + while (in_initial_view_p (first)) + first = NEXT_INSN (first); + + final_1 (first, file, 0, optimize_p); +} const char * -get_insn_template (int code, rtx insn) +get_insn_template (int code, rtx_insn *insn) { switch (insn_data[code].output_format) { @@ -2076,8 +2066,7 @@ return insn_data[code].output.multi[which_alternative]; case INSN_OUTPUT_FORMAT_FUNCTION: gcc_assert (insn); - return (*insn_data[code].output.function) (recog_data.operand, - as_a <rtx_insn *> (insn)); + return (*insn_data[code].output.function) (recog_data.operand, insn); default: gcc_unreachable (); @@ -2154,14 +2143,13 @@ if (!filename) return; - int line_size; - const char *line = location_get_source_line (filename, linenum, &line_size); + char_span line = location_get_source_line (filename, linenum); if (!line) return; fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START, filename, linenum); - /* "line" is not 0-terminated, so we must use line_size. */ - fwrite (line, 1, line_size, asm_out_file); + /* "line" is not 0-terminated, so we must use its length. */ + fwrite (line.get_buffer (), 1, line.length (), asm_out_file); fputc ('\n', asm_out_file); } @@ -2177,9 +2165,9 @@ debug information. We force the emission of a line note after both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG. */ -rtx_insn * -final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, - int nopeepholes ATTRIBUTE_UNUSED, int *seen) +static rtx_insn * +final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, + int nopeepholes ATTRIBUTE_UNUSED, int *seen) { #if HAVE_cc0 rtx set; @@ -2204,10 +2192,26 @@ break; case NOTE_INSN_SWITCH_TEXT_SECTIONS: + maybe_output_next_view (seen); + + output_function_exception_table (0); + + if (targetm.asm_out.unwind_emit) + targetm.asm_out.unwind_emit (asm_out_file, insn); + in_cold_section_p = !in_cold_section_p; + if (in_cold_section_p) + cold_function_name + = clone_function_name (current_function_decl, "cold"); + if (dwarf2out_do_frame ()) - dwarf2out_switch_text_section (); + { + dwarf2out_switch_text_section (); + if (!dwarf2_debug_info_emitted_p (current_function_decl) + && !DECL_IGNORED_P (current_function_decl)) + debug_hooks->switch_text_section (); + } else if (!DECL_IGNORED_P (current_function_decl)) debug_hooks->switch_text_section (); @@ -2219,8 +2223,6 @@ suffixing "cold" to the original function's name. */ if (in_cold_section_p) { - cold_function_name - = clone_function_name (current_function_decl, "cold"); #ifdef ASM_DECLARE_COLD_FUNCTION_NAME ASM_DECLARE_COLD_FUNCTION_NAME (asm_out_file, IDENTIFIER_POINTER @@ -2230,6 +2232,9 @@ ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (cold_function_name)); #endif + if (dwarf2out_do_frame () + && cfun->fde->dw_fde_second_begin != NULL) + ASM_OUTPUT_LABEL (asm_out_file, cfun->fde->dw_fde_second_begin); } break; @@ -2243,8 +2248,7 @@ if (targetm.asm_out.unwind_emit) targetm.asm_out.unwind_emit (asm_out_file, insn); - discriminator = NOTE_BASIC_BLOCK (insn)->discriminator; - + bb_discriminator = NOTE_BASIC_BLOCK (insn)->discriminator; break; case NOTE_INSN_EH_REGION_BEG: @@ -2328,8 +2332,7 @@ TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p; } - if (write_symbols == DBX_DEBUG - || write_symbols == SDB_DEBUG) + if (write_symbols == DBX_DEBUG) { location_t *locus_ptr = block_nonartificial_location (NOTE_BLOCK (insn)); @@ -2344,6 +2347,8 @@ break; case NOTE_INSN_BLOCK_END: + maybe_output_next_view (seen); + if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE || write_symbols == DWARF2_DEBUG @@ -2363,8 +2368,7 @@ gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) == in_cold_section_p); } - if (write_symbols == DBX_DEBUG - || write_symbols == SDB_DEBUG) + if (write_symbols == DBX_DEBUG) { tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn)); location_t *locus_ptr @@ -2399,9 +2403,36 @@ break; case NOTE_INSN_VAR_LOCATION: - case NOTE_INSN_CALL_ARG_LOCATION: if (!DECL_IGNORED_P (current_function_decl)) - debug_hooks->var_location (insn); + { + debug_hooks->var_location (insn); + set_next_view_needed (seen); + } + break; + + case NOTE_INSN_BEGIN_STMT: + gcc_checking_assert (cfun->debug_nonbind_markers); + if (!DECL_IGNORED_P (current_function_decl) + && notice_source_line (insn, NULL)) + { + output_source_line: + (*debug_hooks->source_line) (last_linenum, last_columnnum, + last_filename, last_discriminator, + true); + clear_next_view_needed (seen); + } + break; + + case NOTE_INSN_INLINE_ENTRY: + gcc_checking_assert (cfun->debug_nonbind_markers); + if (!DECL_IGNORED_P (current_function_decl)) + { + if (!notice_source_line (insn, NULL)) + break; + (*debug_hooks->inline_entry) (LOCATION_BLOCK + (NOTE_MARKER_LOCATION (insn))); + goto output_source_line; + } break; default: @@ -2418,20 +2449,20 @@ some insn, e.g. sh.c output_branchy_insn. */ if (CODE_LABEL_NUMBER (insn) <= max_labelno) { - int align = LABEL_TO_ALIGNMENT (insn); -#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN - int max_skip = LABEL_TO_MAX_SKIP (insn); -#endif - - if (align && NEXT_INSN (insn)) + align_flags alignment = LABEL_TO_ALIGNMENT (insn); + if (alignment.levels[0].log && NEXT_INSN (insn)) { #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN - ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); + /* Output both primary and secondary alignment. */ + ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[0].log, + alignment.levels[0].maxskip); + ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[1].log, + alignment.levels[1].maxskip); #else #ifdef ASM_OUTPUT_ALIGN_WITH_NOP - ASM_OUTPUT_ALIGN_WITH_NOP (file, align); + ASM_OUTPUT_ALIGN_WITH_NOP (file, alignment.levels[0].log); #else - ASM_OUTPUT_ALIGN (file, align); + ASM_OUTPUT_ALIGN (file, alignment.levels[0].log); #endif #endif } @@ -2490,7 +2521,15 @@ rtx body = PATTERN (insn); int insn_code_number; const char *templ; - bool is_stmt; + bool is_stmt, *is_stmt_p; + + if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers) + { + is_stmt = false; + is_stmt_p = NULL; + } + else + is_stmt_p = &is_stmt; /* Reset this early so it is correct for ASM statements. */ current_insn_predicate = NULL_RTX; @@ -2588,19 +2627,28 @@ switch_to_section (current_function_section ()); + if (debug_variable_location_views + && !DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); + break; } /* Output this line note if it is the first or the last line note in a row. */ if (!DECL_IGNORED_P (current_function_decl) - && notice_source_line (insn, &is_stmt)) + && notice_source_line (insn, is_stmt_p)) { if (flag_verbose_asm) asm_show_source (last_filename, last_linenum); (*debug_hooks->source_line) (last_linenum, last_columnnum, last_filename, last_discriminator, is_stmt); + clear_next_view_needed (seen); } + else + maybe_output_next_view (seen); + + gcc_checking_assert (!DEBUG_INSN_P (insn)); if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT) @@ -3067,7 +3115,8 @@ /* Let the debug info back-end know about this call. We do this only after the instruction has been emitted because labels that may be created to reference the call instruction must appear after it. */ - if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl)) + if ((debug_variable_location_views || call_insn != NULL) + && !DECL_IGNORED_P (current_function_decl)) debug_hooks->var_location (insn); current_output_insn = debug_insn = 0; @@ -3075,7 +3124,93 @@ } return NEXT_INSN (insn); } + +/* This is a wrapper around final_scan_insn_1 that allows ports to + call it recursively without a known value for SEEN. The value is + saved at the outermost call, and recovered for recursive calls. + Recursive calls MUST pass NULL, or the same pointer if they can + otherwise get to it. */ + +rtx_insn * +final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p, + int nopeepholes, int *seen) +{ + static int *enclosing_seen; + static int recursion_counter; + + gcc_assert (seen || recursion_counter); + gcc_assert (!recursion_counter || !seen || seen == enclosing_seen); + + if (!recursion_counter++) + enclosing_seen = seen; + else if (!seen) + seen = enclosing_seen; + + rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen); + + if (!--recursion_counter) + enclosing_seen = NULL; + + return ret; +} + + +/* Map DECLs to instance discriminators. This is allocated and + defined in ada/gcc-interfaces/trans.c, when compiling with -gnateS. + Mappings from this table are saved and restored for LTO, so + link-time compilation will have this map set, at least in + partitions containing at least one DECL with an associated instance + discriminator. */ + +decl_to_instance_map_t *decl_to_instance_map; + +/* Return the instance number assigned to DECL. */ + +static inline int +map_decl_to_instance (const_tree decl) +{ + int *inst; + + if (!decl_to_instance_map || !decl || !DECL_P (decl)) + return 0; + + inst = decl_to_instance_map->get (decl); + + if (!inst) + return 0; + + return *inst; +} + +/* Set DISCRIMINATOR to the appropriate value, possibly derived from LOC. */ + +static inline void +maybe_set_discriminator (location_t loc) +{ + if (!decl_to_instance_map) + discriminator = bb_discriminator; + else + { + tree block = LOCATION_BLOCK (loc); + + while (block && TREE_CODE (block) == BLOCK + && !inlined_function_outer_scope_p (block)) + block = BLOCK_SUPERCONTEXT (block); + + tree decl; + + if (!block) + decl = current_function_decl; + else if (DECL_P (block)) + decl = block; + else + decl = block_ultimate_origin (block); + + discriminator = map_decl_to_instance (decl); + } +} + /* 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. */ @@ -3086,7 +3221,23 @@ const char *filename; int linenum, columnnum; - if (override_filename) + if (NOTE_MARKER_P (insn)) + { + location_t loc = NOTE_MARKER_LOCATION (insn); + expanded_location xloc = expand_location (loc); + if (xloc.line == 0) + { + gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION + || LOCATION_LOCUS (loc) == BUILTINS_LOCATION); + return false; + } + filename = xloc.file; + linenum = xloc.line; + columnnum = xloc.column; + maybe_set_discriminator (loc); + force_source_line = true; + } + else if (override_filename) { filename = override_filename; linenum = override_linenum; @@ -3098,6 +3249,7 @@ filename = xloc.file; linenum = xloc.line; columnnum = xloc.column; + maybe_set_discriminator (INSN_LOCATION (insn)); } else { @@ -3119,7 +3271,8 @@ last_linenum = linenum; last_columnnum = columnnum; last_discriminator = discriminator; - *is_stmt = true; + if (is_stmt) + *is_stmt = true; high_block_linenum = MAX (last_linenum, high_block_linenum); high_function_linenum = MAX (last_linenum, high_function_linenum); return true; @@ -3131,7 +3284,8 @@ 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; + if (is_stmt) + *is_stmt = false; return true; } @@ -3194,7 +3348,7 @@ We are required to. */ if (MEM_P (y)) { - int offset = SUBREG_BYTE (x); + poly_int64 offset = SUBREG_BYTE (x); /* For paradoxical subregs on big-endian machines, SUBREG_BYTE contains 0 instead of the proper offset. See simplify_subreg. */ @@ -3217,7 +3371,7 @@ { /* Simplify_subreg can't handle some REG cases, but we have to. */ unsigned int regno; - HOST_WIDE_INT offset; + poly_int64 offset; regno = subreg_regno (x); if (subreg_lowpart_p (x)) @@ -3460,16 +3614,20 @@ { if (debug_insn) { + fprintf (asm_out_file, "\t%s %d\t", + ASM_COMMENT_START, INSN_UID (debug_insn)); + + fprintf (asm_out_file, "[c=%d", + insn_cost (debug_insn, optimize_insn_for_speed_p ())); + if (HAVE_ATTR_length) + fprintf (asm_out_file, " l=%d", + get_attr_length (debug_insn)); + fprintf (asm_out_file, "] "); + int num = INSN_CODE (debug_insn); - fprintf (asm_out_file, "\t%s %d\t%s", - ASM_COMMENT_START, INSN_UID (debug_insn), - insn_data[num].name); + fprintf (asm_out_file, "%s", insn_data[num].name); if (insn_data[num].n_alternatives > 1) - fprintf (asm_out_file, "/%d", which_alternative + 1); - - if (HAVE_ATTR_length) - fprintf (asm_out_file, "\t[length = %d]", - get_attr_length (debug_insn)); + fprintf (asm_out_file, "/%d", which_alternative); /* Clear this so only the first assembler insn of any rtl insn will get the special comment for -dp. */ @@ -3815,6 +3973,10 @@ putc (c, asm_out_file); } + /* Try to keep the asm a bit more readable. */ + if ((flag_verbose_asm || flag_print_asm_name) && strlen (templ) < 9) + putc ('\t', asm_out_file); + /* Write out the variable names for operands, if we know them. */ if (flag_verbose_asm) output_asm_operand_names (operands, oporder, ops); @@ -4448,11 +4610,9 @@ break; case 'E': - if (NULL != XVEC (in_rtx, i)) - { - for (j = 0; j < XVECLEN (in_rtx, i); j++) - leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); - } + if (XVEC (in_rtx, i) != NULL) + for (j = 0; j < XVECLEN (in_rtx, i); j++) + leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); break; case 'S': @@ -4460,6 +4620,7 @@ case '0': case 'i': case 'w': + case 'p': case 'n': case 'u': break; @@ -4476,9 +4637,16 @@ { const char *fnname = get_fnname_from_decl (current_function_decl); + /* Turn debug markers into notes if the var-tracking pass has not + been invoked. */ + if (!flag_var_tracking && MAY_HAVE_DEBUG_MARKER_INSNS) + delete_vta_debug_insns (false); + assemble_start_function (current_function_decl, fnname); - final_start_function (get_insns (), asm_out_file, optimize); - final (get_insns (), asm_out_file, optimize); + rtx_insn *first = get_insns (); + int seen = 0; + final_start_function_1 (&first, asm_out_file, &seen, optimize); + final_1 (first, asm_out_file, seen, optimize); if (flag_ipa_ra && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl))) collect_fn_hard_reg_usage (); @@ -4487,7 +4655,7 @@ /* 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); + output_function_exception_table (crtl->has_bb_partition ? 1 : 0); assemble_end_function (current_function_decl, fnname); @@ -4633,7 +4801,7 @@ { flag_dump_noaddr = flag_dump_unnumbered = 1; if (flag_compare_debug_opt || flag_compare_debug) - dump_flags |= TDF_NOUID; + dump_flags |= TDF_NOUID | TDF_COMPARE_DEBUG; dump_function_header (final_output, current_function_decl, dump_flags); final_insns_dump_p = true; @@ -4660,13 +4828,29 @@ SET_NEXT_INSN (insn) = NULL; SET_PREV_INSN (insn) = NULL; + rtx_insn *call_insn = insn; + if (NONJUMP_INSN_P (call_insn) + && GET_CODE (PATTERN (call_insn)) == SEQUENCE) + { + rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (call_insn)); + call_insn = seq->insn (0); + } + if (CALL_P (call_insn)) + { + rtx note + = find_reg_note (call_insn, REG_CALL_ARG_LOCATION, NULL_RTX); + if (note) + remove_note (call_insn, note); + } + 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_DELETED_DEBUG_LABEL))) + && (!NOTE_P (insn) + || (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION + && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT + && NOTE_KIND (insn) != NOTE_INSN_INLINE_ENTRY + && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG + && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END + && NOTE_KIND (insn) != NOTE_INSN_DELETED_DEBUG_LABEL))) print_rtl_single (final_output, insn); } @@ -4684,12 +4868,6 @@ } } - /* In case the function was not output, - don't leave any temporary anonymous types - queued up for sdb output. */ - if (SDB_DEBUGGING_INFO && write_symbols == SDB_DEBUG) - sdbout_types (NULL_TREE); - flag_rerun_cse_after_global_opts = 0; reload_completed = 0; epilogue_completed = 0;