X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Ffinal.c;h=a3601964a8d31f2436e7c8e3d378345c8cf8dd60;hb=0cd74f3588928e22c08003c643c91340f555785e;hp=db3095c5526248cd7c35519a2e36c48e4fb87924;hpb=e3a174d0d1eef07442fca5867cfcdd05f3b845f8;p=gcc.git diff --git a/gcc/final.c b/gcc/final.c index db3095c5526..a3601964a8d 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1,5 +1,5 @@ /* Convert RTL to assembler code and output it, for GNU compiler. - Copyright (C) 1987-2018 Free Software Foundation, Inc. + Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of GCC. @@ -75,12 +75,12 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "tree-ssa.h" #include "cfgloop.h" -#include "params.h" #include "stringpool.h" #include "attribs.h" #include "asan.h" #include "rtl-iter.h" #include "print-rtl.h" +#include "function-abi.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data declarations. */ @@ -110,6 +110,7 @@ along with GCC; see the file COPYING3. If not see /* 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; @@ -121,11 +122,20 @@ static int last_linenum; /* 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; +static inline int compute_discriminator (location_t loc); + +/* 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; @@ -140,6 +150,7 @@ static const char *last_filename; static const char *override_filename; static int override_linenum; static int override_columnnum; +static int override_discriminator; /* Whether to force emission of a line note before the next insn. */ static bool force_source_line = false; @@ -196,7 +207,7 @@ static int dialect_number; /* 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. */ @@ -219,7 +230,6 @@ static int alter_cond (rtx); #endif static int align_fuzz (rtx, rtx, int, unsigned); static void collect_fn_hard_reg_usage (void); -static tree get_call_fndecl (rtx_insn *); /* Initialize data in final at the beginning of a compilation. */ @@ -326,15 +336,9 @@ int insn_current_align; 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 label_align; /* Indicate that branch shortening hasn't yet been done. */ @@ -472,11 +476,11 @@ get_attr_min_length (rtx_insn *insn) 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 @@ -484,33 +488,9 @@ get_attr_min_length (rtx_insn *insn) #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) @@ -535,27 +515,16 @@ final_addr_vec_align (rtx_jump_table_data *addr_vec) 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 @@ -603,8 +572,8 @@ align_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth) 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); @@ -636,7 +605,7 @@ insn_current_reference_address (rtx_insn *branch) rtx_insn *seq = NEXT_INSN (PREV_INSN (branch)); seq_uid = INSN_UID (seq); - if (!JUMP_P (branch)) + if (!jump_to_label_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. @@ -666,18 +635,14 @@ insn_current_reference_address (rtx_insn *branch) unsigned int compute_alignments (void) { - int log, max_skip, max_log; basic_block bb; + align_flags max_alignment; - if (label_align) - { - free (label_align); - label_align = 0; - } + 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)) @@ -691,7 +656,7 @@ compute_alignments (void) } loop_optimizer_init (AVOID_CFG_MODIFICATIONS); profile_count count_threshold = cfun->cfg->count_max.apply_scale - (1, PARAM_VALUE (PARAM_ALIGN_THRESHOLD)); + (1, param_align_threshold); if (dump_file) { @@ -717,8 +682,7 @@ compute_alignments (void) 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 (); @@ -760,18 +724,14 @@ compute_alignments (void) if (!has_fallthru && (branch_count > count_threshold || (bb->count > bb->prev_bb->count.apply_scale (10, 1) - && (bb->prev_bb->count + && (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. */ @@ -782,19 +742,14 @@ compute_alignments (void) && branch_count + fallthru_count > count_threshold && (branch_count > fallthru_count.apply_scale - (PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS), 1))) + (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 (); @@ -804,7 +759,7 @@ compute_alignments (void) /* Grow the LABEL_ALIGN array after new labels are created. */ -static void +static void grow_label_align (void) { int old = max_labelno; @@ -816,14 +771,11 @@ grow_label_align (void) 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 @@ -841,10 +793,7 @@ update_alignments (vec &label_pairs) 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; } @@ -902,15 +851,12 @@ shorten_branches (rtx_insn *first) 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 (); @@ -925,17 +871,14 @@ shorten_branches (rtx_insn *first) /* 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; @@ -943,22 +886,14 @@ shorten_branches (rtx_insn *first) if (rtx_code_label *label = dyn_cast (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. */ @@ -966,17 +901,11 @@ shorten_branches (rtx_insn *first) || 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)) { @@ -986,12 +915,9 @@ shorten_branches (rtx_insn *first) 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; } } @@ -1015,18 +941,19 @@ shorten_branches (rtx_insn *first) 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; @@ -1077,8 +1004,10 @@ shorten_branches (rtx_insn *first) 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); @@ -1112,7 +1041,7 @@ shorten_branches (rtx_insn *first) 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; @@ -1220,7 +1149,7 @@ shorten_branches (rtx_insn *first) if (rtx_code_label *label = dyn_cast (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 @@ -1295,7 +1224,7 @@ shorten_branches (rtx_insn *first) 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; } @@ -1507,72 +1436,6 @@ asm_str_count (const char *templ) 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 @@ -1676,6 +1539,7 @@ reemit_insn_block_notes (void) 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; @@ -1758,6 +1622,67 @@ get_some_local_dynamic_name () 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 @@ -1765,12 +1690,15 @@ get_some_local_dynamic_name () 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; @@ -1782,14 +1710,28 @@ final_start_function (rtx_insn *first, FILE *file, 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); @@ -1846,14 +1788,14 @@ final_start_function (rtx_insn *first, FILE *file, TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; } - HOST_WIDE_INT min_frame_size = constant_lower_bound (get_frame_size ()); - if (warn_frame_larger_than - && min_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", - min_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. */ @@ -1865,6 +1807,17 @@ final_start_function (rtx_insn *first, FILE *file, 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) { @@ -1994,11 +1947,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb, /* 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; @@ -2058,6 +2010,9 @@ final (rtx_insn *first, FILE *file, int optimize_p) } 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, @@ -2065,6 +2020,8 @@ final (rtx_insn *first, FILE *file, int optimize_p) insn = final_scan_insn (insn, file, optimize_p, 0, &seen); } + maybe_output_next_view (&seen); + if (flag_debug_asm) { free (start_to_bb); @@ -2081,9 +2038,26 @@ final (rtx_insn *first, FILE *file, int optimize_p) 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) { @@ -2093,8 +2067,7 @@ get_insn_template (int code, rtx insn) 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 (insn)); + return (*insn_data[code].output.function) (recog_data.operand, insn); default: gcc_unreachable (); @@ -2171,14 +2144,13 @@ asm_show_source (const char *filename, int linenum) 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); } @@ -2194,9 +2166,9 @@ asm_show_source (const char *filename, int linenum) 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; @@ -2221,6 +2193,13 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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) @@ -2254,6 +2233,9 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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; @@ -2267,8 +2249,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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: @@ -2362,11 +2343,14 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, override_filename = LOCATION_FILE (*locus_ptr); override_linenum = LOCATION_LINE (*locus_ptr); override_columnnum = LOCATION_COLUMN (*locus_ptr); + override_discriminator = compute_discriminator (*locus_ptr); } } 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 @@ -2397,12 +2381,14 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, override_filename = LOCATION_FILE (*locus_ptr); override_linenum = LOCATION_LINE (*locus_ptr); override_columnnum = LOCATION_COLUMN (*locus_ptr); + override_discriminator = compute_discriminator (*locus_ptr); } else { override_filename = NULL; override_linenum = 0; override_columnnum = 0; + override_discriminator = 0; } } break; @@ -2421,9 +2407,11 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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: @@ -2431,9 +2419,22 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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) + && notice_source_line (insn, NULL)) + { + (*debug_hooks->inline_entry) (LOCATION_BLOCK + (NOTE_MARKER_LOCATION (insn))); + goto output_source_line; } break; @@ -2451,20 +2452,20 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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 } @@ -2629,6 +2630,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, 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 @@ -2641,7 +2646,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, (*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) @@ -3108,7 +3118,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, /* 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; @@ -3116,7 +3127,97 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, } 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 int +compute_discriminator (location_t loc) +{ + int discriminator; + + 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 discriminator; +} + /* 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. */ @@ -3140,6 +3241,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) filename = xloc.file; linenum = xloc.line; columnnum = xloc.column; + discriminator = compute_discriminator (loc); force_source_line = true; } else if (override_filename) @@ -3147,6 +3249,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) filename = override_filename; linenum = override_linenum; columnnum = override_columnnum; + discriminator = override_discriminator; } else if (INSN_HAS_LOCATION (insn)) { @@ -3154,12 +3257,14 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) filename = xloc.file; linenum = xloc.line; columnnum = xloc.column; + discriminator = compute_discriminator (INSN_LOCATION (insn)); } else { filename = NULL; linenum = 0; columnnum = 0; + discriminator = 0; } if (filename == NULL) @@ -4547,17 +4652,23 @@ rest_of_handle_final (void) 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))) + && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)) + /* Functions with naked attributes are supported only with basic asm + statements in the body, thus for supported use cases the information + on clobbered registers is not available. */ + && !lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl))) collect_fn_hard_reg_usage (); final_end_function (); /* 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); @@ -4730,14 +4841,29 @@ rest_of_clean_state (void) 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 (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_BEGIN_STMT - && 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); } @@ -4777,7 +4903,8 @@ rest_of_clean_state (void) /* 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)) + if (flag_ipa_stack_alignment + && 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) @@ -4866,7 +4993,16 @@ collect_fn_hard_reg_usage (void) if (!targetm.call_fusage_contains_non_callee_clobbers) return; - CLEAR_HARD_REG_SET (function_used_regs); + /* Be conservative - mark fixed and global registers as used. */ + function_used_regs = fixed_reg_set; + +#ifdef STACK_REGS + /* Handle STACK_REGS conservatively, since the df-framework does not + provide accurate information for them. */ + + for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) + SET_HARD_REG_BIT (function_used_regs, i); +#endif for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn)) { @@ -4877,97 +5013,23 @@ collect_fn_hard_reg_usage (void) if (CALL_P (insn) && !self_recursive_call_p (insn)) - { - if (!get_call_reg_set_usage (insn, &insn_used_regs, - call_used_reg_set)) - return; - - IOR_HARD_REG_SET (function_used_regs, insn_used_regs); - } + function_used_regs + |= insn_callee_abi (insn).full_and_partial_reg_clobbers (); find_all_hard_reg_sets (insn, &insn_used_regs, false); - IOR_HARD_REG_SET (function_used_regs, insn_used_regs); - } + function_used_regs |= insn_used_regs; - /* Be conservative - mark fixed and global registers as used. */ - IOR_HARD_REG_SET (function_used_regs, fixed_reg_set); - -#ifdef STACK_REGS - /* Handle STACK_REGS conservatively, since the df-framework does not - provide accurate information for them. */ - - for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) - SET_HARD_REG_BIT (function_used_regs, i); -#endif + if (hard_reg_set_subset_p (crtl->abi->full_and_partial_reg_clobbers (), + function_used_regs)) + return; + } - /* The information we have gathered is only interesting if it exposes a - register from the call_used_regs that is not used in this function. */ - if (hard_reg_set_subset_p (call_used_reg_set, function_used_regs)) - return; + /* Mask out fully-saved registers, so that they don't affect equality + comparisons between function_abis. */ + function_used_regs &= crtl->abi->full_and_partial_reg_clobbers (); node = cgraph_node::rtl_info (current_function_decl); gcc_assert (node != NULL); - COPY_HARD_REG_SET (node->function_used_regs, function_used_regs); - node->function_used_regs_valid = 1; -} - -/* Get the declaration of the function called by INSN. */ - -static tree -get_call_fndecl (rtx_insn *insn) -{ - rtx note, datum; - - note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX); - if (note == NULL_RTX) - return NULL_TREE; - - datum = XEXP (note, 0); - if (datum != NULL_RTX) - return SYMBOL_REF_DECL (datum); - - return NULL_TREE; -} - -/* Return the cgraph_rtl_info of the function called by INSN. Returns NULL for - call targets that can be overwritten. */ - -static struct cgraph_rtl_info * -get_call_cgraph_rtl_info (rtx_insn *insn) -{ - tree fndecl; - - if (insn == NULL_RTX) - return NULL; - - fndecl = get_call_fndecl (insn); - if (fndecl == NULL_TREE - || !decl_binds_to_current_def_p (fndecl)) - return NULL; - - return cgraph_node::rtl_info (fndecl); -} - -/* Find hard registers used by function call instruction INSN, and return them - in REG_SET. Return DEFAULT_SET in REG_SET if not found. */ - -bool -get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set, - HARD_REG_SET default_set) -{ - if (flag_ipa_ra) - { - struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn); - if (node != NULL - && node->function_used_regs_valid) - { - COPY_HARD_REG_SET (*reg_set, node->function_used_regs); - AND_HARD_REG_SET (*reg_set, default_set); - return true; - } - } - - COPY_HARD_REG_SET (*reg_set, default_set); - return false; + node->function_used_regs = function_used_regs; }