Hi,

On Tue, Apr 01 2025, Richard Biener wrote:
> On Mon, 31 Mar 2025, Martin Jambor wrote:
>
>> Hi,
>> 
>> the testcase in PR 118924, when compiled on Aarch64, contains an
>> gimple aggregate assignment statement in between different types which
>> are types_compatible_p but behave differently for the purposes of
>> alias analysis.
>> 
>> SRA replaces the statement with a series of scalar assignments which
>> however have LHSs access chains modeled on the RHS type and so do not
>> alias with a subsequent reads and so are DSEd.
>> 
[...]
>> 
>> The issue here is that even when the access path is the same, it must
>> not be bolted on an aggregate type that does not match.  This patch
>> does that, taking just one simple function from the
>> ao_compare::compare_ao_refs machinery and using it to detect the
>> situation.  The rest is just merging the information in between
>> accesses of the same access group.
>> 
>
> I'm unsure about the lto_streaming_safe arg, in fact the implementation is
>
>   if (lto_streaming_safe)
>     return type1 == type2;
>   else
>     return TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2);
>
> but I think we guarantee (we _need_ to guarantee!) that when
> TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2), after LTO streaming
> it's still TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2).  Otherwise
> assignments previously valid GIMPLE might no longer be valid and
> things that aliased previously might no longer alias.
>
> But that's an implementation bug in types_equal_for_same_type_for_tbaa_p,
> but I think you should be able to pass in false as if the implementation
> were fixed.  IMO if necessary the implementation itself should
> use sth like if (flag_lto && !in_lto_p) rather than leaving it up to
> the caller ... the only existing caller uses
> lto_streaming_expected_p () as arg, which is similar to my proposal.
>
> I'd say you want to export at a forwarder
>
> bool
> types_equal_for_same_type_for_tbaa_p (tree type1, tree type2)
> {
>   return types_equal_for_same_type_for_tbaa_p (type1, type2, 
> lto_streaming_expected_p ());
> }
>
> instead as it should be an internal detail.
>
> OK with that change.
>
> Can you fixup the comment
>
> /* Return ture if TYPE1 and TYPE2 will always give the same answer
>    when compared wit hother types using same_type_for_tbaa_p.  */
>
> when you are there?  The function is called same_type_for_tbaa
> and 'wit hother' should be 'with other'

Thanks, I am about to commit the following then (I did another way of
bootstrapping and testing on x86_64-linux and Aarch64-linux).

Martin


gcc/ChangeLog:

2025-04-04  Martin Jambor  <mjam...@suse.cz>

        PR tree-optimization/118924
        * tree-ssa-alias-compare.h (types_equal_for_same_type_for_tbaa_p):
        Declare.
        * tree-ssa-alias.cc: Include ipa-utils.h.
        (types_equal_for_same_type_for_tbaa_p): New public overloaded variant.
        * tree-sra.cc: Include tree-ssa-alias-compare.h.
        (create_access): Initialzie grp_same_access_path to true.
        (build_accesses_from_assign): Detect tbaa hazards and clear
        grp_same_access_path fields of involved accesses when they occur.
        (sort_and_splice_var_accesses): Take previous values of
        grp_same_access_path into account.

gcc/testsuite/ChangeLog:

2025-03-25  Martin Jambor  <mjam...@suse.cz>

        PR tree-optimization/118924
        * g++.dg/tree-ssa/pr118924.C: New test.
---
 gcc/testsuite/g++.dg/tree-ssa/pr118924.C | 29 ++++++++++++++++++++++++
 gcc/tree-sra.cc                          | 17 +++++++++++---
 gcc/tree-ssa-alias-compare.h             |  2 ++
 gcc/tree-ssa-alias.cc                    | 13 ++++++++++-
 4 files changed, 57 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr118924.C

diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr118924.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr118924.C
new file mode 100644
index 00000000000..c95eacafc9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr118924.C
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-options "-std=c++17 -O2" } */
+
+template <int Size> struct Vector {
+  int m_data[Size];
+  Vector(int, int, int) {}
+};
+enum class E { POINTS, LINES, TRIANGLES };
+
+__attribute__((noipa))
+void getName(E type) {
+  static E check = E::POINTS;
+  if (type == check)
+    check = (E)((int)check + 1);
+  else
+    __builtin_abort ();
+}
+
+int main() {
+  int arr[]{0, 1, 2};
+  for (auto dim : arr) {
+    Vector<3> localInvs(1, 1, 1);
+    localInvs.m_data[dim] = 8;
+  }
+  E types[] = {E::POINTS, E::LINES, E::TRIANGLES};
+  for (auto primType : types)
+    getName(primType);
+  return 0;
+}
diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc
index c26559edc66..ae7cd57a5f2 100644
--- a/gcc/tree-sra.cc
+++ b/gcc/tree-sra.cc
@@ -100,6 +100,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "tree-sra.h"
 #include "opts.h"
+#include "tree-ssa-alias-compare.h"
 
 /* Enumeration of all aggregate reductions we can do.  */
 enum sra_mode { SRA_MODE_EARLY_IPA,   /* early call regularization */
@@ -979,6 +980,7 @@ create_access (tree expr, gimple *stmt, bool write)
   access->type = TREE_TYPE (expr);
   access->write = write;
   access->grp_unscalarizable_region = unscalarizable_region;
+  access->grp_same_access_path = true;
   access->stmt = stmt;
   access->reverse = reverse;
 
@@ -1522,6 +1524,9 @@ build_accesses_from_assign (gimple *stmt)
   racc = build_access_from_expr_1 (rhs, stmt, false);
   lacc = build_access_from_expr_1 (lhs, stmt, true);
 
+  bool tbaa_hazard
+    = !types_equal_for_same_type_for_tbaa_p (TREE_TYPE (lhs), TREE_TYPE (rhs));
+
   if (lacc)
     {
       lacc->grp_assignment_write = 1;
@@ -1536,6 +1541,8 @@ build_accesses_from_assign (gimple *stmt)
            bitmap_set_bit (cannot_scalarize_away_bitmap,
                            DECL_UID (lacc->base));
        }
+      if (tbaa_hazard)
+       lacc->grp_same_access_path = false;
     }
 
   if (racc)
@@ -1555,6 +1562,8 @@ build_accesses_from_assign (gimple *stmt)
        }
       if (storage_order_barrier_p (lhs))
        racc->grp_unscalarizable_region = 1;
+      if (tbaa_hazard)
+       racc->grp_same_access_path = false;
     }
 
   if (lacc && racc
@@ -2396,7 +2405,7 @@ sort_and_splice_var_accesses (tree var)
       bool grp_partial_lhs = access->grp_partial_lhs;
       bool first_scalar = is_gimple_reg_type (access->type);
       bool unscalarizable_region = access->grp_unscalarizable_region;
-      bool grp_same_access_path = true;
+      bool grp_same_access_path = access->grp_same_access_path;
       bool bf_non_full_precision
        = (INTEGRAL_TYPE_P (access->type)
           && TYPE_PRECISION (access->type) != access->size
@@ -2432,7 +2441,8 @@ sort_and_splice_var_accesses (tree var)
          return NULL;
        }
 
-      grp_same_access_path = path_comparable_for_same_access (access->expr);
+      if (grp_same_access_path)
+       grp_same_access_path = path_comparable_for_same_access (access->expr);
 
       j = i + 1;
       while (j < access_count)
@@ -2496,7 +2506,8 @@ sort_and_splice_var_accesses (tree var)
            }
 
          if (grp_same_access_path
-             && !same_access_path_p (access->expr, ac2->expr))
+             && (!ac2->grp_same_access_path
+                 || !same_access_path_p (access->expr, ac2->expr)))
            grp_same_access_path = false;
 
          ac2->group_representative = access;
diff --git a/gcc/tree-ssa-alias-compare.h b/gcc/tree-ssa-alias-compare.h
index 4c4856c9124..fb37337cfaf 100644
--- a/gcc/tree-ssa-alias-compare.h
+++ b/gcc/tree-ssa-alias-compare.h
@@ -40,4 +40,6 @@ class ao_compare : public operand_compare
                    inchash::hash &hstate);
 };
 
+bool types_equal_for_same_type_for_tbaa_p (tree type1, tree type2);
+
 #endif
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index e93d5187d50..9dd1780867d 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-alias-compare.h"
 #include "builtins.h"
 #include "internal-fn.h"
+#include "ipa-utils.h"
 
 /* Broad overview of how alias analysis on gimple works:
 
@@ -4165,7 +4166,7 @@ attr_fnspec::verify ()
 }
 
 /* Return ture if TYPE1 and TYPE2 will always give the same answer
-   when compared wit hother types using same_type_for_tbaa_p.  */
+   when compared with other types using same_type_for_tbaa.  */
 
 static bool
 types_equal_for_same_type_for_tbaa_p (tree type1, tree type2,
@@ -4188,6 +4189,16 @@ types_equal_for_same_type_for_tbaa_p (tree type1, tree 
type2,
     return TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2);
 }
 
+/* Return ture if TYPE1 and TYPE2 will always give the same answer
+   when compared with other types using same_type_for_tbaa.  */
+
+bool
+types_equal_for_same_type_for_tbaa_p (tree type1, tree type2)
+{
+  return types_equal_for_same_type_for_tbaa_p (type1, type2,
+                                              lto_streaming_expected_p ());
+}
+
 /* Compare REF1 and REF2 and return flags specifying their differences.
    If LTO_STREAMING_SAFE is true do not use alias sets and canonical
    types that are going to be recomputed.
-- 
2.48.1

Reply via email to