Commit 5f2d6cfa by Michael Meissner Committed by Michael Meissner

Fix __builtin_expect on PowerPCs

From-SVN: r43470
parent f34c9fd4
2001-06-20 Michael Meissner <meissner@redhat.com>
* builtins.c (predict.h): Include.
(expand_builtin_expect): Update comment.
(expand_builtin_expect_jump): New function to expand
__builtin_expect inside of a conditional jump expansion.
* expr.c (do_jump): Special case __builtin_expect (<test>, 0) and
__builtin_expect (<test>, 1).
* Makefile.in (builtins.o): Depend on $(PREDICT_H).
* rtl.h (expand_builtin_expect_jump): Add prototype.
2001-06-19 Geoffrey Keating <geoffk@redhat.com>
* doc/rtl.texi (Machine Modes): Correct description of
......
......@@ -1371,7 +1371,7 @@ expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h \
builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
function.h $(REGS_H) $(EXPR_H) insn-config.h \
$(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \
except.h $(TM_P_H)
except.h $(TM_P_H) $(PREDICT_H)
calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h $(EXPR_H) \
$(REGS_H) toplev.h output.h function.h $(TIMEVAR_H) $(TM_P_H)
expmed.o : expmed.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
......
......@@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA. */
#include "output.h"
#include "typeclass.h"
#include "toplev.h"
#include "predict.h"
#include "tm_p.h"
#define CALLED_AS_BUILT_IN(NODE) \
......@@ -3232,8 +3233,9 @@ expand_builtin_fputs (arglist, ignore)
VOIDmode, EXPAND_NORMAL);
}
/* Expand a call to __builtin_expect. We return our argument and
emit a NOTE_INSN_EXPECTED_VALUE note. */
/* 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. */
static rtx
expand_builtin_expect (arglist, target)
......@@ -3273,6 +3275,115 @@ expand_builtin_expect (arglist, target)
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 SEQUENCE 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 (exp, if_false_label, if_true_label)
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
&& TREE_CODE (arg1) == INTEGER_CST
&& (TREE_INT_CST_LOW (arg1) == 0 || TREE_INT_CST_LOW (arg1) == 1)
&& TREE_INT_CST_HIGH (arg1) == 0)
{
int j;
int num_jumps = 0;
/* Expand the jump insns. */
start_sequence ();
do_jump (arg0, if_false_label, if_true_label);
ret = gen_sequence ();
end_sequence ();
/* Now that the __builtin_expect has been validated, go through and add
the expect's to each of the conditional jumps. If we run into an
error, just give up and generate the 'safe' code of doing a SCC
operation and then doing a branch on that. */
for (j = 0; j < XVECLEN (ret, 0); j++)
{
rtx insn = XVECEXP (ret, 0, j);
rtx pattern;
if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
&& (pattern = pc_set (insn)) != NULL_RTX)
{
rtx ifelse = SET_SRC (pattern);
rtx label;
int taken;
if (GET_CODE (ifelse) != IF_THEN_ELSE)
continue;
if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
{
taken = 1;
label = XEXP (XEXP (ifelse, 1), 0);
}
/* An inverted jump reverses the probabilities. */
else if (GET_CODE (XEXP (ifelse, 2)) == LABEL_REF)
{
taken = 0;
label = XEXP (XEXP (ifelse, 2), 0);
}
/* We shouldn't have to worry about conditional returns during
the expansion stage, but handle it gracefully anyway. */
else if (GET_CODE (XEXP (ifelse, 1)) == RETURN)
{
taken = 1;
label = NULL_RTX;
}
/* An inverted return reverses the probabilities. */
else if (GET_CODE (XEXP (ifelse, 2)) == RETURN)
{
taken = 0;
label = NULL_RTX;
}
else
continue;
/* If the test is expected to fail, reverse the
probabilities. */
if (TREE_INT_CST_LOW (arg1) == 0)
taken = 1 - taken;
/* If we are jumping to the false label, reverse the
probabilities. */
if (label == NULL_RTX)
; /* conditional return */
else if (label == if_false_label)
taken = 1 - taken;
else if (label != if_true_label)
continue;
num_jumps++;
predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
}
}
/* If no jumps were modified, fail and do __builtin_expect the normal
way. */
if (num_jumps == 0)
ret = NULL_RTX;
}
return ret;
}
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
......
......@@ -9913,6 +9913,39 @@ do_jump (exp, if_false_label, 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. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& DECL_BUILT_IN (fndecl)
&& 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:
temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
......
......@@ -1146,6 +1146,9 @@ extern int ceil_log2 PARAMS ((unsigned HOST_WIDE_INT));
#define plus_constant_for_output(X,C) \
plus_constant_for_output_wide (X, (HOST_WIDE_INT) (C))
/* In builtins.c */
extern rtx expand_builtin_expect_jump PARAMS ((union tree_node *, rtx, rtx));
/* In explow.c */
extern void set_stack_check_libfunc PARAMS ((rtx));
extern HOST_WIDE_INT trunc_int_for_mode PARAMS ((HOST_WIDE_INT,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment