Re: [PATCH v3] phiopt: Add some TARGET_MEM_REF support to factoring of loads [PR100173]

Andrea Pinski <[email protected]> Mon, 3 Aug 2026 21:33:04 -0700
Newsgroups gmane.comp.gcc.patches
Message-ID <CALvbMcDvUk=fhjCnzkpCwYDBWgL-q=xeysPR2x-bOFnyqznj5w@mail.gmail.com>
On Wed, Jul 29, 2026 at 5:01 AM Richard Biener
<[email protected]> wrote:
>
> On Sat, Jul 25, 2026 at 2:48 AM Andrea Pinski
> <[email protected]> wrote:
> >
> > The testcase in factor_op_phi-load-target_mem-1.c at -O2 gets:
> > ```
> >   if (_4 > _6)
> >     goto <bb 4>; [50.00%]
> >   else
> >     goto <bb 5>; [50.00%]
> >
> >   <bb 4> [local count: 531502204]:
> >   t_21 = MEM[(int *)c_19(D) + ivtmp.23_12 * 1];
> >   goto <bb 6>; [100.00%]
> >
> >   <bb 5> [local count: 531502204]:
> >   t_20 = MEM[(int *)c_19(D) + 8B + ivtmp.23_12 * 1];
> >
> >   <bb 6> [local count: 1063004408]:
> >   # t_13 = PHI <t_21(4), t_20(5)>
> >   # t1_14 = PHI <_4(4), _6(5)>
> > ```
> >
> > But that MEM is a TARGET_MEM_REF which is not supported by
> > factor_out_conditional_load yet. This adds simple TARGET_MEM_REF
> > support by requiring the index/step and index2 to be all the same.
> > It even supports a mismatched TARGET_MEM_REF with a MEM_REF but
> > only if the TARGET_MEM_REF had an null index/step and index2.
> >
> > We now get a similar code generation for telecom/viterb00data_1 (EEMBC)
> > at -O2 as LLVM.
> >
> > Changes since v1:
> > * v2: Fix small issue checking of equality and nullptr of TARGET_MEM_REF
> > operands.
> > * v3: Fix operand_equal check.
> >
> > Bootstrapped and tested on x86_64-linux-gnu.
> >
> >         PR tree-optmization/100173
> >
> > gcc/ChangeLog:
> >
> >         * tree-ssa-phiopt.cc (factor_out_conditional_load): Add simple
> >         support for TARGET_MEM_REF.
> >
> > gcc/testsuite/ChangeLog:
> >
> >         * gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c: New test.
> >
> > Signed-off-by: Andrea Pinski <[email protected]>
> > ---
> >  .../factor_op_phi-load-target_mem-1.c         | 24 +++++++++
> >  gcc/tree-ssa-phiopt.cc                        | 53 +++++++++++++++++--
> >  2 files changed, 74 insertions(+), 3 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
> >
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
> > new file mode 100644
> > index 00000000000..2e2a9ad7834
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
> > @@ -0,0 +1,24 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -fdump-tree-phiopt4-details" } */
> > +/* PR tree-optmization/100173 */
> > +/* TARGET_MEM_REF was not being supported for load factoring.  */
> > +
> > +void f(int a, int *b, int *d, int *c)
> > +{
> > +    for(int i = 0; i < 1024; i++)
> > +    {
> > +      int t;
> > +      int t1;
> > +      if (b[i] > d[i]) {
> > +        t1 = b[i];
> > +        t = c[i];
> > +      }
> > +      else {
> > +        t1 = d[i];
> > +        t = c[i+2];
> > +      }
> > +      b[i] = t+t1;
> > +    }
> > +}
> > +
> > +/* { dg-final { scan-tree-dump "changed to factor out load from COND_EXPR" "phiopt4" } } */
> > diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> > index d48f164c7fb..a5f469e883e 100644
> > --- a/gcc/tree-ssa-phiopt.cc
> > +++ b/gcc/tree-ssa-phiopt.cc
> > @@ -3972,12 +3972,54 @@ factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
> >
> >    tree ref0 = gimple_assign_rhs1 (load0);
> >    tree ref1 = gimple_assign_rhs1 (load1);
> > +  tree index = nullptr;
> > +  tree step = nullptr;
> > +  tree index2 = nullptr;
> >
> >    /* Both must be *P loads of a compatible value type.  The
> >       TBAA alias-ptr type carried by MEM_REF operand 1 need not match; it is
> >       merged the way get_alias_type_for_stmts does when the load is built.  */
> > -  if (TREE_CODE (ref0) != MEM_REF || TREE_CODE (ref1) != MEM_REF
> > -      || !types_compatible_p (TREE_TYPE (ref0), TREE_TYPE (ref1)))
> > +  if (TREE_CODE (ref0) != MEM_REF)
> > +    {
> > +      if (TREE_CODE (ref0) != TARGET_MEM_REF)
> > +       return false;
> > +      index = TREE_OPERAND (ref0, 2);
>
> TMR_INDEX
>
> > +      step = TREE_OPERAND (ref0, 3);
>
> TMR_STEP
>
> > +      index2 = TREE_OPERAND (ref0, 4);
>
> TMR_INDEX2
>
> > +    }
> > +  if (TREE_CODE (ref1) == MEM_REF)
> > +    {
> > +      if (index || step || index2)
> > +       return false;
> > +    }
> > +  else
> > +    {
> > +      if (TREE_CODE (ref1) != TARGET_MEM_REF)
> > +       return false;
> > +      if (index != TREE_OPERAND (ref1, 2))
> > +       {
> > +         if (!index || !TREE_OPERAND (ref1, 2))
> > +           return false;
> > +         if (!operand_equal_p (index, TREE_OPERAND (ref1, 2)))
> > +           return false;
> > +       }
> > +      if (step != TREE_OPERAND (ref1, 3))
> > +       {
> > +         if (!step || !TREE_OPERAND (ref1, 3))
> > +           return false;
> > +         if (!operand_equal_p (step, TREE_OPERAND (ref1, 3)))
> > +           return false;
> > +       }
> > +      if (index2 != TREE_OPERAND (ref1, 4))
> > +       {
> > +         if (!index2 || !TREE_OPERAND (ref1, 4))
> > +           return false;
> > +         if (!operand_equal_p (index2, TREE_OPERAND (ref1, 4)))
> > +           return false;
> > +       }
> > +    }
>
> Ick!  I wonder if a safe_operand_equal_p that deals with NULL would help.  I'll
> note that using just == might actually work given while TMR_STEP can be
> constant it should be always of sth like sizetype for the base.

Yes it makes sense to have a safe_operand_equal_p; There is at least
one other location where this pattern shows up; mem_attrs_eq_p in
emit-rtl.cc :
```
          && (p->expr == q->expr
              || (p->expr != NULL_TREE && q->expr != NULL_TREE
                  && operand_equal_p (p->expr, q->expr, 0))));

```
mem_expr_equal_p, address_info_hasher::equal, perform_symbolic_merge are others.
I added it and will push a fixed up version after a bootstrap/test is completed.

>
> Otherwise OK.
>
> Thanks,
> Richard.
>
> > +
> > +  if (!types_compatible_p (TREE_TYPE (ref0), TREE_TYPE (ref1)))
> >      return false;
> >
> >    /* The alignment of the two accesses need to be the same.  */
> > @@ -4098,7 +4140,12 @@ factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
> >
> >    /* Build the combined load RES = *PTR, reusing the PHI result so any range
> >       info on it is preserved (as factor_out_conditional_operation does).  */
> > -  tree nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
> > +  tree nref;
> > +  if (index || step || index2)
> > +    nref = build5 (TARGET_MEM_REF, TREE_TYPE (ref0), newptr,
> > +                  newindex, index, step, index2);
> > +  else
> > +    nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
> >    MR_DEPENDENCE_CLIQUE (nref) = clique;
> >    MR_DEPENDENCE_BASE (nref) = base;
> >    tree res = gimple_phi_result (phi);
> > --
> > 2.43.0
> >