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.