有没有一种方法可以增加 xmm 寄存器中的值?

3

我想知道,是否有办法增加 xmm 寄存器中的值,或者你只能将一个值移动到其中?

我的意思是,您可以这样做:

inc eax

或者像这样:
inc [ebp+7F00F000]

有没有办法使用xmm完成相同的操作?

我尝试了类似的方法,但是...它并没有起作用。

  inc [rbx+08]
  movss xmm1,[rbx+08]

我甚至尝试了一些非常愚蠢的方法,但它们也没有起作用。
push edx
pextrw edx,xmm2,0
add edx,1
mov [rbx+08],edx
movss xmm1,[rbx+08]
pop edx

你想要增加 xmm 寄存器中的所有整数值,还是只增加单个值? - galinette
1
可能是在x86中将常量值添加到xmm寄存器的重复问题。 - Hans Passant
1
@HansPassant:这是关于浮点数的问题。但这个问题似乎不是,因为它使用整数incpextrw。否则,OP可能真的很困惑。如果它应该是关于浮点数的问题,那么显然你只需要添加一个向量,其中所有元素都为零,除了一个元素。(或者如果是低元素,则使用addss,因为这些指令与旧值合并)。 - Peter Cordes
2个回答

7

对于xmm寄存器,没有inc等效指令,也没有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++

或者

paddw      xmm0, [ones]  ; where ones is a static constant.

如果构造常量需要超过两个指令,或寄存器压力很大,那么从内存加载常量可能是一个好主意。


如果您想构建一个常量,仅递增低32位元素,例如,您可以使用字节移位将其他元素归零:
; 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

如果你尝试递增xmm2中的低16位元素,那么是一个愚蠢的尝试。我不知道你在做什么,存储到[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.

如果你想使用除16位以外的元素进行工作,你可以使用SSE4.1的pinsrb/d/q指令,或者使用movd和shuffles指令。

请参考Agner Fog的优化汇编指南,了解如何更好地使用SSE向量。另外,在标签维基中还有其他链接。


1
简而言之,不是以您所想的方式进行操作。
在SSE下,所有原始的XMM寄存器都是浮点寄存器。浮点数没有增量操作。
SSE2添加了许多整数类型寄存器,但仍然没有增量操作。这些寄存器和添加的操作实际上是为高速算术运算而设计的,包括点积、精确舍入乘积等。
增量操作是您期望在通用寄存器或累加器中找到的操作。
您可能会发现this set of slides对于一般概述和功能有一定的信息价值。

2
SSE2使用相同的XMM寄存器,只是增加了操作整数数据类型的指令,包括b/w/d/q元素大小的整数加法/减法。在XMM寄存器中进行矢量整数加法是完全正常的。如果需要,甚至可以使用它们来实现斐波那契数列生成器。具体请参考此链接:https://dev59.com/cI_ea4cB1Zd3GeqPL0Ot#32661389 - Peter Cordes
彼得,现代AMD / Intel上的SSE2在将int和fp块分开时是否使用相同的XMM寄存器,并且在AMD中它们具有单独的PRF:http://hothardware.com/articleimages/Item1552/BobcatDetail1.jpg - osgx
@osgx:之前没有看到你的回复,因为你没有@提醒我。我指的是相同的架构寄存器。Intel和AMD CPU针对向量整数和向量浮点分别有单独的转发网络。然而,Intel SnB系列明确使用单个PRF来处理所有向量寄存器。由于大多数代码不会同时使用两者,这为相同硅片面积提供了更多的乱序执行能力。我认为Bobcat实际上也是一样的: "int"块是标量整数(通用)寄存器。请注意IntMul单元:FP在这里只是指XMM/MMX/x87。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接