Got, thanks Richard and will have a try in v5.

Pan

-----Original Message-----
From: Richard Biener <richard.guent...@gmail.com> 
Sent: Wednesday, September 18, 2024 8:06 PM
To: Li, Pan2 <pan2...@intel.com>
Cc: gcc-patches@gcc.gnu.org; tamar.christ...@arm.com; juzhe.zh...@rivai.ai; 
kito.ch...@gmail.com; jeffreya...@gmail.com; rdapp....@gmail.com
Subject: Re: [PATCH v4 1/4] Match: Add interface match_cond_with_binary_phi for 
true/false arg

On Wed, Sep 18, 2024 at 2:02 PM Richard Biener
<richard.guent...@gmail.com> wrote:
>
> On Fri, Sep 13, 2024 at 12:42 AM <pan2...@intel.com> wrote:
> >
> > From: Pan Li <pan2...@intel.com>
> >
> > When matching the cond with 2 args phi node, we need to figure out
> > which arg of phi node comes from the true edge of cond block, as
> > well as the false edge.  This patch would like to add interface
> > to perform the action and return the true and false arg in TREE type.
> >
> > There will be some additional handling if one of the arg is INTEGER_CST.
> > Because the INTEGER_CST args may have no source block, thus its' edge
> > source points to the condition block.  See below example in line 31,
> > the 255 INTEGER_CST has block 2 as source.  Thus, we need to find
> > the non-INTEGER_CST (aka _1) to tell which one is the true/false edge.
> > For example, the _1(3) takes block 3 as source, which is the dest
> > of false edge of the condition block.
> >
> >    4   │ __attribute__((noinline))
> >    5   │ uint8_t sat_u_add_imm_type_check_uint8_t_fmt_2 (uint8_t x)
> >    6   │ {
> >    7   │   unsigned char _1;
> >    8   │   unsigned char _2;
> >    9   │   uint8_t _3;
> >   10   │   __complex__ unsigned char _5;
> >   11   │
> >   12   │ ;;   basic block 2, loop depth 0
> >   13   │ ;;    pred:       ENTRY
> >   14   │   _5 = .ADD_OVERFLOW (x_4(D), 9);
> >   15   │   _2 = IMAGPART_EXPR <_5>;
> >   16   │   if (_2 != 0)
> >   17   │     goto <bb 4>; [35.00%]
> >   18   │   else
> >   19   │     goto <bb 3>; [65.00%]
> >   20   │ ;;    succ:       3
> >   21   │ ;;                4
> >   22   │
> >   23   │ ;;   basic block 3, loop depth 0
> >   24   │ ;;    pred:       2
> >   25   │   _1 = REALPART_EXPR <_5>;
> >   26   │ ;;    succ:       4
> >   27   │
> >   28   │ ;;   basic block 4, loop depth 0
> >   29   │ ;;    pred:       2
> >   30   │ ;;                3
> >   31   │   # _3 = PHI <255(2), _1(3)>
> >   32   │   return _3;
> >   33   │ ;;    succ:       EXIT
> >   34   │
> >   35   │ }
> >
> > The below test suites are passed for this patch.
> > * The rv64gcv fully regression test.
> > * The x86 bootstrap test.
> > * The x86 fully regression test.
> >
> > gcc/ChangeLog:
> >
> >         * gimple-match-head.cc (match_cond_with_binary_phi): Add new func
> >         impl to match binary phi for true and false arg.
> >
> > Signed-off-by: Pan Li <pan2...@intel.com>
> > ---
> >  gcc/gimple-match-head.cc | 118 +++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 118 insertions(+)
> >
> > diff --git a/gcc/gimple-match-head.cc b/gcc/gimple-match-head.cc
> > index 924d3f1e710..6e7a3a0d62e 100644
> > --- a/gcc/gimple-match-head.cc
> > +++ b/gcc/gimple-match-head.cc
> > @@ -375,3 +375,121 @@ gimple_bitwise_inverted_equal_p (tree expr1, tree 
> > expr2, bool &wascmp, tree (*va
> >      return true;
> >    return false;
> >  }
> > +
> > +/*
> > + * Return the relevant gcond * of the given phi, as well as the true
> > + * and false TREE args of the phi.  Or return NULL.
> > + *
> > + * If matched the gcond *, the output argument TREE true_arg and false_arg
> > + * will be updated to the relevant args of phi.
> > + *
> > + * If failed to match, NULL gcond * will be returned, as well as the output
> > + * arguments will be set to NULL_TREE.
> > + */
> > +
> > +static inline gcond *
> > +match_cond_with_binary_phi (gphi *phi, tree *true_arg, tree *false_arg)
> > +{
> > +  *true_arg = *false_arg = NULL_TREE;
> > +
> > +  if (gimple_phi_num_args (phi) != 2
> > +      || EDGE_COUNT (gimple_bb (phi)->preds) != 2)
> > +    return NULL;
> > +
> > +  basic_block pred_0 = EDGE_PRED (gimple_bb (phi), 0)->src;
> > +  basic_block pred_1 = EDGE_PRED (gimple_bb (phi), 1)->src;
> > +  basic_block cond_block = NULL;
> > +
> > +  if ((EDGE_COUNT (pred_0->succs) == 2 && EDGE_COUNT (pred_1->succs) == 1)
> > +     || (EDGE_COUNT (pred_0->succs) == 1 && EDGE_COUNT (pred_1->succs) == 
> > 2))
> > +    {
> > +      /* For below control flow graph:
> > +       *    |
> > +       *    v
> > +       * +------+
> > +       * | b0:  |
> > +       * | def  |       +-----+
> > +       * | ...  |       | b1: |
> > +       * | cond |------>| def |
> > +       * +------+       | ... |
> > +       *    |           +-----+
> > +       *    |              |
> > +       *    v              |
> > +       * +-----+           |
> > +       * | b2: |           |
> > +       * | def |<----------+
> > +       * +-----+
> > +       */
> > +      basic_block b0 = EDGE_COUNT (pred_0->succs) == 2 ? pred_0 : pred_1;
> > +      basic_block b1 = EDGE_COUNT (pred_0->succs) == 1 ? pred_0 : pred_1;
> > +
> > +      if (EDGE_COUNT (b1->preds) == 1 && EDGE_PRED (b1, 0)->src == b0)
> > +       cond_block = b0;
> > +    }
> > +
> > +  if (EDGE_COUNT (pred_0->succs) == 1 && EDGE_COUNT (pred_0->preds) == 1
> > +      && EDGE_COUNT (pred_1->succs) == 1 && EDGE_COUNT (pred_1->preds) == 
> > 1)
> > +    {
> > +      /* For below control flow graph:
> > +       *    |
> > +       *    v
> > +       * +------+
> > +       * | b0:  |
> > +       * | ...  |       +-----+
> > +       * | cond |------>| b2: |
> > +       * +------+       | ... |
> > +       *    |           +-----+
> > +       *    |              |
> > +       *    v              |
> > +       * +-----+           |
> > +       * | b1: |           |
> > +       * | ... |           |
> > +       * +-----+           |
> > +       *    |              |
> > +       *    |              |
> > +       *    v              |
> > +       * +-----+           |
> > +       * | b3: |<----------+
> > +       * | ... |
> > +       * +-----+
> > +       */
> > +      basic_block b0 = EDGE_PRED (pred_0, 0)->src;
> > +
> > +      if (EDGE_COUNT (b0->succs) == 2 && EDGE_PRED (pred_1, 0)->src == b0)
> > +       cond_block = b0;
> > +    }
> > +
> > +  if (cond_block == NULL)
> > +    return NULL;
>
> I think it's better to above compute the edge from the possible gcond block 
> that
> leads to PHI arg0, because the CFG matching easily identifies it and we
> can take the edge flag from it.  Like maybe (untested):
>
> static inline gcond *
> match_cond_with_binary_phi (gphi *phi, tree *true_arg, tree *false_arg)
> {
>   *true_arg = *false_arg = NULL_TREE;
>
>   if (gimple_phi_num_args (phi) != 2)
>     return NULL;
>
>  basic_block pred0 = EDGE_PRED (gimple_bb (phi), 0)->src;
>  basic_block pred1 = EDGE_PRED (gimple_bb (phi), 1)->src;
>  gcond *cond;
>  edge edge_for_pred0;
>
>  if (EDGE_COUNT (pred0->succs) == 2
>      && EDGE_COUNT (pred1->succs) == 1
>      && EDGE_COUNT (pred1->preds) == 1
>      && pred0->src == EDGE_PRED (pred1->preds, 0)->src)
>    edge_for_pred0 = EDGE_PRED (gimple_bb (phi), 0);
>
>  else if (EDGE_COUNT (pred1->succs) == 2
>           && EDGE_COUNT (pred0->succs) == 1
>           && EDGE_COUNT (pred0->preds) == 1
>           && EDGE_PRED (pred0->preds, 0)->src == pred1->src)
>    edge_for_pred0 = EDGE_PRED (pred0, 0);
>
>  else if (EDGE_COUNT (pred0->succs) == 1
>           && EDGE_COUNT (pred1->succs) == 1
>           && EDGE_COUNT (pred0->preds) == 1
>           && EDGE_COUNT (pred1->preds) == 1
>           && EDGE_COUNT (EDGE_SUCC (EDGE_PRED (pred0, 0)->src)) == 2
>           && EDGE_PRED (pred0, 0)->src == EDGE_PRED (pred1, 0)->src)
>    edge_for_pred0 = EDGE_PRED (pred0, 0);
>
>  gcond *cond = safe_dyn_cast <gcond *> (*gsi_last_bb (edge_for_pred0->src));
>  if (!cond)
>    return nullptr;
>
>  if (edge_for_pred0->flags & EDGE_TRUE_VALUE)
>    {
>      *true_arg = gimple_phi_arg_def (phi, 0);
>      *false_arg = gimple_phi_arg_def (phi, 1);
>    }
>  else /* edge_for_pred0->flags & EDGE_FALSE_VALUE */
>    {
>      *true_arg = gimple_phi_arg_def (phi, 0);
>      *false_arg = gimple_phi_arg_def (phi, 1);
>    }
>
>  return cond;
> }

Sorry, that doesn't evne build, the following does:

static inline gcond *
match_cond_with_binary_phi (gphi *phi, tree *true_arg, tree *false_arg)
{
  *true_arg = *false_arg = NULL_TREE;

  if (gimple_phi_num_args (phi) != 2)
    return NULL;

 basic_block pred0 = EDGE_PRED (gimple_bb (phi), 0)->src;
 basic_block pred1 = EDGE_PRED (gimple_bb (phi), 1)->src;
 edge edge_for_pred0;

 if (EDGE_COUNT (pred0->succs) == 2
     && EDGE_COUNT (pred1->succs) == 1
     && EDGE_COUNT (pred1->preds) == 1
     && pred0 == EDGE_PRED (pred1, 0)->src)
   edge_for_pred0 = EDGE_PRED (gimple_bb (phi), 0);

 else if (EDGE_COUNT (pred1->succs) == 2
          && EDGE_COUNT (pred0->succs) == 1
          && EDGE_COUNT (pred0->preds) == 1
          && EDGE_PRED (pred0, 0)->src == pred1)
   edge_for_pred0 = EDGE_PRED (pred0, 0);

 else if (EDGE_COUNT (pred0->succs) == 1
          && EDGE_COUNT (pred1->succs) == 1
          && EDGE_COUNT (pred0->preds) == 1
          && EDGE_COUNT (pred1->preds) == 1
          && EDGE_COUNT (EDGE_PRED (pred0, 0)->src->succs) == 2
          && EDGE_PRED (pred0, 0)->src == EDGE_PRED (pred1, 0)->src)
   edge_for_pred0 = EDGE_PRED (pred0, 0);

 gcond *cond = safe_dyn_cast <gcond *> (*gsi_last_bb (edge_for_pred0->src));
 if (!cond)
   return nullptr;

 if (edge_for_pred0->flags & EDGE_TRUE_VALUE)
   {
     *true_arg = gimple_phi_arg_def (phi, 0);
     *false_arg = gimple_phi_arg_def (phi, 1);
   }
 else /* edge_for_pred0->flags & EDGE_FALSE_VALUE */
   {
     *true_arg = gimple_phi_arg_def (phi, 0);
     *false_arg = gimple_phi_arg_def (phi, 1);
   }

 return cond;
}


>
> > +  /* Now we locate the cond_block for phi node.  */
> > +  tree t0 = gimple_phi_arg_def (phi, 0);
> > +  tree t1 = gimple_phi_arg_def (phi, 1);
> > +  edge e0 = gimple_phi_arg_edge (phi, 0);
> > +  edge e1 = gimple_phi_arg_edge (phi, 1);
> > +
> > +  if (TREE_CODE (t0) == INTEGER_CST && TREE_CODE (t1) == INTEGER_CST)
> > +    return NULL;
> > +
> > +  bool arg_0_cst_p = TREE_CODE (t0) == INTEGER_CST;
> > +  edge arg_edge = arg_0_cst_p ? e1 : e0;
> > +  tree arg = arg_0_cst_p ? t1 : t0;
> > +  tree other_arg = arg_0_cst_p ? t0 : t1;
> > +
> > +  edge cond_e0 = EDGE_SUCC (cond_block, 0);
> > +  edge cond_e1 = EDGE_SUCC (cond_block, 1);
> > +  edge matched_edge = arg_edge->src == cond_e0->dest ? cond_e0 : cond_e1;
> > +
> > +  if (matched_edge->flags & EDGE_TRUE_VALUE)
> > +    {
> > +      *true_arg = arg;
> > +      *false_arg = other_arg;
> > +    }
> > +  else
> > +    {
> > +      *false_arg = arg;
> > +      *true_arg = other_arg;
> > +    }
> > +
> > +  return safe_dyn_cast <gcond *> (*gsi_last_bb (cond_block));
> > +}
> > --
> > 2.43.0
> >

Reply via email to