On Wed, 3 Jun 2020, Richard Biener wrote: > > The following patch avoids keeping the inherited MEM_ATTRs when > set_mem_attributes_minus_bitpos is called with a variable ARRAY_REF. > The inherited ones may not reflect the correct offset. > > We try to preserve the MEM_EXPR from the base object expansion > but we have to make sure to also preserve the corresponding MEM_ALIAS_SET > then since otherwise path-based disambiguation gets confused. > The other choice we'd have would be to drop the MEM_EXPR but keep > the alias-set from the full reference. Or, of course "improve" > MEM_EXPR generation to not "fail" in case the ARRAY_REF offset is > variable (we keep variable ARRAY_REFs in the MEM_EXPR if there's > a COMPONENT_REF ontop of the ref for example). I > understand the "inheriting" be exactly useful in the > case we otherwise give up (I've added an assert that we're not > inheriting from sth when creating a stack slot). > > The expand_assignment fix could be treated separately (in different > code paths we are already preserving MEM_ALIAS_SET this way). > > As said the alternative fix for set_mem_attrs_minus_bitpos would > be to remove all the ARRAY_REF special-casing and do the same > as we do for MEM_REF. > > Bootstrap and regtest running on x86_64-unknown-linux-gnu.
Testing passed but only with the assert removed - at least when expanding SSA partitions we run into this case (but with a NULL previous MEM_EXPR). > Any comments? > > Thanks, > Richard. > > 2020-06-03 Richard Biener <rguent...@suse.de> > > PR middle-end/95493 > * emit-rtl.c (set_mem_attrs_minus_bitpos): Clear > offset-known when the ARRAY_REF is variable. If we end up > inherting the MEM_EXPR from the original MEM_ATTRS then also > inherit the corresponding MEM_ALIAS_SET. Avoid altering > MEM_KEEP_ALIAS_SET_P in that case. > * expr.c (expand_assignment): Preserve MEM_ALIAS_SET when emitting > the store. > > * g++.dg/torture/pr95493.C: New testcase. > --- > gcc/emit-rtl.c | 59 ++++++++++++++---------- > gcc/expr.c | 6 ++- > gcc/testsuite/g++.dg/torture/pr95493.C | 62 ++++++++++++++++++++++++++ > 3 files changed, 103 insertions(+), 24 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/torture/pr95493.C > > diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c > index 2b790636366..09521b6f85e 100644 > --- a/gcc/emit-rtl.c > +++ b/gcc/emit-rtl.c > @@ -1964,8 +1964,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int > objectp, > refattrs = MEM_ATTRS (ref); > if (refattrs) > { > - /* ??? Can this ever happen? Calling this routine on a MEM that > - already carries memory attributes should probably be invalid. */ > + gcc_assert (! TYPE_P (t)); > + /* We are calling this function with attributes set up from expanding > + the base of a memory reference as returned by get_inner_referece. */ > attrs.expr = refattrs->expr; > attrs.offset_known_p = refattrs->offset_known_p; > attrs.offset = refattrs->offset; > @@ -2052,11 +2053,6 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int > objectp, > as = TYPE_ADDR_SPACE (TREE_TYPE (base)); > } > > - /* If this expression uses it's parent's alias set, mark it such > - that we won't change it. */ > - if (component_uses_parent_alias_set_from (t) != NULL_TREE) > - MEM_KEEP_ALIAS_SET_P (ref) = 1; > - > /* If this is a decl, set the attributes of the MEM from it. */ > if (DECL_P (t)) > { > @@ -2114,6 +2110,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int > objectp, > } > while (TREE_CODE (t2) == ARRAY_REF); > > + attrs.offset_known_p = false; > + attrs.offset = 0; > + apply_bitpos = 0; > if (DECL_P (t2) > || (TREE_CODE (t2) == COMPONENT_REF > /* For trailing arrays t2 doesn't have a size that > @@ -2141,24 +2140,38 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int > objectp, > apply_bitpos = bitpos; > } > > - /* If this is a reference based on a partitioned decl replace the > - base with a MEM_REF of the pointer representative we created > - during stack slot partitioning. */ > - if (attrs.expr > - && VAR_P (base) > - && ! is_global_var (base) > - && cfun->gimple_df->decls_to_pointers != NULL) > + /* If we chose to keep the MEM_EXPR from the inner reference > + expansion make sure to also keep the corresponding alias-set > + since otherwise path-based disambiguation is confused. */ > + if (refattrs > + && attrs.expr == refattrs->expr) > + attrs.alias = refattrs->alias; > + else if (attrs.expr) > { > - tree *namep = cfun->gimple_df->decls_to_pointers->get (base); > - if (namep) > + /* If this expression uses it's parent's alias set, mark it such > + that we won't change it. */ > + if (component_uses_parent_alias_set_from (t) != NULL_TREE) > + MEM_KEEP_ALIAS_SET_P (ref) = 1; > + > + /* If this is a reference based on a partitioned decl replace the > + base with a MEM_REF of the pointer representative we created > + during stack slot partitioning. */ > + if (attrs.expr > + && VAR_P (base) > + && ! is_global_var (base) > + && cfun->gimple_df->decls_to_pointers != NULL) > { > - attrs.expr = unshare_expr (attrs.expr); > - tree *orig_base = &attrs.expr; > - while (handled_component_p (*orig_base)) > - orig_base = &TREE_OPERAND (*orig_base, 0); > - tree aptrt = reference_alias_ptr_type (*orig_base); > - *orig_base = build2 (MEM_REF, TREE_TYPE (*orig_base), *namep, > - build_int_cst (aptrt, 0)); > + tree *namep = cfun->gimple_df->decls_to_pointers->get (base); > + if (namep) > + { > + attrs.expr = unshare_expr (attrs.expr); > + tree *orig_base = &attrs.expr; > + while (handled_component_p (*orig_base)) > + orig_base = &TREE_OPERAND (*orig_base, 0); > + tree aptrt = reference_alias_ptr_type (*orig_base); > + *orig_base = build2 (MEM_REF, TREE_TYPE (*orig_base), *namep, > + build_int_cst (aptrt, 0)); > + } > } > } > > diff --git a/gcc/expr.c b/gcc/expr.c > index 6b75028e7f1..2357178fce4 100644 > --- a/gcc/expr.c > +++ b/gcc/expr.c > @@ -5354,6 +5354,7 @@ expand_assignment (tree to, tree from, bool nontemporal) > } > else > { > + alias_set_type alias_set; > if (MEM_P (to_rtx)) > { > /* If the field is at offset zero, we could have been given the > @@ -5362,7 +5363,10 @@ expand_assignment (tree to, tree from, bool > nontemporal) > set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos); > if (volatilep) > MEM_VOLATILE_P (to_rtx) = 1; > + alias_set = MEM_ALIAS_SET (to_rtx); > } > + else > + alias_set = get_alias_set (to); > > gcc_checking_assert (known_ge (bitpos, 0)); > if (optimize_bitfield_assignment_op (bitsize, bitpos, > @@ -5373,7 +5377,7 @@ expand_assignment (tree to, tree from, bool nontemporal) > else > result = store_field (to_rtx, bitsize, bitpos, > bitregion_start, bitregion_end, > - mode1, from, get_alias_set (to), > + mode1, from, alias_set, > nontemporal, reversep); > } > > diff --git a/gcc/testsuite/g++.dg/torture/pr95493.C > b/gcc/testsuite/g++.dg/torture/pr95493.C > new file mode 100644 > index 00000000000..5e05056854d > --- /dev/null > +++ b/gcc/testsuite/g++.dg/torture/pr95493.C > @@ -0,0 +1,62 @@ > +// { dg-do run } > +// { dg-additional-options "-std=c++17" } > + > +struct verify > +{ > + const bool m_failed = false; > + > + [[gnu::noinline]] void print_hex(const void* x, int n) const > + { > + const auto* bytes = static_cast<const unsigned char*>(x); > + for (int i = 0; i < n; ++i) > + __builtin_printf((i && i % 4 == 0) ? "'%02x" : "%02x", bytes[i]); > + __builtin_printf("\n"); > + } > + > + template <typename... Ts> > + verify(bool ok, const Ts&... extra_info) : m_failed(!ok) > + { > + if (m_failed) > + (print_hex(&extra_info, sizeof(extra_info)), ...); > + } > + > + ~verify() > + { > + if (m_failed) > + __builtin_abort(); > + } > +}; > + > +using K [[gnu::vector_size(16)]] = int; > + > +int > +main() > +{ > + int count = 1; > + asm("" : "+m"(count)); > + verify(count == 1, 0, "", 0); > + > + { > + struct SW > + { > + K d; > + }; > + struct > + { > + SW d; > + } xx; > + SW& x = xx.d; > + x = SW(); // [0, 0, 0, 0] > + for (int i = 3; i >= 2; --i) > + { > + x.d[i] = -1; // [0, 0, 0, -1] ... > + int a = [](K y) { > + for (int j = 0; j < 4; ++j) > + if (y[j] != 0) > + return j; > + return -1; > + }(x.d); > + verify(a == i, 0, 0, 0, 0, i, x); > + } > + } > +} > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)