OSDN Git Service

* bb-reorder.c (fix_crossing_unconditional_branches): Use Pmode
[pf3gnuchains/gcc-fork.git] / gcc / dojump.c
index 14fed96..eb98e76 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -33,17 +33,19 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "expr.h"
 #include "optabs.h"
 #include "langhooks.h"
+#include "ggc.h"
 
-static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
-static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
-static void do_compare_and_jump        PARAMS ((tree, enum rtx_code, enum rtx_code,
-                                        rtx, rtx));
+static bool prefer_and_bit_test (enum machine_mode, int);
+static void do_jump_by_parts_greater (tree, int, rtx, rtx);
+static void do_jump_by_parts_equality (tree, rtx, rtx);
+static void do_compare_and_jump        (tree, enum rtx_code, enum rtx_code, rtx,
+                                rtx);
 
 /* At the start of a function, record that we have no previously-pushed
    arguments waiting to be popped.  */
 
 void
-init_pending_stack_adjust ()
+init_pending_stack_adjust (void)
 {
   pending_stack_adjust = 0;
 }
@@ -55,9 +57,8 @@ init_pending_stack_adjust ()
    frame pointer regardless of the value of flag_omit_frame_pointer.  */
 
 void
-clear_pending_stack_adjust ()
+clear_pending_stack_adjust (void)
 {
-#ifdef EXIT_IGNORE_STACK
   if (optimize > 0
       && (! flag_omit_frame_pointer || current_function_calls_alloca)
       && EXIT_IGNORE_STACK
@@ -67,13 +68,12 @@ clear_pending_stack_adjust ()
       stack_pointer_delta -= pending_stack_adjust,
       pending_stack_adjust = 0;
     }
-#endif
 }
 
 /* Pop any previously-pushed arguments that have not been popped yet.  */
 
 void
-do_pending_stack_adjust ()
+do_pending_stack_adjust (void)
 {
   if (inhibit_defer_pop == 0)
     {
@@ -90,9 +90,7 @@ do_pending_stack_adjust ()
    functions here.  */
 
 void
-jumpifnot (exp, label)
-     tree exp;
-     rtx label;
+jumpifnot (tree exp, rtx label)
 {
   do_jump (exp, label, NULL_RTX);
 }
@@ -100,13 +98,50 @@ jumpifnot (exp, label)
 /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
 
 void
-jumpif (exp, label)
-     tree exp;
-     rtx label;
+jumpif (tree exp, rtx label)
 {
   do_jump (exp, NULL_RTX, label);
 }
 
+/* Used internally by prefer_and_bit_test.  */
+
+static GTY(()) rtx and_reg;
+static GTY(()) rtx and_test;
+static GTY(()) rtx shift_test;
+
+/* Compare the relative costs of "(X & (1 << BITNUM))" and "(X >> BITNUM) & 1",
+   where X is an arbitrary register of mode MODE.  Return true if the former
+   is preferred.  */
+
+static bool
+prefer_and_bit_test (enum machine_mode mode, int bitnum)
+{
+  if (and_test == 0)
+    {
+      /* Set up rtxes for the two variations.  Use NULL as a placeholder
+        for the BITNUM-based constants.  */
+      and_reg = gen_rtx_REG (mode, FIRST_PSEUDO_REGISTER);
+      and_test = gen_rtx_AND (mode, and_reg, NULL);
+      shift_test = gen_rtx_AND (mode, gen_rtx_ASHIFTRT (mode, and_reg, NULL),
+                               const1_rtx);
+    }
+  else
+    {
+      /* Change the mode of the previously-created rtxes.  */
+      PUT_MODE (and_reg, mode);
+      PUT_MODE (and_test, mode);
+      PUT_MODE (shift_test, mode);
+      PUT_MODE (XEXP (shift_test, 0), mode);
+    }
+
+  /* Fill in the integers.  */
+  XEXP (and_test, 1) = GEN_INT ((unsigned HOST_WIDE_INT) 1 << bitnum);
+  XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
+
+  return (rtx_cost (and_test, IF_THEN_ELSE)
+         <= rtx_cost (shift_test, IF_THEN_ELSE));
+}
+
 /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
    the result is zero, or IF_TRUE_LABEL if the result is one.
    Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
@@ -120,9 +155,7 @@ jumpif (exp, label)
    &&, || and comparison operators in EXP.  */
 
 void
-do_jump (exp, if_false_label, if_true_label)
-     tree exp;
-     rtx if_false_label, if_true_label;
+do_jump (tree exp, rtx if_false_label, rtx if_true_label)
 {
   enum tree_code code = TREE_CODE (exp);
   /* Some cases need to create a label to jump to
@@ -134,10 +167,6 @@ do_jump (exp, if_false_label, if_true_label)
   tree type;
   enum machine_mode mode;
 
-#ifdef MAX_INTEGER_COMPUTATION_MODE
-  check_max_integer_computation_mode (exp);
-#endif
-
   emit_queue ();
 
   switch (code)
@@ -163,7 +192,7 @@ do_jump (exp, if_false_label, if_true_label)
     case UNSAVE_EXPR:
       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
       TREE_OPERAND (exp, 0)
-       = (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0));
+       = lang_hooks.unsave_expr_now (TREE_OPERAND (exp, 0));
       break;
 
     case NOP_EXPR:
@@ -188,15 +217,6 @@ do_jump (exp, if_false_label, if_true_label)
       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
       break;
 
-    case WITH_RECORD_EXPR:
-      /* Put the object on the placeholder list, recurse through our first
-         operand, and pop the list.  */
-      placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
-                                    placeholder_list);
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-      placeholder_list = TREE_CHAIN (placeholder_list);
-      break;
-
 #if 0
       /* This is never less insns than evaluating the PLUS_EXPR followed by
          a test and can be longer if the test is eliminated.  */
@@ -218,6 +238,29 @@ do_jump (exp, if_false_label, if_true_label)
       break;
 
     case BIT_AND_EXPR:
+      /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
+        See if the former is preferred for jump tests and restore it
+        if so.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 0)) == RSHIFT_EXPR
+         && integer_onep (TREE_OPERAND (exp, 1)))
+       {
+         tree arg = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+         tree shift = TREE_OPERAND (TREE_OPERAND (exp, 0), 1);
+         tree one = TREE_OPERAND (exp, 1);
+         tree argtype = TREE_TYPE (arg);
+         if (TREE_CODE (shift) == INTEGER_CST
+             && compare_tree_int (shift, 0) > 0
+             && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
+             && prefer_and_bit_test (TYPE_MODE (argtype),
+                                     TREE_INT_CST_LOW (shift)))
+           {
+             do_jump (build (BIT_AND_EXPR, argtype, arg,
+                             fold (build (LSHIFT_EXPR, argtype, one, shift))),
+                      if_false_label, if_true_label);
+             break;
+           }
+       }
+
       /* If we are AND'ing with a small constant, do this comparison in the
          smallest type that fits.  If the machine doesn't have comparisons
          that small, it will be converted back to the wider comparison.
@@ -230,7 +273,7 @@ do_jump (exp, if_false_label, if_true_label)
           && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
           && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
           && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
-          && (type = (*lang_hooks.types.type_for_mode) (mode, 1)) != 0
+          && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
           && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
           && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
               != CODE_FOR_nothing))
@@ -290,7 +333,7 @@ do_jump (exp, if_false_label, if_true_label)
         get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
                              &unsignedp, &volatilep);
 
-        type = (*lang_hooks.types.type_for_size) (bitsize, unsignedp);
+        type = lang_hooks.types.type_for_size (bitsize, unsignedp);
         if (! SLOW_BYTE_ACCESS
             && type != 0 && bitsize >= 0
             && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
@@ -536,28 +579,27 @@ do_jump (exp, if_false_label, if_true_label)
          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.  */
+      {
+       tree fndecl = get_callee_fndecl (exp);
+       tree arglist = TREE_OPERAND (exp, 1);
+
+       if (fndecl
+           && 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:
@@ -588,10 +630,22 @@ do_jump (exp, if_false_label, if_true_label)
         /* Note swapping the labels gives us not-equal.  */
         do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
       else if (GET_MODE (temp) != VOIDmode)
-        do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
-                                 NE, TREE_UNSIGNED (TREE_TYPE (exp)),
-                                 GET_MODE (temp), NULL_RTX,
-                                 if_false_label, if_true_label);
+       {
+         /* The RTL optimizers prefer comparisons against pseudos.  */
+         if (GET_CODE (temp) == SUBREG)
+           {
+             /* Compare promoted variables in their promoted mode.  */
+             if (SUBREG_PROMOTED_VAR_P (temp)
+                 && GET_CODE (XEXP (temp, 0)) == REG)
+               temp = XEXP (temp, 0);
+             else
+               temp = copy_to_reg (temp);
+           }
+         do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
+                                  NE, TYPE_UNSIGNED (TREE_TYPE (exp)),
+                                  GET_MODE (temp), NULL_RTX,
+                                  if_false_label, if_true_label);
+       }
       else
         abort ();
     }
@@ -612,17 +666,16 @@ do_jump (exp, if_false_label, if_true_label)
    and LT if SWAP is 1.  */
 
 static void
-do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
-     tree exp;
-     int swap;
-     rtx if_false_label, if_true_label;
+do_jump_by_parts_greater (tree exp, int swap, rtx if_false_label,
+                         rtx if_true_label)
 {
   rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0);
   rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0);
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-  int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
 
-  do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label);
+  do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label,
+                               if_true_label);
 }
 
 /* Compare OP0 with OP1, word at a time, in mode MODE.
@@ -630,11 +683,8 @@ do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
    Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise.  */
 
 void
-do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label)
-     enum machine_mode mode;
-     int unsignedp;
-     rtx op0, op1;
-     rtx if_false_label, if_true_label;
+do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
+                             rtx op1, rtx if_false_label, rtx if_true_label)
 {
   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
   rtx drop_through_label = 0;
@@ -683,9 +733,7 @@ do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true
    with one insn, test the comparison and jump to the appropriate label.  */
 
 static void
-do_jump_by_parts_equality (exp, if_false_label, if_true_label)
-     tree exp;
-     rtx if_false_label, if_true_label;
+do_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
 {
   rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
   rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
@@ -700,7 +748,7 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label)
   for (i = 0; i < nwords; i++)
     do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
                              operand_subword_force (op1, i, mode),
-                             EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
+                             EQ, TYPE_UNSIGNED (TREE_TYPE (exp)),
                              word_mode, NULL_RTX, if_false_label, NULL_RTX);
 
   if (if_true_label)
@@ -714,9 +762,7 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label)
    for the available compare insns.  */
 
 void
-do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
-     rtx op0;
-     rtx if_false_label, if_true_label;
+do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
 {
   int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
   rtx part;
@@ -771,12 +817,8 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
    compared.  */
 
 rtx
-compare_from_rtx (op0, op1, code, unsignedp, mode, size)
-     rtx op0, op1;
-     enum rtx_code code;
-     int unsignedp;
-     enum machine_mode mode;
-     rtx size;
+compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
+                 enum machine_mode mode, rtx size)
 {
   enum rtx_code ucode;
   rtx tem;
@@ -801,7 +843,8 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size)
   do_pending_stack_adjust ();
 
   ucode = unsignedp ? unsigned_condition (code) : code;
-  if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
+  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
+  if (tem != 0)
     return tem;
 
 #if 0
@@ -842,14 +885,9 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size)
    compared.  */
 
 void
-do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
-                         if_false_label, if_true_label)
-     rtx op0, op1;
-     enum rtx_code code;
-     int unsignedp;
-     enum machine_mode mode;
-     rtx size;
-     rtx if_false_label, if_true_label;
+do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
+                        enum machine_mode mode, rtx size, rtx if_false_label,
+                        rtx if_true_label)
 {
   enum rtx_code ucode;
   rtx tem;
@@ -884,7 +922,8 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
   do_pending_stack_adjust ();
 
   ucode = unsignedp ? unsigned_condition (code) : code;
-  if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
+  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
+  if (tem != 0)
     {
       if (tem == const_true_rtx)
         {
@@ -947,11 +986,9 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
    things pushed on the stack that aren't yet used.  */
 
 static void
-do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
-                     if_true_label)
-     tree exp;
-     enum rtx_code signed_code, unsigned_code;
-     rtx if_false_label, if_true_label;
+do_compare_and_jump (tree exp, enum rtx_code signed_code,
+                    enum rtx_code unsigned_code, rtx if_false_label,
+                    rtx if_true_label)
 {
   rtx op0, op1;
   tree type;
@@ -981,7 +1018,7 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
       type = TREE_TYPE (TREE_OPERAND (exp, 1));
       mode = TYPE_MODE (type);
     }
-  unsignedp = TREE_UNSIGNED (type);
+  unsignedp = TYPE_UNSIGNED (type);
   code = unsignedp ? unsigned_code : signed_code;
 
 #ifdef HAVE_canonicalize_funcptr_for_compare
@@ -1018,3 +1055,5 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
                             ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
                            if_false_label, if_true_label);
 }
+
+#include "gt-dojump.h"