diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4142eef6418..658e7640deb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2001-06-20 Michael Meissner + + * 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 (, 0) and + __builtin_expect (, 1). + + * Makefile.in (builtins.o): Depend on $(PREDICT_H). + + * rtl.h (expand_builtin_expect_jump): Add prototype. + 2001-06-19 Geoffrey Keating * doc/rtl.texi (Machine Modes): Correct description of diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 949211f9c06..563e7b718d6 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 0d71b292b12..3e4ef1553ee 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 9b81988521b..4031cab1635 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 (, 0) and + __builtin_expect (, 1) + + We need to do this here, so that 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 32c22ecbe2c..ca35d3f33bc 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,