将单个字节从内存移动到 xmm 寄存器作为 float

Move single byte from memory to xmm register as float

如何从内存中的地址检索单个字节并将其 作为浮点数移动到 xmm 寄存器中? (例如,如果在地址位置有一个字节 123,我希望能够使用 sse 指令对该值、123+5 等进行浮点运算。)

我是汇编的新手,我希望这个问题是有道理的。我已经相当随机地尝试了几件事(例如首先移动到 al 然后从那里移动到 xmm - 但不知道如何继续转换为 float ...);也许有人可以指出正确的方向?

明显的标量方式,就像您从编译器中获得的那样 (http://godbolt.org/):

movzx     eax,  byte [mem]         ; zero extend.  Use movsx to sign-extend
cvtsi2ss  xmm0, eax

这在 Sandybridge 系列上总共花费了 3 个微指令。 (cvtsi2ss 是 2)。

注意cvtsi2ss设计的不好,合并到XMM0的旧值,所以有假依赖。 gcc 倾向于 pxor xmm0,xmm0 首先打破依赖关系,但如果最近没有使用 XMM0 那么你应该没问题。使用 AVX,您可以将一个 XMM 寄存器置零,然后将其重复用作多个转换的安全无依赖源。

vxorps   xmm0, xmm0, xmm0

;then repeated multiple times:
vcvtsi2ss  xmm1, xmm0, eax       ; xmm1 is write-only, no false dep

如果 SSE4.1 可用,并且可以读取超出所需字节的 3 个字节(不会因读取未映射的页面而发生段错误,也不会因缓存行或页面拆分而出现性能问题),那么您可以这样做这个:

pmovzxbd    xmm0,  dword [mem]       ; byte->dword packed zero extend
cvtdq2ps    xmm1,  xmm0              ; packed-convert of int32 to float

这在 SnB 系列上总共花费 2 个微指令:pmovzx/sx XMM 目的地可以微熔断负载。 (但不是 AVX2 YMM 版本)。 (http://agner.org/optimize/).

当然,如果您确实想要转换 4 个连续的字节,这当然很棒。否则,如果您有多个转化,您可能会随机设置 cvt 指令。