Fix __builtin_expect on PowerPCs
authorMichael Meissner <meissner@redhat.com>
Wed, 20 Jun 2001 07:18:18 +0000 (07:18 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Wed, 20 Jun 2001 07:18:18 +0000 (07:18 +0000)
From-SVN: r43470

gcc/ChangeLog
gcc/Makefile.in
gcc/builtins.c
gcc/expr.c
gcc/rtl.h

index 4142eef641847f0286853532b32f8e8af0d41b73..658e7640debbc8a36ab4c6b08b2641d9955696e9 100644 (file)
@@ -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
index 949211f9c06f049f78797b8dc5c5a1ed068b183a..563e7b718d67b3d954ea425a69f25fe03634c957 100644 (file)
@@ -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  \
index 0d71b292b12f69657533e330d88d20f1874dd9c3..3e4ef1553eefd67f8d6c0b6e827a91178adbddfd 100644 (file)
@@ -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;
+}
+
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
index 9b81988521bf70a2aa4e21ed906f8618ddcbe0d6..4031cab1635c911b5a1c574b89b1a921156100b5 100644 (file)
@@ -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);
index 32c22ecbe2c4fa1ee498b23f11a946149124b38a..ca35d3f33bc9ef5aa7b43b4e0cb2b428c1402cbc 100644 (file)
--- 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,