extended.texi (__builtin_expect): We no longer require second argument to be constant.
* extended.texi (__builtin_expect): We no longer require second argument to be constant. * gengtype.c (adjust_field_rtx_def): Drop NOTE_INSN_EXPECTED_VALUE. * builtins.c (expand_builtin_expect): Simplify. (expand_builtin_expect_jump): Kill. * final.c (final_scan_insn): Do not skip the removed notes. * insn-notes.def (LOOP_BEG, LOOP_END, REPEATED_LINE_NUMBER, EXPECTED_VALUE): Remove. * dojump.c (do_jump): Do not care about __builtin_expect. * predict.c (expected_value_to_br_prob): Kill. * function.c (expand_function_end): Do not expand NOTE_INSN_REPEATED_LINE_NUMBER. * print-rtl.c (print_rtx): Do not pretty print the removed notes. * expect.c (sjlj_emit_function_enter): Emit directly branch probability. * cfgexpand.c (add_reg_br_prob_note): Export. * cfgcleanup.c (rest_of_handle_jump2): Do not call expected_value_to_br_prob. * cfglayout.c (duplicate_insn_chain): Do not deal with removed notes. * rtl.h (add_reg_br_prob_note): Declare. From-SVN: r118696
This commit is contained in:
parent
89fa98d6b9
commit
ef950eba66
13 changed files with 34 additions and 271 deletions
|
@ -1,3 +1,25 @@
|
|||
2006-11-11 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* extended.texi (__builtin_expect): We no longer require second argument
|
||||
to be constant.
|
||||
* gengtype.c (adjust_field_rtx_def): Drop NOTE_INSN_EXPECTED_VALUE.
|
||||
* builtins.c (expand_builtin_expect): Simplify.
|
||||
(expand_builtin_expect_jump): Kill.
|
||||
* final.c (final_scan_insn): Do not skip the removed notes.
|
||||
* insn-notes.def (LOOP_BEG, LOOP_END, REPEATED_LINE_NUMBER,
|
||||
EXPECTED_VALUE): Remove.
|
||||
* dojump.c (do_jump): Do not care about __builtin_expect.
|
||||
* predict.c (expected_value_to_br_prob): Kill.
|
||||
* function.c (expand_function_end): Do not expand
|
||||
NOTE_INSN_REPEATED_LINE_NUMBER.
|
||||
* print-rtl.c (print_rtx): Do not pretty print the removed notes.
|
||||
* expect.c (sjlj_emit_function_enter): Emit directly branch probability.
|
||||
* cfgexpand.c (add_reg_br_prob_note): Export.
|
||||
* cfgcleanup.c (rest_of_handle_jump2): Do not call
|
||||
expected_value_to_br_prob.
|
||||
* cfglayout.c (duplicate_insn_chain): Do not deal with removed notes.
|
||||
* rtl.h (add_reg_br_prob_note): Declare.
|
||||
|
||||
2006-11-11 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* tree-pretty-print.c (dump_generic_node): Print sign of Inf.
|
||||
|
|
147
gcc/builtins.c
147
gcc/builtins.c
|
@ -4693,9 +4693,9 @@ expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Expand a call to __builtin_expect. We return our argument and emit a
|
||||
NOTE_INSN_EXPECTED_VALUE note. This is the expansion of __builtin_expect in
|
||||
a non-jump context. */
|
||||
/* Expand a call to __builtin_expect. We just return our argument
|
||||
as the builtin_expect semantic should've been already executed by
|
||||
tree branch prediction pass. */
|
||||
|
||||
static rtx
|
||||
expand_builtin_expect (tree arglist, rtx target)
|
||||
|
@ -4709,149 +4709,12 @@ expand_builtin_expect (tree arglist, rtx target)
|
|||
exp = TREE_VALUE (arglist);
|
||||
c = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
|
||||
if (TREE_CODE (c) != INTEGER_CST)
|
||||
{
|
||||
error ("second argument to %<__builtin_expect%> must be a constant");
|
||||
c = integer_zero_node;
|
||||
}
|
||||
|
||||
target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
|
||||
|
||||
/* Don't bother with expected value notes for integral constants. */
|
||||
if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
|
||||
{
|
||||
/* We do need to force this into a register so that we can be
|
||||
moderately sure to be able to correctly interpret the branch
|
||||
condition later. */
|
||||
target = force_reg (GET_MODE (target), target);
|
||||
|
||||
rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
|
||||
|
||||
note = emit_note (NOTE_INSN_EXPECTED_VALUE);
|
||||
NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
|
||||
}
|
||||
|
||||
/* When guessing was done, the hints should be already stripped away. */
|
||||
gcc_assert (!flag_guess_branch_prob);
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Like expand_builtin_expect, except do this in a jump context. This is
|
||||
called from do_jump if the conditional is a __builtin_expect. Return either
|
||||
a list of insns to emit the jump or NULL if we cannot optimize
|
||||
__builtin_expect. We need to optimize this at jump time so that machines
|
||||
like the PowerPC don't turn the test into a SCC operation, and then jump
|
||||
based on the test being 0/1. */
|
||||
|
||||
rtx
|
||||
expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
{
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
tree arg0 = TREE_VALUE (arglist);
|
||||
tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
rtx ret = NULL_RTX;
|
||||
|
||||
/* Only handle __builtin_expect (test, 0) and
|
||||
__builtin_expect (test, 1). */
|
||||
if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
|
||||
&& (integer_zerop (arg1) || integer_onep (arg1)))
|
||||
{
|
||||
rtx insn, drop_through_label, temp;
|
||||
|
||||
/* Expand the jump insns. */
|
||||
start_sequence ();
|
||||
do_jump (arg0, if_false_label, if_true_label);
|
||||
ret = get_insns ();
|
||||
|
||||
drop_through_label = get_last_insn ();
|
||||
if (drop_through_label && NOTE_P (drop_through_label))
|
||||
drop_through_label = prev_nonnote_insn (drop_through_label);
|
||||
if (drop_through_label && !LABEL_P (drop_through_label))
|
||||
drop_through_label = NULL_RTX;
|
||||
end_sequence ();
|
||||
|
||||
if (! if_true_label)
|
||||
if_true_label = drop_through_label;
|
||||
if (! if_false_label)
|
||||
if_false_label = drop_through_label;
|
||||
|
||||
/* Go through and add the expect's to each of the conditional jumps. */
|
||||
insn = ret;
|
||||
while (insn != NULL_RTX)
|
||||
{
|
||||
rtx next = NEXT_INSN (insn);
|
||||
|
||||
if (JUMP_P (insn) && any_condjump_p (insn))
|
||||
{
|
||||
rtx ifelse = SET_SRC (pc_set (insn));
|
||||
rtx then_dest = XEXP (ifelse, 1);
|
||||
rtx else_dest = XEXP (ifelse, 2);
|
||||
int taken = -1;
|
||||
|
||||
/* First check if we recognize any of the labels. */
|
||||
if (GET_CODE (then_dest) == LABEL_REF
|
||||
&& XEXP (then_dest, 0) == if_true_label)
|
||||
taken = 1;
|
||||
else if (GET_CODE (then_dest) == LABEL_REF
|
||||
&& XEXP (then_dest, 0) == if_false_label)
|
||||
taken = 0;
|
||||
else if (GET_CODE (else_dest) == LABEL_REF
|
||||
&& XEXP (else_dest, 0) == if_false_label)
|
||||
taken = 1;
|
||||
else if (GET_CODE (else_dest) == LABEL_REF
|
||||
&& XEXP (else_dest, 0) == if_true_label)
|
||||
taken = 0;
|
||||
/* Otherwise check where we drop through. */
|
||||
else if (else_dest == pc_rtx)
|
||||
{
|
||||
if (next && NOTE_P (next))
|
||||
next = next_nonnote_insn (next);
|
||||
|
||||
if (next && JUMP_P (next)
|
||||
&& any_uncondjump_p (next))
|
||||
temp = XEXP (SET_SRC (pc_set (next)), 0);
|
||||
else
|
||||
temp = next;
|
||||
|
||||
/* TEMP is either a CODE_LABEL, NULL_RTX or something
|
||||
else that can't possibly match either target label. */
|
||||
if (temp == if_false_label)
|
||||
taken = 1;
|
||||
else if (temp == if_true_label)
|
||||
taken = 0;
|
||||
}
|
||||
else if (then_dest == pc_rtx)
|
||||
{
|
||||
if (next && NOTE_P (next))
|
||||
next = next_nonnote_insn (next);
|
||||
|
||||
if (next && JUMP_P (next)
|
||||
&& any_uncondjump_p (next))
|
||||
temp = XEXP (SET_SRC (pc_set (next)), 0);
|
||||
else
|
||||
temp = next;
|
||||
|
||||
if (temp == if_false_label)
|
||||
taken = 0;
|
||||
else if (temp == if_true_label)
|
||||
taken = 1;
|
||||
}
|
||||
|
||||
if (taken != -1)
|
||||
{
|
||||
/* If the test is expected to fail, reverse the
|
||||
probabilities. */
|
||||
if (integer_zerop (arg1))
|
||||
taken = 1 - taken;
|
||||
predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
|
||||
}
|
||||
}
|
||||
|
||||
insn = next;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
expand_builtin_trap (void)
|
||||
{
|
||||
|
|
|
@ -2300,11 +2300,6 @@ struct tree_opt_pass pass_jump =
|
|||
static unsigned int
|
||||
rest_of_handle_jump2 (void)
|
||||
{
|
||||
/* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this
|
||||
before jump optimization switches branch directions. */
|
||||
if (flag_guess_branch_prob)
|
||||
expected_value_to_br_prob ();
|
||||
|
||||
delete_trivially_dead_insns (get_insns (), max_reg_num ());
|
||||
reg_scan (get_insns (), max_reg_num ());
|
||||
if (dump_file)
|
||||
|
|
|
@ -45,7 +45,7 @@ Boston, MA 02110-1301, USA. */
|
|||
??? We really ought to pass the probability down to RTL expanders and let it
|
||||
re-distribute it when the conditional expands into multiple conditionals.
|
||||
This is however difficult to do. */
|
||||
static void
|
||||
void
|
||||
add_reg_br_prob_note (rtx last, int probability)
|
||||
{
|
||||
if (profile_status == PROFILE_ABSENT)
|
||||
|
|
|
@ -997,7 +997,6 @@ duplicate_insn_chain (rtx from, rtx to)
|
|||
case NOTE_INSN_BASIC_BLOCK:
|
||||
break;
|
||||
|
||||
case NOTE_INSN_REPEATED_LINE_NUMBER:
|
||||
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
|
||||
emit_note_copy (insn);
|
||||
break;
|
||||
|
|
|
@ -5874,10 +5874,9 @@ programmers are notoriously bad at predicting how their programs
|
|||
actually perform. However, there are applications in which this
|
||||
data is hard to collect.
|
||||
|
||||
The return value is the value of @var{exp}, which should be an
|
||||
integral expression. The value of @var{c} must be a compile-time
|
||||
constant. The semantics of the built-in are that it is expected
|
||||
that @var{exp} == @var{c}. For example:
|
||||
The return value is the value of @var{exp}, which should be an integral
|
||||
expression. The semantics of the built-in are that it is expected that
|
||||
@var{exp} == @var{c}. For example:
|
||||
|
||||
@smallexample
|
||||
if (__builtin_expect (x, 0))
|
||||
|
|
31
gcc/dojump.c
31
gcc/dojump.c
|
@ -551,37 +551,6 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
|
|||
}
|
||||
break;
|
||||
|
||||
/* Special case:
|
||||
__builtin_expect (<test>, 0) and
|
||||
__builtin_expect (<test>, 1)
|
||||
|
||||
We need to do this here, so that <test> is not converted to a SCC
|
||||
operation on machines that use condition code registers and COMPARE
|
||||
like the PowerPC, and then the jump is done based on whether the SCC
|
||||
operation produced a 1 or 0. */
|
||||
case CALL_EXPR:
|
||||
/* Check for a built-in function. */
|
||||
{
|
||||
tree fndecl = get_callee_fndecl (exp);
|
||||
tree arglist = TREE_OPERAND (exp, 1);
|
||||
|
||||
if (fndecl
|
||||
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
|
||||
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
|
||||
&& arglist != NULL_TREE
|
||||
&& TREE_CHAIN (arglist) != NULL_TREE)
|
||||
{
|
||||
rtx seq = expand_builtin_expect_jump (exp, if_false_label,
|
||||
if_true_label);
|
||||
|
||||
if (seq != NULL_RTX)
|
||||
{
|
||||
emit_insn (seq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fall through and generate the normal code. */
|
||||
default:
|
||||
normal:
|
||||
|
|
|
@ -1875,11 +1875,9 @@ sjlj_emit_function_enter (rtx dispatch_label)
|
|||
plus_constant (XEXP (fc, 0),
|
||||
sjlj_fc_jbuf_ofs), Pmode);
|
||||
|
||||
note = emit_note (NOTE_INSN_EXPECTED_VALUE);
|
||||
NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
|
||||
|
||||
emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
|
||||
TYPE_MODE (integer_type_node), 0, dispatch_label);
|
||||
add_reg_br_prob_note (get_insns (), REG_BR_PROB_BASE/100);
|
||||
}
|
||||
#else
|
||||
expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
|
||||
|
|
|
@ -1698,8 +1698,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
|
|||
{
|
||||
case NOTE_INSN_DELETED:
|
||||
case NOTE_INSN_FUNCTION_END:
|
||||
case NOTE_INSN_REPEATED_LINE_NUMBER:
|
||||
case NOTE_INSN_EXPECTED_VALUE:
|
||||
break;
|
||||
|
||||
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
|
||||
|
|
|
@ -519,7 +519,6 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
|
|||
note_flds = create_field (note_flds, tree_tp, "rt_tree");
|
||||
break;
|
||||
|
||||
case NOTE_INSN_EXPECTED_VALUE:
|
||||
case NOTE_INSN_VAR_LOCATION:
|
||||
note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
|
||||
break;
|
||||
|
|
|
@ -1340,79 +1340,6 @@ tree_estimate_probability (void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* __builtin_expect dropped tokens into the insn stream describing expected
|
||||
values of registers. Generate branch probabilities based off these
|
||||
values. */
|
||||
|
||||
void
|
||||
expected_value_to_br_prob (void)
|
||||
{
|
||||
rtx insn, cond, ev = NULL_RTX, ev_reg = NULL_RTX;
|
||||
|
||||
for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
|
||||
{
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
case NOTE:
|
||||
/* Look for expected value notes. */
|
||||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EXPECTED_VALUE)
|
||||
{
|
||||
ev = NOTE_EXPECTED_VALUE (insn);
|
||||
ev_reg = XEXP (ev, 0);
|
||||
delete_insn (insn);
|
||||
}
|
||||
continue;
|
||||
|
||||
case CODE_LABEL:
|
||||
/* Never propagate across labels. */
|
||||
ev = NULL_RTX;
|
||||
continue;
|
||||
|
||||
case JUMP_INSN:
|
||||
/* Look for simple conditional branches. If we haven't got an
|
||||
expected value yet, no point going further. */
|
||||
if (!JUMP_P (insn) || ev == NULL_RTX
|
||||
|| ! any_condjump_p (insn))
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Look for insns that clobber the EV register. */
|
||||
if (ev && reg_set_p (ev_reg, insn))
|
||||
ev = NULL_RTX;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Collect the branch condition, hopefully relative to EV_REG. */
|
||||
/* ??? At present we'll miss things like
|
||||
(expected_value (eq r70 0))
|
||||
(set r71 -1)
|
||||
(set r80 (lt r70 r71))
|
||||
(set pc (if_then_else (ne r80 0) ...))
|
||||
as canonicalize_condition will render this to us as
|
||||
(lt r70, r71)
|
||||
Could use cselib to try and reduce this further. */
|
||||
cond = XEXP (SET_SRC (pc_set (insn)), 0);
|
||||
cond = canonicalize_condition (insn, cond, 0, NULL, ev_reg,
|
||||
false, false);
|
||||
if (! cond || XEXP (cond, 0) != ev_reg
|
||||
|| GET_CODE (XEXP (cond, 1)) != CONST_INT)
|
||||
continue;
|
||||
|
||||
/* Substitute and simplify. Given that the expression we're
|
||||
building involves two constants, we should wind up with either
|
||||
true or false. */
|
||||
cond = gen_rtx_fmt_ee (GET_CODE (cond), VOIDmode,
|
||||
XEXP (ev, 1), XEXP (cond, 1));
|
||||
cond = simplify_rtx (cond);
|
||||
|
||||
/* Turn the condition into a scaled branch probability. */
|
||||
gcc_assert (cond == const_true_rtx || cond == const0_rtx);
|
||||
predict_insn_def (insn, PRED_BUILTIN_EXPECT,
|
||||
cond == const_true_rtx ? TAKEN : NOT_TAKEN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether this is the last basic block of function. Commonly
|
||||
there is one extra common cleanup block. */
|
||||
static bool
|
||||
|
|
|
@ -299,14 +299,6 @@ print_rtx (rtx in_rtx)
|
|||
break;
|
||||
}
|
||||
|
||||
case NOTE_INSN_EXPECTED_VALUE:
|
||||
indent += 2;
|
||||
if (!sawclose)
|
||||
fprintf (outfile, " ");
|
||||
print_rtx (NOTE_EXPECTED_VALUE (in_rtx));
|
||||
indent -= 2;
|
||||
break;
|
||||
|
||||
case NOTE_INSN_DELETED_LABEL:
|
||||
{
|
||||
const char *label = NOTE_DELETED_LABEL_NAME (in_rtx);
|
||||
|
|
|
@ -2250,6 +2250,8 @@ extern GTY(()) rtx stack_limit_rtx;
|
|||
/* In predict.c */
|
||||
extern void invert_br_probabilities (rtx);
|
||||
extern bool expensive_function_p (int);
|
||||
/* In cfgexpand.c */
|
||||
extern void add_reg_br_prob_note (rtx last, int probability);
|
||||
/* In tracer.c */
|
||||
extern void tracer (unsigned int);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue