> Am 04.05.2026 um 15:52 schrieb Andrew Pinski <[email protected]>:
>
> Like the already approved patch at
> https://inbox.sourceware.org/gcc-patches/[email protected]/
> but reworked to fit into the new simplified code and
> also fixed a bug noticed for aggregates.
>
> Aggregates include a store when doing phiprop so we need to
> check if there are also loads between the original store/load
> and the clobber we are skipping. Like the skipping of the
> store case, I didn't see this happening enough to add the
> extra checks. I did add a testcase (phiprop-5.C) which checks
> this.
>
> changes since v2:
> * v3: treat aggregates special earlier and don't duplicate code.
> * v2: adapt to can_handle_load instead of inline.
Ok
Richard
> PR tree-optimization/116823
>
> gcc/ChangeLog:
>
> * tree-ssa-phiprop.cc (can_handle_load): Skip past
> clobbers for !aggregate.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/tree-ssa/phiprop-2.C: New test.
> * g++.dg/tree-ssa/phiprop-4.C: New test.
> * g++.dg/tree-ssa/phiprop-5.C: New test.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> gcc/testsuite/g++.dg/tree-ssa/phiprop-2.C | 23 +++++++++++
> gcc/testsuite/g++.dg/tree-ssa/phiprop-4.C | 30 ++++++++++++++
> gcc/testsuite/g++.dg/tree-ssa/phiprop-5.C | 36 +++++++++++++++++
> gcc/tree-ssa-phiprop.cc | 49 +++++++++++++++++++----
> 4 files changed, 131 insertions(+), 7 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/tree-ssa/phiprop-2.C
> create mode 100644 gcc/testsuite/g++.dg/tree-ssa/phiprop-4.C
> create mode 100644 gcc/testsuite/g++.dg/tree-ssa/phiprop-5.C
>
> diff --git a/gcc/testsuite/g++.dg/tree-ssa/phiprop-2.C
> b/gcc/testsuite/g++.dg/tree-ssa/phiprop-2.C
> new file mode 100644
> index 00000000000..e3388d1d157
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tree-ssa/phiprop-2.C
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O1 -fdump-tree-phiprop1-details -fdump-tree-release_ssa" }
> */
> +
> +/* PR tree-optimization/116823 */
> +/* The clobber on a should not get in the way of phiprop here even if
> + this is undefined code. */
> +/* We should have MIN_EXPR early on then too. */
> +
> +static inline
> +const int &c(const int &d, const int &e) {
> + if (d < e)
> + return d;
> + return e;
> +}
> +
> +int g(int i, struct f *ff)
> +{
> + const int &a = c(i, 10);
> + return a;
> +}
> +/* { dg-final { scan-tree-dump-times "Inserting PHI for result of load" 1
> "phiprop1"} } */
> +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "release_ssa"} } */
> +
> diff --git a/gcc/testsuite/g++.dg/tree-ssa/phiprop-4.C
> b/gcc/testsuite/g++.dg/tree-ssa/phiprop-4.C
> new file mode 100644
> index 00000000000..b630148faa5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tree-ssa/phiprop-4.C
> @@ -0,0 +1,30 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-tree-sra -fdump-tree-phiprop-details" } */
> +/* PR tree-optimization/123120 */
> +/* Make sure the store to *e conflicts with the store to *d */
> +
> +
> +struct s1
> +{
> + int a;
> +};
> +
> +void f(int *);
> +
> +void g(struct s1 i, struct s1 *d, struct s1 *e)
> +{
> + const struct s1 t = {10};
> + const struct s1 *a;
> + struct s1 t1 = {2};
> + if (t.a < i.a)
> + a = &t;
> + else
> + a = &i;
> + *e = t1;
> + t1 = *a;
> + *d = t1;
> +}
> +
> +/* { dg-final { scan-tree-dump-not "Inserting PHI for result of load"
> "phiprop1"} } */
> +/* { dg-final { scan-tree-dump-not "Inserting PHI for result of load"
> "phiprop2"} } */
> +
> diff --git a/gcc/testsuite/g++.dg/tree-ssa/phiprop-5.C
> b/gcc/testsuite/g++.dg/tree-ssa/phiprop-5.C
> new file mode 100644
> index 00000000000..5a3a04dfaa4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tree-ssa/phiprop-5.C
> @@ -0,0 +1,36 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-phiprop-details" } */
> +/* PR tree-optimization/116823 */
> +/* Make sure the store to *d conflicts with the load from d->a; */
> +
> +
> +struct s1
> +{
> + int a;
> +};
> +
> +void f(int *);
> +
> +int g(struct s1 i, struct s1 *d, struct s1 *e)
> +{
> + int t3;
> + struct s1 t1 = {2};
> + const struct s1 t = {10};
> + const struct s1 *a;
> + {
> + int t67;
> + f(&t67);
> + if (t.a < i.a)
> + a = &t;
> + else
> + a = &i;
> + }
> + t3 = d->a;
> + *d = *a;
> + return t3;
> +}
> +
> +
> +/* { dg-final { scan-tree-dump-not "Inserting PHI for result of load"
> "phiprop1"} } */
> +/* { dg-final { scan-tree-dump-not "Inserting PHI for result of load"
> "phiprop2"} } */
> +
> diff --git a/gcc/tree-ssa-phiprop.cc b/gcc/tree-ssa-phiprop.cc
> index 5985beae26a..54f3ad8d9f8 100644
> --- a/gcc/tree-ssa-phiprop.cc
> +++ b/gcc/tree-ssa-phiprop.cc
> @@ -274,22 +274,57 @@ can_handle_load (gimple *load_stmt,
> expected_vuse = gimple_phi_result (vphi);
> else if (up_vuse)
> expected_vuse = up_vuse;
> + /* Try to see if the store does not effect the load. */
> + gimple *other_store = SSA_NAME_DEF_STMT (vuse);
> + /* For aggregates, skipping the store is too
> + hard to handle as you need to check for loads
> + and it is not worth the extra checks so just handle expected vuse
> + and the dominated by case. */
> + if (aggregate)
> + {
> + /* If the vuse on the load is the same as the expected vuse,
> + there are no stores inbetween. */
> + if (vuse == expected_vuse)
> + return vuse;
> + if (expected_vuse)
> + return NULL_TREE;
> + if (gimple_bb (other_store) != bb
> + && dominated_by_p (CDI_DOMINATORS,
> + bb, gimple_bb (other_store)))
> + return vuse;
> + return NULL_TREE;
> + }
> +
> + /* Skip over clobbers in the same bb as the use
> + as they don't interfere with loads. */
> + while (!SSA_NAME_IS_DEFAULT_DEF (vuse)
> + && gimple_clobber_p (other_store)
> + && gimple_bb (other_store) == bb)
> + {
> + vuse = gimple_vuse (other_store);
> + other_store = SSA_NAME_DEF_STMT (vuse);
> + }
> + /* If the load does not have a store beforehand,
> + then we can do the load in conditional. */
> + if (SSA_NAME_IS_DEFAULT_DEF (vuse))
> + {
> + /* For loads that have no stores before, there should be no
> + vphi. */
> + gcc_checking_assert (!vphi);
> + /* The common vuse is the same as the default or there is none. */
> + gcc_checking_assert (!up_vuse || up_vuse == vuse);
> + return vuse;
> + }
>
> /* If the vuse on the load is the same as the expected vuse,
> there are no stores inbetween. */
> if (vuse == expected_vuse)
> return vuse;
> - /* Try to see if the store does not effect the load. */
> - gimple *other_store = SSA_NAME_DEF_STMT (vuse);
> +
> /* Only handling the case where the store is in the same
> bb as the phi. */
> if (gimple_bb (other_store) == bb)
> {
> - /* For aggregates, skipping the store is too
> - hard to handle as you need to check for loads
> - and it is not worth the extra checks. */
> - if (aggregate)
> - return NULL_TREE;
> tree src = gimple_assign_rhs1 (load_stmt);
> ao_ref read;
> ao_ref_init (&read, src);
> --
> 2.43.0
>