I am playing with a bit of SSE assembly code in which I do not have enough xmm
registers to keep all the temporary results and useful constants in registers at the same time.
As a workaround, for some constant vectors that have identical components, I “compress” several vectors into a single xmm
register, xmm14
below. I use the pshufd
instruction to decompress the constant vector I need. This instruction has a bit of latency, but since it takes a source and a destination register, it is otherwise very convenient:
…
Lfour_15_9:
.long 4
.long 1549556828
.long 909522486
.long 0
…
movdqa Lfour_15_9(%rip), %xmm14
…
pshufd $0, %xmm14, %xmm4
paddd %xmm4, %xmm3
…
pshufd $0b10101010, %xmm14, %xmm5
…
pshufd $0b10101010, %xmm14, %xmm5
…
pshufd $0b01010101, %xmm14, %xmm5
xorps %xmm5, %xmm2
movaps %xmm5, 112(%rax)
The above code is in gas/AT&T syntax and I am targeting Intel processors from Core 2 to Westmere, that offer instructions up to SSSE3.
One of Agner Fog's manuals points out that for some uses, it may be advantageous to use vector instructions that have the wrong “type”. For instance, memcpy
is advantageous to write with movaps
instructions even if the data being moved is not floating-point because movaps
is shorter than movdqa
, is available on more processors, and since it does not compute with the data, none of the usual caveats about subnormals apply. The same advice is given for shuffling words around (sections 13.2 and 13.3 in the manual I linked to earlier).
My case is a bit special because of the constant vectors I aim to reconstitute, some can, if necessary, be used with only single-precision “type” instructions: these will be involved only in movaps
, shufps
, xorps
computations. And some constant vectors will have to participate into computations that can only be done with integer-type instructions: paddd
(and thus I can use movdqa
, pshufd
and pxor
instructions as necessary to remain in the integer execution domain).
The general version of this question is: considering that I am targeting Intel processors between Core 2 and Westmere, what types of instructions should I use respectively to (re-)load xmm14
from memory, to uncompress it to a register that will only see single-precision computations, to uncompress it to a register that will see some computations that cannot be done with single-precision instructions, and for those operations that can be done with single-precision instructions in the latter case?
EDIT: The part of the question below this point was answered by harold in a comment.
And a more specific sub-question that's included in the general question: does anyone have an explanation for why, when I randomly replace some integer execution domain instructions by floating-point instructions (e.g. movdqa
instructions by movaps
instructions), the function can compute wrong? I expected the only consequence would be execution delays, not wrong results.
For instance, if in the above I change only the pshufd $0, %xmm14, %xmm4
instruction to a shufps
one, the computations become completely wrong (xmm4
is the register that is involved in a paddd
later). Changing other instructions instead of that one result in other kinds of errors.