Patch is rebased and merged with other changes according to comments.

Thanks!
-Zhenqiang

> -----Original Message-----
> From: gcc-patches-ow...@gcc.gnu.org [mailto:gcc-patches-
> ow...@gcc.gnu.org] On Behalf Of Zhenqiang Chen
> Sent: Tuesday, September 23, 2014 2:44 PM
> To: gcc-patches@gcc.gnu.org
> Subject: [Ping] [PATCH, 4/10] expand ccmp
> 
> Ping?
> 
> Patch is rebased and regenerated since "[PATCH, 3/10] skip swapping
> operands used in ccmp" is discarded.
> 
> Please find the updated patch in attachment.
> 
> Bootstrap and no make check regression on X86-64.
> 
> Thanks!
> -Zhenqiang
> 
> ChangeLog:
> 2014-09-23  Zhenqiang Chen  <zhenqiang.c...@linaro.org>
> 
>       * ccmp.c: New file.
>       * ccmp.h: New file.
>       * Makefile.in: Add ccmp.o
>       * expr.c: #include "ccmp.h"
>       (expand_expr_real_1): Try to expand ccmp.
> 
> > -----Original Message-----
> > From: gcc-patches-ow...@gcc.gnu.org [mailto:gcc-patches-
> > ow...@gcc.gnu.org] On Behalf Of Zhenqiang Chen
> > Sent: Tuesday, July 01, 2014 4:01 PM
> > To: Richard Earnshaw
> > Cc: gcc-patches@gcc.gnu.org
> > Subject: Re: [PATCH, 4/10] expand ccmp
> >
> > On 25 June 2014 23:16, Richard Earnshaw <rearn...@arm.com> wrote:
> > > On 23/06/14 07:59, Zhenqiang Chen wrote:
> > >> Hi,
> > >>
> > >> This patch includes the main logic to expand ccmp instructions.
> > >>
> > >> In the patch,
> > >>   * 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 gen_ccmp_first and gen_ccmp_next to generate CCMP
> > instructions.
> > >>
> > >>     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.
> > >>
> > >> Bootstrap and no make check regression on X86-64.
> > >>
> > >> OK for trunk?
> > >>
> > >> Thanks!
> > >> -Zhenqiang
> > >>
> > >> ChangeLog:
> > >> 2014-06-23  Zhenqiang Chen  <zhenqiang.c...@linaro.org>
> > >>
> > >>         * ccmp.c (ccmp_candidate_p, used_in_cond_stmt_p,
> > check_clobber_cc,
> > >>         clobber_cc_p, expand_ccmp_next, expand_ccmp_expr_1,
> > expand_ccmp_expr):
> > >>         New functions to expand ccmp.
> > >>         * ccmp.h (expand_ccmp_expr): New prototype.
> > >>         * expr.c: #include "ccmp.h"
> > >>         (expand_expr_real_1): Try to expand ccmp.
> > >>
> > >> diff --git a/gcc/ccmp.c b/gcc/ccmp.c index 665c2a5..97b3910 100644
> > >> --- a/gcc/ccmp.c
> > >> +++ b/gcc/ccmp.c
> > >> @@ -47,6 +47,262 @@ along with GCC; see the file COPYING3.  If not
> > >> see  #include "expmed.h"
> > >>  #include "ccmp.h"
> > >>
> > >> +/* 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.
> > >> +
> > >> +       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);
> > >> +       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)
> > >
> > > You shouldn't assume that CC regs will only ever have mode CCmode.
> > > It's probably better to check for the mode class being MODE_CC.
> > > Also, not all architectures have a single CC register, so this test
> > > might be unduly restrictive on targets with multiple predicate
registers.
> >
> > Thanks for the comments. The code segment is removed as the update for
> > the following comments "hoist any preparation operations above the
> > entire conditional compare sequence"
> >
> > >> +    *(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
> > >> +expand_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;
> > >> +
> > >
> > > I suspect it might be better to just hoist any preparation
> > > operations above the entire conditional compare sequence, so that by
> > > the time we start the ccmp expansion we're dealing with operands
> > > that are in the 'natural' sizes for the machine (breaking up the
> > > conditional compare sequence for what are almost side-effect
> > > operationssounds like a source of potential bugs).  This would also
> > > ensure that the back-end can safely re-order at least some
> > > comparison operations if this leads a workable conditional compare
> sequence.
> >
> > Updated. All the preparation operations are moved above the entire
> > conditional compare sequence.
> >
> > > For example, in ARM
> > >
> > >   (a < b && c <= d)
> > >
> > > has to be computed as
> > >   cmp   c, d
> > >   cmple a, b
> > >   ...lt true-op
> > >   ...ge false-op
> > >
> > > since the sequence
> > >   cmp   a, b
> > >   cmplt c, d
> > >   ...le true-op
> > >
> > > would lead to the wrong behaviour when a == b and c == d.
> > >
> > >
> > >> +  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;
> > >> +         enum rtx_code rcode0, rcode1;
> > >> +         rtx op0, op1, op2, op3, tmp;
> > >> +
> > >> +         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);
> > >> +         if (!tmp)
> > >> +           return NULL_RTX;
> > >> +
> > >> +         return targetm.gen_ccmp_next (tmp, rcode1, op2, op3,
> > >> +                                       get_rtx_code (code, 0));
> > >> +       }
> > >> +      else
> > >> +       {
> > >> +         gcc_assert (code1 == BIT_AND_EXPR || code1 ==
> > >> + BIT_IOR_EXPR);
> > >> +
> > >> +         /* Note: We swap the order to make the recursive function
> work.
> > */
> > >> +         tmp = expand_ccmp_expr_1 (gs1);
> > >> +         if (tmp)
> > >> +           return expand_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 expand_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;
> > >> +}
> > >> +
> > >> +rtx
> > >> +expand_ccmp_expr (gimple g)
> > >> +{
> > >> +  rtx last, tmp;
> > >> +
> > >> +  if (!ccmp_candidate_p (g))
> > >> +    return NULL_RTX;
> > >> +
> > >> +  last = get_last_insn ();
> > >> +  tmp = expand_ccmp_expr_1 (g);
> > >> +
> > >> +  if (tmp)
> > >> +    {
> > >> +      enum insn_code icode;
> > >> +      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;
> > >> +
> > >> +      /* 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);
> > >
> > > I think you should be using SELECT_CC_MODE here.
> >
> > Updated.
> >
> > diff --git a/gcc/ccmp.c b/gcc/ccmp.c
> > index fb51129..e0670f1 100644
> > --- a/gcc/ccmp.c
> > +++ b/gcc/ccmp.c
> > @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
> > #include "coretypes.h"
> >  #include "tm.h"
> >  #include "rtl.h"
> > +#include "tm_p.h"
> >  #include "tree.h"
> >  #include "stringpool.h"
> >  #include "regs.h"
> > @@ -47,6 +48,245 @@ along with GCC; see the file COPYING3.  If not see
> > #include "expmed.h"
> >  #include "ccmp.h"
> >
> > +/* 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.
> > +
> > +     * 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);
> > +       if (integer_zerop (op1))
> > +         expand_cond = true;
> > +       BREAK_FROM_IMM_USE_STMT (ui);
> > +      }
> > +  return expand_cond;
> > +}
> > +
> > +/* 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;
> > +         enum rtx_code rcode0, rcode1;
> > +         rtx op0, op1, op2, op3, tmp;
> > +
> > +         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);
> > +         if (!tmp)
> > +           return NULL_RTX;
> > +
> > +         return targetm.gen_ccmp_next (tmp, rcode1, op2, op3,
> > +                                       get_rtx_code (code, 0));
> > +       }
> > +      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);
> > +
> > +         /* 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));
> > +       }
> > +    }
> > +  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)
> > +       {
> > +         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));
> > +       }
> > +      else
> > +       {
> > +         gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR
> > +                     || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR);
> > +       }
> > +    }
> > +
> > +  return NULL_RTX;
> > +}
> > +
> > +rtx
> > +expand_ccmp_expr (gimple g)
> > +{
> > +  rtx last, tmp;
> > +
> > +  if (!ccmp_candidate_p (g))
> > +    return NULL_RTX;
> > +
> > +  last = get_last_insn ();
> > +  tmp = expand_ccmp_expr_1 (g);
> > +
> > +  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;
> > +
> > +#ifdef SELECT_CC_MODE
> > +      cc_mode = SELECT_CC_MODE (NE, tmp, const0_rtx); #endif
> > +      /* 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, cc_mode);
> > +      if (icode != CODE_FOR_nothing)
> > +       {
> > +         rtx target = gen_reg_rtx (word_mode);
> > +         tmp = emit_cstore (target, icode, NE, cc_mode, cc_mode,
> > +                            0, tmp, const0_rtx, 1, word_mode);
> > +         if (tmp)
> > +           return tmp;
> > +       }
> > +    }
> > +
> > +  /* Clean up.  */
> > +  delete_insns_since (last);
> > +  return NULL_RTX;
> > +}
> > +
> > bool
> >  ccmp_insn_p (rtx object)
> >  {
> > diff --git a/gcc/ccmp.h b/gcc/ccmp.h
> > index 7e139aa..56f3ac2 100644
> > --- a/gcc/ccmp.h
> > +++ b/gcc/ccmp.h
> > @@ -20,6 +20,8 @@ along with GCC; see the file COPYING3.  If not see
> > #ifndef GCC_CCMP_H  #define GCC_CCMP_H
> >
> > +extern rtx expand_ccmp_expr (gimple);
> > +
> >  extern bool ccmp_insn_p (rtx);
> >
> >  #endif  /* GCC_CCMP_H  */
> > diff --git a/gcc/expr.c b/gcc/expr.c
> > index 04cf56e..4c31521 100644
> > --- a/gcc/expr.c
> > +++ b/gcc/expr.c
> > @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
> > #include "tree-ssa-address.h"
> >  #include "cfgexpand.h"
> >  #include "builtins.h"
> > +#include "ccmp.h"
> >
> >  #ifndef STACK_PUSH_CODE
> >  #ifdef STACK_GROWS_DOWNWARD
> > @@ -9379,6 +9380,15 @@ expand_expr_real_1 (tree exp, rtx target, enum
> > machine_mode tmode,
> >               /* Fallthru */
> >             case GIMPLE_BINARY_RHS:
> >               ops.op1 = gimple_assign_rhs2 (g);
> > +
> > +             /* Try to expand conditonal compare.  */
> > +             if (targetm.gen_ccmp_first != NULL)
> > +               {
> > +                 gcc_checking_assert (targetm.gen_ccmp_next != NULL);
> > +                 r = expand_ccmp_expr (g);
> > +                 if (r)
> > +                   break;
> > +               }
> >               /* Fallthru */
> >             case GIMPLE_UNARY_RHS:
> >               ops.op0 = gimple_assign_rhs1 (g);

Attachment: 3-4-ccmp.patch
Description: Binary data

Reply via email to