]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ifcvt.c
Update copyright years.
[thirdparty/gcc.git] / gcc / ifcvt.c
index 723ea3eee91f587cd4d4bc64a7bef64a7b5d5be9..a9ea7b1808d0498dd5a1dca8f1f9f0baef5be5b3 100644 (file)
@@ -1,5 +1,5 @@
 /* If-conversion support.
-   Copyright (C) 2000-2016 Free Software Foundation, Inc.
+   Copyright (C) 2000-2020 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -26,6 +26,7 @@
 #include "tree.h"
 #include "cfghooks.h"
 #include "df.h"
+#include "memmodel.h"
 #include "tm_p.h"
 #include "expmed.h"
 #include "optabs.h"
@@ -44,7 +45,6 @@
 #include "shrink-wrap.h"
 #include "rtl-iter.h"
 #include "ifcvt.h"
-#include "params.h"
 
 #ifndef MAX_CONDITIONAL_EXECUTE
 #define MAX_CONDITIONAL_EXECUTE \
@@ -77,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);
@@ -122,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. 
 
@@ -131,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.
 
@@ -161,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;
 
@@ -331,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;
@@ -406,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)
@@ -435,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)
@@ -468,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 */
@@ -499,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;
 
@@ -614,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
@@ -648,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;
 
@@ -740,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);
@@ -759,61 +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;
-
-  /* True if the contents of then_bb and else_bb are a
-     simple single set instruction.  */
-  bool then_simple;
-  bool else_simple;
-
-  /* The total rtx cost of the instructions in then_bb and else_bb.  */
-  unsigned int then_cost;
-  unsigned int else_cost;
-
-  /* Estimated cost of the particular branch instruction.  */
-  unsigned 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 *);
@@ -827,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
@@ -848,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);
@@ -863,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 ();
@@ -901,7 +893,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)
     {
@@ -1112,11 +1104,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
@@ -1140,8 +1166,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;
@@ -1160,6 +1185,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
@@ -1238,6 +1264,7 @@ noce_try_inverse_constants (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_inverse_constants";
       return true;
     }
 
@@ -1259,7 +1286,7 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
   HOST_WIDE_INT itrue, ifalse, diff, tmp;
   int normalize;
   bool can_reverse;
-  machine_mode mode = GET_MODE (if_info->x);;
+  machine_mode mode = GET_MODE (if_info->x);
   rtx common = NULL_RTX;
 
   rtx a = if_info->a;
@@ -1271,8 +1298,11 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       && CONST_INT_P (XEXP (a, 1))
       && CONST_INT_P (XEXP (b, 1))
       && rtx_equal_p (XEXP (a, 0), XEXP (b, 0))
-      && noce_operand_ok (XEXP (a, 0))
-      && if_info->branch_cost >= 2)
+      /* 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);
@@ -1297,9 +1327,7 @@ 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);
-
+      can_reverse = noce_reversed_cond_code (if_info) != UNKNOWN;
       reversep = false;
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
        {
@@ -1345,22 +1373,24 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
          else
            gcc_unreachable ();
        }
-      else if (ifalse == 0 && exact_log2 (itrue) >= 0
-              && (STORE_FLAG_VALUE == 1
-                  || if_info->branch_cost >= 2))
+      /* 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))
+      /* 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))
+              && STORE_FLAG_VALUE == -1)
        {
          normalize = -1;
          reversep = true;
@@ -1449,11 +1479,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;
     }
 
@@ -1475,11 +1507,18 @@ noce_try_addcc (struct noce_if_info *if_info)
 
   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)
@@ -1501,21 +1540,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)))
@@ -1541,11 +1582,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 ();
@@ -1568,15 +1610,12 @@ noce_try_store_flag_mask (struct noce_if_info *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,
@@ -1590,26 +1629,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;
        }
 
@@ -1693,12 +1723,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)
@@ -1755,11 +1785,13 @@ 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;
        }
       /* If both a and b are constants try a last-ditch transformation:
@@ -1770,9 +1802,7 @@ noce_try_cmove (struct noce_if_info *if_info)
         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)
-               && ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1)
-                   || if_info->branch_cost >= 3))
+               && CONST_INT_P (if_info->a) && CONST_INT_P (if_info->b))
        {
          machine_mode mode = GET_MODE (if_info->x);
          HOST_WIDE_INT ifalse = INTVAL (if_info->a);
@@ -1808,11 +1838,12 @@ 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
@@ -1867,11 +1898,13 @@ insn_valid_noce_process_p (rtx_insn *insn, rtx cc)
 }
 
 
-/* Return true iff the registers that the insns in BB_A set do not
-   get used in BB_B.  */
+/* 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)
+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);
@@ -1891,10 +1924,10 @@ bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b)
          BITMAP_FREE (bba_sets);
          return false;
        }
-
       /* Record all registers that BB_A sets.  */
       FOR_EACH_INSN_DEF (def, a_insn)
-       bitmap_set_bit (bba_sets, DF_REF_REGNO (def));
+       if (!(to_rename && DF_REF_REG (def) == to_rename))
+         bitmap_set_bit (bba_sets, DF_REF_REGNO (def));
     }
 
   rtx_insn *b_insn;
@@ -1913,8 +1946,15 @@ bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b)
        }
 
       /* Make sure this is a REG and not some instance
-        of ZERO_EXTRACT or SUBREG or other dangerous stuff.  */
-      if (!REG_P (SET_DEST (sset_b)))
+        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;
@@ -2005,17 +2045,16 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
   rtx target;
   int is_mem = 0;
   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);
 
@@ -2038,7 +2077,7 @@ 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;
 
@@ -2047,25 +2086,8 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
   if (!can_conditionally_move_p (x_mode))
     return FALSE;
 
-  unsigned int then_cost;
-  unsigned int else_cost;
-  if (insn_a)
-    then_cost = if_info->then_cost;
-  else
-    then_cost = 0;
-
-  if (insn_b)
-    else_cost = if_info->else_cost;
-  else
-    else_cost = 0;
-
-  /* We're going to execute one of the basic blocks anyway, so
-     bail out if the most expensive of the two blocks is unacceptable.  */
-  if (MAX (then_cost, else_cost) > COSTS_N_INSNS (if_info->branch_cost))
-    return FALSE;
-
   /* Possibly rearrange operands to make things come out more natural.  */
-  if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
+  if (noce_reversed_cond_code (if_info) != UNKNOWN)
     {
       int reversep = 0;
       if (rtx_equal_p (b, x))
@@ -2075,7 +2097,13 @@ 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);
@@ -2083,9 +2111,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
        }
     }
 
-  if (then_bb && else_bb && !a_simple && !b_simple
-      && (!bbs_ok_for_cmove_arith (then_bb, else_bb)
-         || !bbs_ok_for_cmove_arith (else_bb, then_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 ();
@@ -2111,7 +2139,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
   rtx emit_b = NULL_RTX;
   rtx_insn *tmp_insn = NULL;
   bool modified_in_a = false;
-  bool  modified_in_b = 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.
@@ -2169,7 +2197,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
              rtx tmp_reg = tmp_b ? tmp_b : gen_reg_rtx (GET_MODE (b));
              emit_b = gen_rtx_SET (tmp_reg, b);
              b = tmp_reg;
-         }
+           }
        }
     }
 
@@ -2224,8 +2252,8 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
   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;
@@ -2252,11 +2280,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:
@@ -2287,7 +2316,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;
 
@@ -2348,28 +2377,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);
@@ -2509,6 +2542,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;
 }
@@ -2675,6 +2710,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;
 }
@@ -2731,7 +2768,7 @@ noce_try_sign_mask (struct noce_if_info *if_info)
      && (if_info->insn_b == NULL_RTX
         || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb));
   if (!(t_unconditional
-       || (set_src_cost (t, mode, optimize_bb_for_speed_p (if_info->test_bb))
+       || (set_src_cost (t, mode, if_info->speed_p)
            < COSTS_N_INSNS (2))))
     return FALSE;
 
@@ -2756,6 +2793,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;
 }
 
@@ -2768,7 +2807,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;
 
@@ -2776,6 +2815,10 @@ 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;
 
@@ -2798,7 +2841,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)
@@ -2814,7 +2856,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.   */
@@ -2824,13 +2866,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);
        }
     }
@@ -2840,7 +2882,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.  */
@@ -2861,6 +2903,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;
 }
 
@@ -2885,7 +2928,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
@@ -2938,27 +2981,14 @@ noce_operand_ok (const_rtx op)
   return ! may_trap_p (op);
 }
 
-/* Return true if X contains a MEM subrtx.  */
-
-static bool
-contains_mem_rtx_p (rtx x)
-{
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, x, ALL)
-    if (MEM_P (*iter))
-      return true;
-
-  return false;
-}
-
 /* 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.  Put the rtx cost of the insns
-   in TEST_BB into COST.  Record whether TEST_BB is a single simple
+   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
@@ -2990,7 +3020,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
   if (first_insn == last_insn)
     {
       *simple_p = noce_operand_ok (SET_DEST (first_set));
-      *cost = insn_rtx_cost (first_set, speed_p);
+      *cost += pattern_cost (first_set, speed_p);
       return *simple_p;
     }
 
@@ -3006,7 +3036,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
   /* The regs that are live out of test_bb.  */
   bitmap test_bb_live_out = df_get_live_out (test_bb);
 
-  int potential_cost = insn_rtx_cost (last_set, speed_p);
+  int potential_cost = pattern_cost (last_set, speed_p);
   rtx_insn *insn;
   FOR_BB_INSNS (test_bb, insn)
     {
@@ -3026,7 +3056,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
              || reg_overlap_mentioned_p (SET_DEST (sset), cond))
            goto free_bitmap_and_fail;
 
-         potential_cost += insn_rtx_cost (sset, speed_p);
+         potential_cost += pattern_cost (sset, speed_p);
          bitmap_set_bit (test_bb_temps, REGNO (SET_DEST (sset)));
        }
     }
@@ -3037,7 +3067,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
     goto free_bitmap_and_fail;
 
   BITMAP_FREE (test_bb_temps);
-  *cost = potential_cost;
+  *cost += potential_cost;
   *simple_p = false;
   return true;
 
@@ -3151,6 +3181,41 @@ noce_convert_multiple_sets (struct noce_if_info *if_info)
       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))
+       {
+         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);
+       }
+
       /* Actually emit the conditional move.  */
       rtx temp_dest = noce_emit_cmove (if_info, temp, cond_code,
                                       x, y, new_val, old_val);
@@ -3178,9 +3243,15 @@ noce_convert_multiple_sets (struct noce_if_info *if_info)
   for (int i = 0; i < count; i++)
     noce_emit_move_insn (targets[i], temporaries[i]);
 
-  /* Actually emit the sequence.  */
+  /* 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);
 
@@ -3224,27 +3295,22 @@ noce_convert_multiple_sets (struct noce_if_info *if_info)
     }
 
   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.  FORNOW: Use II to find the expected cost of
-   the branch into/over TEST_BB.
-
-   TODO: This creates an implicit "magic number" for branch_cost.
-   II->branch_cost now guides the maximum number of set instructions in
-   a basic block which is considered profitable to completely
-   if-convert.  */
+   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,
-                                     struct noce_if_info *ii)
+bb_ok_for_noce_convert_multiple_sets (basic_block test_bb)
 {
   rtx_insn *insn;
   unsigned count = 0;
-  unsigned param = PARAM_VALUE (PARAM_MAX_RTL_IF_CONVERSION_INSNS);
-  unsigned limit = MIN (ii->branch_cost, param);
+  unsigned param = param_max_rtl_if_conversion_insns;
 
   FOR_BB_INSNS (test_bb, insn)
     {
@@ -3261,9 +3327,15 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb,
       rtx src = SET_SRC (set);
 
       /* We can possibly relax this, but for now only handle REG to REG
-        moves.  This avoids any issues that might come from introducing
-        loads/stores that might violate data-race-freedom guarantees.  */
-      if (!(REG_P (src) && REG_P (dest)))
+        (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.  */
@@ -3274,16 +3346,25 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb,
       if (!can_conditionally_move_p (GET_MODE (dest)))
        return false;
 
-      ++count;
+      count++;
     }
 
-  /* FORNOW: Our cost model is a count of the number of instructions we
-     would if-convert.  This is suboptimal, and should be improved as part
-     of a wider rework of branch_cost.  */
-  if (count > limit)
-    return false;
+  /* 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;
+}
 
-  return count > 0;
+/* 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
@@ -3319,21 +3400,34 @@ noce_process_if_block (struct noce_if_info *if_info)
   if (!else_bb
       && HAVE_conditional_move
       && !HAVE_cc0
-      && bb_ok_for_noce_convert_multiple_sets (then_bb, if_info))
+      && bb_ok_for_noce_convert_multiple_sets (then_bb))
     {
       if (noce_convert_multiple_sets (if_info))
-       return TRUE;
+       {
+         if (dump_file && if_info->transform_name)
+           fprintf (dump_file, "if-conversion succeeded through %s\n",
+                    if_info->transform_name);
+         return TRUE;
+       }
     }
 
-  if (! bb_valid_for_noce_process_p (then_bb, cond, &if_info->then_cost,
+  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;
 
   if (else_bb
-      && ! bb_valid_for_noce_process_p (else_bb, cond, &if_info->else_cost,
-                                     &if_info->else_simple))
+      && !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);
@@ -3360,7 +3454,14 @@ noce_process_if_block (struct noce_if_info *if_info)
     }
   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.  */
@@ -3403,6 +3504,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))))
@@ -3478,6 +3580,8 @@ noce_process_if_block (struct noce_if_info *if_info)
 
   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))
@@ -3518,6 +3622,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)
@@ -3730,6 +3837,7 @@ cond_move_process_if_block (struct noce_if_info *if_info)
   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.  */
@@ -3779,7 +3887,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,
@@ -3853,6 +3962,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);
@@ -3920,7 +4030,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;
@@ -3941,11 +4051,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.  */
 
@@ -4503,7 +4626,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
@@ -4523,12 +4645,12 @@ 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.  Give up for returnjump_p,
+     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.  */
@@ -4539,22 +4661,18 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
   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));
 
@@ -4703,7 +4821,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
@@ -4749,10 +4868,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.  */
@@ -4823,7 +4939,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
@@ -4869,16 +4985,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)
@@ -5024,7 +5132,9 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
        return FALSE;
 
       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)
        {
@@ -5033,8 +5143,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)
@@ -5182,8 +5291,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);
@@ -5347,6 +5454,10 @@ if_convert (bool after_combine)
   if (optimize == 1)
     df_remove_problem (df_live);
 
+  /* Some non-cold blocks may now be only reachable from cold blocks.
+     Fix that up.  */
+  fixup_partitions ();
+
   checking_verify_flow_info ();
 }
 \f
@@ -5354,6 +5465,8 @@ if_convert (bool after_combine)
 static unsigned int
 rest_of_handle_if_conversion (void)
 {
+  int flags = 0;
+
   if (flag_if_conversion)
     {
       if (dump_file)
@@ -5363,9 +5476,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;
 }