x86_64: Some SUBREG related optimization tweaks to i386 backend.
authorRoger Sayle <roger@nextmovesoftware.com>
Wed, 13 Oct 2021 18:49:47 +0000 (19:49 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Wed, 13 Oct 2021 18:49:47 +0000 (19:49 +0100)
commit97c320016642a40a347d558abc952cc487ad4ff6
treee89dbe617cd88bbd6b9b683172b149d1c9ceab1c
parent90582eb6c565afb9cef89c1781af6d9a96b086e9
x86_64: Some SUBREG related optimization tweaks to i386 backend.

This patch contains two SUBREG-related optimization enabling tweaks to
the x86 backend.

The first change, to ix86_expand_vector_extract, cures the strange
-march=cascadelake related non-determinism that affected my new test
cases last week.  Extracting a QImode or HImode element from an SSE
vector performs a zero-extension to SImode, which is currently
represented as:

(set (subreg:SI (reg:QI target)) (zero_extend:SI (...))

Unfortunately, the semantics of this RTL doesn't quite match what was
intended.  A set of a paradoxical subreg allows the high-bits to take
an arbitrary value (hence the non-determinism).  A more correct
representation should be:

(set (reg:SI temp) (zero_extend:SI (...))
(set (reg:QI target) (subreg:QI (reg:SI temp))

Optionally with the SUBREG rtx annotated as SUBREG_PROMOTED_VAR_P to
indicate that value is already zero-extended in the SUBREG_REG.

The second change is very similar, which is why I've included it in
this patch, where currently the early RTL optimizers can produce:

(set (reg:V?? hardreg) (subreg ...))

where this instruction may require a spill/reload from memory when
the modes aren't tieable.  Alas the presence of the hard register
prevents combine/gcse etc. optimizing this away, or reusing the result
which would increase the lifetime of the hard register before reload.

The solution is to treat vector hard registers the same way as the
x86 backend handles scalar hard registers, and only allow sets from
pseudos before register allocation, which is achieved by checking
ix86_hardreg_mov_ok.  Hence the above instruction is expanded and
maintained as:

(set (reg:V?? pseudo) (subreg ...))
(set (reg:V?? hardreg) (reg:V?? pseudo))

which allows the RTL optimizers freedom to optimize the SUBREG.

2021-10-13  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
* config/i386/i386-expand.c (ix86_expand_vector_move):  Use a
pseudo intermediate when moving a SUBREG into a hard register,
by checking ix86_hardreg_mov_ok.
(ix86_expand_vector_extract): Store zero-extended SImode
intermediate in a pseudo, then set target using a SUBREG_PROMOTED
annotated subreg.
* config/i386/sse.md (mov<VMOVE>_internal): Prevent CSE creating
complex (SUBREG) sets of (vector) hard registers before reload, by
checking ix86_hardreg_mov_ok.
gcc/config/i386/i386-expand.c
gcc/config/i386/sse.md