有没有办法增加 xmm 寄存器中的值?

Posted

技术标签:

【中文标题】有没有办法增加 xmm 寄存器中的值?【英文标题】:Is there a way to increase a value in a xmm register? 【发布时间】:2016-07-10 17:11:54 【问题描述】:

我想知道,有没有办法增加 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 寄存器中的所有整数值,还是只增加一个? Add a constant value to a xmm register in x86的可能重复 @HansPassant:这是在询问浮点数。这似乎不是,因为它使用整数incpextrw。否则OP真的很困惑。如果它应该是关于浮点的,那么显然你只需添加一个向量,该向量在除一个之外的所有元素中都为零。 (或者如果它是低元素,则使用addss,因为这些insn 与旧值合并)。 【参考方案1】:

xmm regs 没有 inc 等效项,paddw 也没有立即操作数形式(因此也没有 add eax, 1 等效项)。

paddw (and other element sizes) 仅适用于 xmm/m128 源操作数。所以如果你想增加一个向量的一个元素,你需要从内存中加载一个常量or generate it on the fly。

例如增加 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 位元素,那么是的,这是一个愚蠢的尝试。 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.

如果您想使用 16 位以外的元素,您可以使用 SSE4.1 pinsrb/d/q,或者使用 movd 和随机播放。


请参阅Agner Fog's Optimize Assembly 指南,了解有关如何使用 SSE 向量的更多好技巧。还有x86 标签维基中的其他链接。

【讨论】:

【参考方案2】:

简而言之,不,不是你想的那样。

在 SSE 下,所有原始 XMM 寄存器都是浮点寄存器。浮点数没有自增操作。

SSE2 增加了一些整数类型的寄存器,但是仍然没有增量。这些寄存器和附加操作实际上是为高速算术运算而设计的,包括点积、四舍五入的精确积等。

增量操作是您希望发现应用于通用寄存器或累加器的东西。

您可能会发现 this set of slides 在一般概述和功能方面提供了一些信息。

【讨论】:

SSE2 使用相同的 XMM 寄存器,它只是添加了对整数数据类型进行操作的指令,包括用于 b/w/d/q 元素大小的整数加法/减法。在 XMM regs 中进行向量整数相加是完全正常的。如果您愿意,您甚至可以将它们用于implement a Fibonacci sequence generator。 Peter,当 int 和 fp 块分开时,现代 AMD/Intel 上的 SSE2 是否对 int 和 fp 使用相同的 XMM 寄存器,并且在 AMD 中它们有单独的 PRF:hothardware.com/articleimages/Item1552/BobcatDetail1.jpg @osgx:之前没有看到你的回复,因为你没有@-通知我。我的意思是相同的架构寄存器。 Intel 和 AMD CPU 对 vector-int 和 vector-fp 有单独的转发网络。但是,Intel SnB 系列肯定是uses a single PRF for all vector registers.。由于大多数代码不会同时使用两者,这为相同的硅区域提供了更多的乱序执行能力。我认为山猫实际上是一样的:“int”块是标量整数(通用)寄存器。注意 IntMul 单位:FP 在这里仅表示 XMM/MMX/x87。

以上是关于有没有办法增加 xmm 寄存器中的值?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法利用所有 XMM 寄存器?

XMM 寄存器中的取消引用指针(收集)

将XMM寄存器推入堆栈

如何将浮点常量值移动到xmm寄存器中?

xmm 寄存器 sse x64 里面的值

XMM 寄存器值