【问题标题】:MOVQ/PINSRQ vs VMOV to populate XMM (one works, the other doesn't)MOVQ/PINSRQ 与 VMOV 填充 XMM(一个有效,另一个无效)
【发布时间】:2020-02-13 17:18:02
【问题描述】:

在我的学习过程中,我开始尝试使用 AVX 指令并编写了一个简单的数组乘法,只是为了让事情正常工作,非常基础。 第一个问题是 xmm0 和 xmm1 的填充,因为 nasm 不接受 XMMWORD 作为大小(yasm 接受它,但由于它不再开发,我不想使用它),我不得不填充 2 个 64 位步骤。 我发现this thread 展示了适合我的解决方案,使用了 MOVQ 和 PINSRQ。 (某种)工作的代码是:

section .data
array1: dd  1.0, 2.0, 3.0, 4.0  ; Declares 2 arrays of 16 bytes
array2: dd  2.0, 3.0, 4.0, 5.0

section .text
global _start
_start:

mov     r8, qword array1        ; Stores the address of the 1st element
mov     r9, qword array2        ; of each array in the registers
movq    xmm0, r8                ; Populates the first half of xmm0
pinsrq  xmm0, r8, 1             ; Populates the second half   
movq    xmm1, r9                ; The same for xmm1
pinsrq  xmm1, r9, 1
vmulps  xmm0, xmm1              ; Multiplies the arrays and save in xmm0

xor     ebx, ebx
mov     rax, 1
int     80h

但在我找到这个解决方案之前,我正在尝试:

vmovlps xmm0, qword [r8]
vmovhps xmm0, qword [r8 + 8]

这些应该填充 xmm0 寄存器的低位,然后是高位,但程序在第一个 vmov 中崩溃。那么,你们能解释一下为什么这对 mov 不起作用,而 movq/pinsrq 对却能正常工作吗?如果在这个简单的过程中有任何可以改进的地方,请随时提出建议。

========= 编辑、更新 ========

只是为了尝试将结果放回内存中,以便 rdi 指向 xmm0 中保存的 4 个 32 位值中的第一个,以防万一我想返回 rdi,这会组合输出(由 C++ 程序打印) ) 是垃圾,所以显然是错误的方式:

vmulps  xmm0, xmm1     ; Multiplies the arrays and save in xmm0
vmovdqa [rdi], xmm0    ; Assembles and doesn't crash, but no meaningful result

【问题讨论】:

  • nasmmovupdmovapd 没有问题,如果您的数组是对齐的。
  • movq xmm0, r8 将地址放入 XMM reg 中。 vmovlps xmm0, qword [r8] 加载指向的 qword。 (效率低下,使用错误的依赖项和合并 uop;使用 movqmovsd,而不是 movlps,除非您需要 SSE1 兼容性。但是您使用的是 AVX 编码。)顺便说一句,请确保您了解 SSE/ Haswell/Icelake 与 Skylake 中的 AVX 转换惩罚,以确保如果您使用 YMM 寄存器,而不仅仅是 AVX-128,您不会在脚下开枪。
  • 感谢两位 cmets。小丑,我将尝试 movupd/movapd(我实际上已经尝试过使用 vmov 变体,但 vmulps 只作用于 2 个元素,所以我认为我的加载不正确)。彼得,我会注意你说的话,因为我不需要任何 SSE 兼容性并且打算只使用 AVX。如果你们中的任何人想提出答案,我很乐意接受,因为我的疑问现在已经澄清。
  • @PeterCordes 如果我可以要求您再澄清一点, movlps/movhps 列在 AVX 指令集中。由于我使用的是 xmm 而不是 ymm,所以您对混合 SSE/AVX 的评论是什么?
  • movhps 是 SSE1。 vmovhps 是 AVX1。 felixcloutier.com/x86/movhps。至于回答这个问题:你所说的一切似乎都是倒退的。您说从[r8] 插入不起作用,但插入r8 可以。请注意,您链接的答案是将立即常量插入 XMM 寄存器,这就是您对 64 位绝对地址所做的事情。我想知道您是否尝试在来自vmulps/vmovdqa 的浮点数上使用printf,但这样做也是错误的,而不是使用调试器。你不能printf一个浮点数,你需要转换成双精度。

标签: assembly x86-64 nasm


【解决方案1】:

我只是想发布有效的代码,在阅读了更多文档并且不做艰难的事情之后:

global mul_array_float         ; mul_array_float(float &array1, float *array2)
mul_array_float:
    vmovups xmm0, [rdi]    ; populates xmm0 and xmm1 with rdi and rsi being
    vmovups xmm1, [rsi]    ; passed by the function call
    vmulps  xmm0, xmm1     ; multiply them and save result in xmm0
    vmovups [rdi], xmm0    ; return the result to rdi (being passed by reference)
    ret

如果函数以对齐方式传递数组,则“ups”指令不会造成速度损失。感谢 Peter Cordes 和 Jester 的考虑。

【讨论】:

    猜你喜欢
    • 2020-02-29
    • 2020-07-28
    • 1970-01-01
    • 2015-04-26
    • 2019-11-22
    • 2019-08-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    相关资源
    最近更新 更多