diff --git a/gcc/ccmp.c b/gcc/ccmp.c
index c1460aa..6382974 100644
--- a/gcc/ccmp.c
+++ b/gcc/ccmp.c
@@ -134,6 +134,13 @@ used_in_cond_stmt_p (tree exp)
 	  expand_cond = true;
 	BREAK_FROM_IMM_USE_STMT (ui);
       }
+    else if (gimple_code (use_stmt) == GIMPLE_ASSIGN
+	     && gimple_expr_code (use_stmt) == COND_EXPR)
+      {
+	if (gimple_assign_rhs1 (use_stmt) == exp)
+	  expand_cond = true;
+      }
+
   return expand_cond;
 }
 
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index e213cbe..c2cbdf0 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2589,15 +2589,19 @@
 			   (match_operand:ALLI 3 "register_operand" "")))]
   ""
   {
-    rtx ccreg;
     enum rtx_code code = GET_CODE (operands[1]);
 
     if (code == UNEQ || code == LTGT)
       FAIL;
 
-    ccreg = aarch64_gen_compare_reg (code, XEXP (operands[1], 0),
-				  XEXP (operands[1], 1));
-    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
+    if (!ccmp_cc_register (XEXP (operands[1], 0),
+			   GET_MODE (XEXP (operands[1], 0))))
+      {
+	rtx ccreg;
+	ccreg = aarch64_gen_compare_reg (code, XEXP (operands[1], 0),
+					 XEXP (operands[1], 1));
+	operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
+      }
   }
 )
 
diff --git a/gcc/expr.c b/gcc/expr.c
index a5a8130..f449e0b 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -8011,7 +8011,9 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED,
       op00 = expand_normal (treeop0);
       op01 = const0_rtx;
       comparison_code = NE;
-      comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
+      comparison_mode = GET_MODE (op00);
+      if (comparison_mode == VOIDmode)
+	comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
     }
 
   if (GET_MODE (op1) != mode)
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 6bcc23a..ffeecf1 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -43,6 +43,7 @@
 #include "vec.h"
 #include "dbgcnt.h"
 #include "shrink-wrap.h"
+#include "ccmp.h"
 
 #ifndef HAVE_conditional_move
 #define HAVE_conditional_move 0
@@ -809,6 +810,9 @@ struct noce_if_info
 
   /* Estimated cost of the particular branch instruction.  */
   int branch_cost;
+
+  /* The COND is a conditional compare or not.  */
+  bool ccmp_p;
 };
 
 static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
@@ -1436,9 +1440,16 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
       end_sequence ();
     }
 
-  /* Don't even try if the comparison operands are weird.  */
-  if (! general_operand (cmp_a, GET_MODE (cmp_a))
-      || ! general_operand (cmp_b, GET_MODE (cmp_b)))
+  /* Don't even try if the comparison operands are weird
+     except conditional compare.  */
+  if (if_info->ccmp_p)
+    {
+      if (!(GET_MODE_CLASS (GET_MODE (cmp_a)) == MODE_CC
+	    || GET_MODE_CLASS (GET_MODE (cmp_b)) == MODE_CC))
+	return NULL_RTX;
+    }
+  else if (! general_operand (cmp_a, GET_MODE (cmp_a))
+	   || ! general_operand (cmp_b, GET_MODE (cmp_b)))
     return NULL_RTX;
 
 #if HAVE_conditional_move
@@ -1886,7 +1897,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
     }
 
   cond = canonicalize_condition (if_info->jump, cond, reverse,
-				 earliest, target, false, true);
+				 earliest, target, if_info->ccmp_p, true);
   if (! cond || ! reg_mentioned_p (target, cond))
     return NULL;
 
@@ -2342,6 +2353,7 @@ noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed
 {
   rtx cond, set, tmp;
   bool reverse;
+  int allow_cc_mode = false;
 
   if (! any_condjump_p (jump))
     return NULL_RTX;
@@ -2375,10 +2387,21 @@ noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed
       return cond;
     }
 
+  /* For conditional compare, set ALLOW_CC_MODE to TRUE.  */
+  if (targetm.gen_ccmp_first)
+    {
+      rtx prev = prev_nonnote_nondebug_insn (jump);
+      if (prev
+	  && NONJUMP_INSN_P (prev)
+	  && BLOCK_FOR_INSN (prev) == BLOCK_FOR_INSN (jump)
+	  && ccmp_insn_p (prev))
+	allow_cc_mode = true;
+    }
+
   /* 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, false, true);
+				NULL_RTX, allow_cc_mode, true);
 
   /* We don't handle side-effects in the condition, like handling
      REG_INC notes and making sure no duplicate conditions are emitted.  */
@@ -2622,6 +2645,11 @@ noce_process_if_block (struct noce_if_info *if_info)
   if_info->a = a;
   if_info->b = b;
 
+  if (targetm.gen_ccmp_first)
+    if (GET_MODE_CLASS (GET_MODE (XEXP (if_info->cond, 0))) == MODE_CC
+	|| GET_MODE_CLASS (GET_MODE (XEXP (if_info->cond, 1))) == MODE_CC)
+      if_info->ccmp_p = true;
+
   /* 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.  */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
new file mode 100644
index 0000000..472c271
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+  return a < b && c > -5 ? d : 7;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
new file mode 100644
index 0000000..c7d41d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+  return a < b && c > -9 ? d : c;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
new file mode 100644
index 0000000..9350e5d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+  return a > b && c <= -2 ? 9 : 7;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
new file mode 100644
index 0000000..2d0929f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+  return a < b && c <= d ? d : 7;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
new file mode 100644
index 0000000..978aa64
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+  return a < b && c > d ? d : c;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
new file mode 100644
index 0000000..7db1cd5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+  return a > b && c <= d ? 9 : 7;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
