From d042bb4925c59010aa989eb5d1cb23023c3b21d9 Mon Sep 17 00:00:00 2001 From: Ilya Palachev Date: Wed, 29 Apr 2015 17:38:43 +0300 Subject: [PATCH] discriminator support. Ported from google/gcc-4_9 branch Ported from r210338 r210397 r210523 r214745 Change-Id: I4f3e93badd474092b375577c574cfa119b99a875 Signed-off-by: Ilya Palachev --- gcc/basic-block.h | 5 --- gcc/builtins.c | 7 +++- gcc/cfghooks.c | 1 - gcc/diagnostic.c | 4 ++ gcc/dwarf2out.c | 6 ++- gcc/final.c | 29 +++++++++++---- gcc/gimple-pretty-print.c | 2 - gcc/input.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/input.h | 8 +++- gcc/print-rtl.c | 9 ++++- gcc/rtl.h | 1 + gcc/tree-cfg.c | 76 ++++++++++++++++++++++++++++++++++---- gcc/tree-diagnostic.c | 2 + gcc/tree-pretty-print.c | 6 +++ gcc/tree-ssa-uninit.c | 1 + 15 files changed, 222 insertions(+), 28 deletions(-) diff --git a/gcc/basic-block.h b/gcc/basic-block.h index f55cd8d..64949c4 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -201,11 +201,6 @@ struct GTY((chain_next ("%h.next_bb"), chain_prev ("%h.prev_bb"))) basic_block_d /* Expected frequency. Normalized to be in range 0 to BB_FREQ_MAX. */ int frequency; - - /* The discriminator for this block. The discriminator distinguishes - among several basic blocks that share a common locus, allowing for - more accurate sample-based profiling. */ - int discriminator; }; /* This ensures that struct gimple_bb_info is smaller than diff --git a/gcc/builtins.c b/gcc/builtins.c index 0825391..3387f46 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -12069,13 +12069,16 @@ fold_builtin_next_arg (tree exp, bool va_start_p) tree fntype = TREE_TYPE (current_function_decl); int nargs = call_expr_nargs (exp); tree arg; + location_t loc = LOCATION_LOCUS (input_location); + if (has_discriminator (loc)) + loc = map_discriminator_location (loc); + /* There is good chance the current input_location points inside the definition of the va_start macro (perhaps on the token for builtin) in a system header, so warnings will not be emitted. Use the location in real source code. */ source_location current_location = - linemap_unwind_to_first_non_reserved_loc (line_table, input_location, - NULL); + linemap_unwind_to_first_non_reserved_loc (line_table, loc, NULL); if (!stdarg_p (fntype)) { diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c index bc1634a..5de7cdc 100644 --- a/gcc/cfghooks.c +++ b/gcc/cfghooks.c @@ -500,7 +500,6 @@ split_block (basic_block bb, void *i) new_bb->count = bb->count; new_bb->frequency = bb->frequency; - new_bb->discriminator = bb->discriminator; if (dom_info_available_p (CDI_DOMINATORS)) { diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 0cc7593..7cb4ae7 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -187,6 +187,7 @@ diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg, va_list *args, location_t location, diagnostic_t kind) { + location = map_discriminator_location (location); diagnostic->message.err_no = errno; diagnostic->message.args_ptr = args; diagnostic->message.format_spec = msg; @@ -513,6 +514,9 @@ diagnostic_report_current_module (diagnostic_context *context, location_t where) if (where <= BUILTINS_LOCATION) return; + if (has_discriminator (where)) + where = map_discriminator_location (where); + linemap_resolve_location (line_table, where, LRK_MACRO_DEFINITION_LOCATION, &map); diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 6b4e83a..bb937f8 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -18892,12 +18892,16 @@ gen_label_die (tree decl, dw_die_ref context_die) static inline void add_call_src_coords_attributes (tree stmt, dw_die_ref die) { - expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt)); + location_t locus = BLOCK_SOURCE_LOCATION (stmt); + expanded_location s = expand_location (locus); if (dwarf_version >= 3 || !dwarf_strict) { add_AT_file (die, DW_AT_call_file, lookup_filename (s.file)); add_AT_unsigned (die, DW_AT_call_line, s.line); + unsigned discr = get_discriminator_from_locus (locus); + if (discr != 0) + add_AT_unsigned (die, DW_AT_GNU_discriminator, discr); } } diff --git a/gcc/final.c b/gcc/final.c index 83abee2..1f1eded 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -125,9 +125,6 @@ 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; @@ -137,9 +134,10 @@ static int high_function_linenum; /* Filename of last NOTE. */ static const char *last_filename; -/* Override filename and line number. */ +/* Override filename, line number, and discriminator. */ static const char *override_filename; static int override_linenum; +static int override_discriminator; /* Whether to force emission of a line note before the next insn. */ static bool force_source_line = false; @@ -1735,7 +1733,7 @@ final_start_function (rtx first, FILE *file, last_filename = LOCATION_FILE (prologue_location); last_linenum = LOCATION_LINE (prologue_location); - last_discriminator = discriminator = 0; + last_discriminator = 0; high_block_linenum = high_function_linenum = last_linenum; @@ -2186,8 +2184,6 @@ final_scan_insn (rtx 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; - break; case NOTE_INSN_EH_REGION_BEG: @@ -2280,6 +2276,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, { override_filename = LOCATION_FILE (*locus_ptr); override_linenum = LOCATION_LINE (*locus_ptr); + override_discriminator = + get_discriminator_from_locus (*locus_ptr); } } break; @@ -2313,11 +2311,14 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, { override_filename = LOCATION_FILE (*locus_ptr); override_linenum = LOCATION_LINE (*locus_ptr); + override_discriminator = + get_discriminator_from_locus (*locus_ptr); } else { override_filename = NULL; override_linenum = 0; + override_discriminator = 0; } } break; @@ -3000,6 +3001,17 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, } return NEXT_INSN (insn); } + +/* Return discriminator of the statement that produced this insn. */ +int +insn_discriminator (const_rtx insn) +{ + location_t loc = INSN_LOCATION (insn); + if (!loc) + return 0; + return get_discriminator_from_locus (loc); +} + /* 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 @@ -3010,16 +3022,19 @@ notice_source_line (rtx insn, bool *is_stmt) { const char *filename; int linenum; + int discriminator; if (override_filename) { filename = override_filename; linenum = override_linenum; + discriminator = override_discriminator; } else { filename = insn_file (insn); linenum = insn_line (insn); + discriminator = insn_discriminator (insn); } if (filename == NULL) diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 741cd92..65f4566 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -2268,8 +2268,6 @@ dump_gimple_bb_header (FILE *outf, basic_block bb, int indent, int flags) indent, "", get_lineno (gsi_stmt (gsi))); break; } - if (bb->discriminator) - fprintf (outf, ", discriminator %i", bb->discriminator); fputc ('\n', outf); } } diff --git a/gcc/input.c b/gcc/input.c index 63cd062..c819303 100644 --- a/gcc/input.c +++ b/gcc/input.c @@ -109,6 +109,11 @@ location_t input_location; struct line_maps *line_table; +static vec discriminator_location_locations; +static vec discriminator_location_discriminators; +static location_t next_discriminator_location = UNKNOWN_LOCATION; +static location_t min_discriminator_location = UNKNOWN_LOCATION; + static fcache *fcache_tab; static const size_t fcache_tab_size = 16; static const size_t fcache_buffer_size = 4 * 1024; @@ -143,6 +148,13 @@ expand_location_1 (source_location loc, loc = LOCATION_LOCUS (loc); } + /* If LOC describes a location with a discriminator, extract the + discriminator and map it to the real location. */ + if (min_discriminator_location != UNKNOWN_LOCATION + && loc >= min_discriminator_location + && loc < next_discriminator_location) + loc = map_discriminator_location (loc); + memset (&xloc, 0, sizeof (xloc)); if (loc >= RESERVED_LOCATION_COUNT) @@ -852,3 +864,84 @@ dump_line_table_statistics (void) STAT_LABEL (total_used_map_size)); fprintf (stderr, "\n"); } + +/* Associate the DISCRIMINATOR with LOCUS, and return a new locus. + We associate discriminators with a locus by allocating location_t + values beyond those assigned by libcpp. Each new value is mapped + directly to a real location_t value, and separately to the + discriminator. */ + +location_t +location_with_discriminator (location_t locus, int discriminator) +{ + tree block = LOCATION_BLOCK (locus); + location_t ret; + int i; + locus = map_discriminator_location (locus); + + if (locus == UNKNOWN_LOCATION) + return block ? COMBINE_LOCATION_DATA (line_table, locus, block) + : locus; + + if (min_discriminator_location == UNKNOWN_LOCATION) + { + min_discriminator_location = line_table->highest_location + 1; + next_discriminator_location = min_discriminator_location; + } + + /* Traverse the last few discriminator_locations to see if we can reuse + the entry. */ + for (i = next_discriminator_location - min_discriminator_location - 1; + (i >= 0 && LOCATION_LINE (discriminator_location_locations[i]) == + LOCATION_LINE (locus) + && discriminator_location_discriminators[i] == discriminator); + i--) + if (discriminator_location_locations[i] == locus) + return (block + ? COMBINE_LOCATION_DATA (line_table, min_discriminator_location + i, + block) + : min_discriminator_location + i); + + discriminator_location_locations.safe_push(locus); + discriminator_location_discriminators.safe_push(discriminator); + + ret = (block + ? COMBINE_LOCATION_DATA (line_table, next_discriminator_location, block) + : next_discriminator_location); + + next_discriminator_location++; + return ret; +} + +/* Return TRUE if LOCUS represents a location with a discriminator. */ + +bool +has_discriminator (location_t locus) +{ + locus = LOCATION_LOCUS (locus); + return (min_discriminator_location != UNKNOWN_LOCATION + && locus >= min_discriminator_location + && locus < next_discriminator_location); +} + +/* Return the real location_t value for LOCUS. */ + +location_t +map_discriminator_location (location_t locus) +{ + locus = LOCATION_LOCUS (locus); + if (! has_discriminator (locus)) + return locus; + return (location_t) discriminator_location_locations[locus - min_discriminator_location]; +} + +/* Return the discriminator for LOCUS. */ + +int +get_discriminator_from_locus (location_t locus) +{ + locus = LOCATION_LOCUS (locus); + if (! has_discriminator (locus)) + return 0; + return discriminator_location_discriminators[locus - min_discriminator_location]; +} diff --git a/gcc/input.h b/gcc/input.h index d910bb8..1b73ee8 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -48,6 +48,11 @@ typedef source_location location_t; extern location_t input_location; +extern location_t location_with_discriminator (location_t, int); +extern bool has_discriminator (location_t); +extern location_t map_discriminator_location (location_t); +extern int get_discriminator_from_locus (location_t); + #define LOCATION_FILE(LOC) ((expand_location (LOC)).file) #define LOCATION_LINE(LOC) ((expand_location (LOC)).line) #define LOCATION_COLUMN(LOC)((expand_location (LOC)).column) @@ -59,7 +64,8 @@ extern location_t input_location; : NULL)) #define in_system_header_at(LOC) \ - ((linemap_location_in_system_header_p (line_table, LOC))) + ((linemap_location_in_system_header_p (line_table, \ + map_discriminator_location (LOC)))) void dump_line_table_statistics (void); diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index 09ac387..668d0c4 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -410,8 +410,13 @@ print_rtx (const_rtx in_rtx) redundant with line number information and do not print anything when there is no location information available. */ if (INSN_LOCATION (in_rtx) && insn_file (in_rtx)) - fprintf (outfile, " %s:%i", insn_file (in_rtx), - insn_line (in_rtx)); + { + int discriminator = insn_discriminator (in_rtx); + fprintf (outfile, " %s:%i", insn_file (in_rtx), + insn_line (in_rtx)); + if (discriminator) + fprintf (outfile, " discrim %d", discriminator); + } #endif } else if (i == 6 && GET_CODE (in_rtx) == ASM_OPERANDS) diff --git a/gcc/rtl.h b/gcc/rtl.h index f1cda4c..115491a 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1920,6 +1920,7 @@ extern rtx prev_cc0_setter (rtx); extern int insn_line (const_rtx); extern const char * insn_file (const_rtx); extern tree insn_scope (const_rtx); +extern int insn_discriminator (const_rtx); extern location_t prologue_location, epilogue_location; /* In jump.c */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 1469d78..d466195 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -110,7 +110,14 @@ static struct cfg_stats_d cfg_stats; struct locus_discrim_map { location_t locus; - int discriminator; + /* Different calls belonging to the same source line will be assigned + different discriminators. But we want to keep the discriminator of + the first call in the same source line to be 0, in order to reduce + the .debug_line section size. needs_increment is used for this + purpose. It is initialized as false and will be set to true after + the first call is seen. */ + bool needs_increment:1; + int discriminator:31; }; /* Hashtable helpers. */ @@ -942,10 +949,15 @@ make_edges (void) /* Find the next available discriminator value for LOCUS. The discriminator distinguishes among several basic blocks that share a common locus, allowing for more accurate sample-based - profiling. */ + profiling. If RETURN_NEXT is true, return the next discriminator + anyway. If RETURN_NEXT is not true, we may not increase the + discriminator if locus_discrim_map::needs_increment is false, + which is used when the stmt is the first call stmt in current + source line. locus_discrim_map::needs_increment will be set to + true after the first call is seen. */ static int -next_discriminator_for_locus (location_t locus) +next_discriminator_for_locus (location_t locus, bool return_next) { struct locus_discrim_map item; struct locus_discrim_map **slot; @@ -960,9 +972,13 @@ next_discriminator_for_locus (location_t locus) *slot = XNEW (struct locus_discrim_map); gcc_assert (*slot); (*slot)->locus = locus; + (*slot)->needs_increment = false; (*slot)->discriminator = 0; } - (*slot)->discriminator++; + if (return_next || (*slot)->needs_increment) + (*slot)->discriminator++; + else + (*slot)->needs_increment = true; return (*slot)->discriminator; } @@ -988,6 +1004,32 @@ same_line_p (location_t locus1, location_t locus2) && filename_cmp (from.file, to.file) == 0); } +/* Assign a unique discriminator value to instructions in block BB that + have the same LOCUS as its predecessor block. */ + +static void +assign_discriminator (location_t locus, basic_block bb) +{ + gimple_stmt_iterator gsi; + int discriminator; + + locus = map_discriminator_location (locus); + + if (locus == UNKNOWN_LOCATION) + return; + + discriminator = next_discriminator_for_locus (locus, true); + + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + location_t stmt_locus = gimple_location (stmt); + if (same_line_p (locus, stmt_locus)) + gimple_set_location (stmt, + location_with_discriminator (stmt_locus, discriminator)); + } +} + /* Assign discriminators to each basic block. */ static void @@ -999,8 +1041,26 @@ assign_discriminators (void) { edge e; edge_iterator ei; + gimple_stmt_iterator gsi; gimple last = last_stmt (bb); location_t locus = last ? gimple_location (last) : UNKNOWN_LOCATION; + location_t curr_locus = UNKNOWN_LOCATION; + int curr_discr = 0; + + /* Traverse the basic block, if two function calls within a basic block + are mapped to a same line, assign a new discriminator because a call + stmt could be a split point of a basic block. */ + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (gimple_code (stmt) == GIMPLE_CALL) + { + curr_locus = gimple_location (stmt); + curr_discr = next_discriminator_for_locus (curr_locus, false); + gimple_set_location (stmt, location_with_discriminator ( + curr_locus, curr_discr)); + } + } if (locus == UNKNOWN_LOCATION) continue; @@ -1012,10 +1072,12 @@ assign_discriminators (void) if ((first && same_line_p (locus, gimple_location (first))) || (last && same_line_p (locus, gimple_location (last)))) { - if (e->dest->discriminator != 0 && bb->discriminator == 0) - bb->discriminator = next_discriminator_for_locus (locus); + if (((first && has_discriminator (gimple_location (first))) + || (last && has_discriminator (gimple_location (last)))) + && !has_discriminator (locus)) + assign_discriminator (locus, bb); else - e->dest->discriminator = next_discriminator_for_locus (locus); + assign_discriminator (locus, e->dest); } } } diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c index ee71555..dec95f8 100644 --- a/gcc/tree-diagnostic.c +++ b/gcc/tree-diagnostic.c @@ -108,6 +108,8 @@ maybe_unwind_expanded_macro_loc (diagnostic_context *context, unsigned ix; loc_map_pair loc, *iter; + if (has_discriminator (where)) + where = map_discriminator_location (where); map = linemap_lookup (line_table, where); if (!linemap_macro_expansion_map_p (map)) return; diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index d6f39d8..fae506a 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -671,6 +671,7 @@ static void dump_location (pretty_printer *buffer, location_t loc) { expanded_location xloc = expand_location (loc); + int discriminator = get_discriminator_from_locus (loc); pp_left_bracket (buffer); if (xloc.file) @@ -679,6 +680,11 @@ dump_location (pretty_printer *buffer, location_t loc) pp_string (buffer, " : "); } pp_decimal_int (buffer, xloc.line); + if (discriminator) + { + pp_string (buffer, " discrim "); + pp_decimal_int (buffer, discriminator); + } pp_string (buffer, "] "); } diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index eee83f7..ca68412 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -149,6 +149,7 @@ warn_uninit (enum opt_code wc, tree t, location = (context != NULL && gimple_has_location (context)) ? gimple_location (context) : DECL_SOURCE_LOCATION (var); + location = map_discriminator_location (location); location = linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, NULL); -- 2.7.4