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