predict.c (expr_expected_value, [...]): New function.

* predict.c (expr_expected_value, strip_builtin_expect): New function.
	(tree_predict_by_opcode): Use it.
	(tree_estimate_probability): Add, for now disabled,
	strip_builtin_expect call.

From-SVN: r87578
This commit is contained in:
Jan Hubicka 2004-09-16 02:01:41 +02:00 committed by Jan Hubicka
parent 097f3d486a
commit 42f97fd2c2
2 changed files with 154 additions and 0 deletions

View File

@ -1,3 +1,10 @@
2004-09-13 Jan Hubicka <jh@suse.cz>
* predict.c (expr_expected_value, strip_builtin_expect): New function.
(tree_predict_by_opcode): Use it.
(tree_estimate_probability): Add, for now disabled,
strip_builtin_expect call.
2004-09-15 James E Wilson <wilson@specifixinc.com>
PR target/17455

View File

@ -897,7 +897,139 @@ guess_outgoing_edge_probabilities (basic_block bb)
combine_predictions_for_insn (BB_END (bb), bb);
}
/* Return constant EXPR will likely have at execution time, NULL if unknown.
The function is used by builtin_expect branch predictor so the evidence
must come from this construct and additional possible constant folding.
We may want to implement more involved value guess (such as value range
propagation based prediction), but such tricks shall go to new
implementation. */
static tree
expr_expected_value (tree expr, bitmap visited)
{
if (TREE_CONSTANT (expr))
return expr;
else if (TREE_CODE (expr) == SSA_NAME)
{
tree def = SSA_NAME_DEF_STMT (expr);
/* If we were already here, break the infinite cycle. */
if (bitmap_bit_p (visited, SSA_NAME_VERSION (expr)))
return NULL;
bitmap_set_bit (visited, SSA_NAME_VERSION (expr));
if (TREE_CODE (def) == PHI_NODE)
{
/* All the arguments of the PHI node must have the same constant
length. */
int i;
tree val = NULL, new_val;
for (i = 0; i < PHI_NUM_ARGS (def); i++)
{
tree arg = PHI_ARG_DEF (def, i);
/* If this PHI has itself as an argument, we cannot
determine the string length of this argument. However,
if we can find a expectd constant value for the other
PHI args then we can still be sure that this is
likely a constant. So be optimistic and just
continue with the next argument. */
if (arg == PHI_RESULT (def))
continue;
new_val = expr_expected_value (arg, visited);
if (!new_val)
return NULL;
if (!val)
val = new_val;
else if (!operand_equal_p (val, new_val, false))
return NULL;
}
return val;
}
if (TREE_CODE (def) != MODIFY_EXPR || TREE_OPERAND (def, 0) != expr)
return NULL;
return expr_expected_value (TREE_OPERAND (def, 1), visited);
}
else if (TREE_CODE (expr) == CALL_EXPR)
{
tree decl = get_callee_fndecl (expr);
if (!decl)
return NULL;
if (DECL_BUILT_IN (decl) && DECL_FUNCTION_CODE (decl) == BUILT_IN_EXPECT)
{
tree arglist = TREE_OPERAND (expr, 1);
tree val;
if (arglist == NULL_TREE
|| TREE_CHAIN (arglist) == NULL_TREE)
return NULL;
val = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
if (TREE_CONSTANT (val))
return val;
return TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
}
}
if (TREE_CODE_CLASS (TREE_CODE (expr)) == '2'
|| TREE_CODE_CLASS (TREE_CODE (expr)) == '<')
{
tree op0, op1, res;
op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
if (!op0)
return NULL;
op1 = expr_expected_value (TREE_OPERAND (expr, 1), visited);
if (!op1)
return NULL;
res = fold (build (TREE_CODE (expr), TREE_TYPE (expr), op0, op1));
if (TREE_CONSTANT (res))
return res;
return NULL;
}
if (TREE_CODE_CLASS (TREE_CODE (expr)) == '1')
{
tree op0, res;
op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
if (!op0)
return NULL;
res = fold (build1 (TREE_CODE (expr), TREE_TYPE (expr), op0));
if (TREE_CONSTANT (res))
return res;
return NULL;
}
return NULL;
}
/* Get rid of all builtin_expect calls we no longer need. */
static void
strip_builtin_expect (void)
{
basic_block bb;
FOR_EACH_BB (bb)
{
block_stmt_iterator bi;
for (bi = bsi_start (bb); !bsi_end_p (bi); bsi_next (&bi))
{
tree stmt = bsi_stmt (bi);
tree fndecl;
tree arglist;
if (TREE_CODE (stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR
&& (fndecl = get_callee_fndecl (TREE_OPERAND (stmt, 1)))
&& DECL_BUILT_IN (fndecl)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
&& (arglist = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1))
&& TREE_CHAIN (arglist))
{
TREE_OPERAND (stmt, 1) = TREE_VALUE (arglist);
modify_stmt (stmt);
}
}
}
}
/* Predict using opcode of the last statement in basic block. */
static void
tree_predict_by_opcode (basic_block bb)
@ -907,6 +1039,8 @@ tree_predict_by_opcode (basic_block bb)
tree cond;
tree op0;
tree type;
tree val;
bitmap visited;
if (!stmt || TREE_CODE (stmt) != COND_EXPR)
return;
@ -918,6 +1052,17 @@ tree_predict_by_opcode (basic_block bb)
return;
op0 = TREE_OPERAND (cond, 0);
type = TREE_TYPE (op0);
visited = BITMAP_XMALLOC ();
val = expr_expected_value (cond, visited);
BITMAP_XFREE (visited);
if (val)
{
if (integer_zerop (val))
predict_edge_def (then_edge, PRED_BUILTIN_EXPECT, NOT_TAKEN);
else
predict_edge_def (then_edge, PRED_BUILTIN_EXPECT, TAKEN);
return;
}
/* Try "pointer heuristic."
A comparison ptr == 0 is predicted as false.
Similarly, a comparison ptr1 == ptr2 is predicted as false. */
@ -1072,6 +1217,8 @@ tree_estimate_probability (void)
FOR_EACH_BB (bb)
combine_predictions_for_bb (dump_file, bb);
if (0) /* FIXME: Enable once we are pass down the profile to RTL level. */
strip_builtin_expect ();
estimate_bb_frequencies (&loops_info);
free_dominance_info (CDI_POST_DOMINATORS);
remove_fake_exit_edges ();