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.
--------------------------------------------------------------------------
>> [...]
>> 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.
> [...]
[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