]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ifcvt.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / ifcvt.c
index 6e20557d52b5821317d25a3fdaa933af2e961925..017944f4f79aa687f89788f1ea0a78c0abd05298 100644 (file)
@@ -1,5 +1,5 @@
 /* If-conversion support.
-   Copyright (C) 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 2000-2021 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "expmed.h"
+#include "optabs.h"
 #include "regs.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "flags.h"
-#include "insn-config.h"
+#include "emit-rtl.h"
 #include "recog.h"
-#include "except.h"
-#include "predict.h"
-#include "dominance.h"
-#include "cfg.h"
+
 #include "cfgrtl.h"
 #include "cfganal.h"
 #include "cfgcleanup.h"
-#include "basic-block.h"
-#include "symtab.h"
-#include "alias.h"
-#include "tree.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
 #include "expr.h"
 #include "output.h"
-#include "insn-codes.h"
-#include "optabs.h"
-#include "diagnostic-core.h"
-#include "tm_p.h"
 #include "cfgloop.h"
-#include "target.h"
 #include "tree-pass.h"
-#include "df.h"
 #include "dbgcnt.h"
 #include "shrink-wrap.h"
+#include "rtl-iter.h"
 #include "ifcvt.h"
 
-#ifndef HAVE_incscc
-#define HAVE_incscc 0
-#endif
-#ifndef HAVE_decscc
-#define HAVE_decscc 0
-#endif
-#ifndef HAVE_trap
-#define HAVE_trap 0
-#endif
-
 #ifndef MAX_CONDITIONAL_EXECUTE
 #define MAX_CONDITIONAL_EXECUTE \
   (BRANCH_COST (optimize_function_for_speed_p (cfun), false) \
    + 1)
 #endif
 
-#ifndef HAVE_cbranchcc4
-#define HAVE_cbranchcc4 0
-#endif
-
 #define IFCVT_MULTIPLE_DUMPS 1
 
 #define NULL_BLOCK     ((basic_block) NULL)
@@ -88,6 +59,9 @@
 /* True if after combine pass.  */
 static bool ifcvt_after_combine;
 
+/* True if the target has the cbranchcc4 optab.  */
+static bool have_cbranchcc4;
+
 /* # of IF-THEN or IF-THEN-ELSE blocks we looked at  */
 static int num_possible_if_blocks;
 
@@ -103,14 +77,12 @@ static int cond_exec_changed_p;
 
 /* Forward references.  */
 static int count_bb_insns (const_basic_block);
-static bool cheap_bb_rtx_cost_p (const_basic_block, int, int);
+static bool cheap_bb_rtx_cost_p (const_basic_block, profile_probability, int);
 static rtx_insn *first_active_insn (basic_block);
 static rtx_insn *last_active_insn (basic_block, int);
 static rtx_insn *find_active_insn_before (basic_block, rtx_insn *);
 static rtx_insn *find_active_insn_after (basic_block, rtx_insn *);
 static basic_block block_fallthru (basic_block);
-static int cond_exec_process_insns (ce_if_block *, rtx_insn *, rtx, rtx, int,
-                                   int);
 static rtx cond_exec_get_condition (rtx_insn *);
 static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool);
 static int noce_operand_ok (const_rtx);
@@ -148,7 +120,7 @@ count_bb_insns (const_basic_block bb)
   return count;
 }
 
-/* Determine whether the total insn_rtx_cost on non-jump insns in
+/* Determine whether the total insn_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. 
 
@@ -157,14 +129,17 @@ count_bb_insns (const_basic_block bb)
    plus a small fudge factor.  */
 
 static bool
-cheap_bb_rtx_cost_p (const_basic_block bb, int scale, int max_cost)
+cheap_bb_rtx_cost_p (const_basic_block bb,
+                    profile_probability prob, int max_cost)
 {
   int count = 0;
   rtx_insn *insn = BB_HEAD (bb);
   bool speed = optimize_bb_for_speed_p (bb);
+  int scale = prob.initialized_p () ? prob.to_reg_br_prob_base ()
+             : REG_BR_PROB_BASE;
 
   /* Set scale to REG_BR_PROB_BASE to void the identical scaling
-     applied to insn_rtx_cost when optimizing for size.  Only do
+     applied to insn_cost when optimizing for size.  Only do
      this after combine because if-conversion might interfere with
      passes before combine.
 
@@ -187,7 +162,7 @@ cheap_bb_rtx_cost_p (const_basic_block bb, int scale, int max_cost)
     {
       if (NONJUMP_INSN_P (insn))
        {
-         int cost = insn_rtx_cost (PATTERN (insn), speed) * REG_BR_PROB_BASE;
+         int cost = insn_cost (insn, speed) * REG_BR_PROB_BASE;
          if (cost == 0)
            return false;
 
@@ -357,7 +332,8 @@ cond_exec_process_insns (ce_if_block *ce_info ATTRIBUTE_UNUSED,
                         /* if block information */rtx_insn *start,
                         /* first insn to look at */rtx end,
                         /* last insn to look at */rtx test,
-                        /* conditional execution test */int prob_val,
+                        /* conditional execution test */profile_probability
+                                                           prob_val,
                         /* probability of branch taken. */int mod_ok)
 {
   int must_be_last = FALSE;
@@ -432,10 +408,11 @@ cond_exec_process_insns (ce_if_block *ce_info ATTRIBUTE_UNUSED,
 
       validate_change (insn, &PATTERN (insn), pattern, 1);
 
-      if (CALL_P (insn) && prob_val >= 0)
+      if (CALL_P (insn) && prob_val.initialized_p ())
        validate_change (insn, &REG_NOTES (insn),
                         gen_rtx_INT_LIST ((machine_mode) REG_BR_PROB,
-                                          prob_val, REG_NOTES (insn)), 1);
+                                          prob_val.to_reg_br_prob_note (),
+                                          REG_NOTES (insn)), 1);
 
     insn_done:
       if (insn == end)
@@ -461,7 +438,7 @@ cond_exec_get_condition (rtx_insn *jump)
   /* If this branches to JUMP_LABEL when the condition is false,
      reverse the condition.  */
   if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
-      && LABEL_REF_LABEL (XEXP (test_if, 2)) == JUMP_LABEL (jump))
+      && label_ref_label (XEXP (test_if, 2)) == JUMP_LABEL (jump))
     {
       enum rtx_code rev = reversed_comparison_code (cond, jump);
       if (rev == UNKNOWN)
@@ -494,8 +471,8 @@ cond_exec_process_if_block (ce_if_block * ce_info,
   int then_mod_ok;             /* whether conditional mods are ok in THEN */
   rtx true_expr;               /* test for else block insns */
   rtx false_expr;              /* test for then block insns */
-  int true_prob_val;           /* probability of else block */
-  int false_prob_val;          /* probability of then block */
+  profile_probability true_prob_val;/* probability of else block */
+  profile_probability false_prob_val;/* probability of then block */
   rtx_insn *then_last_head = NULL;     /* Last match at the head of THEN */
   rtx_insn *else_last_head = NULL;     /* Last match at the head of ELSE */
   rtx_insn *then_first_tail = NULL;    /* First match at the tail of THEN */
@@ -525,7 +502,7 @@ cond_exec_process_if_block (ce_if_block * ce_info,
     return FALSE;
 
   /* If the conditional jump is more than just a conditional jump,
-     then we can not do conditional execution conversion on this block.  */
+     then we cannot do conditional execution conversion on this block.  */
   if (! onlyjump_p (BB_END (test_bb)))
     return FALSE;
 
@@ -640,13 +617,13 @@ cond_exec_process_if_block (ce_if_block * ce_info,
   note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
   if (note)
     {
-      true_prob_val = XINT (note, 0);
-      false_prob_val = REG_BR_PROB_BASE - true_prob_val;
+      true_prob_val = profile_probability::from_reg_br_prob_note (XINT (note, 0));
+      false_prob_val = true_prob_val.invert ();
     }
   else
     {
-      true_prob_val = -1;
-      false_prob_val = -1;
+      true_prob_val = profile_probability::uninitialized ();
+      false_prob_val = profile_probability::uninitialized ();
     }
 
   /* If we have && or || tests, do them here.  These tests are in the adjacent
@@ -674,7 +651,7 @@ cond_exec_process_if_block (ce_if_block * ce_info,
            goto fail;
 
          /* If the conditional jump is more than just a conditional jump, then
-            we can not do conditional execution conversion on this block.  */
+            we cannot do conditional execution conversion on this block.  */
          if (! onlyjump_p (BB_END (bb)))
            goto fail;
 
@@ -766,7 +743,7 @@ cond_exec_process_if_block (ce_if_block * ce_info,
       rtx_insn *from = then_first_tail;
       if (!INSN_P (from))
        from = find_active_insn_after (then_bb, from);
-      delete_insn_chain (from, BB_END (then_bb), false);
+      delete_insn_chain (from, get_last_bb_insn (then_bb), false);
     }
   if (else_last_head)
     delete_insn_chain (first_active_insn (else_bb), else_last_head, false);
@@ -785,52 +762,9 @@ cond_exec_process_if_block (ce_if_block * ce_info,
   return FALSE;
 }
 \f
-/* Used by noce_process_if_block to communicate with its subroutines.
-
-   The subroutines know that A and B may be evaluated freely.  They
-   know that X is a register.  They should insert new instructions
-   before cond_earliest.  */
-
-struct noce_if_info
-{
-  /* 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_insn *jump;
-
-  /* The jump condition.  */
-  rtx cond;
-
-  /* New insns should be inserted before this one.  */
-  rtx_insn *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 *insn_a, *insn_b;
-
-  /* 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);
 static int noce_try_move (struct noce_if_info *);
+static int noce_try_ifelse_collapse (struct noce_if_info *);
 static int noce_try_store_flag (struct noce_if_info *);
 static int noce_try_addcc (struct noce_if_info *);
 static int noce_try_store_flag_constants (struct noce_if_info *);
@@ -844,6 +778,39 @@ static int noce_try_minmax (struct noce_if_info *);
 static int noce_try_abs (struct noce_if_info *);
 static int noce_try_sign_mask (struct noce_if_info *);
 
+/* Return the comparison code for reversed condition for IF_INFO,
+   or UNKNOWN if reversing the condition is not possible.  */
+
+static inline enum rtx_code
+noce_reversed_cond_code (struct noce_if_info *if_info)
+{
+  if (if_info->rev_cond)
+    return GET_CODE (if_info->rev_cond);
+  return reversed_comparison_code (if_info->cond, if_info->jump);
+}
+
+/* Return true if SEQ is a good candidate as a replacement for the
+   if-convertible sequence described in IF_INFO.
+   This is the default implementation that targets can override
+   through a target hook.  */
+
+bool
+default_noce_conversion_profitable_p (rtx_insn *seq,
+                                     struct noce_if_info *if_info)
+{
+  bool speed_p = if_info->speed_p;
+
+  /* Cost up the new sequence.  */
+  unsigned int cost = seq_cost (seq, speed_p);
+
+  if (cost <= if_info->original_cost)
+    return true;
+
+  /* When compiling for size, we can make a reasonably accurately guess
+     at the size growth.  When compiling for speed, use the maximum.  */
+  return speed_p && cost <= if_info->max_seq_cost;
+}
+
 /* Helper function for noce_try_store_flag*.  */
 
 static rtx
@@ -865,11 +832,19 @@ noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
       rtx set = pc_set (if_info->jump);
       cond = XEXP (SET_SRC (set), 0);
       if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
-         && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump))
+         && label_ref_label (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump))
        reversep = !reversep;
       if (if_info->then_else_reversed)
        reversep = !reversep;
     }
+  else if (reversep
+          && if_info->rev_cond
+          && general_operand (XEXP (if_info->rev_cond, 0), VOIDmode)
+          && general_operand (XEXP (if_info->rev_cond, 1), VOIDmode))
+    {
+      cond = if_info->rev_cond;
+      reversep = false;
+    }
 
   if (reversep)
     code = reversed_comparison_code (cond, if_info->jump);
@@ -880,7 +855,7 @@ noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
       && (normalize == 0 || STORE_FLAG_VALUE == normalize))
     {
       rtx src = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
-                           XEXP (cond, 1));
+                               XEXP (cond, 1));
       rtx set = gen_rtx_SET (x, src);
 
       start_sequence ();
@@ -910,6 +885,60 @@ noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
                           || code == GEU || code == GTU), normalize);
 }
 
+/* Return true if X can be safely forced into a register by copy_to_mode_reg
+   / force_operand.  */
+
+static bool
+noce_can_force_operand (rtx x)
+{
+  if (general_operand (x, VOIDmode))
+    return true;
+  if (SUBREG_P (x))
+    {
+      if (!noce_can_force_operand (SUBREG_REG (x)))
+       return false;
+      return true;
+    }
+  if (ARITHMETIC_P (x))
+    {
+      if (!noce_can_force_operand (XEXP (x, 0))
+         || !noce_can_force_operand (XEXP (x, 1)))
+       return false;
+      switch (GET_CODE (x))
+       {
+       case MULT:
+       case DIV:
+       case MOD:
+       case UDIV:
+       case UMOD:
+         return true;
+       default:
+         return code_to_optab (GET_CODE (x));
+       }
+    }
+  if (UNARY_P (x))
+    {
+      if (!noce_can_force_operand (XEXP (x, 0)))
+       return false;
+      switch (GET_CODE (x))
+       {
+       case ZERO_EXTEND:
+       case SIGN_EXTEND:
+       case TRUNCATE:
+       case FLOAT_EXTEND:
+       case FLOAT_TRUNCATE:
+       case FIX:
+       case UNSIGNED_FIX:
+       case FLOAT:
+       case UNSIGNED_FLOAT:
+         return true;
+       default:
+         return code_to_optab (GET_CODE (x));
+       }
+    }
+  return false;
+}
+
 /* Emit instruction to move an rtx, possibly into STRICT_LOW_PART.
    X is the destination/target and Y is the value to copy.  */
 
@@ -918,7 +947,7 @@ noce_emit_move_insn (rtx x, rtx y)
 {
   machine_mode outmode;
   rtx outer, inner;
-  int bitpos;
+  poly_int64 bitpos;
 
   if (GET_CODE (x) != STRICT_LOW_PART)
     {
@@ -960,7 +989,7 @@ noce_emit_move_insn (rtx x, rtx y)
                }
 
              gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
-             store_bit_field (op, size, start, 0, 0, GET_MODE (x), y);
+             store_bit_field (op, size, start, 0, 0, GET_MODE (x), y, false);
              return;
            }
 
@@ -968,7 +997,7 @@ noce_emit_move_insn (rtx x, rtx y)
            {
            case RTX_UNARY:
              ot = code_to_optab (GET_CODE (y));
-             if (ot)
+             if (ot && noce_can_force_operand (XEXP (y, 0)))
                {
                  start_sequence ();
                  target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
@@ -985,7 +1014,9 @@ noce_emit_move_insn (rtx x, rtx y)
            case RTX_BIN_ARITH:
            case RTX_COMM_ARITH:
              ot = code_to_optab (GET_CODE (y));
-             if (ot)
+             if (ot
+                 && noce_can_force_operand (XEXP (y, 0))
+                 && noce_can_force_operand (XEXP (y, 1)))
                {
                  start_sequence ();
                  target = expand_binop (GET_MODE (y), ot,
@@ -1015,7 +1046,7 @@ noce_emit_move_insn (rtx x, rtx y)
   outmode = GET_MODE (outer);
   bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
   store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos,
-                  0, 0, outmode, y);
+                  0, 0, outmode, y, false);
 }
 
 /* Return the CC reg if it is used in COND.  */
@@ -1023,7 +1054,7 @@ noce_emit_move_insn (rtx x, rtx y)
 static rtx
 cc_in_cond (rtx cond)
 {
-  if (HAVE_cbranchcc4 && cond
+  if (have_cbranchcc4 && cond
       && GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_CC)
     return XEXP (cond, 0);
 
@@ -1046,6 +1077,10 @@ end_ifcvt_sequence (struct noce_if_info *if_info)
   set_used_flags (if_info->cond);
   set_used_flags (if_info->a);
   set_used_flags (if_info->b);
+
+  for (insn = seq; insn; insn = NEXT_INSN (insn))
+    set_used_flags (insn);
+
   unshare_all_rtl_in_chain (seq);
   end_sequence ();
 
@@ -1063,6 +1098,21 @@ end_ifcvt_sequence (struct noce_if_info *if_info)
   return seq;
 }
 
+/* Return true iff the then and else basic block (if it exists)
+   consist of a single simple set instruction.  */
+
+static bool
+noce_simple_bbs (struct noce_if_info *if_info)
+{
+  if (!if_info->then_simple)
+    return false;
+
+  if (if_info->else_bb)
+    return if_info->else_simple;
+
+  return true;
+}
+
 /* Convert "if (a != b) x = a; else x = b" into "x = a" and
    "if (a == b) x = a; else x = b" into "x = b".  */
 
@@ -1077,6 +1127,9 @@ noce_try_move (struct noce_if_info *if_info)
   if (code != NE && code != EQ)
     return FALSE;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   /* This optimization isn't valid if either A or B could be a NaN
      or a signed zero.  */
   if (HONOR_NANS (if_info->x)
@@ -1107,11 +1160,45 @@ noce_try_move (struct noce_if_info *if_info)
          emit_insn_before_setloc (seq, if_info->jump,
                                   INSN_LOCATION (if_info->insn_a));
        }
+      if_info->transform_name = "noce_try_move";
       return TRUE;
     }
   return FALSE;
 }
 
+/* Try forming an IF_THEN_ELSE (cond, b, a) and collapsing that
+   through simplify_rtx.  Sometimes that can eliminate the IF_THEN_ELSE.
+   If that is the case, emit the result into x.  */
+
+static int
+noce_try_ifelse_collapse (struct noce_if_info * if_info)
+{
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
+  machine_mode mode = GET_MODE (if_info->x);
+  rtx if_then_else = simplify_gen_ternary (IF_THEN_ELSE, mode, mode,
+                                           if_info->cond, if_info->b,
+                                           if_info->a);
+
+  if (GET_CODE (if_then_else) == IF_THEN_ELSE)
+    return FALSE;
+
+  rtx_insn *seq;
+  start_sequence ();
+  noce_emit_move_insn (if_info->x, if_then_else);
+  seq = end_ifcvt_sequence (if_info);
+  if (!seq)
+    return FALSE;
+
+  emit_insn_before_setloc (seq, if_info->jump,
+                         INSN_LOCATION (if_info->insn_a));
+
+  if_info->transform_name = "noce_try_ifelse_collapse";
+  return TRUE;
+}
+
+
 /* Convert "if (test) x = 1; else x = 0".
 
    Only try 0 and STORE_FLAG_VALUE here.  Other combinations will be
@@ -1125,6 +1212,9 @@ noce_try_store_flag (struct noce_if_info *if_info)
   rtx target;
   rtx_insn *seq;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   if (CONST_INT_P (if_info->b)
       && INTVAL (if_info->b) == STORE_FLAG_VALUE
       && if_info->a == const0_rtx)
@@ -1132,8 +1222,7 @@ noce_try_store_flag (struct noce_if_info *if_info)
   else if (if_info->b == const0_rtx
           && CONST_INT_P (if_info->a)
           && INTVAL (if_info->a) == STORE_FLAG_VALUE
-          && (reversed_comparison_code (if_info->cond, if_info->jump)
-              != UNKNOWN))
+          && noce_reversed_cond_code (if_info) != UNKNOWN)
     reversep = 1;
   else
     return FALSE;
@@ -1152,6 +1241,7 @@ noce_try_store_flag (struct noce_if_info *if_info)
 
       emit_insn_before_setloc (seq, if_info->jump,
                               INSN_LOCATION (if_info->insn_a));
+      if_info->transform_name = "noce_try_store_flag";
       return TRUE;
     }
   else
@@ -1161,24 +1251,129 @@ noce_try_store_flag (struct noce_if_info *if_info)
     }
 }
 
-/* Convert "if (test) x = a; else x = b", for A and B constant.  */
+
+/* Convert "if (test) x = -A; else x = A" into
+   x = A; if (test) x = -x if the machine can do the
+   conditional negate form of this cheaply.
+   Try this before noce_try_cmove that will just load the
+   immediates into two registers and do a conditional select
+   between them.  If the target has a conditional negate or
+   conditional invert operation we can save a potentially
+   expensive constant synthesis.  */
+
+static bool
+noce_try_inverse_constants (struct noce_if_info *if_info)
+{
+  if (!noce_simple_bbs (if_info))
+    return false;
+
+  if (!CONST_INT_P (if_info->a)
+      || !CONST_INT_P (if_info->b)
+      || !REG_P (if_info->x))
+    return false;
+
+  machine_mode mode = GET_MODE (if_info->x);
+
+  HOST_WIDE_INT val_a = INTVAL (if_info->a);
+  HOST_WIDE_INT val_b = INTVAL (if_info->b);
+
+  rtx cond = if_info->cond;
+
+  rtx x = if_info->x;
+  rtx target;
+
+  start_sequence ();
+
+  rtx_code code;
+  if (val_b != HOST_WIDE_INT_MIN && val_a == -val_b)
+    code = NEG;
+  else if (val_a == ~val_b)
+    code = NOT;
+  else
+    {
+      end_sequence ();
+      return false;
+    }
+
+  rtx tmp = gen_reg_rtx (mode);
+  noce_emit_move_insn (tmp, if_info->a);
+
+  target = emit_conditional_neg_or_complement (x, code, mode, cond, tmp, tmp);
+
+  if (target)
+    {
+      rtx_insn *seq = get_insns ();
+
+      if (!seq)
+       {
+         end_sequence ();
+         return false;
+       }
+
+      if (target != if_info->x)
+       noce_emit_move_insn (if_info->x, target);
+
+      seq = end_ifcvt_sequence (if_info);
+
+      if (!seq)
+       return false;
+
+      emit_insn_before_setloc (seq, if_info->jump,
+                              INSN_LOCATION (if_info->insn_a));
+      if_info->transform_name = "noce_try_inverse_constants";
+      return true;
+    }
+
+  end_sequence ();
+  return false;
+}
+
+
+/* Convert "if (test) x = a; else x = b", for A and B constant.
+   Also allow A = y + c1, B = y + c2, with a common y between A
+   and B.  */
 
 static int
 noce_try_store_flag_constants (struct noce_if_info *if_info)
 {
   rtx target;
   rtx_insn *seq;
-  int reversep;
+  bool reversep;
   HOST_WIDE_INT itrue, ifalse, diff, tmp;
-  int normalize, can_reverse;
-  machine_mode mode;
+  int normalize;
+  bool can_reverse;
+  machine_mode mode = GET_MODE (if_info->x);
+  rtx common = NULL_RTX;
 
-  if (CONST_INT_P (if_info->a)
-      && CONST_INT_P (if_info->b))
+  rtx a = if_info->a;
+  rtx b = if_info->b;
+
+  /* Handle cases like x := test ? y + 3 : y + 4.  */
+  if (GET_CODE (a) == PLUS
+      && GET_CODE (b) == PLUS
+      && CONST_INT_P (XEXP (a, 1))
+      && CONST_INT_P (XEXP (b, 1))
+      && rtx_equal_p (XEXP (a, 0), XEXP (b, 0))
+      /* Allow expressions that are not using the result or plain
+         registers where we handle overlap below.  */
+      && (REG_P (XEXP (a, 0))
+         || (noce_operand_ok (XEXP (a, 0))
+             && ! reg_overlap_mentioned_p (if_info->x, XEXP (a, 0)))))
+    {
+      common = XEXP (a, 0);
+      a = XEXP (a, 1);
+      b = XEXP (b, 1);
+    }
+
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
+  if (CONST_INT_P (a)
+      && CONST_INT_P (b))
     {
-      mode = GET_MODE (if_info->x);
-      ifalse = INTVAL (if_info->a);
-      itrue = INTVAL (if_info->b);
+      ifalse = INTVAL (a);
+      itrue = INTVAL (b);
+      bool subtract_flag_p = false;
 
       diff = (unsigned HOST_WIDE_INT) itrue - ifalse;
       /* Make sure we can represent the difference between the two values.  */
@@ -1188,29 +1383,74 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
 
       diff = trunc_int_for_mode (diff, mode);
 
-      can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
-                    != UNKNOWN);
-
-      reversep = 0;
+      can_reverse = noce_reversed_cond_code (if_info) != UNKNOWN;
+      reversep = false;
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
-       normalize = 0;
-      else if (ifalse == 0 && exact_log2 (itrue) >= 0
-              && (STORE_FLAG_VALUE == 1
-                  || if_info->branch_cost >= 2))
+       {
+         normalize = 0;
+         /* We could collapse these cases but it is easier to follow the
+            diff/STORE_FLAG_VALUE combinations when they are listed
+            explicitly.  */
+
+         /* test ? 3 : 4
+            => 4 + (test != 0).  */
+         if (diff < 0 && STORE_FLAG_VALUE < 0)
+             reversep = false;
+         /* test ? 4 : 3
+            => can_reverse  | 4 + (test == 0)
+               !can_reverse | 3 - (test != 0).  */
+         else if (diff > 0 && STORE_FLAG_VALUE < 0)
+           {
+             reversep = can_reverse;
+             subtract_flag_p = !can_reverse;
+             /* If we need to subtract the flag and we have PLUS-immediate
+                A and B then it is unlikely to be beneficial to play tricks
+                here.  */
+             if (subtract_flag_p && common)
+               return FALSE;
+           }
+         /* test ? 3 : 4
+            => can_reverse  | 3 + (test == 0)
+               !can_reverse | 4 - (test != 0).  */
+         else if (diff < 0 && STORE_FLAG_VALUE > 0)
+           {
+             reversep = can_reverse;
+             subtract_flag_p = !can_reverse;
+             /* If we need to subtract the flag and we have PLUS-immediate
+                A and B then it is unlikely to be beneficial to play tricks
+                here.  */
+             if (subtract_flag_p && common)
+               return FALSE;
+           }
+         /* test ? 4 : 3
+            => 4 + (test != 0).  */
+         else if (diff > 0 && STORE_FLAG_VALUE > 0)
+           reversep = false;
+         else
+           gcc_unreachable ();
+       }
+      /* Is this (cond) ? 2^n : 0?  */
+      else if (ifalse == 0 && pow2p_hwi (itrue)
+              && STORE_FLAG_VALUE == 1)
        normalize = 1;
-      else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
-              && (STORE_FLAG_VALUE == 1 || if_info->branch_cost >= 2))
-       normalize = 1, reversep = 1;
+      /* Is this (cond) ? 0 : 2^n?  */
+      else if (itrue == 0 && pow2p_hwi (ifalse) && can_reverse
+              && STORE_FLAG_VALUE == 1)
+       {
+         normalize = 1;
+         reversep = true;
+       }
+      /* Is this (cond) ? -1 : x?  */
       else if (itrue == -1
-              && (STORE_FLAG_VALUE == -1
-                  || if_info->branch_cost >= 2))
+              && STORE_FLAG_VALUE == -1)
        normalize = -1;
+      /* Is this (cond) ? x : -1?  */
       else if (ifalse == -1 && can_reverse
-              && (STORE_FLAG_VALUE == -1 || if_info->branch_cost >= 2))
-       normalize = -1, reversep = 1;
-      else if ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1)
-              || if_info->branch_cost >= 3)
-       normalize = -1;
+              && STORE_FLAG_VALUE == -1)
+       {
+         normalize = -1;
+         reversep = true;
+       }
       else
        return FALSE;
 
@@ -1221,6 +1461,15 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
        }
 
       start_sequence ();
+
+      /* If we have x := test ? x + 3 : x + 4 then move the original
+        x out of the way while we store flags.  */
+      if (common && rtx_equal_p (common, if_info->x))
+       {
+         common = gen_reg_rtx (mode);
+         noce_emit_move_insn (common, if_info->x);
+       }
+
       target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize);
       if (! target)
        {
@@ -1232,13 +1481,27 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
         =>   x = 3 + (test == 0);  */
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
        {
-         target = expand_simple_binop (mode,
-                                       (diff == STORE_FLAG_VALUE
-                                        ? PLUS : MINUS),
+         /* Add the common part now.  This may allow combine to merge this
+            with the store flag operation earlier into some sort of conditional
+            increment/decrement if the target allows it.  */
+         if (common)
+           target = expand_simple_binop (mode, PLUS,
+                                          target, common,
+                                          target, 0, OPTAB_WIDEN);
+
+         /* Always use ifalse here.  It should have been swapped with itrue
+            when appropriate when reversep is true.  */
+         target = expand_simple_binop (mode, subtract_flag_p ? MINUS : PLUS,
                                        gen_int_mode (ifalse, mode), target,
                                        if_info->x, 0, OPTAB_WIDEN);
        }
-
+      /* Other cases are not beneficial when the original A and B are PLUS
+        expressions.  */
+      else if (common)
+       {
+         end_sequence ();
+         return FALSE;
+       }
       /* if (test) x = 8; else x = 0;
         =>   x = (test != 0) << 3;  */
       else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
@@ -1256,18 +1519,10 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
                                        target, gen_int_mode (ifalse, mode),
                                        if_info->x, 0, OPTAB_WIDEN);
        }
-
-      /* if (test) x = a; else x = b;
-        =>   x = (-(test != 0) & (b - a)) + a;  */
       else
        {
-         target = expand_simple_binop (mode, AND,
-                                       target, gen_int_mode (diff, mode),
-                                       if_info->x, 0, OPTAB_WIDEN);
-         if (target)
-           target = expand_simple_binop (mode, PLUS,
-                                         target, gen_int_mode (ifalse, mode),
-                                         if_info->x, 0, OPTAB_WIDEN);
+         end_sequence ();
+         return FALSE;
        }
 
       if (! target)
@@ -1280,11 +1535,13 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
        noce_emit_move_insn (if_info->x, target);
 
       seq = end_ifcvt_sequence (if_info);
-      if (!seq)
+      if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
        return FALSE;
 
       emit_insn_before_setloc (seq, if_info->jump,
                               INSN_LOCATION (if_info->insn_a));
+      if_info->transform_name = "noce_try_store_flag_constants";
+
       return TRUE;
     }
 
@@ -1301,13 +1558,23 @@ noce_try_addcc (struct noce_if_info *if_info)
   rtx_insn *seq;
   int subtract, normalize;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   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))
+      && noce_reversed_cond_code (if_info) != UNKNOWN)
     {
-      rtx cond = if_info->cond;
-      enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
+      rtx cond = if_info->rev_cond;
+      enum rtx_code code;
+
+      if (cond == NULL_RTX)
+       {
+         cond = if_info->cond;
+         code = reversed_comparison_code (cond, if_info->jump);
+       }
+      else
+       code = GET_CODE (cond);
 
       /* First try to use addcc pattern.  */
       if (general_operand (XEXP (cond, 0), VOIDmode)
@@ -1329,21 +1596,23 @@ noce_try_addcc (struct noce_if_info *if_info)
                noce_emit_move_insn (if_info->x, target);
 
              seq = end_ifcvt_sequence (if_info);
-             if (!seq)
+             if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
                return FALSE;
 
              emit_insn_before_setloc (seq, if_info->jump,
                                       INSN_LOCATION (if_info->insn_a));
+             if_info->transform_name = "noce_try_addcc";
+
              return TRUE;
            }
          end_sequence ();
        }
 
       /* If that fails, construct conditional increment or decrement using
-        setcc.  */
-      if (if_info->branch_cost >= 2
-         && (XEXP (if_info->a, 1) == const1_rtx
-             || XEXP (if_info->a, 1) == constm1_rtx))
+        setcc.  We're changing a branch and an increment to a comparison and
+        an ADD/SUB.  */
+      if (XEXP (if_info->a, 1) == const1_rtx
+         || XEXP (if_info->a, 1) == constm1_rtx)
         {
          start_sequence ();
          if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
@@ -1369,11 +1638,12 @@ noce_try_addcc (struct noce_if_info *if_info)
                noce_emit_move_insn (if_info->x, target);
 
              seq = end_ifcvt_sequence (if_info);
-             if (!seq)
+             if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
                return FALSE;
 
              emit_insn_before_setloc (seq, if_info->jump,
                                       INSN_LOCATION (if_info->insn_a));
+             if_info->transform_name = "noce_try_addcc";
              return TRUE;
            }
          end_sequence ();
@@ -1392,16 +1662,16 @@ noce_try_store_flag_mask (struct noce_if_info *if_info)
   rtx_insn *seq;
   int reversep;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   reversep = 0;
-  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,
-                                                    if_info->jump)
-                          != UNKNOWN))
-             && if_info->b == const0_rtx
-             && rtx_equal_p (if_info->a, if_info->x))))
+
+  if ((if_info->a == const0_rtx
+       && rtx_equal_p (if_info->b, if_info->x))
+      || ((reversep = (noce_reversed_cond_code (if_info) != UNKNOWN))
+         && if_info->b == const0_rtx
+         && rtx_equal_p (if_info->a, if_info->x)))
     {
       start_sequence ();
       target = noce_emit_store_flag (if_info,
@@ -1415,26 +1685,17 @@ noce_try_store_flag_mask (struct noce_if_info *if_info)
 
       if (target)
        {
-         int old_cost, new_cost, insn_cost;
-         int speed_p;
-
          if (target != if_info->x)
            noce_emit_move_insn (if_info->x, target);
 
          seq = end_ifcvt_sequence (if_info);
-         if (!seq)
-           return FALSE;
-
-         speed_p = optimize_bb_for_speed_p (BLOCK_FOR_INSN (if_info->insn_a));
-         insn_cost = insn_rtx_cost (PATTERN (if_info->insn_a), speed_p);
-         old_cost = COSTS_N_INSNS (if_info->branch_cost) + insn_cost;
-         new_cost = seq_cost (seq, speed_p);
-
-         if (new_cost > old_cost)
+         if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
            return FALSE;
 
          emit_insn_before_setloc (seq, if_info->jump,
                                   INSN_LOCATION (if_info->insn_a));
+         if_info->transform_name = "noce_try_store_flag_mask";
+
          return TRUE;
        }
 
@@ -1485,7 +1746,7 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
   if (! general_operand (cmp_a, GET_MODE (cmp_a))
       || ! general_operand (cmp_b, GET_MODE (cmp_b)))
     {
-      if (!(HAVE_cbranchcc4)
+      if (!have_cbranchcc4
          || GET_MODE_CLASS (GET_MODE (cmp_a)) != MODE_CC
          || cmp_b != const0_rtx)
        return NULL_RTX;
@@ -1518,12 +1779,12 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
     {
       rtx reg_vtrue = SUBREG_REG (vtrue);
       rtx reg_vfalse = SUBREG_REG (vfalse);
-      unsigned int byte_vtrue = SUBREG_BYTE (vtrue);
-      unsigned int byte_vfalse = SUBREG_BYTE (vfalse);
+      poly_uint64 byte_vtrue = SUBREG_BYTE (vtrue);
+      poly_uint64 byte_vfalse = SUBREG_BYTE (vfalse);
       rtx promoted_target;
 
       if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse)
-         || byte_vtrue != byte_vfalse
+         || maybe_ne (byte_vtrue, byte_vfalse)
          || (SUBREG_PROMOTED_VAR_P (vtrue)
              != SUBREG_PROMOTED_VAR_P (vfalse))
          || (SUBREG_PROMOTED_GET (vtrue)
@@ -1560,6 +1821,9 @@ noce_try_cmove (struct noce_if_info *if_info)
   rtx target;
   rtx_insn *seq;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   if ((CONSTANT_P (if_info->a) || register_operand (if_info->a, VOIDmode))
       && (CONSTANT_P (if_info->b) || register_operand (if_info->b, VOIDmode)))
     {
@@ -1577,23 +1841,249 @@ noce_try_cmove (struct noce_if_info *if_info)
            noce_emit_move_insn (if_info->x, target);
 
          seq = end_ifcvt_sequence (if_info);
-         if (!seq)
+         if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
            return FALSE;
 
          emit_insn_before_setloc (seq, if_info->jump,
                                   INSN_LOCATION (if_info->insn_a));
+         if_info->transform_name = "noce_try_cmove";
+
          return TRUE;
        }
-      else
+      /* If both a and b are constants try a last-ditch transformation:
+        if (test) x = a; else x = b;
+        =>   x = (-(test != 0) & (b - a)) + a;
+        Try this only if the target-specific expansion above has failed.
+        The target-specific expander may want to generate sequences that
+        we don't know about, so give them a chance before trying this
+        approach.  */
+      else if (!targetm.have_conditional_execution ()
+               && CONST_INT_P (if_info->a) && CONST_INT_P (if_info->b))
        {
-         end_sequence ();
-         return FALSE;
+         machine_mode mode = GET_MODE (if_info->x);
+         HOST_WIDE_INT ifalse = INTVAL (if_info->a);
+         HOST_WIDE_INT itrue = INTVAL (if_info->b);
+         rtx target = noce_emit_store_flag (if_info, if_info->x, false, -1);
+         if (!target)
+           {
+             end_sequence ();
+             return FALSE;
+           }
+
+         HOST_WIDE_INT diff = (unsigned HOST_WIDE_INT) itrue - ifalse;
+         /* Make sure we can represent the difference
+            between the two values.  */
+         if ((diff > 0)
+             != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
+           {
+             end_sequence ();
+             return FALSE;
+           }
+
+         diff = trunc_int_for_mode (diff, mode);
+         target = expand_simple_binop (mode, AND,
+                                       target, gen_int_mode (diff, mode),
+                                       if_info->x, 0, OPTAB_WIDEN);
+         if (target)
+           target = expand_simple_binop (mode, PLUS,
+                                         target, gen_int_mode (ifalse, mode),
+                                         if_info->x, 0, OPTAB_WIDEN);
+         if (target)
+           {
+             if (target != if_info->x)
+               noce_emit_move_insn (if_info->x, target);
+
+             seq = end_ifcvt_sequence (if_info);
+             if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
+               return FALSE;
+
+             emit_insn_before_setloc (seq, if_info->jump,
+                                  INSN_LOCATION (if_info->insn_a));
+             if_info->transform_name = "noce_try_cmove";
+             return TRUE;
+           }
+         else
+           {
+             end_sequence ();
+             return FALSE;
+           }
        }
+      else
+       end_sequence ();
     }
 
   return FALSE;
 }
 
+/* Return true if X contains a conditional code mode rtx.  */
+
+static bool
+contains_ccmode_rtx_p (rtx x)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    if (GET_MODE_CLASS (GET_MODE (*iter)) == MODE_CC)
+      return true;
+
+  return false;
+}
+
+/* Helper for bb_valid_for_noce_process_p.  Validate that
+   the rtx insn INSN is a single set that does not set
+   the conditional register CC and is in general valid for
+   if-conversion.  */
+
+static bool
+insn_valid_noce_process_p (rtx_insn *insn, rtx cc)
+{
+  if (!insn
+      || !NONJUMP_INSN_P (insn)
+      || (cc && set_of (cc, insn)))
+      return false;
+
+  rtx sset = single_set (insn);
+
+  /* Currently support only simple single sets in test_bb.  */
+  if (!sset
+      || !noce_operand_ok (SET_DEST (sset))
+      || contains_ccmode_rtx_p (SET_DEST (sset))
+      || !noce_operand_ok (SET_SRC (sset)))
+    return false;
+
+  return true;
+}
+
+
+/* Return true iff the registers that the insns in BB_A set do not get
+   used in BB_B.  If TO_RENAME is non-NULL then it is a location that will be
+   renamed later by the caller and so conflicts on it should be ignored
+   in this function.  */
+
+static bool
+bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b, rtx to_rename)
+{
+  rtx_insn *a_insn;
+  bitmap bba_sets = BITMAP_ALLOC (&reg_obstack);
+
+  df_ref def;
+  df_ref use;
+
+  FOR_BB_INSNS (bb_a, a_insn)
+    {
+      if (!active_insn_p (a_insn))
+       continue;
+
+      rtx sset_a = single_set (a_insn);
+
+      if (!sset_a)
+       {
+         BITMAP_FREE (bba_sets);
+         return false;
+       }
+      /* Record all registers that BB_A sets.  */
+      FOR_EACH_INSN_DEF (def, a_insn)
+       if (!(to_rename && DF_REF_REG (def) == to_rename))
+         bitmap_set_bit (bba_sets, DF_REF_REGNO (def));
+    }
+
+  rtx_insn *b_insn;
+
+  FOR_BB_INSNS (bb_b, b_insn)
+    {
+      if (!active_insn_p (b_insn))
+       continue;
+
+      rtx sset_b = single_set (b_insn);
+
+      if (!sset_b)
+       {
+         BITMAP_FREE (bba_sets);
+         return false;
+       }
+
+      /* Make sure this is a REG and not some instance
+        of ZERO_EXTRACT or SUBREG or other dangerous stuff.
+        If we have a memory destination then we have a pair of simple
+        basic blocks performing an operation of the form [addr] = c ? a : b.
+        bb_valid_for_noce_process_p will have ensured that these are
+        the only stores present.  In that case [addr] should be the location
+        to be renamed.  Assert that the callers set this up properly.  */
+      if (MEM_P (SET_DEST (sset_b)))
+       gcc_assert (rtx_equal_p (SET_DEST (sset_b), to_rename));
+      else if (!REG_P (SET_DEST (sset_b)))
+       {
+         BITMAP_FREE (bba_sets);
+         return false;
+       }
+
+      /* If the insn uses a reg set in BB_A return false.  */
+      FOR_EACH_INSN_USE (use, b_insn)
+       {
+         if (bitmap_bit_p (bba_sets, DF_REF_REGNO (use)))
+           {
+             BITMAP_FREE (bba_sets);
+             return false;
+           }
+       }
+
+    }
+
+  BITMAP_FREE (bba_sets);
+  return true;
+}
+
+/* Emit copies of all the active instructions in BB except the last.
+   This is a helper for noce_try_cmove_arith.  */
+
+static void
+noce_emit_all_but_last (basic_block bb)
+{
+  rtx_insn *last = last_active_insn (bb, FALSE);
+  rtx_insn *insn;
+  FOR_BB_INSNS (bb, insn)
+    {
+      if (insn != last && active_insn_p (insn))
+       {
+         rtx_insn *to_emit = as_a <rtx_insn *> (copy_rtx (insn));
+
+         emit_insn (PATTERN (to_emit));
+       }
+    }
+}
+
+/* Helper for noce_try_cmove_arith.  Emit the pattern TO_EMIT and return
+   the resulting insn or NULL if it's not a valid insn.  */
+
+static rtx_insn *
+noce_emit_insn (rtx to_emit)
+{
+  gcc_assert (to_emit);
+  rtx_insn *insn = emit_insn (to_emit);
+
+  if (recog_memoized (insn) < 0)
+    return NULL;
+
+  return insn;
+}
+
+/* Helper for noce_try_cmove_arith.  Emit a copy of the insns up to
+   and including the penultimate one in BB if it is not simple
+   (as indicated by SIMPLE).  Then emit LAST_INSN as the last
+   insn in the block.  The reason for that is that LAST_INSN may
+   have been modified by the preparation in noce_try_cmove_arith.  */
+
+static bool
+noce_emit_bb (rtx last_insn, basic_block bb, bool simple)
+{
+  if (bb && !simple)
+    noce_emit_all_but_last (bb);
+
+  if (last_insn && !noce_emit_insn (last_insn))
+    return false;
+
+  return true;
+}
+
 /* Try more complex cases involving conditional_move.  */
 
 static int
@@ -1604,21 +2094,23 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
   rtx x = if_info->x;
   rtx orig_a, orig_b;
   rtx_insn *insn_a, *insn_b;
+  bool a_simple = if_info->then_simple;
+  bool b_simple = if_info->else_simple;
+  basic_block then_bb = if_info->then_bb;
+  basic_block else_bb = if_info->else_bb;
   rtx target;
   int is_mem = 0;
-  int insn_cost;
   enum rtx_code code;
+  rtx cond = if_info->cond;
   rtx_insn *ifcvt_seq;
 
   /* A conditional move from two memory sources is equivalent to a
      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.  */
-  /* ??? FIXME: Magic number 5.  */
   if (cse_not_expected
       && MEM_P (a) && MEM_P (b)
-      && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b)
-      && if_info->branch_cost >= 5)
+      && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b))
     {
       machine_mode address_mode = get_address_mode (a);
 
@@ -1641,34 +2133,17 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
          x = y;
   */
 
-  code = GET_CODE (if_info->cond);
+  code = GET_CODE (cond);
   insn_a = if_info->insn_a;
   insn_b = if_info->insn_b;
 
-  /* Total insn_rtx_cost should be smaller than branch cost.  Exit
-     if insn_rtx_cost can't be estimated.  */
-  if (insn_a)
-    {
-      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;
+  machine_mode x_mode = GET_MODE (x);
 
-  if (insn_b)
-    {
-      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 (!can_conditionally_move_p (x_mode))
+    return FALSE;
 
   /* Possibly rearrange operands to make things come out more natural.  */
-  if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
+  if (noce_reversed_cond_code (if_info) != UNKNOWN)
     {
       int reversep = 0;
       if (rtx_equal_p (b, x))
@@ -1678,84 +2153,163 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
 
       if (reversep)
        {
-         code = reversed_comparison_code (if_info->cond, if_info->jump);
+         if (if_info->rev_cond)
+           {
+             cond = if_info->rev_cond;
+             code = GET_CODE (cond);
+           }
+         else
+           code = reversed_comparison_code (cond, if_info->jump);
          std::swap (a, b);
          std::swap (insn_a, insn_b);
+         std::swap (a_simple, b_simple);
+         std::swap (then_bb, else_bb);
        }
     }
 
+  if (then_bb && else_bb
+      && (!bbs_ok_for_cmove_arith (then_bb, else_bb,  if_info->orig_x)
+         || !bbs_ok_for_cmove_arith (else_bb, then_bb,  if_info->orig_x)))
+    return FALSE;
+
   start_sequence ();
 
+  /* If one of the blocks is empty then the corresponding B or A value
+     came from the test block.  The non-empty complex block that we will
+     emit might clobber the register used by B or A, so move it to a pseudo
+     first.  */
+
+  rtx tmp_a = NULL_RTX;
+  rtx tmp_b = NULL_RTX;
+
+  if (b_simple || !else_bb)
+    tmp_b = gen_reg_rtx (x_mode);
+
+  if (a_simple || !then_bb)
+    tmp_a = gen_reg_rtx (x_mode);
+
   orig_a = a;
   orig_b = b;
 
+  rtx emit_a = NULL_RTX;
+  rtx emit_b = NULL_RTX;
+  rtx_insn *tmp_insn = NULL;
+  bool modified_in_a = false;
+  bool modified_in_b = false;
   /* 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.
      This is of course not possible in the IS_MEM case.  */
-  if (! general_operand (a, GET_MODE (a)))
+
+  if (! general_operand (a, GET_MODE (a)) || tmp_a)
     {
-      rtx_insn *insn;
 
       if (is_mem)
        {
          rtx reg = gen_reg_rtx (GET_MODE (a));
-         insn = emit_insn (gen_rtx_SET (reg, a));
+         emit_a = gen_rtx_SET (reg, a);
        }
-      else if (! insn_a)
-       goto end_seq_and_fail;
       else
        {
-         a = gen_reg_rtx (GET_MODE (a));
-         rtx_insn *copy_of_a = as_a <rtx_insn *> (copy_rtx (insn_a));
-         rtx set = single_set (copy_of_a);
-         SET_DEST (set) = a;
-         insn = emit_insn (PATTERN (copy_of_a));
+         if (insn_a)
+           {
+             a = tmp_a ? tmp_a : gen_reg_rtx (GET_MODE (a));
+
+             rtx_insn *copy_of_a = as_a <rtx_insn *> (copy_rtx (insn_a));
+             rtx set = single_set (copy_of_a);
+             SET_DEST (set) = a;
+
+             emit_a = PATTERN (copy_of_a);
+           }
+         else
+           {
+             rtx tmp_reg = tmp_a ? tmp_a : gen_reg_rtx (GET_MODE (a));
+             emit_a = gen_rtx_SET (tmp_reg, a);
+             a = tmp_reg;
+           }
        }
-      if (recog_memoized (insn) < 0)
-       goto end_seq_and_fail;
     }
-  if (! general_operand (b, GET_MODE (b)))
-    {
-      rtx pat;
-      rtx_insn *last;
-      rtx_insn *new_insn;
 
+  if (! general_operand (b, GET_MODE (b)) || tmp_b)
+    {
       if (is_mem)
        {
           rtx reg = gen_reg_rtx (GET_MODE (b));
-         pat = gen_rtx_SET (reg, b);
+         emit_b = gen_rtx_SET (reg, b);
        }
-      else if (! insn_b)
-       goto end_seq_and_fail;
       else
        {
-          b = gen_reg_rtx (GET_MODE (b));
-         rtx_insn *copy_of_insn_b = as_a <rtx_insn *> (copy_rtx (insn_b));
-         rtx set = single_set (copy_of_insn_b);
-         SET_DEST (set) = b;
-         pat = PATTERN (copy_of_insn_b);
+         if (insn_b)
+           {
+             b = tmp_b ? tmp_b : gen_reg_rtx (GET_MODE (b));
+             rtx_insn *copy_of_b = as_a <rtx_insn *> (copy_rtx (insn_b));
+             rtx set = single_set (copy_of_b);
+
+             SET_DEST (set) = b;
+             emit_b = PATTERN (copy_of_b);
+           }
+         else
+           {
+             rtx tmp_reg = tmp_b ? tmp_b : gen_reg_rtx (GET_MODE (b));
+             emit_b = gen_rtx_SET (tmp_reg, b);
+             b = tmp_reg;
+           }
        }
+    }
+
+  modified_in_a = emit_a != NULL_RTX && modified_in_p (orig_b, emit_a);
+  if (tmp_b && then_bb)
+    {
+      FOR_BB_INSNS (then_bb, tmp_insn)
+       /* Don't check inside insn_a.  We will have changed it to emit_a
+          with a destination that doesn't conflict.  */
+       if (!(insn_a && tmp_insn == insn_a)
+           && modified_in_p (orig_b, tmp_insn))
+         {
+           modified_in_a = true;
+           break;
+         }
 
-      /* 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))
+    }
+
+  modified_in_b = emit_b != NULL_RTX && modified_in_p (orig_a, emit_b);
+  if (tmp_a && else_bb)
+    {
+      FOR_BB_INSNS (else_bb, tmp_insn)
+      /* Don't check inside insn_b.  We will have changed it to emit_b
+        with a destination that doesn't conflict.  */
+      if (!(insn_b && tmp_insn == insn_b)
+         && modified_in_p (orig_a, tmp_insn))
        {
-         new_insn = emit_insn_before (pat, get_insns ());
-         if (modified_in_p (orig_a, new_insn))
-           goto end_seq_and_fail;
+         modified_in_b = true;
+         break;
        }
-      else
-       new_insn = emit_insn (pat);
+    }
+
+  /* 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.  */
+  if (modified_in_a && !modified_in_b)
+    {
+      if (!noce_emit_bb (emit_b, else_bb, b_simple))
+       goto end_seq_and_fail;
 
-      if (recog_memoized (new_insn) < 0)
+      if (!noce_emit_bb (emit_a, then_bb, a_simple))
        goto end_seq_and_fail;
     }
+  else if (!modified_in_a)
+    {
+      if (!noce_emit_bb (emit_a, then_bb, a_simple))
+       goto end_seq_and_fail;
+
+      if (!noce_emit_bb (emit_b, else_bb, b_simple))
+       goto end_seq_and_fail;
+    }
+  else
+    goto end_seq_and_fail;
 
-  target = noce_emit_cmove (if_info, x, code, XEXP (if_info->cond, 0),
-                           XEXP (if_info->cond, 1), a, b);
+  target = noce_emit_cmove (if_info, x, code, XEXP (cond, 0), XEXP (cond, 1),
+                           a, b);
 
   if (! target)
     goto end_seq_and_fail;
@@ -1782,11 +2336,12 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
     noce_emit_move_insn (x, target);
 
   ifcvt_seq = end_ifcvt_sequence (if_info);
-  if (!ifcvt_seq)
+  if (!ifcvt_seq || !targetm.noce_conversion_profitable_p (ifcvt_seq, if_info))
     return FALSE;
 
   emit_insn_before_setloc (ifcvt_seq, if_info->jump,
                           INSN_LOCATION (if_info->insn_a));
+  if_info->transform_name = "noce_try_cmove_arith";
   return TRUE;
 
  end_seq_and_fail:
@@ -1817,7 +2372,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
   cond = XEXP (SET_SRC (set), 0);
   reverse
     = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
-      && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump);
+      && label_ref_label (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump);
   if (if_info->then_else_reversed)
     reverse = !reverse;
 
@@ -1843,7 +2398,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
       rtx_insn *prev_insn;
 
       /* First, look to see if we put a constant in a register.  */
-      prev_insn = prev_nonnote_insn (if_info->cond_earliest);
+      prev_insn = prev_nonnote_nondebug_insn (if_info->cond_earliest);
       if (prev_insn
          && BLOCK_FOR_INSN (prev_insn)
             == BLOCK_FOR_INSN (if_info->cond_earliest)
@@ -1878,28 +2433,32 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
          switch (code)
            {
            case LT:
-             if (actual_val == desired_val + 1)
+             if (desired_val != HOST_WIDE_INT_MAX
+                 && actual_val == desired_val + 1)
                {
                  code = LE;
                  op_b = GEN_INT (desired_val);
                }
              break;
            case LE:
-             if (actual_val == desired_val - 1)
+             if (desired_val != HOST_WIDE_INT_MIN
+                 && actual_val == desired_val - 1)
                {
                  code = LT;
                  op_b = GEN_INT (desired_val);
                }
              break;
            case GT:
-             if (actual_val == desired_val - 1)
+             if (desired_val != HOST_WIDE_INT_MIN
+                 && actual_val == desired_val - 1)
                {
                  code = GE;
                  op_b = GEN_INT (desired_val);
                }
              break;
            case GE:
-             if (actual_val == desired_val + 1)
+             if (desired_val != HOST_WIDE_INT_MAX
+                 && actual_val == desired_val + 1)
                {
                  code = GT;
                  op_b = GEN_INT (desired_val);
@@ -1924,7 +2483,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
     }
 
   cond = canonicalize_condition (if_info->jump, cond, reverse,
-                                earliest, target, HAVE_cbranchcc4, true);
+                                earliest, target, have_cbranchcc4, true);
   if (! cond || ! reg_mentioned_p (target, cond))
     return NULL;
 
@@ -1956,6 +2515,9 @@ noce_try_minmax (struct noce_if_info *if_info)
   enum rtx_code code, op;
   int unsignedp;
 
+  if (!noce_simple_bbs (if_info))
+    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...  */
@@ -2036,6 +2598,8 @@ noce_try_minmax (struct noce_if_info *if_info)
   emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a));
   if_info->cond = cond;
   if_info->cond_earliest = earliest;
+  if_info->rev_cond = NULL_RTX;
+  if_info->transform_name = "noce_try_minmax";
 
   return TRUE;
 }
@@ -2052,6 +2616,9 @@ noce_try_abs (struct noce_if_info *if_info)
   int negate;
   bool one_cmpl = false;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   /* Reject modes with signed zeros.  */
   if (HONOR_SIGNED_ZEROS (if_info->x))
     return FALSE;
@@ -2102,7 +2669,7 @@ noce_try_abs (struct noce_if_info *if_info)
   if (REG_P (c))
     {
       rtx set;
-      rtx_insn *insn = prev_nonnote_insn (earliest);
+      rtx_insn *insn = prev_nonnote_nondebug_insn (earliest);
       if (insn
          && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (earliest)
          && (set = single_set (insn))
@@ -2124,12 +2691,26 @@ noce_try_abs (struct noce_if_info *if_info)
 
   /* Work around funny ideas get_condition has wrt canonicalization.
      Note that these rtx constants are known to be CONST_INT, and
-     therefore imply integer comparisons.  */
+     therefore imply integer comparisons.
+     The one_cmpl case is more complicated, as we want to handle
+     only x < 0 ? ~x : x or x >= 0 ? x : ~x to one_cmpl_abs (x)
+     and x < 0 ? x : ~x or x >= 0 ? ~x : x to ~one_cmpl_abs (x),
+     but not other cases (x > -1 is equivalent of x >= 0).  */
   if (c == constm1_rtx && GET_CODE (cond) == GT)
     ;
   else if (c == const1_rtx && GET_CODE (cond) == LT)
-    ;
-  else if (c != CONST0_RTX (GET_MODE (b)))
+    {
+      if (one_cmpl)
+       return FALSE;
+    }
+  else if (c == CONST0_RTX (GET_MODE (b)))
+    {
+      if (one_cmpl
+         && GET_CODE (cond) != GE
+         && GET_CODE (cond) != LT)
+       return FALSE;
+    }
+  else
     return FALSE;
 
   /* Determine what sort of operation this is.  */
@@ -2185,6 +2766,8 @@ noce_try_abs (struct noce_if_info *if_info)
   emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a));
   if_info->cond = cond;
   if_info->cond_earliest = earliest;
+  if_info->rev_cond = NULL_RTX;
+  if_info->transform_name = "noce_try_abs";
 
   return TRUE;
 }
@@ -2200,6 +2783,9 @@ noce_try_sign_mask (struct noce_if_info *if_info)
   enum rtx_code code;
   bool t_unconditional;
 
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   cond = if_info->cond;
   code = GET_CODE (cond);
   m = XEXP (cond, 0);
@@ -2233,15 +2819,18 @@ noce_try_sign_mask (struct noce_if_info *if_info)
      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));
+  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
-       || (set_src_cost (t, optimize_bb_for_speed_p (if_info->test_bb))
+       || (set_src_cost (t, mode, if_info->speed_p)
            < COSTS_N_INSNS (2))))
     return FALSE;
 
+  if (!noce_can_force_operand (t))
+    return FALSE;
+
   start_sequence ();
   /* Use emit_store_flag to generate "m < 0 ? -1 : 0" instead of expanding
      "(signed) m >> 31" directly.  This benefits targets with specialized
@@ -2263,6 +2852,8 @@ noce_try_sign_mask (struct noce_if_info *if_info)
     return FALSE;
 
   emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a));
+  if_info->transform_name = "noce_try_sign_mask";
+
   return TRUE;
 }
 
@@ -2275,7 +2866,7 @@ noce_try_bitop (struct noce_if_info *if_info)
 {
   rtx cond, x, a, result;
   rtx_insn *seq;
-  machine_mode mode;
+  scalar_int_mode mode;
   enum rtx_code code;
   int bitnum;
 
@@ -2283,6 +2874,13 @@ noce_try_bitop (struct noce_if_info *if_info)
   cond = if_info->cond;
   code = GET_CODE (cond);
 
+  /* Check for an integer operation.  */
+  if (!is_a <scalar_int_mode> (GET_MODE (x), &mode))
+    return FALSE;
+
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
   /* Check for no else condition.  */
   if (! rtx_equal_p (x, if_info->b))
     return FALSE;
@@ -2302,7 +2900,6 @@ noce_try_bitop (struct noce_if_info *if_info)
          || ! rtx_equal_p (x, XEXP (cond, 0)))
        return FALSE;
       bitnum = INTVAL (XEXP (cond, 2));
-      mode = GET_MODE (x);
       if (BITS_BIG_ENDIAN)
        bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
       if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
@@ -2318,7 +2915,7 @@ noce_try_bitop (struct noce_if_info *if_info)
       if (! rtx_equal_p (x, XEXP (a, 0))
           || !CONST_INT_P (XEXP (a, 1))
          || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
-            != (unsigned HOST_WIDE_INT) 1 << bitnum)
+            != HOST_WIDE_INT_1U << bitnum)
         return FALSE;
 
       /* if ((x & C) == 0) x |= C; is transformed to x |= C.   */
@@ -2328,13 +2925,13 @@ noce_try_bitop (struct noce_if_info *if_info)
       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 = 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 = gen_int_mode (~(HOST_WIDE_INT_1 << bitnum), mode);
          result = simplify_gen_binary (AND, mode, x, result);
        }
     }
@@ -2344,7 +2941,7 @@ noce_try_bitop (struct noce_if_info *if_info)
       if (! rtx_equal_p (x, XEXP (a, 0))
          || !CONST_INT_P (XEXP (a, 1))
          || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
-            != (~((HOST_WIDE_INT) 1 << bitnum) & 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.  */
@@ -2365,6 +2962,7 @@ noce_try_bitop (struct noce_if_info *if_info)
       emit_insn_before_setloc (seq, if_info->jump,
                               INSN_LOCATION (if_info->insn_a));
     }
+  if_info->transform_name = "noce_try_bitop";
   return TRUE;
 }
 
@@ -2389,7 +2987,7 @@ noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed
   /* If this branches to JUMP_LABEL when the condition is false,
      reverse the condition.  */
   reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
-            && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (jump));
+            && label_ref_label (XEXP (SET_SRC (set), 2)) == 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
@@ -2416,7 +3014,7 @@ noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed
   /* Otherwise, fall back on canonicalize_condition to do the dirty
      work of manipulating MODE_CC values and COMPARE rtx codes.  */
   tmp = canonicalize_condition (jump, cond, reverse, earliest,
-                               NULL_RTX, HAVE_cbranchcc4, true);
+                               NULL_RTX, have_cbranchcc4, true);
 
   /* We don't handle side-effects in the condition, like handling
      REG_INC notes and making sure no duplicate conditions are emitted.  */
@@ -2442,95 +3040,390 @@ noce_operand_ok (const_rtx op)
   return ! may_trap_p (op);
 }
 
-/* Return true if a write into MEM may trap or fault.  */
+/* Return true iff basic block TEST_BB is valid for noce if-conversion.
+   The condition used in this if-conversion is in COND.
+   In practice, check that TEST_BB ends with a single set
+   x := a and all previous computations
+   in TEST_BB don't produce any values that are live after TEST_BB.
+   In other words, all the insns in TEST_BB are there only
+   to compute a value for x.  Add the rtx cost of the insns
+   in TEST_BB to COST.  Record whether TEST_BB is a single simple
+   set instruction in SIMPLE_P.  */
 
 static bool
-noce_mem_write_may_trap_or_fault_p (const_rtx mem)
+bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
+                             unsigned int *cost, bool *simple_p)
 {
-  rtx addr;
+  if (!test_bb)
+    return false;
 
-  if (MEM_READONLY_P (mem))
-    return true;
+  rtx_insn *last_insn = last_active_insn (test_bb, FALSE);
+  rtx last_set = NULL_RTX;
 
-  if (may_trap_or_fault_p (mem))
-    return true;
+  rtx cc = cc_in_cond (cond);
 
-  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 (CONST_INT_P (XEXP (addr, 1)))
-         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;
-      }
+  if (!insn_valid_noce_process_p (last_insn, cc))
+    return false;
+  last_set = single_set (last_insn);
+
+  rtx x = SET_DEST (last_set);
+  rtx_insn *first_insn = first_active_insn (test_bb);
+  rtx first_set = single_set (first_insn);
+
+  if (!first_set)
+    return false;
+
+  /* We have a single simple set, that's okay.  */
+  bool speed_p = optimize_bb_for_speed_p (test_bb);
+
+  if (first_insn == last_insn)
+    {
+      *simple_p = noce_operand_ok (SET_DEST (first_set));
+      *cost += pattern_cost (first_set, speed_p);
+      return *simple_p;
+    }
+
+  rtx_insn *prev_last_insn = PREV_INSN (last_insn);
+  gcc_assert (prev_last_insn);
+
+  /* For now, disallow setting x multiple times in test_bb.  */
+  if (REG_P (x) && reg_set_between_p (x, first_insn, prev_last_insn))
+    return false;
+
+  bitmap test_bb_temps = BITMAP_ALLOC (&reg_obstack);
+
+  /* The regs that are live out of test_bb.  */
+  bitmap test_bb_live_out = df_get_live_out (test_bb);
+
+  int potential_cost = pattern_cost (last_set, speed_p);
+  rtx_insn *insn;
+  FOR_BB_INSNS (test_bb, insn)
+    {
+      if (insn != last_insn)
+       {
+         if (!active_insn_p (insn))
+           continue;
+
+         if (!insn_valid_noce_process_p (insn, cc))
+           goto free_bitmap_and_fail;
+
+         rtx sset = single_set (insn);
+         gcc_assert (sset);
+
+         if (contains_mem_rtx_p (SET_SRC (sset))
+             || !REG_P (SET_DEST (sset))
+             || reg_overlap_mentioned_p (SET_DEST (sset), cond))
+           goto free_bitmap_and_fail;
+
+         potential_cost += pattern_cost (sset, speed_p);
+         bitmap_set_bit (test_bb_temps, REGNO (SET_DEST (sset)));
+       }
+    }
+
+  /* If any of the intermediate results in test_bb are live after test_bb
+     then fail.  */
+  if (bitmap_intersect_p (test_bb_live_out, test_bb_temps))
+    goto free_bitmap_and_fail;
+
+  BITMAP_FREE (test_bb_temps);
+  *cost += potential_cost;
+  *simple_p = false;
+  return true;
 
+ free_bitmap_and_fail:
+  BITMAP_FREE (test_bb_temps);
   return false;
 }
 
-/* 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.  */
+/* We have something like:
 
-static bool
-noce_can_store_speculate_p (basic_block top_bb, const_rtx mem)
+     if (x > y)
+       { i = a; j = b; k = c; }
+
+   Make it:
+
+     tmp_i = (x > y) ? a : i;
+     tmp_j = (x > y) ? b : j;
+     tmp_k = (x > y) ? c : k;
+     i = tmp_i;
+     j = tmp_j;
+     k = tmp_k;
+
+   Subsequent passes are expected to clean up the extra moves.
+
+   Look for special cases such as writes to one register which are
+   read back in another SET, as might occur in a swap idiom or
+   similar.
+
+   These look like:
+
+   if (x > y)
+     i = a;
+     j = i;
+
+   Which we want to rewrite to:
+
+     tmp_i = (x > y) ? a : i;
+     tmp_j = (x > y) ? tmp_i : j;
+     i = tmp_i;
+     j = tmp_j;
+
+   We can catch these when looking at (SET x y) by keeping a list of the
+   registers we would have targeted before if-conversion and looking back
+   through it for an overlap with Y.  If we find one, we rewire the
+   conditional set to use the temporary we introduced earlier.
+
+   IF_INFO contains the useful information about the block structure and
+   jump instructions.  */
+
+static int
+noce_convert_multiple_sets (struct noce_if_info *if_info)
 {
-  basic_block dominator;
+  basic_block test_bb = if_info->test_bb;
+  basic_block then_bb = if_info->then_bb;
+  basic_block join_bb = if_info->join_bb;
+  rtx_insn *jump = if_info->jump;
+  rtx_insn *cond_earliest;
+  rtx_insn *insn;
+
+  start_sequence ();
+
+  /* Decompose the condition attached to the jump.  */
+  rtx cond = noce_get_condition (jump, &cond_earliest, false);
+  rtx x = XEXP (cond, 0);
+  rtx y = XEXP (cond, 1);
+  rtx_code cond_code = GET_CODE (cond);
+
+  /* The true targets for a conditional move.  */
+  auto_vec<rtx> targets;
+  /* The temporaries introduced to allow us to not consider register
+     overlap.  */
+  auto_vec<rtx> temporaries;
+  /* The insns we've emitted.  */
+  auto_vec<rtx_insn *> unmodified_insns;
+  int count = 0;
 
-  for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
-       dominator != NULL;
-       dominator = get_immediate_dominator (CDI_POST_DOMINATORS, dominator))
+  FOR_BB_INSNS (then_bb, insn)
     {
-      rtx_insn *insn;
+      /* Skip over non-insns.  */
+      if (!active_insn_p (insn))
+       continue;
+
+      rtx set = single_set (insn);
+      gcc_checking_assert (set);
+
+      rtx target = SET_DEST (set);
+      rtx temp = gen_reg_rtx (GET_MODE (target));
+      rtx new_val = SET_SRC (set);
+      rtx old_val = target;
+
+      /* If we were supposed to read from an earlier write in this block,
+        we've changed the register allocation.  Rewire the read.  While
+        we are looking, also try to catch a swap idiom.  */
+      for (int i = count - 1; i >= 0; --i)
+       if (reg_overlap_mentioned_p (new_val, targets[i]))
+         {
+           /* Catch a "swap" style idiom.  */
+           if (find_reg_note (insn, REG_DEAD, new_val) != NULL_RTX)
+             /* The write to targets[i] is only live until the read
+                here.  As the condition codes match, we can propagate
+                the set to here.  */
+             new_val = SET_SRC (single_set (unmodified_insns[i]));
+           else
+             new_val = temporaries[i];
+           break;
+         }
 
-      FOR_BB_INSNS (dominator, insn)
+      /* If we had a non-canonical conditional jump (i.e. one where
+        the fallthrough is to the "else" case) we need to reverse
+        the conditional select.  */
+      if (if_info->then_else_reversed)
+       std::swap (old_val, new_val);
+
+
+      /* We allow simple lowpart register subreg SET sources in
+        bb_ok_for_noce_convert_multiple_sets.  Be careful when processing
+        sequences like:
+        (set (reg:SI r1) (reg:SI r2))
+        (set (reg:HI r3) (subreg:HI (r1)))
+        For the second insn new_val or old_val (r1 in this example) will be
+        taken from the temporaries and have the wider mode which will not
+        match with the mode of the other source of the conditional move, so
+        we'll end up trying to emit r4:HI = cond ? (r1:SI) : (r3:HI).
+        Wrap the two cmove operands into subregs if appropriate to prevent
+        that.  */
+      if (GET_MODE (new_val) != GET_MODE (temp))
        {
-         /* 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;
+         machine_mode src_mode = GET_MODE (new_val);
+         machine_mode dst_mode = GET_MODE (temp);
+         if (!partial_subreg_p (dst_mode, src_mode))
+           {
+             end_sequence ();
+             return FALSE;
+           }
+         new_val = lowpart_subreg (dst_mode, new_val, src_mode);
+       }
+      if (GET_MODE (old_val) != GET_MODE (temp))
+       {
+         machine_mode src_mode = GET_MODE (old_val);
+         machine_mode dst_mode = GET_MODE (temp);
+         if (!partial_subreg_p (dst_mode, src_mode))
+           {
+             end_sequence ();
+             return FALSE;
+           }
+         old_val = lowpart_subreg (dst_mode, old_val, src_mode);
+       }
 
-         if (memory_must_be_modified_in_insn_p (mem, insn))
-           return true;
-         if (modified_in_p (XEXP (mem, 0), insn))
-           return false;
+      /* Actually emit the conditional move.  */
+      rtx temp_dest = noce_emit_cmove (if_info, temp, cond_code,
+                                      x, y, new_val, old_val);
 
+      /* If we failed to expand the conditional move, drop out and don't
+        try to continue.  */
+      if (temp_dest == NULL_RTX)
+       {
+         end_sequence ();
+         return FALSE;
        }
+
+      /* Bookkeeping.  */
+      count++;
+      targets.safe_push (target);
+      temporaries.safe_push (temp_dest);
+      unmodified_insns.safe_push (insn);
     }
 
-  return false;
+  /* We must have seen some sort of insn to insert, otherwise we were
+     given an empty BB to convert, and we can't handle that.  */
+  gcc_assert (!unmodified_insns.is_empty ());
+
+  /* Now fixup the assignments.  */
+  for (int i = 0; i < count; i++)
+    noce_emit_move_insn (targets[i], temporaries[i]);
+
+  /* Actually emit the sequence if it isn't too expensive.  */
+  rtx_insn *seq = get_insns ();
+
+  if (!targetm.noce_conversion_profitable_p (seq, if_info))
+    {
+      end_sequence ();
+      return FALSE;
+    }
+
+  for (insn = seq; insn; insn = NEXT_INSN (insn))
+    set_used_flags (insn);
+
+  /* Mark all our temporaries and targets as used.  */
+  for (int i = 0; i < count; i++)
+    {
+      set_used_flags (temporaries[i]);
+      set_used_flags (targets[i]);
+    }
+
+  set_used_flags (cond);
+  set_used_flags (x);
+  set_used_flags (y);
+
+  unshare_all_rtl_in_chain (seq);
+  end_sequence ();
+
+  if (!seq)
+    return FALSE;
+
+  for (insn = seq; insn; insn = NEXT_INSN (insn))
+    if (JUMP_P (insn)
+       || recog_memoized (insn) == -1)
+      return FALSE;
+
+  emit_insn_before_setloc (seq, if_info->jump,
+                          INSN_LOCATION (unmodified_insns.last ()));
+
+  /* Clean up THEN_BB and the edges in and out of it.  */
+  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++;
+
+  /* Maybe merge blocks now the jump is simple enough.  */
+  if (can_merge_blocks_p (test_bb, join_bb))
+    {
+      merge_blocks (test_bb, join_bb);
+      num_true_changes++;
+    }
+
+  num_updated_if_blocks++;
+  if_info->transform_name = "noce_convert_multiple_sets";
+  return TRUE;
+}
+
+/* Return true iff basic block TEST_BB is comprised of only
+   (SET (REG) (REG)) insns suitable for conversion to a series
+   of conditional moves.  Also check that we have more than one set
+   (other routines can handle a single set better than we would), and
+   fewer than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets.  */
+
+static bool
+bb_ok_for_noce_convert_multiple_sets (basic_block test_bb)
+{
+  rtx_insn *insn;
+  unsigned count = 0;
+  unsigned param = param_max_rtl_if_conversion_insns;
+
+  FOR_BB_INSNS (test_bb, insn)
+    {
+      /* Skip over notes etc.  */
+      if (!active_insn_p (insn))
+       continue;
+
+      /* We only handle SET insns.  */
+      rtx set = single_set (insn);
+      if (set == NULL_RTX)
+       return false;
+
+      rtx dest = SET_DEST (set);
+      rtx src = SET_SRC (set);
+
+      /* We can possibly relax this, but for now only handle REG to REG
+        (including subreg) moves.  This avoids any issues that might come
+        from introducing loads/stores that might violate data-race-freedom
+        guarantees.  */
+      if (!REG_P (dest))
+       return false;
+
+      if (!(REG_P (src)
+          || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
+              && subreg_lowpart_p (src))))
+       return false;
+
+      /* Destination must be appropriate for a conditional write.  */
+      if (!noce_operand_ok (dest))
+       return false;
+
+      /* We must be able to conditionally move in this mode.  */
+      if (!can_conditionally_move_p (GET_MODE (dest)))
+       return false;
+
+      count++;
+    }
+
+  /* If we would only put out one conditional move, the other strategies
+     this pass tries are better optimized and will be more appropriate.
+     Some targets want to strictly limit the number of conditional moves
+     that are emitted, they set this through PARAM, we need to respect
+     that.  */
+  return count > 1 && count <= param;
+}
+
+/* Compute average of two given costs weighted by relative probabilities
+   of respective basic blocks in an IF-THEN-ELSE.  E is the IF-THEN edge.
+   With P as the probability to take the IF-THEN branch, return
+   P * THEN_COST + (1 - P) * ELSE_COST.  */
+static unsigned
+average_cost (unsigned then_cost, unsigned else_cost, edge e)
+{
+  return else_cost + e->probability.apply ((signed) (then_cost - else_cost));
 }
 
 /* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
@@ -2549,24 +3442,53 @@ noce_process_if_block (struct noce_if_info *if_info)
   rtx_insn *insn_a, *insn_b;
   rtx set_a, set_b;
   rtx orig_x, x, a, b;
-  rtx cc;
 
   /* We're looking for patterns of the form
 
      (1) if (...) x = a; else x = b;
      (2) x = b; if (...) x = a;
      (3) if (...) x = a;   // as if with an initial x = x.
-
+     (4) if (...) { x = a; y = b; z = c; }  // Like 3, for multiple SETS.
      The later patterns require jumps to be more expensive.
+     For the if (...) x = a; else x = b; case we allow multiple insns
+     inside the then and else blocks as long as their only effect is
+     to calculate a value for x.
+     ??? For future expansion, further expand the "multiple X" rules.  */
+
+  /* First look for multiple SETS.  */
+  if (!else_bb
+      && HAVE_conditional_move
+      && bb_ok_for_noce_convert_multiple_sets (then_bb))
+    {
+      if (noce_convert_multiple_sets (if_info))
+       {
+         if (dump_file && if_info->transform_name)
+           fprintf (dump_file, "if-conversion succeeded through %s\n",
+                    if_info->transform_name);
+         return TRUE;
+       }
+    }
 
-     ??? For future expansion, look for multiple X in such patterns.  */
+  bool speed_p = optimize_bb_for_speed_p (test_bb);
+  unsigned int then_cost = 0, else_cost = 0;
+  if (!bb_valid_for_noce_process_p (then_bb, cond, &then_cost,
+                                   &if_info->then_simple))
+    return false;
 
-  /* Look for one of the potential sets.  */
-  insn_a = first_active_insn (then_bb);
-  if (! insn_a
-      || insn_a != last_active_insn (then_bb, FALSE)
-      || (set_a = single_set (insn_a)) == NULL_RTX)
-    return FALSE;
+  if (else_bb
+      && !bb_valid_for_noce_process_p (else_bb, cond, &else_cost,
+                                      &if_info->else_simple))
+    return false;
+
+  if (speed_p)
+    if_info->original_cost += average_cost (then_cost, else_cost,
+                                           find_edge (test_bb, then_bb));
+  else
+    if_info->original_cost += then_cost + else_cost;
+
+  insn_a = last_active_insn (then_bb, FALSE);
+  set_a = single_set (insn_a);
+  gcc_assert (set_a);
 
   x = SET_DEST (set_a);
   a = SET_SRC (set_a);
@@ -2581,16 +3503,23 @@ noce_process_if_block (struct noce_if_info *if_info)
   set_b = NULL_RTX;
   if (else_bb)
     {
-      insn_b = first_active_insn (else_bb);
-      if (! insn_b
-         || insn_b != last_active_insn (else_bb, FALSE)
-         || (set_b = single_set (insn_b)) == NULL_RTX
-         || ! rtx_interchangeable_p (x, SET_DEST (set_b)))
+      insn_b = last_active_insn (else_bb, FALSE);
+      set_b = single_set (insn_b);
+      gcc_assert (set_b);
+
+      if (!rtx_interchangeable_p (x, SET_DEST (set_b)))
        return FALSE;
     }
   else
     {
-      insn_b = prev_nonnote_nondebug_insn (if_info->cond_earliest);
+      insn_b = if_info->cond_earliest;
+      do
+       insn_b = prev_nonnote_nondebug_insn (insn_b);
+      while (insn_b
+            && (BLOCK_FOR_INSN (insn_b)
+                == BLOCK_FOR_INSN (if_info->cond_earliest))
+            && !modified_in_p (x, insn_b));
+
       /* 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.  */
@@ -2633,6 +3562,7 @@ noce_process_if_block (struct noce_if_info *if_info)
   /* Only operate on register destinations, and even then avoid extending
      the lifetime of hard registers on small register class machines.  */
   orig_x = x;
+  if_info->orig_x = orig_x;
   if (!REG_P (x)
       || (HARD_REGISTER_P (x)
          && targetm.small_register_classes_for_mode_p (GET_MODE (x))))
@@ -2661,20 +3591,14 @@ noce_process_if_block (struct noce_if_info *if_info)
   if_info->a = a;
   if_info->b = b;
 
-  /* Skip it if the instruction to be moved might clobber CC.  */
-  cc = cc_in_cond (cond);
-  if (cc
-      && (set_of (cc, insn_a)
-         || (insn_b && set_of (cc, insn_b))))
-    return FALSE;
-
   /* Try optimizations in some approximation of a useful order.  */
   /* ??? Should first look to see if X is live incoming at all.  If it
      isn't, we don't need anything but an unconditional set.  */
 
   /* Look and see if A and B are really the same.  Avoid creating silly
      cmove constructs that no one will fix up later.  */
-  if (rtx_interchangeable_p (a, b))
+  if (noce_simple_bbs (if_info)
+      && rtx_interchangeable_p (a, b))
     {
       /* If we have an INSN_B, we don't have to create any new rtl.  Just
         move the instruction that we already have.  If we don't have an
@@ -2705,33 +3629,17 @@ noce_process_if_block (struct noce_if_info *if_info)
     }
 
   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;
-    }
+    /* We want to avoid store speculation to avoid cases like
+        if (pthread_mutex_trylock(mutex))
+          ++global_variable;
+       Rather than go to much effort here, we rely on the SSA optimizers,
+       which do a good enough job these days.  */
+    return FALSE;
 
   if (noce_try_move (if_info))
     goto success;
+  if (noce_try_ifelse_collapse (if_info))
+    goto success;
   if (noce_try_store_flag (if_info))
     goto success;
   if (noce_try_bitop (if_info))
@@ -2740,13 +3648,16 @@ noce_process_if_block (struct noce_if_info *if_info)
     goto success;
   if (noce_try_abs (if_info))
     goto success;
+  if (noce_try_inverse_constants (if_info))
+    goto success;
+  if (!targetm.have_conditional_execution ()
+      && noce_try_store_flag_constants (if_info))
+    goto success;
   if (HAVE_conditional_move
       && noce_try_cmove (if_info))
     goto success;
   if (! targetm.have_conditional_execution ())
     {
-      if (noce_try_store_flag_constants (if_info))
-       goto success;
       if (noce_try_addcc (if_info))
        goto success;
       if (noce_try_store_flag_mask (if_info))
@@ -2769,6 +3680,9 @@ noce_process_if_block (struct noce_if_info *if_info)
   return FALSE;
 
  success:
+  if (dump_file && if_info->transform_name)
+    fprintf (dump_file, "if-conversion succeeded through %s\n",
+            if_info->transform_name);
 
   /* If we used a temporary, fix it up now.  */
   if (orig_x != x)
@@ -2975,12 +3889,11 @@ cond_move_process_if_block (struct noce_if_info *if_info)
   rtx_insn *jump = if_info->jump;
   rtx cond = if_info->cond;
   rtx_insn *seq, *loc_insn;
-  rtx reg;
   int c;
   vec<rtx> then_regs = vNULL;
   vec<rtx> else_regs = vNULL;
-  unsigned int i;
   int success_p = FALSE;
+  int limit = param_max_rtl_if_conversion_insns;
 
   /* Build a mapping for each block to the value used for each
      register.  */
@@ -3000,7 +3913,7 @@ cond_move_process_if_block (struct noce_if_info *if_info)
      source register does not change after the assignment.  Also count
      the number of registers set in only one of the blocks.  */
   c = 0;
-  FOR_EACH_VEC_ELT (then_regs, i, reg)
+  for (rtx reg : then_regs)
     {
       rtx *then_slot = then_vals.get (reg);
       rtx *else_slot = else_vals.get (reg);
@@ -3019,7 +3932,7 @@ cond_move_process_if_block (struct noce_if_info *if_info)
     }
 
   /* Finish off c for MAX_CONDITIONAL_EXECUTE.  */
-  FOR_EACH_VEC_ELT (else_regs, i, reg)
+  for (rtx reg : else_regs)
     {
       gcc_checking_assert (else_vals.get (reg));
       if (!then_vals.get (reg))
@@ -3030,7 +3943,8 @@ cond_move_process_if_block (struct noce_if_info *if_info)
      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)
+  if (c > MAX_CONDITIONAL_EXECUTE
+      || c > limit)
     goto done;
 
   /* Try to emit the conditional moves.  First do the then block,
@@ -3077,7 +3991,6 @@ cond_move_process_if_block (struct noce_if_info *if_info)
     }
 
   num_updated_if_blocks++;
-
   success_p = TRUE;
 
 done:
@@ -3105,6 +4018,7 @@ noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge,
   rtx cond;
   rtx_insn *cond_earliest;
   struct noce_if_info if_info;
+  bool speed_p = optimize_bb_for_speed_p (test_bb);
 
   /* We only ever should get here before reload.  */
   gcc_assert (!reload_completed);
@@ -3172,7 +4086,7 @@ noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge,
     }
 
   /* If the conditional jump is more than just a conditional
-     jump, then we can not do if-conversion on this block.  */
+     jump, then we cannot do if-conversion on this block.  */
   jump = BB_END (test_bb);
   if (! onlyjump_p (jump))
     return FALSE;
@@ -3193,11 +4107,24 @@ noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge,
   if_info.else_bb = else_bb;
   if_info.join_bb = join_bb;
   if_info.cond = cond;
+  rtx_insn *rev_cond_earliest;
+  if_info.rev_cond = noce_get_condition (jump, &rev_cond_earliest,
+                                        !then_else_reversed);
+  gcc_assert (if_info.rev_cond == NULL_RTX
+             || rev_cond_earliest == cond_earliest);
   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));
+  if_info.speed_p = speed_p;
+  if_info.max_seq_cost
+    = targetm.max_noce_ifcvt_seq_cost (then_edge);
+  /* We'll add in the cost of THEN_BB and ELSE_BB later, when we check
+     that they are valid to transform.  We can't easily get back to the insn
+     for COND (and it may not exist if we had to canonicalize to get COND),
+     and jump_insns are always given a cost of 1 by seq_cost, so treat
+     both instructions as having cost COSTS_N_INSNS (1).  */
+  if_info.original_cost = COSTS_N_INSNS (2);
+
 
   /* Do the real work.  */
 
@@ -3414,7 +4341,7 @@ find_if_header (basic_block test_bb, int pass)
       && cond_exec_find_if_block (&ce_info))
     goto success;
 
-  if (HAVE_trap
+  if (targetm.have_trap ()
       && optab_handler (ctrap_optab, word_mode) != CODE_FOR_nothing
       && find_cond_trap (test_bb, then_edge, else_edge))
     goto success;
@@ -3755,7 +4682,6 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
   rtx_insn *trap, *jump;
   rtx cond;
   rtx_insn *cond_earliest;
-  enum rtx_code code;
 
   /* Locate the block with the trap instruction.  */
   /* ??? While we look for no successors, we really ought to allow
@@ -3775,35 +4701,34 @@ 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, false);
+  cond = noce_get_condition (jump, &cond_earliest, then_bb == trap_bb);
   if (! cond)
     return FALSE;
 
   /* If the conditional jump is more than just a conditional jump, then
-     we can not do if-conversion on this block.  */
-  if (! onlyjump_p (jump))
+     we cannot do if-conversion on this block.  Give up for returnjump_p,
+     changing a conditional return followed by unconditional trap for
+     conditional trap followed by unconditional return is likely not
+     beneficial and harder to handle.  */
+  if (! onlyjump_p (jump) || returnjump_p (jump))
     return FALSE;
 
   /* We must be comparing objects whose modes imply the size.  */
   if (GET_MODE (XEXP (cond, 0)) == BLKmode)
     return FALSE;
 
-  /* Reverse the comparison code, if necessary.  */
-  code = GET_CODE (cond);
-  if (then_bb == trap_bb)
-    {
-      code = reversed_comparison_code (cond, jump);
-      if (code == UNKNOWN)
-       return FALSE;
-    }
-
   /* Attempt to generate the conditional trap.  */
-  rtx_insn *seq = gen_cond_trap (code, copy_rtx (XEXP (cond, 0)),
+  rtx_insn *seq = gen_cond_trap (GET_CODE (cond), copy_rtx (XEXP (cond, 0)),
                                 copy_rtx (XEXP (cond, 1)),
                                 TRAP_CODE (PATTERN (trap)));
   if (seq == NULL)
     return FALSE;
 
+  /* If that results in an invalid insn, back out.  */
+  for (rtx_insn *x = seq; x; x = NEXT_INSN (x))
+    if (recog_memoized (x) < 0)
+      return FALSE;
+
   /* Emit the new insns before cond_earliest.  */
   emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATION (trap));
 
@@ -3952,7 +4877,8 @@ 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;
   basic_block new_bb;
-  int then_bb_index, then_prob;
+  int then_bb_index;
+  profile_probability then_prob;
   rtx else_target = NULL_RTX;
 
   /* If we are partitioning hot/cold basic blocks, we don't want to
@@ -3998,10 +4924,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
             "\nIF-CASE-1 found, start %d, then %d\n",
             test_bb->index, then_bb->index);
 
-  if (then_edge->probability)
-    then_prob = REG_BR_PROB_BASE - then_edge->probability;
-  else
-    then_prob = REG_BR_PROB_BASE / 2;
+  then_prob = then_edge->probability.invert ();
 
   /* We're speculating from the THEN path, we want to make sure the cost
      of speculation is within reason.  */
@@ -4061,7 +4984,6 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
 
   num_true_changes++;
   num_updated_if_blocks++;
-
   return TRUE;
 }
 
@@ -4073,7 +4995,7 @@ 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 then_prob, else_prob;
+  profile_probability then_prob, else_prob;
 
   /* We do not want to speculate (empty) loop latches.  */
   if (current_loops
@@ -4119,16 +5041,8 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
   if (then_bb->index < NUM_FIXED_BLOCKS)
     return FALSE;
 
-  if (else_edge->probability)
-    {
-      else_prob = else_edge->probability;
-      then_prob = REG_BR_PROB_BASE - else_prob;
-    }
-  else
-    {
-      else_prob = REG_BR_PROB_BASE / 2;
-      then_prob = REG_BR_PROB_BASE / 2;
-    }
+  else_prob = else_edge->probability;
+  then_prob = else_prob.invert ();
 
   /* ELSE is predicted or SUCC(ELSE) postdominates THEN.  */
   if (else_prob > then_prob)
@@ -4269,12 +5183,19 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
 
       rtx cond;
 
+      /* If the conditional jump is more than just a conditional jump,
+        then we cannot do conditional execution conversion on this block.  */
+      if (!onlyjump_p (jump))
+       goto nce;
+
       cond = cond_exec_get_condition (jump);
       if (! cond)
-       return FALSE;
+       goto nce;
 
       rtx note = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
-      int prob_val = (note ? XINT (note, 0) : -1);
+      profile_probability prob_val
+         = (note ? profile_probability::from_reg_br_prob_note (XINT (note, 0))
+            : profile_probability::uninitialized ());
 
       if (reversep)
        {
@@ -4283,8 +5204,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
            return FALSE;
          cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
                                 XEXP (cond, 1));
-         if (prob_val >= 0)
-           prob_val = REG_BR_PROB_BASE - prob_val;
+         prob_val = prob_val.invert ();
        }
 
       if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0)
@@ -4295,6 +5215,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
 
       earliest = jump;
     }
+ nce:
 #endif
 
   /* If we allocated new pseudos (e.g. in the conditional move
@@ -4432,8 +5353,6 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
       redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
       if (reversep)
        {
-         std::swap (BRANCH_EDGE (test_bb)->count,
-                    FALLTHRU_EDGE (test_bb)->count);
          std::swap (BRANCH_EDGE (test_bb)->probability,
                     FALLTHRU_EDGE (test_bb)->probability);
          update_br_prob_note (test_bb);
@@ -4516,6 +5435,8 @@ if_convert (bool after_combine)
 
   /* Record whether we are after combine pass.  */
   ifcvt_after_combine = after_combine;
+  have_cbranchcc4 = (direct_optab_handler (cbranch_optab, CCmode)
+                    != CODE_FOR_nothing);
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
   num_true_changes = 0;
@@ -4595,15 +5516,19 @@ if_convert (bool after_combine)
   if (optimize == 1)
     df_remove_problem (df_live);
 
-#ifdef ENABLE_CHECKING
-  verify_flow_info ();
-#endif
+  /* Some non-cold blocks may now be only reachable from cold blocks.
+     Fix that up.  */
+  fixup_partitions ();
+
+  checking_verify_flow_info ();
 }
 \f
 /* If-conversion and CFG cleanup.  */
 static unsigned int
 rest_of_handle_if_conversion (void)
 {
+  int flags = 0;
+
   if (flag_if_conversion)
     {
       if (dump_file)
@@ -4613,9 +5538,12 @@ rest_of_handle_if_conversion (void)
        }
       cleanup_cfg (CLEANUP_EXPENSIVE);
       if_convert (false);
+      if (num_updated_if_blocks)
+       /* Get rid of any dead CC-related instructions.  */
+       flags |= CLEANUP_FORCE_FAST_DCE;
     }
 
-  cleanup_cfg (0);
+  cleanup_cfg (flags);
   return 0;
 }