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 <[email protected]>
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 <[email protected]>
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