OSDN Git Service

PR middle-end/40525
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index da32ab4..c47dfab 100644 (file)
@@ -1,12 +1,12 @@
 /* If-conversion support.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -15,9 +15,8 @@
    License for more details.
 
    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, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "target.h"
 #include "timevar.h"
 #include "tree-pass.h"
-
+#include "df.h"
+#include "vec.h"
+#include "vecprim.h"
+#include "dbgcnt.h"
 
 #ifndef HAVE_conditional_execution
 #define HAVE_conditional_execution 0
 #ifndef HAVE_trap
 #define HAVE_trap 0
 #endif
-#ifndef HAVE_conditional_trap
-#define HAVE_conditional_trap 0
-#endif
 
 #ifndef MAX_CONDITIONAL_EXECUTE
-#define MAX_CONDITIONAL_EXECUTE   (BRANCH_COST + 1)
+#define MAX_CONDITIONAL_EXECUTE \
+  (BRANCH_COST (optimize_function_for_speed_p (cfun), false) \
+   + 1)
 #endif
 
+#define IFCVT_MULTIPLE_DUMPS 1
+
 #define NULL_BLOCK     ((basic_block) NULL)
 
 /* # of IF-THEN or IF-THEN-ELSE blocks we looked at  */
@@ -77,33 +80,28 @@ static int num_possible_if_blocks;
    execution.  */
 static int num_updated_if_blocks;
 
-/* # of changes made which require life information to be updated.  */
+/* # of changes made.  */
 static int num_true_changes;
 
 /* Whether conditional execution changes were made.  */
 static int cond_exec_changed_p;
 
-/* True if life data ok at present.  */
-static bool life_data_ok;
-
 /* Forward references.  */
-static int count_bb_insns (basic_block);
-static bool cheap_bb_rtx_cost_p (basic_block, int);
+static int count_bb_insns (const_basic_block);
+static bool cheap_bb_rtx_cost_p (const_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);
 static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
 static rtx cond_exec_get_condition (rtx);
-static int cond_exec_process_if_block (ce_if_block_t *, int);
-static rtx noce_get_condition (rtx, rtx *);
-static int noce_operand_ok (rtx);
-static int noce_process_if_block (ce_if_block_t *);
-static int process_if_block (ce_if_block_t *);
+static rtx noce_get_condition (rtx, rtx *, bool);
+static int noce_operand_ok (const_rtx);
 static void merge_if_block (ce_if_block_t *);
 static int find_cond_trap (basic_block, edge, edge);
 static basic_block find_if_header (basic_block, int);
 static int block_jumps_and_fallthru_p (basic_block, basic_block);
-static int find_if_block (ce_if_block_t *);
+static int noce_find_if_block (basic_block, edge, edge, int);
+static int cond_exec_find_if_block (ce_if_block_t *);
 static int find_if_case_1 (basic_block, edge, edge);
 static int find_if_case_2 (basic_block, edge, edge);
 static int find_memory (rtx *, void *);
@@ -115,7 +113,7 @@ static rtx block_has_only_trap (basic_block);
 /* Count the number of non-jump active insns in BB.  */
 
 static int
-count_bb_insns (basic_block bb)
+count_bb_insns (const_basic_block bb)
 {
   int count = 0;
   rtx insn = BB_HEAD (bb);
@@ -138,29 +136,32 @@ count_bb_insns (basic_block bb)
    false if the cost of any instruction could not be estimated.  */
 
 static bool
-cheap_bb_rtx_cost_p (basic_block bb, int max_cost)
+cheap_bb_rtx_cost_p (const_basic_block bb, int max_cost)
 {
   int count = 0;
   rtx insn = BB_HEAD (bb);
+  bool speed = optimize_bb_for_speed_p (bb);
 
   while (1)
     {
       if (NONJUMP_INSN_P (insn))
        {
-         int cost = insn_rtx_cost (PATTERN (insn));
+         int cost = insn_rtx_cost (PATTERN (insn), speed);
          if (cost == 0)
            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.  */
+            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 +171,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 +595,40 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
 
 struct noce_if_info
 {
-  basic_block test_bb;
+  /* The basic blocks that make up the IF-THEN-{ELSE-,}JOIN block.  */
+  basic_block test_bb, then_bb, else_bb, join_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;
+
+  /* True if this if block is not canonical.  In the canonical form of
+     if blocks, the THEN_BB is the block reached via the fallthru edge
+     from TEST_BB.  For the noce transformations, we allow the symmetric
+     form as well.  */
+  bool then_else_reversed;
+
+  /* Estimated cost of the particular branch instruction.  */
+  int branch_cost;
 };
 
 static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
@@ -634,7 +663,15 @@ noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
      build the store_flag insn directly.  */
 
   if (cond_complex)
-    cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
+    {
+      rtx set = pc_set (if_info->jump);
+      cond = XEXP (SET_SRC (set), 0);
+      if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
+         && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump))
+       reversep = !reversep;
+      if (if_info->then_else_reversed)
+       reversep = !reversep;
+    }
 
   if (reversep)
     code = reversed_comparison_code (cond, if_info->jump);
@@ -699,49 +736,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;
@@ -839,12 +905,12 @@ noce_try_store_flag (struct noce_if_info *if_info)
   int reversep;
   rtx target, seq;
 
-  if (GET_CODE (if_info->b) == CONST_INT
+  if (CONST_INT_P (if_info->b)
       && INTVAL (if_info->b) == STORE_FLAG_VALUE
       && if_info->a == const0_rtx)
     reversep = 0;
   else if (if_info->b == const0_rtx
-          && GET_CODE (if_info->a) == CONST_INT
+          && CONST_INT_P (if_info->a)
           && INTVAL (if_info->a) == STORE_FLAG_VALUE
           && (reversed_comparison_code (if_info->cond, if_info->jump)
               != UNKNOWN))
@@ -886,9 +952,8 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
   int normalize, can_reverse;
   enum machine_mode mode;
 
-  if (! no_new_pseudos
-      && GET_CODE (if_info->a) == CONST_INT
-      && GET_CODE (if_info->b) == CONST_INT)
+  if (CONST_INT_P (if_info->a)
+      && CONST_INT_P (if_info->b))
     {
       mode = GET_MODE (if_info->x);
       ifalse = INTVAL (if_info->a);
@@ -909,20 +974,20 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
        normalize = 0;
       else if (ifalse == 0 && exact_log2 (itrue) >= 0
               && (STORE_FLAG_VALUE == 1
-                  || BRANCH_COST >= 2))
+                  || if_info->branch_cost >= 2))
        normalize = 1;
       else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
-              && (STORE_FLAG_VALUE == 1 || BRANCH_COST >= 2))
+              && (STORE_FLAG_VALUE == 1 || if_info->branch_cost >= 2))
        normalize = 1, reversep = 1;
       else if (itrue == -1
               && (STORE_FLAG_VALUE == -1
-                  || BRANCH_COST >= 2))
+                  || if_info->branch_cost >= 2))
        normalize = -1;
       else if (ifalse == -1 && can_reverse
-              && (STORE_FLAG_VALUE == -1 || BRANCH_COST >= 2))
+              && (STORE_FLAG_VALUE == -1 || if_info->branch_cost >= 2))
        normalize = -1, reversep = 1;
-      else if ((BRANCH_COST >= 2 && STORE_FLAG_VALUE == -1)
-              || BRANCH_COST >= 3)
+      else if ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1)
+              || if_info->branch_cost >= 3)
        normalize = -1;
       else
        return FALSE;
@@ -1013,8 +1078,7 @@ noce_try_addcc (struct noce_if_info *if_info)
   rtx target, seq;
   int subtract, normalize;
 
-  if (! no_new_pseudos
-      && GET_CODE (if_info->a) == PLUS
+  if (GET_CODE (if_info->a) == PLUS
       && rtx_equal_p (XEXP (if_info->a, 0), if_info->b)
       && (reversed_comparison_code (if_info->cond, if_info->jump)
          != UNKNOWN))
@@ -1054,7 +1118,7 @@ noce_try_addcc (struct noce_if_info *if_info)
 
       /* If that fails, construct conditional increment or decrement using
         setcc.  */
-      if (BRANCH_COST >= 2
+      if (if_info->branch_cost >= 2
          && (XEXP (if_info->a, 1) == const1_rtx
              || XEXP (if_info->a, 1) == constm1_rtx))
         {
@@ -1105,9 +1169,8 @@ noce_try_store_flag_mask (struct noce_if_info *if_info)
   int reversep;
 
   reversep = 0;
-  if (! no_new_pseudos
-      && (BRANCH_COST >= 2
-         || STORE_FLAG_VALUE == -1)
+  if ((if_info->branch_cost >= 2
+       || STORE_FLAG_VALUE == -1)
       && ((if_info->a == const0_rtx
           && rtx_equal_p (if_info->b, if_info->x))
          || ((reversep = (reversed_comparison_code (if_info->cond,
@@ -1262,9 +1325,10 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
      conditional on their addresses followed by a load.  Don't do this
      early because it'll screw alias analysis.  Note that we've
      already checked for no side effects.  */
-  if (! no_new_pseudos && cse_not_expected
+  /* ??? FIXME: Magic number 5.  */
+  if (cse_not_expected
       && MEM_P (a) && MEM_P (b)
-      && BRANCH_COST >= 5)
+      && if_info->branch_cost >= 5)
     {
       a = XEXP (a, 0);
       b = XEXP (b, 0);
@@ -1293,21 +1357,22 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
      if insn_rtx_cost can't be estimated.  */
   if (insn_a)
     {
-      insn_cost = insn_rtx_cost (PATTERN (insn_a));
-      if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
+      insn_cost = insn_rtx_cost (PATTERN (insn_a),
+                                optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn_a)));
+      if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (if_info->branch_cost))
        return FALSE;
     }
   else
+    insn_cost = 0;
+
+  if (insn_b)
     {
-      insn_cost = 0;
+      insn_cost += insn_rtx_cost (PATTERN (insn_b),
+                                optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn_b)));
+      if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (if_info->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)
     {
@@ -1338,9 +1403,6 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
     {
       rtx set;
 
-      if (no_new_pseudos)
-       goto end_seq_and_fail;
-
       if (is_mem)
        {
          tmp = gen_reg_rtx (GET_MODE (a));
@@ -1363,9 +1425,6 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
     {
       rtx set, last;
 
-      if (no_new_pseudos)
-       goto end_seq_and_fail;
-
       if (is_mem)
        {
           tmp = gen_reg_rtx (GET_MODE (b));
@@ -1462,6 +1521,8 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
   reverse
     = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
       && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
+  if (if_info->then_else_reversed)
+    reverse = !reverse;
 
   /* If we're looking for a constant, try to make the conditional
      have that constant in it.  There are two reasons why it may
@@ -1477,7 +1538,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
        make equivalent types of changes) to get the constants we need
        if they're off by one in the right direction.  */
 
-  if (GET_CODE (target) == CONST_INT)
+  if (CONST_INT_P (target))
     {
       enum rtx_code code = GET_CODE (if_info->cond);
       rtx op_a = XEXP (if_info->cond, 0);
@@ -1485,22 +1546,23 @@ 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
+         && BLOCK_NUM (prev_insn) == BLOCK_NUM (if_info->cond_earliest)
          && INSN_P (prev_insn)
          && GET_CODE (PATTERN (prev_insn)) == SET)
        {
          rtx src = find_reg_equal_equiv_note (prev_insn);
          if (!src)
            src = SET_SRC (PATTERN (prev_insn));
-         if (GET_CODE (src) == CONST_INT)
+         if (CONST_INT_P (src))
            {
              if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
                op_a = src;
              else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
                op_b = src;
 
-             if (GET_CODE (op_a) == CONST_INT)
+             if (CONST_INT_P (op_a))
                {
                  rtx tmp = op_a;
                  op_a = op_b;
@@ -1512,7 +1574,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
 
       /* Now, look to see if we can get the right constant by
         adjusting the conditional.  */
-      if (GET_CODE (op_b) == CONST_INT)
+      if (CONST_INT_P (op_b))
        {
          HOST_WIDE_INT desired_val = INTVAL (target);
          HOST_WIDE_INT actual_val = INTVAL (op_b);
@@ -1597,10 +1659,6 @@ noce_try_minmax (struct noce_if_info *if_info)
   enum rtx_code code, op;
   int unsignedp;
 
-  /* ??? Can't guarantee that expand_binop won't create pseudos.  */
-  if (no_new_pseudos)
-    return FALSE;
-
   /* ??? Reject modes with NaNs or signed zeros since we don't know how
      they will be resolved with an SMIN/SMAX.  It wouldn't be too hard
      to get the target to tell us...  */
@@ -1693,11 +1751,13 @@ noce_try_abs (struct noce_if_info *if_info)
   rtx cond, earliest, target, seq, a, b, c;
   int negate;
 
-  /* ??? Can't guarantee that expand_binop won't create pseudos.  */
-  if (no_new_pseudos)
+  /* Reject modes with signed zeros.  */
+  if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
     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))
@@ -1718,25 +1778,31 @@ 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
+         && BLOCK_NUM (insn) == BLOCK_NUM (earliest)
+         && (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
@@ -1808,9 +1874,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;
-
-  if (no_new_pseudos)
-    return FALSE;
+  bool t_unconditional;
 
   cond = if_info->cond;
   code = GET_CODE (cond);
@@ -1839,11 +1903,19 @@ noce_try_sign_mask (struct noce_if_info *if_info)
   if (GET_MODE (m) != mode)
     return FALSE;
 
-  /* This is only profitable if T is cheap, or T is unconditionally
-     executed/evaluated in the original insn sequence.  */
-  if (rtx_cost (t, SET) >= COSTS_N_INSNS (2)
-      && (!if_info->b_unconditional
-          || t != if_info->b))
+  /* This is only profitable if T is unconditionally executed/evaluated in the
+     original insn sequence or T is cheap.  The former happens if B is the
+     non-zero (T) value and if INSN_B was taken from TEST_BB, or there was no
+     INSN_B which can happen for e.g. conditional stores to memory.  For the
+     cost computation use the block TEST_BB where the evaluation will end up
+     after the transformation.  */
+  t_unconditional =
+    (t == if_info->b
+     && (if_info->insn_b == NULL_RTX
+        || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb));
+  if (!(t_unconditional
+       || (rtx_cost (t, SET, optimize_bb_for_speed_p (if_info->test_bb))
+           < COSTS_N_INSNS (2))))
     return FALSE;
 
   start_sequence ();
@@ -1901,12 +1973,14 @@ noce_try_bitop (struct noce_if_info *if_info)
   if (GET_CODE (cond) == ZERO_EXTRACT)
     {
       if (XEXP (cond, 1) != const1_rtx
-         || GET_CODE (XEXP (cond, 2)) != CONST_INT
+         || !CONST_INT_P (XEXP (cond, 2))
          || ! 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)
+      if (BITS_BIG_ENDIAN)
+       bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
+      if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
        return FALSE;
     }
   else
@@ -1917,7 +1991,7 @@ noce_try_bitop (struct noce_if_info *if_info)
     {
       /* Check for "if (X & C) x = x op C".  */
       if (! rtx_equal_p (x, XEXP (a, 0))
-          || GET_CODE (XEXP (a, 1)) != CONST_INT
+          || !CONST_INT_P (XEXP (a, 1))
          || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
             != (unsigned HOST_WIDE_INT) 1 << bitnum)
         return FALSE;
@@ -1943,7 +2017,7 @@ noce_try_bitop (struct noce_if_info *if_info)
     {
       /* Check for "if (X & C) x &= ~C".  */
       if (! rtx_equal_p (x, XEXP (a, 0))
-         || GET_CODE (XEXP (a, 1)) != CONST_INT
+         || !CONST_INT_P (XEXP (a, 1))
          || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
             != (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode)))
         return FALSE;
@@ -1971,10 +2045,13 @@ noce_try_bitop (struct noce_if_info *if_info)
 
 
 /* Similar to get_condition, only the resulting condition must be
-   valid at JUMP, instead of at EARLIEST.  */
+   valid at JUMP, instead of at EARLIEST.
+
+   If THEN_ELSE_REVERSED is true, the fallthrough does not go to the
+   THEN block of the caller, and we have to reverse the condition.  */
 
 static rtx
-noce_get_condition (rtx jump, rtx *earliest)
+noce_get_condition (rtx jump, rtx *earliest, bool then_else_reversed)
 {
   rtx cond, set, tmp;
   bool reverse;
@@ -1989,6 +2066,12 @@ noce_get_condition (rtx jump, rtx *earliest)
   reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
             && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump));
 
+  /* We may have to reverse because the caller's if block is not canonical,
+     i.e. the THEN block isn't the fallthrough block for the TEST block
+     (see find_if_header).  */
+  if (then_else_reversed)
+    reverse = !reverse;
+
   /* If the condition variable is a register and is MODE_INT, accept it.  */
 
   cond = XEXP (SET_SRC (set), 0);
@@ -2012,7 +2095,7 @@ noce_get_condition (rtx jump, rtx *earliest)
 /* Return true if OP is ok for if-then-else processing.  */
 
 static int
-noce_operand_ok (rtx op)
+noce_operand_ok (const_rtx op)
 {
   /* We special-case memories, so handle any of them with
      no address side effects.  */
@@ -2028,7 +2111,7 @@ noce_operand_ok (rtx op)
 /* Return true if a write into MEM may trap or fault.  */
 
 static bool
-noce_mem_write_may_trap_or_fault_p (rtx mem)
+noce_mem_write_may_trap_or_fault_p (const_rtx mem)
 {
   rtx addr;
 
@@ -2059,7 +2142,7 @@ noce_mem_write_may_trap_or_fault_p (rtx mem)
        addr = XEXP (addr, 1);
        break;
       case PLUS:
-       if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
+       if (CONST_INT_P (XEXP (addr, 1)))
          addr = XEXP (addr, 0);
        else
          return false;
@@ -2078,21 +2161,60 @@ noce_mem_write_may_trap_or_fault_p (rtx mem)
   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.  */
+/* Return whether we can use store speculation for MEM.  TOP_BB is the
+   basic block above the conditional block where we are considering
+   doing the speculative store.  We look for whether MEM is set
+   unconditionally later in the function.  */
+
+static bool
+noce_can_store_speculate_p (basic_block top_bb, const_rtx mem)
+{
+  basic_block dominator;
+
+  for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
+       dominator != NULL;
+       dominator = get_immediate_dominator (CDI_POST_DOMINATORS, dominator))
+    {
+      rtx insn;
+
+      FOR_BB_INSNS (dominator, insn)
+       {
+         /* If we see something that might be a memory barrier, we
+            have to stop looking.  Even if the MEM is set later in
+            the function, we still don't want to set it
+            unconditionally before the barrier.  */
+         if (INSN_P (insn)
+             && (volatile_insn_p (PATTERN (insn))
+                 || (CALL_P (insn) && (!RTL_CONST_CALL_P (insn)))))
+           return false;
+
+         if (memory_modified_in_insn_p (mem, insn))
+           return true;
+         if (modified_in_p (XEXP (mem, 0), insn))
+           return false;
+
+       }
+    }
+
+  return false;
+}
+
+/* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
+   it without using conditional execution.  Return TRUE if we were successful
+   at converting the block.  */
 
 static int
-noce_process_if_block (struct ce_if_block * ce_info)
+noce_process_if_block (struct noce_if_info *if_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 */
-  struct noce_if_info if_info;
+  basic_block test_bb = if_info->test_bb;      /* test block */
+  basic_block then_bb = if_info->then_bb;      /* THEN */
+  basic_block else_bb = if_info->else_bb;      /* ELSE or NULL */
+  basic_block join_bb = if_info->join_bb;      /* JOIN */
+  rtx jump = if_info->jump;
+  rtx cond = if_info->cond;
   rtx insn_a, insn_b;
   rtx set_a, set_b;
   rtx orig_x, x, a, b;
-  rtx jump, cond;
 
   /* We're looking for patterns of the form
 
@@ -2104,34 +2226,6 @@ 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))
-    return FALSE;
-
-  /* We must be comparing objects whose modes imply the size.  */
-  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
-    return FALSE;
-
   /* Look for one of the potential sets.  */
   insn_a = first_active_insn (then_bb);
   if (! insn_a
@@ -2161,23 +2255,25 @@ noce_process_if_block (struct ce_if_block * ce_info)
     }
   else
     {
-      insn_b = prev_nonnote_insn (if_info.cond_earliest);
+      insn_b = prev_nonnote_insn (if_info->cond_earliest);
       /* We're going to be moving the evaluation of B down from above
         COND_EARLIEST to JUMP.  Make sure the relevant data is still
         intact.  */
       if (! insn_b
+         || BLOCK_NUM (insn_b) != BLOCK_NUM (if_info->cond_earliest)
          || !NONJUMP_INSN_P (insn_b)
          || (set_b = single_set (insn_b)) == NULL_RTX
          || ! rtx_equal_p (x, SET_DEST (set_b))
+         || ! noce_operand_ok (SET_SRC (set_b))
          || reg_overlap_mentioned_p (x, SET_SRC (set_b))
          || modified_between_p (SET_SRC (set_b),
-                                PREV_INSN (if_info.cond_earliest), jump)
+                                PREV_INSN (if_info->cond_earliest), jump)
          /* Likewise with X.  In particular this can happen when
             noce_get_condition looks farther back in the instruction
             stream than one might expect.  */
          || reg_overlap_mentioned_p (x, cond)
          || reg_overlap_mentioned_p (x, a)
-         || modified_between_p (x, PREV_INSN (if_info.cond_earliest), jump))
+         || modified_between_p (x, PREV_INSN (if_info->cond_earliest), jump))
        insn_b = set_b = NULL_RTX;
     }
 
@@ -2198,8 +2294,14 @@ noce_process_if_block (struct ce_if_block * ce_info)
       || (SMALL_REGISTER_CLASSES
          && REGNO (x) < FIRST_PSEUDO_REGISTER))
     {
-      if (no_new_pseudos || GET_MODE (x) == BLKmode)
+      if (GET_MODE (x) == BLKmode)
+       return FALSE;
+
+      if (GET_CODE (x) == ZERO_EXTRACT
+         && (!CONST_INT_P (XEXP (x, 1))
+             || !CONST_INT_P (XEXP (x, 2))))
        return FALSE;
+
       x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
                                 ? XEXP (x, 0) : x));
     }
@@ -2208,16 +2310,13 @@ noce_process_if_block (struct ce_if_block * ce_info)
   if (! noce_operand_ok (a) || ! noce_operand_ok (b))
     return FALSE;
 
+ retry:
   /* 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;
+  if_info->insn_a = insn_a;
+  if_info->insn_b = insn_b;
+  if_info->x = x;
+  if_info->a = a;
+  if_info->b = b;
 
   /* Try optimizations in some approximation of a useful order.  */
   /* ??? Should first look to see if X is live incoming at all.  If it
@@ -2255,115 +2354,515 @@ noce_process_if_block (struct ce_if_block * ce_info)
       goto success;
     }
 
-  /* Disallow the "if (...) x = a;" form (with an implicit "else x = x;")
-     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 (!set_b && MEM_P (orig_x))
+    {
+      /* Disallow the "if (...) x = a;" form (implicit "else x = x;")
+        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 (noce_mem_write_may_trap_or_fault_p (orig_x))
+       return FALSE;
+
+      /* Avoid store speculation: given "if (...) x = a" where x is a
+        MEM, we only want to do the store if x is always set
+        somewhere in the function.  This avoids cases like
+          if (pthread_mutex_trylock(mutex))
+            ++global_variable;
+        where we only want global_variable to be changed if the mutex
+        is held.  FIXME: This should ideally be expressed directly in
+        RTL somehow.  */
+      if (!noce_can_store_speculate_p (test_bb, orig_x))
+       return FALSE;
+    }
 
-  if (noce_try_move (&if_info))
+  if (noce_try_move (if_info))
     goto success;
-  if (noce_try_store_flag (&if_info))
+  if (noce_try_store_flag (if_info))
     goto success;
-  if (noce_try_bitop (&if_info))
+  if (noce_try_bitop (if_info))
     goto success;
-  if (noce_try_minmax (&if_info))
+  if (noce_try_minmax (if_info))
     goto success;
-  if (noce_try_abs (&if_info))
+  if (noce_try_abs (if_info))
     goto success;
   if (HAVE_conditional_move
-      && noce_try_cmove (&if_info))
+      && noce_try_cmove (if_info))
     goto success;
   if (! HAVE_conditional_execution)
     {
-      if (noce_try_store_flag_constants (&if_info))
+      if (noce_try_store_flag_constants (if_info))
        goto success;
-      if (noce_try_addcc (&if_info))
+      if (noce_try_addcc (if_info))
        goto success;
-      if (noce_try_store_flag_mask (&if_info))
+      if (noce_try_store_flag_mask (if_info))
        goto success;
       if (HAVE_conditional_move
-         && noce_try_cmove_arith (&if_info))
+         && noce_try_cmove_arith (if_info))
        goto success;
-      if (noce_try_sign_mask (&if_info))
+      if (noce_try_sign_mask (if_info))
        goto success;
     }
 
+  if (!else_bb && set_b)
+    {
+      insn_b = set_b = NULL_RTX;
+      b = orig_x;
+      goto retry;
+    }
+
   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.  */
+  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;
 }
-\f
-/* Attempt to convert an IF-THEN or IF-THEN-ELSE block into
-   straight line code.  Return true if successful.  */
+
+/* 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
-process_if_block (struct ce_if_block * ce_info)
+check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, rtx cond)
 {
-  if (! reload_completed
-      && noce_process_if_block (ce_info))
-    return TRUE;
+  rtx insn;
 
-  if (HAVE_conditional_execution && reload_completed)
+   /* 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)
     {
-      /* If we have && and || tests, try to first handle combining the && and
-         || tests into the conditional code, and if that fails, go back and
-         handle it without the && and ||, which at present handles the && case
-         if there was no ELSE block.  */
-      if (cond_exec_process_if_block (ce_info, TRUE))
-       return TRUE;
+      rtx set, dest, src;
 
-      if (ce_info->num_multiple_test_blocks)
+      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
        {
-         cancel_changes (0);
+         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-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
+   it using only conditional moves.  Return TRUE if we were successful at
+   converting the block.  */
 
-         if (cond_exec_process_if_block (ce_info, FALSE))
-           return TRUE;
+static int
+cond_move_process_if_block (struct noce_if_info *if_info)
+{
+  basic_block test_bb = if_info->test_bb;
+  basic_block then_bb = if_info->then_bb;
+  basic_block else_bb = if_info->else_bb;
+  basic_block join_bb = if_info->join_bb;
+  rtx jump = if_info->jump;
+  rtx cond = if_info->cond;
+  rtx 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;
+
+  /* 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)))
+    {
+      VEC_free (int, heap, then_regs);
+      VEC_free (int, heap, else_regs);
+      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]))
+           {
+             VEC_free (int, heap, then_regs);
+             VEC_free (int, heap, else_regs);
+             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)
+    {
+      VEC_free (int, heap, then_regs);
+      VEC_free (int, heap, else_regs);
+      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 ();
+      VEC_free (int, heap, then_regs);
+      VEC_free (int, heap, else_regs);
+      return FALSE;
+    }
+  seq = end_ifcvt_sequence (if_info);
+  if (!seq)
+    {
+      VEC_free (int, heap, then_regs);
+      VEC_free (int, heap, else_regs);
+      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));
+
+  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
+/* Determine if a given basic block heads a simple IF-THEN-JOIN or an
+   IF-THEN-ELSE-JOIN block.
+
+   If so, we'll try to convert the insns to not require the branch,
+   using only transformations that do not require conditional execution.
+
+   Return TRUE if we were successful at converting the block.  */
+
+static int
+noce_find_if_block (basic_block test_bb,
+                   edge then_edge, edge else_edge,
+                   int pass)
+{
+  basic_block then_bb, else_bb, join_bb;
+  bool then_else_reversed = false;
+  rtx jump, cond;
+  rtx cond_earliest;
+  struct noce_if_info if_info;
+
+  /* We only ever should get here before reload.  */
+  gcc_assert (!reload_completed);
+
+  /* Recognize an IF-THEN-ELSE-JOIN block.  */
+  if (single_pred_p (then_edge->dest)
+      && single_succ_p (then_edge->dest)
+      && single_pred_p (else_edge->dest)
+      && single_succ_p (else_edge->dest)
+      && single_succ (then_edge->dest) == single_succ (else_edge->dest))
+    {
+      then_bb = then_edge->dest;
+      else_bb = else_edge->dest;
+      join_bb = single_succ (then_bb);
+    }
+  /* Recognize an IF-THEN-JOIN block.  */
+  else if (single_pred_p (then_edge->dest)
+          && single_succ_p (then_edge->dest)
+          && single_succ (then_edge->dest) == else_edge->dest)
+    {
+      then_bb = then_edge->dest;
+      else_bb = NULL_BLOCK;
+      join_bb = else_edge->dest;
+    }
+  /* Recognize an IF-ELSE-JOIN block.  We can have those because the order
+     of basic blocks in cfglayout mode does not matter, so the fallthrough
+     edge can go to any basic block (and not just to bb->next_bb, like in
+     cfgrtl mode).  */
+  else if (single_pred_p (else_edge->dest)
+          && single_succ_p (else_edge->dest)
+          && single_succ (else_edge->dest) == then_edge->dest)
+    {
+      /* The noce transformations do not apply to IF-ELSE-JOIN blocks.
+        To make this work, we have to invert the THEN and ELSE blocks
+        and reverse the jump condition.  */
+      then_bb = else_edge->dest;
+      else_bb = NULL_BLOCK;
+      join_bb = single_succ (then_bb);
+      then_else_reversed = true;
+    }
+  else
+    /* Not a form we can handle.  */
+    return FALSE;
+
+  /* The edges of the THEN and ELSE blocks cannot have complex edges.  */
+  if (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
+    return FALSE;
+  if (else_bb
+      && single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
+    return FALSE;
+
+  num_possible_if_blocks++;
+
+  if (dump_file)
+    {
+      fprintf (dump_file,
+              "\nIF-THEN%s-JOIN block found, pass %d, test %d, then %d",
+              (else_bb) ? "-ELSE" : "",
+              pass, test_bb->index, then_bb->index);
+
+      if (else_bb)
+       fprintf (dump_file, ", else %d", else_bb->index);
+
+      fprintf (dump_file, ", join %d\n", join_bb->index);
+    }
+
+  /* If the conditional jump is more than just a conditional
+     jump, then we can not do if-conversion on this block.  */
+  jump = BB_END (test_bb);
+  if (! onlyjump_p (jump))
+    return FALSE;
+
+  /* If this is not a standard conditional jump, we can't parse it.  */
+  cond = noce_get_condition (jump,
+                            &cond_earliest,
+                            then_else_reversed);
+  if (!cond)
+    return FALSE;
+
+  /* We must be comparing objects whose modes imply the size.  */
+  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
+    return FALSE;
+
+  /* Initialize an IF_INFO struct to pass around.  */
+  memset (&if_info, 0, sizeof if_info);
+  if_info.test_bb = test_bb;
+  if_info.then_bb = then_bb;
+  if_info.else_bb = else_bb;
+  if_info.join_bb = join_bb;
+  if_info.cond = cond;
+  if_info.cond_earliest = cond_earliest;
+  if_info.jump = jump;
+  if_info.then_else_reversed = then_else_reversed;
+  if_info.branch_cost = BRANCH_COST (optimize_bb_for_speed_p (test_bb),
+                                    predictable_edge_p (then_edge));
+
+  /* Do the real work.  */
+
+  if (noce_process_if_block (&if_info))
+    return TRUE;
+
+  if (HAVE_conditional_move
+      && cond_move_process_if_block (&if_info))
+    return TRUE;
+
   return FALSE;
 }
+\f
 
 /* Merge the blocks and mark for local life update.  */
 
@@ -2379,6 +2878,7 @@ merge_if_block (struct ce_if_block * ce_info)
   /* All block merging is done into the lower block numbers.  */
 
   combo_bb = test_bb;
+  df_set_bb_dirty (test_bb);
 
   /* Merge any basic blocks to handle && and || subtests.  Each of
      the blocks are on the fallthru path from the predecessor block.  */
@@ -2404,9 +2904,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++;
     }
@@ -2456,11 +2953,8 @@ merge_if_block (struct ce_if_block * ce_info)
   else if (EDGE_COUNT (join_bb->preds) < 2
           && 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);
-
+      /* We can merge the JOIN cleanly and update the dataflow try
+        again on this pass.*/
       merge_blocks (combo_bb, join_bb);
       num_true_changes++;
     }
@@ -2500,6 +2994,11 @@ find_if_header (basic_block test_bb, int pass)
   then_edge = EDGE_SUCC (test_bb, 0);
   else_edge = EDGE_SUCC (test_bb, 1);
 
+  if (df_get_bb_dirty (then_edge->dest))
+    return NULL;
+  if (df_get_bb_dirty (else_edge->dest))
+    return NULL;
+
   /* Neither edge should be abnormal.  */
   if ((then_edge->flags & EDGE_COMPLEX)
       || (else_edge->flags & EDGE_COMPLEX))
@@ -2533,14 +3032,20 @@ find_if_header (basic_block test_bb, int pass)
   IFCVT_INIT_EXTRA_FIELDS (&ce_info);
 #endif
 
-  if (find_if_block (&ce_info))
+  if (! reload_completed
+      && noce_find_if_block (test_bb, then_edge, else_edge, pass))
+    goto success;
+
+  if (HAVE_conditional_execution && reload_completed
+      && cond_exec_find_if_block (&ce_info))
     goto success;
 
-  if (HAVE_trap && HAVE_conditional_trap
+  if (HAVE_trap
+      && optab_handler (ctrap_optab, word_mode)->insn_code != CODE_FOR_nothing
       && find_cond_trap (test_bb, then_edge, else_edge))
     goto success;
 
-  if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY
+  if (dom_info_state (CDI_POST_DOMINATORS) >= DOM_NO_FAST_QUERY
       && (! HAVE_conditional_execution || reload_completed))
     {
       if (find_if_case_1 (test_bb, then_edge, else_edge))
@@ -2554,6 +3059,8 @@ find_if_header (basic_block test_bb, int pass)
  success:
   if (dump_file)
     fprintf (dump_file, "Conversion succeeded on pass %d.\n", pass);
+  /* Set this so we continue looking.  */
+  cond_exec_changed_p = TRUE;
   return ce_info.test_bb;
 }
 
@@ -2631,7 +3138,7 @@ block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb)
    Return TRUE if we were successful at converting the block.  */
 
 static int
-find_if_block (struct ce_if_block * ce_info)
+cond_exec_find_if_block (struct ce_if_block * ce_info)
 {
   basic_block test_bb = ce_info->test_bb;
   basic_block then_bb = ce_info->then_bb;
@@ -2643,11 +3150,14 @@ find_if_block (struct ce_if_block * ce_info)
 
   ce_info->last_test_bb = test_bb;
 
+  /* We only ever should get here after reload,
+     and only if we have conditional execution.  */
+  gcc_assert (HAVE_conditional_execution && reload_completed);
+
   /* Discover if any fall through predecessors of the current test basic block
      were && tests (which jump to the else block) or || tests (which jump to
      the then block).  */
-  if (HAVE_conditional_execution && reload_completed
-      && single_pred_p (test_bb)
+  if (single_pred_p (test_bb)
       && single_pred_edge (test_bb)->flags == EDGE_FALLTHRU)
     {
       basic_block bb = single_pred (test_bb);
@@ -2705,7 +3215,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)
     {
@@ -2723,7 +3233,7 @@ find_if_block (struct ce_if_block * ce_info)
   if (EDGE_COUNT (then_bb->succs) > 0
       && (!single_succ_p (then_bb)
           || (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
-         || (flow2_completed && tablejump_p (BB_END (then_bb), NULL, NULL))))
+         || (epilogue_completed && tablejump_p (BB_END (then_bb), NULL, NULL))))
     return FALSE;
 
   /* If the THEN block has no successors, conditional execution can still
@@ -2770,7 +3280,7 @@ find_if_block (struct ce_if_block * ce_info)
           && 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)))
+          && ! (epilogue_completed && tablejump_p (BB_END (else_bb), NULL, NULL)))
     join_bb = single_succ (else_bb);
 
   /* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination.  */
@@ -2833,10 +3343,26 @@ find_if_block (struct ce_if_block * ce_info)
     }
 
   /* Do the real work.  */
+
   ce_info->else_bb = else_bb;
   ce_info->join_bb = join_bb;
 
-  return process_if_block (ce_info);
+  /* If we have && and || tests, try to first handle combining the && and ||
+     tests into the conditional code, and if that fails, go back and handle
+     it without the && and ||, which at present handles the && case if there
+     was no ELSE block.  */
+  if (cond_exec_process_if_block (ce_info, TRUE))
+    return TRUE;
+
+  if (ce_info->num_multiple_test_blocks)
+    {
+      cancel_changes (0);
+
+      if (cond_exec_process_if_block (ce_info, FALSE))
+       return TRUE;
+    }
+
+  return FALSE;
 }
 
 /* Convert a branch over a trap, or a branch
@@ -2869,7 +3395,7 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
 
   /* If this is not a standard conditional jump, we can't parse it.  */
   jump = BB_END (test_bb);
-  cond = noce_get_condition (jump, &cond_earliest);
+  cond = noce_get_condition (jump, &cond_earliest, false);
   if (! cond)
     return FALSE;
 
@@ -2892,35 +3418,30 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
     }
 
   /* Attempt to generate the conditional trap.  */
-  seq = gen_cond_trap (code, XEXP (cond, 0),
-                      XEXP (cond, 1),
+  seq = gen_cond_trap (code, copy_rtx (XEXP (cond, 0)),
+                      copy_rtx (XEXP (cond, 1)),
                       TRAP_CODE (PATTERN (trap)));
   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);
+  df_set_bb_dirty (test_bb);
+  df_set_bb_dirty (then_bb);
+  df_set_bb_dirty (else_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)
+  if (EDGE_COUNT (trap_bb->preds) == 0)
     {
-      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;
@@ -2930,10 +3451,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;
 }
 
@@ -3044,25 +3571,26 @@ static int
 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;
+  basic_block else_bb = else_edge->dest;
+  basic_block new_bb;
   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
      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;
 
@@ -3089,7 +3617,9 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
             test_bb->index, then_bb->index);
 
   /* THEN is small.  */
-  if (! cheap_bb_rtx_cost_p (then_bb, COSTS_N_INSNS (BRANCH_COST)))
+  if (! cheap_bb_rtx_cost_p (then_bb,
+       COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (then_edge->src),
+                                   predictable_edge_p (then_edge)))))
     return FALSE;
 
   /* Registers set are dead, or are predicable.  */
@@ -3100,11 +3630,6 @@ find_if_case_1 (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->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.  */
@@ -3118,7 +3643,10 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
     }
   else
     new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb),
-                                             else_bb);
+                                            else_bb);
+
+  df_set_bb_dirty (test_bb);
+  df_set_bb_dirty (else_bb);
 
   then_bb_index = then_bb->index;
   delete_basic_block (then_bb);
@@ -3127,15 +3655,12 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
      block we removed.  */
   if (new_bb)
     {
-      new_bb->index = then_bb_index;
-      BASIC_BLOCK (then_bb_index) = new_bb;
+      df_bb_replace (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).  */
       BB_COPY_PARTITION (new_bb, test_bb);
     }
-  /* We've possibly created jump to next insn, cleanup_cfg will solve that
-     later.  */
 
   num_true_changes++;
   num_updated_if_blocks++;
@@ -3156,19 +3681,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;
 
@@ -3187,14 +3712,14 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
     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))
     ;
@@ -3208,7 +3733,9 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
             test_bb->index, else_bb->index);
 
   /* ELSE is small.  */
-  if (! cheap_bb_rtx_cost_p (else_bb, COSTS_N_INSNS (BRANCH_COST)))
+  if (! cheap_bb_rtx_cost_p (else_bb, 
+       COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (else_edge->src),
+                                   predictable_edge_p (else_edge)))))
     return FALSE;
 
   /* Registers set are dead, or are predicable.  */
@@ -3218,10 +3745,8 @@ 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->il.rtl->global_live_at_end,
-             then_bb->il.rtl->global_live_at_start,
-             else_bb->il.rtl->global_live_at_end);
-
+  df_set_bb_dirty (test_bb);
+  df_set_bb_dirty (then_bb);
   delete_basic_block (else_bb);
 
   num_true_changes++;
@@ -3255,6 +3780,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
                    basic_block other_bb, basic_block new_dest, int reversep)
 {
   rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX;
+  /* Number of pending changes.  */
+  int n_validated_changes = 0;
 
   jump = BB_END (test_bb);
 
@@ -3262,6 +3789,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))
@@ -3316,22 +3850,24 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
            prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
        }
 
-      if (! cond_exec_process_insns ((ce_if_block_t *)0, head, end, cond,
-                                    prob_val, 0))
-       goto cancel;
+      if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0)
+         && verify_changes (0))
+       n_validated_changes = num_validated_changes ();
+      else
+       cancel_changes (0);
 
       earliest = jump;
     }
-  else
 #endif
+  /* Try the NCE path if the CE path did not result in any changes.  */
+  if (n_validated_changes == 0)
     {
       /* In the non-conditional execution case, we have to verify that there
         are no trapping operations, no calls, no references to memory, and
         that any registers modified are dead at the branch site.  */
 
       rtx insn, cond, prev;
-      regset merge_set, tmp, test_live, test_set;
-      struct propagate_block_info *pbi;
+      bitmap merge_set, test_live, test_set;
       unsigned i, fail = 0;
       bitmap_iterator bi;
 
@@ -3361,7 +3897,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
        return FALSE;
 
       /* Find the extent of the conditional.  */
-      cond = noce_get_condition (jump, &earliest);
+      cond = noce_get_condition (jump, &earliest, false);
       if (! cond)
        return FALSE;
 
@@ -3371,10 +3907,9 @@ 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 = 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);
+      merge_set = BITMAP_ALLOC (&reg_obstack);
+      test_live = BITMAP_ALLOC (&reg_obstack);
+      test_set = BITMAP_ALLOC (&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,
@@ -3383,11 +3918,21 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
         expander called from noce_emit_cmove), we must resize the
         array first.  */
       if (max_regno < max_reg_num ())
+       max_regno = max_reg_num ();
+
+      FOR_BB_INSNS (merge_bb, insn)
        {
-         max_regno = max_reg_num ();
-         allocate_reg_info (max_regno, FALSE, FALSE);
+         if (INSN_P (insn))
+           {
+             unsigned int uid = INSN_UID (insn);
+             df_ref *def_rec;
+             for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+               {
+                 df_ref def = *def_rec;
+                 bitmap_set_bit (merge_set, DF_REF_REGNO (def));
+               }
+           }
        }
-      propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
 
       /* For small register class machines, don't lengthen lifetimes of
         hard registers before reload.  */
@@ -3401,39 +3946,40 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
                fail = 1;
            }
        }
-
+      
       /* 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->il.rtl->global_live_at_start);
-      pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
-                                      0);
-
+      
+      /* The loop below takes the set of live registers 
+         after JUMP, and calculates the live set before EARLIEST. */
+      bitmap_copy (test_live, df_get_live_in (other_bb));
+      df_simulate_initialize_backwards (test_bb, test_live);
       for (insn = jump; ; insn = prev)
        {
-         prev = propagate_one_insn (pbi, insn);
+         if (INSN_P (insn))
+           {
+             df_simulate_find_defs (insn, test_set);
+             df_simulate_one_insn_backwards (test_bb, insn, test_live);
+           }
+         prev = PREV_INSN (insn);
          if (insn == earliest)
            break;
        }
 
-      free_propagate_block_info (pbi);
-
       /* We can perform the transformation if
           MERGE_SET & (TEST_SET | TEST_LIVE)
         and
-          TEST_SET & merge_bb->il.rtl->global_live_at_start
+          TEST_SET & DF_LIVE_IN (merge_bb)
         are empty.  */
 
       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))
+         || bitmap_intersect_p (test_set, df_get_live_in (merge_bb)))
        fail = 1;
 
-      FREE_REG_SET (tmp);
-      FREE_REG_SET (merge_set);
-      FREE_REG_SET (test_live);
-      FREE_REG_SET (test_set);
+      BITMAP_FREE (merge_set);
+      BITMAP_FREE (test_live);
+      BITMAP_FREE (test_set);
 
       if (fail)
        return FALSE;
@@ -3454,12 +4000,14 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
        goto cancel;
     }
 
-  if (! apply_change_group ())
-    return FALSE;
+  if (verify_changes (n_validated_changes))
+    confirm_change_group ();
+  else
+    goto cancel;
 
   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)
@@ -3484,9 +4032,6 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
       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;
@@ -3525,35 +4070,31 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
 \f
 /* Main entry point for all if-conversion.  */
 
-void
-if_convert (int x_life_data_ok)
+static void
+if_convert (void)
 {
   basic_block bb;
   int pass;
 
+  if (optimize == 1)
+    {
+      df_live_add_problem ();
+      df_live_set_all_dirty ();
+    }
+
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
   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))
-    {
-      struct loops loops;
 
-      flow_loops_find (&loops);
-      mark_loop_exit_edges (&loops);
-      flow_loops_free (&loops);
-      free_dominance_info (CDI_DOMINATORS);
-    }
+  loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+  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)
-    calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* Compute postdominators.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
 
-  if (life_data_ok)
-    clear_bb_flags ();
+  df_set_flags (DF_LR_RUN_DCE);
 
   /* Go through each of the basic blocks looking for things to convert.  If we
      have conditional execution, we make multiple passes to allow us to handle
@@ -3561,6 +4102,9 @@ if_convert (int x_life_data_ok)
   pass = 0;
   do
     {
+      df_analyze ();
+      /* Only need to do dce on the first pass.  */
+      df_clear_flags (DF_LR_RUN_DCE);
       cond_exec_changed_p = FALSE;
       pass++;
 
@@ -3571,9 +4115,10 @@ if_convert (int x_life_data_ok)
 
       FOR_EACH_BB (bb)
        {
-         basic_block new_bb;
-         while ((new_bb = find_if_header (bb, pass)))
-           bb = new_bb;
+          basic_block new_bb;
+          while (!df_get_bb_dirty (bb) 
+                 && (new_bb = find_if_header (bb, pass)) != NULL)
+            bb = new_bb;
        }
 
 #ifdef IFCVT_MULTIPLE_DUMPS
@@ -3595,19 +4140,9 @@ if_convert (int x_life_data_ok)
 
   clear_aux_for_blocks ();
 
-  /* Rebuild life info for basic blocks that require it.  */
-  if (num_true_changes && life_data_ok)
-    {
-      /* If we allocated new pseudos, we must resize the array for sched1.  */
-      if (max_regno < max_reg_num ())
-       {
-         max_regno = max_reg_num ();
-         allocate_reg_info (max_regno, FALSE, FALSE);
-       }
-      update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
-                                       PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
-                                       | PROP_KILL_DEAD_CODE);
-    }
+  /* If we allocated new pseudos, we must resize the array for sched1.  */
+  if (max_regno < max_reg_num ())
+    max_regno = max_reg_num ();
 
   /* Write the final stats.  */
   if (dump_file && num_possible_if_blocks > 0)
@@ -3623,6 +4158,9 @@ if_convert (int x_life_data_ok)
               num_true_changes);
     }
 
+  if (optimize == 1)
+    df_remove_problem (df_live);
+
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
@@ -3631,30 +4169,30 @@ if_convert (int x_life_data_ok)
 static bool
 gate_handle_if_conversion (void)
 {
-  return (optimize > 0);
+  return (optimize > 0)
+    && dbg_cnt (if_conversion);
 }
 
 /* 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);
+      if_convert ();
     }
 
-  timevar_push (TV_JUMP);
-  cleanup_cfg (CLEANUP_EXPENSIVE);
-  reg_scan (get_insns (), max_reg_num ());
-  timevar_pop (TV_JUMP);
+  cleanup_cfg (0);
+  return 0;
 }
 
-struct tree_opt_pass pass_rtl_ifcvt =
+struct rtl_opt_pass pass_rtl_ifcvt =
 {
+ {
+  RTL_PASS,
   "ce1",                                /* name */
   gate_handle_if_conversion,            /* gate */
   rest_of_handle_if_conversion,         /* execute */
@@ -3666,29 +4204,32 @@ struct tree_opt_pass pass_rtl_ifcvt =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  'C'                                   /* letter */
+  TODO_df_finish | TODO_verify_rtl_sharing |
+  TODO_dump_func                        /* todo_flags_finish */
+ }
 };
 
 static bool
 gate_handle_if_after_combine (void)
 {
-  return (optimize > 0 && flag_if_conversion);
+  return optimize > 0 && flag_if_conversion
+    && dbg_cnt (if_after_combine);
 }
 
 
 /* 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;
+  if_convert ();
+  return 0;
 }
 
-struct tree_opt_pass pass_if_after_combine =
+struct rtl_opt_pass pass_if_after_combine =
 {
+ {
+  RTL_PASS,
   "ce2",                                /* name */
   gate_handle_if_after_combine,         /* gate */
   rest_of_handle_if_after_combine,      /* execute */
@@ -3700,33 +4241,32 @@ struct tree_opt_pass pass_if_after_combine =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'C'                                   /* letter */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
 
 
 static bool
 gate_handle_if_after_reload (void)
 {
-  return (optimize > 0);
+  return optimize > 0 && flag_if_conversion2
+    && dbg_cnt (if_after_reload);
 }
 
-static void
+static unsigned int
 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);
+  if_convert ();
+  return 0;
 }
 
 
-struct tree_opt_pass pass_if_after_reload =
+struct rtl_opt_pass pass_if_after_reload =
 {
+ {
+  RTL_PASS,
   "ce3",                                /* name */
   gate_handle_if_after_reload,          /* gate */
   rest_of_handle_if_after_reload,       /* execute */
@@ -3738,9 +4278,8 @@ struct tree_opt_pass pass_if_after_reload =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'E'                                   /* letter */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
-
-