On Wed, Sep 16, 2026 at 10:57 AM Andrea Pinski
<[email protected]> wrote:
>
> Currently we reject most commonalization of loads in 
> factor_out_conditional_load
> before the vectorizer.  This was done as the easiest and simpliest herustics 
> at
> the time I was writing the code.  We can do better than that.  This inproves
> the heurstics by allowing pointers which don't analyize via scalar evolution.
> This means loads which are from other loads can be factored out earlier than
> the loop optimizers.
>
> This changes 2 testcases which are now factored out in phiopt2 and one
> testcase where we don't want the factoring out before the vectorizer as
> we want to be able to vectorize the code (derived from eembc's
> telecom/viterb00data_1 benchmark).
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
>         PR tree-optimization/125945
>
> gcc/ChangeLog:
>
>         * tree-ssa-phiopt.cc (induction_based): New function.
>         (factor_out_conditional_load): Allow some factoring out
>         with early and/or before_vect.
>         (factor_out_all): Set before_vect to false when not vectorizing.
>         (pass_phiopt::execute): Initialize scev in some cases.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/tree-ssa/scc-diamond-1.c:
>         * gcc.dg/tree-ssa/scc-diamond-3.c:
>         * gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c: New test.

Just a small change to the changelog that I missed about the testsuite:
        * gcc.dg/tree-ssa/scc-diamond-1.c: Update to look at phiopt2
        rather than phiopt4.
        * gcc.dg/tree-ssa/scc-diamond-3.c: Likewise.

Thanks,
Andrea

>
> Signed-off-by: Andrea Pinski <[email protected]>
> ---
>  .../tree-ssa/factor_op_phi-load-vect-1.c      | 64 ++++++++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c |  4 +-
>  gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c |  4 +-
>  gcc/tree-ssa-phiopt.cc                        | 66 ++++++++++++++++---
>  4 files changed, 124 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c
> new file mode 100644
> index 00000000000..c26ea907f2e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c
> @@ -0,0 +1,64 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-aliasing -fdump-tree-phiopt-details" } */
> +/* PR tree-optimization/125945 */
> +/* These factoring out of loads should happen only after the vectorizer for 
> this code. */
> +typedef short s16;
> +struct S { s16 tag; s16 key; };
> +void f(s16 *dst, const struct S *a, const struct S *b, int n)
> +{
> +    for (int i = 0; i < n; i++) {
> +        s16 ka = a[i].key;
> +        s16 kb = b[i].key;
> +        if (ka >= kb)
> +            dst[i] = a[i].tag;
> +        else
> +            dst[i] = b[i].tag;
> +    }
> +}
> +void f1(s16 *dst, const struct S *a, const struct S *b, int n)
> +{
> +    for (int i = 0; i < n; i++) {
> +        s16 ka = a[i].key;
> +        s16 kb = b[i].key;
> +        s16 t;
> +        if (ka >= kb)
> +            t = a[i].tag;
> +        else
> +            t = b[i].tag;
> +        dst[i] = t;
> +    }
> +}
> +void f2(s16 *dst, const struct S *a, const struct S *b, int n)
> +{
> +    for (int i = 0; i < n; i++) {
> +        s16 ka = a[i].key;
> +        s16 kb = b[i].key;
> +        s16 t;
> +        const struct S *tt = &a[i];
> +        const struct S *tt1 = &b[i];
> +        if (ka >= kb)
> +            t = tt->tag;
> +        else
> +            t = tt1->tag;
> +        dst[i] = t;
> +    }
> +}
> +void f3(s16 *dst, const struct S *a, const struct S *b, int n)
> +{
> +    for (int i = 0; i < n; i++) {
> +        s16 ka = a[i].key;
> +        s16 kb = b[i].key;
> +        s16 t;
> +        const s16 *tt = &a[i].tag;
> +        const s16 *tt1 = &b[i].tag;
> +        if (ka >= kb)
> +            t = *tt;
> +        else
> +            t = *tt1;
> +        dst[i] = t;
> +    }
> +}
> +
> +/* { dg-final { scan-tree-dump-not "changed to factor out load from" 
> "phiopt3" } } */
> +/* { dg-final { scan-tree-dump-not "changed to factor out load from" 
> "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-times "changed to factor out load from" 4 
> "phiopt4" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c
> index de4f003bcf3..f6206273d14 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c
> @@ -35,6 +35,6 @@ advance (const uint8_t *ip, size_t tag, const uint8_t *end)
>  }
>
>  /* The diamond is if-converted (branchless): one selected-offset load 
> remains.  */
> -/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
> "phiopt4" } } */
> -/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 
> 1 "phiopt4" } } */
> +/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
> "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 
> 1 "phiopt2" } } */
>  /* { dg-final { scan-tree-dump-times "changed to factor operation out from" 
> 2 "phiopt1" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c
> index 8f9f6a4dead..00c8dd278bc 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c
> @@ -46,6 +46,6 @@ advance (const uint8_t *ip, size_t tag, const uint8_t *end)
>
>  /* The mismatched alias types are merged to the alias-everything type, so the
>     loads are commoned and the diamond is if-converted.  */
> -/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
> "phiopt4" } } */
> -/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 
> 1 "phiopt4" } } */
> +/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
> "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 
> 1 "phiopt2" } } */
>  /* { dg-final { scan-tree-dump-times "changed to factor operation out from" 
> 2 "phiopt1" } } */
> diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> index fbb4ec545e6..84a7949583d 100644
> --- a/gcc/tree-ssa-phiopt.cc
> +++ b/gcc/tree-ssa-phiopt.cc
> @@ -4063,6 +4063,22 @@ cond_if_else_store_replacement (basic_block then_bb, 
> basic_block else_bb,
>    return ok;
>  }
>
> +/* Returns true when P is based on an induction variable
> +   inside MERGE's inner most loop.  */
> +static bool
> +induction_based (tree p, basic_block merge)
> +{
> +  if (TREE_CODE (p) != SSA_NAME)
> +    return false;
> +  tree ev = analyze_scalar_evolution (merge->loop_father, p);
> +  if (chrec_contains_undetermined (ev)
> +      || chrec_contains_symbols_defined_in_loop (ev, 
> merge->loop_father->num))
> +    return false;
> +  if (tree_does_not_contain_chrecs (ev))
> +    return false;
> +  return true;
> +}
> +
>  /* If PHI at MERGE is a "load PHI", PHI <*P, *Q> whose two arguments are
>     single-use, non-volatile scalar MEM_REF loads reading the same memory 
> state
>     (same VUSE), factor the load out: introduce P' = PHI <P, Q> and a single
> @@ -4078,15 +4094,6 @@ static bool
>  factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
>                              bool early_p, bool before_vect)
>  {
> -  /* Factoring out a load during the first phi means we can't
> -     trust if this is inside a loop or not; due to before inlining.  */
> -  if (early_p)
> -    return false;
> -
> -  /* Before vectorization, we don't want to factor out loads unless not 
> inside a loop.  */
> -  if (before_vect && bb_loop_depth (merge) != 0)
> -    return false;
> -
>    /* Not a virtual operand. */
>    if (virtual_operand_p (gimple_phi_result (phi))
>        /* can only handle the merge bb having 2 predecessors.  */
> @@ -4204,6 +4211,23 @@ factor_out_conditional_load (edge e0, edge e1, 
> basic_block merge, gphi *phi,
>    gimple_stmt_iterator gsi;
>    gsi = gsi_after_labels (merge);
>
> +  // factoring of the same pointer should be allowed
> +  // irrespect to loops.
> +  if (p0 == p1 && operand_equal_p (index0, index1))
> +    ;
> +  // Before inlining, we can't tell if different
> +  // pointers are going to be induction variable based
> +  // or not.
> +  else if (early_p)
> +    return false;
> +  // Before vectorization, don't factor out
> +  // pointers which are based on induction variables.
> +  else if (before_vect
> +          && bb_loop_depth (merge) != 0
> +          && (induction_based (p0, merge)
> +              || induction_based (p1, merge)))
> +    return false;
> +
>    /* Try to handle different indices.  */
>    if (operand_equal_p (index0, index1))
>      newindex = fold_convert (atype, index0);
> @@ -4354,6 +4378,11 @@ factor_out_all (edge e1, edge e2, basic_block merge,
>  {
>    bool changed = false;
>    bool do_over;
> +  bool before_vect = !fold_before_rtl_expansion_p ();
> +  // If vectorization is disable, then we are never before the vectorizer.
> +  if (!flag_tree_loop_vectorize
> +      && !merge->loop_father->force_vectorize)
> +    before_vect = false;
>    basic_block bb1 = e1->src;
>    basic_block bb2 = e2->src;
>    do
> @@ -4385,7 +4414,7 @@ factor_out_all (edge e1, edge e2, basic_block merge,
>           /* Conditional load elimination can only be on a diamond.  */
>           if ((diamond_p
>                && factor_out_conditional_load (e1, e2, merge, phi, early_p,
> -                                              !fold_before_rtl_expansion_p 
> ()))
> +                                              before_vect))
>               || factor_out_conditional_operation (e1, e2, merge, phi,
>                                                    cond_stmt, early_p))
>             {
> @@ -4973,6 +5002,18 @@ pass_phiopt::execute (function *)
>  {
>    bool do_hoist_loads = !early_p ? gate_hoist_loads () : false;
>    bool cfgchanged = false;
> +  bool need_loop_finalize = false;
> +
> +  if (!early_p
> +      && !fold_before_rtl_expansion_p ()
> +      && (flag_tree_loop_vectorize
> +         || cfun->has_force_vectorize_loops)
> +      && number_of_loops (cfun) > 1)
> +  {
> +    loop_optimizer_init (LOOPS_NORMAL);
> +    scev_initialize ();
> +    need_loop_finalize = true;
> +  }
>
>    calculate_dominance_info (CDI_DOMINATORS);
>    mark_ssa_maybe_undefs ();
> @@ -5063,6 +5104,11 @@ pass_phiopt::execute (function *)
>
>    execute_over_cond_phis (phiopt_exec);
>
> +  if (need_loop_finalize)
> +    {
> +      loop_optimizer_finalize ();
> +      scev_finalize ();
> +    }
>    if (replicate_conds_over_phis ())
>      {
>        free_dominance_info (CDI_DOMINATORS);
> --
> 2.43.0
>

Reply via email to