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

Reply via email to