[AArch64] Enable CCMP support for AArch64, PR64015 resolved
authorZhenqiang Chen <zhenqiang.chen@arm.com>
Fri, 16 Jan 2015 11:48:00 +0000 (11:48 +0000)
committerJiong Wang <jiwang@gcc.gnu.org>
Fri, 16 Jan 2015 11:48:00 +0000 (11:48 +0000)
gcc/
2015-01-16  Zhenqiang Chen  <zhenqiang.chen@arm.com>

PR target/64015
* ccmp.c (expand_ccmp_next): New function.
(expand_ccmp_expr_1, expand_ccmp_expr): Handle operand insn sequence
and compare insn sequence.
* config/aarch64/aarch64.c (aarch64_code_to_ccmode,
aarch64_gen_ccmp_first, aarch64_gen_ccmp_next): New functions.
(TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): New MICRO.
* config/aarch64/aarch64.md (*ccmp_and): Changed to ccmp_and<mode>.
(*ccmp_ior): Changed to ccmp_ior<mode>.
(cmp<mode>): New pattern.
* doc/tm.texi (TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): Update
parameters.
* target.def (gen_ccmp_first, gen_ccmp_next): Update parameters.

gcc/testsuite/
2015-01-16  Zhenqiang Chen <zhenqiang.chen@arm.com>

* gcc.dg/pr64015.c: New test.

From-SVN: r219723

gcc/ChangeLog
gcc/ccmp.c
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.md
gcc/doc/tm.texi
gcc/target.def
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr64015.c [new file with mode: 0644]

index 27713b007520a8e2e57f3b0b8aa127644ce5fae5..198e5e11a8cccdef9dc461f954741cfc6273f8b4 100644 (file)
@@ -1,3 +1,19 @@
+2015-01-16  Zhenqiang Chen  <zhenqiang.chen@arm.com>
+
+       PR target/64015
+       * ccmp.c (expand_ccmp_next): New function.
+       (expand_ccmp_expr_1, expand_ccmp_expr): Handle operand insn sequence
+       and compare insn sequence.
+       * config/aarch64/aarch64.c (aarch64_code_to_ccmode,
+       aarch64_gen_ccmp_first, aarch64_gen_ccmp_next): New functions.
+       (TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): New MICRO.
+       * config/aarch64/aarch64.md (*ccmp_and): Changed to ccmp_and<mode>.
+       (*ccmp_ior): Changed to ccmp_ior<mode>.
+       (cmp<mode>): New pattern.
+       * doc/tm.texi (TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): Update
+       parameters.
+       * target.def (gen_ccmp_first, gen_ccmp_next): Update parameters.
+
 2015-01-16  Ilya Tocar  <ilya.tocar@intel.com>
 
        * config/i386/avx2intrin.h (_mm256_bslli_epi128,
index 1130329ab3093fd3978a2ae466e8252b6cb8f95e..903d5a865de1c19bdf23fd1897dea98574f65cef 100644 (file)
@@ -92,7 +92,16 @@ along with GCC; see the file COPYING3.  If not see
 
      * 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.  */
+       general register.
+
+   Since the operands of the later compares might clobber CC reg, we do not
+   emit the insns during expand.  We keep the insn sequences in two seq
+
+     * prep_seq, which includes all the insns to prepare the operands.
+     * gen_seq, which includes all the compare and conditional compares.
+
+   If all checks OK in expand_ccmp_expr, it emits insns in prep_seq, then
+   insns in gen_seq.  */
 
 /* Check whether G is a potential conditional compare candidate.  */
 static bool
@@ -172,6 +181,27 @@ used_in_cond_stmt_p (tree exp)
   return expand_cond;
 }
 
+/* PREV is the CC flag from precvious compares.  The function expands the
+   next compare based on G which ops previous compare with CODE.
+   PREP_SEQ returns all insns to prepare opearands for compare.
+   GEN_SEQ returnss all compare insns.  */
+static rtx
+expand_ccmp_next (gimple g, enum tree_code code, rtx prev,
+                 rtx *prep_seq, rtx *gen_seq)
+{
+  enum rtx_code rcode;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)));
+
+  gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR);
+
+  rcode = get_rtx_code (gimple_assign_rhs_code (g), unsignedp);
+
+  return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode,
+                               gimple_assign_rhs1 (g),
+                               gimple_assign_rhs2 (g),
+                               get_rtx_code (code, 0));
+}
+
 /* Expand conditional compare gimple G.  A typical CCMP sequence is like:
 
      CC0 = CMP (a, b);
@@ -180,9 +210,11 @@ used_in_cond_stmt_p (tree exp)
      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.  */
+   hook gen_ccmp_next is used to expand the following CCMP.
+   PREP_SEQ returns all insns to prepare opearand.
+   GEN_SEQ returns all compare insns.  */
 static rtx
-expand_ccmp_expr_1 (gimple g)
+expand_ccmp_expr_1 (gimple g, rtx *prep_seq, rtx *gen_seq)
 {
   tree exp = gimple_assign_rhs_to_tree (g);
   enum tree_code code = TREE_CODE (exp);
@@ -199,52 +231,27 @@ expand_ccmp_expr_1 (gimple g)
     {
       if (TREE_CODE_CLASS (code1) == tcc_comparison)
        {
-         int unsignedp0, unsignedp1;
-         enum rtx_code rcode0, rcode1;
-         rtx op0, op1, op2, op3, tmp;
+         int unsignedp0;
+         enum rtx_code rcode0;
 
          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);
-
-         expand_operands (gimple_assign_rhs1 (gs0),
-                          gimple_assign_rhs2 (gs0),
-                          NULL_RTX, &op0, &op1, EXPAND_NORMAL);
-
-         /* Since the operands of GS1 might clobber CC reg, we expand the
-            operands of GS1 before GEN_CCMP_FIRST.  */
-         expand_operands (gimple_assign_rhs1 (gs1),
-                          gimple_assign_rhs2 (gs1),
-                          NULL_RTX, &op2, &op3, EXPAND_NORMAL);
-         tmp = targetm.gen_ccmp_first (rcode0, op0, op1);
+
+         tmp = targetm.gen_ccmp_first (prep_seq, gen_seq, rcode0,
+                                       gimple_assign_rhs1 (gs0),
+                                       gimple_assign_rhs2 (gs0));
          if (!tmp)
            return NULL_RTX;
 
-         return targetm.gen_ccmp_next (tmp, rcode1, op2, op3,
-                                       get_rtx_code (code, 0));
+         return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq);
        }
       else
        {
-         rtx op0, op1;
-         enum rtx_code rcode;
-         int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0)));
-
-         rcode = get_rtx_code (gimple_assign_rhs_code (gs0), unsignedp);
-
-         /* Hoist the preparation operations above the entire
-            conditional compare sequence.  */
-         expand_operands (gimple_assign_rhs1 (gs0),
-                          gimple_assign_rhs2 (gs0),
-                          NULL_RTX, &op0, &op1, EXPAND_NORMAL);
-
-         gcc_assert (code1 == BIT_AND_EXPR || code1 == BIT_IOR_EXPR);
+         tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq);
+         if (!tmp)
+           return NULL_RTX;
 
-         /* Note: We swap the order to make the recursive function work.  */
-         tmp = expand_ccmp_expr_1 (gs1);
-         if (tmp)
-           return targetm.gen_ccmp_next (tmp, rcode, op0, op1,
-                                         get_rtx_code (code, 0));
+         return expand_ccmp_next (gs0, code, tmp, prep_seq, gen_seq);
        }
     }
   else
@@ -254,21 +261,11 @@ expand_ccmp_expr_1 (gimple g)
 
       if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison)
        {
-         rtx op0, op1;
-         enum rtx_code rcode;
-         int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1)));
-
-         rcode = get_rtx_code (gimple_assign_rhs_code (gs1), unsignedp);
-
-         /* Hoist the preparation operations above the entire
-            conditional compare sequence.  */
-         expand_operands (gimple_assign_rhs1 (gs1),
-                          gimple_assign_rhs2 (gs1),
-                          NULL_RTX, &op0, &op1, EXPAND_NORMAL);
-         tmp = expand_ccmp_expr_1 (gs0);
-         if (tmp)
-           return targetm.gen_ccmp_next (tmp, rcode, op0, op1,
-                                         get_rtx_code (code, 0));
+         tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq);
+         if (!tmp)
+           return NULL_RTX;
+
+         return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq);
        }
       else
        {
@@ -288,23 +285,30 @@ expand_ccmp_expr (gimple g)
 {
   rtx_insn *last;
   rtx tmp;
+  rtx prep_seq, gen_seq;
+
+  prep_seq = gen_seq = NULL_RTX;
 
   if (!ccmp_candidate_p (g))
     return NULL_RTX;
 
   last = get_last_insn ();
-  tmp = expand_ccmp_expr_1 (g);
+  tmp = expand_ccmp_expr_1 (g, &prep_seq, &gen_seq);
 
   if (tmp)
     {
       enum insn_code icode;
       enum machine_mode cc_mode = CCmode;
-
       tree lhs = gimple_assign_lhs (g);
+
       /* 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;
+       {
+         emit_insn (prep_seq);
+         emit_insn (gen_seq);
+         return tmp;
+       }
 
 #ifdef SELECT_CC_MODE
       cc_mode = SELECT_CC_MODE (NE, tmp, const0_rtx);
@@ -314,9 +318,12 @@ expand_ccmp_expr (gimple g)
       icode = optab_handler (cstore_optab, cc_mode);
       if (icode != CODE_FOR_nothing)
        {
-         tree lhs = gimple_assign_lhs (g);
          enum machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
          rtx target = gen_reg_rtx (mode);
+
+         emit_insn (prep_seq);
+         emit_insn (gen_seq);
+
          tmp = emit_cstore (target, icode, NE, cc_mode, cc_mode,
                             0, tmp, const0_rtx, 1, mode);
          if (tmp)
index 34cce91b24b3a264e97b3d26def2df19880bdc30..f3cf6ed06432d2dad8da5e3387428a1f72004d05 100644 (file)
@@ -10381,6 +10381,198 @@ aarch64_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
   return default_use_by_pieces_infrastructure_p (size, align, op, speed_p);
 }
 
+static enum machine_mode
+aarch64_code_to_ccmode (enum rtx_code code)
+{
+  switch (code)
+    {
+    case NE:
+      return CC_DNEmode;
+
+    case EQ:
+      return CC_DEQmode;
+
+    case LE:
+      return CC_DLEmode;
+
+    case LT:
+      return CC_DLTmode;
+
+    case GE:
+      return CC_DGEmode;
+
+    case GT:
+      return CC_DGTmode;
+
+    case LEU:
+      return CC_DLEUmode;
+
+    case LTU:
+      return CC_DLTUmode;
+
+    case GEU:
+      return CC_DGEUmode;
+
+    case GTU:
+      return CC_DGTUmode;
+
+    default:
+      return CCmode;
+    }
+}
+
+static rtx
+aarch64_gen_ccmp_first (rtx *prep_seq, rtx *gen_seq,
+                       int code, tree treeop0, tree treeop1)
+{
+  enum machine_mode op_mode, cmp_mode, cc_mode;
+  rtx op0, op1, cmp, target;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (treeop0));
+  enum insn_code icode;
+  struct expand_operand ops[4];
+
+  cc_mode = aarch64_code_to_ccmode ((enum rtx_code) code);
+  if (cc_mode == CCmode)
+    return NULL_RTX;
+
+  start_sequence ();
+  expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+
+  op_mode = GET_MODE (op0);
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (op1);
+
+  switch (op_mode)
+    {
+    case QImode:
+    case HImode:
+    case SImode:
+      cmp_mode = SImode;
+      icode = CODE_FOR_cmpsi;
+      break;
+
+    case DImode:
+      cmp_mode = DImode;
+      icode = CODE_FOR_cmpdi;
+      break;
+
+    default:
+      end_sequence ();
+      return NULL_RTX;
+    }
+
+  op0 = prepare_operand (icode, op0, 2, op_mode, cmp_mode, unsignedp);
+  op1 = prepare_operand (icode, op1, 3, op_mode, cmp_mode, unsignedp);
+  if (!op0 || !op1)
+    {
+      end_sequence ();
+      return NULL_RTX;
+    }
+  *prep_seq = get_insns ();
+  end_sequence ();
+
+  cmp = gen_rtx_fmt_ee ((enum rtx_code) code, cmp_mode, op0, op1);
+  target = gen_rtx_REG (CCmode, CC_REGNUM);
+
+  create_output_operand (&ops[0], target, CCmode);
+  create_fixed_operand (&ops[1], cmp);
+  create_fixed_operand (&ops[2], op0);
+  create_fixed_operand (&ops[3], op1);
+
+  start_sequence ();
+  if (!maybe_expand_insn (icode, 4, ops))
+    {
+      end_sequence ();
+      return NULL_RTX;
+    }
+  *gen_seq = get_insns ();
+  end_sequence ();
+
+  return gen_rtx_REG (cc_mode, CC_REGNUM);
+}
+
+static rtx
+aarch64_gen_ccmp_next (rtx *prep_seq, rtx *gen_seq, rtx prev, int cmp_code,
+                      tree treeop0, tree treeop1, int bit_code)
+{
+  rtx op0, op1, cmp0, cmp1, target;
+  enum machine_mode op_mode, cmp_mode, cc_mode;
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (treeop0));
+  enum insn_code icode = CODE_FOR_ccmp_andsi;
+  struct expand_operand ops[6];
+
+  cc_mode = aarch64_code_to_ccmode ((enum rtx_code) cmp_code);
+  if (cc_mode == CCmode)
+    return NULL_RTX;
+
+  push_to_sequence ((rtx_insn*) *prep_seq);
+  expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+
+  op_mode = GET_MODE (op0);
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (op1);
+
+  switch (op_mode)
+    {
+    case QImode:
+    case HImode:
+    case SImode:
+      cmp_mode = SImode;
+      icode = (enum rtx_code) bit_code == AND ? CODE_FOR_ccmp_andsi
+                                               : CODE_FOR_ccmp_iorsi;
+      break;
+
+    case DImode:
+      cmp_mode = DImode;
+      icode = (enum rtx_code) bit_code == AND ? CODE_FOR_ccmp_anddi
+                                               : CODE_FOR_ccmp_iordi;
+      break;
+
+    default:
+      end_sequence ();
+      return NULL_RTX;
+    }
+
+  op0 = prepare_operand (icode, op0, 2, op_mode, cmp_mode, unsignedp);
+  op1 = prepare_operand (icode, op1, 3, op_mode, cmp_mode, unsignedp);
+  if (!op0 || !op1)
+    {
+      end_sequence ();
+      return NULL_RTX;
+    }
+  *prep_seq = get_insns ();
+  end_sequence ();
+
+  target = gen_rtx_REG (cc_mode, CC_REGNUM);
+  cmp1 = gen_rtx_fmt_ee ((enum rtx_code) cmp_code, cmp_mode, op0, op1);
+  cmp0 = gen_rtx_fmt_ee (NE, cmp_mode, prev, const0_rtx);
+
+  create_fixed_operand (&ops[0], prev);
+  create_fixed_operand (&ops[1], target);
+  create_fixed_operand (&ops[2], op0);
+  create_fixed_operand (&ops[3], op1);
+  create_fixed_operand (&ops[4], cmp0);
+  create_fixed_operand (&ops[5], cmp1);
+
+  push_to_sequence ((rtx_insn*) *gen_seq);
+  if (!maybe_expand_insn (icode, 6, ops))
+    {
+      end_sequence ();
+      return NULL_RTX;
+    }
+
+  *gen_seq = get_insns ();
+  end_sequence ();
+
+  return target;
+}
+
+#undef TARGET_GEN_CCMP_FIRST
+#define TARGET_GEN_CCMP_FIRST aarch64_gen_ccmp_first
+
+#undef TARGET_GEN_CCMP_NEXT
+#define TARGET_GEN_CCMP_NEXT aarch64_gen_ccmp_next
+
 /* Implement TARGET_SCHED_MACRO_FUSION_P.  Return true if target supports
    instruction fusion of some sort.  */
 
index adfa46d0e088f3ff41907e210cb644e3de7163bb..c780e417d2827114e16fbfd3d298d4e5b59855b7 100644 (file)
   ""
   "")
 
-(define_insn "*ccmp_and"
+(define_insn "ccmp_and<mode>"
   [(set (match_operand 1 "ccmp_cc_register" "")
        (compare
         (and:SI
   [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
 )
 
-(define_insn "*ccmp_ior"
+(define_insn "ccmp_ior<mode>"
   [(set (match_operand 1 "ccmp_cc_register" "")
        (compare
         (ior:SI
   [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
 )
 
+(define_expand "cmp<mode>"
+  [(set (match_operand 0 "cc_register" "")
+        (match_operator:CC 1 "aarch64_comparison_operator"
+         [(match_operand:GPI 2 "register_operand" "")
+          (match_operand:GPI 3 "aarch64_plus_operand" "")]))]
+  ""
+  {
+    operands[1] = gen_rtx_fmt_ee (COMPARE,
+                                 SELECT_CC_MODE (GET_CODE (operands[1]),
+                                                 operands[2], operands[3]),
+                                 operands[2], operands[3]);
+  }
+)
+
 (define_insn "*condjump"
   [(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator"
                            [(match_operand 1 "cc_register" "") (const_int 0)])
index 4e6c947643155513198080f34dcd9cb2b62004c3..9c81fdb98d47acd30f890a2eeae1a000d444e024 100644 (file)
@@ -11259,18 +11259,25 @@ 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} 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 @code{cbranch_optab}.  @var{code} is
+@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (rtx *@var{prep_seq}, rtx *@var{gen_seq}, int @var{code}, tree @var{op0}, tree @var{op1})
+This function prepares to emit a comparison insn for the first compare in a
+ sequence of conditional comparisions.  It returns a appropriate @code{CC}
+ for passing to @code{gen_ccmp_next} or @code{cbranch_optab}.  The insns to
+ prepare the compare are saved in @var{prep_seq} and the compare insns are
+ saved in @var{gen_seq}.  They will be emitted when all the compares in the
+ the conditional comparision are generated without error.  @var{code} is
  the @code{rtx_code} of the compare for @var{op0} and @var{op1}.
 @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 @var{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 @var{prev} and this comparison is
+@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_NEXT (rtx *@var{prep_seq}, rtx *@var{gen_seq}, rtx @var{prev}, int @var{cmp_code}, tree @var{op0}, tree @var{op1}, int @var{bit_code})
+This function prepare to emit a conditional comparison within a sequence of
+ conditional comparisons.  It returns a appropriate @code{CC} for passing to
+ @code{gen_ccmp_next} or @code{cbranch_optab}.  The insns to prepare the
+ compare are saved in @var{prep_seq} and the compare insns are saved in
+ @var{gen_seq}.  They will be emitted when all the compares in the conditional
+ comparision are generated without error.  The @var{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 @var{prev} and this comparison is
  not supported, otherwise the result must be appropriate for passing to
  @code{gen_ccmp_next} or @code{cbranch_optab}.  @var{code} is the
  @code{rtx_code} of the compare for @var{op0} and @var{op1}.  @var{bit_code}
index 4aebcfeddd2b288374e5744ff228229be144384c..356f7c1c9a4934de6b69c54f0a616827e5523981 100644 (file)
@@ -2542,24 +2542,31 @@ modes and they have different conditional execution capability, such as ARM.",
 
 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 @code{cbranch_optab}.  @var{code} is\n\
+ "This function prepares to emit a comparison insn for the first compare in a\n\
+ sequence of conditional comparisions.  It returns a appropriate @code{CC}\n\
+ for passing to @code{gen_ccmp_next} or @code{cbranch_optab}.  The insns to\n\
+ prepare the compare are saved in @var{prep_seq} and the compare insns are\n\
+ saved in @var{gen_seq}.  They will be emitted when all the compares in the\n\
+ the conditional comparision are generated without error.  @var{code} is\n\
  the @code{rtx_code} of the compare for @var{op0} and @var{op1}.",
- rtx, (int code, rtx op0, rtx op1),
+ rtx, (rtx *prep_seq, rtx *gen_seq, int code, tree op0, tree op1),
  NULL)
 
 DEFHOOK
 (gen_ccmp_next,
- "This function emits a conditional comparison within a sequence of\n\
- conditional comparisons.  The @var{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 @var{prev} and this comparison is\n\
+ "This function prepare to emit a conditional comparison within a sequence of\n\
+ conditional comparisons.  It returns a appropriate @code{CC} for passing to\n\
+ @code{gen_ccmp_next} or @code{cbranch_optab}.  The insns to prepare the\n\
+ compare are saved in @var{prep_seq} and the compare insns are saved in\n\
+ @var{gen_seq}.  They will be emitted when all the compares in the conditional\n\
+ comparision are generated without error.  The @var{prev} expression is the\n\
+ result of a prior call to @code{gen_ccmp_first} or @code{gen_ccmp_next}.  It\n\
+ may return @code{NULL} if the combination of @var{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}.  @var{code} is the\n\
  @code{rtx_code} of the compare for @var{op0} and @var{op1}.  @var{bit_code}\n\
  is @code{AND} or @code{IOR}, which is the op on the two compares.",
- rtx, (rtx prev, int cmp_code, rtx op0, rtx op1, int bit_code),
+ rtx, (rtx *prep_seq, rtx *gen_seq, rtx prev, int cmp_code, tree op0, tree op1, int bit_code),
  NULL)
 
 /* Return a new value for loop unroll size.  */
index 4e657a479081f22735288eebfe74e8a982c51bb1..72c6283755c3e2cd9c9d014f10519db2dcbcc492 100644 (file)
@@ -1,3 +1,7 @@
+2015-01-16  Zhenqiang Chen <zhenqiang.chen@arm.com>
+
+       * gcc.dg/pr64015.c: New test.
+
 2015-01-16  Markus Trippelsdorf  <markus@trippelsdorf.de>
 
        PR ipa/64163
diff --git a/gcc/testsuite/gcc.dg/pr64015.c b/gcc/testsuite/gcc.dg/pr64015.c
new file mode 100644 (file)
index 0000000..daf8393
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 " } */
+
+int
+test (unsigned short a, unsigned char b)
+{
+  return a > 0xfff2 && b > 252;
+}
+
+/* { dg-final { scan-assembler "ccmp" { target aarch64*-*-* } } } */