[0/3] Address vectors (mem:<vectype> (reg:<vectype>))

Message ID 20260708144633.1530935-1-ams@baylibre.com
Headers
Series Address vectors (mem:<vectype> (reg:<vectype>)) |

Message

Andrew Stubbs July 8, 2026, 2:46 p.m. UTC
  Hi all,

This patch series implements the "MEMs with address vectors" feature
that I want to use in AMD GCN, and have previously discussed on gcc@.
The motivation is to simplify a new back-end optimization pass I'm
working on and plan to post in the coming weeks.

The first patch, in this series, is the middle-end enablement and
documentation changes.

The second patch converts the amdgcn back-end to use the new scheme,
without adding any real new features. It depends on the
INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
correctly.

The third and final patch demonstrates how I can use the new MEM to
extend my machine description without writing whole new insns for the
vector modes, just for them to evaluate to the same assembler code in
the end.

I have not yet finished testing the patches, so these might not be quite
the final form, but I'm not expecting big changes to the middle-end
portion.  (I can self-approve the amdgcn parts, once the other is
committed, but comments are welcome.)

OK for mainline? (Pending test results.)

Thanks

Andrew Stubbs (3):
  rtl: Allow "(mem:<vecmode> (reg:<vecmode>))"
  amdgcn: Implement "(mem (reg:<vecmode>))"
  amdgcn: Add vector atomics

 gcc/config/gcn/constraints.md |  49 ++-
 gcc/config/gcn/gcn-protos.h   |  10 +-
 gcc/config/gcn/gcn-valu.md    | 745 ++++++++++++----------------------
 gcc/config/gcn/gcn.cc         | 529 +++++++++++++-----------
 gcc/config/gcn/gcn.h          |   1 +
 gcc/config/gcn/gcn.md         | 123 +++---
 gcc/doc/rtl.texi              |   8 +
 gcc/doc/tm.texi               |  13 +-
 gcc/emit-rtl.cc               |  30 +-
 gcc/explow.cc                 |  12 +-
 gcc/recog.cc                  |   4 +-
 gcc/rtl.h                     |   2 +-
 gcc/rtlanal.cc                |   4 +-
 gcc/simplify-rtx.cc           |   5 +-
 gcc/target.def                |  13 +-
 gcc/targhooks.cc              |   4 +-
 gcc/targhooks.h               |   3 +-
 17 files changed, 768 insertions(+), 787 deletions(-)
  

Comments

Andrew Stubbs July 10, 2026, 10:22 a.m. UTC | #1
On 08/07/2026 15:46, Andrew Stubbs wrote:
> Hi all,
> 
> This patch series implements the "MEMs with address vectors" feature
> that I want to use in AMD GCN, and have previously discussed on gcc@.
> The motivation is to simplify a new back-end optimization pass I'm
> working on and plan to post in the coming weeks.
> 
> The first patch, in this series, is the middle-end enablement and
> documentation changes.
> 
> The second patch converts the amdgcn back-end to use the new scheme,
> without adding any real new features. It depends on the
> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> correctly.
> 
> The third and final patch demonstrates how I can use the new MEM to
> extend my machine description without writing whole new insns for the
> vector modes, just for them to evaluate to the same assembler code in
> the end.
> 
> I have not yet finished testing the patches, so these might not be quite
> the final form, but I'm not expecting big changes to the middle-end
> portion.  (I can self-approve the amdgcn parts, once the other is
> committed, but comments are welcome.)
> 
> OK for mainline? (Pending test results.)

The test results have come back clean.


> Thanks
> 
> Andrew Stubbs (3):
>    rtl: Allow "(mem:<vecmode> (reg:<vecmode>))"
>    amdgcn: Implement "(mem (reg:<vecmode>))"
>    amdgcn: Add vector atomics
> 
>   gcc/config/gcn/constraints.md |  49 ++-
>   gcc/config/gcn/gcn-protos.h   |  10 +-
>   gcc/config/gcn/gcn-valu.md    | 745 ++++++++++++----------------------
>   gcc/config/gcn/gcn.cc         | 529 +++++++++++++-----------
>   gcc/config/gcn/gcn.h          |   1 +
>   gcc/config/gcn/gcn.md         | 123 +++---
>   gcc/doc/rtl.texi              |   8 +
>   gcc/doc/tm.texi               |  13 +-
>   gcc/emit-rtl.cc               |  30 +-
>   gcc/explow.cc                 |  12 +-
>   gcc/recog.cc                  |   4 +-
>   gcc/rtl.h                     |   2 +-
>   gcc/rtlanal.cc                |   4 +-
>   gcc/simplify-rtx.cc           |   5 +-
>   gcc/target.def                |  13 +-
>   gcc/targhooks.cc              |   4 +-
>   gcc/targhooks.h               |   3 +-
>   17 files changed, 768 insertions(+), 787 deletions(-)
>
  
Andrew Stubbs July 15, 2026, 11:18 a.m. UTC | #2
Ping.

On 08/07/2026 15:46, Andrew Stubbs wrote:
> Hi all,
> 
> This patch series implements the "MEMs with address vectors" feature
> that I want to use in AMD GCN, and have previously discussed on gcc@.
> The motivation is to simplify a new back-end optimization pass I'm
> working on and plan to post in the coming weeks.
> 
> The first patch, in this series, is the middle-end enablement and
> documentation changes.
> 
> The second patch converts the amdgcn back-end to use the new scheme,
> without adding any real new features. It depends on the
> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> correctly.
> 
> The third and final patch demonstrates how I can use the new MEM to
> extend my machine description without writing whole new insns for the
> vector modes, just for them to evaluate to the same assembler code in
> the end.
> 
> I have not yet finished testing the patches, so these might not be quite
> the final form, but I'm not expecting big changes to the middle-end
> portion.  (I can self-approve the amdgcn parts, once the other is
> committed, but comments are welcome.)
> 
> OK for mainline? (Pending test results.)
> 
> Thanks
> 
> Andrew Stubbs (3):
>    rtl: Allow "(mem:<vecmode> (reg:<vecmode>))"
>    amdgcn: Implement "(mem (reg:<vecmode>))"
>    amdgcn: Add vector atomics
> 
>   gcc/config/gcn/constraints.md |  49 ++-
>   gcc/config/gcn/gcn-protos.h   |  10 +-
>   gcc/config/gcn/gcn-valu.md    | 745 ++++++++++++----------------------
>   gcc/config/gcn/gcn.cc         | 529 +++++++++++++-----------
>   gcc/config/gcn/gcn.h          |   1 +
>   gcc/config/gcn/gcn.md         | 123 +++---
>   gcc/doc/rtl.texi              |   8 +
>   gcc/doc/tm.texi               |  13 +-
>   gcc/emit-rtl.cc               |  30 +-
>   gcc/explow.cc                 |  12 +-
>   gcc/recog.cc                  |   4 +-
>   gcc/rtl.h                     |   2 +-
>   gcc/rtlanal.cc                |   4 +-
>   gcc/simplify-rtx.cc           |   5 +-
>   gcc/target.def                |  13 +-
>   gcc/targhooks.cc              |   4 +-
>   gcc/targhooks.h               |   3 +-
>   17 files changed, 768 insertions(+), 787 deletions(-)
>
  
Richard Biener July 17, 2026, 8:13 a.m. UTC | #3
On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>
> Hi all,
>
> This patch series implements the "MEMs with address vectors" feature
> that I want to use in AMD GCN, and have previously discussed on gcc@.
> The motivation is to simplify a new back-end optimization pass I'm
> working on and plan to post in the coming weeks.
>
> The first patch, in this series, is the middle-end enablement and
> documentation changes.
>
> The second patch converts the amdgcn back-end to use the new scheme,
> without adding any real new features. It depends on the
> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> correctly.
>
> The third and final patch demonstrates how I can use the new MEM to
> extend my machine description without writing whole new insns for the
> vector modes, just for them to evaluate to the same assembler code in
> the end.
>
> I have not yet finished testing the patches, so these might not be quite
> the final form, but I'm not expecting big changes to the middle-end
> portion.  (I can self-approve the amdgcn parts, once the other is
> committed, but comments are welcome.)
>
> OK for mainline? (Pending test results.)

I think this exposes what GCN does in a natural way.  I'm not sure
the advantage (exposing former gather/scatter as move) is not
also its disadvantage (moves are special!), and I somewhat question
the benefit over using some UNSPEC for this.  For example I would
assume that you side-step RTL alias/dependence analysis, meaning these
are barriers for optimization and scheduling?

The proposed semantics (overlap has undefined behavior) does not
match up with usual vector ISA scatter semantics (left-to-right), so
the representation isn't universally useable (if we solve the masking
issue).

That said, my overall hunch is that we're extending general RTL
semantics in a somewhat ad-hoc (and incomplete?) way.  Not
that I have a better idea here.

Thanks,
Richard.

>
> Thanks
>
> Andrew Stubbs (3):
>   rtl: Allow "(mem:<vecmode> (reg:<vecmode>))"
>   amdgcn: Implement "(mem (reg:<vecmode>))"
>   amdgcn: Add vector atomics
>
>  gcc/config/gcn/constraints.md |  49 ++-
>  gcc/config/gcn/gcn-protos.h   |  10 +-
>  gcc/config/gcn/gcn-valu.md    | 745 ++++++++++++----------------------
>  gcc/config/gcn/gcn.cc         | 529 +++++++++++++-----------
>  gcc/config/gcn/gcn.h          |   1 +
>  gcc/config/gcn/gcn.md         | 123 +++---
>  gcc/doc/rtl.texi              |   8 +
>  gcc/doc/tm.texi               |  13 +-
>  gcc/emit-rtl.cc               |  30 +-
>  gcc/explow.cc                 |  12 +-
>  gcc/recog.cc                  |   4 +-
>  gcc/rtl.h                     |   2 +-
>  gcc/rtlanal.cc                |   4 +-
>  gcc/simplify-rtx.cc           |   5 +-
>  gcc/target.def                |  13 +-
>  gcc/targhooks.cc              |   4 +-
>  gcc/targhooks.h               |   3 +-
>  17 files changed, 768 insertions(+), 787 deletions(-)
>
> --
> 2.54.0
>
  
Andrew Stubbs July 17, 2026, 10:13 a.m. UTC | #4
On 17/07/2026 09:13, Richard Biener wrote:
> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>
>> Hi all,
>>
>> This patch series implements the "MEMs with address vectors" feature
>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>> The motivation is to simplify a new back-end optimization pass I'm
>> working on and plan to post in the coming weeks.
>>
>> The first patch, in this series, is the middle-end enablement and
>> documentation changes.
>>
>> The second patch converts the amdgcn back-end to use the new scheme,
>> without adding any real new features. It depends on the
>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>> correctly.
>>
>> The third and final patch demonstrates how I can use the new MEM to
>> extend my machine description without writing whole new insns for the
>> vector modes, just for them to evaluate to the same assembler code in
>> the end.
>>
>> I have not yet finished testing the patches, so these might not be quite
>> the final form, but I'm not expecting big changes to the middle-end
>> portion.  (I can self-approve the amdgcn parts, once the other is
>> committed, but comments are welcome.)
>>
>> OK for mainline? (Pending test results.)
> 
> I think this exposes what GCN does in a natural way.  I'm not sure
> the advantage (exposing former gather/scatter as move) is not
> also its disadvantage (moves are special!), and I somewhat question
> the benefit over using some UNSPEC for this.  For example I would
> assume that you side-step RTL alias/dependence analysis, meaning these
> are barriers for optimization and scheduling?

This is intended to be an enabling technology for my real project, in 
which I want to transform scalar operations into vector operations in 
the backend, and the special casing for memory accesses was getting out 
of hand. By expressing (unmasked) vector operations identically to the 
scalar equivalent I can simplify things greatly, and the other compiler 
passes can do (some of) their special MEM handling as they normally would.

> The proposed semantics (overlap has undefined behavior) does not
> match up with usual vector ISA scatter semantics (left-to-right), so
> the representation isn't universally useable (if we solve the masking
> issue).

Unfortunately, this is the semantics of the hardware; specifying any 
other assumptions in the compiler might mean that it wouldn't be safe to 
use it for GCN. (It might be the case that the hardware is deterministic 
in practice, but the details are not documented in the ISA manuals; it 
just says that it will "write-combine data across the work-items".)

We can say that "the compiler assumes the UB doesn't happen", and trust 
that the algorithm is constructed such that this is true.  (It certainly 
should be the case for the code I'm generating.)  I'm not familiar with 
the parts of the compiler where these assumptions are made.   I don't 
believe I have specifically disabled any such analysis, but if something 
somewhere has a "return false" rather than a fatal assertion then I 
suppose I wouldn't have seen it.

> That said, my overall hunch is that we're extending general RTL
> semantics in a somewhat ad-hoc (and incomplete?) way.  Not
> that I have a better idea here.

I prefer "incremental" to "incomplete", and as ad-hoc designs go it 
feels fairly natural, given what I want to represent. If time and money 
were no issue I could certainly spend a lot longer designing and 
implementing this feature, but it's a sub-project of a task order that 
comes with a budget and a deadline, so I've implemented as much of it as 
is necessary and I can test without constructing testcases for 
hypothetical use-cases.


> Thanks,
> Richard.
> 
>>
>> Thanks
>>
>> Andrew Stubbs (3):
>>    rtl: Allow "(mem:<vecmode> (reg:<vecmode>))"
>>    amdgcn: Implement "(mem (reg:<vecmode>))"
>>    amdgcn: Add vector atomics
>>
>>   gcc/config/gcn/constraints.md |  49 ++-
>>   gcc/config/gcn/gcn-protos.h   |  10 +-
>>   gcc/config/gcn/gcn-valu.md    | 745 ++++++++++++----------------------
>>   gcc/config/gcn/gcn.cc         | 529 +++++++++++++-----------
>>   gcc/config/gcn/gcn.h          |   1 +
>>   gcc/config/gcn/gcn.md         | 123 +++---
>>   gcc/doc/rtl.texi              |   8 +
>>   gcc/doc/tm.texi               |  13 +-
>>   gcc/emit-rtl.cc               |  30 +-
>>   gcc/explow.cc                 |  12 +-
>>   gcc/recog.cc                  |   4 +-
>>   gcc/rtl.h                     |   2 +-
>>   gcc/rtlanal.cc                |   4 +-
>>   gcc/simplify-rtx.cc           |   5 +-
>>   gcc/target.def                |  13 +-
>>   gcc/targhooks.cc              |   4 +-
>>   gcc/targhooks.h               |   3 +-
>>   17 files changed, 768 insertions(+), 787 deletions(-)
>>
>> --
>> 2.54.0
>>
  
Richard Biener July 17, 2026, 10:48 a.m. UTC | #5
On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
>
> On 17/07/2026 09:13, Richard Biener wrote:
> > On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
> >>
> >> Hi all,
> >>
> >> This patch series implements the "MEMs with address vectors" feature
> >> that I want to use in AMD GCN, and have previously discussed on gcc@.
> >> The motivation is to simplify a new back-end optimization pass I'm
> >> working on and plan to post in the coming weeks.
> >>
> >> The first patch, in this series, is the middle-end enablement and
> >> documentation changes.
> >>
> >> The second patch converts the amdgcn back-end to use the new scheme,
> >> without adding any real new features. It depends on the
> >> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> >> correctly.
> >>
> >> The third and final patch demonstrates how I can use the new MEM to
> >> extend my machine description without writing whole new insns for the
> >> vector modes, just for them to evaluate to the same assembler code in
> >> the end.
> >>
> >> I have not yet finished testing the patches, so these might not be quite
> >> the final form, but I'm not expecting big changes to the middle-end
> >> portion.  (I can self-approve the amdgcn parts, once the other is
> >> committed, but comments are welcome.)
> >>
> >> OK for mainline? (Pending test results.)
> >
> > I think this exposes what GCN does in a natural way.  I'm not sure
> > the advantage (exposing former gather/scatter as move) is not
> > also its disadvantage (moves are special!), and I somewhat question
> > the benefit over using some UNSPEC for this.  For example I would
> > assume that you side-step RTL alias/dependence analysis, meaning these
> > are barriers for optimization and scheduling?
>
> This is intended to be an enabling technology for my real project, in
> which I want to transform scalar operations into vector operations in
> the backend, and the special casing for memory accesses was getting out
> of hand. By expressing (unmasked) vector operations identically to the
> scalar equivalent I can simplify things greatly, and the other compiler
> passes can do (some of) their special MEM handling as they normally would.

I see.  I guess you ruled out a

 ([parallel
   (set (mem:<scalar> ...) (...))
   (set (mem:<scalar> ...) (...))])

etc. with vector extracts for the address.  At least for "transform scalar ops
to vectors" the actual representation of the MEM could be a black box
as long as you
have addresses in vectors (which is possible already).

> > The proposed semantics (overlap has undefined behavior) does not
> > match up with usual vector ISA scatter semantics (left-to-right), so
> > the representation isn't universally useable (if we solve the masking
> > issue).
>
> Unfortunately, this is the semantics of the hardware; specifying any
> other assumptions in the compiler might mean that it wouldn't be safe to
> use it for GCN. (It might be the case that the hardware is deterministic
> in practice, but the details are not documented in the ISA manuals; it
> just says that it will "write-combine data across the work-items".)

Yeah, I think your proposed semantic is fine, it's just unfortunate we
cannot make use of it elsewhere.

> We can say that "the compiler assumes the UB doesn't happen", and trust
> that the algorithm is constructed such that this is true.  (It certainly
> should be the case for the code I'm generating.)  I'm not familiar with
> the parts of the compiler where these assumptions are made.   I don't
> believe I have specifically disabled any such analysis, but if something
> somewhere has a "return false" rather than a fatal assertion then I
> suppose I wouldn't have seen it.
>
> > That said, my overall hunch is that we're extending general RTL
> > semantics in a somewhat ad-hoc (and incomplete?) way.  Not
> > that I have a better idea here.
>
> I prefer "incremental" to "incomplete", and as ad-hoc designs go it
> feels fairly natural, given what I want to represent. If time and money
> were no issue I could certainly spend a lot longer designing and
> implementing this feature, but it's a sub-project of a task order that
> comes with a budget and a deadline, so I've implemented as much of it as
> is necessary and I can test without constructing testcases for
> hypothetical use-cases.

Sure.

Richard.

>
>
> > Thanks,
> > Richard.
> >
> >>
> >> Thanks
> >>
> >> Andrew Stubbs (3):
> >>    rtl: Allow "(mem:<vecmode> (reg:<vecmode>))"
> >>    amdgcn: Implement "(mem (reg:<vecmode>))"
> >>    amdgcn: Add vector atomics
> >>
> >>   gcc/config/gcn/constraints.md |  49 ++-
> >>   gcc/config/gcn/gcn-protos.h   |  10 +-
> >>   gcc/config/gcn/gcn-valu.md    | 745 ++++++++++++----------------------
> >>   gcc/config/gcn/gcn.cc         | 529 +++++++++++++-----------
> >>   gcc/config/gcn/gcn.h          |   1 +
> >>   gcc/config/gcn/gcn.md         | 123 +++---
> >>   gcc/doc/rtl.texi              |   8 +
> >>   gcc/doc/tm.texi               |  13 +-
> >>   gcc/emit-rtl.cc               |  30 +-
> >>   gcc/explow.cc                 |  12 +-
> >>   gcc/recog.cc                  |   4 +-
> >>   gcc/rtl.h                     |   2 +-
> >>   gcc/rtlanal.cc                |   4 +-
> >>   gcc/simplify-rtx.cc           |   5 +-
> >>   gcc/target.def                |  13 +-
> >>   gcc/targhooks.cc              |   4 +-
> >>   gcc/targhooks.h               |   3 +-
> >>   17 files changed, 768 insertions(+), 787 deletions(-)
> >>
> >> --
> >> 2.54.0
> >>
>
  
Andrew Stubbs July 17, 2026, 11:37 a.m. UTC | #6
On 17/07/2026 11:48, Richard Biener wrote:
> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>
>> On 17/07/2026 09:13, Richard Biener wrote:
>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>
>>>> Hi all,
>>>>
>>>> This patch series implements the "MEMs with address vectors" feature
>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>>>> The motivation is to simplify a new back-end optimization pass I'm
>>>> working on and plan to post in the coming weeks.
>>>>
>>>> The first patch, in this series, is the middle-end enablement and
>>>> documentation changes.
>>>>
>>>> The second patch converts the amdgcn back-end to use the new scheme,
>>>> without adding any real new features. It depends on the
>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>>>> correctly.
>>>>
>>>> The third and final patch demonstrates how I can use the new MEM to
>>>> extend my machine description without writing whole new insns for the
>>>> vector modes, just for them to evaluate to the same assembler code in
>>>> the end.
>>>>
>>>> I have not yet finished testing the patches, so these might not be quite
>>>> the final form, but I'm not expecting big changes to the middle-end
>>>> portion.  (I can self-approve the amdgcn parts, once the other is
>>>> committed, but comments are welcome.)
>>>>
>>>> OK for mainline? (Pending test results.)
>>>
>>> I think this exposes what GCN does in a natural way.  I'm not sure
>>> the advantage (exposing former gather/scatter as move) is not
>>> also its disadvantage (moves are special!), and I somewhat question
>>> the benefit over using some UNSPEC for this.  For example I would
>>> assume that you side-step RTL alias/dependence analysis, meaning these
>>> are barriers for optimization and scheduling?
>>
>> This is intended to be an enabling technology for my real project, in
>> which I want to transform scalar operations into vector operations in
>> the backend, and the special casing for memory accesses was getting out
>> of hand. By expressing (unmasked) vector operations identically to the
>> scalar equivalent I can simplify things greatly, and the other compiler
>> passes can do (some of) their special MEM handling as they normally would.
> 
> I see.  I guess you ruled out a
> 
>   ([parallel
>     (set (mem:<scalar> ...) (...))
>     (set (mem:<scalar> ...) (...))])

I would need this insn for V2, V4, V8, V16, V32, and V64. And probably 
SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).

It would be very verbose, and what would the constraints even look like?

Not to mention it's right back to the special-case conversions I was 
trying to avoid in the first place.

> etc. with vector extracts for the address.  At least for "transform scalar ops
> to vectors" the actual representation of the MEM could be a black box
> as long as you
> have addresses in vectors (which is possible already).

I'm not really sure what this means. Can you give an example, please?

Andrew
  
Robin Dapp July 17, 2026, 4:07 p.m. UTC | #7
> This is intended to be an enabling technology for my real project, in which I 
> want to transform scalar operations into vector operations in the backend, 
> and the special casing for memory accesses was getting out of hand. By 
> expressing (unmasked) vector operations identically to the scalar equivalent 
> I can simplify things greatly, and the other compiler passes can do (some of) 
> their special MEM handling as they normally would.

Could you sketch what you want to achieve?  I'm just trying to get an idea of 
what the "option space" is.  Like, could you do your transform at gimple level?
If that were possible, things could maybe just stay opaque at RTL level?

Maybe related: I have been starting with "native" vector masking for RTL via a 
"vec_predicate" and I wonder if your requirements could influence the design of 
predicated movs, loads, and stores.  But that's a separate topic.
  
Andrew Stubbs July 17, 2026, 5:09 p.m. UTC | #8
On 17/07/2026 17:07, Robin Dapp wrote:
>> This is intended to be an enabling technology for my real project, in which I
>> want to transform scalar operations into vector operations in the backend,
>> and the special casing for memory accesses was getting out of hand. By
>> expressing (unmasked) vector operations identically to the scalar equivalent
>> I can simplify things greatly, and the other compiler passes can do (some of)
>> their special MEM handling as they normally would.
> 
> Could you sketch what you want to achieve?  I'm just trying to get an idea of
> what the "option space" is.  Like, could you do your transform at gimple level?
> If that were possible, things could maybe just stay opaque at RTL level?

It's essentially vectorization in the backend, for code with specific 
attributes. I definitely do not want to do it at gimple level because 
that would have the exact same problems that the existing vectorizer has.

For example, in most cases I can simply transform

   (set (reg:SI) (plus:SI (reg:SI) (const_int)))

into

   (set (reg:V64SI) (plus:V64SI (reg:V64SI) (const_vector:V64SI)))

which makes total sense and Just Works on AMD GCN for almost all 
instructions.

So, I want to do the same thing for a MEM:

   (set (reg:SI) (mem:SI (reg:DI)))

becomes

   (set (reg:V64SI) (mem:V64SI (reg:V64DI)))

except that the MEM is not valid because the address "isn't valid". 
There's no reason it shouldn't work on the architecture -- the two RTL 
patterns here will emit the *exact same* assembler code (obviously I set 
the execution mask differently) -- it's just an old assumption built 
into the compiler.

I considered just leaving the scalar representation for everything, but 
the register allocator needs to know when to allocate vector registers, 
and when not (for example, a vec_duplicate looks like a move, except 
that the source and destination registers are different classes), and 
stack spills still need the extra space, so that would have required a 
lot of different cludges.

> Maybe related: I have been starting with "native" vector masking for RTL via a
> "vec_predicate" and I wonder if your requirements could influence the design of
> predicated movs, loads, and stores.  But that's a separate topic.
> 

It might be that a "vec_predicate" would be better than "vec_merge"? But 
if the register allocator can pull the MEM out of context then we didn't 
gain anything for the specific issues I discussed in the gcc@ thread.


Andrew
  
Richard Biener July 17, 2026, 5:19 p.m. UTC | #9
> Am 17.07.2026 um 13:38 schrieb Andrew Stubbs <ams@baylibre.com>:
> 
> On 17/07/2026 11:48, Richard Biener wrote:
>>> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>> 
>>> On 17/07/2026 09:13, Richard Biener wrote:
>>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>> 
>>>>> Hi all,
>>>>> 
>>>>> This patch series implements the "MEMs with address vectors" feature
>>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>>>>> The motivation is to simplify a new back-end optimization pass I'm
>>>>> working on and plan to post in the coming weeks.
>>>>> 
>>>>> The first patch, in this series, is the middle-end enablement and
>>>>> documentation changes.
>>>>> 
>>>>> The second patch converts the amdgcn back-end to use the new scheme,
>>>>> without adding any real new features. It depends on the
>>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>>>>> correctly.
>>>>> 
>>>>> The third and final patch demonstrates how I can use the new MEM to
>>>>> extend my machine description without writing whole new insns for the
>>>>> vector modes, just for them to evaluate to the same assembler code in
>>>>> the end.
>>>>> 
>>>>> I have not yet finished testing the patches, so these might not be quite
>>>>> the final form, but I'm not expecting big changes to the middle-end
>>>>> portion.  (I can self-approve the amdgcn parts, once the other is
>>>>> committed, but comments are welcome.)
>>>>> 
>>>>> OK for mainline? (Pending test results.)
>>>> 
>>>> I think this exposes what GCN does in a natural way.  I'm not sure
>>>> the advantage (exposing former gather/scatter as move) is not
>>>> also its disadvantage (moves are special!), and I somewhat question
>>>> the benefit over using some UNSPEC for this.  For example I would
>>>> assume that you side-step RTL alias/dependence analysis, meaning these
>>>> are barriers for optimization and scheduling?
>>> 
>>> This is intended to be an enabling technology for my real project, in
>>> which I want to transform scalar operations into vector operations in
>>> the backend, and the special casing for memory accesses was getting out
>>> of hand. By expressing (unmasked) vector operations identically to the
>>> scalar equivalent I can simplify things greatly, and the other compiler
>>> passes can do (some of) their special MEM handling as they normally would.
>> I see.  I guess you ruled out a
>>  ([parallel
>>    (set (mem:<scalar> ...) (...))
>>    (set (mem:<scalar> ...) (...))])
> 
> I would need this insn for V2, V4, V8, V16, V32, and V64. And probably SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).
> 
> It would be very verbose, and what would the constraints even look like?
> 
> Not to mention it's right back to the special-case conversions I was trying to avoid in the first place.
> 
>> etc. with vector extracts for the address.  At least for "transform scalar ops
>> to vectors" the actual representation of the MEM could be a black box
>> as long as you
>> have addresses in vectors (which is possible already).
> 
> I'm not really sure what this means. Can you give an example, please?

I mean you can write in your pass ‚turn MEM into a vec op‘ but how this is reflected into RTL is a detail that shouldn’t concern the pass itself (aka it might be an arbitrary complex but recognizable construct)

Richard 

> 
> Andrew
  
Robin Dapp July 17, 2026, 8:40 p.m. UTC | #10
> It's essentially vectorization in the backend, for code with specific 
> attributes. I definitely do not want to do it at gimple level because that 
> would have the exact same problems that the existing vectorizer has.

> For example, in most cases I can simply transform
>
>    (set (reg:SI) (plus:SI (reg:SI) (const_int)))
>
> into
>
>    (set (reg:V64SI) (plus:V64SI (reg:V64SI) (const_vector:V64SI)))
>
> which makes total sense and Just Works on AMD GCN for almost all 
> instructions.
>
> So, I want to do the same thing for a MEM:
>
>    (set (reg:SI) (mem:SI (reg:DI)))
>
> becomes
>
>    (set (reg:V64SI) (mem:V64SI (reg:V64DI)))
>
> except that the MEM is not valid because the address "isn't valid". 
> There's no reason it shouldn't work on the architecture -- the two RTL 
> patterns here will emit the *exact same* assembler code (obviously I set 
> the execution mask differently) -- it's just an old assumption built 
> into the compiler.

I'm not sure I follow 100% so let me just spell it out for myself.  You're 
probably trying to "just vectorize everything", like in a GPU/SIMT programming 
model?  And obviously this clashes with the vectorizer which doesn't if-convert 
everything, bails, costs etc.?

But I don't see how vectorization, even simple one, is easier at RTL level.  
What about divergence, calls, aliasing, loops?  Or is your target much 
narrower?

Even if narrow, for a proper gimple solution you'd need a "second vectorizer" 
with limited scope and predicated gimple (because our usual IFNs aren't 
comprehensive enough)?  It would "just" eat all conditions turning them into 
masks.  That's a long-term goal for the vectorizer as well BTW :)

Then, however, you'd still have the representational problem post expand :/
A vec_predicate would be helpful there, but only if it supported moves, loads 
and stores, which my initial RFC skipped for the known reasons ("they are 
special").

I guess it's time to start thinking more about them but that's obviously the 
opposite of a quick solution...  so nothing here will actually help you right 
away :/

> It might be that a "vec_predicate" would be better than "vec_merge"? But if 
> the register allocator can pull the MEM out of context then we didn't gain 
> anything for the specific issues I discussed in the gcc@ thread.

Yeah, one of the main reasons for vec_predicate as a "first-class" citizen is 
that we should not be able use its constituents context free.  Under that model 
a vec_merge is already an atomic operation, a predicated reg-move.  I wouldn't 
re-use vec_merge of course but we'd have something like
  (set (reg...) (vec_predicate [(reg ...)] vmask velse ...))
  
Richard Biener July 20, 2026, 7:23 a.m. UTC | #11
On Fri, Jul 17, 2026 at 10:40 PM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>
> > It's essentially vectorization in the backend, for code with specific
> > attributes. I definitely do not want to do it at gimple level because that
> > would have the exact same problems that the existing vectorizer has.
>
> > For example, in most cases I can simply transform
> >
> >    (set (reg:SI) (plus:SI (reg:SI) (const_int)))
> >
> > into
> >
> >    (set (reg:V64SI) (plus:V64SI (reg:V64SI) (const_vector:V64SI)))
> >
> > which makes total sense and Just Works on AMD GCN for almost all
> > instructions.
> >
> > So, I want to do the same thing for a MEM:
> >
> >    (set (reg:SI) (mem:SI (reg:DI)))
> >
> > becomes
> >
> >    (set (reg:V64SI) (mem:V64SI (reg:V64DI)))
> >
> > except that the MEM is not valid because the address "isn't valid".
> > There's no reason it shouldn't work on the architecture -- the two RTL
> > patterns here will emit the *exact same* assembler code (obviously I set
> > the execution mask differently) -- it's just an old assumption built
> > into the compiler.
>
> I'm not sure I follow 100% so let me just spell it out for myself.  You're
> probably trying to "just vectorize everything", like in a GPU/SIMT programming
> model?  And obviously this clashes with the vectorizer which doesn't if-convert
> everything, bails, costs etc.?
>
> But I don't see how vectorization, even simple one, is easier at RTL level.
> What about divergence, calls, aliasing, loops?  Or is your target much
> narrower?
>
> Even if narrow, for a proper gimple solution you'd need a "second vectorizer"
> with limited scope and predicated gimple (because our usual IFNs aren't
> comprehensive enough)?  It would "just" eat all conditions turning them into
> masks.  That's a long-term goal for the vectorizer as well BTW :)
>
> Then, however, you'd still have the representational problem post expand :/
> A vec_predicate would be helpful there, but only if it supported moves, loads
> and stores, which my initial RFC skipped for the known reasons ("they are
> special").
>
> I guess it's time to start thinking more about them but that's obviously the
> opposite of a quick solution...  so nothing here will actually help you right
> away :/
>
> > It might be that a "vec_predicate" would be better than "vec_merge"? But if
> > the register allocator can pull the MEM out of context then we didn't gain
> > anything for the specific issues I discussed in the gcc@ thread.
>
> Yeah, one of the main reasons for vec_predicate as a "first-class" citizen is
> that we should not be able use its constituents context free.  Under that model
> a vec_merge is already an atomic operation, a predicated reg-move.  I wouldn't
> re-use vec_merge of course but we'd have something like
>   (set (reg...) (vec_predicate [(reg ...)] vmask velse ...))

I'll note that (cond_exec ...) also needs to behave that way, so we
have precedent.
(vec_pred_set ...) maybe.

>
> --
> Regards
>  Robin
>
  
Andrew Stubbs July 20, 2026, 9:10 a.m. UTC | #12
On 17/07/2026 21:40, Robin Dapp wrote:
>> It's essentially vectorization in the backend, for code with specific
>> attributes. I definitely do not want to do it at gimple level because that
>> would have the exact same problems that the existing vectorizer has.
> 
>> For example, in most cases I can simply transform
>>
>>     (set (reg:SI) (plus:SI (reg:SI) (const_int)))
>>
>> into
>>
>>     (set (reg:V64SI) (plus:V64SI (reg:V64SI) (const_vector:V64SI)))
>>
>> which makes total sense and Just Works on AMD GCN for almost all
>> instructions.
>>
>> So, I want to do the same thing for a MEM:
>>
>>     (set (reg:SI) (mem:SI (reg:DI)))
>>
>> becomes
>>
>>     (set (reg:V64SI) (mem:V64SI (reg:V64DI)))
>>
>> except that the MEM is not valid because the address "isn't valid".
>> There's no reason it shouldn't work on the architecture -- the two RTL
>> patterns here will emit the *exact same* assembler code (obviously I set
>> the execution mask differently) -- it's just an old assumption built
>> into the compiler.
> 
> I'm not sure I follow 100% so let me just spell it out for myself.  You're
> probably trying to "just vectorize everything", like in a GPU/SIMT programming
> model?  And obviously this clashes with the vectorizer which doesn't if-convert
> everything, bails, costs etc.?

Yes, this is for the GPU, and yes, SIMT is the way to think of it. The 
vectorizer would not be enabled for this code. That would not go well!

> But I don't see how vectorization, even simple one, is easier at RTL level.
> What about divergence, calls, aliasing, loops?  Or is your target much
> narrower?

Divergence is a high-level concept that does not really exist at the 
assembler level (GCN has fork/join instructions, but then says not to 
use them in all but "irreducible cases" -- they simply loop until all 
the mask variations are exhausted).

Calls are not an issue in themselves (provided all parameters fit in 
registers).

Aliasing is no more of an issue than it would be in the original scalar 
code because the threads are required to be "independent".

Loops work just fine, as long as the masks are managed correctly.

> Even if narrow, for a proper gimple solution you'd need a "second vectorizer"
> with limited scope and predicated gimple (because our usual IFNs aren't
> comprehensive enough)?  It would "just" eat all conditions turning them into
> masks.  That's a long-term goal for the vectorizer as well BTW :)

Some things are easier at gimple level, and some are easier at RTL. The 
RTL level requires fewer changes that end up in discussions like this 
one. ;-)

> Then, however, you'd still have the representational problem post expand :/
> A vec_predicate would be helpful there, but only if it supported moves, loads
> and stores, which my initial RFC skipped for the known reasons ("they are
> special").
> 
> I guess it's time to start thinking more about them but that's obviously the
> opposite of a quick solution...  so nothing here will actually help you right
> away :/
> 
>> It might be that a "vec_predicate" would be better than "vec_merge"? But if
>> the register allocator can pull the MEM out of context then we didn't gain
>> anything for the specific issues I discussed in the gcc@ thread.
> 
> Yeah, one of the main reasons for vec_predicate as a "first-class" citizen is
> that we should not be able use its constituents context free.  Under that model
> a vec_merge is already an atomic operation, a predicated reg-move.  I wouldn't
> re-use vec_merge of course but we'd have something like
>    (set (reg...) (vec_predicate [(reg ...)] vmask velse ...))

So, it would be another way to write vec_merge, but with different 
behaviours/restrictions in certain passes?
  
Robin Dapp July 20, 2026, 8:49 p.m. UTC | #13
> Yes, this is for the GPU, and yes, SIMT is the way to think of it. The 
> vectorizer would not be enabled for this code. That would not go well!
>
>> But I don't see how vectorization, even simple one, is easier at RTL level.
>> What about divergence, calls, aliasing, loops?  Or is your target much
>> narrower?
>
> Divergence is a high-level concept that does not really exist at the 
> assembler level (GCN has fork/join instructions, but then says not to 
> use them in all but "irreducible cases" -- they simply loop until all 
> the mask variations are exhausted).
>
> Calls are not an issue in themselves (provided all parameters fit in 
> registers).
>
> Aliasing is no more of an issue than it would be in the original scalar 
> code because the threads are required to be "independent".
>
> Loops work just fine, as long as the masks are managed correctly.

> Some things are easier at gimple level, and some are easier at RTL. 
> The RTL level requires fewer changes that end up in discussions like 
> this one. ;-)

So you're transforming scalar "kernels" to SIMT and all prerequisites 
are already checked?  I don't think I'll be able to get a full picture
of your use case but to me it still sounds like a gimple-level problem, 
conceptually (when ignoring the fact that, currently, we cannot express 
it in gimple).

>> Yeah, one of the main reasons for vec_predicate as a "first-class" citizen is
>> that we should not be able use its constituents context free.  Under that model
>> a vec_merge is already an atomic operation, a predicated reg-move.  I wouldn't
>> re-use vec_merge of course but we'd have something like
>>    (set (reg...) (vec_predicate [(reg ...)] vmask velse ...))
>
> So, it would be another way to write vec_merge, but with different 
> behaviours/restrictions in certain passes?

A vec_merge is just a merge of two unpredicated inputs, vec_predicate is 
supposed to directly represent predication with mask, length etc. so a 
bit more comprehensive than vec_merge.  Also, the intention is to make
predication/masking more regular in the RTL passes.  Once it gets 
interesting, i.e. stores, moves, vec_predicate alone also isn't enough.  
But as indicated, separate topic and doesn't help you directly here, 
apologies for derailing.
  
Robin Dapp July 20, 2026, 8:50 p.m. UTC | #14
> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>
>> Hi all,
>>
>> This patch series implements the "MEMs with address vectors" feature
>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>> The motivation is to simplify a new back-end optimization pass I'm
>> working on and plan to post in the coming weeks.
>>
>> The first patch, in this series, is the middle-end enablement and
>> documentation changes.
>>
>> The second patch converts the amdgcn back-end to use the new scheme,
>> without adding any real new features. It depends on the
>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>> correctly.
>>
>> The third and final patch demonstrates how I can use the new MEM to
>> extend my machine description without writing whole new insns for the
>> vector modes, just for them to evaluate to the same assembler code in
>> the end.
>>
>> I have not yet finished testing the patches, so these might not be quite
>> the final form, but I'm not expecting big changes to the middle-end
>> portion.  (I can self-approve the amdgcn parts, once the other is
>> committed, but comments are welcome.)
>>
>> OK for mainline? (Pending test results.)
>
> I think this exposes what GCN does in a natural way.  I'm not sure
> the advantage (exposing former gather/scatter as move) is not
> also its disadvantage (moves are special!), and I somewhat question
> the benefit over using some UNSPEC for this.  For example I would
> assume that you side-step RTL alias/dependence analysis, meaning these
> are barriers for optimization and scheduling?
>
> The proposed semantics (overlap has undefined behavior) does not
> match up with usual vector ISA scatter semantics (left-to-right), so
> the representation isn't universally useable (if we solve the masking
> issue).

I just realized that we use the unordered flavor for scatters in RVV...

Right now, the only reasonable thing a mem:<V> can represent is 
unordered accesses?  And, as established in the RFC thread, we 
definitely need at least a non-overlap flag if it is supposed to be
useful for scatter?  And how would we even determine non-overlap? I 
don't see that we even can, apart from the stride-0 case.

So we would still need the hardware to operate left-to-right and mem:<V> 
would effectively become an unspec again.  On top, IIRC we assume 
somewhere that for mem:<mode> GET_MODE_SIZE (<mode>) is the size of the 
accessed memory.  I guess (mem:BLK (reg:V16SI)) was already discussed 
and considered bad/unwanted/worst of both worlds?
  
Richard Biener July 21, 2026, 6 a.m. UTC | #15
On Mon, Jul 20, 2026 at 10:50 PM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>
> > On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
> >>
> >> Hi all,
> >>
> >> This patch series implements the "MEMs with address vectors" feature
> >> that I want to use in AMD GCN, and have previously discussed on gcc@.
> >> The motivation is to simplify a new back-end optimization pass I'm
> >> working on and plan to post in the coming weeks.
> >>
> >> The first patch, in this series, is the middle-end enablement and
> >> documentation changes.
> >>
> >> The second patch converts the amdgcn back-end to use the new scheme,
> >> without adding any real new features. It depends on the
> >> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> >> correctly.
> >>
> >> The third and final patch demonstrates how I can use the new MEM to
> >> extend my machine description without writing whole new insns for the
> >> vector modes, just for them to evaluate to the same assembler code in
> >> the end.
> >>
> >> I have not yet finished testing the patches, so these might not be quite
> >> the final form, but I'm not expecting big changes to the middle-end
> >> portion.  (I can self-approve the amdgcn parts, once the other is
> >> committed, but comments are welcome.)
> >>
> >> OK for mainline? (Pending test results.)
> >
> > I think this exposes what GCN does in a natural way.  I'm not sure
> > the advantage (exposing former gather/scatter as move) is not
> > also its disadvantage (moves are special!), and I somewhat question
> > the benefit over using some UNSPEC for this.  For example I would
> > assume that you side-step RTL alias/dependence analysis, meaning these
> > are barriers for optimization and scheduling?
> >
> > The proposed semantics (overlap has undefined behavior) does not
> > match up with usual vector ISA scatter semantics (left-to-right), so
> > the representation isn't universally useable (if we solve the masking
> > issue).
>
> I just realized that we use the unordered flavor for scatters in RVV...
>
> Right now, the only reasonable thing a mem:<V> can represent is
> unordered accesses?  And, as established in the RFC thread, we
> definitely need at least a non-overlap flag if it is supposed to be
> useful for scatter?  And how would we even determine non-overlap? I
> don't see that we even can, apart from the stride-0 case.

I'll note that for this very reason the autovectorizer assumes scatters are
left-to-right.  As you say we cannot reasonably do a runtime check (OK,
there's separate ISA on x86 to detect conflicts, but we do not utilize that).
The md.texi docs for scatter_store roughly document that (we should
make the For each element index @var{i} more explicit I guess).

> So we would still need the hardware to operate left-to-right and mem:<V>
> would effectively become an unspec again.  On top, IIRC we assume
> somewhere that for mem:<mode> GET_MODE_SIZE (<mode>) is the size of the
> accessed memory.  I guess (mem:BLK (reg:V16SI)) was already discussed
> and considered bad/unwanted/worst of both worlds?
>
> --
> Regards
>  Robin
>
  
Andrew Stubbs July 28, 2026, 9 a.m. UTC | #16
On 17/07/2026 18:19, Richard Biener wrote:
> 
> 
>> Am 17.07.2026 um 13:38 schrieb Andrew Stubbs <ams@baylibre.com>:
>>
>> On 17/07/2026 11:48, Richard Biener wrote:
>>>> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>
>>>> On 17/07/2026 09:13, Richard Biener wrote:
>>>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>>>
>>>>>> Hi all,
>>>>>>
>>>>>> This patch series implements the "MEMs with address vectors" feature
>>>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>>>>>> The motivation is to simplify a new back-end optimization pass I'm
>>>>>> working on and plan to post in the coming weeks.
>>>>>>
>>>>>> The first patch, in this series, is the middle-end enablement and
>>>>>> documentation changes.
>>>>>>
>>>>>> The second patch converts the amdgcn back-end to use the new scheme,
>>>>>> without adding any real new features. It depends on the
>>>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>>>>>> correctly.
>>>>>>
>>>>>> The third and final patch demonstrates how I can use the new MEM to
>>>>>> extend my machine description without writing whole new insns for the
>>>>>> vector modes, just for them to evaluate to the same assembler code in
>>>>>> the end.
>>>>>>
>>>>>> I have not yet finished testing the patches, so these might not be quite
>>>>>> the final form, but I'm not expecting big changes to the middle-end
>>>>>> portion.  (I can self-approve the amdgcn parts, once the other is
>>>>>> committed, but comments are welcome.)
>>>>>>
>>>>>> OK for mainline? (Pending test results.)
>>>>>
>>>>> I think this exposes what GCN does in a natural way.  I'm not sure
>>>>> the advantage (exposing former gather/scatter as move) is not
>>>>> also its disadvantage (moves are special!), and I somewhat question
>>>>> the benefit over using some UNSPEC for this.  For example I would
>>>>> assume that you side-step RTL alias/dependence analysis, meaning these
>>>>> are barriers for optimization and scheduling?
>>>>
>>>> This is intended to be an enabling technology for my real project, in
>>>> which I want to transform scalar operations into vector operations in
>>>> the backend, and the special casing for memory accesses was getting out
>>>> of hand. By expressing (unmasked) vector operations identically to the
>>>> scalar equivalent I can simplify things greatly, and the other compiler
>>>> passes can do (some of) their special MEM handling as they normally would.
>>> I see.  I guess you ruled out a
>>>   ([parallel
>>>     (set (mem:<scalar> ...) (...))
>>>     (set (mem:<scalar> ...) (...))])
>>
>> I would need this insn for V2, V4, V8, V16, V32, and V64. And probably SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).
>>
>> It would be very verbose, and what would the constraints even look like?
>>
>> Not to mention it's right back to the special-case conversions I was trying to avoid in the first place.
>>
>>> etc. with vector extracts for the address.  At least for "transform scalar ops
>>> to vectors" the actual representation of the MEM could be a black box
>>> as long as you
>>> have addresses in vectors (which is possible already).
>>
>> I'm not really sure what this means. Can you give an example, please?
> 
> I mean you can write in your pass ‚turn MEM into a vec op‘ but how this is reflected into RTL is a detail that shouldn’t concern the pass itself (aka it might be an arbitrary complex but recognizable construct)
> 

The discussion seems to have run out of steam without producing a 
conclusion.

How can I proceed with this patch review?

Thanks

Andrew
  
Richard Biener July 28, 2026, 10:22 a.m. UTC | #17
On Tue, Jul 28, 2026 at 11:00 AM Andrew Stubbs <ams@baylibre.com> wrote:
>
> On 17/07/2026 18:19, Richard Biener wrote:
> >
> >
> >> Am 17.07.2026 um 13:38 schrieb Andrew Stubbs <ams@baylibre.com>:
> >>
> >> On 17/07/2026 11:48, Richard Biener wrote:
> >>>> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
> >>>>
> >>>> On 17/07/2026 09:13, Richard Biener wrote:
> >>>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
> >>>>>>
> >>>>>> Hi all,
> >>>>>>
> >>>>>> This patch series implements the "MEMs with address vectors" feature
> >>>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
> >>>>>> The motivation is to simplify a new back-end optimization pass I'm
> >>>>>> working on and plan to post in the coming weeks.
> >>>>>>
> >>>>>> The first patch, in this series, is the middle-end enablement and
> >>>>>> documentation changes.
> >>>>>>
> >>>>>> The second patch converts the amdgcn back-end to use the new scheme,
> >>>>>> without adding any real new features. It depends on the
> >>>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> >>>>>> correctly.
> >>>>>>
> >>>>>> The third and final patch demonstrates how I can use the new MEM to
> >>>>>> extend my machine description without writing whole new insns for the
> >>>>>> vector modes, just for them to evaluate to the same assembler code in
> >>>>>> the end.
> >>>>>>
> >>>>>> I have not yet finished testing the patches, so these might not be quite
> >>>>>> the final form, but I'm not expecting big changes to the middle-end
> >>>>>> portion.  (I can self-approve the amdgcn parts, once the other is
> >>>>>> committed, but comments are welcome.)
> >>>>>>
> >>>>>> OK for mainline? (Pending test results.)
> >>>>>
> >>>>> I think this exposes what GCN does in a natural way.  I'm not sure
> >>>>> the advantage (exposing former gather/scatter as move) is not
> >>>>> also its disadvantage (moves are special!), and I somewhat question
> >>>>> the benefit over using some UNSPEC for this.  For example I would
> >>>>> assume that you side-step RTL alias/dependence analysis, meaning these
> >>>>> are barriers for optimization and scheduling?
> >>>>
> >>>> This is intended to be an enabling technology for my real project, in
> >>>> which I want to transform scalar operations into vector operations in
> >>>> the backend, and the special casing for memory accesses was getting out
> >>>> of hand. By expressing (unmasked) vector operations identically to the
> >>>> scalar equivalent I can simplify things greatly, and the other compiler
> >>>> passes can do (some of) their special MEM handling as they normally would.
> >>> I see.  I guess you ruled out a
> >>>   ([parallel
> >>>     (set (mem:<scalar> ...) (...))
> >>>     (set (mem:<scalar> ...) (...))])
> >>
> >> I would need this insn for V2, V4, V8, V16, V32, and V64. And probably SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).
> >>
> >> It would be very verbose, and what would the constraints even look like?
> >>
> >> Not to mention it's right back to the special-case conversions I was trying to avoid in the first place.
> >>
> >>> etc. with vector extracts for the address.  At least for "transform scalar ops
> >>> to vectors" the actual representation of the MEM could be a black box
> >>> as long as you
> >>> have addresses in vectors (which is possible already).
> >>
> >> I'm not really sure what this means. Can you give an example, please?
> >
> > I mean you can write in your pass ‚turn MEM into a vec op‘ but how this is reflected into RTL is a detail that shouldn’t concern the pass itself (aka it might be an arbitrary complex but recognizable construct)
> >
>
> The discussion seems to have run out of steam without producing a
> conclusion.

Heh, sorry.  It's still that I do not like (mem:<vector> ) much, I
think it does not capture
the GCN case well which the (parallel [(set (mem:<scalar> ...])
variant would.  That
doesn't solve your pattern explosion/typing problem, of course.  Maybe
that can be
solved by parametrizing that (ick)

 (parallel_vec:<vector>
  [(set (mem:<scalar> (subreg:DI ...) ...)])

so basically have a parallel that implicitly enumerates operations on all vector
lanes of a mode.  The (parallel ..) bit implies it's unordered.  I'm
not exactly sure
about the subreg part for the address - some magic needs to happen for the
subreg offset of course.  Would this be
too restrictive?  I think GCN can actually do few (two?) lanes as actual vector
operation in an ALU, but I guess we're not modeling that.

That said, I do not want to stand in the way of (mem:<vector> ..) when there's
consensus this is the best general way to address this.

> How can I proceed with this patch review?
>
> Thanks
>
> Andrew
  
Andrew Stubbs July 28, 2026, 10:40 a.m. UTC | #18
On 28/07/2026 11:22, Richard Biener wrote:
> On Tue, Jul 28, 2026 at 11:00 AM Andrew Stubbs <ams@baylibre.com> wrote:
>>
>> On 17/07/2026 18:19, Richard Biener wrote:
>>>
>>>
>>>> Am 17.07.2026 um 13:38 schrieb Andrew Stubbs <ams@baylibre.com>:
>>>>
>>>> On 17/07/2026 11:48, Richard Biener wrote:
>>>>>> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>>>
>>>>>> On 17/07/2026 09:13, Richard Biener wrote:
>>>>>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>>>>>
>>>>>>>> Hi all,
>>>>>>>>
>>>>>>>> This patch series implements the "MEMs with address vectors" feature
>>>>>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>>>>>>>> The motivation is to simplify a new back-end optimization pass I'm
>>>>>>>> working on and plan to post in the coming weeks.
>>>>>>>>
>>>>>>>> The first patch, in this series, is the middle-end enablement and
>>>>>>>> documentation changes.
>>>>>>>>
>>>>>>>> The second patch converts the amdgcn back-end to use the new scheme,
>>>>>>>> without adding any real new features. It depends on the
>>>>>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>>>>>>>> correctly.
>>>>>>>>
>>>>>>>> The third and final patch demonstrates how I can use the new MEM to
>>>>>>>> extend my machine description without writing whole new insns for the
>>>>>>>> vector modes, just for them to evaluate to the same assembler code in
>>>>>>>> the end.
>>>>>>>>
>>>>>>>> I have not yet finished testing the patches, so these might not be quite
>>>>>>>> the final form, but I'm not expecting big changes to the middle-end
>>>>>>>> portion.  (I can self-approve the amdgcn parts, once the other is
>>>>>>>> committed, but comments are welcome.)
>>>>>>>>
>>>>>>>> OK for mainline? (Pending test results.)
>>>>>>>
>>>>>>> I think this exposes what GCN does in a natural way.  I'm not sure
>>>>>>> the advantage (exposing former gather/scatter as move) is not
>>>>>>> also its disadvantage (moves are special!), and I somewhat question
>>>>>>> the benefit over using some UNSPEC for this.  For example I would
>>>>>>> assume that you side-step RTL alias/dependence analysis, meaning these
>>>>>>> are barriers for optimization and scheduling?
>>>>>>
>>>>>> This is intended to be an enabling technology for my real project, in
>>>>>> which I want to transform scalar operations into vector operations in
>>>>>> the backend, and the special casing for memory accesses was getting out
>>>>>> of hand. By expressing (unmasked) vector operations identically to the
>>>>>> scalar equivalent I can simplify things greatly, and the other compiler
>>>>>> passes can do (some of) their special MEM handling as they normally would.
>>>>> I see.  I guess you ruled out a
>>>>>    ([parallel
>>>>>      (set (mem:<scalar> ...) (...))
>>>>>      (set (mem:<scalar> ...) (...))])
>>>>
>>>> I would need this insn for V2, V4, V8, V16, V32, and V64. And probably SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).
>>>>
>>>> It would be very verbose, and what would the constraints even look like?
>>>>
>>>> Not to mention it's right back to the special-case conversions I was trying to avoid in the first place.
>>>>
>>>>> etc. with vector extracts for the address.  At least for "transform scalar ops
>>>>> to vectors" the actual representation of the MEM could be a black box
>>>>> as long as you
>>>>> have addresses in vectors (which is possible already).
>>>>
>>>> I'm not really sure what this means. Can you give an example, please?
>>>
>>> I mean you can write in your pass ‚turn MEM into a vec op‘ but how this is reflected into RTL is a detail that shouldn’t concern the pass itself (aka it might be an arbitrary complex but recognizable construct)
>>>
>>
>> The discussion seems to have run out of steam without producing a
>> conclusion.
> 
> Heh, sorry.  It's still that I do not like (mem:<vector> ) much, I
> think it does not capture
> the GCN case well which the (parallel [(set (mem:<scalar> ...])
> variant would.  That
> doesn't solve your pattern explosion/typing problem, of course.

I don't know how the constraints would even work?

(parallel [(set (match_operand:<scalar> 0 "memory_operand" "v") (...))
            (set (match_operand:<scalar> 1 "memory_operand" "0") (...))
            ....

Or does it use (match_dup 0)? There are 64 notional scalar operands that 
are somehow all in the same register. I don't know how to express that.

> Maybe that can be
> solved by parametrizing that (ick)
> 
>   (parallel_vec:<vector>
>    [(set (mem:<scalar> (subreg:DI ...) ...)])
> 
> so basically have a parallel that implicitly enumerates operations on all vector
> lanes of a mode.  The (parallel ..) bit implies it's unordered.

That could work, although that's a whole project in itself, and you'd 
probably want to express all vector operations that way or else you'll 
end up having to convert between them. And you'd have to stop the 
combine pass trying to insert actual scalars into parallel_vec patterns 
because they look like they'd fit.

 > I'm not exactly sure> about the subreg part for the address - some 
magic needs to happen for the
> subreg offset of course.

Subregs are already basically unusable for GCN because the implied 
operation just doesn't fit when you can't reinterpret the entire vector 
with a different number of lanes.

I want a "vsubreg" which refers to a portion of each lane, but I also 
don't want to completely rewrite the compiler to handle that everywhere 
it would come up.

> Would this be
> too restrictive?  I think GCN can actually do few (two?) lanes as actual vector
> operation in an ALU, but I guess we're not modeling that.

As far as I know, the GPU does everything x64 in parallel. I'm sure 
there's some hidden implementation details in there, but those are not 
in the ISA manual.

> That said, I do not want to stand in the way of (mem:<vector> ..) when there's
> consensus this is the best general way to address this.

Thank you.


>> How can I proceed with this patch review?
>>
>> Thanks
>>
>> Andrew
  
Richard Biener July 28, 2026, 11:54 a.m. UTC | #19
On Tue, Jul 28, 2026 at 12:40 PM Andrew Stubbs <ams@baylibre.com> wrote:
>
> On 28/07/2026 11:22, Richard Biener wrote:
> > On Tue, Jul 28, 2026 at 11:00 AM Andrew Stubbs <ams@baylibre.com> wrote:
> >>
> >> On 17/07/2026 18:19, Richard Biener wrote:
> >>>
> >>>
> >>>> Am 17.07.2026 um 13:38 schrieb Andrew Stubbs <ams@baylibre.com>:
> >>>>
> >>>> On 17/07/2026 11:48, Richard Biener wrote:
> >>>>>> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
> >>>>>>
> >>>>>> On 17/07/2026 09:13, Richard Biener wrote:
> >>>>>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
> >>>>>>>>
> >>>>>>>> Hi all,
> >>>>>>>>
> >>>>>>>> This patch series implements the "MEMs with address vectors" feature
> >>>>>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
> >>>>>>>> The motivation is to simplify a new back-end optimization pass I'm
> >>>>>>>> working on and plan to post in the coming weeks.
> >>>>>>>>
> >>>>>>>> The first patch, in this series, is the middle-end enablement and
> >>>>>>>> documentation changes.
> >>>>>>>>
> >>>>>>>> The second patch converts the amdgcn back-end to use the new scheme,
> >>>>>>>> without adding any real new features. It depends on the
> >>>>>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
> >>>>>>>> correctly.
> >>>>>>>>
> >>>>>>>> The third and final patch demonstrates how I can use the new MEM to
> >>>>>>>> extend my machine description without writing whole new insns for the
> >>>>>>>> vector modes, just for them to evaluate to the same assembler code in
> >>>>>>>> the end.
> >>>>>>>>
> >>>>>>>> I have not yet finished testing the patches, so these might not be quite
> >>>>>>>> the final form, but I'm not expecting big changes to the middle-end
> >>>>>>>> portion.  (I can self-approve the amdgcn parts, once the other is
> >>>>>>>> committed, but comments are welcome.)
> >>>>>>>>
> >>>>>>>> OK for mainline? (Pending test results.)
> >>>>>>>
> >>>>>>> I think this exposes what GCN does in a natural way.  I'm not sure
> >>>>>>> the advantage (exposing former gather/scatter as move) is not
> >>>>>>> also its disadvantage (moves are special!), and I somewhat question
> >>>>>>> the benefit over using some UNSPEC for this.  For example I would
> >>>>>>> assume that you side-step RTL alias/dependence analysis, meaning these
> >>>>>>> are barriers for optimization and scheduling?
> >>>>>>
> >>>>>> This is intended to be an enabling technology for my real project, in
> >>>>>> which I want to transform scalar operations into vector operations in
> >>>>>> the backend, and the special casing for memory accesses was getting out
> >>>>>> of hand. By expressing (unmasked) vector operations identically to the
> >>>>>> scalar equivalent I can simplify things greatly, and the other compiler
> >>>>>> passes can do (some of) their special MEM handling as they normally would.
> >>>>> I see.  I guess you ruled out a
> >>>>>    ([parallel
> >>>>>      (set (mem:<scalar> ...) (...))
> >>>>>      (set (mem:<scalar> ...) (...))])
> >>>>
> >>>> I would need this insn for V2, V4, V8, V16, V32, and V64. And probably SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).
> >>>>
> >>>> It would be very verbose, and what would the constraints even look like?
> >>>>
> >>>> Not to mention it's right back to the special-case conversions I was trying to avoid in the first place.
> >>>>
> >>>>> etc. with vector extracts for the address.  At least for "transform scalar ops
> >>>>> to vectors" the actual representation of the MEM could be a black box
> >>>>> as long as you
> >>>>> have addresses in vectors (which is possible already).
> >>>>
> >>>> I'm not really sure what this means. Can you give an example, please?
> >>>
> >>> I mean you can write in your pass ‚turn MEM into a vec op‘ but how this is reflected into RTL is a detail that shouldn’t concern the pass itself (aka it might be an arbitrary complex but recognizable construct)
> >>>
> >>
> >> The discussion seems to have run out of steam without producing a
> >> conclusion.
> >
> > Heh, sorry.  It's still that I do not like (mem:<vector> ) much, I
> > think it does not capture
> > the GCN case well which the (parallel [(set (mem:<scalar> ...])
> > variant would.  That
> > doesn't solve your pattern explosion/typing problem, of course.
>
> I don't know how the constraints would even work?
>
> (parallel [(set (match_operand:<scalar> 0 "memory_operand" "v") (...))
>             (set (match_operand:<scalar> 1 "memory_operand" "0") (...))
>             ....
>
> Or does it use (match_dup 0)? There are 64 notional scalar operands that
> are somehow all in the same register. I don't know how to express that.
>
> > Maybe that can be
> > solved by parametrizing that (ick)
> >
> >   (parallel_vec:<vector>
> >    [(set (mem:<scalar> (subreg:DI ...) ...)])
> >
> > so basically have a parallel that implicitly enumerates operations on all vector
> > lanes of a mode.  The (parallel ..) bit implies it's unordered.
>
> That could work, although that's a whole project in itself, and you'd
> probably want to express all vector operations that way or else you'll
> end up having to convert between them. And you'd have to stop the
> combine pass trying to insert actual scalars into parallel_vec patterns
> because they look like they'd fit.
>
>  > I'm not exactly sure> about the subreg part for the address - some
> magic needs to happen for the
> > subreg offset of course.
>
> Subregs are already basically unusable for GCN because the implied
> operation just doesn't fit when you can't reinterpret the entire vector
> with a different number of lanes.
>
> I want a "vsubreg" which refers to a portion of each lane, but I also
> don't want to completely rewrite the compiler to handle that everywhere
> it would come up.
>
> > Would this be
> > too restrictive?  I think GCN can actually do few (two?) lanes as actual vector
> > operation in an ALU, but I guess we're not modeling that.
>
> As far as I know, the GPU does everything x64 in parallel. I'm sure
> there's some hidden implementation details in there, but those are not
> in the ISA manual.
>
> > That said, I do not want to stand in the way of (mem:<vector> ..) when there's
> > consensus this is the best general way to address this.

Just to add that (mem:<vector> ..) with unordered semantics ties us to that
unless we want to have a flag on the mem to have left-to-right semantics.
Given it in theory should be made to fit gather/scatter modelling (ignoring
the masking representational issue).  So I'd like at least that thought out,
if not documented and implemented (having the flag and printing it).

Richard.

>
> Thank you.
>
>
> >> How can I proceed with this patch review?
> >>
> >> Thanks
> >>
> >> Andrew
>
  
Andrew Stubbs July 28, 2026, 4:01 p.m. UTC | #20
On 28/07/2026 12:54, Richard Biener wrote:
> On Tue, Jul 28, 2026 at 12:40 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>
>> On 28/07/2026 11:22, Richard Biener wrote:
>>> On Tue, Jul 28, 2026 at 11:00 AM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>
>>>> On 17/07/2026 18:19, Richard Biener wrote:
>>>>>
>>>>>
>>>>>> Am 17.07.2026 um 13:38 schrieb Andrew Stubbs <ams@baylibre.com>:
>>>>>>
>>>>>> On 17/07/2026 11:48, Richard Biener wrote:
>>>>>>>> On Fri, Jul 17, 2026 at 12:13 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>>>>>
>>>>>>>> On 17/07/2026 09:13, Richard Biener wrote:
>>>>>>>>> On Wed, Jul 8, 2026 at 4:48 PM Andrew Stubbs <ams@baylibre.com> wrote:
>>>>>>>>>>
>>>>>>>>>> Hi all,
>>>>>>>>>>
>>>>>>>>>> This patch series implements the "MEMs with address vectors" feature
>>>>>>>>>> that I want to use in AMD GCN, and have previously discussed on gcc@.
>>>>>>>>>> The motivation is to simplify a new back-end optimization pass I'm
>>>>>>>>>> working on and plan to post in the coming weeks.
>>>>>>>>>>
>>>>>>>>>> The first patch, in this series, is the middle-end enablement and
>>>>>>>>>> documentation changes.
>>>>>>>>>>
>>>>>>>>>> The second patch converts the amdgcn back-end to use the new scheme,
>>>>>>>>>> without adding any real new features. It depends on the
>>>>>>>>>> INSN_BASE_REG_CLASS patch I posted last week (still in review) to run
>>>>>>>>>> correctly.
>>>>>>>>>>
>>>>>>>>>> The third and final patch demonstrates how I can use the new MEM to
>>>>>>>>>> extend my machine description without writing whole new insns for the
>>>>>>>>>> vector modes, just for them to evaluate to the same assembler code in
>>>>>>>>>> the end.
>>>>>>>>>>
>>>>>>>>>> I have not yet finished testing the patches, so these might not be quite
>>>>>>>>>> the final form, but I'm not expecting big changes to the middle-end
>>>>>>>>>> portion.  (I can self-approve the amdgcn parts, once the other is
>>>>>>>>>> committed, but comments are welcome.)
>>>>>>>>>>
>>>>>>>>>> OK for mainline? (Pending test results.)
>>>>>>>>>
>>>>>>>>> I think this exposes what GCN does in a natural way.  I'm not sure
>>>>>>>>> the advantage (exposing former gather/scatter as move) is not
>>>>>>>>> also its disadvantage (moves are special!), and I somewhat question
>>>>>>>>> the benefit over using some UNSPEC for this.  For example I would
>>>>>>>>> assume that you side-step RTL alias/dependence analysis, meaning these
>>>>>>>>> are barriers for optimization and scheduling?
>>>>>>>>
>>>>>>>> This is intended to be an enabling technology for my real project, in
>>>>>>>> which I want to transform scalar operations into vector operations in
>>>>>>>> the backend, and the special casing for memory accesses was getting out
>>>>>>>> of hand. By expressing (unmasked) vector operations identically to the
>>>>>>>> scalar equivalent I can simplify things greatly, and the other compiler
>>>>>>>> passes can do (some of) their special MEM handling as they normally would.
>>>>>>> I see.  I guess you ruled out a
>>>>>>>     ([parallel
>>>>>>>       (set (mem:<scalar> ...) (...))
>>>>>>>       (set (mem:<scalar> ...) (...))])
>>>>>>
>>>>>> I would need this insn for V2, V4, V8, V16, V32, and V64. And probably SI/SF, DI/DF, and TI variants of each of those too (maybe QI and HI also).
>>>>>>
>>>>>> It would be very verbose, and what would the constraints even look like?
>>>>>>
>>>>>> Not to mention it's right back to the special-case conversions I was trying to avoid in the first place.
>>>>>>
>>>>>>> etc. with vector extracts for the address.  At least for "transform scalar ops
>>>>>>> to vectors" the actual representation of the MEM could be a black box
>>>>>>> as long as you
>>>>>>> have addresses in vectors (which is possible already).
>>>>>>
>>>>>> I'm not really sure what this means. Can you give an example, please?
>>>>>
>>>>> I mean you can write in your pass ‚turn MEM into a vec op‘ but how this is reflected into RTL is a detail that shouldn’t concern the pass itself (aka it might be an arbitrary complex but recognizable construct)
>>>>>
>>>>
>>>> The discussion seems to have run out of steam without producing a
>>>> conclusion.
>>>
>>> Heh, sorry.  It's still that I do not like (mem:<vector> ) much, I
>>> think it does not capture
>>> the GCN case well which the (parallel [(set (mem:<scalar> ...])
>>> variant would.  That
>>> doesn't solve your pattern explosion/typing problem, of course.
>>
>> I don't know how the constraints would even work?
>>
>> (parallel [(set (match_operand:<scalar> 0 "memory_operand" "v") (...))
>>              (set (match_operand:<scalar> 1 "memory_operand" "0") (...))
>>              ....
>>
>> Or does it use (match_dup 0)? There are 64 notional scalar operands that
>> are somehow all in the same register. I don't know how to express that.
>>
>>> Maybe that can be
>>> solved by parametrizing that (ick)
>>>
>>>    (parallel_vec:<vector>
>>>     [(set (mem:<scalar> (subreg:DI ...) ...)])
>>>
>>> so basically have a parallel that implicitly enumerates operations on all vector
>>> lanes of a mode.  The (parallel ..) bit implies it's unordered.
>>
>> That could work, although that's a whole project in itself, and you'd
>> probably want to express all vector operations that way or else you'll
>> end up having to convert between them. And you'd have to stop the
>> combine pass trying to insert actual scalars into parallel_vec patterns
>> because they look like they'd fit.
>>
>>   > I'm not exactly sure> about the subreg part for the address - some
>> magic needs to happen for the
>>> subreg offset of course.
>>
>> Subregs are already basically unusable for GCN because the implied
>> operation just doesn't fit when you can't reinterpret the entire vector
>> with a different number of lanes.
>>
>> I want a "vsubreg" which refers to a portion of each lane, but I also
>> don't want to completely rewrite the compiler to handle that everywhere
>> it would come up.
>>
>>> Would this be
>>> too restrictive?  I think GCN can actually do few (two?) lanes as actual vector
>>> operation in an ALU, but I guess we're not modeling that.
>>
>> As far as I know, the GPU does everything x64 in parallel. I'm sure
>> there's some hidden implementation details in there, but those are not
>> in the ISA manual.
>>
>>> That said, I do not want to stand in the way of (mem:<vector> ..) when there's
>>> consensus this is the best general way to address this.
> 
> Just to add that (mem:<vector> ..) with unordered semantics ties us to that
> unless we want to have a flag on the mem to have left-to-right semantics.
> Given it in theory should be made to fit gather/scatter modelling (ignoring
> the masking representational issue).  So I'd like at least that thought out,
> if not documented and implemented (having the flag and printing it).

I believe the /i and /s flags are available, if we should choose to use 
them.

Would a target hook not be sufficient though? These things are likely to 
be true always or never, for any given mode, on most architectures.

Better even, as such flags are somewhat likely to "get lost" in all the 
random places that manipulate MEM.

Andrew
  
Richard Sandiford July 28, 2026, 4:21 p.m. UTC | #21
Andrew Stubbs <ams@baylibre.com> writes:
> On 28/07/2026 12:54, Richard Biener wrote:
>> [...]
>> Just to add that (mem:<vector> ..) with unordered semantics ties us to that
>> unless we want to have a flag on the mem to have left-to-right semantics.
>> Given it in theory should be made to fit gather/scatter modelling (ignoring
>> the masking representational issue).  So I'd like at least that thought out,
>> if not documented and implemented (having the flag and printing it).

Agreed FWIW.

I think it would be good to think about the masking issue too, given
Robin's parallel discussion about having a better representation of
predication.  Again, just in terms of having a plausible approach
thought out, rather than being implemented in the first version.

> I believe the /i and /s flags are available, if we should choose to use 
> them.
>
> Would a target hook not be sufficient though? These things are likely to 
> be true always or never, for any given mode, on most architectures.
>
> Better even, as such flags are somewhat likely to "get lost" in all the 
> random places that manipulate MEM.

Please don't use a hook! :)  IMO RTL semantics should stand on their own
as far as possible.  I realise there are exceptions, like STORE_FLAG_VALUE
and SHIFT_COUNT_TRUNCATED, but even there, I think it would have been
better to make the RTL operators self-descriptive and use the macros
to control which operator is generated.

Making SHIFT_COUNT_TRUNCATED apply to all shift rtxes has been a problem
in the past and using a hook here might end up the same way.

Thanks,
Richard
  
Andrew Stubbs July 28, 2026, 4:59 p.m. UTC | #22
On 28/07/2026 17:21, Richard Sandiford wrote:
> Andrew Stubbs <ams@baylibre.com> writes:
>> On 28/07/2026 12:54, Richard Biener wrote:
>>> [...]
>>> Just to add that (mem:<vector> ..) with unordered semantics ties us to that
>>> unless we want to have a flag on the mem to have left-to-right semantics.
>>> Given it in theory should be made to fit gather/scatter modelling (ignoring
>>> the masking representational issue).  So I'd like at least that thought out,
>>> if not documented and implemented (having the flag and printing it).
> 
> Agreed FWIW.
> 
> I think it would be good to think about the masking issue too, given
> Robin's parallel discussion about having a better representation of
> predication.  Again, just in terms of having a plausible approach
> thought out, rather than being implemented in the first version.
> 
>> I believe the /i and /s flags are available, if we should choose to use
>> them.
>>
>> Would a target hook not be sufficient though? These things are likely to
>> be true always or never, for any given mode, on most architectures.
>>
>> Better even, as such flags are somewhat likely to "get lost" in all the
>> random places that manipulate MEM.
> 
> Please don't use a hook! :)  IMO RTL semantics should stand on their own
> as far as possible.  I realise there are exceptions, like STORE_FLAG_VALUE
> and SHIFT_COUNT_TRUNCATED, but even there, I think it would have been
> better to make the RTL operators self-descriptive and use the macros
> to control which operator is generated.
> 
> Making SHIFT_COUNT_TRUNCATED apply to all shift rtxes has been a problem
> in the past and using a hook here might end up the same way.

OK, let's say MEM_IN_ORDER_WRITE with /i then? If the flag is not 
present then the order is undefined. It could work the other way around, 
but this seemed to fit nicer with "i".

How does it get written at expand time? Does the expand pass just assume 
that all gimple vector operators are "in-order"? Is there a hook for 
*that*? Ordered/unordered optabs? The legitimate/legitimize hooks can't 
do anything with flags because they only see the address expression.

If we're just assuming in-order by default, the code produced would 
actually be unsuitable for GCN. Except it isn't, of course, because 
autovectorization (and OpenMP parallel, etc) require that the loop 
iterations are independent, and therefore we choose to assume (rightly 
or wrongly) that using the writes that we have are safe.

But GCN would have to somehow go though and remove all those flags, or 
else whatever RTL optimizer it is that cares about such things would be 
getting misinformed.

Andrew
  
Richard Biener July 28, 2026, 5:17 p.m. UTC | #23
> Am 28.07.2026 um 18:59 schrieb Andrew Stubbs <ams@baylibre.com>:
> 
> On 28/07/2026 17:21, Richard Sandiford wrote:
>> Andrew Stubbs <ams@baylibre.com> writes:
>>>> On 28/07/2026 12:54, Richard Biener wrote:
>>>>> [...]
>>>>> Just to add that (mem:<vector> ..) with unordered semantics ties us to that
>>>>> unless we want to have a flag on the mem to have left-to-right semantics.
>>>>> Given it in theory should be made to fit gather/scatter modelling (ignoring
>>>>> the masking representational issue).  So I'd like at least that thought out,
>>>>> if not documented and implemented (having the flag and printing it).
>>> Agreed FWIW.
>>> I think it would be good to think about the masking issue too, given
>>> Robin's parallel discussion about having a better representation of
>>> predication.  Again, just in terms of having a plausible approach
>>> thought out, rather than being implemented in the first version.
>>> I believe the /i and /s flags are available, if we should choose to use
>>> them.
>>> 
>>> Would a target hook not be sufficient though? These things are likely to
>>> be true always or never, for any given mode, on most architectures.
>>> 
>>> Better even, as such flags are somewhat likely to "get lost" in all the
>>> random places that manipulate MEM.
>> Please don't use a hook! :)  IMO RTL semantics should stand on their own
>> as far as possible.  I realise there are exceptions, like STORE_FLAG_VALUE
>> and SHIFT_COUNT_TRUNCATED, but even there, I think it would have been
>> better to make the RTL operators self-descriptive and use the macros
>> to control which operator is generated.
>> Making SHIFT_COUNT_TRUNCATED apply to all shift rtxes has been a problem
>> in the past and using a hook here might end up the same way.
> 
> OK, let's say MEM_IN_ORDER_WRITE with /i then? If the flag is not present then the order is undefined. It could work the other way around, but this seemed to fit nicer with "i".
> 
> How does it get written at expand time? Does the expand pass just assume that all gimple vector operators are "in-order"? Is there a hook for *that*? Ordered/unordered optabs? The legitimate/legitimize hooks can't do anything with flags because they only see the address expression.

The only way to get this from RTL expansion is through gather (order does not matter) and scatter (in-order required) both generated via optabs thus the flag is set from targets.  And recog would somehow need to match on it as riscv can do both in-order and unspecified order.

Richard 

> 
> If we're just assuming in-order by default, the code produced would actually be unsuitable for GCN. Except it isn't, of course, because autovectorization (and OpenMP parallel, etc) require that the loop iterations are independent, and therefore we choose to assume (rightly or wrongly) that using the writes that we have are safe.
> 
> But GCN would have to somehow go though and remove all those flags, or else whatever RTL optimizer it is that cares about such things would be getting misinformed.
> 
> Andrew
  
Andrew Stubbs July 29, 2026, 8:33 a.m. UTC | #24
On 28/07/2026 18:17, Richard Biener wrote:
> 
> 
>> Am 28.07.2026 um 18:59 schrieb Andrew Stubbs <ams@baylibre.com>:
>>
>> On 28/07/2026 17:21, Richard Sandiford wrote:
>>> Andrew Stubbs <ams@baylibre.com> writes:
>>>>> On 28/07/2026 12:54, Richard Biener wrote:
>>>>>> [...]
>>>>>> Just to add that (mem:<vector> ..) with unordered semantics ties us to that
>>>>>> unless we want to have a flag on the mem to have left-to-right semantics.
>>>>>> Given it in theory should be made to fit gather/scatter modelling (ignoring
>>>>>> the masking representational issue).  So I'd like at least that thought out,
>>>>>> if not documented and implemented (having the flag and printing it).
>>>> Agreed FWIW.
>>>> I think it would be good to think about the masking issue too, given
>>>> Robin's parallel discussion about having a better representation of
>>>> predication.  Again, just in terms of having a plausible approach
>>>> thought out, rather than being implemented in the first version.
>>>> I believe the /i and /s flags are available, if we should choose to use
>>>> them.
>>>>
>>>> Would a target hook not be sufficient though? These things are likely to
>>>> be true always or never, for any given mode, on most architectures.
>>>>
>>>> Better even, as such flags are somewhat likely to "get lost" in all the
>>>> random places that manipulate MEM.
>>> Please don't use a hook! :)  IMO RTL semantics should stand on their own
>>> as far as possible.  I realise there are exceptions, like STORE_FLAG_VALUE
>>> and SHIFT_COUNT_TRUNCATED, but even there, I think it would have been
>>> better to make the RTL operators self-descriptive and use the macros
>>> to control which operator is generated.
>>> Making SHIFT_COUNT_TRUNCATED apply to all shift rtxes has been a problem
>>> in the past and using a hook here might end up the same way.
>>
>> OK, let's say MEM_IN_ORDER_WRITE with /i then? If the flag is not present then the order is undefined. It could work the other way around, but this seemed to fit nicer with "i".
>>
>> How does it get written at expand time? Does the expand pass just assume that all gimple vector operators are "in-order"? Is there a hook for *that*? Ordered/unordered optabs? The legitimate/legitimize hooks can't do anything with flags because they only see the address expression.
> 
> The only way to get this from RTL expansion is through gather (order does not matter) and scatter (in-order required) both generated via optabs thus the flag is set from targets.  And recog would somehow need to match on it as riscv can do both in-order and unspecified order.

OK, so expand is not actually a problem because no current gimple 
generates such things directly; got it. The scatter_store patterns can 
do as required.

Also, since scatter operations use fixed strides the question of 
in-order, or not, is actually a non-issue even on GCN so we could set 
the flag safely.

As for the recog issue, can predicates not take care of that?

(define_predicate "riscv_in_order_vector_mem"
   (and (match_operand 0 "memory_operand")
        (match_test "MEM_IN_ORDER_WRITE_P (op)")))

Andrew

> 
> Richard
> 
>>
>> If we're just assuming in-order by default, the code produced would actually be unsuitable for GCN. Except it isn't, of course, because autovectorization (and OpenMP parallel, etc) require that the loop iterations are independent, and therefore we choose to assume (rightly or wrongly) that using the writes that we have are safe.
>>
>> But GCN would have to somehow go though and remove all those flags, or else whatever RTL optimizer it is that cares about such things would be getting misinformed.
>>
>> Andrew
  
Robin Dapp July 29, 2026, 8:36 a.m. UTC | #25
> Also, since scatter operations use fixed strides the question of 
> in-order, or not, is actually a non-issue even on GCN so we could set 
> the flag safely.

Consider stride 0 and stride < element size, though.  I'm currently 
thinking of how/where to add the proper versioning decision for that.
  
Robin Dapp July 29, 2026, 8:38 a.m. UTC | #26
>> Also, since scatter operations use fixed strides the question of 
>> in-order, or not, is actually a non-issue even on GCN so we could set 
>> the flag safely.
>
> Consider stride 0 and stride < element size, though.  I'm currently 
> thinking of how/where to add the proper versioning decision for that.

Ah, that might only be an issue for riscv where we allow byte strides.  
For a regular scatter with at least element stride, this would be ok I 
guess.
  
Richard Biener July 29, 2026, 8:52 a.m. UTC | #27
On Wed, Jul 29, 2026 at 10:38 AM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>
> >> Also, since scatter operations use fixed strides the question of
> >> in-order, or not, is actually a non-issue even on GCN so we could set
> >> the flag safely.
> >
> > Consider stride 0 and stride < element size, though.  I'm currently
> > thinking of how/where to add the proper versioning decision for that.
>
> Ah, that might only be an issue for riscv where we allow byte strides.
> For a regular scatter with at least element stride, this would be ok I
> guess.

scatter is not fixed stride but base address + vector of offsets where
offsets need not be distinct.

Richard.

> --
> Regards
>  Robin
>
  
Andrew Stubbs July 29, 2026, 8:53 a.m. UTC | #28
On 29/07/2026 09:36, Robin Dapp wrote:
>> Also, since scatter operations use fixed strides the question of
>> in-order, or not, is actually a non-issue even on GCN so we could set
>> the flag safely.
> 
> Consider stride 0 and stride < element size, though.  I'm currently
> thinking of how/where to add the proper versioning decision for that.

I'm generally of the opinion that the compiler should not compromise the 
speed of well written code to cover whatever abomination somehow manages 
to convince the autovectorizer to generate zero stride lengths.

My interest is in OpenMP/OpenACC where the multithreading already 
destroyed all notion of left-to-rightness that the vectorizer tries so 
hard to preserve. In these cases, the end-user has declared and promised 
that the loop iterations are independent, and if it turns out that's not 
the case, then that's on them.

However, if riscv has the instructions and hardware to handle that case, 
would it not naturally fall to the "scatter_store" expander to handle 
these cases? This feeling like a back-end decision, to me.

Or, are you thinking of versioning it in gimple, somehow? I assume this 
would require knowing how the backend instruction handles the writes... 
would the plan be to never ask the backend to do something in-order if 
it can't promise that?

Andrew
  
Richard Biener July 29, 2026, 9:07 a.m. UTC | #29
On Wed, Jul 29, 2026 at 10:53 AM Andrew Stubbs <ams@baylibre.com> wrote:
>
> On 29/07/2026 09:36, Robin Dapp wrote:
> >> Also, since scatter operations use fixed strides the question of
> >> in-order, or not, is actually a non-issue even on GCN so we could set
> >> the flag safely.
> >
> > Consider stride 0 and stride < element size, though.  I'm currently
> > thinking of how/where to add the proper versioning decision for that.
>
> I'm generally of the opinion that the compiler should not compromise the
> speed of well written code to cover whatever abomination somehow manages
> to convince the autovectorizer to generate zero stride lengths.
>
> My interest is in OpenMP/OpenACC where the multithreading already
> destroyed all notion of left-to-rightness that the vectorizer tries so
> hard to preserve. In these cases, the end-user has declared and promised
> that the loop iterations are independent, and if it turns out that's not
> the case, then that's on them.
>
> However, if riscv has the instructions and hardware to handle that case,
> would it not naturally fall to the "scatter_store" expander to handle
> these cases? This feeling like a back-end decision, to me.
>
> Or, are you thinking of versioning it in gimple, somehow? I assume this
> would require knowing how the backend instruction handles the writes...
> would the plan be to never ask the backend to do something in-order if
> it can't promise that?

It's when the vectorizer vectorizes a store with an invaraint but not
known non-zero stride or when there a scatter pattern

  for (int i ...)
    a[b[i]] = ...;

where we cannot obviously "prove" there's no dependence between
a[b[0]] and a[b[1]] that we can either not vectorize or have a left-to-right
scatter operation.  For strided stores we can version on the invariant
stride being non-zero (or again rely on left-to-right, which riscv supports)

Sure if the user writes a #pragma ivdep or similar openacc/openmp
annotation we do not have to do dependence checking and are free
to use unordered variants.

Richard.

>
> Andrew
  
Robin Dapp July 29, 2026, 9:19 a.m. UTC | #30
> I'm generally of the opinion that the compiler should not compromise 
> the speed of well written code to cover whatever abomination somehow 
> manages to convince the autovectorizer to generate zero stride 
> lengths.

Just suppose we have a (runtime) variable stride like in x264.

Here, as well as with general scatter (just an array of offset from a 
base address) we have no easy way of knowing whether the access is not 
overlapping.  Thus, we need to conservatively assume overlap takes place 
and basically always have to assume the mem is "left to right".

Even if the stride is statically known and large there can be overlap in 
case we cannot analyze the dataref.

> My interest is in OpenMP/OpenACC where the multithreading already 
> destroyed all notion of left-to-rightness that the vectorizer tries so 
> hard to preserve. In these cases, the end-user has declared and 
> promised that the loop iterations are independent, and if it turns out 
> that's not the case, then that's on them.
>
> However, if riscv has the instructions and hardware to handle that case, 
> would it not naturally fall to the "scatter_store" expander to handle 
> these cases? This feeling like a back-end decision, to me.

> Or, are you thinking of versioning it in gimple, somehow? I assume 
> this would require knowing how the backend instruction handles the 
> writes... would the plan be to never ask the backend to do something 
> in-order if it can't promise that?

Yes, gimple/vect and I'm still undecided how to best ask the backend.  
Unfortunately, riscv's strided store only does unordered accesses and 
cannot switch like our scatters.  If we always fell back to ordered 
scatters, it would likely impact performance (depends on the uarch of 
course) while versioning for stride > element size would allow us to 
always generate strided stores which are potentially faster.
  
Richard Sandiford July 29, 2026, 9:54 a.m. UTC | #31
Andrew Stubbs <ams@baylibre.com> writes:
> On 28/07/2026 17:21, Richard Sandiford wrote:
>> Andrew Stubbs <ams@baylibre.com> writes:
>>> On 28/07/2026 12:54, Richard Biener wrote:
>>>> [...]
>>>> Just to add that (mem:<vector> ..) with unordered semantics ties us
>>>> to that
>>>> unless we want to have a flag on the mem to have left-to-right semantics.
>>>> Given it in theory should be made to fit gather/scatter modelling
>>>> (ignoring
>>>> the masking representational issue).  So I'd like at least that
>>>> thought out,
>>>> if not documented and implemented (having the flag and printing it).
>> 
>> Agreed FWIW.
>> 
>> I think it would be good to think about the masking issue too, given
>> Robin's parallel discussion about having a better representation of
>> predication.  Again, just in terms of having a plausible approach
>> thought out, rather than being implemented in the first version.
>> 
>>> I believe the /i and /s flags are available, if we should choose to use
>>> them.
>>>
>>> Would a target hook not be sufficient though? These things are likely to
>>> be true always or never, for any given mode, on most architectures.
>>>
>>> Better even, as such flags are somewhat likely to "get lost" in all the
>>> random places that manipulate MEM.
>> 
>> Please don't use a hook! :)  IMO RTL semantics should stand on their own
>> as far as possible.  I realise there are exceptions, like STORE_FLAG_VALUE
>> and SHIFT_COUNT_TRUNCATED, but even there, I think it would have been
>> better to make the RTL operators self-descriptive and use the macros
>> to control which operator is generated.
>> 
>> Making SHIFT_COUNT_TRUNCATED apply to all shift rtxes has been a problem
>> in the past and using a hook here might end up the same way.
>
> OK, let's say MEM_IN_ORDER_WRITE with /i then? If the flag is not 
> present then the order is undefined. It could work the other way around, 
> but this seemed to fit nicer with "i".

I'm not sure it should be MEM_IN_ORDER_WRITE vs not.  That seems more
like a property of the operation, rather than a property of the mem
object itself.

Instead I think the useful information is "guaranteed indepenent addresses"
vs not, where "independent" means "not overlapping".  As discussed downthread,
we'd have to assume that addresses might overlap unless we have specific
information to the contrary, so I think "independent" should be 1 and the
default/conservative "possibly overlapping" should be 0.

Then we could define, for now, that setting a mem whose addresses might
overlap is done left-to-right, as a scatter.

Thanks,
Richard
  
Andrew Stubbs July 29, 2026, 10:34 a.m. UTC | #32
On 29/07/2026 09:52, Richard Biener wrote:
> On Wed, Jul 29, 2026 at 10:38 AM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>>
>>>> Also, since scatter operations use fixed strides the question of
>>>> in-order, or not, is actually a non-issue even on GCN so we could set
>>>> the flag safely.
>>>
>>> Consider stride 0 and stride < element size, though.  I'm currently
>>> thinking of how/where to add the proper versioning decision for that.
>>
>> Ah, that might only be an issue for riscv where we allow byte strides.
>> For a regular scatter with at least element stride, this would be ok I
>> guess.
> 
> scatter is not fixed stride but base address + vector of offsets where
> offsets need not be distinct.

Sorry, I always forget that it's used primarily for fixed stride 
accesses, but not actually limited to that.

Andrew
  
Andrew Stubbs July 29, 2026, 10:53 a.m. UTC | #33
On 29/07/2026 10:54, Richard Sandiford wrote:
> Andrew Stubbs <ams@baylibre.com> writes:
>> On 28/07/2026 17:21, Richard Sandiford wrote:
>>> Andrew Stubbs <ams@baylibre.com> writes:
>>>> On 28/07/2026 12:54, Richard Biener wrote:
>>>>> [...]
>>>>> Just to add that (mem:<vector> ..) with unordered semantics ties us
>>>>> to that
>>>>> unless we want to have a flag on the mem to have left-to-right semantics.
>>>>> Given it in theory should be made to fit gather/scatter modelling
>>>>> (ignoring
>>>>> the masking representational issue).  So I'd like at least that
>>>>> thought out,
>>>>> if not documented and implemented (having the flag and printing it).
>>>
>>> Agreed FWIW.
>>>
>>> I think it would be good to think about the masking issue too, given
>>> Robin's parallel discussion about having a better representation of
>>> predication.  Again, just in terms of having a plausible approach
>>> thought out, rather than being implemented in the first version.
>>>
>>>> I believe the /i and /s flags are available, if we should choose to use
>>>> them.
>>>>
>>>> Would a target hook not be sufficient though? These things are likely to
>>>> be true always or never, for any given mode, on most architectures.
>>>>
>>>> Better even, as such flags are somewhat likely to "get lost" in all the
>>>> random places that manipulate MEM.
>>>
>>> Please don't use a hook! :)  IMO RTL semantics should stand on their own
>>> as far as possible.  I realise there are exceptions, like STORE_FLAG_VALUE
>>> and SHIFT_COUNT_TRUNCATED, but even there, I think it would have been
>>> better to make the RTL operators self-descriptive and use the macros
>>> to control which operator is generated.
>>>
>>> Making SHIFT_COUNT_TRUNCATED apply to all shift rtxes has been a problem
>>> in the past and using a hook here might end up the same way.
>>
>> OK, let's say MEM_IN_ORDER_WRITE with /i then? If the flag is not
>> present then the order is undefined. It could work the other way around,
>> but this seemed to fit nicer with "i".
> 
> I'm not sure it should be MEM_IN_ORDER_WRITE vs not.  That seems more
> like a property of the operation, rather than a property of the mem
> object itself.
> 
> Instead I think the useful information is "guaranteed indepenent addresses"
> vs not, where "independent" means "not overlapping".  As discussed downthread,
> we'd have to assume that addresses might overlap unless we have specific
> information to the contrary, so I think "independent" should be 1 and the
> default/conservative "possibly overlapping" should be 0.
> 
> Then we could define, for now, that setting a mem whose addresses might
> overlap is done left-to-right, as a scatter.

Agreed, MEM_INDEPENDENT works too, and still fits /i neatly.

However, this implies that there might be multiple ways to handle 
non-independent MEMs, and I think that's not true: it really does have 
to be in-order or nothing.

Anyway, this matters little to me. I'm happy to specify whichever. It'll 
be trivial to set the flag in my code, and only targets that accept 
vectors as "legitimate addresses" will be affected, which means only GCN 
to start.

Andrew