mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-09 02:56:44 +08:00
Fix __builtin_expect on PowerPCs
From-SVN: r43470
This commit is contained in:
parent
f34c9fd4a6
commit
5f2d6cfa81
@ -1,3 +1,17 @@
|
||||
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 \
|
||||
|
115
gcc/builtins.c
115
gcc/builtins.c
@ -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
|
||||
|
33
gcc/expr.c
33
gcc/expr.c
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user