是否可以在不使用通用寄存器的情况下将 8 位从 XMM 寄存器移动到内存?

It is possible move 8 bits from an XMM register to memory without using general purpose registers?

我需要在不使用通用寄存器的情况下将 1 个字节从 xmm 寄存器移动到内存。而且我也不能使用 SSE4.1。有可能吗?

=(

通常您首先会想避免这种情况。例如,除了单独的字节存储,你能做一个更广泛的加载和合并(pand/pandn/por 如果你没有 pblendvb),然后存储回合并结果吗?

这不是线程安全的(未修改字节的非原子 RMW),但只要您知道您是 RMWing 的字节就不会超出数组或结构的末尾,也不会超出其他线程对同一个 array/struct 中的其他元素做同样的事情,这是在不修改其他字节的情况下对字符串中的每个小写字母进行大写之类的正常方法。


单 uop 存储只能来自 4、8、16、32 或 64 字节大小的向量寄存器,AVX-512BW masked stores 除外,只有 1 个元素未被屏蔽。像 pextrb 这样更窄的存储涉及一个 shuffle uop 来提取要存储的 2 或 1 个字节。

在没有 GP 整数 regs 的情况下真正准确存储 1 个字节的唯一好方法是使用 SSE4.1 pextrb [mem], xmm0, 0..15 即使立即使用 [=16],这仍然是随机播放 + 存储=] 在当前的 CPU 上。 如果您可以安全地在目标位置写入 2 个字节,则 SSE2 pextrw 可用。

可以 使用 SSE2 maskmovdqu 字节掩码存储(使用 0xff,0,0,... 掩码),但您不想这样做,因为它慢得多比 movd eax, xmm0 / mov [mem], al。例如在 Skylake 上,10 微指令,每 6 个周期吞吐量 1 个。

如果你想在之后重新加载字节,情况会更糟,因为(与 AVX / AVX-512 掩码存储不同),maskmovdqu 具有 NT 语义,如 movntps(旁路缓存,或如果以前很热,则逐出缓存行。


如果你的要求完全是人为的,你只是想玩愚蠢的计算机技巧(避免在寄存器中使用你的数据),你也可以设置 scratch space 例如在堆栈上并使用 movsb 复制它:

;; with destination address already in RDI
    lea  rsi, [rsp-4]          ; scratch space in the red zone below RSP on non-Windows
    movd  [rsi], xmm0
    movsb                   ; copy a byte, [rdi] <- [rsi], incrementing RSI and RDI

这显然比正常方式慢,并且需要一个额外的寄存器 (RSI) 用于 tmp 缓冲区地址。并且您需要 RDI 中的确切目标地址,而不是 [rel foo] 静态存储或任何其他灵活的寻址模式。

pop 也可以复制 mem-to-mem,但仅适用于 16 位和 64 位操作数大小,因此它不能使您免于需要 RSI 和 RDI。

由于上面的方式需要一个额外的寄存器,它几乎在所有方面都比正常方式差:

   movd  esi, xmm0            ; pick any register.
   mov   [rdi], sil           ; al..dl would avoid needing a REX prefix for low-8


;; or even use a register where you can read the low and high bytes separately
   movd  eax, xmm0
   mov   [rdi], al            ; no REX prefix needed, more compact than SIL
   mov   [rsi], ah            ; scatter two bytes reasonably efficiently
   shr   eax, 16              ; bring down the next 2 bytes

(读取 AH 在当前的 Intel CPU 上有一个额外的延迟周期,但这对吞吐量来说很好,我们无论如何都存储在这里,所以延迟不是一个很大的因素。)

xmm -> GP 整数传输在大多数 CPU 上并不慢。 (Bulldozer 系列是异常值,但它的延迟仍然与 store/reload 相当;Agner Fog 在他的微架构指南 (https://agner.org/optimize/) 中说,他发现 AMD 对 store/reload 的优化手册建议并不快.)

很难想象 movsb 会更好,因为您已经需要一个免费的寄存器,而 movsb 是多个 uops。可能如果在当前英特尔 CPU 上 movd r32, xmm 端口 0 微码出现瓶颈? (https://uops.info/)