diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 06d494c..a57e11c 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2046,9 +2046,10 @@ expand_gimple_cond (basic_block bb, gimple stmt)
 	      op0 = gimple_assign_rhs1 (second);
 	      op1 = gimple_assign_rhs2 (second);
 	    }
-	  /* If jumps are cheap turn some more codes into
-	     jumpy sequences.  */
-	  else if (BRANCH_COST (optimize_insn_for_speed_p (), false) < 4)
+	  /* If jumps are cheap and the target does not support conditional
+	     compare, turn some more codes into jumpy sequences.  */
+	  else if (BRANCH_COST (optimize_insn_for_speed_p (), false) < 4
+		   && (targetm.gen_ccmp_first == NULL))
 	    {
 	      if ((code2 == BIT_AND_EXPR
 		   && TYPE_PRECISION (TREE_TYPE (op0)) == 1
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 746acc2..dfcdc61 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -6206,6 +6206,42 @@ A typical @code{ctrap} pattern looks like
   "@dots{}")
 @end smallexample
 
+@cindex @code{ccmp} instruction pattern
+@item @samp{ccmp}
+Conditional compare instruction.  Operand 2 and 5 are RTLs which perform
+two comparisons.  Operand 1 is AND or IOR, which operates on the result of
+Operand 2 and 5.  Operand 0 is the result of operand 1.
+It uses recursive method to support more than two compares.  e.g.
+
+  CC0 = CMP (a, b);
+  CC1 = CCMP (NE (CC0, 0), CMP (e, f));
+  ...
+  CCn = CCMP (NE (CCn-1, 0), CMP (...));
+
+Two target hooks are used to generate conditional compares.  GEN_CCMP_FISRT
+is used to generate the first CMP.  And GEN_CCMP_NEXT is used to generate the
+following CCMPs.  Operand 1 is AND or IOR.  Operand 3 is the result of
+GEN_CCMP_FISRT or a previous GEN_CCMP_NEXT.  Operand 2 is NE.
+Operand 4, 5 and 6 is another compare expression.
+
+A typical CCMP pattern looks like
+
+@smallexample
+(define_insn "*ccmp_and_ior"
+  [(set (match_operand 6 "dominant_cc_register" "")
+        (compare
+         (match_operator 1
+          (match_operator 2 "comparison_operator"
+           [(match_operand 3 "dominant_cc_register")
+            (const_int 0)])
+          (match_operator 4 "comparison_operator"
+           [(match_operand 5 "register_operand")
+            (match_operand 6 "compare_operand"]))
+         (const_int 0)))]
+  ""
+  "@dots{}")
+@end smallexample
+
 @cindex @code{prefetch} instruction pattern
 @item @samp{prefetch}
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index f204936..0aedc31 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11180,6 +11180,32 @@ This target hook is required only when the target has several different
 modes and they have different conditional execution capability, such as ARM.
 @end deftypefn
 
+@deftypefn {Target Hook} int TARGET_SELECT_CCMP_CMP_ORDER (int @var{code1}, int @var{code2})
+For some target (like ARM), the order of two compares is sensitive for
+conditional compare.  cmp0-cmp1 might be an invalid combination.  But when
+swapping the order, cmp1-cmp0 is valid.  The function will return
+   1: Keep current order.
+  -1: Swap the two compares.
+   0: Invalid combination.
+@end deftypefn
+
+@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (int @var{code}, rtx @var{op0}, rtx @var{op1})
+This function emits a comparison insn for the first of a sequence of
+ conditional comparisions.  It returns a comparison expression appropriate
+ for passing to @code{gen_ccmp_next} or to @code{cbranch_optab}.
+ @code{unsignedp} is used when converting @code{op0} and @code{op1}'s mode.
+@end deftypefn
+
+@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_NEXT (rtx @var{prev}, int @var{cmp_code}, rtx @var{op0}, rtx @var{op1}, int @var{bit_code})
+This function emits a conditional comparison within a sequence of
+ conditional comparisons.  The @code{prev} expression is the result of a
+ prior call to @code{gen_ccmp_first} or @code{gen_ccmp_next}.  It may return
+ @code{NULL} if the combination of @code{prev} and this comparison is
+ not supported, otherwise the result must be appropriate for passing to
+ @code{gen_ccmp_next} or @code{cbranch_optab}.  @code{bit_code}
+ is AND or IOR, which is the op on the two compares.
+@end deftypefn
+
 @deftypefn {Target Hook} unsigned TARGET_LOOP_UNROLL_ADJUST (unsigned @var{nunroll}, struct loop *@var{loop})
 This target hook returns a new value for the number of times @var{loop}
 should be unrolled. The parameter @var{nunroll} is the number of times
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 50f412c..ecbb8b6 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8283,6 +8283,12 @@ build_type_attribute_variant (@var{mdecl},
 
 @hook TARGET_HAVE_CONDITIONAL_EXECUTION
 
+@hook TARGET_SELECT_CCMP_CMP_ORDER
+
+@hook TARGET_GEN_CCMP_FIRST
+
+@hook TARGET_GEN_CCMP_NEXT
+
 @hook TARGET_LOOP_UNROLL_ADJUST
 
 @defmac POWI_MAX_MULTS
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 7c1c979..4ff90ce 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -5160,7 +5160,7 @@ expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target)
 }
 
 /* Helper function for emit_store_flag.  */
-static rtx
+rtx
 emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
 	     enum machine_mode mode, enum machine_mode compare_mode,
 	     int unsignedp, rtx x, rtx y, int normalizep,
diff --git a/gcc/expr.c b/gcc/expr.c
index f6708da..d2c6f6b 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -67,6 +67,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "tree-ssa-address.h"
 #include "cfgexpand.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -9228,6 +9230,299 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 }
 #undef REDUCE_BIT_FIELD
 
+/* The following functions expand conditional compare (CCMP) instructions.
+   Here is a short description about the over all algorithm:
+     * ccmp_candidate_p is used to identify the CCMP candidate
+
+     * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1
+       to expand CCMP.
+
+     * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP.
+       It calls two target hooks gen_ccmp_first and gen_ccmp_next to generate
+       CCMP instructions.
+	 - gen_ccmp_first expands the first compare in CCMP.
+	 - gen_ccmp_next expands the following compares.
+
+       Another hook select_ccmp_cmp_order is called to determine which compare
+       is done first since not all combination of compares are legal in some
+       target like ARM.  We might get more chance when swapping the compares.
+
+       During expanding, we must make sure that no instruction can clobber the
+       CC reg except the compares.  So clobber_cc_p and check_clobber_cc are
+       introduced to do the check.
+
+     * If the final result is not used in a COND_EXPR (checked by function
+       used_in_cond_stmt_p), it calls cstorecc4 pattern to store the CC to a
+       general register.  */
+
+/* Check whether G is a potential conditional compare candidate.  */
+static bool
+ccmp_candidate_p (gimple g)
+{
+  tree rhs = gimple_assign_rhs_to_tree (g);
+  tree lhs, op0, op1;
+  gimple gs0, gs1;
+  enum tree_code tcode, tcode0, tcode1;
+  tcode = TREE_CODE (rhs);
+
+  if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR)
+    return false;
+
+  lhs = gimple_assign_lhs (g);
+  op0 = TREE_OPERAND (rhs, 0);
+  op1 = TREE_OPERAND (rhs, 1);
+
+  if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME)
+      || !has_single_use (lhs))
+    return false;
+
+  gs0 = get_gimple_for_ssa_name (op0);
+  gs1 = get_gimple_for_ssa_name (op1);
+  if (!gs0 || !gs1 || !is_gimple_assign (gs0) || !is_gimple_assign (gs1)
+      /* g, gs0 and gs1 must be in the same basic block, since current stage
+	 is out-of-ssa.  We can not guarantee the correctness when forwording
+	 the gs0 and gs1 into g whithout DATAFLOW analysis.  */
+      || gimple_bb (gs0) != gimple_bb (gs1)
+      || gimple_bb (gs0) != gimple_bb (g))
+    return false;
+
+  if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))
+       || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))))
+      || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1)))
+	   || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1)))))
+    return false;
+
+  tcode0 = gimple_assign_rhs_code (gs0);
+  tcode1 = gimple_assign_rhs_code (gs1);
+  if (TREE_CODE_CLASS (tcode0) == tcc_comparison
+      && TREE_CODE_CLASS (tcode1) == tcc_comparison)
+    return true;
+  if (TREE_CODE_CLASS (tcode0) == tcc_comparison
+      && ccmp_candidate_p (gs1))
+    return true;
+  else if (TREE_CODE_CLASS (tcode1) == tcc_comparison
+	   && ccmp_candidate_p (gs0))
+    return true;
+  /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since
+     there is no way to set the CC flag.  */
+  return false;
+}
+
+/* Check whether EXP is used in a GIMPLE_COND statement or not.  */
+static bool
+used_in_cond_stmt_p (tree exp)
+{
+  bool expand_cond = false;
+  imm_use_iterator ui;
+  gimple use_stmt;
+  FOR_EACH_IMM_USE_STMT (use_stmt, ui, exp)
+    if (gimple_code (use_stmt) == GIMPLE_COND)
+      {
+	tree op1 = gimple_cond_rhs (use_stmt);
+	/* TBD: If we can convert all
+	    _Bool t;
+
+	    if (t == 1)
+	      goto <bb 3>;
+	    else
+	      goto <bb 4>;
+	   to
+	    if (t != 0)
+	      goto <bb 3>;
+	    else
+	      goto <bb 4>;
+	   we can remove the following check.  */
+	if (integer_zerop (op1))
+	  expand_cond = true;
+	BREAK_FROM_IMM_USE_STMT (ui);
+      }
+  return expand_cond;
+}
+
+/* If SETTER clobber CC reg, set DATA to TRUE.  */
+
+static void
+check_clobber_cc (rtx reg, const_rtx setter, void *data)
+{
+  if (GET_CODE (setter) == CLOBBER && GET_MODE (reg) == CCmode)
+    *(bool *)data = true;
+}
+
+/* Check whether INSN and all its NEXT_INSN clobber CC reg or not.  */
+
+static bool
+clobber_cc_p (rtx insn)
+{
+  bool clobber = false;
+  for (; insn; insn = NEXT_INSN (insn))
+    {
+      note_stores (PATTERN (insn), check_clobber_cc, &clobber);
+      if (clobber)
+	return true;
+    }
+  return false;
+}
+
+/* Help function to generate conditional compare.  PREV is the result of
+   GEN_CCMP_FIRST or GEN_CCMP_NEXT.  G is the next compare.
+   CODE is BIT_AND_EXPR or BIT_IOR_EXPR.  */
+
+static rtx
+gen_ccmp_next (rtx prev, gimple g, enum tree_code code)
+{
+  rtx op0, op1;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)));
+  enum rtx_code rcode = get_rtx_code (gimple_assign_rhs_code (g), unsignedp);
+  rtx last = get_last_insn ();
+
+  expand_operands (gimple_assign_rhs1 (g),
+		   gimple_assign_rhs2 (g),
+		   NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+
+  /* If any operand clobbers CC reg, we will give up.  */
+  if (clobber_cc_p (NEXT_INSN (last)))
+    return NULL_RTX;
+
+  return targetm.gen_ccmp_next (prev, rcode, op0, op1, get_rtx_code (code, 0));
+}
+
+/* Expand conditional compare gimple G.  A typical CCMP sequence is like:
+
+     CC0 = CMP (a, b);
+     CC1 = CCMP (NE (CC0, 0), CMP (e, f));
+     ...
+     CCn = CCMP (NE (CCn-1, 0), CMP (...));
+
+   hook gen_ccmp_first is used to expand the first compare.
+   hook gen_ccmp_next is used to expand the following CCMP.  */
+
+static rtx
+expand_ccmp_expr_1 (gimple g)
+{
+  tree exp = gimple_assign_rhs_to_tree (g);
+  enum tree_code code = TREE_CODE (exp);
+  gimple gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0));
+  gimple gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1));
+  rtx tmp;
+  enum tree_code code0 = gimple_assign_rhs_code (gs0);
+  enum tree_code code1 = gimple_assign_rhs_code (gs1);
+
+  gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR);
+  gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign (gs1));
+
+  if (TREE_CODE_CLASS (code0) == tcc_comparison)
+    {
+      if (TREE_CODE_CLASS (code1) == tcc_comparison)
+	{
+	  int unsignedp0, unsignedp1, cmp_order;
+	  enum rtx_code rcode0, rcode1, rcode;
+	  rtx op0, op1, op2, op3, tmp;
+	  gimple first, next;
+
+	  unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0)));
+	  rcode0 = get_rtx_code (code0, unsignedp0);
+	  unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1)));
+	  rcode1 = get_rtx_code (code1, unsignedp1);
+
+	  /* For some target (like ARM), the order of two compares is sensitive
+	     for conditional compare.  cmp0-cmp1 might be an invalid combination.
+	     But when swapping the order, cmp1-cmp0 is valid.  The target hook
+	     select_ccmp_cmp_order will return
+		 1: Keep current order.
+		-1: Swap the two compares.
+		 0: Invalid combination.  */
+
+	  cmp_order = targetm.select_ccmp_cmp_order (rcode0, rcode1);
+	  /* Invalid combination.  */
+	  if (!cmp_order)
+	    return NULL_RTX;
+	  /* Swap the compare order.  Do gs1 first.  */
+	  if (cmp_order == -1)
+	    {
+	      first = gs1;
+	      next = gs0;
+	      rcode = rcode1;
+	    }
+	  else
+	    {
+	      first = gs0;
+	      next = gs1;
+	      rcode = rcode0;
+	    }
+	    expand_operands (gimple_assign_rhs1 (first),
+			     gimple_assign_rhs2 (first),
+			     NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+
+	    /* Since the operands of NEXT might clobber CC reg, we expand the
+	       operands of NEXT before GEN_CCMP_FIRST.  */
+	    expand_operands (gimple_assign_rhs1 (next),
+			     gimple_assign_rhs2 (next),
+			     NULL_RTX, &op2, &op3, EXPAND_NORMAL);
+	    tmp = targetm.gen_ccmp_first (rcode, op0, op1);
+	    if (!tmp)
+	      return NULL_RTX;
+
+	    return targetm.gen_ccmp_next (tmp,
+					  rcode == rcode1 ? rcode0 : rcode1,
+					  op2, op3, get_rtx_code (code, 0));
+	}
+      gcc_assert (code1 == BIT_AND_EXPR || code1 == BIT_IOR_EXPR);
+      tmp = expand_ccmp_expr_1 (gs1);
+      if (tmp)
+	return gen_ccmp_next (tmp, gs0, code);
+    }
+  else
+    {
+      gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR
+                  || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR);
+      if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison)
+	{
+	  tmp = expand_ccmp_expr_1 (gs0);
+	  if (tmp)
+	    return gen_ccmp_next (tmp, gs1, code);
+	}
+      else
+	{
+	  gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR
+		      || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR);
+	}
+    }
+
+  return NULL_RTX;
+}
+
+static rtx
+expand_ccmp_expr (gimple g)
+{
+  rtx last = get_last_insn ();
+  tree lhs = gimple_assign_lhs (g);
+  rtx tmp = expand_ccmp_expr_1 (g);
+
+  if (tmp)
+    {
+      enum insn_code icode;
+      /* TMP should be CC.  If it is used in a GIMPLE_COND, just return it.
+	 Note: Target needs to define "cbranchcc4".  */
+      if (used_in_cond_stmt_p (lhs))
+	return tmp;
+
+      /* If TMP is not used in a GIMPLE_COND, store it with a csctorecc4_optab.
+	 Note: Target needs to define "cstorecc4".  */
+      icode = optab_handler (cstore_optab, CCmode);
+      if (icode != CODE_FOR_nothing)
+	{
+	  rtx target = gen_reg_rtx (word_mode);
+	  tmp = emit_cstore (target, icode, NE, CCmode, CCmode,
+			     0, tmp, const0_rtx, 1, word_mode);
+	  if (tmp)
+	    return tmp;
+	}
+    }
+
+  /* Clean up.  */
+  delete_insns_since (last);
+  return NULL_RTX;
+}
 
 /* Return TRUE if expression STMT is suitable for replacement.  
    Never consider memory loads as replaceable, because those don't ever lead 
@@ -9392,10 +9687,22 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	{
 	  rtx r;
 	  location_t saved_loc = curr_insn_location ();
+	  tree rhs = gimple_assign_rhs_to_tree (g);
 
 	  set_curr_insn_location (gimple_location (g));
-	  r = expand_expr_real (gimple_assign_rhs_to_tree (g), target,
-				tmode, modifier, NULL, inner_reference_p);
+
+	  if ((targetm.gen_ccmp_first != NULL) && ccmp_candidate_p (g))
+	    {
+	      gcc_checking_assert (targetm.gen_ccmp_next != NULL);
+	      r = expand_ccmp_expr (g);
+	      if (!r)
+		r = expand_expr_real (rhs, target, tmode, modifier,
+				      NULL, inner_reference_p);
+	    }
+	  else
+	    r = expand_expr_real (rhs, target, tmode, modifier,
+				  NULL, inner_reference_p);
+
 	  set_curr_insn_location (saved_loc);
 	  if (REG_P (r) && !REG_EXPR (r))
 	    set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index cec25a4..7fdbf47 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6398,7 +6398,7 @@ gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, rtx tcode)
 /* Return rtx code for TCODE. Use UNSIGNEDP to select signed
    or unsigned operation code.  */
 
-static enum rtx_code
+enum rtx_code
 get_rtx_code (enum tree_code tcode, bool unsignedp)
 {
   enum rtx_code code;
@@ -6448,6 +6448,12 @@ get_rtx_code (enum tree_code tcode, bool unsignedp)
       code = LTGT;
       break;
 
+    case BIT_AND_EXPR:
+      code = AND;
+      break;
+    case BIT_IOR_EXPR:
+      code = IOR;
+      break;
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 8ecaa41..4426270 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -91,7 +91,7 @@ extern rtx expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op,
 extern rtx expand_ternary_op (enum machine_mode mode, optab ternary_optab,
 			      rtx op0, rtx op1, rtx op2, rtx target,
 			      int unsignedp);
-
+extern enum rtx_code get_rtx_code (enum tree_code tcode, bool unsignedp);
 /* Expand a binary operation given optab and rtx operands.  */
 extern rtx expand_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
 			 enum optab_methods);
@@ -556,4 +556,9 @@ extern void gen_satfractuns_conv_libfunc (convert_optab, const char *,
 					  enum machine_mode);
 extern void init_tree_optimization_optabs (tree);
 
+extern rtx emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
+			enum machine_mode mode, enum machine_mode compare_mode,
+			int unsignedp, rtx x, rtx y, int normalizep,
+			enum machine_mode target_mode);
+
 #endif /* GCC_OPTABS_H */
diff --git a/gcc/recog.c b/gcc/recog.c
index f9040dc..32a2648 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -556,6 +556,19 @@ cancel_changes (int num)
 #define CODE_FOR_extzv	CODE_FOR_nothing
 #endif
 
+static bool
+ccmp_insn_p (rtx object)
+{
+  rtx x = PATTERN (object);
+  if (targetm.gen_ccmp_first
+      && GET_CODE (x) == SET
+      && GET_CODE (XEXP (x, 1)) == COMPARE
+      && (GET_CODE (XEXP (XEXP (x, 1), 0)) == IOR
+	  || GET_CODE (XEXP (XEXP (x, 1), 0)) == AND))
+    return true;
+  return false;
+}
+
 /* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting
    rtx.  */
 
@@ -567,7 +580,8 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
   enum rtx_code code = GET_CODE (x);
   rtx new_rtx = NULL_RTX;
 
-  if (SWAPPABLE_OPERANDS_P (x)
+  /* Do not swap compares in conditional compare instruction.  */
+  if (SWAPPABLE_OPERANDS_P (x) && !ccmp_insn_p (object)
       && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
     {
       validate_unshare_change (object, loc,
diff --git a/gcc/target.def b/gcc/target.def
index 3a64cd1..e34d4a1 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2334,6 +2334,38 @@ modes and they have different conditional execution capability, such as ARM.",
  bool, (void),
  default_have_conditional_execution)
 
+DEFHOOK
+(select_ccmp_cmp_order,
+ "For some target (like ARM), the order of two compares is sensitive for\n\
+conditional compare.  cmp0-cmp1 might be an invalid combination.  But when\n\
+swapping the order, cmp1-cmp0 is valid.  The function will return\n\
+   1: Keep current order.\n\
+  -1: Swap the two compares.\n\
+   0: Invalid combination.",
+ int, (int code1, int code2),
+ default_select_ccmp_cmp_order)
+
+DEFHOOK
+(gen_ccmp_first,
+ "This function emits a comparison insn for the first of a sequence of\n\
+ conditional comparisions.  It returns a comparison expression appropriate\n\
+ for passing to @code{gen_ccmp_next} or to @code{cbranch_optab}.\n\
+ @code{unsignedp} is used when converting @code{op0} and @code{op1}'s mode.",
+ rtx, (int code, rtx op0, rtx op1),
+ NULL)
+
+DEFHOOK
+(gen_ccmp_next,
+ "This function emits a conditional comparison within a sequence of\n\
+ conditional comparisons.  The @code{prev} expression is the result of a\n\
+ prior call to @code{gen_ccmp_first} or @code{gen_ccmp_next}.  It may return\n\
+ @code{NULL} if the combination of @code{prev} and this comparison is\n\
+ not supported, otherwise the result must be appropriate for passing to\n\
+ @code{gen_ccmp_next} or @code{cbranch_optab}.  @code{bit_code}\n\
+ is AND or IOR, which is the op on the two compares.",
+ rtx, (rtx prev, int cmp_code, rtx op0, rtx op1, int bit_code),
+ NULL)
+
 /* Return a new value for loop unroll size.  */
 DEFHOOK
 (loop_unroll_adjust,
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index f3b5d56..014fd85 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -76,6 +76,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssanames.h"
 #include "insn-codes.h"
 
+/* Default return 1 to keep current order.  */
+int
+default_select_ccmp_cmp_order (int, int)
+{
+  return 1;
+}
 
 bool
 default_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 9dd4c83..00456dc 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -208,3 +208,4 @@ extern tree build_va_arg_indirect_ref (tree);
 extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 extern bool can_use_doloop_if_innermost (double_int, double_int,
 					 unsigned int, bool);
+extern int default_select_ccmp_cmp_order (int, int);
