+2019-05-09 Martin Liska <mliska@suse.cz>
+
+ * tree-cfg.c (dump_function_to_file): Dump entry BB count.
+ * gimple-pretty-print.c (dump_gimple_bb_header):
+ Dump BB count.
+ (pp_cfg_jump): Dump edge probability.
+ * profile-count.c (profile_quality_as_string): Simplify
+ with a static array.
+ (parse_profile_quality): New function.
+ (profile_count::dump): Simplify with a static array.
+ (profile_count::from_gcov_type): Add new argument.
+ * profile-count.h (parse_profile_quality): Likewise.
+ * predict.h (set_hot_bb_threshold): New.
+ * params.def (PARAM_GIMPLE_FE_COMPUTED_HOT_BB_THRESHOLD):
+ New param.
+ * predict.c (get_hot_bb_threshold): Set from the new param.
+ (set_hot_bb_threshold): New.
+
2019-05-09 Richard Biener <rguenther@suse.de>
PR tree-optimization/90395
+2019-05-09 Martin Liska <mliska@suse.cz>
+
+ * gimple-parser.c (struct gimple_parser): Add probability.
+ for gimple_parser_edge.
+ (gimple_parser::push_edge): Add new argument probability.
+ (c_parser_gimple_parse_bb_spec): Parse also probability
+ if present.
+ (c_parser_parse_gimple_body): Set edge probability.
+ (c_parser_gimple_compound_statement): Consume token
+ before calling c_parser_gimple_goto_stmt.
+ Parse BB counts.
+ (c_parser_gimple_statement): Pass new argument.
+ (c_parser_gimple_goto_stmt): Likewise.
+ (c_parser_gimple_if_stmt): Likewise.
+ (c_parser_gimple_or_rtl_pass_list): Parse hot_bb_threshold.
+ * c-parser.c (c_parser_declaration_or_fndef): Pass
+ hot_bb_threshold argument.
+ * c-tree.h (struct c_declspecs): Add hot_bb_threshold
+ field.
+ (c_parser_gimple_parse_bb_spec_edge_probability): New.
+
2019-04-26 Jakub Jelinek <jakub@redhat.com>
PR debug/90197
bool saved = in_late_binary_op;
in_late_binary_op = true;
c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
- specs->declspec_il);
+ specs->declspec_il,
+ specs->entry_bb_count);
in_late_binary_op = saved;
}
else
tree attrs;
/* The pass to start compiling a __GIMPLE or __RTL function with. */
char *gimple_or_rtl_pass;
+ /* ENTRY BB count. */
+ profile_count entry_bb_count;
/* The base-2 log of the greatest alignment required by an _Alignas
specifier, in bytes, or -1 if no such specifiers with nonzero
alignment. */
#include "tree-phinodes.h"
#include "tree-into-ssa.h"
#include "bitmap.h"
+#include "params.h"
/* GIMPLE parser state. */
int src;
int dest;
int flags;
+ profile_probability probability;
};
auto_vec<gimple_parser_edge> edges;
basic_block current_bb;
- void push_edge (int, int, int);
+ void push_edge (int, int, int, profile_probability);
};
void
-gimple_parser::push_edge (int src, int dest, int flags)
+gimple_parser::push_edge (int src, int dest, int flags,
+ profile_probability prob)
{
gimple_parser_edge e;
e.src = src;
e.dest = dest;
e.flags = flags;
+ e.probability = prob;
edges.safe_push (e);
}
/* See if VAL is an identifier matching __BB<num> and return <num>
- in *INDEX. Return true if so. */
+ in *INDEX. */
static bool
c_parser_gimple_parse_bb_spec (tree val, int *index)
return *index > 0;
}
+/* See if VAL is an identifier matching __BB<num> and return <num>
+ in *INDEX. Return true if so and parse also FREQUENCY of
+ the edge. */
+
+
+static bool
+c_parser_gimple_parse_bb_spec_edge_probability (tree val,
+ gimple_parser &parser,
+ int *index,
+ profile_probability *probablity)
+{
+ bool return_p = c_parser_gimple_parse_bb_spec (val, index);
+ if (return_p)
+ {
+ *probablity = profile_probability::uninitialized ();
+ /* Parse frequency if provided. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree f;
+ c_parser_consume_token (parser);
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected frequency quality");
+ return false;
+ }
+
+ profile_quality quality;
+ const char *v
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (!parse_profile_quality (v, &quality))
+ {
+ c_parser_error (parser, "unknown profile quality");
+ return false;
+ }
+
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return false;
+
+ if (!c_parser_next_token_is (parser, CPP_NUMBER)
+ || (TREE_CODE (f = c_parser_peek_token (parser)->value)
+ != INTEGER_CST))
+ {
+ c_parser_error (parser, "expected frequency value");
+ return false;
+ }
+
+ unsigned int value = TREE_INT_CST_LOW (f);
+ *probablity = profile_probability (value, quality);
+
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return false;
+
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+
+}
+
/* Parse the body of a function declaration marked with "__GIMPLE". */
void
c_parser_parse_gimple_body (c_parser *cparser, char *gimple_pass,
- enum c_declspec_il cdil)
+ enum c_declspec_il cdil,
+ profile_count entry_bb_count)
{
gimple_parser parser (cparser);
gimple_seq seq = NULL;
add_local_decl (cfun, var);
/* We have a CFG. Build the edges. */
for (unsigned i = 0; i < parser.edges.length (); ++i)
- make_edge (BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].src),
- BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].dest),
- parser.edges[i].flags);
+ {
+ edge e = make_edge (BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].src),
+ BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].dest),
+ parser.edges[i].flags);
+ e->probability = parser.edges[i].probability;
+ }
/* Add edges for case labels. */
basic_block bb;
FOR_EACH_BB_FN (bb, cfun)
fix_loop_structure (NULL);
}
+ if (cfun->curr_properties & PROP_cfg)
+ {
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = entry_bb_count;
+ gcov_type t = PARAM_VALUE (PARAM_GIMPLE_FE_COMPUTED_HOT_BB_THRESHOLD);
+ set_hot_bb_threshold (t);
+ update_max_bb_count ();
+ }
dump_function (TDI_gimple, current_function_decl);
}
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
- c_parser_gimple_goto_stmt (parser, loc,
- c_parser_peek_token
- (parser)->value,
- seq);
+ tree label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
+ c_parser_gimple_goto_stmt (parser, loc, label, seq);
if (! c_parser_require (parser, CPP_SEMICOLON,
"expected %<;%>"))
return return_p;
"expected %<;%>"))
return return_p;
if (cfun->curr_properties & PROP_cfg)
- parser.push_edge (parser.current_bb->index, EXIT_BLOCK, 0);
+ parser.push_edge (parser.current_bb->index, EXIT_BLOCK, 0,
+ profile_probability::uninitialized ());
break;
default:
goto expr_stmt;
return return_p;
}
int is_loop_header_of = -1;
+ profile_count bb_count = profile_count::uninitialized ();
c_parser_consume_token (parser);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
"expected %<)%>"))
return return_p;
}
+ /* Parse profile: quality(value) */
else
{
- c_parser_error (parser, "unknown block specifier");
- return return_p;
+ tree q;
+ profile_quality quality;
+ tree v = c_parser_peek_token (parser)->value;
+ if (!parse_profile_quality (IDENTIFIER_POINTER (v),
+ &quality))
+ {
+ c_parser_error (parser, "unknown block specifier");
+ return false;
+ }
+
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN,
+ "expected %<(%>"))
+ return false;
+
+ if (!c_parser_next_token_is (parser, CPP_NUMBER)
+ || (TREE_CODE (q = c_parser_peek_token (parser)->value)
+ != INTEGER_CST))
+ {
+ c_parser_error (parser, "expected count value");
+ return false;
+ }
+
+ bb_count
+ = profile_count::from_gcov_type (TREE_INT_CST_LOW (q),
+ quality);
+ c_parser_consume_token (parser);
+ if (! c_parser_require (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>"))
+ return return_p;
}
}
if (! c_parser_require (parser, CPP_CLOSE_PAREN,
last_basic_block_for_fn (cfun) = index + 1;
n_basic_blocks_for_fn (cfun)++;
if (!parser.current_bb)
- parser.push_edge (ENTRY_BLOCK, bb->index, EDGE_FALLTHRU);
+ parser.push_edge (ENTRY_BLOCK, bb->index, EDGE_FALLTHRU,
+ profile_probability::always ());
/* We leave the proper setting to fixup. */
struct loop *loop_father = loops_for_fn (cfun)->tree_root;
loop_father = get_loop (cfun, is_loop_header_of);
}
bb->loop_father = loop_father;
+ bb->count = bb_count;
/* Stmts now go to the new block. */
parser.current_bb = bb;
return;
c_parser_consume_token (parser);
+ specs->entry_bb_count = profile_count::uninitialized ();
while (c_parser_next_token_is (parser, CPP_NAME))
{
+ profile_quality quality;
const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
if (! strcmp (op, "startwith"))
if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>"))
return;
}
+ else if (parse_profile_quality (op, &quality))
+ {
+ tree q;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return;
+
+ if (!c_parser_next_token_is (parser, CPP_NUMBER)
+ || (TREE_CODE (q = c_parser_peek_token (parser)->value)
+ != INTEGER_CST))
+ {
+ c_parser_error (parser, "expected count value");
+ return;
+ }
+
+ specs->entry_bb_count
+ = profile_count::from_gcov_type (TREE_INT_CST_LOW (q), quality);
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return;
+ }
else if (specs->declspec_il != cdil_gimple)
/* Allow only one IL specifier and none on RTL. */
;
if (cfun->curr_properties & PROP_cfg)
{
int dest_index;
- if (c_parser_gimple_parse_bb_spec (label, &dest_index))
+ profile_probability prob;
+ if (c_parser_gimple_parse_bb_spec_edge_probability (label, parser,
+ &dest_index, &prob))
{
parser.push_edge (parser.current_bb->index, dest_index,
- EDGE_FALLTHRU);
+ EDGE_FALLTHRU, prob);
return;
}
}
label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
int dest_index;
+ profile_probability prob;
if ((cfun->curr_properties & PROP_cfg)
- && c_parser_gimple_parse_bb_spec (label, &dest_index))
+ && c_parser_gimple_parse_bb_spec_edge_probability (label, parser,
+ &dest_index, &prob))
parser.push_edge (parser.current_bb->index, dest_index,
- EDGE_TRUE_VALUE);
+ EDGE_TRUE_VALUE, prob);
else
t_label = lookup_label_for_goto (loc, label);
if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
return;
}
label = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
int dest_index;
+ profile_probability prob;
if ((cfun->curr_properties & PROP_cfg)
- && c_parser_gimple_parse_bb_spec (label, &dest_index))
+ && c_parser_gimple_parse_bb_spec_edge_probability (label, parser,
+ &dest_index, &prob))
parser.push_edge (parser.current_bb->index, dest_index,
- EDGE_FALSE_VALUE);
+ EDGE_FALSE_VALUE, prob);
else
f_label = lookup_label_for_goto (loc, label);
- c_parser_consume_token (parser);
if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
return;
}
/* Gimple parsing functions. */
extern void c_parser_parse_gimple_body (c_parser *, char *,
- enum c_declspec_il);
+ enum c_declspec_il,
+ profile_count);
extern void c_parser_gimple_or_rtl_pass_list (c_parser *, c_declspecs *);
#endif
fprintf (outf, "%*s__BB(%d", indent, "", bb->index);
if (bb->loop_father->header == bb)
fprintf (outf, ",loop_header(%d)", bb->loop_father->num);
+ if (bb->count.initialized_p ())
+ fprintf (outf, ",%s(%d)",
+ profile_quality_as_string (bb->count.quality ()),
+ bb->count.value ());
fprintf (outf, "):\n");
}
else
{
pp_string (buffer, "goto __BB");
pp_decimal_int (buffer, e->dest->index);
+ if (e->probability.initialized_p ())
+ {
+ pp_string (buffer, "(");
+ pp_string (buffer,
+ profile_quality_as_string (e->probability.quality ()));
+ pp_string (buffer, "(");
+ pp_decimal_int (buffer, e->probability.value ());
+ pp_string (buffer, "))");
+ }
pp_semicolon (buffer);
}
else
" loops.",
100, 0, 0)
+DEFPARAM(PARAM_GIMPLE_FE_COMPUTED_HOT_BB_THRESHOLD,
+ "gimple-fe-computed-hot-bb-threshold",
+ "The number of executions of a basic block which is considered hot."
+ " The parameters is used only in GIMPLE FE.",
+ 0, 0, 0)
+
/*
Local variables:
{
if (min_count == -1)
{
- min_count
- = profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION);
+ gcov_type t = profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION);
+ set_hot_bb_threshold (t);
if (dump_file)
fprintf (dump_file, "Setting hotness threshold to %" PRId64 ".\n",
min_count);
#include "wide-int.h"
#include "sreal.h"
+/* Names from profile_quality enum values. */
+
+const char *profile_quality_names[] =
+{
+ "uninitialized",
+ "guessed_local",
+ "guessed_global0",
+ "guessed_global0adjusted",
+ "guessed",
+ "afdo",
+ "adjusted",
+ "precise"
+};
+
/* Get a string describing QUALITY. */
const char *
profile_quality_as_string (enum profile_quality quality)
{
- switch (quality)
- {
- default:
- gcc_unreachable ();
- case profile_uninitialized:
- return "uninitialized";
- case profile_guessed_local:
- return "guessed_local";
- case profile_guessed_global0:
- return "guessed_global0";
- case profile_guessed_global0adjusted:
- return "guessed_global0adjusted";
- case profile_guessed:
- return "guessed";
- case profile_afdo:
- return "afdo";
- case profile_adjusted:
- return "adjusted";
- case profile_precise:
- return "precise";
- }
+ return profile_quality_names[quality];
+}
+
+/* Parse VALUE as profile quality and return true when a valid QUALITY. */
+
+bool
+parse_profile_quality (const char *value, profile_quality *quality)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE (profile_quality_names); i++)
+ if (strcmp (profile_quality_names[i], value) == 0)
+ {
+ *quality = (profile_quality)i;
+ return true;
+ }
+
+ return false;
}
+/* Display names from profile_quality enum values. */
+
+const char *profile_quality_display_names[] =
+{
+ NULL,
+ "estimated locally",
+ "estimated locally, globally 0",
+ "estimated locally, globally 0 adjusted",
+ "adjusted",
+ "auto FDO",
+ "guessed",
+ "precise"
+};
+
/* Dump THIS to F. */
void
if (!initialized_p ())
fprintf (f, "uninitialized");
else
- {
- fprintf (f, "%" PRId64, m_val);
- if (m_quality == profile_guessed_local)
- fprintf (f, " (estimated locally)");
- else if (m_quality == profile_guessed_global0)
- fprintf (f, " (estimated locally, globally 0)");
- else if (m_quality == profile_guessed_global0adjusted)
- fprintf (f, " (estimated locally, globally 0 adjusted)");
- else if (m_quality == profile_adjusted)
- fprintf (f, " (adjusted)");
- else if (m_quality == profile_afdo)
- fprintf (f, " (auto FDO)");
- else if (m_quality == profile_guessed)
- fprintf (f, " (guessed)");
- else if (m_quality == profile_precise)
- fprintf (f, " (precise)");
- }
+ fprintf (f, "%" PRId64 " (%s)", m_val,
+ profile_quality_display_names[m_quality]);
}
/* Dump THIS to stderr. */
Conversions back and forth are used to read the coverage and get it
into internal representation. */
profile_count
-profile_count::from_gcov_type (gcov_type v)
+profile_count::from_gcov_type (gcov_type v, profile_quality quality)
{
profile_count ret;
gcc_checking_assert (v >= 0);
"Capping gcov count %" PRId64 " to max_count %" PRId64 "\n",
(int64_t) v, (int64_t) max_count);
ret.m_val = MIN (v, (gcov_type)max_count);
- ret.m_quality = profile_precise;
+ ret.m_quality = quality;
return ret;
}
};
extern const char *profile_quality_as_string (enum profile_quality);
+extern bool parse_profile_quality (const char *value,
+ profile_quality *quality);
/* The base value for branch probability notes and edge probabilities. */
#define REG_BR_PROB_BASE 10000
friend class profile_count;
public:
+ profile_probability (): m_val (uninitialized_probability),
+ m_quality (profile_guessed)
+ {}
+
+ profile_probability (uint32_t val, profile_quality quality):
+ m_val (val), m_quality (quality)
+ {}
/* Named probabilities. */
static profile_probability never ()
return initialized_p () && other.initialized_p () && m_val >= other.m_val;
}
+ /* Get the value of the count. */
+ uint32_t value () const { return m_val; }
+
+ /* Get the quality of the count. */
+ enum profile_quality quality () const { return m_quality; }
+
/* Output THIS to F. */
void dump (FILE *f) const;
return ipa_p () == other.ipa_p ();
}
public:
-
/* Used for counters which are expected to be never executed. */
static profile_count zero ()
{
return m_quality == profile_precise;
}
+ /* Get the value of the count. */
+ uint32_t value () const { return m_val; }
+
/* Get the quality of the count. */
enum profile_quality quality () const { return m_quality; }
/* The profiling runtime uses gcov_type, which is usually 64bit integer.
Conversions back and forth are used to read the coverage and get it
into internal representation. */
- static profile_count from_gcov_type (gcov_type v);
+ static profile_count from_gcov_type (gcov_type v,
+ profile_quality quality = profile_precise);
/* LTO streaming support. */
static profile_count stream_in (struct lto_input_block *);
+2019-05-09 Martin Liska <mliska@suse.cz>
+
+ * gcc.dg/gimplefe-37.c: New test.
+ * gcc.dg/gimplefe-33.c: Likewise.
+
2019-05-09 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/90382
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -fdump-tree-optimized --param=gimple-fe-computed-hot-bb-threshold=10 " } */
+
+int __GIMPLE (ssa,startwith("slsr"),precise(3))
+main (int argc)
+{
+ int _1;
+
+ __BB(2,precise(3)):
+ if (argc_2(D) == 2)
+ goto __BB3(precise(44739243));
+ else
+ goto __BB4(precise(89478485));
+
+ __BB(3,precise(1)):
+ goto __BB4(precise(134217728));
+
+ __BB(4,precise(3)):
+ _1 = __PHI (__BB2: 0, __BB3: 12);
+ return _1;
+}
+
+
+/* { dg-final { scan-tree-dump-times "<bb \[0-9\]> \\\[count: 3" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "<bb \[0-9\]> \\\[count: 2" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "goto <bb \[0-9\]>; \\\[33\\\.33%\\\]" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "goto <bb \[0-9\]>; \\\[66\\\.67%\\\]" 1 "optimized" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -fdump-tree-slsr" } */
+
+int __GIMPLE (ssa,startwith("slsr"),guessed_local(1073741824))
+main (int argc)
+{
+ int _1;
+
+ __BB(2,guessed_local(1073741824)):
+ if (argc_2(D) == 2)
+ goto __BB3(guessed(16777216));
+ else
+ goto __BB4(guessed(117440512));
+
+ __BB(3,guessed_local(134217728)):
+ goto __BB4(precise(134217728));
+
+ __BB(4,guessed_local(1073741824)):
+ _1 = __PHI (__BB2: 0, __BB3: 12);
+ return _1;
+}
+
+
+/* { dg-final { scan-tree-dump-times "<bb \[0-9\]> \\\[local count: 1073741824" 2 "slsr" } } */
+/* { dg-final { scan-tree-dump-times "<bb \[0-9\]> \\\[local count: 134217728" 1 "slsr" } } */
+/* { dg-final { scan-tree-dump-times "goto <bb \[0-9\]>; \\\[12\\\.50%\\\]" 1 "slsr" } } */
+/* { dg-final { scan-tree-dump-times "goto <bb \[0-9\]>; \\\[87\\\.50%\\\]" 1 "slsr" } } */
#include "selftest.h"
#include "opts.h"
#include "asan.h"
+#include "profile.h"
/* This file contains functions for building the Control Flow Graph (CFG)
for a function tree. */
current_function_decl = fndecl;
if (flags & TDF_GIMPLE)
{
+ static bool hotness_bb_param_printed = false;
+ if (profile_info != NULL
+ && !hotness_bb_param_printed)
+ {
+ hotness_bb_param_printed = true;
+ fprintf (file,
+ "/* --param=gimple-fe-computed-hot-bb-threshold=%" PRId64
+ " */\n", get_hot_bb_threshold ());
+ }
+
print_generic_expr (file, TREE_TYPE (TREE_TYPE (fndecl)),
dump_flags | TDF_SLIM);
- fprintf (file, " __GIMPLE (%s)\n%s (",
+ fprintf (file, " __GIMPLE (%s",
(fun->curr_properties & PROP_ssa) ? "ssa"
: (fun->curr_properties & PROP_cfg) ? "cfg"
- : "",
- function_name (fun));
+ : "");
+
+ if (cfun->cfg)
+ {
+ basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ if (bb->count.initialized_p ())
+ fprintf (file, ",%s(%d)",
+ profile_quality_as_string (bb->count.quality ()),
+ bb->count.value ());
+ fprintf (file, ")\n%s (", function_name (fun));
+ }
}
else
fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : "");