OSDN Git Service

Amend last change: add %, in front of Ldi%=:
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index 79be885..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,8 +71,9 @@ 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, int));
+static int cond_exec_process_insns     PARAMS ((rtx, rtx, rtx, rtx, int));
 static rtx cond_exec_get_condition     PARAMS ((rtx));
 static int cond_exec_process_if_block  PARAMS ((basic_block, basic_block,
                                                 basic_block, basic_block));
@@ -173,20 +172,40 @@ 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
    insns were processed.  */
 
 static int
-cond_exec_process_insns (start, end, test, mod_ok)
+cond_exec_process_insns (start, end, test, prob_val, mod_ok)
      rtx start;                        /* first insn to look at */
      rtx end;                  /* last insn to look at */
      rtx test;                 /* conditional execution test */
+     rtx prob_val;             /* probability of branch taken.  */
      int mod_ok;               /* true if modifications ok last insn.  */
 {
   int must_be_last = FALSE;
   rtx insn;
+  rtx pattern;
 
   for (insn = start; ; insn = NEXT_INSN (insn))
     {
@@ -196,6 +215,17 @@ cond_exec_process_insns (start, end, test, 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;
@@ -208,9 +238,25 @@ cond_exec_process_insns (start, end, test, 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),
+                        alloc_EXPR_LIST (REG_BR_PROB, prob_val,
+                                         REG_NOTES (insn)), 1);
 
     insn_done:
       if (insn == end)
@@ -228,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);
@@ -261,12 +305,14 @@ 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 */
   rtx false_expr;              /* test for then block insns */
+  rtx true_prob_val;           /* probability of else block */
+  rtx false_prob_val;          /* probability of then block */
   int n_insns;
 
   /* Find the conditional jump to the ELSE or JOIN part, and isolate
@@ -275,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
@@ -324,6 +379,26 @@ 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)
+    {
+      true_prob_val = XEXP (true_prob_val, 0);
+      false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
+    }
+  else
+    false_prob_val = NULL_RTX;
+
   /* For IF-THEN-ELSE blocks, we don't allow modifications of the test
      on then THEN block.  */
   then_mod_ok = (else_bb == NULL_BLOCK);
@@ -333,17 +408,22 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
 
   if (then_end
       && ! cond_exec_process_insns (then_start, then_end,
-                                   false_expr, then_mod_ok))
+                                   false_expr, false_prob_val, then_mod_ok))
     goto fail;
 
   if (else_bb
       && ! cond_exec_process_insns (else_start, else_end,
-                                   true_expr, TRUE))
+                                   true_expr, true_prob_val, TRUE))
     goto fail;
 
   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",
@@ -354,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;
 }
@@ -605,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;
@@ -659,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;
@@ -706,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;
@@ -980,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)
     {
@@ -995,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));
@@ -1040,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;
@@ -1078,7 +1183,9 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
          || GET_CODE (insn_b) != INSN
          || (set_b = single_set (insn_b)) == NULL_RTX
          || ! rtx_equal_p (x, SET_DEST (set_b))
-         || reg_mentioned_p (x, cond))
+         || reg_mentioned_p (x, cond)
+         || reg_mentioned_p (x, a)
+         || reg_mentioned_p (x, SET_SRC (set_b)))
        insn_b = set_b = NULL_RTX;
     }
   b = (set_b ? SET_SRC (set_b) : x);
@@ -1139,8 +1246,8 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
            else_bb->end = PREV_INSN (insn_b);
          reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
          insn_b = NULL_RTX;
-         x = orig_x;
        }
+      x = orig_x;
       goto success;
     }
 
@@ -1256,37 +1363,8 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
      get their addresses taken.  */
   if (else_bb)
     {
-      if (LABEL_NUSES (else_bb->head) == 0
-         && ! LABEL_PRESERVE_P (else_bb->head)
-         && ! LABEL_NAME (else_bb->head))
-       {
-         /* We can merge the ELSE.  */
-         merge_blocks_nomove (combo_bb, else_bb);
-         num_removed_blocks++;
-       }
-      else
-       {
-         /* We cannot merge the ELSE.  */
-
-         /* Properly rewire the edge out of the now combined
-            TEST-THEN block to point here.  */
-         remove_edge (combo_bb->succ);
-         if (combo_bb->succ || else_bb->pred)
-           abort ();
-         make_edge (NULL, combo_bb, else_bb, EDGE_FALLTHRU);
-
-         /* Remove the jump and cruft from the end of the TEST-THEN block.  */
-         tidy_fallthru_edge (combo_bb->succ, combo_bb, else_bb);
-
-         /* Make sure we update life info properly.  */
-         SET_UPDATE_LIFE(combo_bb);
-         if (else_bb->global_live_at_end)
-           COPY_REG_SET (else_bb->global_live_at_start,
-                         else_bb->global_live_at_end);
-
-         /* The ELSE is the new combo block.  */
-         combo_bb = else_bb;
-       }
+      merge_blocks_nomove (combo_bb, else_bb);
+      num_removed_blocks++;
     }
 
   /* If there was no join block reported, that means it was not adjacent
@@ -1306,12 +1384,13 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
        abort ();
     }
 
-  /* The JOIN block had a label.  It may have had quite a number
-     of other predecessors too, but probably not.  See if we can
-     merge this with the others.  */
-  else if (LABEL_NUSES (join_bb->head) == 0
-      && ! LABEL_PRESERVE_P (join_bb->head)
-      && ! LABEL_NAME (join_bb->head))
+  /* 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.  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)
@@ -1413,20 +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;
 
-  /* The THEN block may not start with a label, as might happen with an
-     unused user label that has had its address taken.  */
-  if (GET_CODE (then_bb->head) == CODE_LABEL)
-    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;
@@ -1581,10 +1684,6 @@ find_if_case_1 (test_bb, then_edge, else_edge)
   if (then_bb->pred->pred_next != NULL)
     return FALSE;
 
-  /* THEN has no label.  */
-  if (GET_CODE (then_bb->head) == CODE_LABEL)
-    return FALSE;
-
   /* ELSE follows THEN.  (??? could be moved)  */
   if (else_bb->index != then_bb->index + 1)
     return FALSE;
@@ -1655,10 +1754,8 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   if (else_bb->pred->pred_next != NULL)
     return FALSE;
 
-  /* ELSE has a label we can delete.  */
-  if (LABEL_NUSES (else_bb->head) > 1
-      || LABEL_PRESERVE_P (else_bb->head)
-      || LABEL_NAME (else_bb->head))
+  /* THEN is not EXIT.  */
+  if (then_bb->index < 0)
     return FALSE;
 
   /* ELSE is predicted or SUCC(ELSE) postdominates THEN.  */
@@ -1666,9 +1763,8 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   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;
@@ -1782,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
@@ -1790,20 +1889,30 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
         All that's left is making sure the insns involved can actually
         be predicated.  */
 
-      rtx cond;
+      rtx cond, prob_val;
 
       cond = cond_exec_get_condition (jump);
+
+      prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
+      if (prob_val)
+       prob_val = XEXP (prob_val, 0);
+
       if (reversep)
-       cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                              GET_MODE (cond), XEXP (cond, 0),
-                              XEXP (cond, 1));
+       {
+         cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
+                                GET_MODE (cond), XEXP (cond, 0),
+                                XEXP (cond, 1));
+         if (prob_val)
+           prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
+       }
 
-      if (! cond_exec_process_insns (head, end, cond, 0))
+      if (! cond_exec_process_insns (head, end, cond, prob_val, 0))
        goto cancel;
 
       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
@@ -1837,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.  */
@@ -2007,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);
@@ -2033,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);
     }