diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index f4ecc41..42c41b3 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1143,6 +1143,16 @@ (define_predicate "branch_comparison_operator"
 					      GET_MODE (XEXP (op, 0))),
 		     1")))
 
+;; Return 1 if OP is a comparison that needs an extra instruction to do (a
+;; crlogical or an extra branch).
+(define_predicate "extra_insn_branch_comparison_operator"
+   (and (match_operand 0 "comparison_operator")
+	(match_test "GET_MODE (XEXP (op, 0)) == CCFPmode")
+	(match_code "ltgt,le,ge,unlt,ungt,uneq")
+	(match_test "validate_condition_mode (GET_CODE (op),
+					      GET_MODE (XEXP (op, 0))),
+		     1")))
+
 ;; Return 1 if OP is an unsigned comparison operator.
 (define_predicate "unsigned_comparison_operator"
   (match_code "ltu,gtu,leu,geu"))
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 0dddb40..69e67ac 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -112,6 +112,7 @@ extern const char *rs6000_pltseq_template (rtx *, int);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
+extern rtx rs6000_emit_fp_cror (rtx_code, machine_mode, rtx);
 extern void rs6000_emit_sCOND (machine_mode, rtx[]);
 extern void rs6000_emit_cbranch (machine_mode, rtx[]);
 extern char * output_cbranch (rtx, const char *, int, rtx_insn *);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 0282ebd..2995348 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -13954,42 +13954,6 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
 				gen_rtx_COMPARE (comp_mode, op0, op1)));
     }
 
-  /* Some kinds of FP comparisons need an OR operation;
-     under flag_finite_math_only we don't bother.  */
-  if (FLOAT_MODE_P (mode)
-      && (!FLOAT128_IEEE_P (mode) || TARGET_FLOAT128_HW)
-      && !flag_finite_math_only
-      && (code == LE || code == GE
-	  || code == UNEQ || code == LTGT
-	  || code == UNGT || code == UNLT))
-    {
-      enum rtx_code or1, or2;
-      rtx or1_rtx, or2_rtx, compare2_rtx;
-      rtx or_result = gen_reg_rtx (CCEQmode);
-
-      switch (code)
-	{
-	case LE: or1 = LT;  or2 = EQ;  break;
-	case GE: or1 = GT;  or2 = EQ;  break;
-	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
-	case LTGT: or1 = LT;  or2 = GT;  break;
-	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
-	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
-	default:  gcc_unreachable ();
-	}
-      validate_condition_mode (or1, comp_mode);
-      validate_condition_mode (or2, comp_mode);
-      or1_rtx = gen_rtx_fmt_ee (or1, SImode, compare_result, const0_rtx);
-      or2_rtx = gen_rtx_fmt_ee (or2, SImode, compare_result, const0_rtx);
-      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
-				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
-				      const_true_rtx);
-      emit_insn (gen_rtx_SET (or_result, compare2_rtx));
-
-      compare_result = or_result;
-      code = EQ;
-    }
-
   validate_condition_mode (code, GET_MODE (compare_result));
 
   return gen_rtx_fmt_ee (code, VOIDmode, compare_result, const0_rtx);
@@ -14301,21 +14265,44 @@ rs6000_emit_eqne (machine_mode mode, rtx op1, rtx op2, rtx scratch)
   return scratch;
 }
 
+/* Emit code doing a cror of two CR bits, for FP comparisons with a CODE that
+   requires this.  The result is mode MODE.  */
+rtx
+rs6000_emit_fp_cror (rtx_code code, machine_mode mode, rtx x)
+{
+  rtx cond[2];
+  int n = 0;
+  if (code == LTGT || code == LE || code == UNLT)
+    cond[n++] = gen_rtx_fmt_ee (LT, mode, x, const0_rtx);
+  if (code == LTGT || code == GE || code == UNGT)
+    cond[n++] = gen_rtx_fmt_ee (GT, mode, x, const0_rtx);
+  if (code == LE || code == GE || code == UNEQ)
+    cond[n++] = gen_rtx_fmt_ee (EQ, mode, x, const0_rtx);
+  if (code == UNLT || code == UNGT || code == UNEQ)
+    cond[n++] = gen_rtx_fmt_ee (UNORDERED, mode, x, const0_rtx);
+
+  gcc_assert (n == 2);
+
+  rtx cc = gen_reg_rtx (CCEQmode);
+  rtx logical = gen_rtx_IOR (mode, cond[0], cond[1]);
+  emit_insn (gen_cceq_ior_compare (mode, cc, logical, cond[0], x, cond[1], x));
+
+  return cc;
+}
+
 void
 rs6000_emit_sCOND (machine_mode mode, rtx operands[])
 {
-  rtx condition_rtx;
-  machine_mode op_mode;
-  enum rtx_code cond_code;
-  rtx result = operands[0];
+  rtx condition_rtx = rs6000_generate_compare (operands[1], mode);
+  rtx_code cond_code = GET_CODE (condition_rtx);
 
-  condition_rtx = rs6000_generate_compare (operands[1], mode);
-  cond_code = GET_CODE (condition_rtx);
-
-  if (cond_code == NE
-      || cond_code == GE || cond_code == LE
-      || cond_code == GEU || cond_code == LEU
-      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
+  if (FLOAT_MODE_P (mode) && HONOR_NANS (mode)
+      && !(FLOAT128_VECTOR_P (mode) && !TARGET_FLOAT128_HW))
+    ;
+  else if (cond_code == NE
+	   || cond_code == GE || cond_code == LE
+	   || cond_code == GEU || cond_code == LEU
+	   || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
     {
       rtx not_result = gen_reg_rtx (CCEQmode);
       rtx not_op, rev_cond_rtx;
@@ -14330,19 +14317,19 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[])
       condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
     }
 
-  op_mode = GET_MODE (XEXP (operands[1], 0));
+  machine_mode op_mode = GET_MODE (XEXP (operands[1], 0));
   if (op_mode == VOIDmode)
     op_mode = GET_MODE (XEXP (operands[1], 1));
 
   if (TARGET_POWERPC64 && (op_mode == DImode || FLOAT_MODE_P (mode)))
     {
       PUT_MODE (condition_rtx, DImode);
-      convert_move (result, condition_rtx, 0);
+      convert_move (operands[0], condition_rtx, 0);
     }
   else
     {
       PUT_MODE (condition_rtx, SImode);
-      emit_insn (gen_rtx_SET (result, condition_rtx));
+      emit_insn (gen_rtx_SET (operands[0], condition_rtx));
     }
 }
 
@@ -14351,13 +14338,10 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[])
 void
 rs6000_emit_cbranch (machine_mode mode, rtx operands[])
 {
-  rtx condition_rtx, loc_ref;
-
-  condition_rtx = rs6000_generate_compare (operands[0], mode);
-  loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
-  emit_jump_insn (gen_rtx_SET (pc_rtx,
-			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
-						     loc_ref, pc_rtx)));
+  rtx condition_rtx = rs6000_generate_compare (operands[0], mode);
+  rtx loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
+  rtx ite = gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, loc_ref, pc_rtx);
+  emit_jump_insn (gen_rtx_SET (pc_rtx, ite));
 }
 
 /* Return the string to output a conditional branch to LABEL, which is
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 8dc0a29..dff5680 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -12373,6 +12373,44 @@ (define_insn_and_split "*nesi3_ext<mode>"
 	(if_then_else (match_test "operands[2] == const0_rtx")
 		      (const_string "12")
 		      (const_string "16")))])
+
+
+(define_code_iterator fp_rev [ordered ne unle unge])
+(define_code_iterator fp_two [ltgt le ge unlt ungt uneq])
+
+(define_insn_and_split "*<code><mode>_cc"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+	(fp_rev:GPR (match_operand:CCFP 1 "cc_reg_operand" "y")
+		    (const_int 0)))]
+  "!flag_finite_math_only"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  rtx_code revcode = reverse_condition_maybe_unordered (<CODE>);
+  rtx eq = gen_rtx_fmt_ee (revcode, <MODE>mode, operands[1], const0_rtx);
+  rtx tmp = gen_reg_rtx (<MODE>mode);
+  emit_move_insn (tmp, eq);
+  emit_insn (gen_xor<mode>3 (operands[0], tmp, const1_rtx));
+  DONE;
+}
+  [(set_attr "length" "12")])
+
+(define_insn_and_split "*<code><mode>_cc"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+	(fp_two:GPR (match_operand:CCFP 1 "cc_reg_operand" "y")
+		  (const_int 0)))]
+  "!flag_finite_math_only"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  rtx cc = rs6000_emit_fp_cror (<CODE>, <MODE>mode, operands[1]);
+
+  emit_move_insn (operands[0], gen_rtx_EQ (<MODE>mode, cc, const0_rtx));
+  DONE;
+}
+  [(set_attr "length" "12")])
 
 ;; Conditional branches.
 ;; These either are a single bc insn, or a bc around a b.
@@ -12397,6 +12435,46 @@ (define_insn "*cbranch"
 		      (const_int 4)
 		      (const_int 8)))])
 
+(define_insn_and_split "*cbranch_2insn"
+  [(set (pc)
+	(if_then_else (match_operator 1 "extra_insn_branch_comparison_operator"
+				      [(match_operand 2 "cc_reg_operand" "y")
+				       (const_int 0)])
+		      (label_ref (match_operand 0))
+		      (pc)))]
+  "!flag_finite_math_only"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  rtx cc = rs6000_emit_fp_cror (GET_CODE (operands[1]), SImode, operands[2]);
+
+  rtx note = find_reg_note (curr_insn, REG_BR_PROB, 0);
+
+  rtx loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[0]);
+  rtx cond = gen_rtx_EQ (CCEQmode, cc, const0_rtx);
+  rtx ite = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, loc_ref, pc_rtx);
+  emit_jump_insn (gen_rtx_SET (pc_rtx, ite));
+
+  if (note)
+    {
+      profile_probability prob
+	= profile_probability::from_reg_br_prob_note (XINT (note, 0));
+
+      add_reg_br_prob_note (get_last_insn (), prob);
+    }
+
+  DONE;
+}
+  [(set_attr "type" "branch")
+   (set (attr "length")
+	(if_then_else (and (ge (minus (match_dup 0) (pc))
+			       (const_int -32764))
+			   (lt (minus (match_dup 0) (pc))
+			       (const_int 32760)))
+		      (const_int 8)
+		      (const_int 16)))])
+
 ;; Conditional return.
 (define_insn "*creturn"
   [(set (pc)
