Gec*_*o64 2 x86 assembly sse add
我想知道,有没有办法在xmm寄存器中增加一个值,或者你只能将一个值移动到一个?
我的意思是,你可以这样做:
inc eax
Run Code Online (Sandbox Code Playgroud)
或者像这样:
inc [ebp+7F00F000]
Run Code Online (Sandbox Code Playgroud)
有没有办法用xmm做同样的事情?
我尝试过类似的东西,但......它不起作用
inc [rbx+08]
movss xmm1,[rbx+08]
Run Code Online (Sandbox Code Playgroud)
我甚至尝试过一些非常愚蠢的东西,但它也没有用
push edx
pextrw edx,xmm2,0
add edx,1
mov [rbx+08],edx
movss xmm1,[rbx+08]
pop edx
Run Code Online (Sandbox Code Playgroud)
inc
xmm regs 没有等价物,并且没有立即操作数形式paddw
(所以没有相当于add eax, 1
任何一个).
paddw
(和其他元素大小)仅适用于xmm/m128源操作数.因此,如果要增加向量的一个元素,则需要从内存中加载常量,或者动态生成它.
例如,增加xmm0的所有元素的最便宜的方法是:
; outside the loop
pcmpeqw xmm1,xmm1 # xmm1 = all-ones = -1
; inside the loop
psubw xmm0, xmm1 ; xmm0 -= -1 (in each element). i.e. xmm0++
Run Code Online (Sandbox Code Playgroud)
要么
paddw xmm0, [ones] ; where ones is a static constant.
Run Code Online (Sandbox Code Playgroud)
如果需要两个以上的指令来构造常量,或者寄存器压力是个问题,那么从内存加载常量可能只是一个好主意.
例如,如果要构造一个仅增加低32位元素的常量,则可以使用byte-shift将其他元素归零:
; hoisted out of the loop
pcmpeqw xmm1,xmm1 # xmm1 = all-ones = -1
psrldq xmm1, 12 # xmm1 = [ 0 0 0 -1 ]
; in the loop
psubd xmm0, xmm1
Run Code Online (Sandbox Code Playgroud)
如果你的尝试只是增加xmm2中的低16位元素,那么是的,这是一次愚蠢的尝试.IDK你正在做什么存储[rbx+8]
然后加载到xmm1(将高96位归零).
以下是如何以较少的愚蠢方式编写xmm - > gp - > xmm往返.(paddw
与矢量常数相比仍然很糟糕).
# don't push/pop. Instead, pick a register you can clobber without saving/restoring
movd edx, xmm2 # this is the cheapest way to get the low 16. It doesn't matter that we also get the element 1 as garbage in the high half of edx
inc edx # we only care about dx, but this is still the most efficient instruction
pinsrw xmm2, edx, 0 # normally you'd just use movd again, but we actually want to merge with the old contents.
Run Code Online (Sandbox Code Playgroud)
如果你想使用16bit以外的元素,你可以使用SSE4.1 pinsrb
/ d
/ q
,或者你使用movd
和shuffle.
有关如何使用SSE向量的更多有用提示,请参阅Agner Fog的Optimize Assembly指南.还有x86标签wiki 中的其他链接.