OSDN Git Service

Amend last change: add %, in front of Ldi%=:
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index aa54390..901bd42 100644 (file)
 #include "flags.h"
 #include "insn-config.h"
 #include "recog.h"
+#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "expr.h"
 #include "output.h"
-#include "hard-reg-set.h"
 #include "tm_p.h"
 
 
@@ -51,8 +51,6 @@
 #define MAX_CONDITIONAL_EXECUTE   (BRANCH_COST + 1)
 #endif
 
-#define EDGE_COMPLEX   (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
-
 #define NULL_EDGE      ((struct edge_def *)NULL)
 #define NULL_BLOCK     ((struct basic_block_def *)NULL)
 
@@ -73,6 +71,7 @@ static sbitmap *post_dominators;
 static int count_bb_insns              PARAMS ((basic_block));
 static rtx first_active_insn           PARAMS ((basic_block));
 static int last_active_insn_p          PARAMS ((basic_block, rtx));
+static int seq_contains_jump           PARAMS ((rtx));
 
 static int cond_exec_process_insns     PARAMS ((rtx, rtx, rtx, rtx, int));
 static rtx cond_exec_get_condition     PARAMS ((rtx));
@@ -173,6 +172,24 @@ last_active_insn_p (bb, insn)
 
   return GET_CODE (insn) == JUMP_INSN;
 }
+
+/* It is possible, especially when having dealt with multi-word 
+   arithmetic, for the expanders to have emitted jumps.  Search
+   through the sequence and return TRUE if a jump exists so that
+   we can abort the conversion.  */
+
+static int
+seq_contains_jump (insn)
+     rtx insn;
+{
+  while (insn)
+    {
+      if (GET_CODE (insn) == JUMP_INSN)
+       return 1;
+      insn = NEXT_INSN (insn);
+    }
+  return 0;
+}
 \f
 /* Go through a bunch of insns, converting them to conditional
    execution format if possible.  Return TRUE if all of the non-note
@@ -188,6 +205,7 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok)
 {
   int must_be_last = FALSE;
   rtx insn;
+  rtx pattern;
 
   for (insn = start; ; insn = NEXT_INSN (insn))
     {
@@ -197,6 +215,17 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok)
       if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
        abort ();
 
+      /* Remove USE insns that get in the way.  */
+      if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
+       {
+         /* ??? Ug.  Actually unlinking the thing is problematic, 
+            given what we'd have to coordinate with our callers.  */
+         PUT_CODE (insn, NOTE);
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+         NOTE_SOURCE_FILE (insn) = 0;
+         goto insn_done;
+       }
+
       /* Last insn wasn't last?  */
       if (must_be_last)
        return FALSE;
@@ -209,9 +238,20 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok)
        }
 
       /* Now build the conditional form of the instruction.  */
+      pattern = PATTERN (insn);
+
+      /* If the machine needs to modify the insn being conditionally executed,
+         say for example to force a constant integer operand into a temp
+         register, do so here.  */
+#ifdef IFCVT_MODIFY_INSN
+      IFCVT_MODIFY_INSN (pattern, insn);
+      if (! pattern)
+       return FALSE;
+#endif
+
       validate_change (insn, &PATTERN (insn),
                       gen_rtx_COND_EXEC (VOIDmode, copy_rtx (test),
-                                         PATTERN (insn)), 1);
+                                         pattern), 1);
 
       if (GET_CODE (insn) == CALL_INSN && prob_val)
        validate_change (insn, &REG_NOTES (insn),
@@ -234,10 +274,8 @@ cond_exec_get_condition (jump)
 {
   rtx test_if, cond;
 
-  if (condjump_p (jump))
-    test_if = SET_SRC (PATTERN (jump));
-  else if (condjump_in_parallel_p (jump))
-    test_if = SET_SRC (XVECEXP (PATTERN (jump), 0, 0));
+  if (any_condjump_p (jump))
+    test_if = SET_SRC (pc_set (jump));
   else
     return NULL_RTX;
   cond = XEXP (test_if, 0);
@@ -267,8 +305,8 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   rtx test_expr;               /* expression in IF_THEN_ELSE that is tested */
   rtx then_start;              /* first insn in THEN block */
   rtx then_end;                        /* last insn + 1 in THEN block */
-  rtx else_start;              /* first insn in ELSE block or NULL */
-  rtx else_end;                        /* last insn + 1 in ELSE 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 then_mod_ok;             /* whether conditional mods are ok in THEN */
   rtx true_expr;               /* test for else block insns */
@@ -283,11 +321,20 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   if (! test_expr)
     return FALSE;
 
+  /* If the conditional jump is more than just a conditional jump,
+     then we can not do conditional execution conversion on this block.  */
+  if (!onlyjump_p (test_bb->end))
+    return FALSE;
+
   /* Collect the bounds of where we're to search.  */
 
   then_start = then_bb->head;
   then_end = then_bb->end;
 
+  /* Skip a label heading THEN block.  */
+  if (GET_CODE (then_start) == CODE_LABEL)
+    then_start = NEXT_INSN (then_start);
+
   /* Skip a (use (const_int 0)) or branch as the final insn.  */
   if (GET_CODE (then_end) == INSN
       && GET_CODE (PATTERN (then_end)) == USE
@@ -332,6 +379,17 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
                               GET_MODE (true_expr), XEXP (true_expr, 0),
                               XEXP (true_expr, 1));
 
+#ifdef IFCVT_MODIFY_TESTS
+  /* If the machine description needs to modify the tests, such as setting a
+     conditional execution register from a comparison, it can do so here.  */
+  IFCVT_MODIFY_TESTS (true_expr, false_expr, test_bb, then_bb, else_bb,
+                     join_bb);
+
+  /* See if the conversion failed */
+  if (!true_expr || !false_expr)
+    goto fail;
+#endif
+
   true_prob_val = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
   if (true_prob_val)
     {
@@ -361,6 +419,11 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   if (! apply_change_group ())
     return FALSE;
 
+#ifdef IFCVT_MODIFY_FINAL
+  /* Do any machine dependent final modifications */
+  IFCVT_MODIFY_FINAL (test_bb, then_bb, else_bb, join_bb);
+#endif
+
   /* Conversion succeeded.  */
   if (rtl_dump_file)
     fprintf (rtl_dump_file, "%d insn%s converted to conditional execution.\n",
@@ -371,6 +434,11 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   return TRUE;
 
  fail:
+#ifdef IFCVT_MODIFY_CANCEL
+  /* Cancel any machine dependent changes.  */
+  IFCVT_MODIFY_CANCEL (test_bb, then_bb, else_bb, join_bb);
+#endif
+
   cancel_changes (0);
   return FALSE;
 }
@@ -622,6 +690,10 @@ noce_try_store_flag_constants (if_info)
 
       seq = get_insns ();
       end_sequence ();
+
+      if (seq_contains_jump (seq))
+       return FALSE;
+
       emit_insns_before (seq, if_info->cond_earliest);
 
       return TRUE;
@@ -676,6 +748,10 @@ noce_try_store_flag_inc (if_info)
 
          seq = get_insns ();
          end_sequence ();
+
+         if (seq_contains_jump (seq))
+           return FALSE;
+
          emit_insns_before (seq, if_info->cond_earliest);
 
          return TRUE;
@@ -723,6 +799,10 @@ noce_try_store_flag_mask (if_info)
 
          seq = get_insns ();
          end_sequence ();
+
+         if (seq_contains_jump (seq))
+           return FALSE;
+
          emit_insns_before (seq, if_info->cond_earliest);
 
          return TRUE;
@@ -997,14 +1077,17 @@ noce_get_condition (jump, earliest)
      rtx *earliest;
 {
   rtx cond;
+  rtx set;
 
   /* If the condition variable is a register and is MODE_INT, accept it.
      Otherwise, fall back on get_condition.  */
 
-  if (! condjump_p (jump))
+  if (! any_condjump_p (jump))
     return NULL_RTX;
 
-  cond = XEXP (SET_SRC (PATTERN (jump)), 0);
+  set = pc_set (jump);
+
+  cond = XEXP (SET_SRC (set), 0);
   if (GET_CODE (XEXP (cond, 0)) == REG
       && GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_INT)
     {
@@ -1012,8 +1095,8 @@ noce_get_condition (jump, earliest)
 
       /* If this branches to JUMP_LABEL when the condition is false,
         reverse the condition.  */
-      if (GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 2)) == LABEL_REF
-         && XEXP (XEXP (SET_SRC (PATTERN (jump)), 2), 0) == JUMP_LABEL (jump))
+      if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
+         && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump))
        cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
                               GET_MODE (cond), XEXP (cond, 0),
                               XEXP (cond, 1));
@@ -1057,6 +1140,11 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
   if (! cond)
     return FALSE;
 
+  /* If the conditional jump is more than just a conditional jump,
+     then we can not do if-conversion on this block.  */
+  if (! onlyjump_p (jump))
+    return FALSE;
+
   /* We must be comparing objects whose modes imply the size.  */
   if (GET_MODE (XEXP (cond, 0)) == BLKmode)
     return FALSE;
@@ -1299,8 +1387,10 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
   /* The JOIN block may have had quite a number of other predecessors too.
      Since we've already merged the TEST, THEN and ELSE blocks, we should
      have only one remaining edge from our if-then-else diamond.  If there
-     is more than one remaining edge, it must come from elsewhere.  */
-  else if (join_bb->pred->pred_next == NULL)
+     is more than one remaining edge, it must come from elsewhere.  There
+     may be zero incoming edges if the THEN block didn't actually join 
+     back up (as with a call to abort).  */
+  else if (join_bb->pred == NULL || join_bb->pred->pred_next == NULL)
     {
       /* We can merge the JOIN.  */
       if (combo_bb->global_live_at_end)
@@ -1402,15 +1492,44 @@ find_if_block (test_bb, then_edge, else_edge)
   if (then_bb->pred->pred_next != NULL_EDGE)
     return FALSE;
 
-  /* The THEN block of an IF-THEN combo must have exactly one successor.  */
-  if (then_succ == NULL_EDGE
-      || then_succ->succ_next != NULL_EDGE
-      || (then_succ->flags & EDGE_COMPLEX))
+  /* The THEN block of an IF-THEN combo must have zero or one successors.  */
+  if (then_succ != NULL_EDGE
+      && (then_succ->succ_next != NULL_EDGE
+          || (then_succ->flags & EDGE_COMPLEX)))
     return FALSE;
 
+  /* If the THEN block has no successors, conditional execution can still
+     make a conditional call.  Don't do this unless the ELSE block has
+     only one incoming edge -- the CFG manipulation is too ugly otherwise.
+     Check for the last insn of the THEN block being an indirect jump, which
+     is listed as not having any successors, but confuses the rest of the CE
+     code processing.  XXX we should fix this in the future.  */
+  if (then_succ == NULL)
+    {
+      if (else_bb->pred->pred_next == NULL_EDGE)
+       {
+         rtx last_insn = then_bb->end;
+
+         while (last_insn
+                && GET_CODE (last_insn) == NOTE
+                && last_insn != then_bb->head)
+           last_insn = PREV_INSN (last_insn);
+
+         if (last_insn
+             && GET_CODE (last_insn) == JUMP_INSN
+             && ! simplejump_p (last_insn))
+           return FALSE;
+
+         join_bb = else_bb;
+         else_bb = NULL_BLOCK;
+       }
+      else
+       return FALSE;
+    }
+
   /* If the THEN block's successor is the other edge out of the TEST block,
      then we have an IF-THEN combo without an ELSE.  */
-  if (then_succ->dest == else_bb)
+  else if (then_succ->dest == else_bb)
     {
       join_bb = else_bb;
       else_bb = NULL_BLOCK;
@@ -1635,14 +1754,17 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   if (else_bb->pred->pred_next != NULL)
     return FALSE;
 
+  /* THEN is not EXIT.  */
+  if (then_bb->index < 0)
+    return FALSE;
+
   /* ELSE is predicted or SUCC(ELSE) postdominates THEN.  */
   note = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
   if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
     ;
   else if (else_succ->dest->index < 0
-          || (then_bb->index >= 0
-              && TEST_BIT (post_dominators[ORIG_INDEX (then_bb)], 
-                           ORIG_INDEX (else_succ->dest))))
+          || TEST_BIT (post_dominators[ORIG_INDEX (then_bb)], 
+                       ORIG_INDEX (else_succ->dest)))
     ;
   else
     return FALSE;
@@ -1756,6 +1878,9 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       end = PREV_INSN (end);
     }
 
+  /* Disable handling dead code by conditional execution if the machine needs
+     to do anything funny with the tests, etc.  */
+#ifndef IFCVT_MODIFY_TESTS
   if (HAVE_conditional_execution)
     {
       /* In the conditional execution case, we have things easy.  We know
@@ -1787,6 +1912,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       earliest = jump;
     }
   else
+#endif
     {
       /* In the non-conditional execution case, we have to verify that there
         are no trapping operations, no calls, no references to memory, and
@@ -1820,7 +1946,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
            break;
        }
 
-      if (! condjump_p (jump))
+      if (! any_condjump_p (jump))
        return FALSE;
 
       /* Find the extent of the conditional.  */
@@ -1990,7 +2116,8 @@ if_convert (life_data_ok)
        block_num++;
     }
 
-  sbitmap_vector_free (post_dominators);
+  if (post_dominators)
+    sbitmap_vector_free (post_dominators);
 
   if (rtl_dump_file)
     fflush (rtl_dump_file);
@@ -2016,8 +2143,11 @@ if_convert (life_data_ok)
          SET_BIT (update_life_blocks, block_num);
 
       count_or_remove_death_notes (update_life_blocks, 1);
-      update_life_info (update_life_blocks, UPDATE_LIFE_LOCAL,
-                       PROP_DEATH_NOTES);
+      /* ??? See about adding a mode that verifies that the initial
+       set of blocks don't let registers come live.  */
+      update_life_info (update_life_blocks, UPDATE_LIFE_GLOBAL,
+                       PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
+                       | PROP_KILL_DEAD_CODE);
 
       sbitmap_free (update_life_blocks);
     }