On 23/06/2026 13:28, Michael Matz wrote:
Hello,
On Mon, 22 Jun 2026, Andrew Stubbs wrote:
TARGET_POINTER_MODE and TARGET_ADDR_SPACE_POINTER mode only
return one mode,
but now we have multiple valid modes: DImode, V2DImode,
V4DImode, etc. They
also return scalar_int_mode so I can't even invent a new address
space for
the vector pointers.
Same for TARGET_ADDR_SPACE_ADDRESS_MODE.
TARGET_VALID_POINTER_MODE and
TARGET_ADDR_SPACE_VALID_POINTER_MODE only
accept scalar_int_mode, so automatically exclude vector pointers.
These can be patched to use plain machine_mode, perhaps, or keep
them all
scalar and add a new TARGET_ADDR_SPACE_ALLOWS_VECTOR_POINTERS to
fix the
problem at the call sites, which might make more sense?
I've been working on this proposal some more. I've solved the
above problem by
keeping all the hooks returning pointer/address types scalar, but
changing
TARGET_ADDR_SPACE_VALID_POINTER_MODE to accept vector types, so
the backend
can approve them. When the target independent code encounters a
vector of
addresses it checks that the inner mode matches the appropriate
hook values.
I was hoping to post a patch series this week, but I've hit
against another
issue.....
I have an insn that looks like this:
(set (reg:V64SI 123)
(vec_merge:V64SI
(mem:V64SI (reg:V64DI 456))
(reg:V64SI 123)
(reg:DI 789)))
How would anything in RTL-land see that this load is masked?
There's no
info anywhere that makes it differ from
(set (reg:V64SI 123)
(vec_merge:V64SI
(mem:V64SI (reg:V64DI 456))
(reg:V64SI 123)
(reg:DI 789)))
with me saying that this is a vector merge operation with a memory
operand
that is loaded completely. It's a verbatim copy of your RTL
pattern. See
my point? :)
I'm pretty sure you just restated my point. ;-)
I can workaround the "reload" in the backend by using unspecs
(exactly
what I was trying to avoid), but does anyone have a better
suggestion?
(a) unspec
(b) teaching RTL-land generally that vec_merge(...(mem)) is
"special" and
its operands cannot just be lifted out (nah)
(c) biting the bullet and introduce and set a flag on (mem)s that
it is
"special"/partial
(c') similar flag on the vec_merge
(d) biting a different bullet and introduce a new top-level RTL
expression
(partial_mem:mode (addr) (mask)) (with either target-
defined methods
to specify content of unselected bits/bytes, or with a
third operand
to specify them (which then makes this just a different
vec_merge)
I think (d) is most elegant and most involved, (c) or (c') are the
"best"
on a cost/benefit basis, (b) the most hacky, but may be fine if
done via a
target hook and (a) the easiest but most unelegant. (a) has
subcases:
where to put the unspec: around the (mem), around the (vec_merge),
around
the whole (set). IMHO, around the vec_merge makes "most sense",
whatever
that means for unspecs, but, well, still unspecs :-/
I've been working to implement an unspec solution in the backend, for
now, so that I can move on with this and get the actually working bits
proposed.
Putting an unspec around the whole pattern doesn't help. Nor does
replacing the vec_merge with an unspec. In both cases the register
allocator happily tries to break out the MEM, just as before.
I tried creating an unspec that matches a custom memory constraint
(the
idea being that it will drop into the existing vec_merge patterns),
but
the register allocator now breaks out the unspec into another
step. If
I use a non-memory-specific constraint then the same thing
happens. If
I place the mask inside the unspec and have a specific instruction
handle that, then it works, but now I have a masked load feeding
into a
masked move for no good reason.
Here's what it looks like now:
(set (reg:V64SI 123)
(vec_merge:V64SI
(mem:V64SI (unspec:V64DI [(reg:V64DI 456) (reg:DI 789)]
UNSPEC_PARTIAL_ADDRVEC))
(reg:V64SI 123)
(reg:DI 789)))
Note that the mask register, r789, now also appears within the MEM.
When
reload tries to break it out, gen_movv64si sees the new unspec and
expands to a masked load. The new instruction is basically
identical to
the one that it came from, but reload seems happy now, and my program
runs correctly without the memory fault.