代码拉取完成,页面将自动刷新
diff -Nurp a/gcc/cgraphunit.c b/gcc/cgraphunit.c
--- a/gcc/cgraphunit.c 2018-01-12 13:32:31.212894000 +0800
+++ b/gcc/cgraphunit.c 2019-12-19 21:13:25.988489301 +0800
@@ -204,6 +204,8 @@ along with GCC; see the file COPYING3.
#include "dbgcnt.h"
#include "tree-chkp.h"
#include "lto-section-names.h"
+#include "profile-feature.h"
+#include "predict.h"
/* Queue of cgraph nodes scheduled to be added into cgraph. This is a
secondary queue used during optimization to accommodate passes that
@@ -2325,6 +2327,9 @@ ipa_passes (void)
if (!in_lto_p)
{
execute_ipa_pass_list (passes->all_small_ipa_passes);
+ free_prof_prog (g_prof_prog);
+ g_prof_prog = NULL;
+
if (seen_error ())
return;
}
diff -Nurp a/gcc/common.opt b/gcc/common.opt
--- a/gcc/common.opt 2019-12-19 21:12:20.292491748 +0800
+++ b/gcc/common.opt 2019-12-19 21:15:13.192485307 +0800
@@ -797,6 +797,10 @@ Wvector-operation-performance
Common Var(warn_vector_operation_performance) Warning
Warn when a vector operation is compiled outside the SIMD.
+Whcc-fgo-feature-obsolete
+Common Var(warn_fgo_feature_obsolete) Init(0) Warning
+Warn when the condition features are out of date.
+
Xassembler
Driver Separate
@@ -2041,6 +2045,22 @@ fprofile-reorder-functions
Common Report Var(flag_profile_reorder_functions)
Enable function reordering that improves code placement.
+fhcc-fgo-estimate-gen=
+Common Joined RejectNegative Var(fgo_estimate_gen)
+Generate features for branch.
+
+fhcc-fgo-estimate-use=
+Common Joined RejectNegative Var(hcc_fgo_estimate_use)
+Analysis the config file and use it in branch predict.
+
+fhcc-fgo-feature-gen=
+Common Joined RejectNegative Var(fgo_feature_gen)
+Generate features for condition expressions.
+
+fhcc-fgo-feature-use=
+Common Joined RejectNegative Var(fgo_feature_use)
+Optimization with features of condition expressions.
+
frandom-seed
Common Var(common_deferred_options) Defer
diff -Nurp a/gcc/Makefile.in b/gcc/Makefile.in
--- a/gcc/Makefile.in 2019-12-19 21:12:20.148491753 +0800
+++ b/gcc/Makefile.in 2019-12-19 21:13:25.988489301 +0800
@@ -1414,6 +1414,7 @@ OBJS = \
print-rtl-function.o \
print-tree.o \
profile.o \
+ profile-feature.o \
read-md.o \
read-rtl.o \
read-rtl-function.o \
diff -Nurp a/gcc/opts.c b/gcc/opts.c
--- a/gcc/opts.c 2019-12-19 21:12:20.264491749 +0800
+++ b/gcc/opts.c 2019-12-19 21:13:25.992489300 +0800
@@ -2128,6 +2128,18 @@ common_handle_option (struct gcc_options
case OPT_fprofile_use_:
opts->x_profile_data_prefix = xstrdup (arg);
+ /* No break here - do -fprofile-use processing. */
+ case OPT_fhcc_fgo_estimate_gen_:
+ /* No break here - do -fprofile-use processing. */
+ case OPT_fhcc_fgo_feature_gen_:
+ /* No break here - do -fprofile-use processing. */
+ case OPT_fhcc_fgo_feature_use_:
+ if (opts->x_fgo_feature_use && opts->x_fgo_feature_gen)
+ {
+ warning (0,
+ "-fhcc-fgo-feature-gen ignored because -fhcc-fgo-feature-use specified");
+ opts->x_fgo_feature_gen = NULL;
+ }
opts->x_flag_profile_use = true;
value = true;
/* No break here - do -fprofile-use processing. */
diff -Nurp a/gcc/params.def b/gcc/params.def
--- a/gcc/params.def 2019-12-19 21:12:20.340491746 +0800
+++ b/gcc/params.def 2019-12-19 21:13:25.996489300 +0800
@@ -402,6 +402,11 @@ DEFPARAM(HOT_BB_FREQUENCY_FRACTION,
"hot-bb-frequency-fraction",
"Select fraction of the maximal frequency of executions of basic block in function given basic block needs to have to be considered hot.",
1000, 0, 0)
+
+DEFPARAM(MIN_CONDITION_MATCHED_FRACTION,
+ "min-condition-matched-fraction",
+ "Select fraction of the minimal match rate of condition features. Used to determine whether the code has changed too much.",
+ 80, 20, 100)
DEFPARAM(UNLIKELY_BB_COUNT_FRACTION,
"unlikely-bb-count-fraction",
diff -Nurp a/gcc/predict.c b/gcc/predict.c
--- a/gcc/predict.c 2017-01-07 00:10:09.549265000 +0800
+++ b/gcc/predict.c 2019-12-19 21:16:40.832482042 +0800
@@ -56,7 +56,32 @@ along with GCC; see the file COPYING3.
#include "tree-ssa-loop.h"
#include "tree-scalar-evolution.h"
#include "ipa-utils.h"
+#include "langhooks.h"
#include "gimple-pretty-print.h"
+#include "profile-feature.h"
+#include "tree-ssa-operands.h"
+
+
+#define COLD_FUC_TAG "COLD_FUNCTION:"
+#define ERROR_LABEL_TAG "ERROR_LABEL:"
+#define ERROR_VARS_TAG "ERROR_VARS:"
+#define ERROR_RETURN_TAG "ERROR_RETURN:"
+#define US_MAX_VALUE_COUNT 100
+#define US_MAX_NAME_LEN 256
+#define US_MAX_STRLEN 2000
+#define SEPARATE "\t \n\r"
+
+/* Free memory for four lists. */
+#define FREE_LIST(TYPE, LIST, FREE_FUNC)\
+ do {\
+ size_t i;\
+ TYPE node = NULL;\
+ FOR_EACH_VEC_ELT (LIST, i, node)\
+ {\
+ FREE_FUNC (node);\
+ }\
+ LIST.release ();\
+ } while (0)
/* Enum with reasons why a predictor is ignored. */
@@ -117,6 +142,592 @@ static const struct predictor_info predi
};
#undef DEF_PREDICTOR
+/* The data type of formal argument. */
+typedef enum
+{
+ US_DT_INTEGER, /* Integer types, including char. */
+ US_DT_ENUMERAL /* C enums. */
+} US_DATA_TYPE;
+
+
+/* User-specific cold function. */
+typedef struct
+{
+ char name[US_MAX_NAME_LEN]; /* Function name. */
+ long arg_index; /* Argument index, start from 1, ignore arguments if ARG_INDEX < 1. */
+ US_DATA_TYPE arg_type; /* The data type of formal argument. */
+ int arg_value_count; /* Values count, for US_DT_INTEGER only. */
+ char* arg_values[US_MAX_VALUE_COUNT]; /* Expectable argument values. */
+ unsigned int count; /* The count of matching feature in config file. */
+} us_cold_function_def, *us_cold_function;
+
+/* User-specific error label. */
+typedef struct
+{
+ char name[US_MAX_NAME_LEN]; /* Label name. */
+ unsigned int count; /* The count of matching feature in config file. */
+} us_error_label_def, *us_error_label;
+
+/* User-specific error variable. */
+typedef struct
+{
+ char name[US_MAX_NAME_LEN]; /* Variable name. */
+ HOST_WIDE_INT success_value; /* The success value. */
+ unsigned int count; /* The count of matching config file. */
+} us_error_var_def, *us_error_var;
+
+typedef struct
+{
+ HOST_WIDE_INT return_value; /* The return value. */
+ unsigned int count; /* The count of matching feature in config file. */
+} us_error_return_def, *us_error_return;
+
+/* Four feature lists,each list stores its feature information. */
+vec<us_cold_function> cold_func_list;
+vec<us_error_label> error_label_list;
+vec<us_error_var> error_vars_list;
+vec<us_error_return> error_return_list;
+
+/* Two branch predictors: COLD_FUNC_PRED which is used in cold function
+ feature, ERROR_LABEL_PRED which is used in error label feature. */
+static const enum br_predictor COLD_FUNC_PRED = PRED_US_COLD_FUNC;
+static const enum br_predictor ERROR_LABEL_PRED = PRED_GOTO_ERROR_LABEL;
+
+/* User define fuction: turn string type to long. */
+
+static bool
+ud_strtol (const char *str, long *result)
+{
+ char *endptr = NULL;
+
+ if (!str)
+ {
+ return false;
+ }
+
+ *result = strtol (str, &endptr, 0);
+ if (*endptr != '\0')
+ {
+ inform (0, "the value of argument (%qs) in %qs is not currect.\n",
+ str, hcc_fgo_estimate_use);
+ return false;
+ }
+
+ return true;
+}
+
+/* Judge the ending symbol. */
+
+static bool
+line_feed_p (const char * str)
+{
+ if (strcmp (str,"\r\n") == 0 || strcmp (str,"\n") == 0 || strcmp (str,"\r") == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/* Free US_COLD_FUNCTION structure. */
+
+static void
+free_us_cold_function (us_cold_function node)
+{
+ int i;
+ for (i = 0; i < node->arg_value_count; i++)
+ {
+ free (node->arg_values[i]);
+ }
+ free (node);
+}
+
+/* Create new node to cold function list. */
+static us_cold_function
+create_new_node_for_cold_function (char *str)
+{
+ us_cold_function new_node = NULL;
+ char *arg_value = NULL, *func_name = NULL, *arg_index = NULL;
+ int i = 0;
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ func_name = strtok (str, SEPARATE);
+ if (!func_name)
+ {
+ inform (0, "No func info to optimize.");
+ return NULL;
+ }
+ arg_index = strtok (NULL, SEPARATE);
+ if (!arg_index)
+ {
+ inform (0, "No info to optimize.");
+ return NULL;
+ }
+ new_node = XNEW (us_cold_function_def);
+ memset (new_node, 0, sizeof (us_cold_function_def));
+ strncpy (new_node->name, func_name, strlen (func_name));
+ if (!ud_strtol (arg_index, &new_node->arg_index))
+ {
+ free_us_cold_function (new_node);
+ return NULL;
+ }
+ arg_value = strtok (NULL, SEPARATE);
+ if (arg_value)
+ {
+ if ((arg_value[0] >= '0' && arg_value[0] <= '9')
+ || arg_value[0] == '-'
+ || arg_value[0] == '+')
+ {
+ new_node->arg_type = US_DT_INTEGER;
+ }
+ else
+ {
+ new_node->arg_type = US_DT_ENUMERAL;
+ }
+ while (arg_value != NULL && i < US_MAX_VALUE_COUNT)
+ {
+ new_node->arg_values[i] = (char *)xmalloc (strlen (arg_value) + 1);
+ strncpy (new_node->arg_values[i],
+ arg_value, strlen (arg_value));
+ arg_value = strtok (NULL, SEPARATE);
+ i++;
+ }
+ new_node->arg_value_count = i;
+
+ if (new_node->arg_type == US_DT_INTEGER)
+ {
+ for (i = 0; i < new_node->arg_value_count; i++)
+ {
+ long value;
+
+ if (!ud_strtol (new_node->arg_values[i], &value))
+ {
+ free_us_cold_function (new_node);
+ return NULL;
+ }
+ }
+ }
+ }
+ else
+ {
+ new_node->arg_value_count = 0;
+ }
+
+ return new_node;
+}
+
+/* Create cold function list. */
+
+void
+create_function_list (FILE *config_fp)
+{
+ char str[US_MAX_STRLEN];
+
+ while (fgets (str, US_MAX_STRLEN, config_fp) != NULL)
+ {
+ us_cold_function pnew = NULL;
+
+ if (line_feed_p (str))
+ {
+ break;
+ }
+
+ pnew = create_new_node_for_cold_function (str);
+ if (!pnew)
+ {
+ continue;
+ }
+
+ cold_func_list.safe_push (pnew);
+ }
+
+}
+
+/* Create new node to error label list. */
+
+static us_error_label
+create_new_node_for_error_lable (char *str)
+{
+ us_error_label new_node = NULL;
+ char * label_name = NULL;
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ label_name = strtok (str, SEPARATE);
+ if (label_name == NULL)
+ {
+ inform (0, "No label info to optimize.");
+ return NULL;
+ }
+ new_node = XNEW (us_error_label_def);
+ memset (new_node, 0, sizeof (us_error_label_def));
+ strncpy (new_node->name, label_name, strlen (label_name));
+
+ return new_node;
+}
+
+/* Create error label list. */
+
+void
+create_error_label_list (FILE *config_fp)
+{
+ char str[US_MAX_STRLEN];
+
+ while (fgets (str, US_MAX_STRLEN, config_fp) != NULL)
+ {
+ us_error_label pnew = NULL;
+
+ if (line_feed_p (str))
+ {
+ break;
+ }
+
+ pnew = create_new_node_for_error_lable (str);
+ if (!pnew)
+ {
+ continue;
+ }
+
+ error_label_list.safe_push (pnew);
+ }
+
+}
+
+/* Create new node to error vars list. */
+
+static us_error_var
+create_new_node_for_error_vars (char *str)
+{
+ us_error_var new_node = NULL;
+ char *var_name = NULL, *success_value = NULL;
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ var_name = strtok (str, SEPARATE);
+ if (!var_name)
+ {
+ inform (0, "No Var info to optimize.");
+ return NULL;
+ }
+ success_value = strtok (NULL, SEPARATE);
+ if (!success_value)
+ {
+ inform (0, "No info to optimize.");
+ return NULL;
+ }
+ new_node = XNEW (us_error_var_def);
+ memset (new_node, 0, sizeof (us_error_var_def));
+ strncpy (new_node->name, var_name, strlen (var_name));
+ if (!ud_strtol (success_value, &new_node->success_value))
+ {
+ free (new_node);
+ return NULL;
+ }
+ return new_node;
+}
+
+/* Creat error vars linklist. */
+void
+create_error_vars_list (FILE *config_fp)
+{
+ char str[US_MAX_STRLEN];
+
+ while (fgets (str, US_MAX_STRLEN, config_fp) != NULL)
+ {
+ us_error_var pnew = NULL;
+
+ if (line_feed_p (str))
+ {
+ break;
+ }
+
+ pnew = create_new_node_for_error_vars (str);
+ if (!pnew)
+ {
+ continue;
+ }
+
+ error_vars_list.safe_push (pnew);
+ }
+
+}
+
+/* Create new node for error return list. */
+
+static us_error_return
+create_new_node_for_error_return (char *str)
+{
+ us_error_return new_node = NULL;
+ char *return_value = NULL;
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ return_value = strtok (str, SEPARATE);
+ if (!return_value)
+ {
+ inform (0, "No info to optimize.");
+ return NULL;
+ }
+ new_node = XNEW (us_error_return_def);
+ memset (new_node, 0, sizeof (us_error_return_def));
+ if (!ud_strtol (return_value, &new_node->return_value))
+ {
+ free (new_node);
+ return NULL;
+ }
+
+ return new_node;
+}
+
+/* Create error return list. */
+
+void
+create_error_return_list (FILE *config_fp)
+{
+ char str[US_MAX_STRLEN];
+
+ while (fgets (str, US_MAX_STRLEN, config_fp) != NULL)
+ {
+ us_error_return pnew = NULL;
+
+ if (line_feed_p (str))
+ {
+ break;
+ }
+
+ pnew = create_new_node_for_error_return (str);
+ if (!pnew)
+ {
+ continue;
+ }
+
+ error_return_list.safe_push (pnew);
+ }
+}
+
+/* Analysis config file. */
+
+static void
+analysis_config_file (void)
+{
+ FILE *config_fp = NULL;
+ char str[US_MAX_STRLEN], tag[US_MAX_STRLEN];
+
+
+ /* Open the config file. */
+ const char *mode = "r";
+ if ((config_fp = verify_path (hcc_fgo_estimate_use, mode)) == NULL)
+ {
+ warning (0,"can not open the config file %qs, make sure it exists",
+ hcc_fgo_estimate_use);
+ hcc_fgo_estimate_use = NULL;
+ return;
+ }
+ while (fgets (str, US_MAX_STRLEN, config_fp) != NULL)
+ {
+ memset (tag, 0, US_MAX_STRLEN);
+ if (str[0])
+ {
+ sscanf (str, "%s", tag);
+ }
+
+ if (strcmp (tag, COLD_FUC_TAG) == 0)
+ {
+ if (cold_func_list.exists ())
+ {
+ inform (0, "cold_func_list is not NULL");
+ FREE_LIST (us_cold_function, cold_func_list, free_us_cold_function);
+ }
+ create_function_list (config_fp);
+ }
+
+ if (strcmp (tag, ERROR_LABEL_TAG) == 0)
+ {
+ if (error_label_list.exists ())
+ {
+ inform (0, "error_label_list is not NULL");
+ FREE_LIST (us_error_label, error_label_list, free);
+ }
+ create_error_label_list (config_fp);
+ }
+
+ if (strcmp (tag, ERROR_VARS_TAG) == 0)
+ {
+ if (error_vars_list.exists ())
+ {
+ inform (0, "error_vars_list is not NULL");
+ FREE_LIST (us_error_var, error_vars_list, free);
+ }
+ create_error_vars_list (config_fp);
+ }
+
+ if (strcmp (tag, ERROR_RETURN_TAG) == 0)
+ {
+ if (error_return_list.exists ())
+ {
+ inform (0, "error_return_list is not NULL");
+ FREE_LIST (us_error_return, error_return_list, free);
+ }
+ create_error_return_list (config_fp);
+ }
+ }
+
+ fclose (config_fp);
+}
+
+/* Reset the count. */
+
+static void
+reset_count (void)
+{
+ size_t i;
+ us_cold_function func = NULL;
+ us_error_label us_label = NULL;
+ us_error_var pvar = NULL;
+ us_error_return preturn = NULL;
+
+ FOR_EACH_VEC_ELT (cold_func_list, i, func)
+ {
+ if (!func)
+ {
+ break;
+ }
+ func->count = 0;
+ }
+
+ FOR_EACH_VEC_ELT (error_label_list, i, us_label)
+ {
+ if (!us_label)
+ {
+ break;
+ }
+ us_label->count = 0;
+ }
+
+ FOR_EACH_VEC_ELT (error_vars_list, i, pvar)
+ {
+ if (!pvar)
+ {
+ break;
+ }
+ pvar->count = 0;
+ }
+
+ FOR_EACH_VEC_ELT (error_return_list, i, preturn)
+ {
+ if (!preturn)
+ {
+ break;
+ }
+ preturn->count = 0;
+ }
+}
+
+/* Print the matching information to DUMPFILE. */
+
+static void
+print_matched_features (FILE * dumpfile)
+{
+ size_t i;
+ us_cold_function func = NULL;
+ us_error_label us_label = NULL;
+ us_error_var pvar = NULL;
+ us_error_return preturn = NULL;
+ const char * cur_func = NULL;
+
+ if (dumpfile)
+ {
+ /* 2 mean the tree has two branch. */
+ cur_func = lang_hooks.decl_printable_name (current_function_decl, 2);
+
+ FOR_EACH_VEC_ELT (cold_func_list, i, func)
+ {
+ if (!func)
+ {
+ break;
+ }
+ if (func->count > 0)
+ {
+ fprintf (dumpfile, "fgo-estimate-use: %s ", cur_func);
+ fprintf (dumpfile, "COLD_FUNCTION: %s ", func->name);
+ fprintf (dumpfile, "%ld ", func->arg_index);
+ if (func->arg_index >= 1)
+ {
+ int i;
+ for (i = 0; i < func->arg_value_count; i++)
+ fprintf (dumpfile, "%s ", func->arg_values[i]);
+ }
+ fprintf (dumpfile, "COUNT: %u\n", func->count);
+ }
+ }
+
+ FOR_EACH_VEC_ELT (error_label_list, i, us_label)
+ {
+ if (!us_label)
+ {
+ break;
+ }
+ if (us_label->count > 0)
+ {
+ fprintf (dumpfile, "fgo-estimate-use: %s ", cur_func);
+ fprintf (dumpfile, "ERROR_LABEL: %s ", us_label->name);
+ fprintf (dumpfile, "COUNT: %u\n", us_label->count);
+ }
+ }
+
+ FOR_EACH_VEC_ELT (error_vars_list, i, pvar)
+ {
+ if (!pvar)
+ {
+ break;
+ }
+ if (pvar->count > 0)
+ {
+ fprintf (dumpfile, "fgo-estimate-use: %s ", cur_func);
+ fprintf (dumpfile, "ERROR_VARS: %s %" PRId64" ", pvar->name,
+ pvar->success_value);
+ fprintf (dumpfile, "COUNT: %u\n", pvar->count);
+ }
+ }
+
+ FOR_EACH_VEC_ELT (error_return_list, i, preturn)
+ {
+ if (!preturn)
+ {
+ break;
+ }
+ if (preturn->count > 0)
+ {
+ fprintf (dumpfile, "fgo-estimate-use: %s ", cur_func);
+ fprintf (dumpfile, "ERROR_RETURN: ");
+ fprintf (dumpfile, "%" PRId64" COUNT: %u\n", preturn->return_value,
+ preturn->count);
+ }
+ }
+ }
+}
+
+/* Free memory for predict. */
+
+void
+free_memory_for_predict (void)
+{
+ FREE_LIST (us_cold_function, cold_func_list, free_us_cold_function);
+
+ FREE_LIST (us_error_label, error_label_list, free);
+
+ FREE_LIST (us_error_var, error_vars_list, free);
+
+ FREE_LIST (us_error_return, error_return_list, free);
+}
+
/* Return TRUE if frequency FREQ is considered to be hot. */
static inline bool
@@ -2439,6 +3050,45 @@ tree_predict_by_opcode (basic_block bb)
predict_edge_def (then_edge, PRED_TREE_POINTER, TAKEN);
}
else
+ {
+ bool is_except_error_var = false;
+
+ if (hcc_fgo_estimate_use && error_vars_list.exists ())
+ {
+ /* Determine whether OP0 is a error variable. */
+ if (TREE_CODE (op0) == SSA_NAME && TREE_CODE (op1) == INTEGER_CST)
+ {
+ const_tree var = SSA_NAME_VAR (op0);
+ if (!var)
+ {
+ return;
+ }
+ if (TREE_CODE (var) == VAR_DECL && DECL_NAME (var))
+ {
+ size_t i;
+ us_error_var pvar = NULL;
+ const char* decl_name = IDENTIFIER_POINTER (DECL_NAME (var));
+
+ FOR_EACH_VEC_ELT (error_vars_list, i, pvar)
+ {
+ if (!pvar)
+ {
+ break;
+ }
+ if (strcmp (decl_name, pvar->name) == 0)
+ {
+ HOST_WIDE_INT except_value = pvar->success_value;
+ if ((unsigned HOST_WIDE_INT) except_value == TREE_INT_CST_LOW (op1))
+ {
+ is_except_error_var = true;
+ pvar->count++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
/* Try "opcode heuristic."
EQ tests are usually false and NE tests are usually true. Also,
@@ -2453,6 +3103,10 @@ tree_predict_by_opcode (basic_block bb)
FP code. */
if (FLOAT_TYPE_P (type))
;
+ else if (hcc_fgo_estimate_use && is_except_error_var)
+ {
+ predict_edge_def (then_edge, PRED_US_ERROR_VAR_EQ_SUCC, TAKEN);
+ }
/* Comparisons with 0 are often used for booleans and there is
nothing useful to predict about them. */
else if (integer_zerop (op0) || integer_zerop (op1))
@@ -2468,6 +3122,10 @@ tree_predict_by_opcode (basic_block bb)
FP code. */
if (FLOAT_TYPE_P (type))
;
+ else if (hcc_fgo_estimate_use && is_except_error_var)
+ {
+ predict_edge_def (then_edge, PRED_US_ERROR_VAR_NE_SUCC, NOT_TAKEN);
+ }
/* Comparisons with 0 are often used for booleans and there is
nothing useful to predict about them. */
else if (integer_zerop (op0)
@@ -2510,6 +3168,51 @@ tree_predict_by_opcode (basic_block bb)
default:
break;
}
+ }
+
+
+}
+
+/* Get user-specific error return structure. */
+
+static us_error_return
+get_us_error_return (tree val)
+{
+ size_t i;
+ us_error_return preturn = NULL;
+
+ if (!error_return_list.exists ())
+ {
+ return NULL;
+ }
+
+ if (TREE_CODE (val) == INTEGER_CST
+ && tree_int_cst_sgn (val) < 0)
+ {
+ return NULL;
+ }
+
+ if (INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ {
+ FOR_EACH_VEC_ELT (error_return_list, i, preturn)
+ {
+ if (!preturn)
+ {
+ break;
+ }
+ if (((tree_fits_shwi_p (val)
+ && (HOST_WIDE_INT) TREE_INT_CST_LOW (val)
+ == (HOST_WIDE_INT) preturn->return_value))
+ || ((tree_fits_uhwi_p (val)
+ && (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (val)
+ == (unsigned HOST_WIDE_INT) preturn->return_value)))
+ {
+ return preturn;
+ }
+ }
+ }
+
+ return NULL;
}
/* Returns TRUE if the STMT is exit(0) like statement. */
@@ -2555,6 +3258,19 @@ return_prediction (tree val, enum predic
*prediction = NOT_TAKEN;
return PRED_NEGATIVE_RETURN;
}
+
+ if (hcc_fgo_estimate_use)
+ {
+ if (TREE_CODE (val) == INTEGER_CST)
+ {
+ if (NULL != get_us_error_return (val))
+ {
+ *prediction = NOT_TAKEN;
+ return PRED_NEGATIVE_RETURN;
+ }
+ }
+ }
+
/* Constant return values seems to be commonly taken.
Zero/one often represent booleans so exclude them from the
heuristics. */
@@ -2616,11 +3332,211 @@ apply_return_prediction (void)
{
pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
if (pred != PRED_NO_PREDICTION)
- predict_paths_leading_to_edge (gimple_phi_arg_edge (phi, i), pred,
- direction);
+ {
+ if (hcc_fgo_estimate_use)
+ {
+ us_error_return us_return;
+
+ us_return = get_us_error_return (PHI_ARG_DEF (phi, i));
+ if (NULL != us_return)
+ {
+ us_return->count++;
+ }
+ }
+ predict_paths_leading_to_edge (gimple_phi_arg_edge\
+ (phi, i), pred, direction);
+ }
}
}
+/* Return TRUE if the ARG has the expectable value. */
+
+static bool
+argument_expectable_p (const_tree arg, const us_cold_function func)
+{
+ const_tree type = TREE_TYPE (arg);
+
+ gcc_assert (arg != NULL);
+
+ if (TREE_CODE (arg) == INTEGER_CST)
+ {
+ const unsigned HOST_WIDE_INT arg_value = TREE_INT_CST_LOW (arg);
+
+ if (func->arg_type == US_DT_INTEGER && TREE_CODE (type) == INTEGER_TYPE)
+ {
+ int i = 0;
+
+ for (; i < func->arg_value_count; i++)
+ {
+ long except_value = 0;
+ bool ret = ud_strtol (func->arg_values[i], &except_value);
+ if (ret && arg_value == except_value)
+ {
+ return true;
+ }
+ }
+ }
+ else if (func->arg_type == US_DT_ENUMERAL
+ && TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ const_tree type_value = TYPE_VALUES (type);
+
+ /* Determine the type-value of DATA. */
+ while (type_value && type_value != error_mark_node)
+ {
+ const_tree purpose = TREE_PURPOSE (type_value);
+
+ if (purpose
+ && TREE_CODE (purpose) == IDENTIFIER_NODE
+ && TREE_INT_CST_LOW (TREE_VALUE (type_value))
+ == (unsigned HOST_WIDE_INT)arg_value)
+ {
+ int i = 0;
+ const char* arg_identifier = IDENTIFIER_POINTER (purpose);
+
+ /* Check whether the ARG is expectable value. */
+ for (; i < US_MAX_VALUE_COUNT; i++)
+ {
+ const char* expect_value
+ = (const char*) func->arg_values[i];
+
+ if (!expect_value)
+ break;
+
+ if (strcmp (arg_identifier, expect_value) == 0)
+ {
+ return true;
+ }
+ }
+
+ /* Miss match. */
+ return false;
+ }
+
+ type_value = TREE_CHAIN (type_value);
+ }
+ }
+ }
+
+ return false;
+}
+
+/* Return predictor if GS is a user-specific cold function.
+ Imitate print_call_name. */
+
+static const enum br_predictor*
+get_user_specific_cold_func_pred (const gimple *gs)
+{
+ const char * function_name = 0;
+
+ if (!cold_func_list.exists ())
+ {
+ return NULL;
+ }
+
+ if (!is_gimple_call (gs))
+ {
+ return NULL;
+ }
+
+ if (!gimple_call_internal_p (gs))
+ {
+ function_name = get_callee_name (gs);
+
+ if (function_name)
+ {
+ size_t i;
+ us_cold_function func = NULL;
+
+ if (cold_func_list.is_empty ())
+ {
+ return NULL;
+ }
+
+ /* Determine whether GS is a cold function. */
+ FOR_EACH_VEC_ELT (cold_func_list, i, func)
+ {
+ if (!func)
+ {
+ break;
+ }
+ int arg_index = func->arg_index - 1;
+ if (strcmp (function_name, func->name) == 0)
+ {
+ if (arg_index < 0)
+ {
+ /* Ignore arguments. */
+ func->count++;
+ return &COLD_FUNC_PRED;
+ }
+ else if ((unsigned) arg_index < gimple_call_num_args (gs))
+ {
+ /* Check argument value. */
+ const_tree arg = gimple_call_arg (gs, arg_index);
+
+ if (argument_expectable_p (arg, func))
+ {
+ func->count++;
+ return &COLD_FUNC_PRED;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Return predictor if GS is a user-specific error label. */
+
+static const enum br_predictor*
+get_user_specific_error_label_pred (const glabel *gs)
+{
+ const_tree label = NULL;
+
+ if (!error_label_list.exists ())
+ {
+ return NULL;
+ }
+
+ if (gimple_code (gs) != GIMPLE_LABEL)
+ {
+ return NULL;
+ }
+
+ label = gimple_label_label (gs);
+
+ gcc_assert (TREE_CODE (label) == LABEL_DECL);
+
+ if (DECL_NAME (label))
+ {
+ const char* label_name = IDENTIFIER_POINTER (DECL_NAME (label));
+
+ if (label_name)
+ {
+ size_t i;
+ us_error_label us_label = NULL;
+
+ /* Determine whether GS is a error label. */
+ FOR_EACH_VEC_ELT (error_label_list, i, us_label)
+ {
+ if (!us_label)
+ {
+ break;
+ }
+ if (strcmp (label_name, us_label->name) == 0)
+ {
+ us_label->count++;
+ return &ERROR_LABEL_PRED;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
/* Look for basic block that contains unlikely to happen events
(such as noreturn calls) and mark all paths leading to execution
of this basic blocks as unlikely. */
@@ -2650,6 +3566,7 @@ tree_bb_level_predictions (void)
{
gimple *stmt = gsi_stmt (gsi);
tree decl;
+ const enum br_predictor* pred = NULL;
if (is_gimple_call (stmt))
{
@@ -2667,6 +3584,21 @@ tree_bb_level_predictions (void)
if (decl && recursive_call_p (current_function_decl, decl))
predict_paths_leading_to (bb, PRED_RECURSIVE_CALL,
NOT_TAKEN);
+ if (hcc_fgo_estimate_use)
+ {
+ pred = get_user_specific_cold_func_pred (stmt);
+ if (pred)
+ predict_paths_leading_to (bb, *pred, NOT_TAKEN);
+ }
+ }
+ else if (gimple_code (stmt) == GIMPLE_LABEL)
+ {
+ if (hcc_fgo_estimate_use)
+ {
+ pred = get_user_specific_error_label_pred (dyn_cast <glabel *>(stmt));
+ if (pred)
+ predict_paths_leading_to (bb, *pred, NOT_TAKEN);
+ }
}
else if (gimple_code (stmt) == GIMPLE_PREDICT)
{
@@ -2800,6 +3732,221 @@ tree_estimate_probability_bb (basic_bloc
tree_predict_by_opcode (bb);
}
+/* This is the hook to get estimated probability. */
+
+static int
+get_edge_guess_prob (edge e)
+{
+ return e->probability;
+}
+
+/* Annotate branch probability with features file. */
+
+static bool
+annotate_condition_features (void)
+{
+ const char *filename = NULL;
+ const char *funcname = NULL;
+ basic_block bb = NULL;
+ gimple *cond_stmt = NULL;
+
+ prof_bb_info bb_info;
+ prof_cond_info cond_info;
+ prof_func_info *func_info = NULL;
+
+ int num_conds = 0;
+ int num_conds_exec = 0;
+ int num_conds_match = 0;
+ const int max_probra = 10000;
+ const float probra = 100.0;
+ float match_rate;
+ const char *mode = "r";
+ bitmap skipped = NULL; /* The skipped blocks. */
+
+ /* Only handle the C file. */
+ if (strcmp (lang_hooks.name, "GNU C11") != 0)
+ {
+ return false;
+ }
+
+ /* Load the features. */
+ if (!g_prof_prog)
+ {
+ FILE *metrics_file = verify_path (fgo_feature_use, mode);
+ if (metrics_file == NULL)
+ {
+ inform (0, "could not open features file %s", fgo_feature_use);
+ return false;
+ }
+
+ parse_profile_file (metrics_file);
+ fclose (metrics_file);
+ }
+
+ get_curr_filename_and_funcname (&filename, &funcname);
+
+ /* Find the features of current function. */
+ func_info = find_prof_func_in_prog (filename, funcname, g_prof_prog);
+ if (!func_info)
+ {
+ if (warn_fgo_feature_obsolete)
+ {
+ warning (OPT_Whcc_fgo_feature_obsolete,
+ "condition features of function %s not found", funcname);
+ }
+ return false;
+ }
+
+ skipped = BITMAP_ALLOC (NULL);
+
+ /* Init cond_info. */
+ bb_info.next = NULL;
+ cond_info.first_bb = &bb_info;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ prof_cond_info *cond_info_in = NULL; /* Features from file. */
+ edge not_exec_branch = NULL;
+ edge then_edge = NULL, else_edge = NULL;
+ bool is_ok = false;
+ /* Only handle bb with 2 out-edges.
+ Refer to combine_predictions_for_bb(). */
+ if (!(bb->index >= NUM_FIXED_BLOCKS
+ && block_ends_with_condjump_p (bb)
+ && EDGE_COUNT (bb->succs) == 2))
+ {
+ continue;
+ }
+
+ num_conds++;
+
+ if (bitmap_bit_p (skipped, bb->index))
+ {
+ continue;
+ }
+
+ num_conds_exec++;
+
+ cond_stmt = last_stmt (CONST_CAST_BB (bb));
+ gcc_assert (cond_stmt && gimple_code (cond_stmt) == GIMPLE_COND);
+
+ is_ok = extract_prof_cond (bb, &cond_info, get_edge_guess_prob);
+ if (!is_ok)
+ {
+ continue;
+ }
+ /* Search for matched item. */
+ cond_info_in = find_prof_cond (func_info, &cond_info);
+ if (cond_info_in)
+ num_conds_match++;
+
+ gcc_assert ((EDGE_SUCC (bb, 0)->flags & EDGE_TRUE_VALUE)
+ || (EDGE_SUCC (bb, 1)->flags & EDGE_TRUE_VALUE));
+
+ if (EDGE_SUCC (bb, 0)->flags & EDGE_TRUE_VALUE)
+ {
+ then_edge = EDGE_SUCC (bb, 0);
+ else_edge = EDGE_SUCC (bb, 1);
+ }
+ else
+ {
+ then_edge = EDGE_SUCC (bb, 1);
+ else_edge = EDGE_SUCC (bb, 0);
+ }
+
+
+ /* Dump matching information. */
+ if (dump_file)
+ {
+ const char *match = cond_info_in ? "MATCH" : "NOT_MATCH";
+
+ fprintf (dump_file, "fgo-feature-use: %s %s %s %s %s ", funcname,
+ match, cond_info.lhs.var_name, get_cmp_str (cond_info.cmp),
+ cond_info.rhs.var_name);
+
+ if (!cond_info_in)
+ fprintf (dump_file, "-");
+ else
+ fprintf (dump_file, "%.2f%%", cond_info_in->first_bb->profile_prob
+ * probra/ REG_BR_PROB_BASE);
+
+ fprintf (dump_file, " (guess=%.2f%%) ",
+ cond_info.first_bb->guess_prob * probra / REG_BR_PROB_BASE);
+
+ fprintf (dump_file, " [edge: %d->%d] ", bb->index,
+ then_edge->dest->index);
+
+ print_gimple_stmt (dump_file, cond_stmt, 0, 0);
+ }
+
+ if (!cond_info_in)
+ {
+ continue;
+ }
+
+ /* Annotate branch probability. */
+ then_edge->probability = cond_info_in->first_bb->profile_prob;
+ else_edge->probability = REG_BR_PROB_BASE
+ - cond_info_in->first_bb->profile_prob;
+
+ if (then_edge->probability == 0)
+ {
+ not_exec_branch = then_edge;
+ }
+ else if (else_edge->probability == 0)
+ {
+ not_exec_branch = else_edge;
+ }
+
+ /* Mark the not executed blocks. */
+ if (not_exec_branch && single_pred_p (not_exec_branch->dest))
+ {
+ size_t i;
+ basic_block tmp_bb = NULL;
+ vec<basic_block> skipped_bbs = get_all_dominated_blocks (
+ CDI_DOMINATORS, not_exec_branch->dest);
+
+ FOR_EACH_VEC_ELT (skipped_bbs, i, tmp_bb)
+ {
+ if (!tmp_bb)
+ {
+ break;
+ }
+ bitmap_set_bit (skipped, tmp_bb->index);
+ }
+ }
+ }
+
+ match_rate = num_conds_exec > 0
+ ? num_conds_match * probra / num_conds_exec : 0;
+
+ /* Dump summary information of function. */
+ if (dump_file)
+ {
+ fprintf (dump_file,
+ "fgo-feature-use-summary: %s conds=%d exec=%d match=%d[%.2f%%]\n",
+ funcname, num_conds, num_conds_exec, num_conds_match, match_rate);
+ }
+
+ /* Warn when the condition features are out of date. */
+ if (warn_fgo_feature_obsolete
+ && num_conds_exec > 0
+ && func_info->max_bb_count > fake_profile_info.sum_max/max_probra)
+ {
+ int min_matched_fraction = PARAM_VALUE (MIN_CONDITION_MATCHED_FRACTION);
+
+ if (match_rate < min_matched_fraction)
+ warning (
+ OPT_Whcc_fgo_feature_obsolete,
+ "source code of function '%s' have changed too much, file '%s' may be out of date",
+ funcname, fgo_feature_use);
+ }
+
+ BITMAP_FREE (skipped);
+
+ return true;
+}
+
/* Predict branch probabilities and estimate profile of the tree CFG.
This function can be called from the loop optimizers to recompute
the profile information.
@@ -2810,6 +3957,23 @@ tree_estimate_probability (bool dry_run)
{
basic_block bb;
+ if (hcc_fgo_estimate_use)
+ {
+ /* Only handle the C file. */
+ if (strcmp (lang_hooks.name, "GNU C11") == 0)
+ {
+ if ((!cold_func_list.exists ())
+ && (!error_label_list.exists ())
+ && (!error_vars_list.exists ())
+ && (!error_return_list.exists ()))
+ analysis_config_file ();
+ else
+ reset_count ();
+ }
+ else
+ hcc_fgo_estimate_use = NULL;
+ }
+
add_noreturn_fake_exit_edges ();
connect_infinite_loops_to_exit ();
/* We use loop_niter_by_eval, which requires that the loops have
@@ -2830,12 +3994,22 @@ tree_estimate_probability (bool dry_run)
FOR_EACH_BB_FN (bb, cfun)
combine_predictions_for_bb (bb, dry_run);
+ if (hcc_fgo_estimate_use)
+ {
+ print_matched_features (dump_file);
+ }
+
if (flag_checking)
bb_predictions->traverse<void *, assert_is_empty> (NULL);
delete bb_predictions;
bb_predictions = NULL;
+ if (fgo_feature_use)
+ {
+ annotate_condition_features ();
+ }
+
if (!dry_run)
estimate_bb_frequencies (false);
free_dominance_info (CDI_POST_DOMINATORS);
diff -Nurp a/gcc/predict.def b/gcc/predict.def
--- a/gcc/predict.def 2017-01-10 17:14:54.560254000 +0800
+++ b/gcc/predict.def 2019-12-19 21:13:26.000489300 +0800
@@ -92,6 +92,14 @@ DEF_PREDICTOR (PRED_COLD_FUNCTION, "cold
DEF_PREDICTOR (PRED_LOOP_EXIT, "loop exit", HITRATE (85),
PRED_FLAG_FIRST_MATCH)
+/* Branch containing user-specific cold function call is probably not taken. */
+DEF_PREDICTOR (PRED_US_COLD_FUNC, "user-specific cold function call(very likely)",
+ PROB_VERY_LIKELY, PRED_FLAG_FIRST_MATCH)
+
+/* Branch which going to error-label is probably not taken. */
+DEF_PREDICTOR (PRED_GOTO_ERROR_LABEL, "goto error-label(very likely)",
+ PROB_VERY_LIKELY, PRED_FLAG_FIRST_MATCH)
+
/* Same as LOOP_EXIT but for loops containing recursive call. */
DEF_PREDICTOR (PRED_LOOP_EXIT_WITH_RECURSION, "loop exit with recursion",
HITRATE (72), PRED_FLAG_FIRST_MATCH)
@@ -105,6 +113,10 @@ DEF_PREDICTOR (PRED_LOOP_EXTRA_EXIT, "ex
DEF_PREDICTOR (PRED_POINTER, "pointer", HITRATE (70), 0)
DEF_PREDICTOR (PRED_TREE_POINTER, "pointer (on trees)", HITRATE (70), 0)
+/* The value of user-specific error variable is probably 0(success). */
+DEF_PREDICTOR (PRED_US_ERROR_VAR_EQ_SUCC, "user-specific error variable is success", HITRATE (73), 0)
+DEF_PREDICTOR (PRED_US_ERROR_VAR_NE_SUCC, "user-specific error variable is not success", HITRATE (95), 0)
+
/* NE is probable, EQ not etc... */
DEF_PREDICTOR (PRED_OPCODE_POSITIVE, "opcode values positive", HITRATE (64), 0)
DEF_PREDICTOR (PRED_OPCODE_NONEQUAL, "opcode values nonequal", HITRATE (66), 0)
diff -Nurp a/gcc/predict.h b/gcc/predict.h
--- a/gcc/predict.h 2017-01-01 20:07:43.905435000 +0800
+++ b/gcc/predict.h 2019-12-19 21:13:26.000489300 +0800
@@ -92,5 +92,6 @@ extern const char *predictor_name (enum
extern void rebuild_frequencies (void);
extern void report_predictor_hitrates (void);
extern void force_edge_cold (edge, bool);
+extern void free_memory_for_predict(void);
#endif /* GCC_PREDICT_H */
diff -Nurp a/gcc/profile.c b/gcc/profile.c
--- a/gcc/profile.c 2019-12-19 21:12:20.268491749 +0800
+++ b/gcc/profile.c 2019-12-19 21:13:26.008489300 +0800
@@ -64,10 +64,13 @@ along with GCC; see the file COPYING3.
#include "tree-cfg.h"
#include "dumpfile.h"
#include "cfgloop.h"
+#include "langhooks.h"
+#include "profile-feature.h"
#include "profile.h"
#include "auto-profile.h"
+
struct bb_profile_info {
unsigned int count_valid : 1;
@@ -506,6 +509,205 @@ compute_frequency_overlap (void)
return overlap;
}
+/* This is the hook to get estimated probability. */
+
+static int
+get_edge_guess_prob (edge e)
+{
+ return EDGE_INFO (e)->guess_prob;
+}
+
+/* Generate condition features and dump them on given file.
+ NBR is the number of executed branches. */
+
+static void
+generate_condition_features (int nbr)
+{
+ const char *filename = NULL;
+ const char *funcname = NULL;
+ prof_file_info file;
+ prof_func_info func;
+
+ basic_block bb = NULL;
+
+ gcov_type curr_count_max = 0; /* The hottest bb's count. */
+ FILE *feature_file = NULL;
+
+ int num_branches_exec = 0; /* Number of executed condition statements. */
+
+ /* For dumping. */
+ int index;
+ int overlap; /* For comparing the static estimated profile to the actual profile. */
+ int num_branches = 0; /* Number of condition statements. */
+ int num_branches_hot = 0; /* Number of hot condition statements. */
+ int num_prob95, num_prob90, num_prob85; /* Probability for analysing. */
+ const float base_probra = 100.0f;
+ const int base = 100;
+ gcov_type curr_count_sum = 0;
+
+ const char *mode = "a";
+
+ /* Skip the function which was not called. */
+ if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count == 0)
+ {
+ return;
+ }
+
+ /* Only handle the C file. */
+ if (strcmp (lang_hooks.name, "GNU C11") != 0)
+ {
+ return;
+ }
+
+ /* Open the feature file. */
+ feature_file = verify_path (fgo_feature_gen, mode);
+ if (NULL == feature_file)
+ {
+ inform (0, "failed to write %s.", fgo_feature_gen);
+ return;
+ }
+
+ /* Initialize FILE and FUNC. */
+ memset (&file, 0, sizeof (prof_file_info));
+ memset (&func, 0, sizeof (prof_func_info));
+ file.first_func = &func;
+ func.count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
+ func.file = &file;
+
+ /* Get current file name and function name. */
+ if (current_function_decl)
+ {
+ get_curr_filename_and_funcname (&filename, &funcname);
+
+ strncpy (file.name, filename, strlen (filename));
+
+ strncpy (func.name, funcname, strlen (funcname));
+ }
+
+ num_prob95 = num_prob90 = num_prob85 = 0;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ prof_cond_info *cond = NULL;
+ bool is_ok = false;
+
+ edge then_edge = NULL;
+ edge_iterator ei;
+
+ curr_count_max = MAX (bb->count, curr_count_max);
+
+ if (dump_file)
+ {
+ curr_count_sum += bb->count;
+ }
+
+ /* Stat cond stmt. TODO: switch...case... */
+ if (!(bb->index >= NUM_FIXED_BLOCKS
+ && block_ends_with_condjump_p (bb)
+ && EDGE_COUNT (bb->succs) >= 2))
+ {
+ continue;
+ }
+
+ if (dump_file)
+ {
+ num_branches++;
+ }
+
+ if (!bb->count)
+ {
+ continue;
+ }
+
+ num_branches_exec++;
+
+ FOR_EACH_EDGE (then_edge, ei, bb->succs)
+ if (then_edge->flags & EDGE_TRUE_VALUE)
+ {
+ break;
+ }
+
+ if (dump_file)
+ {
+
+ /* Hot branches. */
+ if (bb->count >= (func.count / base))
+ {
+ num_branches_hot++;
+ }
+
+ /* Compute probability range. */
+ index = then_edge->probability * 20 / REG_BR_PROB_BASE;
+ if ((index == 0) || (index == 19) || (index == 20))
+ {
+ num_prob95++;
+ }
+ else if ((index == 1) || (index == 18))
+ {
+ num_prob90++;
+ }
+ else if ((index == 2) || (index == 17))
+ {
+ num_prob85++;
+ }
+ }
+
+ /* Generate condition features for BB. */
+ cond = create_prof_cond ();
+ is_ok = extract_prof_cond (bb, cond, get_edge_guess_prob);
+ if (is_ok)
+ {
+ prof_cond_info *exist_cond = find_prof_cond (&func, cond);
+ if (!exist_cond)
+ {
+ add_prof_cond_to_func (&func, cond);
+ }
+ else
+ {
+ prof_bb_info *bbs = detach_prof_bbs (cond);
+ attach_prof_bbs_to_cond (exist_cond, bbs);
+ free_prof_cond (cond);
+ }
+ }
+ else
+ {
+ free_prof_cond (cond);
+ }
+ }
+
+ gcc_assert (num_branches_exec == nbr);
+
+ func.max_bb_count = curr_count_max;
+ print_prof_func (&func, feature_file);
+
+ if (dump_file)
+ {
+ overlap = compute_frequency_overlap ();
+
+ fprintf (dump_file, "fgo-feature-gen: %s overlap:%d%% ",
+ funcname, overlap * base / OVERLAP_BASE);
+
+ fprintf (
+ dump_file,
+ "blocks:%d edges:%d branches:%d branches_exec:%d[%.1f%%] branches_hot:%d[%.1f%%] ",
+ n_basic_blocks_for_fn (cfun), n_edges_for_fn (cfun), num_branches,
+ num_branches_exec, num_branches ? (num_branches_exec * base_probra / num_branches) : 0,
+ num_branches_hot, num_branches ? (num_branches_hot * base_probra / num_branches) : 0);
+
+ fprintf (dump_file, "prob95:%d prob90:%d prob85:%d prob85~100:%d%% ",
+ num_prob95, num_prob90, num_prob85,
+ num_branches_hot ? ((num_prob95 + num_prob90 + num_prob85) * base
+ / num_branches_hot) : 0);
+
+ fprintf (dump_file, "loop:%d hot:%.1f%%\n",
+ (int) (curr_count_max / func.count),
+ curr_count_sum * base_probra / profile_info->sum_all);
+ }
+
+ free_prof_conds (&(func.first_cond));
+ fclose (feature_file);
+}
+
/* Compute the branch probabilities for the various branches.
Annotate them accordingly.
@@ -760,7 +962,13 @@ compute_branch_probabilities (unsigned c
if (bb->count)
{
FOR_EACH_EDGE (e, ei, bb->succs)
- e->probability = GCOV_COMPUTE_SCALE (e->count, bb->count);
+ {
+ if (fgo_feature_gen)
+ {
+ EDGE_INFO (e)->guess_prob = e->probability;
+ }
+ e->probability = GCOV_COMPUTE_SCALE (e->count, bb->count);
+ }
if (bb->index >= NUM_FIXED_BLOCKS
&& block_ends_with_condjump_p (bb)
&& EDGE_COUNT (bb->succs) >= 2)
@@ -819,16 +1027,24 @@ compute_branch_probabilities (unsigned c
}
counts_to_freqs ();
+ /* Generate condition features. */
+ if (fgo_feature_gen)
+ {
+ generate_condition_features (num_branches);
+ }
+
if (dump_file)
{
fprintf (dump_file, "%d branches\n", num_branches);
if (num_branches)
for (i = 0; i < 10; i++)
+ /* 19 is the last element label, and 100 is the base count. */
fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
(hist_br_prob[i] + hist_br_prob[19-i]) * 100 / num_branches,
5 * i, 5 * i + 5);
total_num_branches += num_branches;
+ /* 20 is the length of total_hist_br_prob. */
for (i = 0; i < 20; i++)
total_hist_br_prob[i] += hist_br_prob[i];
@@ -1500,8 +1716,8 @@ end_branch_prob (void)
if (total_num_branches)
{
int i;
-
for (i = 0; i < 10; i++)
+ /* 19 is the last element label, and 100 is the base count. */
fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
(total_hist_br_prob[i] + total_hist_br_prob[19-i]) * 100
/ total_num_branches, 5*i, 5*i+5);
diff -Nurp a/gcc/profile-feature.c b/gcc/profile-feature.c
--- a/gcc/profile-feature.c 1970-01-01 08:00:00.000000000 +0800
+++ b/gcc/profile-feature.c 2019-12-19 21:13:26.004489300 +0800
@@ -0,0 +1,1639 @@
+/* Generate condition features, and optimizing with condition features.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "options.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "regs.h"
+#include "flags.h"
+#include "function.h"
+#include "diagnostic-core.h"
+#include "recog.h"
+#include "expr.h"
+#include "target.h"
+#include "gimple.h"
+#include "langhooks.h"
+#include "gimple-pretty-print.h"
+#include "profile-feature.h"
+
+#include "tree-ssa-operands.h"
+#include "tree-phinodes.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "ssa-iterators.h"
+
+
+
+/* FGO_FLAGS: FGO_DEBUG, FGO_GEN_DETAILS. */
+
+/* Recompute hitrate in percent to our representation. */
+#define HITRATE(VAL) ((int) ((VAL) * REG_BR_PROB_BASE + 50) / 100)
+
+#define MAX_LINE_LEN 1024
+
+/* Walk depth for function get_prof_operand. */
+#define WALK_DEPTH_FIRST 1
+#define WALK_DEPTH_MAX 5
+#define WALK_DEPTH_INIT (WALK_DEPTH_FIRST - 1)
+
+/* The prefixed tag in the feature file. */
+#define PREFIX_FUNCTION "FUNCTION: "
+#define PREFIX_EXPRESSION "EXPRESSION: "
+#define PREFIX_IGNORE "IGNORE: "
+
+/* For debugging. */
+#ifdef FGO_DEBUG
+#define HANDLE_TYPE_ERROR() fprintf (stderr, "PARSE_TYPE_ERROR:%d ", __LINE__)
+#define HANDLE_VAR_ERROR() fprintf (stderr, "PARSE_VAR_ERROR:%d-%d ", depth, __LINE__)
+#else
+#define HANDLE_TYPE_ERROR()
+#define HANDLE_VAR_ERROR()
+#endif
+
+#define APPEND_ITEM_TO_LIST(container, field, new_item) \
+ do { \
+ if (!(container)->first_##field) \
+ (container)->first_##field = new_item; \
+ else \
+ (container)->last_##field->next = new_item; \
+ \
+ (container)->last_##field = new_item; \
+ } while (0)
+
+/* Code-String map for relational operator. */
+struct cond_code_map
+{
+ enum tree_code code;
+ const char *str;
+};
+
+/* The only PROF_PROG_INFO which contains all the profile info. */
+prof_prog_info *g_prof_prog;
+
+/* Counter summary. */
+struct gcov_ctr_summary fake_profile_info;
+
+/* Code-String map for relational operator. */
+static const struct cond_code_map conds[] = {
+ {LT_EXPR, "<"},
+ {LE_EXPR, "<="},
+ {GT_EXPR, ">"},
+ {GE_EXPR, ">="},
+ {EQ_EXPR, "=="},
+ {NE_EXPR, "!="}
+};
+
+
+/* Get relation operator. */
+
+const char *
+get_cmp_str (enum tree_code code)
+{
+ unsigned i;
+
+ for (i = 0; i < sizeof (conds) / sizeof (conds[0]); i++)
+ {
+ if (code == conds[i].code)
+ {
+ return conds[i].str;
+ }
+ }
+
+ return "Unrecognizable cmp code.";
+}
+
+/* Get code of relation operator. */
+
+enum tree_code
+get_cond_code (const char *str)
+{
+ unsigned i;
+
+ for (i = 0; i < sizeof (conds) / sizeof (conds[0]); i++)
+ {
+ if (strcmp (str, conds[i].str) == 0)
+ {
+ return conds[i].code;
+ }
+ }
+
+ return ERROR_MARK;
+}
+
+/* Get callee name from GS. */
+
+const char *
+get_callee_name (const gimple *gs)
+{
+ tree decl = NULL;
+
+ gcc_assert (is_gimple_call (gs));
+
+ decl = gimple_call_fndecl (gs);
+ if (decl && DECL_NAME (decl))
+ {
+ return lang_hooks.decl_printable_name (decl, 1);
+ }
+
+ return NULL;
+}
+
+/* Remove the dot and characters after dot.
+ For example: we will remove ".0" from temporary variable "gusTu.0". */
+
+static void
+trim_dot (char *str)
+{
+ char *p = NULL;
+
+ for (p = str; *p; p++)
+ {
+ if (*p == '.')
+ {
+ *p = '\0';
+ break;
+ }
+ }
+}
+
+/* Extract type name of NODE and store it in TYPE_NAME.
+ Ignore this funtion if IGNORE is true. */
+
+static void
+get_type_name (tree node, char *type_name, bool ignore)
+{
+ tree type = TREE_TYPE (node);
+ size_t i;
+
+
+ if (!type_name || ignore)
+ {
+ return;
+ }
+
+ /* We Extract the TREE_CODE_NAME (such as integer_cst) for constant type. */
+ if (TREE_CODE_CLASS (TREE_CODE (node)) == tcc_constant)
+ {
+ strncpy (type_name, get_tree_code_name (TREE_CODE (node)),
+ strlen (get_tree_code_name (TREE_CODE (node))));
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type)
+ {
+ /* Print the name of the structure. */
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ strncpy (type_name, "struct ", strlen ("struct "));
+ }
+ else if (TREE_CODE (type) == UNION_TYPE)
+ {
+ strncpy (type_name, "union ", strlen ("union "));
+ }
+
+ if (TYPE_NAME (type))
+ {
+ const char* tmp = NULL;
+
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ {
+ tmp = IDENTIFIER_POINTER (TYPE_NAME (type));
+ }
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && DECL_NAME (
+ TYPE_NAME (type)))
+ {
+ tmp = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ else
+ tmp = "\0";
+ strncat (type_name, tmp, strlen (tmp));
+
+ }
+ /* function pointer type. */
+ else if (TREE_CODE (node) == POINTER_TYPE && TREE_CODE (type)
+ == FUNCTION_TYPE)
+ {
+ strncpy (type_name, "FUNC-POINTER", strlen ("FUNC-POINTER"));
+ }
+ else if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type)
+ == REFERENCE_TYPE)
+ {
+ const char * tmp = (TREE_CODE (type) == POINTER_TYPE ? " *" : " &");
+
+ get_type_name (type, type_name, ignore);
+ strncat (type_name, tmp, strlen (tmp));
+ }
+ else if (TREE_CODE (type) == INTEGER_TYPE)
+ {
+ snprintf (type_name,
+ MAX_NAME_LEN - 1, "<unnamed-%s:%d>",
+ (TYPE_UNSIGNED (type) ? "unsigned" : "signed"),
+ TYPE_PRECISION (type));
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree tmp_node = NULL, tmp_type = NULL;
+
+ /* Print the innermost component type. */
+ tmp_node = type;
+ tmp_type = TREE_TYPE (type);
+ for (;
+ TREE_CODE (tmp_type) == ARRAY_TYPE;
+ tmp_node = tmp_type, tmp_type = TREE_TYPE (tmp_type))
+ ;
+ get_type_name (tmp_node, type_name, ignore);
+ /* Print the dimensions. */
+ for (tmp_type = type; TREE_CODE (tmp_type) == ARRAY_TYPE;
+ tmp_type = TREE_TYPE (tmp_type))
+ {
+ tree domain = TYPE_DOMAIN (tmp_type);
+ HOST_WIDE_INT domain_num = 0;
+ unsigned long type_len = strlen (type_name);
+
+ if (domain)
+ {
+ tree min = TYPE_MIN_VALUE (domain);
+ tree max = TYPE_MAX_VALUE (domain);
+
+ if (min && max
+ && integer_zerop (min)
+ && tree_fits_shwi_p(max))
+ {
+ domain_num = (long)(TREE_INT_CST_LOW\
+ (max) + 1);
+ }
+ }
+ if (domain_num != 0)
+ {
+ snprintf (type_name + type_len,
+ MAX_NAME_LEN - type_len - 1,
+ "[" HOST_WIDE_INT_PRINT_DEC"]",
+ domain_num);
+ }
+ else
+ {
+ snprintf (type_name + type_len,
+ MAX_NAME_LEN - type_len - 1, "[]");
+ }
+ }
+ }
+ else
+ {
+ HANDLE_TYPE_ERROR ();
+ }
+ }
+ else
+ {
+ HANDLE_TYPE_ERROR ();
+ }
+
+ /* Replace SPACE with '-'. */
+ for (i = 0; i < strlen (type_name); i++)
+ {
+ if (type_name[i] == ' ')
+ {
+ type_name[i] = '-';
+ }
+ }
+}
+
+/* Extract the PROF_OPERAND from OP and store it in OP_INFO.
+ DEPTH is the depth of recursion.
+ Not extract OP's type when IGNORE_TYPE is true. */
+
+static void
+get_prof_operand (tree op, prof_operand *op_info, int depth, bool ignore_type)
+{
+ if (!op_info)
+ {
+ return;
+ }
+ depth++;
+ /* Avoid stack overflow. */
+ if (depth > WALK_DEPTH_MAX)
+ {
+ HANDLE_VAR_ERROR ();
+ return;
+ }
+
+ if (TREE_CODE_CLASS (TREE_CODE (op)) == tcc_constant)
+ {
+ get_type_name (op, op_info->type_name, ignore_type);
+
+ if (TREE_CODE (op) == INTEGER_CST)
+ {
+ if (tree_fits_shwi_p (op))
+ {
+ snprintf (op_info->var_name, MAX_NAME_LEN - 1,
+ HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) TREE_INT_CST_LOW (op));
+ }
+ else if (tree_fits_uhwi_p (op))
+ {
+ snprintf (op_info->var_name, MAX_NAME_LEN - 1,
+ HOST_WIDE_INT_PRINT_UNSIGNED, (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op));
+ }
+ }
+ else if (TREE_CODE (op) == REAL_CST)
+ {
+ REAL_VALUE_TYPE d;
+ if (TREE_OVERFLOW (op))
+ {
+ strncpy (op_info->var_name, "overflow",
+ strlen ("overflow"));
+ }
+ #if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
+ d = TREE_REAL_CST (op);
+ if (REAL_VALUE_ISINF (d))
+ {
+ /* 5 is the length of " -Inf" and 4 is the length of " Inf" */
+ strncat (op_info->var_name,
+ REAL_VALUE_NEGATIVE (d) ?
+ " -Inf" : " Inf", REAL_VALUE_NEGATIVE (d) ? 5 : 4);
+ }
+ else if (REAL_VALUE_ISNAN (d))
+ {
+ strncat (op_info->var_name, " Nan",
+ strlen (" Nan"));
+ }
+ else
+ {
+ char string[16] = { 0 };
+ real_to_decimal (string, &d, sizeof (string), 0, 1);
+ strncat (op_info->var_name, string, strlen (string));
+ }
+ #endif
+ }
+ else
+ {
+ op_info->var_name[0] = '\0';
+ }
+ }
+ else if (TREE_CODE (op) == SSA_NAME)
+ {
+ tree var = SSA_NAME_VAR (op);
+
+ /*Compared to gcc 4.7, the method of storing struct type has been changed:
+ var no longer exists (NULL) in current situation so a compilation error will
+ occur. Here for struct type manually put codes here which are same as that
+ to handle temporary variable. */
+ if (NULL == var)
+ {
+ gimple *stmt = SSA_NAME_DEF_STMT (op);
+ /* gimple_num_ops (stmt) equals 2 means stmt has two branch. */
+ if (gimple_num_ops (stmt) == 2)
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ get_prof_operand (rhs1, op_info, depth, false);
+ }
+ }
+ else if ( TREE_CODE_CLASS (TREE_CODE (var)) == tcc_declaration)
+ {
+ if (DECL_NAME (var))
+ {
+ get_type_name (op, op_info->type_name, ignore_type);
+ strncpy (op_info->var_name,
+ IDENTIFIER_POINTER (DECL_NAME (var)),
+ strlen (IDENTIFIER_POINTER (DECL_NAME (var))));
+ trim_dot (op_info->var_name);
+ }
+ /* temporary variable. */
+ else
+ {
+ gimple *stmt = SSA_NAME_DEF_STMT (op);
+
+ if (gimple_num_ops (stmt) == 2)
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ get_prof_operand (rhs1, op_info, depth, false);
+ }
+ else if (is_gimple_call (stmt))
+ {
+ const char *callee_name = get_callee_name (stmt);
+ strncpy (op_info->type_name, "FUNC-CALL",
+ strlen ("FUNC-CALL"));
+ /* We treat CALLEE_NAME as an operand name
+ for function calling statement. */
+ if (callee_name)
+ {
+ strncpy (op_info->var_name, callee_name,
+ strlen (callee_name));
+ }
+ }
+ else
+ {
+ if (!has_zero_uses (op))
+ {
+ use_operand_p use_p = NULL;
+ imm_use_iterator use_iter;
+ bool handled = false;
+
+ FOR_EACH_IMM_USE_FAST (use_p, use_iter, op)
+ {
+ if (!use_p)
+ {
+ break;
+ }
+ gimple *use_stmt = USE_STMT (use_p);
+ if (gimple_code (use_stmt) == GIMPLE_ASSIGN)
+ {
+ tree lhs = gimple_assign_lhs (use_stmt);
+ /* We only handle the non-temporary variables. */
+ if (TREE_CODE (lhs) != SSA_NAME || DECL_NAME (SSA_NAME_VAR (lhs)))
+ {
+ get_prof_operand (lhs, op_info, depth, false);
+ handled = true;
+ break;
+ }
+ }
+ }
+ if (!handled)
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (op)) == tcc_declaration)
+ {
+ if (DECL_NAME (op))
+ {
+ get_type_name (op, op_info->type_name, ignore_type);
+ strncpy (op_info->var_name,
+ IDENTIFIER_POINTER (DECL_NAME (op)),
+ strlen (IDENTIFIER_POINTER (DECL_NAME (op))));
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ else if (TREE_CODE (op) == MEM_REF)
+ {
+ if (TREE_CODE (TREE_OPERAND (op, 0)) != ADDR_EXPR)
+ {
+ prof_operand tmp;
+
+ memset (&tmp, 0, sizeof (prof_operand));
+
+ get_type_name (op, op_info->type_name, ignore_type);
+ get_prof_operand (TREE_OPERAND (op, 0), &tmp, depth, true);
+
+ if (tmp.var_name[0] != '\0')
+ {
+ snprintf (op_info->var_name,
+ MAX_NAME_LEN -1, "*%s", tmp.var_name);
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ else if (TREE_CODE (op) == ARRAY_REF)
+ {
+ prof_operand array, index;
+
+ memset (&array, 0, sizeof (prof_operand));
+ memset (&index, 0, sizeof (prof_operand));
+
+ get_type_name (op, op_info->type_name, ignore_type);
+
+ get_prof_operand (TREE_OPERAND (op, 0), &array, depth, true);
+ get_prof_operand (TREE_OPERAND (op, 1), &index, depth, true);
+
+ snprintf (op_info->var_name,
+ MAX_NAME_LEN - 1,
+ "%s[%s]", array.var_name,
+ index.var_name);
+ }
+ /* struct/union. */
+ else if (TREE_CODE (op) == COMPONENT_REF)
+ {
+ tree container = TREE_OPERAND (op, 0);
+ tree field = TREE_OPERAND (op, 1);
+ const char* field_name = NULL;
+ bool is_mem_ref = false;
+
+ get_type_name (container, op_info->type_name, ignore_type);
+
+ /* struct/union array. */
+ if (TREE_CODE (container) == ARRAY_REF)
+ {
+ prof_operand array, index;
+
+ memset (&array, 0, sizeof (prof_operand));
+ memset (&index, 0, sizeof (prof_operand));
+
+ get_prof_operand (TREE_OPERAND (container, 0), &array, depth, true);
+ get_prof_operand (TREE_OPERAND (container, 1), &index, depth, true);
+
+ snprintf (op_info->var_name, MAX_NAME_LEN - 1, "%s[%s]",
+ array.var_name, index.var_name);
+
+
+
+
+ }
+ /* struct/union pointer. */
+ else if (TREE_CODE (container) == MEM_REF)
+ {
+ if (TREE_CODE (TREE_OPERAND (container, 0)) != ADDR_EXPR)
+ {
+ if (TREE_CODE (TREE_OPERAND (container, 0)) == SSA_NAME)
+ {
+ tree var = SSA_NAME_VAR (TREE_OPERAND (container, 0));
+ if (!var)
+ {
+ return;
+ }
+ if (TREE_CODE_CLASS (TREE_CODE (var)) == tcc_declaration)
+ {
+ if (DECL_NAME (var))
+ {
+ strncpy (op_info->var_name,
+ IDENTIFIER_POINTER (DECL_NAME (var)),
+ strlen (IDENTIFIER_POINTER (DECL_NAME (var))));
+ }
+ else
+ {
+ HANDLE_VAR_ERROR (); /* temporary variable. */
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ is_mem_ref = true;
+ }
+ /* struct/union object. */
+ else if (TREE_CODE_CLASS (TREE_CODE (container)) == tcc_declaration)
+ {
+ if (DECL_NAME (container))
+ {
+ const char* var_name = IDENTIFIER_POINTER (DECL_NAME (container));
+ strncpy (op_info->var_name, var_name,
+ strlen (var_name));
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR (); /* include struct array. */
+ }
+
+ /* field. */
+ if (TREE_CODE (field) == FIELD_DECL && DECL_NAME (field))
+ {
+ field_name = IDENTIFIER_POINTER (DECL_NAME (field));
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+
+ trim_dot (op_info->var_name);
+
+ if (op_info->var_name[0] == '\0')
+ {
+ strncpy (op_info->var_name, "?", strlen ("?"));
+ }
+
+ if (is_mem_ref)
+ {
+ strncat (op_info->var_name, "->", strlen ("->"));
+ }
+ else
+ {
+ strncat (op_info->var_name, ".", strlen ("."));
+ }
+ if (field_name)
+ {
+ strncat (op_info->var_name, field_name,
+ strlen (field_name));
+ }
+ }
+ else
+ {
+ HANDLE_VAR_ERROR ();
+ }
+ /* Finish the TYPE_NAME and VAR_NAME extracting. */
+ if (depth == WALK_DEPTH_FIRST)
+ {
+ if (op_info->type_name[0] == '\0')
+ {
+ get_type_name (op, op_info->type_name, ignore_type);
+ }
+
+ if (op_info->type_name[0] == '\0')
+ {
+ strncpy (op_info->type_name, "?", strlen ("?"));
+ }
+
+ if (op_info->var_name[0] == '\0')
+ {
+ strncpy (op_info->var_name, "?", strlen ("?"));
+ }
+ }
+}
+
+/* Allocate a PROF_COND_INFO and return the new PROF_COND_INFO structure. */
+
+prof_cond_info *
+create_prof_cond (void)
+{
+ prof_cond_info *cond = XNEW (prof_cond_info);
+
+ cond->first_bb = cond->last_bb = XNEW (prof_bb_info);
+ cond->first_bb->next = NULL;
+
+ return cond;
+}
+
+/* Fill COND with 0. */
+
+void
+init_prof_cond_and_bb (prof_cond_info *cond)
+{
+ prof_bb_info *bb = NULL, *first_bb = NULL, *last_bb = NULL;
+
+
+ if (!cond)
+ {
+ return;
+ }
+
+ first_bb = cond->first_bb;
+ last_bb = cond->last_bb;
+
+ memset (cond, 0, sizeof (prof_cond_info));
+
+ cond->first_bb = first_bb;
+ cond->last_bb = last_bb;
+
+ for (bb = cond->first_bb; bb; bb = bb->next)
+ {
+ memset (bb, 0, sizeof (prof_bb_info));
+ }
+}
+
+/* Attach BBS to COND.
+ Return true if succeed and false if not. */
+
+bool
+attach_prof_bbs_to_cond (prof_cond_info *cond, prof_bb_info *bbs)
+{
+ prof_bb_info *last_bb = NULL;
+
+ if (!cond || !bbs)
+ {
+ return false;
+ }
+
+ if (!cond->first_bb)
+ {
+ cond->first_bb = bbs;
+ }
+ else
+ {
+ cond->last_bb->next = bbs;
+ }
+
+ for (last_bb = bbs; last_bb->next; last_bb = last_bb->next)
+ ;
+
+ cond->last_bb = last_bb;
+
+ return true;
+}
+
+/* Detach BBs from COND. */
+
+prof_bb_info *
+detach_prof_bbs (prof_cond_info *cond)
+{
+ prof_bb_info *first_bb = NULL;
+
+ if (!cond)
+ {
+ return NULL;
+ }
+
+ first_bb = cond->first_bb;
+ cond->first_bb = cond->last_bb = NULL;
+
+ return first_bb;
+}
+
+/* Extract condition feature from BB, and store it in COND_INFO.
+ EDGE_GUESS_PROB is the hook to get estimated probability.
+
+ Return true if succeed and false if not. */
+
+bool
+extract_prof_cond (basic_block bb, prof_cond_info
+ *cond_info, int (*edge_guess_prob) (edge e))
+{
+ gimple *stmt = last_stmt (bb);
+ edge then_edge = NULL;
+ tree lhs = NULL, rhs = NULL;
+ edge_iterator ei;
+
+ gcc_assert (cond_info != NULL && cond_info->first_bb && edge_guess_prob);
+
+ if (!cond_info || !cond_info->first_bb || !edge_guess_prob)
+ {
+ return false;
+ }
+
+ if (!stmt || gimple_code (stmt) != GIMPLE_COND)
+ {
+ return false;
+ }
+
+ FOR_EACH_EDGE (then_edge, ei, bb->succs)
+ if (then_edge->flags & EDGE_TRUE_VALUE)
+ {
+ break;
+ }
+
+ lhs = gimple_cond_lhs (stmt);
+ rhs = gimple_cond_rhs (stmt);
+
+ init_prof_cond_and_bb (cond_info);
+
+ get_prof_operand (lhs, &(cond_info->lhs), WALK_DEPTH_INIT, false);
+ get_prof_operand (rhs, &(cond_info->rhs), WALK_DEPTH_INIT, false);
+ cond_info->cmp = gimple_cond_code (stmt);
+
+ cond_info->first_bb->index = bb->index;
+ cond_info->first_bb->count = bb->count;
+ cond_info->first_bb->guess_prob = edge_guess_prob (then_edge);
+
+ if (bb->count)
+ {
+ cond_info->first_bb->profile_prob
+ = (int)(then_edge->count * REG_BR_PROB_BASE / bb->count);
+ }
+ else
+ {
+ cond_info->first_bb->profile_prob = 0;
+ }
+
+ return true;
+}
+
+/* Check to see if COND1 and COND2 are logically equivalent. */
+
+bool
+same_prof_cond_p (const prof_cond_info *cond1, const prof_cond_info *cond2)
+{
+ if (!cond1 || !cond2)
+ {
+ return false;
+ }
+
+ if ((strcmp (cond1->lhs.type_name, cond2->lhs.type_name) == 0)
+ && (strcmp (cond1->lhs.var_name, cond2->lhs.var_name) == 0)
+ && (cond1->cmp == cond2->cmp)
+ && (strcmp (cond1->rhs.type_name, cond2->rhs.type_name) == 0)
+ && (strcmp (cond1->rhs.var_name, cond2->rhs.var_name) == 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* Return the equivalent of COND inside FUNC. */
+
+prof_cond_info *
+find_prof_cond (const prof_func_info *func, const prof_cond_info *cond)
+{
+ prof_cond_info *tmp = NULL;
+
+ if (!func || !cond)
+ {
+ return NULL;
+ }
+
+ for (tmp = func->first_cond; tmp; tmp = tmp->next)
+ {
+ if (same_prof_cond_p (cond, tmp))
+ {
+ return tmp;
+ }
+ }
+
+ return NULL;
+}
+
+/* Attach COND to FUNC.
+ Return true if succeed and false if not. */
+
+bool
+add_prof_cond_to_func (prof_func_info *func, prof_cond_info *cond)
+{
+ if (!func || !cond)
+ {
+ return false;
+ }
+
+ APPEND_ITEM_TO_LIST (func, cond, cond);
+
+ return true;
+}
+
+/* Free COND. */
+
+void
+free_prof_cond (prof_cond_info *cond)
+{
+ prof_bb_info *p = NULL, *q = NULL;
+
+ if (!cond)
+ {
+ return;
+ }
+
+ for (p = cond->first_bb; p; p = q)
+ {
+ q = p->next;
+ free (p);
+ }
+
+ free (cond);
+}
+
+/* Free the list of PROF_COND_INFO nodes. */
+
+void
+free_prof_conds (prof_cond_info **first_cond)
+{
+ prof_cond_info *p = NULL, *q = NULL;
+
+ if (!first_cond || !(*first_cond))
+ {
+ return;
+ }
+
+ for (p = *first_cond; p; p = q)
+ {
+ q = p->next;
+ free_prof_cond (p);
+ }
+
+ *first_cond = NULL;
+}
+
+/* Allocate a PROF_FILE_INFO and return the new PROF_FILE_INFO structure. */
+
+static prof_file_info *
+create_prof_file (const char *filename, prof_prog_info *proginfo)
+{
+ prof_file_info *file = NULL;
+
+
+ if (!filename || !proginfo)
+ {
+ return NULL;
+ }
+ file = XNEW (prof_file_info);
+
+ memset (file, 0, sizeof (prof_file_info));
+ strncpy (file->name, filename, strlen (filename));
+
+ APPEND_ITEM_TO_LIST (proginfo, file, file);
+
+ return file;
+}
+
+/* Allocate a PROF_FUNC_INFO and return the new PROF_FUNC_INFO structure. */
+
+static prof_func_info *
+create_prof_func (const char *funcname, prof_file_info *fileinfo)
+{
+ prof_func_info *func = NULL;
+
+
+ if (!funcname || !fileinfo)
+ {
+ return NULL;
+ }
+
+ func = XNEW (prof_func_info);
+
+ memset (func, 0, sizeof (prof_func_info));
+ strncpy (func->name, funcname, strlen (funcname));
+
+ func->file = fileinfo;
+
+ APPEND_ITEM_TO_LIST (fileinfo, func, func);
+
+ return func;
+}
+
+/* Find a PROF_FILE_INFO with required FILENAME in PROGINFO.
+ Return NULL if it cannot be found. */
+
+static prof_file_info *
+find_prof_file (const char *filename, const prof_prog_info *proginfo)
+{
+ prof_file_info *file = NULL;
+
+ if (!filename || !proginfo)
+ {
+ return NULL;
+ }
+
+ for (file = proginfo->first_file; file; file = file->next)
+ {
+ if (strcmp (file->name, filename) == 0)
+ {
+ return file;
+ }
+ }
+
+ return NULL;
+}
+
+/* Find a PROF_FUNC_INFO with required FUNCNAME in FILEINFO.
+ Return NULL if it cannot be found. */
+
+static prof_func_info *
+find_prof_func (const char *funcname, const prof_file_info *fileinfo)
+{
+ prof_func_info *func = NULL;
+
+ if (!funcname || !fileinfo)
+ {
+ return NULL;
+ }
+
+ for (func = fileinfo->first_func; func; func = func->next)
+ {
+ if (strcmp (func->name, funcname) == 0)
+ {
+ return func;
+ }
+ }
+
+ return NULL;
+}
+
+/* Find a PROF_FUNC_INFO with required FILENAME and FUNCNAME
+ in the prof_file_info list FILEINFO.
+
+ Return NULL if it cannot be found. */
+
+prof_func_info *
+find_prof_func_in_prog (const char *filename, const char *funcname,
+ const prof_prog_info *proginfo)
+{
+ const prof_file_info *file = NULL;
+
+ if (!filename || !funcname || !proginfo)
+ {
+ return NULL;
+ }
+
+ file = find_prof_file (filename, proginfo);
+ if (!file)
+ {
+ return NULL;
+ }
+
+ return find_prof_func (funcname, file);
+}
+
+/* Free FUNC. */
+
+static void
+free_prof_func (prof_func_info *func)
+{
+ if (!func)
+ {
+ return;
+ }
+
+ free_prof_conds (&(func->first_cond));
+ free (func);
+}
+
+/* Free FILE. */
+
+static void
+free_prof_file (prof_file_info *file)
+{
+ prof_func_info *p = NULL, *q = NULL;
+
+ if (!file)
+ {
+ return;
+ }
+
+ for (p = file->first_func; p; p = q)
+ {
+ q = p->next;
+ free_prof_func (p);
+ }
+
+ free (file);
+}
+
+/* Free PROG. */
+
+void
+free_prof_prog (prof_prog_info *prog)
+{
+ prof_file_info *p = NULL, *q = NULL;
+
+ if (!prog)
+ {
+ return;
+ }
+
+ for (p = prog->first_file; p; p = q)
+ {
+ q = p->next;
+ free_prof_file (p);
+ }
+
+ free (prog);
+}
+
+/* Print the COND and BB on file OUTFILE, preceded by PREFIX.
+ Basic form:
+ EXPRESSION: int n > integer_cst 5 100.00% */
+
+static void
+print_prof_bb (const char *prefix, const prof_cond_info *cond,
+ const prof_bb_info *bb, FILE *outfile)
+{
+ gcc_assert (cond != NULL && bb != NULL && bb->count != 0);
+
+ if (!prefix || !cond || !bb || !bb->count || !outfile)
+ {
+ return;
+ }
+
+ fprintf (outfile, "%s", prefix);
+ fprintf (outfile, "%s %s", cond->lhs.type_name, cond->lhs.var_name);
+ fprintf (outfile, " %s ", get_cmp_str (cond->cmp));
+ fprintf (outfile, "%s %s", cond->rhs.type_name, cond->rhs.var_name);
+ /* 100.0 is the base count. */
+ fprintf (outfile, " %.2f%%", bb->profile_prob * 100.0 / REG_BR_PROB_BASE);
+
+#ifdef FGO_GEN_DETAILS
+ fprintf (outfile, " %.2f%%", bb->guess_prob * 100.0 / REG_BR_PROB_BASE);
+ fprintf (outfile, " bb:%d", bb->index);
+ fprintf (outfile, " count:%" PRId64, bb->count);
+#endif
+
+ if (bb->combined)
+ {
+ fprintf (outfile, " (combined");
+ if (bb->prob_ambiguous)
+ {
+ fprintf (outfile, ", ambiguous");
+ }
+ fprintf (outfile, ")");
+ }
+
+ fprintf (outfile, "\n");
+}
+
+/* Print the COND on file OUTFILE. */
+
+static void
+print_prof_cond (const prof_cond_info *cond, FILE *outfile)
+{
+ prof_bb_info * bb = NULL;
+ bool single_bb = true;
+
+
+ gcc_assert (cond != NULL && cond->first_bb != NULL
+ && cond->first_bb->count != 0);
+
+ if (!cond || !cond->first_bb || !cond->first_bb->count || !outfile)
+ {
+ return;
+ }
+
+ /* SINGLE_BB is false if the function has more than one
+ same condition expressions. */
+ if (cond->first_bb->next)
+ {
+ single_bb = false;
+ }
+
+ if (single_bb)
+ {
+ print_prof_bb (PREFIX_EXPRESSION, cond, cond->first_bb, outfile);
+ }
+ else
+ {
+ /* If there are more than one same condition expressions in a function,
+ we will combine and ignore them. */
+
+ prof_bb_info combined_bb;
+ gcov_type prof_succ_count = 0;
+ gcov_type guess_succ_count = 0;
+ bool prob_gt50 = false;
+ bool prob_lt50 = false;
+
+ memset (&combined_bb, 0, sizeof (prof_bb_info));
+ combined_bb.index = -1;
+
+ /* Combine BBs. */
+ for (bb = cond->first_bb; bb; bb = bb->next)
+ {
+ combined_bb.count += bb->count;
+ prof_succ_count += bb->count * bb->profile_prob;
+ guess_succ_count += bb->count * bb->guess_prob;
+ /* REG_BR_PROB_BASE/2 means 50% */
+ if (bb->profile_prob > REG_BR_PROB_BASE/2)
+ {
+ prob_gt50 = true;
+ }
+ else if (bb->profile_prob < REG_BR_PROB_BASE/2)
+ {
+ prob_lt50 = true;
+ }
+ }
+ /* 0.5 means add 50% probability. */
+ combined_bb.profile_prob
+ = (int) (((double) prof_succ_count) / combined_bb.count + 0.5);
+ combined_bb.guess_prob
+ = (int) (((double) guess_succ_count) / combined_bb.count + 0.5);
+
+ combined_bb.combined = true;
+
+ if (prob_gt50 && prob_lt50)
+ {
+ combined_bb.prob_ambiguous = true;
+ }
+
+ print_prof_bb (PREFIX_EXPRESSION, cond, &combined_bb, outfile);
+
+ for (bb = cond->first_bb; bb; bb = bb->next)
+ {
+ print_prof_bb (PREFIX_IGNORE, cond, bb, outfile);
+ }
+ }
+}
+
+/* Print the FUNC on file OUTFILE. */
+
+void
+print_prof_func (const prof_func_info *func, FILE *outfile)
+{
+ prof_cond_info * cond = NULL;
+
+ if (!func || !outfile)
+ {
+ return;
+ }
+
+ fprintf (outfile, PREFIX_FUNCTION"%s %s %" PRId64" %" PRId64"\n",
+ func->file->name, func->name, func->count, func->max_bb_count);
+
+#ifdef FGO_GEN_DETAILS
+ fprintf (outfile, PREFIX_FUNCTION"%s %s %" PRId64" %" PRId64" %.2f%%\n",
+ func->file->name, func->name, func->count, func->max_bb_count,
+ func->count * 100.0 / func->max_bb_count);
+#endif
+
+ for (cond = func->first_cond; cond; cond = cond->next)
+ {
+ print_prof_cond (cond, outfile);
+ }
+
+ fprintf (outfile, "\n");
+}
+
+/* Calculate the counter summary of PROG. */
+
+static void
+calc_counter_summary (const prof_prog_info *prog,
+ struct gcov_ctr_summary *summary)
+{
+ prof_file_info *file = NULL;
+
+ if (!prog || !summary)
+ {
+ return;
+ }
+
+ /* Find the maximum counter value. */
+ for (file = prog->first_file; file; file = file->next)
+ {
+ prof_func_info *func = NULL;
+
+ for (func = file->first_func; func; func = func->next)
+ {
+ if (func->max_bb_count > summary->run_max)
+ {
+ summary->run_max = func->max_bb_count;
+ }
+ }
+ }
+
+ /* Falsify the counter data. */
+ summary->runs = 1;
+ summary->sum_max = summary->run_max;
+ summary->sum_all = summary->sum_max + 1;
+}
+
+/* Parse the string LINE and store the result in FUNC_INFO or FILE_INFO.
+ Return true if succeed and false if not. */
+
+static bool
+parse_profile_line (const char * line, unsigned long lineLen,
+ prof_func_info ** func_info,
+ prof_prog_info * prog_info)
+{
+ bool args_valid = line && lineLen < MAX_LINE_LEN - 1 && func_info
+ && prog_info;
+
+
+ gcc_assert (args_valid);
+
+ if (!args_valid)
+ {
+ return false;
+ }
+
+ /* FUNCTION. */
+ if (strncmp (line, PREFIX_FUNCTION, strlen (PREFIX_FUNCTION)) == 0)
+ {
+ char filename[MAX_LINE_LEN];
+ char funcname[MAX_LINE_LEN];
+ gcov_type count;
+ gcov_type max_count;
+ const int EXPECT_ITEM_COUNT = 4; /* For format checking. */
+ int ret = sscanf (line, PREFIX_FUNCTION"%s %s %" PRId64" %" PRId64,
+ filename, funcname, &count, &max_count);
+ if (ret == EXPECT_ITEM_COUNT)
+ {
+ prof_file_info *file = NULL;
+ prof_func_info *func = NULL;
+
+ /* Find or create PROF_FILE_INFO. */
+ file = find_prof_file (filename, prog_info);
+ if (!file)
+ {
+ file = create_prof_file (filename, prog_info);
+ }
+
+ /* Find or create PROF_FUNC_INFO. */
+ func = find_prof_func (funcname, file);
+ if (!func)
+ {
+ func = create_prof_func (funcname, file);
+ }
+
+ if (!func)
+ {
+ return false;
+ }
+
+ func->count = count;
+ func->max_bb_count = max_count;
+ *func_info = func;
+
+ return true;
+ }
+ }
+ /* EXPRESSION. */
+ else if (strncmp (line, PREFIX_EXPRESSION, strlen (PREFIX_EXPRESSION)) == 0)
+ {
+ char lhs_type[MAX_LINE_LEN];
+ char lhs_var[MAX_LINE_LEN];
+ char rhs_type[MAX_LINE_LEN];
+ char rhs_var[MAX_LINE_LEN];
+ char cmp[MAX_LINE_LEN];
+ float profile_prob;
+ const float guess_prob = 0;
+ const int EXPECT_ITEM_COUNT = 6; /* For format checking. */
+ int ret;
+
+ /* If the prof_func_info was not created,
+ ignore the EXPRESSION line without warning. */
+ if (!(*func_info))
+ {
+ return true;
+ }
+
+ ret = sscanf (line, PREFIX_EXPRESSION"%s %s %s %s %s %f", lhs_type,
+ lhs_var, cmp, rhs_type, rhs_var, &profile_prob);
+
+ if (ret == EXPECT_ITEM_COUNT)
+ {
+ prof_cond_info *cond = create_prof_cond ();
+
+ init_prof_cond_and_bb (cond);
+
+ strncpy (cond->lhs.type_name, lhs_type, strlen (lhs_type));
+ strncpy (cond->lhs.var_name, lhs_var, strlen (lhs_var));
+ cond->cmp = get_cond_code (cmp);
+
+ strncpy (cond->rhs.type_name, rhs_type, strlen (rhs_type));
+ strncpy (cond->rhs.var_name, rhs_var, strlen (rhs_var));
+
+ cond->first_bb->profile_prob = HITRATE (profile_prob);
+ cond->first_bb->guess_prob = HITRATE (guess_prob);
+
+ add_prof_cond_to_func (*func_info, cond);
+
+ return true;
+ }
+ }
+ /* IGNORE. */
+ else if (strncmp (line, PREFIX_IGNORE, strlen (PREFIX_IGNORE)) == 0)
+ {
+ return true;
+ }
+
+ inform (0, "invalid line \"%s\" in file %s", line, fgo_feature_use);
+ return false;
+}
+
+void
+delete_space (char *buf, int len)
+{
+ /* Delete '\r' and '\n'. */
+ if ((len >= 2) && (buf[len - 2] == '\r'))
+ {
+ buf[len - 2] = '\0';
+ }
+ else if ((len >= 1) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
+ {
+ buf[len - 1] = '\0';
+ }
+}
+
+/* Parse the feature file INFILE and store the result in global
+ variable G_PROF_PROG. Return true if succeed and false if not. */
+
+bool
+parse_profile_file (FILE *infile)
+{
+ prof_func_info *func_info = NULL;
+ char buf[MAX_LINE_LEN] = { '\0' };
+ bool has_failure = false;
+
+
+ if (!infile)
+ {
+ return false;
+ }
+
+ g_prof_prog = XNEW (prof_prog_info);
+ memset (g_prof_prog, 0, sizeof (prof_prog_info));
+
+ while (fgets (buf, MAX_LINE_LEN, infile))
+ {
+ if (buf[0]=='\0')
+ {
+ break;
+ }
+ if (buf[0] == '\r' || buf[0] == '\n')
+ {
+ continue;
+ }
+
+ size_t str_len = strlen (buf);
+ delete_space (buf, str_len);
+ if (str_len == MAX_LINE_LEN - 1)
+ {
+ inform (0, "the profile line in file %s is too long: \"%s\"",
+ fgo_feature_use, buf);
+
+ /* Discard the rest of the line. */
+ while (fgets (buf, MAX_LINE_LEN, infile))
+ {
+ size_t sent_len = strlen (buf);
+ if (sent_len > 0 && sent_len < MAX_LINE_LEN)
+ {
+ char last_char = buf[sent_len - 1];
+ if (last_char == '\n' || last_char == '\r')
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ has_failure = true;
+ continue;
+ }
+ if (strlen (buf) <= 0 || strlen (buf) >= MAX_LINE_LEN)
+ {
+ continue;
+ }
+ if (!parse_profile_line (buf, strlen (buf), &func_info, g_prof_prog))
+ {
+ has_failure = true;
+ }
+ }
+
+ calc_counter_summary (g_prof_prog, &fake_profile_info);
+ return !has_failure;
+}
+
+/* Compute counts for blocks and edges by FUNC_INFO. */
+
+void
+compute_inside_counts (const prof_func_info *func_info)
+{
+ basic_block bb = NULL;
+
+ if (!func_info)
+ {
+ return;
+ }
+
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
+ {
+ edge e = NULL;
+ edge_iterator ei;
+ double tmp;
+
+ if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency > 0)
+ {
+ tmp = ((double) func_info->count) * bb->frequency
+ / ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency;
+ }
+ else
+ {
+ tmp = ((double) func_info->max_bb_count) * bb->frequency / BB_FREQ_MAX;
+ }
+ /* 0.5 means add 50% probability. */
+ bb->count = (gcov_type) (tmp + 0.5);
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ tmp = ((double) bb->count) * e->probability / REG_BR_PROB_BASE;
+ e->count = (gcov_type) (tmp + 0.5);
+ }
+ }
+}
+
+/* Return the current file name and function name by parameters. */
+
+void
+get_curr_filename_and_funcname (const char **filename, const char **funcname)
+{
+ gcc_assert (filename && funcname);
+
+ if (!filename || !funcname)
+ {
+ return;
+ }
+
+ *filename = *funcname = NULL;
+
+ if (!current_function_decl)
+ {
+ return;
+ }
+
+ base_of_path (LOCATION_FILE (DECL_SOURCE_LOCATION (current_function_decl)),
+ filename);
+ /* 2 means the tree has two branch. */
+ *funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
+}
+
+
+/* Dump CFG profile on OUTFILE. */
+
+void
+dump_cfg_profile (FILE *outfile, int mark)
+{
+ basic_block bb = NULL;
+ gcov_type count_total = 0, freq_total = 0;
+ const char *funcname = NULL;
+
+ if (!outfile)
+ {
+ return;
+ }
+ /* 2 means the tree has two branch. */
+ funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
+ fprintf (outfile, "Func:%s, Mark:%d\n", funcname, mark);
+
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
+ {
+ count_total += bb->count;
+ freq_total += bb->frequency;
+ }
+ /* 100 is the base count. */
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
+ {
+ edge e = NULL;
+ edge_iterator ei;
+
+ fprintf (outfile, "bb:%d, count:%" PRId64, bb->index,
+ bb->count);
+
+ if (count_total > 0)
+ {
+ fprintf (outfile, "(%.2f%%)", bb->count * 100.0 / count_total);
+ }
+ else
+ {
+ fprintf (outfile, "(-%%)");
+ }
+
+ fprintf (outfile, ", frequency:%d", bb->frequency);
+
+ if (freq_total > 0)
+ {
+ fprintf (outfile, "(%.2f%%)", bb->frequency * 100.0 / freq_total);
+ }
+ else
+ {
+ fprintf (outfile, "(-%%)");
+ }
+
+ fprintf (outfile, "\n");
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ fprintf (
+ outfile,
+ "edge:%d->%d, count:%" PRId64", probability:%.2f%%\n",
+ e->src->index, e->dest->index, e->count,
+ e->probability * 100.0 / REG_BR_PROB_BASE);
+ }
+ }
+
+ fprintf (outfile, "\n");
+}
+
+FILE *
+verify_path (const char *pathname,const char *mode)
+{
+ FILE *file = NULL;
+ char * lreal_path = lrealpath (pathname);
+ if (lreal_path == NULL)
+ {
+ warning (0, "The path type is wrong.");
+ pathname = NULL;
+ return NULL;
+ }
+ if ((file = fopen (lreal_path, mode)) == NULL)
+ {
+ free (lreal_path);
+ warning (0,"can not open the config file %qs, make sure it exists",
+ pathname);
+ pathname = NULL;
+ return NULL;
+ }
+ free (lreal_path);
+ return file;
+}
diff -Nurp a/gcc/profile-feature.h b/gcc/profile-feature.h
--- a/gcc/profile-feature.h 1970-01-01 08:00:00.000000000 +0800
+++ b/gcc/profile-feature.h 2019-12-19 21:13:26.004489300 +0800
@@ -0,0 +1,128 @@
+/* Generate condition features, and optimizing with condition features.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_PROFILE_FEATURE_H
+#define GCC_PROFILE_FEATURE_H
+
+#include "gcov-io.h"
+
+#define MAX_PATH_LEN 300
+#define MAX_NAME_LEN 100
+
+typedef struct _prof_bb_d prof_bb_info;
+typedef struct _prof_cond_d prof_cond_info;
+typedef struct _prof_func_d prof_func_info;
+typedef struct _prof_file_d prof_file_info;
+typedef struct _prof_prog_d prof_prog_info;
+
+/* Operand information. */
+typedef struct
+{
+ char type_name[MAX_NAME_LEN];
+ char var_name[MAX_NAME_LEN];
+} prof_operand;
+
+/* Basic block information. */
+struct _prof_bb_d
+{
+ int index; /* The index of this block. */
+ gcov_type count; /* Expected number of executions. */
+ int profile_prob; /* Expected probability of executions. Biased by REG_BR_PROB_BASE. */
+ int guess_prob; /* Estimated probability. Biased by REG_BR_PROB_BASE. */
+ bool combined; /* Whether this block is combined. */
+ bool prob_ambiguous; /* Whether this combined block is ambiguous. */
+
+ prof_bb_info *next;
+};
+
+/* Condition expression information. */
+struct _prof_cond_d
+{
+ prof_operand lhs;
+ prof_operand rhs;
+ enum tree_code cmp; /* Relational operator. */
+ prof_bb_info *first_bb; /* The bb list header. */
+ prof_bb_info *last_bb; /* The final bb. */
+
+ prof_cond_info *next;
+};
+
+/* Function information. */
+struct _prof_func_d
+{
+ char name[MAX_NAME_LEN]; /* Function name. */
+ gcov_type count; /* Expected number of executions. */
+ gcov_type max_bb_count; /* The hottest bb's count. */
+
+ prof_cond_info *first_cond; /* The cond list header. */
+ prof_cond_info *last_cond; /* The final cond. */
+ prof_file_info *file; /* File that contains this function. */
+
+ prof_func_info *next;
+};
+
+/* File information. */
+struct _prof_file_d
+{
+ char name[MAX_PATH_LEN]; /* File name. */
+ prof_func_info *first_func; /* The func list header. */
+ prof_func_info *last_func; /* The final func. */
+
+ prof_file_info *next;
+};
+
+/* Program information. */
+struct _prof_prog_d
+{
+ prof_file_info *first_file; /* The file list header. */
+ prof_file_info *last_file; /* The final file. */
+};
+
+extern prof_prog_info *g_prof_prog;
+extern struct gcov_ctr_summary fake_profile_info;
+
+extern const char * get_cmp_str (enum tree_code code);
+extern enum tree_code get_cond_code (const char *str);
+extern const char * get_callee_name (const gimple *gs);
+
+extern prof_cond_info * create_prof_cond (void);
+extern void init_prof_cond_and_bb (prof_cond_info *cond);
+extern bool attach_prof_bbs_to_cond (prof_cond_info *cond, prof_bb_info *bbs);
+extern prof_bb_info * detach_prof_bbs (prof_cond_info *cond);
+extern bool extract_prof_cond (basic_block bb, prof_cond_info *cond_info,
+ int (*edge_guess_prob)(edge e));
+extern bool same_prof_cond_p (const prof_cond_info *cond1, const prof_cond_info *cond2);
+extern prof_cond_info * find_prof_cond (const prof_func_info *func, const prof_cond_info *cond);
+extern bool add_prof_cond_to_func (prof_func_info *func, prof_cond_info *cond);
+extern void free_prof_cond (prof_cond_info *cond);
+extern void free_prof_conds (prof_cond_info **first_cond);
+extern void free_prof_prog (prof_prog_info *prog);
+
+extern prof_func_info * find_prof_func_in_prog (const char *filename, const char *funcname,
+ const prof_prog_info *proginfo);
+
+extern void print_prof_func (const prof_func_info *func, FILE *outfile);
+extern bool parse_profile_file (FILE *infile);
+extern void compute_inside_counts (const prof_func_info *func_info);
+
+extern void get_curr_filename_and_funcname (const char **filename, const char **funcname);
+
+extern void dump_cfg_profile (FILE *outfile, int mark);
+extern FILE * verify_path (const char *pathname, const char *mode);
+#endif /* GCC_PROFILE_FEATURE_H. */
diff -Nurp a/gcc/profile.h b/gcc/profile.h
--- a/gcc/profile.h 2017-01-01 20:07:43.905435000 +0800
+++ b/gcc/profile.h 2019-12-19 21:13:26.012489300 +0800
@@ -33,6 +33,9 @@ struct edge_profile_info
/* Pretend this edge does not exist (it is abnormal and we've
inserted a fake to compensate). */
unsigned int ignore:1;
+
+ /* Estimated probability. Biased by REG_BR_PROB_BASE. */
+ int guess_prob;
};
#define EDGE_INFO(e) ((struct edge_profile_info *) (e)->aux)
diff -Nurp a/gcc/tree-profile.c b/gcc/tree-profile.c
--- a/gcc/tree-profile.c 2019-12-19 21:12:20.284491748 +0800
+++ b/gcc/tree-profile.c 2019-12-19 21:13:26.012489300 +0800
@@ -51,6 +51,8 @@ along with GCC; see the file COPYING3.
#include "tree-cfgcleanup.h"
#include "params.h"
#include "auto-profile.h"
+#include "langhooks.h"
+#include "profile-feature.h"
static GTY(()) tree gcov_type_node;
static GTY(()) tree tree_interval_profiler_fn;
@@ -565,6 +567,230 @@ gimple_gen_ior_profiler (histogram_value
gsi_insert_before (&gsi, call, GSI_NEW_STMT);
}
+/* Print the error label info. */
+
+static void
+print_error_label_info (basic_block bb, FILE *outfile)
+{
+ gimple_stmt_iterator gsi;
+ edge e = NULL;
+ edge_iterator ei;
+ int probs[100] = {0};
+ gcov_type counts[100] = {0};
+ int branch_count = 0;
+ const char* cur_func = NULL;
+
+ if (!outfile)
+ {
+ return;
+ }
+
+ /* compare to gcc 4.7 ,the bb struct changes too large ,
+ so calculate the label edge probability in this way. */
+ if (NULL != bb->prev_bb)
+ {
+ FOR_EACH_EDGE (e, ei, bb->prev_bb->preds)
+ {
+ if (!(e->src) || e->src->count <= 0)
+ {
+ continue;
+ }
+ if (EDGE_COUNT (e->src->succs) >= 1)
+ {
+ counts[branch_count] = e->src->count;
+ probs[branch_count] = e->probability;
+ branch_count++;
+ }
+ }
+ }
+
+ /* Calculate the count and probability if its pred has two succs,0 mean the tree has no branch. */
+
+ if (branch_count <= 0)
+ {
+ return;
+ }
+ cur_func = lang_hooks.decl_printable_name (current_function_decl, 2);
+
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ glabel *stmt = (glabel *) (gsi_stmt (gsi));
+
+ /* Judge that weather it is a label or not. */
+ if (gimple_code (stmt) == GIMPLE_LABEL)
+ {
+ const_tree label = gimple_label_label (stmt);
+
+ if (DECL_NAME (label))
+ {
+ int i;
+ /* Get the label name. */
+ const char* label_name = IDENTIFIER_POINTER (DECL_NAME (label));
+
+ for (i = 0; i < branch_count; i++)
+ {
+ fprintf (outfile, "LABEL: %s", label_name);
+ fprintf (outfile, " prob:%d count:%" PRId64" %s\n",
+ probs[i], counts[i], cur_func);
+ }
+ }
+ }
+ }
+}
+
+
+/* This is the hook to get estimated probability. */
+
+static int
+get_edge_prob (edge e)
+{
+ return e->probability;
+}
+
+/* Print error vars info. */
+
+static void
+print_error_vars_info (basic_block bb, FILE *outfile)
+{
+ prof_cond_info *cond_info = NULL;
+
+ cond_info = create_prof_cond ();
+ if (extract_prof_cond (bb, cond_info, get_edge_prob))
+ {
+ if (cond_info->cmp == EQ_EXPR || cond_info->cmp == NE_EXPR)
+ {
+ /* 2 mean the tree has two branch. */
+ const char* cur_func = lang_hooks.decl_printable_name (current_function_decl, 2);
+ const char* compare = get_cmp_str (cond_info->cmp);
+
+ fprintf (outfile, "ERROR_VARS: %s %s %s ", cond_info->lhs.var_name, compare,
+ cond_info->rhs.var_name);
+ fprintf (outfile, "prob:%d count:%" PRId64" %s\n",
+ cond_info->first_bb->profile_prob, cond_info->first_bb->count, cur_func);
+ }
+ }
+ free_prof_cond (cond_info);
+}
+
+/* Print function info. */
+
+static void
+print_cold_function_info (basic_block bb, FILE *outfile)
+{
+ const char *callee_name = NULL;
+ gimple_stmt_iterator gsi;
+ edge e = NULL;
+ edge_iterator ei;
+ int max_branch_count = 100;
+ int probs[max_branch_count] = { 0};
+ gcov_type counts[max_branch_count] = { 0};
+ int branch_count = 0;
+ const char* cur_func = NULL;
+ if (!outfile)
+ {
+ return;
+ }
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if (e->src->count <= 0)
+ {
+ continue;
+ }
+
+ if (EDGE_COUNT (e->src->succs) >= 2 && branch_count <= max_branch_count)
+ {
+ counts[branch_count] = e->src->count;
+ probs[branch_count] = e->probability;
+ branch_count++;
+ }
+ }
+
+ if (branch_count <= 0)
+ {
+ return;
+ }
+ /* 2 mean the tree has two branch. */
+ cur_func = lang_hooks.decl_printable_name (current_function_decl, 2);
+
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
+ {
+ int i;
+
+ /* Get function name. */
+ callee_name = get_callee_name (stmt);
+
+ for (i = 0; i < branch_count && i < max_branch_count; i++)
+ {
+ fprintf (outfile, "FUNCTION: %s", callee_name);
+ fprintf (outfile, " prob:%d count:%" PRId64" %s\n",
+ probs[i], counts[i], cur_func);
+ }
+ }
+ }
+}
+
+
+/* Print the branch feature info. */
+
+static void
+print_branch_feature (FILE *outfile)
+{
+ basic_block bb = NULL;
+
+ if (!outfile)
+ {
+ return;
+ }
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ print_cold_function_info (bb, outfile);
+ print_error_vars_info (bb, outfile);
+ print_error_label_info (bb, outfile);
+ }
+}
+
+/* Annotate count for FGO. */
+
+static void
+fgo_annotate_count (void)
+{
+ prof_func_info *func_info = NULL;
+ const char *filename = NULL;
+ const char *funcname = NULL;
+
+ if (!g_prof_prog)
+ {
+ return;
+ }
+
+ /* Get features of the current function. */
+ get_curr_filename_and_funcname (&filename, &funcname);
+ func_info = find_prof_func_in_prog (filename, funcname, g_prof_prog);
+
+ if (!func_info)
+ {
+ return;
+ }
+
+ /* Init PROFILE_INFO with fake_profile_info. */
+ profile_info = &fake_profile_info;
+
+ /* The basic blocks are expected to be numbered sequentially. */
+ compact_blocks ();
+
+ /* All branch probabilities have been calculated if enable FGO_FEATURE_USE.
+ We just need to do some finishing work and return. */
+ compute_inside_counts (func_info);
+ profile_status_for_fn (cfun) = PROFILE_READ;
+ compute_function_frequency ();
+}
+
#ifndef HAVE_sync_compare_and_swapsi
#define HAVE_sync_compare_and_swapsi 0
#endif
@@ -585,7 +811,8 @@ static unsigned int
tree_profiling (void)
{
struct cgraph_node *node;
-
+ FILE * outputfile = NULL;
+ const char * mode = "a";
/* Verify whether we can utilize atomic update operations. */
bool can_support_atomic = false;
unsigned HOST_WIDE_INT gcov_type_size
@@ -614,6 +841,31 @@ tree_profiling (void)
init_node_map (true);
+ if (fgo_estimate_gen)
+ {
+ if (hcc_fgo_estimate_use)
+ {
+ warning (0,
+ "-fhcc-fgo-estimate-gen ignored because -fhcc-fgo-estimate-use specified");
+ fgo_estimate_gen = NULL;
+ }
+ else
+ {
+ /* Only handle the C file. */
+ if (strcmp (lang_hooks.name, "GNU C11") == 0)
+ {
+ outputfile = verify_path (fgo_estimate_gen, mode);
+ if (outputfile == NULL)
+ {
+ inform (0, "can't open file %qs", fgo_estimate_gen);
+ fgo_estimate_gen = NULL;
+ }
+ }
+ else
+ fgo_estimate_gen = NULL;
+ }
+ }
+
/* Read the profile from the profile data file. */
if (flag_auto_profile_generate)
read_autofdo_file ();
@@ -643,7 +895,14 @@ tree_profiling (void)
if (execute_fixup_cfg () & TODO_cleanup_cfg)
cleanup_tree_cfg ();
- branch_prob ();
+ if (fgo_feature_use)
+ {
+ fgo_annotate_count ();
+ }
+ else
+ {
+ branch_prob ();
+ }
if (! flag_branch_probabilities
&& flag_profile_values)
@@ -654,6 +913,11 @@ tree_profiling (void)
&& flag_value_profile_transformations)
gimple_value_profile_transformations ();
+ if (fgo_estimate_gen)
+ {
+ print_branch_feature (outputfile);
+ }
+
/* The above could hose dominator info. Currently there is
none coming in, this is a safety valve. It should be
easy to adjust it, if and when there is some. */
@@ -662,6 +926,11 @@ tree_profiling (void)
pop_cfun ();
}
+ if (fgo_estimate_gen && outputfile)
+ {
+ fclose (outputfile);
+ }
+
/* Write autofdo profile. */
if (flag_auto_profile_generate)
write_autofdo_file ();
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。