diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 45e9ada..5b52a47 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -12669,3 +12669,51 @@
 (include "sync.md")
 ;; Fixed-point patterns
 (include "arm-fixed.md")
+
+;; Expand conditional compare according to the instruction patterns.
+(define_expand "conditional_compare"
+  [(set (match_operand 0 "s_register_operand" "")
+	(match_operator 1 ""
+	 [(match_operator:SI 2 "arm_comparison_operator"
+	  [(match_operand:SI 3 "s_register_operand" "")
+	   (match_operand:SI 4 "arm_add_operand" "")])
+	 (match_operator:SI 5 "arm_comparison_operator"
+	  [(match_operand:SI 6 "s_register_operand" "")
+	   (match_operand:SI 7 "arm_add_operand" "")])]))]
+  "TARGET_ARM || TARGET_THUMB2"
+  "{
+     enum machine_mode mode;
+     HOST_WIDE_INT cond_or;
+     rtx par;
+     enum rtx_code code = GET_CODE (operands[1]);
+     cond_or = code == AND? DOM_CC_X_AND_Y : DOM_CC_X_OR_Y;
+
+     mode = arm_select_dominance_cc_mode (operands[2],
+					  operands[5],
+					  cond_or);
+     /* To match and/ior_scc_scc, mode should not be CCmode.  */
+     if (mode == CCmode)
+       FAIL;
+
+     operands[2] = gen_rtx_fmt_ee (GET_CODE (operands[2]),
+				   GET_MODE (operands[3]),
+				   operands[3], operands[4]);
+     operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[5]),
+				   GET_MODE (operands[5]),
+				   operands[6], operands[7]);
+     operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode,
+				   operands[2], operands[5]);
+
+      /* Generate insn to match and/ior_scc_scc.  */
+      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
+      XVECEXP (par, 0, 0) = gen_rtx_SET (GET_MODE (operands[0]),
+			    operands[0], operands[1]);
+      XVECEXP (par, 0, 1) = gen_rtx_CLOBBER (CCmode,
+					     gen_rtx_REG (CCmode, CC_REGNUM));
+
+      emit_insn (par);
+
+     DONE;
+  }"
+)
+
diff --git a/gcc/expr.c b/gcc/expr.c
index bbe0401..e42b8ff 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9158,6 +9158,107 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 }
 #undef REDUCE_BIT_FIELD
 
+#ifdef HAVE_conditional_compare
+/* Check whether G is a potential conditional compare candidate.  */
+static bool
+is_conditional_compare_candidate_p (gimple g)
+{
+  tree rhs = gimple_assign_rhs_to_tree (g);
+  tree lhs, op0, op1;
+  gimple gs0, gs1;
+
+  if (TREE_CODE (rhs) != BIT_AND_EXPR && TREE_CODE (rhs) != 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 = SSA_NAME_DEF_STMT (op0);
+  gs1 = SSA_NAME_DEF_STMT (op1);
+  if (!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 (TREE_CODE_CLASS (gimple_assign_rhs_code (gs0)) != tcc_comparison
+      || TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) != tcc_comparison)
+    return false;
+
+  return true;
+}
+
+/* Expand conditional compare EXP with CCMP OP.  */
+static rtx
+expand_ccmp_expr (tree exp, rtx target)
+{
+  rtx target_old = target;
+  enum tree_code code = TREE_CODE (exp);
+
+  gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR);
+
+  gimple gs0 = SSA_NAME_DEF_STMT (TREE_OPERAND (exp, 0));
+  gimple gs1 = SSA_NAME_DEF_STMT (TREE_OPERAND (exp, 1));
+
+  if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))
+      && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))))
+    {
+      rtx op0, op1, op2, op3, tmp;
+      tree cmp0_op0, cmp0_op1, cmp1_op0, cmp1_op1;
+      enum machine_mode mode;
+
+      cmp0_op0 = gimple_assign_rhs1 (gs0);
+      cmp0_op1 = gimple_assign_rhs2 (gs0);
+      cmp1_op0 = gimple_assign_rhs1 (gs1);
+      cmp1_op1 = gimple_assign_rhs2 (gs1);
+
+      expand_operands (cmp0_op0, cmp0_op1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+      expand_operands (cmp1_op0, cmp1_op1, NULL_RTX, &op2, &op3, EXPAND_NORMAL);
+
+      /* Convert the operators to WORD_MODE.  */
+      mode = TYPE_MODE (TREE_TYPE (cmp0_op0));
+      if (mode == VOIDmode)
+	mode = TYPE_MODE (TREE_TYPE (cmp0_op1));
+      if (mode == QImode || mode == HImode)
+	{
+	  op0 = convert_modes (word_mode, mode, op0,
+			       TYPE_UNSIGNED (TREE_TYPE (cmp0_op0)));
+	  op1 = convert_modes (word_mode, mode, op1,
+			       TYPE_UNSIGNED (TREE_TYPE (cmp0_op1)));
+	}
+      mode = TYPE_MODE (TREE_TYPE (cmp1_op0));
+      if (mode == VOIDmode)
+	mode = TYPE_MODE (TREE_TYPE (cmp1_op1));
+      if (mode == QImode || mode == HImode)
+	{
+	  op2 = convert_modes (word_mode, mode, op2,
+			       TYPE_UNSIGNED (TREE_TYPE (cmp1_op0)));
+	  op3 = convert_modes (word_mode, mode, op3,
+			       TYPE_UNSIGNED (TREE_TYPE (cmp1_op1)));
+	}
+
+      target = gen_reg_rtx (word_mode);
+
+      tmp = expand_ccmp_op (op0, op1, op2, op3, target, code, gs0, gs1);
+
+      if (tmp)
+	return tmp;
+
+      /* Restore target.  */
+      target = target_old;
+    }
+
+  return NULL_RTX;
+}
+#endif
+
 rtx
 expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 		    enum expand_modifier modifier, rtx *alt_rtl)
@@ -9303,10 +9404,23 @@ 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);
+
+#ifdef HAVE_conditional_compare
+	  if (optimize_function_for_speed_p (cfun)
+	      && is_conditional_compare_candidate_p (g))
+	    {
+	      r = expand_ccmp_expr (rhs, target);
+	      if (!r)
+		r = expand_expr_real (rhs, target, tmode, modifier, NULL);
+	    }
+	  else
+	    r = expand_expr_real (rhs, target, tmode, modifier, NULL);
+#else
+	  r = expand_expr_real (rhs, target, tmode, modifier, NULL);
+#endif
 	  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/fold-const.c b/gcc/fold-const.c
index 6506ae7..b2ba25a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -4949,12 +4949,16 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
 }
 
 
-
+#ifdef HAVE_conditional_compare
+#undef LOGICAL_OP_NON_SHORT_CIRCUIT
+#define LOGICAL_OP_NON_SHORT_CIRCUIT optimize_function_for_speed_p (cfun)
+#else
 #ifndef LOGICAL_OP_NON_SHORT_CIRCUIT
 #define LOGICAL_OP_NON_SHORT_CIRCUIT \
   (BRANCH_COST (optimize_function_for_speed_p (cfun), \
 		false) >= 2)
 #endif
+#endif
 
 /* EXP is some logical combination of boolean tests.  See if we can
    merge it into some range test.  Return the new tree if so.  */
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a3051ad..e3a8989 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "basic-block.h"
 #include "target.h"
+#include "gimple.h"
 
 struct target_optabs default_target_optabs;
 struct target_libfuncs default_target_libfuncs;
@@ -57,6 +58,7 @@ static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *,
 				   enum machine_mode *);
 static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
 static void emit_libcall_block_1 (rtx, rtx, rtx, rtx, bool);
+static enum rtx_code get_rtx_code (enum tree_code tcode, bool unsignedp);
 
 /* Debug facility for use in GDB.  */
 void debug_optab_libfuncs (void);
@@ -685,6 +687,63 @@ expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
   return ops[0].value;
 }
 
+#ifdef HAVE_conditional_compare
+/* Generate code to perform an operation specified by CCMP_OPTAB
+   on operands OP0, OP1, OP2 and OP3, with result TARGET.
+
+   CODE is BIT_AND_EXPR/BIT_IOR_EXPR, which represent &&/||.
+
+   GS0 and GS1 are the two compares.
+
+   If the backend has insn to match it, it will return the TARGET.
+   Otherwise return NULL_RTX.
+
+   Notes:
+   Backend might need adjust the modes when expanding it if it supports
+   compare which is not WORD_MODE.  E.g. for some 64-bit systems, both
+   32-bit and 64-bit compares are OK.  */
+
+rtx
+expand_ccmp_op (rtx op0, rtx op1, rtx op2, rtx op3, rtx target,
+		enum tree_code code, gimple gs0, gimple gs1)
+{
+  struct expand_operand ops[8];
+  rtx cmp0, cmp1, bit_op;
+  enum insn_code icode = optab_handler (ccmp_optab, VOIDmode);
+  enum rtx_code rcode, rcode0, rcode1;
+  rtx last = get_last_insn ();
+  int unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0)));
+  int unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1)));
+  enum tree_code cmp_code0 = gimple_assign_rhs_code (gs0);
+  enum tree_code cmp_code1 = gimple_assign_rhs_code (gs1);
+
+  gcc_assert (icode != CODE_FOR_nothing);
+
+  rcode = get_rtx_code (code, 0);
+  rcode0 = get_rtx_code (cmp_code0, unsignedp0);
+  cmp0 = gen_rtx_fmt_ee (rcode0, word_mode, op0, op1);
+  rcode1 = get_rtx_code (cmp_code1, unsignedp1);
+  cmp1 = gen_rtx_fmt_ee (rcode1, word_mode, op2, op3);
+  bit_op = gen_rtx_fmt_ee (rcode, word_mode, cmp0, cmp1);
+
+  create_output_operand (&ops[0], target, GET_MODE (target));
+  create_convert_operand_from (&ops[1], bit_op, word_mode, 0);
+  create_convert_operand_from (&ops[2], cmp0, word_mode, unsignedp0);
+  create_convert_operand_from (&ops[3], op0, word_mode, unsignedp0);
+  create_convert_operand_from (&ops[4], op1, word_mode, unsignedp0);
+  create_convert_operand_from (&ops[5], cmp1, word_mode, unsignedp1);
+  create_convert_operand_from (&ops[6], op2, word_mode, unsignedp1);
+  create_convert_operand_from (&ops[7], op3, word_mode, unsignedp1);
+
+  if (!maybe_expand_insn (icode, 8, ops))
+    {
+      delete_insns_since (last);
+      return NULL_RTX;
+    }
+
+  return ops[0].value;
+}
+#endif
 
 /* Like expand_binop, but return a constant rtx if the result can be
    calculated at compile time.  The arguments and return value are
@@ -6436,6 +6495,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.def b/gcc/optabs.def
index 6b924ac..295a6ba 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -187,6 +187,7 @@ OPTAB_D (movcc_optab, "mov$acc")
 OPTAB_D (cmov_optab, "cmov$a6")
 OPTAB_D (cstore_optab, "cstore$a4")
 OPTAB_D (ctrap_optab, "ctrap$a4")
+OPTAB_D (ccmp_optab, "conditional_compare")
 
 OPTAB_D (smul_highpart_optab, "smul$a3_highpart")
 OPTAB_D (umul_highpart_optab, "umul$a3_highpart")
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 4de4409..f009138 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -91,7 +91,11 @@ 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);
-
+#ifdef HAVE_conditional_compare
+/* Expand a conditional compare op.  */
+extern rtx expand_ccmp_op (rtx, rtx, rtx, rtx, rtx,
+			   enum tree_code, gimple, gimple);
+#endif
 /* Expand a binary operation given optab and rtx operands.  */
 extern rtx expand_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
 			 enum optab_methods);
