aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/builtins.c115
-rw-r--r--gcc/expr.c33
-rw-r--r--gcc/rtl.h3
5 files changed, 164 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4142eef..658e764 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 949211f..563e7b7 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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 \
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 0d71b29..3e4ef15 100644
--- a/gcc/builtins.c
+++ b/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
diff --git a/gcc/expr.c b/gcc/expr.c
index 9b81988..4031cab 100644
--- a/gcc/expr.c
+++ b/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);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 32c22ec..ca35d3f 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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,