OSDN Git Service

* gcse.c (lookup_set): Remove unused argument PAT. Update
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index 82660be..ed04aef 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "regs.h"
@@ -343,7 +345,7 @@ cond_exec_get_condition (jump)
 
 /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
    to conditional execution.  Return TRUE if we were successful at
-   converting the the block.  */
+   converting the block.  */
 
 static int
 cond_exec_process_if_block (ce_info, do_multiple_p)
@@ -358,7 +360,7 @@ cond_exec_process_if_block (ce_info, do_multiple_p)
   rtx then_end;                        /* last insn + 1 in THEN block */
   rtx else_start = NULL_RTX;   /* first insn in ELSE block or NULL */
   rtx else_end = NULL_RTX;     /* last insn + 1 in ELSE block */
-  int max;                     /* max # of insns to convert. */
+  int max;                     /* max # of insns to convert.  */
   int then_mod_ok;             /* whether conditional mods are ok in THEN */
   rtx true_expr;               /* test for else block insns */
   rtx false_expr;              /* test for then block insns */
@@ -580,7 +582,7 @@ struct noce_if_info
 static rtx noce_emit_store_flag                PARAMS ((struct noce_if_info *,
                                                 rtx, int, int));
 static int noce_try_store_flag         PARAMS ((struct noce_if_info *));
-static int noce_try_store_flag_inc     PARAMS ((struct noce_if_info *));
+static int noce_try_addcc              PARAMS ((struct noce_if_info *));
 static int noce_try_store_flag_constants PARAMS ((struct noce_if_info *));
 static int noce_try_store_flag_mask    PARAMS ((struct noce_if_info *));
 static rtx noce_emit_cmove             PARAMS ((struct noce_if_info *,
@@ -645,8 +647,8 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
       end_sequence ();
     }
 
-  /* Don't even try if the comparison operands are weird.  */
-  if (cond_complex)
+  /* Don't even try if the comparison operands or the mode of X are weird.  */
+  if (cond_complex || !SCALAR_INT_MODE_P (GET_MODE (x)))
     return NULL_RTX;
 
   return emit_store_flag (x, code, XEXP (cond, 0),
@@ -862,61 +864,91 @@ noce_try_store_flag_constants (if_info)
    similarly for "foo--".  */
 
 static int
-noce_try_store_flag_inc (if_info)
+noce_try_addcc (if_info)
      struct noce_if_info *if_info;
 {
   rtx target, seq;
   int subtract, normalize;
 
   if (! no_new_pseudos
-      && (BRANCH_COST >= 2
-         || HAVE_incscc
-         || HAVE_decscc)
       /* Should be no `else' case to worry about.  */
       && if_info->b == if_info->x
       && GET_CODE (if_info->a) == PLUS
-      && (XEXP (if_info->a, 1) == const1_rtx
-         || XEXP (if_info->a, 1) == constm1_rtx)
       && rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
       && (reversed_comparison_code (if_info->cond, if_info->jump)
          != UNKNOWN))
     {
-      if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
-       subtract = 0, normalize = 0;
-      else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
-       subtract = 1, normalize = 0;
-      else
-       subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
-      
-      start_sequence ();
+      rtx cond = if_info->cond;
+      enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
 
-      target = noce_emit_store_flag (if_info,
-                                    gen_reg_rtx (GET_MODE (if_info->x)),
-                                    1, normalize);
-
-      if (target)
-       target = expand_simple_binop (GET_MODE (if_info->x),
-                                     subtract ? MINUS : PLUS,
-                                     if_info->x, target, if_info->x,
-                                     0, OPTAB_WIDEN);
-      if (target)
+      /* First try to use addcc pattern.  */
+      if (general_operand (XEXP (cond, 0), VOIDmode)
+         && general_operand (XEXP (cond, 1), VOIDmode))
        {
-         if (target != if_info->x)
-           noce_emit_move_insn (if_info->x, target);
-
-         seq = get_insns ();
+         start_sequence ();
+         target = emit_conditional_add (if_info->x, code,
+                                        XEXP (cond, 0), XEXP (cond, 1),
+                                        VOIDmode,
+                                        if_info->b, XEXP (if_info->a, 1),
+                                        GET_MODE (if_info->x),
+                                        (code == LTU || code == GEU
+                                         || code == LEU || code == GTU));
+         if (target)
+           {
+             if (target != if_info->x)
+               noce_emit_move_insn (if_info->x, target);
+
+             seq = get_insns ();
+             end_sequence ();
+             emit_insn_before_scope (seq, if_info->jump,
+                                     INSN_SCOPE (if_info->insn_a));
+             return TRUE;
+           }
          end_sequence ();
+       }
+       
+      /* If that fails, construct conditional increment or decrement using
+        setcc.  */
+      if (BRANCH_COST >= 2
+         && (XEXP (if_info->a, 1) == const1_rtx
+             || XEXP (if_info->a, 1) == constm1_rtx))
+        {
+         start_sequence ();
+         if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
+           subtract = 0, normalize = 0;
+         else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
+           subtract = 1, normalize = 0;
+         else
+           subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
 
-         if (seq_contains_jump (seq))
-           return FALSE;
 
-         emit_insn_before_scope (seq, if_info->jump,
-                                 INSN_SCOPE (if_info->insn_a));
+         target = noce_emit_store_flag (if_info,
+                                        gen_reg_rtx (GET_MODE (if_info->x)),
+                                        1, normalize);
 
-         return TRUE;
-       }
+         if (target)
+           target = expand_simple_binop (GET_MODE (if_info->x),
+                                         subtract ? MINUS : PLUS,
+                                         if_info->x, target, if_info->x,
+                                         0, OPTAB_WIDEN);
+         if (target)
+           {
+             if (target != if_info->x)
+               noce_emit_move_insn (if_info->x, target);
 
-      end_sequence ();
+             seq = get_insns ();
+             end_sequence ();
+
+             if (seq_contains_jump (seq))
+               return FALSE;
+
+             emit_insn_before_scope (seq, if_info->jump,
+                                     INSN_SCOPE (if_info->insn_a));
+
+             return TRUE;
+           }
+         end_sequence ();
+       }
     }
 
   return FALSE;
@@ -1687,7 +1719,7 @@ noce_operand_ok (op)
 
 /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
    without using conditional execution.  Return TRUE if we were
-   successful at converting the the block.  */
+   successful at converting the block.  */
 
 static int
 noce_process_if_block (ce_info)
@@ -1700,7 +1732,7 @@ noce_process_if_block (ce_info)
   rtx insn_a, insn_b;
   rtx set_a, set_b;
   rtx orig_x, x, a, b;
-  rtx jump, cond, insn;
+  rtx jump, cond;
 
   /* We're looking for patterns of the form
 
@@ -1770,30 +1802,26 @@ noce_process_if_block (ce_info)
   else
     {
       insn_b = prev_nonnote_insn (if_info.cond_earliest);
+      /* We're going to be moving the evaluation of B down from above
+        COND_EARLIEST to JUMP.  Make sure the relevant data is still
+        intact.  */
       if (! insn_b
          || GET_CODE (insn_b) != INSN
          || (set_b = single_set (insn_b)) == NULL_RTX
          || ! rtx_equal_p (x, SET_DEST (set_b))
+         || reg_overlap_mentioned_p (x, SET_SRC (set_b))
+         || modified_between_p (SET_SRC (set_b),
+                                PREV_INSN (if_info.cond_earliest), jump)
+         /* Likewise with X.  In particular this can happen when
+            noce_get_condition looks farther back in the instruction
+            stream than one might expect.  */
          || reg_overlap_mentioned_p (x, cond)
          || reg_overlap_mentioned_p (x, a)
-         || reg_overlap_mentioned_p (x, SET_SRC (set_b)))
+         || modified_between_p (x, PREV_INSN (if_info.cond_earliest), jump))
        insn_b = set_b = NULL_RTX;
     }
   b = (set_b ? SET_SRC (set_b) : x);
 
-  /* X may not be mentioned in the range (cond_earliest, jump]. 
-     Note the use of reg_overlap_mentioned_p, which handles memories
-     properly, as opposed to reg_mentioned_p, which doesn't.  */
-  for (insn = jump; insn != if_info.cond_earliest; insn = PREV_INSN (insn))
-    if (INSN_P (insn) && reg_overlap_mentioned_p (x, PATTERN (insn)))
-      return FALSE;
-
-  /* A and B may not be modified in the range [cond_earliest, jump).  */
-  for (insn = if_info.cond_earliest; insn != jump; insn = NEXT_INSN (insn))
-    if (INSN_P (insn)
-       && (modified_in_p (a, insn) || modified_in_p (b, insn)))
-      return FALSE;
-
   /* Only operate on register destinations, and even then avoid extending
      the lifetime of hard registers on small register class machines.  */
   orig_x = x;
@@ -1839,7 +1867,7 @@ noce_process_if_block (ce_info)
 
          if (else_bb && insn_b == else_bb->end)
            else_bb->end = PREV_INSN (insn_b);
-         reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
+         reorder_insns (insn_b, insn_b, PREV_INSN (jump));
 
          /* If there was a REG_EQUAL note, delete it since it may have been
             true due to this insn being after a jump.  */
@@ -1870,7 +1898,7 @@ noce_process_if_block (ce_info)
     {
       if (noce_try_store_flag_constants (&if_info))
        goto success;
-      if (noce_try_store_flag_inc (&if_info))
+      if (noce_try_addcc (&if_info))
        goto success;
       if (noce_try_store_flag_mask (&if_info))
        goto success;
@@ -1894,9 +1922,9 @@ noce_process_if_block (ce_info)
   if (insn_b && else_bb)
     delete_insn (insn_b);
 
-  /* The new insns will have been inserted before cond_earliest.  We should
-     be able to remove the jump with impunity, but the condition itself may
-     have been modified by gcse to be shared across basic blocks.  */
+  /* The new insns will have been inserted immediately before the jump.  We
+     should be able to remove the jump with impunity, but the condition itself
+     may have been modified by gcse to be shared across basic blocks.  */
   delete_insn (jump);
 
   /* If we used a temporary, fix it up now.  */
@@ -2230,7 +2258,7 @@ block_jumps_and_fallthru_p (cur_bb, target_bb)
 
 /* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE
    block.  If so, we'll try to convert the insns to not require the branch.
-   Return TRUE if we were successful at converting the the block.  */
+   Return TRUE if we were successful at converting the block.  */
 
 static int
 find_if_block (ce_info)
@@ -2262,7 +2290,7 @@ find_if_block (ce_info)
       int max_insns = MAX_CONDITIONAL_EXECUTE;
       int n_insns;
 
-      /* Determine if the preceeding block is an && or || block.  */
+      /* Determine if the preceding block is an && or || block.  */
       if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0)
        {
          ce_info->and_and_p = TRUE;
@@ -2580,7 +2608,7 @@ block_has_only_trap (bb)
    transformable, but not necessarily the other.  There need be no
    JOIN block.
 
-   Return TRUE if we were successful at converting the the block.
+   Return TRUE if we were successful at converting the block.
 
    Cases we'd like to look at:
 
@@ -2857,7 +2885,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
   if (HAVE_conditional_execution)
     {
       /* In the conditional execution case, we have things easy.  We know
-        the condition is reversable.  We don't have to check life info,
+        the condition is reversible.  We don't have to check life info,
         becase we're going to conditionally execute the code anyway.
         All that's left is making sure the insns involved can actually
         be predicated.  */
@@ -3115,8 +3143,8 @@ if_convert (x_life_data_ok)
 
       FOR_EACH_BB (bb)
        {
-         basic_block new_bb = find_if_header (bb, pass);
-         if (new_bb)
+         basic_block new_bb;
+         while ((new_bb = find_if_header (bb, pass)))
            bb = new_bb;
        }