On 16/09/2026 14:44, Richard Sandiford wrote:
Richard Biener <[email protected]> writes:
On Thu, Sep 3, 2026 at 3:48 PM Andrew Stubbs <[email protected]> wrote:
This patch makes the middle-end adjustments needed to allow a MEM to take a
vector of addresses in order to read/write a non-contiguous vector of data.
Mostly the changes don't have to do anything besides letting the
vectors pass.
There's a new MEM flag: MEM_INDEPENDENT_P that describes the store semantics
of vectors with conflicting addresses. Nothing uses it, yet, but it will
allow future optimizations that rely on left-to-right semantics to do
the right
thing. GCN does not have such a guarantee, so it sets the flag.
These changes, alone, are not enough to actually allow such MEMs, since it's
unlikely that any back-end reports the vector modes "legitimate", so there
should be no change of behaviour on any existing target (unconfirmed).
I've modified the type of only the TARGET_ADDR_SPACE_VALID_POINTER_MODE hook,
which is currently not being used by any target (amdgcn will use it in the
following patch), and left the TARGET_VALID_POINTER_MODE alone so as not to
have to touch all the other back-ends. If another back-end wants to use
vectors of addresses then I propose that either TARGET_VALID_POINTER_MODE can
be fixed up at that time, or that backend simply switch to using
TARGET_ADDR_SPACE_VALID_POINTER_MODE.
I have not made any changes to LRA code. I believe this is not necessary as
long as the target uses "define_special_memory_constraint". I failed to
figure out how to make the regular memory constraints work, and as it's not
necessary for my use case I'm loath to invest any more time into that.
Hopefully the documentation patches should describe the intended semantics.
I've tried to keep it very simple.
There's one "TODO" in the code; I'm intentionally applying the principle of
"don't add it if you don't need it" here (not least because I don't know how
to test it). There's an assert to make sure it never bites anyone silently.
gcc/ChangeLog:
* doc/rtl.texi: Document MEM_INDEPENDENT_P.
Document new MEM semantics.
* doc/tm.texi: Likewise.
* emit-rtl.cc (gen_int_mode): Extend to DTRT for vector modes.
(adjust_address_1): Permit vectors of addresses.
* explow.cc (convert_memory_address_addr_space_1): Permit vectors of
addresses, for no-op conversions only.
* recog.cc (address_operand): Permit vectors of addresses.
* rtl.h (MEM_INDEPENDENT_P): New macro.
(get_address_mode): Change return type to machine_mode.
* rtlanal.cc (get_address_mode): Likewise.
* simplify-rtx.cc (simplify_context::simplify_subreg): Handle vectors
of addresses.
* target.def (pointer_mode): Document vectors of addresses.
(address_mode): Likewise.
(valid_pointer_mode): Change scalar_int_mode to machine_mode.
* targhooks.cc (default_addr_space_valid_pointer_mode): Change
scalar_int_mode to machine_mode.
* targhooks.h (default_addr_space_valid_pointer_mode): Likewise.
---
gcc/doc/rtl.texi | 23 +++++++++++++++++++++++
gcc/doc/tm.texi | 13 ++++++++++++-
gcc/emit-rtl.cc | 30 ++++++++++++++++++++++++------
gcc/explow.cc | 12 ++++++++++--
gcc/recog.cc | 4 +++-
gcc/rtl.h | 7 ++++++-
gcc/rtlanal.cc | 4 ++--
gcc/simplify-rtx.cc | 5 ++++-
gcc/target.def | 13 ++++++++++---
gcc/targhooks.cc | 4 ++--
gcc/targhooks.h | 3 +--
11 files changed, 97 insertions(+), 21 deletions(-)
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index f606b97389f..a2af57233f4 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -703,6 +703,21 @@ application, this memory will never be
subsequently modified.
Stored in the @code{unchanging} field and printed as @samp{/u}.
+@findex MEM_INDEPENDENT_P
+@cindex @code{mem} and @samp{/i}
+@item MEM_INDEPENDENT_P (@var{x})
+Nonzero in a @code{mem}, if the elements in a vector are written to
memory as
+independent operations, not necessarily completing in left-to-right
order. In
+such a store, the result of two vector elements writing to the same
address, or
+overlapping addresses, is undefined. Otherwise, when the flag is zero, the
+compiler can assume that the vector elements are known to write
predictably and
+in order.
+
+This applies primarily when the write address is a vector of addresses, e.g.
+@samp{(mem:V4SI/i (reg:V4DI r123))}.
I'd fold this into the above and "if the elements in a vector are
written to memory
specified as a vector of addresses as independent operations", because
otherwise
it doesn't make sense(?)
Yeah. And IMO the flag should be about the addresses rather than
the operation. I.e. something like:
--------------------------------------------------------------------------
Nonzero in a @code{mem}, if the memory address is a vector and if that
vector must specify independent, non-overlapping memory locations.
If the vector fails to do this, the behavior is undefined.
When writing to a @code{mem} that has a vector address, an instruction
must write to the elements as if in left-to-right order.
@code{MEM_INDEPENDENT_P} indicates that left-to-right order is
equivalent to any other order and so an instruction can write to each
element independently.
--------------------------------------------------------------------------
I'm struggling to understand what this implies for code transformations,
etc., and what happens when the flag is unset. How about this version?
-------------------------------------------------------------------------
In a @code{mem}, nonzero if the memory address is a vector and if that
vector must specify independent, non-overlapping memory locations, to be
used safely in a store. If the vector fails to do this, the behavior is
undefined.
In general, when writing to a @code{mem} that has a vector address, an
instruction must write to the elements as if in left-to-right order.
@code{MEM_INDEPENDENT_P} indicates that left-to-right order is
equivalent to any other order and so an instruction can safely write to
each element independently.
--------------------------------------------------------------------------
[...]
diff --git a/gcc/explow.cc b/gcc/explow.cc
index ec2bc9bc9b6..9c7c834aaab 100644
--- a/gcc/explow.cc
+++ b/gcc/explow.cc
@@ -298,8 +298,13 @@ convert_memory_address_addr_space_1
(scalar_int_mode to_mode ATTRIBUTE_UNUSED,
bool in_const ATTRIBUTE_UNUSED,
bool no_emit ATTRIBUTE_UNUSED)
{
+ machine_mode xmode = GET_MODE (x);
+ bool vecaddr_p = VECTOR_MODE_P (GET_MODE (x));
+ if (vecaddr_p)
+ xmode = GET_MODE_INNER (xmode);
+
This is the only bit I'm not too sure about. Should callers be passing
the correct vector mode instead?
There again, the gen_int_mode overloading seems fine, so I suppose it's
inconsistent not to take the same approach here. Especially since
requiring each caller to deal with the vector case is more likely
to lead to a game of whack-a-mole than doing it once in the callee.
[...]
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 77a71e5bbec..e523517884d 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2653,6 +2653,11 @@ do { \
#define MEM_READONLY_P(RTX) \
(RTL_FLAG_CHECK1 ("MEM_READONLY_P", (RTX), MEM)->unchanging)
+/* 1 if RTX is a mem whose vector elements are written to memory
+ independently, not necessarily left-to-right. */
I think this should be updated along the lines of the above.
How about this?
---------------------------------------------------------------------
/* 1 is RTX is a mem whose address vector elements all point to
independent memory locations, without overlapping each other. */
---------------------------------------------------------------------
[...]
[various comments that I agree with snipped here and above]
Otherwise I think this looks reasonable. But please give Richard/Jeff
the chance to
comment.
LGTM too apart from the above.
Thanks,
Richard
Thanks for the review.
Andrew