OSDN Git Service

Fix accidental commit
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index d892535..9df57bb 100644 (file)
@@ -1,5 +1,5 @@
 /* If-conversion support.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    This file is part of GCC.
@@ -43,6 +43,8 @@
 #include "target.h"
 #include "timevar.h"
 #include "tree-pass.h"
+#include "vec.h"
+#include "vecprim.h"
 
 
 #ifndef HAVE_conditional_execution
@@ -153,14 +155,16 @@ cheap_bb_rtx_cost_p (basic_block bb, int max_cost)
 
          /* If this instruction is the load or set of a "stack" register,
             such as a floating point register on x87, then the cost of
-            speculatively executing this instruction needs to include
-            the additional cost of popping this register off of the
-            register stack.  */
+            speculatively executing this insn may need to include
+            the additional cost of popping its result off of the
+            register stack.  Unfortunately, correctly recognizing and
+            accounting for this additional overhead is tricky, so for
+            now we simply prohibit such speculative execution.  */
 #ifdef STACK_REGS
          {
            rtx set = single_set (insn);
            if (set && STACK_REG_P (SET_DEST (set)))
-             cost += COSTS_N_INSNS (1);
+             return false;
          }
 #endif
 
@@ -170,7 +174,7 @@ cheap_bb_rtx_cost_p (basic_block bb, int max_cost)
        }
       else if (CALL_P (insn))
        return false;
+
       if (insn == BB_END (bb))
        break;
       insn = NEXT_INSN (insn);
@@ -594,12 +598,31 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
 
 struct noce_if_info
 {
+  /* A basic block that ends in a simple conditional jump.  */
   basic_block test_bb;
+
+  /* The jump that ends TEST_BB.  */
+  rtx jump;
+
+  /* The jump condition.  */
+  rtx cond;
+
+  /* New insns should be inserted before this one.  */
+  rtx cond_earliest;
+
+  /* Insns in the THEN and ELSE block.  There is always just this
+     one insns in those blocks.  The insns are single_set insns.
+     If there was no ELSE block, INSN_B is the last insn before
+     COND_EARLIEST, or NULL_RTX.  In the former case, the insn
+     operands are still valid, as if INSN_B was moved down below
+     the jump.  */
   rtx insn_a, insn_b;
-  rtx x, a, b;
-  rtx jump, cond, cond_earliest;
-  /* True if "b" was originally evaluated unconditionally.  */
-  bool b_unconditional;
+
+  /* The SET_SRC of INSN_A and INSN_B.  */
+  rtx a, b;
+
+  /* The SET_DEST of INSN_A.  */
+  rtx x;
 };
 
 static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
@@ -699,49 +722,78 @@ noce_emit_move_insn (rtx x, rtx y)
             ? emit_move_insn (x, y)
             : emit_insn (gen_rtx_SET (VOIDmode, x, y));
       seq = get_insns ();
-      end_sequence();
+      end_sequence ();
 
       if (recog_memoized (insn) <= 0)
-       switch (GET_RTX_CLASS (GET_CODE (y)))
-         {
-         case RTX_UNARY:
-           ot = code_to_optab[GET_CODE (y)];
-           if (ot)
-             {
-               start_sequence ();
-               target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
-               if (target != NULL_RTX)
-                 {
-                   if (target != x)
-                     emit_move_insn (x, target);
-                   seq = get_insns ();
-                 }
-               end_sequence ();
-             }
-           break;
+       {
+         if (GET_CODE (x) == ZERO_EXTRACT)
+           {
+             rtx op = XEXP (x, 0);
+             unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1));
+             unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2));
+
+             /* store_bit_field expects START to be relative to
+                BYTES_BIG_ENDIAN and adjusts this value for machines with
+                BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN.  In order to be able to
+                invoke store_bit_field again it is necessary to have the START
+                value from the first call.  */
+             if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
+               {
+                 if (MEM_P (op))
+                   start = BITS_PER_UNIT - start - size;
+                 else
+                   {
+                     gcc_assert (REG_P (op));
+                     start = BITS_PER_WORD - start - size;
+                   }
+               }
 
-         case RTX_BIN_ARITH:
-         case RTX_COMM_ARITH:
-           ot = code_to_optab[GET_CODE (y)];
-           if (ot)
-             {
-               start_sequence ();
-               target = expand_binop (GET_MODE (y), ot,
-                                      XEXP (y, 0), XEXP (y, 1),
-                                      x, 0, OPTAB_DIRECT);
-               if (target != NULL_RTX)
-                 {
-                   if (target != x)
-                     emit_move_insn (x, target);
-                   seq = get_insns ();
-                 }
-               end_sequence ();
-             }
-           break;
+             gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
+             store_bit_field (op, size, start, GET_MODE (x), y);
+             return;
+           }
 
-         default:
-           break;
-         }
+         switch (GET_RTX_CLASS (GET_CODE (y)))
+           {
+           case RTX_UNARY:
+             ot = code_to_optab[GET_CODE (y)];
+             if (ot)
+               {
+                 start_sequence ();
+                 target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
+                 if (target != NULL_RTX)
+                   {
+                     if (target != x)
+                       emit_move_insn (x, target);
+                     seq = get_insns ();
+                   }
+                 end_sequence ();
+               }
+             break;
+
+           case RTX_BIN_ARITH:
+           case RTX_COMM_ARITH:
+             ot = code_to_optab[GET_CODE (y)];
+             if (ot)
+               {
+                 start_sequence ();
+                 target = expand_binop (GET_MODE (y), ot,
+                                        XEXP (y, 0), XEXP (y, 1),
+                                        x, 0, OPTAB_DIRECT);
+                 if (target != NULL_RTX)
+                   {
+                     if (target != x)
+                         emit_move_insn (x, target);
+                     seq = get_insns ();
+                   }
+                 end_sequence ();
+               }
+             break;
+
+           default:
+             break;
+           }
+       }
 
       emit_insn (seq);
       return;
@@ -1298,16 +1350,15 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
        return FALSE;
     }
   else
+    insn_cost = 0;
+
+  if (insn_b)
     {
-      insn_cost = 0;
+      insn_cost += insn_rtx_cost (PATTERN (insn_b));
+      if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
+        return FALSE;
     }
 
-  if (insn_b) {
-    insn_cost += insn_rtx_cost (PATTERN (insn_b));
-    if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
-      return FALSE;
-  }
-
   /* Possibly rearrange operands to make things come out more natural.  */
   if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
     {
@@ -1815,6 +1866,7 @@ noce_try_sign_mask (struct noce_if_info *if_info)
   rtx cond, t, m, c, seq;
   enum machine_mode mode;
   enum rtx_code code;
+  bool b_unconditional;
 
   if (no_new_pseudos)
     return FALSE;
@@ -1847,9 +1899,13 @@ noce_try_sign_mask (struct noce_if_info *if_info)
     return FALSE;
 
   /* This is only profitable if T is cheap, or T is unconditionally
-     executed/evaluated in the original insn sequence.  */
+     executed/evaluated in the original insn sequence.  The latter
+     happens if INSN_B was taken from TEST_BB, or if there was no
+     INSN_B which can happen for e.g. conditional stores to memory.  */
+  b_unconditional = (if_info->insn_b == NULL_RTX
+                    || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb);
   if (rtx_cost (t, SET) >= COSTS_N_INSNS (2)
-      && (!if_info->b_unconditional
+      && (!b_unconditional
           || t != if_info->b))
     return FALSE;
 
@@ -1913,7 +1969,9 @@ noce_try_bitop (struct noce_if_info *if_info)
        return FALSE;
       bitnum = INTVAL (XEXP (cond, 2));
       mode = GET_MODE (x);
-      if (bitnum >= HOST_BITS_PER_WIDE_INT)
+      if (BITS_BIG_ENDIAN)
+       bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
+      if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
        return FALSE;
     }
   else
@@ -2016,6 +2074,52 @@ noce_get_condition (rtx jump, rtx *earliest)
                                 NULL_RTX, false, true);
 }
 
+/* Initialize for a simple IF-THEN or IF-THEN-ELSE block.  We will not
+   be using conditional execution.  Set some fields of IF_INFO based
+   on CE_INFO: test_bb, cond, jump, cond_earliest.  Return TRUE if
+   things look OK.  */
+
+static int
+noce_init_if_info (struct ce_if_block *ce_info, struct noce_if_info *if_info)
+{
+  basic_block test_bb = ce_info->test_bb;
+  rtx cond, jump;
+
+  /* If test is comprised of && or || elements, don't handle it unless
+     it is the special case of && elements without an ELSE block.  */
+  if (ce_info->num_multiple_test_blocks)
+    {
+      if (ce_info->else_bb || !ce_info->and_and_p)
+       return FALSE;
+
+      ce_info->test_bb = test_bb = ce_info->last_test_bb;
+      ce_info->num_multiple_test_blocks = 0;
+      ce_info->num_and_and_blocks = 0;
+      ce_info->num_or_or_blocks = 0;
+    }
+
+  /* If this is not a standard conditional jump, we can't parse it.  */
+  jump = BB_END (test_bb);
+  cond = noce_get_condition (jump, &if_info->cond_earliest);
+  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;
+
+  if_info->test_bb = test_bb;
+  if_info->cond = cond;
+  if_info->jump = jump;
+
+  return TRUE;
+}
+
 /* Return true if OP is ok for if-then-else processing.  */
 
 static int
@@ -2095,6 +2199,7 @@ noce_process_if_block (struct ce_if_block * ce_info)
   basic_block test_bb = ce_info->test_bb;      /* test block */
   basic_block then_bb = ce_info->then_bb;      /* THEN */
   basic_block else_bb = ce_info->else_bb;      /* ELSE or NULL */
+  basic_block join_bb;
   struct noce_if_info if_info;
   rtx insn_a, insn_b;
   rtx set_a, set_b;
@@ -2111,33 +2216,11 @@ noce_process_if_block (struct ce_if_block * ce_info)
 
      ??? For future expansion, look for multiple X in such patterns.  */
 
-  /* If test is comprised of && or || elements, don't handle it unless it is
-     the special case of && elements without an ELSE block.  */
-  if (ce_info->num_multiple_test_blocks)
-    {
-      if (else_bb || ! ce_info->and_and_p)
-       return FALSE;
-
-      ce_info->test_bb = test_bb = ce_info->last_test_bb;
-      ce_info->num_multiple_test_blocks = 0;
-      ce_info->num_and_and_blocks = 0;
-      ce_info->num_or_or_blocks = 0;
-    }
-
-  /* If this is not a standard conditional jump, we can't parse it.  */
-  jump = BB_END (test_bb);
-  cond = noce_get_condition (jump, &if_info.cond_earliest);
-  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))
+  if (!noce_init_if_info (ce_info, &if_info))
     return FALSE;
 
-  /* We must be comparing objects whose modes imply the size.  */
-  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
-    return FALSE;
+  cond = if_info.cond;
+  jump = if_info.jump;
 
   /* Look for one of the potential sets.  */
   insn_a = first_active_insn (then_bb);
@@ -2207,6 +2290,12 @@ noce_process_if_block (struct ce_if_block * ce_info)
     {
       if (no_new_pseudos || GET_MODE (x) == BLKmode)
        return FALSE;
+
+      if (GET_MODE (x) == ZERO_EXTRACT
+         && (GET_CODE (XEXP (x, 1)) != CONST_INT
+             || GET_CODE (XEXP (x, 2)) != CONST_INT))
+       return FALSE;
+
       x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
                                 ? XEXP (x, 0) : x));
     }
@@ -2216,15 +2305,11 @@ noce_process_if_block (struct ce_if_block * ce_info)
     return FALSE;
 
   /* Set up the info block for our subroutines.  */
-  if_info.test_bb = test_bb;
-  if_info.cond = cond;
-  if_info.jump = jump;
   if_info.insn_a = insn_a;
   if_info.insn_b = insn_b;
   if_info.x = x;
   if_info.a = a;
   if_info.b = b;
-  if_info.b_unconditional = else_bb == 0;
 
   /* Try optimizations in some approximation of a useful order.  */
   /* ??? Should first look to see if X is live incoming at all.  If it
@@ -2305,41 +2390,320 @@ noce_process_if_block (struct ce_if_block * ce_info)
   return FALSE;
 
  success:
-  /* The original sets may now be killed.  */
-  delete_insn (insn_a);
-
-  /* Several special cases here: First, we may have reused insn_b above,
-     in which case insn_b is now NULL.  Second, we want to delete insn_b
-     if it came from the ELSE block, because follows the now correct
-     write that appears in the TEST block.  However, if we got insn_b from
-     the TEST block, it may in fact be loading data needed for the comparison.
-     We'll let life_analysis remove the insn if it's really dead.  */
-  if (insn_b && else_bb)
-    delete_insn (insn_b);
-
-  /* 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.  */
   if (orig_x != x)
     {
+      rtx seq;
+
       start_sequence ();
       noce_emit_move_insn (orig_x, x);
-      insn_b = get_insns ();
+      seq = get_insns ();
       set_used_flags (orig_x);
-      unshare_all_rtl_in_chain (insn_b);
+      unshare_all_rtl_in_chain (seq);
       end_sequence ();
 
-      emit_insn_after_setloc (insn_b, BB_END (test_bb), INSN_LOCATOR (insn_a));
+      emit_insn_before_setloc (seq, BB_END (test_bb), INSN_LOCATOR (insn_a));
     }
 
-  /* Merge the blocks!  */
-  merge_if_block (ce_info);
+  /* The original THEN and ELSE blocks may now be removed.  The test block
+     must now jump to the join block.  If the test block and the join block
+     can be merged, do so.  */
+
+  join_bb = single_succ (then_bb);
+  if (else_bb)
+    {
+      delete_basic_block (else_bb);
+      num_true_changes++;
+    }
+  else
+    remove_edge (find_edge (test_bb, join_bb));
 
+  remove_edge (find_edge (then_bb, join_bb));
+  redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb);
+  delete_basic_block (then_bb);
+  num_true_changes++;
+
+  if (can_merge_blocks_p (test_bb, join_bb))
+    {
+      merge_blocks (test_bb, join_bb);
+      num_true_changes++;
+    }
+
+  num_updated_if_blocks++;
   return TRUE;
 }
+
+/* Check whether a block is suitable for conditional move conversion.
+   Every insn must be a simple set of a register to a constant or a
+   register.  For each assignment, store the value in the array VALS,
+   indexed by register number, then store the register number in
+   REGS.  COND is the condition we will test.  */
+
+static int
+check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) *regs, rtx cond)
+{
+  rtx insn;
+
+   /* We can only handle simple jumps at the end of the basic block.
+      It is almost impossible to update the CFG otherwise.  */
+  insn = BB_END (bb);
+  if (JUMP_P (insn) && !onlyjump_p (insn))
+    return FALSE;
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      rtx set, dest, src;
+
+      if (!INSN_P (insn) || JUMP_P (insn))
+       continue;
+      set = single_set (insn);
+      if (!set)
+       return FALSE;
+
+      dest = SET_DEST (set);
+      src = SET_SRC (set);
+      if (!REG_P (dest)
+         || (SMALL_REGISTER_CLASSES && HARD_REGISTER_P (dest)))
+       return FALSE;
+
+      if (!CONSTANT_P (src) && !register_operand (src, VOIDmode))
+       return FALSE;
+
+      if (side_effects_p (src) || side_effects_p (dest))
+       return FALSE;
+
+      if (may_trap_p (src) || may_trap_p (dest))
+       return FALSE;
+
+      /* Don't try to handle this if the source register was
+        modified earlier in the block.  */
+      if ((REG_P (src)
+          && vals[REGNO (src)] != NULL)
+         || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
+             && vals[REGNO (SUBREG_REG (src))] != NULL))
+       return FALSE;
+
+      /* Don't try to handle this if the destination register was
+        modified earlier in the block.  */
+      if (vals[REGNO (dest)] != NULL)
+       return FALSE;
+
+      /* Don't try to handle this if the condition uses the
+        destination register.  */
+      if (reg_overlap_mentioned_p (dest, cond))
+       return FALSE;
+
+      /* Don't try to handle this if the source register is modified
+        later in the block.  */
+      if (!CONSTANT_P (src)
+         && modified_between_p (src, insn, NEXT_INSN (BB_END (bb))))
+       return FALSE;
+
+      vals[REGNO (dest)] = src;
+
+      VEC_safe_push (int, heap, regs, REGNO (dest));
+    }
+
+  return TRUE;
+}
+
+/* Given a basic block BB suitable for conditional move conversion,
+   a condition COND, and arrays THEN_VALS and ELSE_VALS containing the
+   register values depending on COND, emit the insns in the block as
+   conditional moves.  If ELSE_BLOCK is true, THEN_BB was already
+   processed.  The caller has started a sequence for the conversion.
+   Return true if successful, false if something goes wrong.  */
+
+static bool
+cond_move_convert_if_block (struct noce_if_info *if_infop,
+                           basic_block bb, rtx cond,
+                           rtx *then_vals, rtx *else_vals,
+                           bool else_block_p)
+{
+  enum rtx_code code;
+  rtx insn, cond_arg0, cond_arg1;
+
+  code = GET_CODE (cond);
+  cond_arg0 = XEXP (cond, 0);
+  cond_arg1 = XEXP (cond, 1);
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      rtx set, target, dest, t, e;
+      unsigned int regno;
+
+      if (!INSN_P (insn) || JUMP_P (insn))
+       continue;
+      set = single_set (insn);
+      gcc_assert (set && REG_P (SET_DEST (set)));
+
+      dest = SET_DEST (set);
+      regno = REGNO (dest);
+
+      t = then_vals[regno];
+      e = else_vals[regno];
+
+      if (else_block_p)
+       {
+         /* If this register was set in the then block, we already
+            handled this case there.  */
+         if (t)
+           continue;
+         t = dest;
+         gcc_assert (e);
+       }
+      else
+       {
+         gcc_assert (t);
+         if (!e)
+           e = dest;
+       }
+
+      target = noce_emit_cmove (if_infop, dest, code, cond_arg0, cond_arg1,
+                               t, e);
+      if (!target)
+       return false;
+
+      if (target != dest)
+       noce_emit_move_insn (dest, target);
+    }
+
+  return true;
+}
+
+/* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
+   using only conditional moves.  Return TRUE if we were successful at
+   converting the block.  */
+
+static int
+cond_move_process_if_block (struct ce_if_block *ce_info)
+{
+  basic_block test_bb = ce_info->test_bb;
+  basic_block then_bb = ce_info->then_bb;
+  basic_block else_bb = ce_info->else_bb;
+  basic_block join_bb;
+  struct noce_if_info if_info;
+  rtx jump, cond, seq, loc_insn;
+  int max_reg, size, c, reg;
+  rtx *then_vals;
+  rtx *else_vals;
+  VEC (int, heap) *then_regs = NULL;
+  VEC (int, heap) *else_regs = NULL;
+  unsigned int i;
+
+  if (!HAVE_conditional_move || no_new_pseudos)
+    return FALSE;
+
+  memset (&if_info, 0, sizeof if_info);
+
+  if (!noce_init_if_info (ce_info, &if_info))
+    return FALSE;
+
+  cond = if_info.cond;
+  jump = if_info.jump;
+
+  /* Build a mapping for each block to the value used for each
+     register.  */
+  max_reg = max_reg_num ();
+  size = (max_reg + 1) * sizeof (rtx);
+  then_vals = (rtx *) alloca (size);
+  else_vals = (rtx *) alloca (size);
+  memset (then_vals, 0, size);
+  memset (else_vals, 0, size);
+
+  /* Make sure the blocks are suitable.  */
+  if (!check_cond_move_block (then_bb, then_vals, then_regs, cond)
+      || (else_bb && !check_cond_move_block (else_bb, else_vals, else_regs, cond)))
+    return FALSE;
+
+  /* Make sure the blocks can be used together.  If the same register
+     is set in both blocks, and is not set to a constant in both
+     cases, then both blocks must set it to the same register.  We
+     have already verified that if it is set to a register, that the
+     source register does not change after the assignment.  Also count
+     the number of registers set in only one of the blocks.  */
+  c = 0;
+  for (i = 0; VEC_iterate (int, then_regs, i, reg); i++)
+    {
+      if (!then_vals[reg] && !else_vals[reg])
+       continue;
+
+      if (!else_vals[reg])
+       ++c;
+      else
+       {
+         if (!CONSTANT_P (then_vals[reg])
+             && !CONSTANT_P (else_vals[reg])
+             && !rtx_equal_p (then_vals[reg], else_vals[reg]))
+           return FALSE;
+       }
+    }
+
+  /* Finish off c for MAX_CONDITIONAL_EXECUTE.  */
+  for (i = 0; VEC_iterate (int, else_regs, i, reg); ++i)
+    if (!then_vals[reg])
+      ++c;
+
+  /* Make sure it is reasonable to convert this block.  What matters
+     is the number of assignments currently made in only one of the
+     branches, since if we convert we are going to always execute
+     them.  */
+  if (c > MAX_CONDITIONAL_EXECUTE)
+    return FALSE;
+
+  /* Try to emit the conditional moves.  First do the then block,
+     then do anything left in the else blocks.  */
+  start_sequence ();
+  if (!cond_move_convert_if_block (&if_info, then_bb, cond,
+                                  then_vals, else_vals, false)
+      || (else_bb
+         && !cond_move_convert_if_block (&if_info, else_bb, cond,
+                                         then_vals, else_vals, true)))
+    {
+      end_sequence ();
+      return FALSE;
+    }
+  seq = end_ifcvt_sequence (&if_info);
+  if (!seq)
+    return FALSE;
+
+  loc_insn = first_active_insn (then_bb);
+  if (!loc_insn)
+    {
+      loc_insn = first_active_insn (else_bb);
+      gcc_assert (loc_insn);
+    }
+  emit_insn_before_setloc (seq, jump, INSN_LOCATOR (loc_insn));
+
+  join_bb = single_succ (then_bb);
+  if (else_bb)
+    {
+      delete_basic_block (else_bb);
+      num_true_changes++;
+    }
+  else
+    remove_edge (find_edge (test_bb, join_bb));
+
+  remove_edge (find_edge (then_bb, join_bb));
+  redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb);
+  delete_basic_block (then_bb);
+  num_true_changes++;
+
+  if (can_merge_blocks_p (test_bb, join_bb))
+    {
+      merge_blocks (test_bb, join_bb);
+      num_true_changes++;
+    }
+
+  num_updated_if_blocks++;
+
+  VEC_free (int, heap, then_regs);
+  VEC_free (int, heap, else_regs);
+
+  return TRUE;
+}
+
 \f
 /* Attempt to convert an IF-THEN or IF-THEN-ELSE block into
    straight line code.  Return true if successful.  */
@@ -2351,6 +2715,10 @@ process_if_block (struct ce_if_block * ce_info)
       && noce_process_if_block (ce_info))
     return TRUE;
 
+  if (HAVE_conditional_move
+      && cond_move_process_if_block (ce_info))
+    return TRUE;
+
   if (HAVE_conditional_execution && reload_completed)
     {
       /* If we have && and || tests, try to first handle combining the && and
@@ -2411,9 +2779,6 @@ merge_if_block (struct ce_if_block * ce_info)
 
   if (then_bb)
     {
-      if (combo_bb->il.rtl->global_live_at_end)
-       COPY_REG_SET (combo_bb->il.rtl->global_live_at_end,
-                     then_bb->il.rtl->global_live_at_end);
       merge_blocks (combo_bb, then_bb);
       num_true_changes++;
     }
@@ -2464,10 +2829,6 @@ merge_if_block (struct ce_if_block * ce_info)
           && join_bb != EXIT_BLOCK_PTR)
     {
       /* We can merge the JOIN.  */
-      if (combo_bb->il.rtl->global_live_at_end)
-       COPY_REG_SET (combo_bb->il.rtl->global_live_at_end,
-                     join_bb->il.rtl->global_live_at_end);
-
       merge_blocks (combo_bb, join_bb);
       num_true_changes++;
     }
@@ -2712,7 +3073,7 @@ find_if_block (struct ce_if_block * ce_info)
      other than any || blocks which jump to the THEN block.  */
   if ((EDGE_COUNT (then_bb->preds) - ce_info->num_or_or_blocks) != 1)
     return FALSE;
-    
+
   /* The edges of the THEN and ELSE blocks cannot have complex edges.  */
   FOR_EACH_EDGE (cur_edge, ei, then_bb->preds)
     {
@@ -2905,29 +3266,20 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
   if (seq == NULL)
     return FALSE;
 
-  num_true_changes++;
-
   /* Emit the new insns before cond_earliest.  */
   emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATOR (trap));
 
   /* Delete the trap block if possible.  */
   remove_edge (trap_bb == then_bb ? then_edge : else_edge);
   if (EDGE_COUNT (trap_bb->preds) == 0)
-    delete_basic_block (trap_bb);
-
-  /* If the non-trap block and the test are now adjacent, merge them.
-     Otherwise we must insert a direct branch.  */
-  if (test_bb->next_bb == other_bb)
     {
-      struct ce_if_block new_ce_info;
-      delete_insn (jump);
-      memset (&new_ce_info, '\0', sizeof (new_ce_info));
-      new_ce_info.test_bb = test_bb;
-      new_ce_info.then_bb = NULL;
-      new_ce_info.else_bb = NULL;
-      new_ce_info.join_bb = other_bb;
-      merge_if_block (&new_ce_info);
+      delete_basic_block (trap_bb);
+      num_true_changes++;
     }
+
+  /* Wire together the blocks again.  */
+  if (current_ir_type () == IR_RTL_CFGLAYOUT)
+    single_succ_edge (test_bb)->flags |= EDGE_FALLTHRU;
   else
     {
       rtx lab, newjump;
@@ -2937,10 +3289,16 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
       LABEL_NUSES (lab) += 1;
       JUMP_LABEL (newjump) = lab;
       emit_barrier_after (newjump);
+    }
+  delete_insn (jump);
 
-      delete_insn (jump);
+  if (can_merge_blocks_p (test_bb, other_bb))
+    {
+      merge_blocks (test_bb, other_bb);
+      num_true_changes++;
     }
 
+  num_updated_if_blocks++;
   return TRUE;
 }
 
@@ -3057,19 +3415,19 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
   /* If we are partitioning hot/cold basic blocks, we don't want to
      mess up unconditional or indirect jumps that cross between hot
      and cold sections.
-  
+
      Basic block partitioning may result in some jumps that appear to
-     be optimizable (or blocks that appear to be mergeable), but which really 
-     must be left untouched (they are required to make it safely across 
-     partition boundaries).  See  the comments at the top of 
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See  the comments at the top of
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if ((BB_END (then_bb) 
+  if ((BB_END (then_bb)
        && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
       || (BB_END (test_bb)
          && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
       || (BB_END (else_bb)
-         && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP, 
+         && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
                            NULL_RTX)))
     return FALSE;
 
@@ -3135,7 +3493,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
   if (new_bb)
     {
       new_bb->index = then_bb_index;
-      BASIC_BLOCK (then_bb_index) = new_bb;
+      SET_BASIC_BLOCK (then_bb_index, new_bb);
       /* Since the fallthru edge was redirected from test_bb to new_bb,
          we need to ensure that new_bb is in the same partition as
          test bb (you can not fall through across section boundaries).  */
@@ -3163,19 +3521,19 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
   /* If we are partitioning hot/cold basic blocks, we don't want to
      mess up unconditional or indirect jumps that cross between hot
      and cold sections.
-  
+
      Basic block partitioning may result in some jumps that appear to
-     be optimizable (or blocks that appear to be mergeable), but which really 
-     must be left untouched (they are required to make it safely across 
-     partition boundaries).  See  the comments at the top of 
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See  the comments at the top of
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
   if ((BB_END (then_bb)
        && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
       || (BB_END (test_bb)
          && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
-      || (BB_END (else_bb) 
-         && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP, 
+      || (BB_END (else_bb)
+         && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
                            NULL_RTX)))
     return FALSE;
 
@@ -3269,6 +3627,13 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
   head = BB_HEAD (merge_bb);
   end = BB_END (merge_bb);
 
+  /* If merge_bb ends with a tablejump, predicating/moving insn's
+     into test_bb and then deleting merge_bb will result in the jumptable
+     that follows merge_bb being removed along with merge_bb and then we
+     get an unresolved reference to the jumptable.  */
+  if (tablejump_p (end, NULL, NULL))
+    return FALSE;
+
   if (LABEL_P (head))
     head = NEXT_INSN (head);
   if (NOTE_P (head))
@@ -3466,7 +3831,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
 
   if (other_bb != new_dest)
     {
-      redirect_jump_2 (jump, old_dest, new_label, -1, reversep);
+      redirect_jump_2 (jump, old_dest, new_label, 0, reversep);
 
       redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
       if (reversep)
@@ -3532,7 +3897,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
 \f
 /* Main entry point for all if-conversion.  */
 
-void
+static void
 if_convert (int x_life_data_ok)
 {
   basic_block bb;
@@ -3543,17 +3908,13 @@ if_convert (int x_life_data_ok)
   num_true_changes = 0;
   life_data_ok = (x_life_data_ok != 0);
 
-  if ((! targetm.cannot_modify_jumps_p ())
-      && (!flag_reorder_blocks_and_partition || !no_new_pseudos
-         || !targetm.have_named_sections))
+  loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+  if (current_loops)
     {
-      struct loops loops;
-
-      flow_loops_find (&loops);
-      mark_loop_exit_edges (&loops);
-      flow_loops_free (&loops);
-      free_dominance_info (CDI_DOMINATORS);
+      mark_loop_exit_edges ();
+      loop_optimizer_finalize ();
     }
+  free_dominance_info (CDI_DOMINATORS);
 
   /* Compute postdominators if we think we'll use them.  */
   if (HAVE_conditional_execution || life_data_ok)
@@ -3642,13 +4003,13 @@ gate_handle_if_conversion (void)
 }
 
 /* If-conversion and CFG cleanup.  */
-static void
+static unsigned int
 rest_of_handle_if_conversion (void)
 {
   if (flag_if_conversion)
     {
       if (dump_file)
-        dump_flow_info (dump_file);
+        dump_flow_info (dump_file, dump_flags);
       cleanup_cfg (CLEANUP_EXPENSIVE);
       reg_scan (get_insns (), max_reg_num ());
       if_convert (0);
@@ -3658,6 +4019,7 @@ rest_of_handle_if_conversion (void)
   cleanup_cfg (CLEANUP_EXPENSIVE);
   reg_scan (get_insns (), max_reg_num ());
   timevar_pop (TV_JUMP);
+  return 0;
 }
 
 struct tree_opt_pass pass_rtl_ifcvt =
@@ -3686,12 +4048,13 @@ gate_handle_if_after_combine (void)
 
 /* Rerun if-conversion, as combine may have simplified things enough
    to now meet sequence length restrictions.  */
-static void
+static unsigned int
 rest_of_handle_if_after_combine (void)
 {
   no_new_pseudos = 0;
   if_convert (1);
   no_new_pseudos = 1;
+  return 0;
 }
 
 struct tree_opt_pass pass_if_after_combine =
@@ -3719,7 +4082,7 @@ gate_handle_if_after_reload (void)
   return (optimize > 0);
 }
 
-static void
+static unsigned int
 rest_of_handle_if_after_reload (void)
 {
   /* Last attempt to optimize CFG, as scheduling, peepholing and insn
@@ -3729,6 +4092,7 @@ rest_of_handle_if_after_reload (void)
                | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
   if (flag_if_conversion2)
     if_convert (1);
+  return 0;
 }
 
 
@@ -3749,5 +4113,3 @@ struct tree_opt_pass pass_if_after_reload =
   TODO_ggc_collect,                     /* todo_flags_finish */
   'E'                                   /* letter */
 };
-
-