OSDN Git Service

2006-02-15 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index 72bb393..5d156a6 100644 (file)
@@ -1,5 +1,6 @@
 /* If-conversion support.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -15,8 +16,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -40,6 +41,8 @@
 #include "tm_p.h"
 #include "cfgloop.h"
 #include "target.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 
 #ifndef HAVE_conditional_execution
@@ -65,7 +68,6 @@
 #define MAX_CONDITIONAL_EXECUTE   (BRANCH_COST + 1)
 #endif
 
-#define NULL_EDGE      ((edge) NULL)
 #define NULL_BLOCK     ((basic_block) NULL)
 
 /* # of IF-THEN or IF-THEN-ELSE blocks we looked at  */
@@ -86,7 +88,7 @@ static bool life_data_ok;
 
 /* Forward references.  */
 static int count_bb_insns (basic_block);
-static int total_bb_rtx_cost (basic_block);
+static bool cheap_bb_rtx_cost_p (basic_block, int);
 static rtx first_active_insn (basic_block);
 static rtx last_active_insn (basic_block, int);
 static basic_block block_fallthru (basic_block);
@@ -109,38 +111,7 @@ static int dead_or_predicable (basic_block, basic_block, basic_block,
                               basic_block, int);
 static void noce_emit_move_insn (rtx, rtx);
 static rtx block_has_only_trap (basic_block);
-static void mark_loop_exit_edges (void);
 \f
-/* Sets EDGE_LOOP_EXIT flag for all loop exits.  */
-static void
-mark_loop_exit_edges (void)
-{
-  struct loops loops;
-  basic_block bb;
-  edge e;
-  
-  flow_loops_find (&loops, LOOP_TREE);
-  free_dominance_info (CDI_DOMINATORS);
-  
-  if (loops.num > 1)
-    {
-      FOR_EACH_BB (bb)
-       {
-         edge_iterator ei;
-         FOR_EACH_EDGE (e, ei, bb->succs)
-           {
-             if (find_common_loop (bb->loop_father, e->dest->loop_father)
-                 != bb->loop_father)
-               e->flags |= EDGE_LOOP_EXIT;
-             else
-               e->flags &= ~EDGE_LOOP_EXIT;
-           }
-       }
-    }
-
-  flow_loops_free (&loops);
-}
-
 /* Count the number of non-jump active insns in BB.  */
 
 static int
@@ -162,12 +133,12 @@ count_bb_insns (basic_block bb)
   return count;
 }
 
-/* Count the total insn_rtx_cost of non-jump active insns in BB.
-   This function returns -1, if the cost of any instruction could
-   not be estimated.  */
+/* Determine whether the total insn_rtx_cost on non-jump insns in
+   basic block BB is less than MAX_COST.  This function returns
+   false if the cost of any instruction could not be estimated.  */
 
-static int
-total_bb_rtx_cost (basic_block bb)
+static bool
+cheap_bb_rtx_cost_p (basic_block bb, int max_cost)
 {
   int count = 0;
   rtx insn = BB_HEAD (bb);
@@ -178,18 +149,34 @@ total_bb_rtx_cost (basic_block bb)
        {
          int cost = insn_rtx_cost (PATTERN (insn));
          if (cost == 0)
-           return -1;
+           return false;
+
+         /* 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.  */
+#ifdef STACK_REGS
+         {
+           rtx set = single_set (insn);
+           if (set && STACK_REG_P (SET_DEST (set)))
+             cost += COSTS_N_INSNS (1);
+         }
+#endif
+
          count += cost;
+         if (count >= max_cost)
+           return false;
        }
       else if (CALL_P (insn))
-       return -1;
+       return false;
  
       if (insn == BB_END (bb))
        break;
       insn = NEXT_INSN (insn);
     }
 
-  return count;
+  return true;
 }
 
 /* Return the first non-jump active insn in the basic block.  */
@@ -284,8 +271,7 @@ cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
       if (NOTE_P (insn))
        goto insn_done;
 
-      if (!NONJUMP_INSN_P (insn) && !CALL_P (insn))
-       abort ();
+      gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn));
 
       /* Remove USE insns that get in the way.  */
       if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
@@ -697,20 +683,73 @@ noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
 static void
 noce_emit_move_insn (rtx x, rtx y)
 {
-  enum machine_mode outmode, inmode;
+  enum machine_mode outmode;
   rtx outer, inner;
   int bitpos;
 
   if (GET_CODE (x) != STRICT_LOW_PART)
     {
-      emit_move_insn (x, y);
+      rtx seq, insn, target;
+      optab ot;
+
+      start_sequence ();
+      /* Check that the SET_SRC is reasonable before calling emit_move_insn,
+        otherwise construct a suitable SET pattern ourselves.  */
+      insn = (OBJECT_P (y) || CONSTANT_P (y) || GET_CODE (y) == SUBREG)
+            ? emit_move_insn (x, y)
+            : emit_insn (gen_rtx_SET (VOIDmode, x, y));
+      seq = get_insns ();
+      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;
+
+         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;
     }
 
   outer = XEXP (x, 0);
   inner = XEXP (outer, 0);
   outmode = GET_MODE (outer);
-  inmode = GET_MODE (inner);
   bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
   store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y);
 }
@@ -1212,6 +1251,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
   rtx a = if_info->a;
   rtx b = if_info->b;
   rtx x = if_info->x;
+  rtx orig_a, orig_b;
   rtx insn_a, insn_b;
   rtx tmp, target;
   int is_mem = 0;
@@ -1287,6 +1327,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
 
   start_sequence ();
 
+  orig_a = a;
+  orig_b = b;
+
   /* If either operand is complex, load it into a register first.
      The best way to do this is to copy the original insn.  In this
      way we preserve any clobbers etc that the insn may have had.
@@ -1318,7 +1361,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
     }
   if (! general_operand (b, GET_MODE (b)))
     {
-      rtx set;
+      rtx set, last;
 
       if (no_new_pseudos)
        goto end_seq_and_fail;
@@ -1326,9 +1369,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
       if (is_mem)
        {
           tmp = gen_reg_rtx (GET_MODE (b));
-         tmp = emit_insn (gen_rtx_SET (VOIDmode,
-                                       tmp,
-                                       b));
+         tmp = gen_rtx_SET (VOIDmode, tmp, b);
        }
       else if (! insn_b)
        goto end_seq_and_fail;
@@ -1338,8 +1379,22 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
          tmp = copy_rtx (insn_b);
          set = single_set (tmp);
          SET_DEST (set) = b;
-         tmp = emit_insn (PATTERN (tmp));
+         tmp = PATTERN (tmp);
        }
+
+      /* If insn to set up A clobbers any registers B depends on, try to
+        swap insn that sets up A with the one that sets up B.  If even
+        that doesn't help, punt.  */
+      last = get_last_insn ();
+      if (last && modified_in_p (orig_b, last))
+       {
+         tmp = emit_insn_before (tmp, get_insns ());
+         if (modified_in_p (orig_a, tmp))
+           goto end_seq_and_fail;
+       }
+      else
+       tmp = emit_insn (tmp);
+
       if (recog_memoized (tmp) < 0)
        goto end_seq_and_fail;
     }
@@ -1430,7 +1485,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
       rtx prev_insn;
 
       /* First, look to see if we put a constant in a register.  */
-      prev_insn = PREV_INSN (if_info->cond_earliest);
+      prev_insn = prev_nonnote_insn (if_info->cond_earliest);
       if (prev_insn
          && INSN_P (prev_insn)
          && GET_CODE (PATTERN (prev_insn)) == SET)
@@ -1642,7 +1697,9 @@ noce_try_abs (struct noce_if_info *if_info)
   if (no_new_pseudos)
     return FALSE;
 
-  /* Recognize A and B as constituting an ABS or NABS.  */
+  /* Recognize A and B as constituting an ABS or NABS.  The canonical
+     form is a branch around the negation, taken when the object is the
+     first operand of a comparison against 0 that evaluates to true.  */
   a = if_info->a;
   b = if_info->b;
   if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
@@ -1663,25 +1720,30 @@ noce_try_abs (struct noce_if_info *if_info)
   if (rtx_equal_p (XEXP (cond, 0), b))
     c = XEXP (cond, 1);
   else if (rtx_equal_p (XEXP (cond, 1), b))
-    c = XEXP (cond, 0);
+    {
+      c = XEXP (cond, 0);
+      negate = !negate;
+    }
   else
     return FALSE;
 
-  /* Verify that C is zero.  Search backward through the block for
-     a REG_EQUAL note if necessary.  */
+  /* Verify that C is zero.  Search one step backward for a
+     REG_EQUAL note or a simple source if necessary.  */
   if (REG_P (c))
     {
-      rtx insn, note = NULL;
-      for (insn = earliest;
-          insn != BB_HEAD (if_info->test_bb);
-          insn = PREV_INSN (insn))
-       if (INSN_P (insn)
-           && ((note = find_reg_note (insn, REG_EQUAL, c))
-               || (note = find_reg_note (insn, REG_EQUIV, c))))
-         break;
-      if (! note)
+      rtx set, insn = prev_nonnote_insn (earliest);
+      if (insn
+         && (set = single_set (insn))
+         && rtx_equal_p (SET_DEST (set), c))
+       {
+         rtx note = find_reg_equal_equiv_note (insn);
+         if (note)
+           c = XEXP (note, 0);
+         else
+           c = SET_SRC (set);
+       }
+      else
        return FALSE;
-      c = XEXP (note, 0);
     }
   if (MEM_P (c)
       && GET_CODE (XEXP (c, 0)) == SYMBOL_REF
@@ -1816,6 +1878,105 @@ noce_try_sign_mask (struct noce_if_info *if_info)
 }
 
 
+/* Optimize away "if (x & C) x |= C" and similar bit manipulation
+   transformations.  */
+
+static int
+noce_try_bitop (struct noce_if_info *if_info)
+{
+  rtx cond, x, a, result, seq;
+  enum machine_mode mode;
+  enum rtx_code code;
+  int bitnum;
+
+  x = if_info->x;
+  cond = if_info->cond;
+  code = GET_CODE (cond);
+
+  /* Check for no else condition.  */
+  if (! rtx_equal_p (x, if_info->b))
+    return FALSE;
+
+  /* Check for a suitable condition.  */
+  if (code != NE && code != EQ)
+    return FALSE;
+  if (XEXP (cond, 1) != const0_rtx)
+    return FALSE;
+  cond = XEXP (cond, 0);
+
+  /* ??? We could also handle AND here.  */
+  if (GET_CODE (cond) == ZERO_EXTRACT)
+    {
+      if (XEXP (cond, 1) != const1_rtx
+         || GET_CODE (XEXP (cond, 2)) != CONST_INT
+         || ! rtx_equal_p (x, XEXP (cond, 0)))
+       return FALSE;
+      bitnum = INTVAL (XEXP (cond, 2));
+      mode = GET_MODE (x);
+      if (bitnum >= HOST_BITS_PER_WIDE_INT)
+       return FALSE;
+    }
+  else
+    return FALSE;
+
+  a = if_info->a;
+  if (GET_CODE (a) == IOR || GET_CODE (a) == XOR)
+    {
+      /* Check for "if (X & C) x = x op C".  */
+      if (! rtx_equal_p (x, XEXP (a, 0))
+          || GET_CODE (XEXP (a, 1)) != CONST_INT
+         || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
+            != (unsigned HOST_WIDE_INT) 1 << bitnum)
+        return FALSE;
+
+      /* if ((x & C) == 0) x |= C; is transformed to x |= C.   */
+      /* if ((x & C) != 0) x |= C; is transformed to nothing.  */
+      if (GET_CODE (a) == IOR)
+       result = (code == NE) ? a : NULL_RTX;
+      else if (code == NE)
+       {
+         /* if ((x & C) == 0) x ^= C; is transformed to x |= C.   */
+         result = gen_int_mode ((HOST_WIDE_INT) 1 << bitnum, mode);
+         result = simplify_gen_binary (IOR, mode, x, result);
+       }
+      else
+       {
+         /* if ((x & C) != 0) x ^= C; is transformed to x &= ~C.  */
+         result = gen_int_mode (~((HOST_WIDE_INT) 1 << bitnum), mode);
+         result = simplify_gen_binary (AND, mode, x, result);
+       }
+    }
+  else if (GET_CODE (a) == AND)
+    {
+      /* Check for "if (X & C) x &= ~C".  */
+      if (! rtx_equal_p (x, XEXP (a, 0))
+         || GET_CODE (XEXP (a, 1)) != CONST_INT
+         || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
+            != (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode)))
+        return FALSE;
+
+      /* if ((x & C) == 0) x &= ~C; is transformed to nothing.  */
+      /* if ((x & C) != 0) x &= ~C; is transformed to x &= ~C.  */
+      result = (code == EQ) ? a : NULL_RTX;
+    }
+  else
+    return FALSE;
+
+  if (result)
+    {
+      start_sequence ();
+      noce_emit_move_insn (x, result);
+      seq = end_ifcvt_sequence (if_info);
+      if (!seq)
+       return FALSE;
+
+      emit_insn_before_setloc (seq, if_info->jump,
+                              INSN_LOCATOR (if_info->insn_a));
+    }
+  return TRUE;
+}
+
+
 /* Similar to get_condition, only the resulting condition must be
    valid at JUMP, instead of at EARLIEST.  */
 
@@ -1855,6 +2016,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
@@ -1871,6 +2078,59 @@ noce_operand_ok (rtx op)
   return ! may_trap_p (op);
 }
 
+/* Return true if a write into MEM may trap or fault.  */
+
+static bool
+noce_mem_write_may_trap_or_fault_p (rtx mem)
+{
+  rtx addr;
+
+  if (MEM_READONLY_P (mem))
+    return true;
+
+  if (may_trap_or_fault_p (mem))
+    return true;
+
+  addr = XEXP (mem, 0);
+
+  /* Call target hook to avoid the effects of -fpic etc....  */
+  addr = targetm.delegitimize_address (addr);
+
+  while (addr)
+    switch (GET_CODE (addr))
+      {
+      case CONST:
+      case PRE_DEC:
+      case PRE_INC:
+      case POST_DEC:
+      case POST_INC:
+      case POST_MODIFY:
+       addr = XEXP (addr, 0);
+       break;
+      case LO_SUM:
+      case PRE_MODIFY:
+       addr = XEXP (addr, 1);
+       break;
+      case PLUS:
+       if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
+         addr = XEXP (addr, 0);
+       else
+         return false;
+       break;
+      case LABEL_REF:
+       return true;
+      case SYMBOL_REF:
+       if (SYMBOL_REF_DECL (addr)
+           && decl_readonly_section (SYMBOL_REF_DECL (addr), 0))
+         return true;
+       return false;
+      default:
+       return false;
+      }
+
+  return false;
+}
+
 /* 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 block.  */
@@ -1897,33 +2157,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);
@@ -2002,9 +2240,6 @@ 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;
@@ -2049,28 +2284,23 @@ noce_process_if_block (struct ce_if_block * ce_info)
     }
 
   /* Disallow the "if (...) x = a;" form (with an implicit "else x = x;")
-     for most optimizations if writing to x may trap, i.e. it's a memory
-     other than a static var or a stack slot.  */
-  if (! set_b
-      && MEM_P (orig_x)
-      && ! MEM_NOTRAP_P (orig_x)
-      && rtx_addr_can_trap_p (XEXP (orig_x, 0)))
-    {
-      if (HAVE_conditional_move)
-       {
-         if (noce_try_cmove (&if_info))
-           goto success;
-         if (! HAVE_conditional_execution
-             && noce_try_cmove_arith (&if_info))
-           goto success;
-       }
-      return FALSE;
-    }
+     for optimizations if writing to x may trap or fault, i.e. it's a memory
+     other than a static var or a stack slot, is misaligned on strict
+     aligned machines or is read-only.
+     If x is a read-only memory, then the program is valid only if we
+     avoid the store into it.  If there are stores on both the THEN and
+     ELSE arms, then we can go ahead with the conversion; either the
+     program is broken, or the condition is always false such that the
+     other memory is selected.  */
+  if (!set_b && MEM_P (orig_x) && noce_mem_write_may_trap_or_fault_p (orig_x))
+    return FALSE;
 
   if (noce_try_move (&if_info))
     goto success;
   if (noce_try_store_flag (&if_info))
     goto success;
+  if (noce_try_bitop (&if_info))
+    goto success;
   if (noce_try_minmax (&if_info))
     goto success;
   if (noce_try_abs (&if_info))
@@ -2131,6 +2361,235 @@ noce_process_if_block (struct ce_if_block * ce_info)
 
   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.  COND is the condition we will
+   test.  */
+
+static int
+check_cond_move_block (basic_block bb, rtx *vals, rtx cond)
+{
+  rtx insn;
+
+  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 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;
+
+      vals[REGNO (dest)] = src;
+
+      /* 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;
+    }
+
+  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 then_bb = ce_info->then_bb;
+  basic_block else_bb = ce_info->else_bb;
+  struct noce_if_info if_info;
+  rtx jump, cond, insn, seq, cond_arg0, cond_arg1, loc_insn;
+  int max_reg, size, c, i;
+  rtx *then_vals;
+  rtx *else_vals;
+  enum rtx_code code;
+
+  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, cond)
+      || (else_bb && !check_cond_move_block (else_bb, else_vals, 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; i <= max_reg; ++i)
+    {
+      if (!then_vals[i] && !else_vals[i])
+       continue;
+
+      if (!then_vals[i] || !else_vals[i])
+       ++c;
+      else
+       {
+         if (!CONSTANT_P (then_vals[i])
+             && !CONSTANT_P (else_vals[i])
+             && !rtx_equal_p (then_vals[i], else_vals[i]))
+           return FALSE;
+       }
+    }
+
+  /* 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;
+
+  /* Emit the conditional moves.  First do the then block, then do
+     anything left in the else blocks.  */
+
+  code = GET_CODE (cond);
+  cond_arg0 = XEXP (cond, 0);
+  cond_arg1 = XEXP (cond, 1);
+
+  start_sequence ();
+
+  FOR_BB_INSNS (then_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];
+      gcc_assert (t);
+      if (!e)
+       e = dest;
+      target = noce_emit_cmove (&if_info, dest, code, cond_arg0, cond_arg1,
+                               t, e);
+      if (!target)
+       {
+         end_sequence ();
+         return FALSE;
+       }
+
+      if (target != dest)
+       noce_emit_move_insn (dest, target);
+    }
+
+  if (else_bb)
+    {
+      FOR_BB_INSNS (else_bb, insn)
+       {
+         rtx set, target, dest;
+         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);
+
+         /* If this register was set in the then block, we already
+            handled this case above.  */
+         if (then_vals[regno])
+           continue;
+         gcc_assert (else_vals[regno]);
+
+         target = noce_emit_cmove (&if_info, dest, code, cond_arg0, cond_arg1,
+                                   dest, else_vals[regno]);
+         if (!target)
+           {
+             end_sequence ();
+             return FALSE;
+           }
+
+         if (target != dest)
+           noce_emit_move_insn (dest, target);
+       }
+    }
+
+  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));
+
+  FOR_BB_INSNS (then_bb, insn)
+    if (INSN_P (insn) && !JUMP_P (insn))
+      delete_insn (insn);
+  if (else_bb)
+    {
+      FOR_BB_INSNS (else_bb, insn)
+       if (INSN_P (insn) && !JUMP_P (insn))
+         delete_insn (insn);
+    }
+  delete_insn (jump);
+
+  merge_if_block (ce_info);
+
+  return TRUE;
+}
 \f
 /* Attempt to convert an IF-THEN or IF-THEN-ELSE block into
    straight line code.  Return true if successful.  */
@@ -2142,6 +2601,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
@@ -2202,9 +2665,9 @@ merge_if_block (struct ce_if_block * ce_info)
 
   if (then_bb)
     {
-      if (combo_bb->global_live_at_end)
-       COPY_REG_SET (combo_bb->global_live_at_end,
-                     then_bb->global_live_at_end);
+      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++;
     }
@@ -2228,30 +2691,21 @@ merge_if_block (struct ce_if_block * ce_info)
       /* The outgoing edge for the current COMBO block should already
         be correct.  Verify this.  */
       if (EDGE_COUNT (combo_bb->succs) == 0)
-       {
-         if (find_reg_note (last, REG_NORETURN, NULL))
-           ;
-         else if (NONJUMP_INSN_P (last)
-                  && GET_CODE (PATTERN (last)) == TRAP_IF
-                  && TRAP_CONDITION (PATTERN (last)) == const_true_rtx)
-           ;
-         else
-           abort ();
-       }
+       gcc_assert (find_reg_note (last, REG_NORETURN, NULL)
+                   || (NONJUMP_INSN_P (last)
+                       && GET_CODE (PATTERN (last)) == TRAP_IF
+                       && (TRAP_CONDITION (PATTERN (last))
+                           == const_true_rtx)));
 
+      else
       /* There should still be something at the end of the THEN or ELSE
          blocks taking us to our final destination.  */
-      else if (JUMP_P (last))
-       ;
-      else if (EDGE_SUCC (combo_bb, 0)->dest == EXIT_BLOCK_PTR
-              && CALL_P (last)
-              && SIBLING_CALL_P (last))
-       ;
-      else if ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH)
-              && can_throw_internal (last))
-       ;
-      else
-       abort ();
+       gcc_assert (JUMP_P (last)
+                   || (EDGE_SUCC (combo_bb, 0)->dest == EXIT_BLOCK_PTR
+                       && CALL_P (last)
+                       && SIBLING_CALL_P (last))
+                   || ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH)
+                       && can_throw_internal (last)));
     }
 
   /* The JOIN block may have had quite a number of other predecessors too.
@@ -2259,14 +2713,14 @@ merge_if_block (struct ce_if_block * ce_info)
      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).  */
+     back up (as with a call to a non-return function).  */
   else if (EDGE_COUNT (join_bb->preds) < 2
           && join_bb != EXIT_BLOCK_PTR)
     {
       /* We can merge the JOIN.  */
-      if (combo_bb->global_live_at_end)
-       COPY_REG_SET (combo_bb->global_live_at_end,
-                     join_bb->global_live_at_end);
+      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++;
@@ -2277,13 +2731,12 @@ merge_if_block (struct ce_if_block * ce_info)
 
       /* The outgoing edge for the current COMBO block should already
         be correct.  Verify this.  */
-      if (EDGE_COUNT (combo_bb->succs) > 1
-         || EDGE_SUCC (combo_bb, 0)->dest != join_bb)
-       abort ();
+      gcc_assert (single_succ_p (combo_bb)
+                 && single_succ (combo_bb) == join_bb);
 
       /* Remove the jump and cruft from the end of the COMBO block.  */
       if (join_bb != EXIT_BLOCK_PTR)
-       tidy_fallthru_edge (EDGE_SUCC (combo_bb, 0));
+       tidy_fallthru_edge (single_succ_edge (combo_bb));
     }
 
   num_updated_if_blocks++;
@@ -2445,8 +2898,6 @@ find_if_block (struct ce_if_block * ce_info)
   basic_block then_bb = ce_info->then_bb;
   basic_block else_bb = ce_info->else_bb;
   basic_block join_bb = NULL_BLOCK;
-  int then_predecessors;
-  int else_predecessors;
   edge cur_edge;
   basic_block next;
   edge_iterator ei;
@@ -2457,10 +2908,10 @@ find_if_block (struct ce_if_block * ce_info)
      were && tests (which jump to the else block) or || tests (which jump to
      the then block).  */
   if (HAVE_conditional_execution && reload_completed
-      && EDGE_COUNT (test_bb->preds) == 1
-      && EDGE_PRED (test_bb, 0)->flags == EDGE_FALLTHRU)
+      && single_pred_p (test_bb)
+      && single_pred_edge (test_bb)->flags == EDGE_FALLTHRU)
     {
-      basic_block bb = EDGE_PRED (test_bb, 0)->src;
+      basic_block bb = single_pred (test_bb);
       basic_block target_bb;
       int max_insns = MAX_CONDITIONAL_EXECUTE;
       int n_insns;
@@ -2493,10 +2944,10 @@ find_if_block (struct ce_if_block * ce_info)
              total_insns += n_insns;
              blocks++;
 
-             if (EDGE_COUNT (bb->preds) != 1)
+             if (!single_pred_p (bb))
                break;
 
-             bb = EDGE_PRED (bb, 0)->src;
+             bb = single_pred (bb);
              n_insns = block_jumps_and_fallthru_p (bb, target_bb);
            }
          while (n_insns >= 0 && (total_insns + n_insns) <= max_insns);
@@ -2511,32 +2962,28 @@ find_if_block (struct ce_if_block * ce_info)
        }
     }
 
-  /* Count the number of edges the THEN and ELSE blocks have.  */
-  then_predecessors = 0;
+  /* The THEN block of an IF-THEN combo must have exactly one predecessor,
+     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)
     {
-      then_predecessors++;
       if (cur_edge->flags & EDGE_COMPLEX)
        return FALSE;
     }
 
-  else_predecessors = 0;
   FOR_EACH_EDGE (cur_edge, ei, else_bb->preds)
     {
-      else_predecessors++;
       if (cur_edge->flags & EDGE_COMPLEX)
        return FALSE;
     }
 
-  /* The THEN block of an IF-THEN combo must have exactly one predecessor,
-     other than any || blocks which jump to the THEN block.  */
-  if ((then_predecessors - ce_info->num_or_or_blocks) != 1)
-    return FALSE;
-
   /* The THEN block of an IF-THEN combo must have zero or one successors.  */
   if (EDGE_COUNT (then_bb->succs) > 0
-      && (EDGE_COUNT (then_bb->succs) > 1
-          || (EDGE_SUCC (then_bb, 0)->flags & EDGE_COMPLEX)
+      && (!single_succ_p (then_bb)
+          || (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
          || (flow2_completed && tablejump_p (BB_END (then_bb), NULL, NULL))))
     return FALSE;
 
@@ -2548,7 +2995,7 @@ find_if_block (struct ce_if_block * ce_info)
      code processing.  ??? we should fix this in the future.  */
   if (EDGE_COUNT (then_bb->succs) == 0)
     {
-      if (EDGE_COUNT (else_bb->preds) == 1)
+      if (single_pred_p (else_bb))
        {
          rtx last_insn = BB_END (then_bb);
 
@@ -2571,7 +3018,7 @@ find_if_block (struct ce_if_block * ce_info)
 
   /* 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.  */
-  else if (EDGE_SUCC (then_bb, 0)->dest == else_bb)
+  else if (single_succ (then_bb) == else_bb)
     {
       join_bb = else_bb;
       else_bb = NULL_BLOCK;
@@ -2580,12 +3027,12 @@ find_if_block (struct ce_if_block * ce_info)
   /* If the THEN and ELSE block meet in a subsequent block, and the ELSE
      has exactly one predecessor and one successor, and the outgoing edge
      is not complex, then we have an IF-THEN-ELSE combo.  */
-  else if (EDGE_COUNT (else_bb->succs) == 1
-          && EDGE_SUCC (then_bb, 0)->dest == EDGE_SUCC (else_bb, 0)->dest
-          && EDGE_COUNT (else_bb->preds) == 1
-          && ! (EDGE_SUCC (else_bb, 0)->flags & EDGE_COMPLEX)
+  else if (single_succ_p (else_bb)
+          && single_succ (then_bb) == single_succ (else_bb)
+          && single_pred_p (else_bb)
+          && ! (single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
           && ! (flow2_completed && tablejump_p (BB_END (else_bb), NULL, NULL)))
-    join_bb = EDGE_SUCC (else_bb, 0)->dest;
+    join_bb = single_succ (else_bb);
 
   /* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination.  */
   else
@@ -2633,7 +3080,7 @@ find_if_block (struct ce_if_block * ce_info)
      we checked the FALLTHRU flag, those are already adjacent to the last IF
      block.  */
   /* ??? As an enhancement, move the ELSE block.  Have to deal with
-     BLOCK notes, if by no other means than aborting the merge if they
+     BLOCK notes, if by no other means than backing out the merge if they
      exist.  Sticky enough I don't want to think about it now.  */
   next = then_bb;
   if (else_bb && (next = next->next_bb) != else_bb)
@@ -2859,7 +3306,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
 {
   basic_block then_bb = then_edge->dest;
   basic_block else_bb = else_edge->dest, new_bb;
-  int then_bb_index, bb_cost;
+  int then_bb_index;
 
   /* If we are partitioning hot/cold basic blocks, we don't want to
      mess up unconditional or indirect jumps that cross between hot
@@ -2871,24 +3318,25 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
      partition boundaries).  See  the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && ((BB_END (then_bb) 
-          && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
-         || (BB_END (else_bb)
-             && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP, 
-                               NULL_RTX))))
+  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, 
+                           NULL_RTX)))
     return FALSE;
 
   /* THEN has one successor.  */
-  if (EDGE_COUNT (then_bb->succs) != 1)
+  if (!single_succ_p (then_bb))
     return FALSE;
 
   /* THEN does not fall through, but is not strange either.  */
-  if (EDGE_SUCC (then_bb, 0)->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
+  if (single_succ_edge (then_bb)->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
     return FALSE;
 
   /* THEN has one predecessor.  */
-  if (EDGE_COUNT (then_bb->preds) != 1)
+  if (!single_pred_p (then_bb))
     return FALSE;
 
   /* THEN must do something.  */
@@ -2902,23 +3350,37 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
             test_bb->index, then_bb->index);
 
   /* THEN is small.  */
-  bb_cost = total_bb_rtx_cost (then_bb);
-  if (bb_cost < 0 || bb_cost >= COSTS_N_INSNS (BRANCH_COST))
+  if (! cheap_bb_rtx_cost_p (then_bb, COSTS_N_INSNS (BRANCH_COST)))
     return FALSE;
 
   /* Registers set are dead, or are predicable.  */
   if (! dead_or_predicable (test_bb, then_bb, else_bb,
-                           EDGE_SUCC (then_bb, 0)->dest, 1))
+                           single_succ (then_bb), 1))
     return FALSE;
 
   /* Conversion went ok, including moving the insns and fixing up the
      jump.  Adjust the CFG to match.  */
 
-  bitmap_ior (test_bb->global_live_at_end,
-             else_bb->global_live_at_start,
-             then_bb->global_live_at_end);
+  bitmap_ior (test_bb->il.rtl->global_live_at_end,
+             else_bb->il.rtl->global_live_at_start,
+             then_bb->il.rtl->global_live_at_end);
+
+
+  /* We can avoid creating a new basic block if then_bb is immediately
+     followed by else_bb, i.e. deleting then_bb allows test_bb to fall
+     thru to else_bb.  */
+
+  if (then_bb->next_bb == else_bb
+      && then_bb->prev_bb == test_bb
+      && else_bb != EXIT_BLOCK_PTR)
+    {
+      redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb);
+      new_bb = 0;
+    }
+  else
+    new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb),
+                                             else_bb);
 
-  new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
   then_bb_index = then_bb->index;
   delete_basic_block (then_bb);
 
@@ -2927,7 +3389,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).  */
@@ -2950,7 +3412,6 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
   basic_block then_bb = then_edge->dest;
   basic_block else_bb = else_edge->dest;
   edge else_succ;
-  int bb_cost;
   rtx note;
 
   /* If we are partitioning hot/cold basic blocks, we don't want to
@@ -2963,37 +3424,38 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
      partition boundaries).  See  the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && ((BB_END (then_bb)
-          && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
-         || (BB_END (else_bb) 
-             && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP, 
-                               NULL_RTX))))
+  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, 
+                           NULL_RTX)))
     return FALSE;
 
   /* ELSE has one successor.  */
-  if (EDGE_COUNT (else_bb->succs) != 1)
+  if (!single_succ_p (else_bb))
     return FALSE;
   else
-    else_succ = EDGE_SUCC (else_bb, 0);
+    else_succ = single_succ_edge (else_bb);
 
   /* ELSE outgoing edge is not complex.  */
   if (else_succ->flags & EDGE_COMPLEX)
     return FALSE;
 
   /* ELSE has one predecessor.  */
-  if (EDGE_COUNT (else_bb->preds) != 1)
+  if (!single_pred_p (else_bb))
     return FALSE;
 
   /* THEN is not EXIT.  */
-  if (then_bb->index < 0)
+  if (then_bb->index < NUM_FIXED_BLOCKS)
     return FALSE;
 
   /* ELSE is predicted or SUCC(ELSE) postdominates THEN.  */
   note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
   if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
     ;
-  else if (else_succ->dest->index < 0
+  else if (else_succ->dest->index < NUM_FIXED_BLOCKS
           || dominated_by_p (CDI_POST_DOMINATORS, then_bb,
                              else_succ->dest))
     ;
@@ -3007,8 +3469,7 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
             test_bb->index, else_bb->index);
 
   /* ELSE is small.  */
-  bb_cost = total_bb_rtx_cost (else_bb);
-  if (bb_cost < 0 || bb_cost >= COSTS_N_INSNS (BRANCH_COST))
+  if (! cheap_bb_rtx_cost_p (else_bb, COSTS_N_INSNS (BRANCH_COST)))
     return FALSE;
 
   /* Registers set are dead, or are predicable.  */
@@ -3018,9 +3479,9 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
   /* Conversion went ok, including moving the insns and fixing up the
      jump.  Adjust the CFG to match.  */
 
-  bitmap_ior (test_bb->global_live_at_end,
-             then_bb->global_live_at_start,
-             else_bb->global_live_at_end);
+  bitmap_ior (test_bb->il.rtl->global_live_at_end,
+             then_bb->il.rtl->global_live_at_start,
+             else_bb->il.rtl->global_live_at_end);
 
   delete_basic_block (else_bb);
 
@@ -3130,10 +3591,9 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
         that any registers modified are dead at the branch site.  */
 
       rtx insn, cond, prev;
-      regset_head merge_set_head, tmp_head, test_live_head, test_set_head;
       regset merge_set, tmp, test_live, test_set;
       struct propagate_block_info *pbi;
-      int i, fail = 0;
+      unsigned i, fail = 0;
       bitmap_iterator bi;
 
       /* Check for no calls or trapping operations.  */
@@ -3172,14 +3632,22 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
           TEST_SET  = set of registers set between EARLIEST and the
                       end of the block.  */
 
-      tmp = INITIALIZE_REG_SET (tmp_head);
-      merge_set = INITIALIZE_REG_SET (merge_set_head);
-      test_live = INITIALIZE_REG_SET (test_live_head);
-      test_set = INITIALIZE_REG_SET (test_set_head);
+      tmp = ALLOC_REG_SET (&reg_obstack);
+      merge_set = ALLOC_REG_SET (&reg_obstack);
+      test_live = ALLOC_REG_SET (&reg_obstack);
+      test_set = ALLOC_REG_SET (&reg_obstack);
 
       /* ??? bb->local_set is only valid during calculate_global_regs_live,
         so we must recompute usage for MERGE_BB.  Not so bad, I suppose,
          since we've already asserted that MERGE_BB is small.  */
+      /* If we allocated new pseudos (e.g. in the conditional move
+        expander called from noce_emit_cmove), we must resize the
+        array first.  */
+      if (max_regno < max_reg_num ())
+       {
+         max_regno = max_reg_num ();
+         allocate_reg_info (max_regno, FALSE, FALSE);
+       }
       propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
 
       /* For small register class machines, don't lengthen lifetimes of
@@ -3198,7 +3666,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
       /* For TEST, we're interested in a range of insns, not a whole block.
         Moreover, we're interested in the insns live from OTHER_BB.  */
 
-      COPY_REG_SET (test_live, other_bb->global_live_at_start);
+      COPY_REG_SET (test_live, other_bb->il.rtl->global_live_at_start);
       pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
                                       0);
 
@@ -3214,16 +3682,13 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
       /* We can perform the transformation if
           MERGE_SET & (TEST_SET | TEST_LIVE)
         and
-          TEST_SET & merge_bb->global_live_at_start
+          TEST_SET & merge_bb->il.rtl->global_live_at_start
         are empty.  */
 
-      bitmap_ior (tmp, test_set, test_live);
-      bitmap_and_into (tmp, merge_set);
-      if (!bitmap_empty_p (tmp))
-       fail = 1;
-
-      bitmap_and (tmp, test_set, merge_bb->global_live_at_start);
-      if (!bitmap_empty_p (tmp))
+      if (bitmap_intersect_p (test_set, merge_set)
+         || bitmap_intersect_p (test_live, merge_set)
+         || bitmap_intersect_p (test_set,
+                                merge_bb->il.rtl->global_live_at_start))
        fail = 1;
 
       FREE_REG_SET (tmp);
@@ -3255,13 +3720,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
 
   if (other_bb != new_dest)
     {
-      if (old_dest)
-       LABEL_NUSES (old_dest) -= 1;
-      if (new_label)
-       LABEL_NUSES (new_label) += 1;
-      JUMP_LABEL (jump) = new_label;
-      if (reversep)
-       invert_br_probabilities (jump);
+      redirect_jump_2 (jump, old_dest, new_label, -1, reversep);
 
       redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
       if (reversep)
@@ -3281,12 +3740,31 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
   /* Move the insns out of MERGE_BB to before the branch.  */
   if (head != NULL)
     {
+      rtx insn;
+
       if (end == BB_END (merge_bb))
        BB_END (merge_bb) = PREV_INSN (head);
 
       if (squeeze_notes (&head, &end))
        return TRUE;
 
+      /* PR 21767: When moving insns above a conditional branch, REG_EQUAL
+        notes might become invalid.  */
+      insn = head;
+      do
+       {
+         rtx note, set;
+
+         if (! INSN_P (insn))
+           continue;
+         note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+         if (! note)
+           continue;
+         set = single_set (insn);
+         if (!set || !function_invariant_p (SET_SRC (set)))
+           remove_note (insn, note);
+       } while (insn != end && (insn = NEXT_INSN (insn)));
+
       reorder_insns (head, end, PREV_INSN (earliest));
     }
 
@@ -3308,7 +3786,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;
@@ -3322,7 +3800,14 @@ if_convert (int x_life_data_ok)
   if ((! targetm.cannot_modify_jumps_p ())
       && (!flag_reorder_blocks_and_partition || !no_new_pseudos
          || !targetm.have_named_sections))
-    mark_loop_exit_edges ();
+    {
+      struct loops loops;
+
+      flow_loops_find (&loops);
+      mark_loop_exit_edges (&loops);
+      flow_loops_free (&loops);
+      free_dominance_info (CDI_DOMINATORS);
+    }
 
   /* Compute postdominators if we think we'll use them.  */
   if (HAVE_conditional_execution || life_data_ok)
@@ -3403,3 +3888,120 @@ if_convert (int x_life_data_ok)
   verify_flow_info ();
 #endif
 }
+\f
+static bool
+gate_handle_if_conversion (void)
+{
+  return (optimize > 0);
+}
+
+/* If-conversion and CFG cleanup.  */
+static void
+rest_of_handle_if_conversion (void)
+{
+  if (flag_if_conversion)
+    {
+      if (dump_file)
+        dump_flow_info (dump_file, dump_flags);
+      cleanup_cfg (CLEANUP_EXPENSIVE);
+      reg_scan (get_insns (), max_reg_num ());
+      if_convert (0);
+    }
+
+  timevar_push (TV_JUMP);
+  cleanup_cfg (CLEANUP_EXPENSIVE);
+  reg_scan (get_insns (), max_reg_num ());
+  timevar_pop (TV_JUMP);
+}
+
+struct tree_opt_pass pass_rtl_ifcvt =
+{
+  "ce1",                                /* name */
+  gate_handle_if_conversion,            /* gate */
+  rest_of_handle_if_conversion,         /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_IFCVT,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'C'                                   /* letter */
+};
+
+static bool
+gate_handle_if_after_combine (void)
+{
+  return (optimize > 0 && flag_if_conversion);
+}
+
+
+/* Rerun if-conversion, as combine may have simplified things enough
+   to now meet sequence length restrictions.  */
+static void
+rest_of_handle_if_after_combine (void)
+{
+  no_new_pseudos = 0;
+  if_convert (1);
+  no_new_pseudos = 1;
+}
+
+struct tree_opt_pass pass_if_after_combine =
+{
+  "ce2",                                /* name */
+  gate_handle_if_after_combine,         /* gate */
+  rest_of_handle_if_after_combine,      /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_IFCVT,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'C'                                   /* letter */
+};
+
+
+static bool
+gate_handle_if_after_reload (void)
+{
+  return (optimize > 0);
+}
+
+static void
+rest_of_handle_if_after_reload (void)
+{
+  /* Last attempt to optimize CFG, as scheduling, peepholing and insn
+     splitting possibly introduced more crossjumping opportunities.  */
+  cleanup_cfg (CLEANUP_EXPENSIVE
+               | CLEANUP_UPDATE_LIFE
+               | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
+  if (flag_if_conversion2)
+    if_convert (1);
+}
+
+
+struct tree_opt_pass pass_if_after_reload =
+{
+  "ce3",                                /* name */
+  gate_handle_if_after_reload,          /* gate */
+  rest_of_handle_if_after_reload,       /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_IFCVT2,                            /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'E'                                   /* letter */
+};
+
+