[英]Why doesn't gcc zero the upper values of an XMM register when only using the lower value with SS/SD instructions?
例如用这样的 function,
int fb(char a, char b, char c, char d) {
return (a + b) - (c + d);
}
gcc
的总成 output 是,
fb:
movsx esi, sil
movsx edi, dil
movsx ecx, cl
movsx edx, dl
add edi, esi
add edx, ecx
mov eax, edi
sub eax, edx
ret
含糊地,我知道movsx
的目的是从寄存器的先前值中删除依赖关系,但老实说,我仍然不明白它试图删除什么样的依赖关系。 我的意思是,例如,是否存在movsx esi, sil
,如果某个值被写入esi
,那么使用esi
的任何操作都必须等待,如果从esi
读取值,任何修改值的操作esi
将不得不等待,如果esi
没有被任何操作使用,代码将继续运行。 movsx
有什么不同? 我不能说编译器做错了,因为movsx
或movzx
(几乎?)在加载小于 32 位的值时总是由任何编译器生成。
除了我缺乏理解之外, gcc
的行为与float
不同。
float ff(float a, float b, float c, float d) {
return (a + b) - (c + d);
}
编译为,
ff:
addss xmm0, xmm1
addss xmm2, xmm3
subss xmm0, xmm2
ret
如果应用相同的逻辑,我相信 output 应该是这样的,
ff:
movd xmm0, xmm0
movd xmm1, xmm1
movd xmm2, xmm2
movd xmm3, xmm3
addss xmm0, xmm1
addss xmm2, xmm3
subss xmm0, xmm2
ret
所以我实际上是在问两个问题。
gcc
的行为与float
不同?movsx
有什么不同?返回值与 args 的宽度相同,因此不需要扩展。 在 x86 和 x86-64 调用约定中,允许类型宽度之外的寄存器部分保存垃圾。 (这适用于 GP integer 和向量寄存器。)
除了 clang 依赖的未记录扩展外,调用者将窄参数扩展到 32 位; clang 将跳过您的char
示例中的movsx
指令。 https://godbolt.org/z/Gv5e4h3Eh
向 x86-64 ABI 的指针添加 32 位偏移时是否需要符号或零扩展? 涵盖了高垃圾和调用约定的非官方扩展。
由于您询问了错误依赖项,请注意编译器确实使用movaps xmm,xmm
来复制标量。 (例如,在(ab) + (ad)
中 GCC 错过的优化中,我们需要从a
中减去两次。它是不可交换的,所以我们需要一个副本: https://godbolt.org/z/Tvx19raa3
C integer 提升规则意味着窄输入的a+b
等价于(int)a + (int)b
。 在所有 x86 / x86-64 ABI 中, char
是有符号类型(例如,与 ARM 不同),因此需要将其符号扩展为int
宽度,而不是零扩展。 并且绝对不会被截断。
如果您通过返回char
再次截断结果,编译器可以只做 8 位加法。 但实际上他们将使用 32 位添加并在那里留下任何高垃圾: https://godbolt.org/z/hGdbecPqv 。 这样做不是为了破坏/性能,只是为了正确。
就性能而言,如果调用者编写了完整的寄存器(调用约定的非官方扩展无论如何都需要),或者在不单独重命名低 8 的 CPU 上,GCC 读取char
的 32 位 reg 的行为很好来自 reg 的 rest (除 P6 系列之外的所有内容:SnB 系列仅重命名高 8 regs,除了原始 Sandybridge 本身。 为什么 GCC 不使用部分寄存器? )
PS:没有像movd xmm0, xmm0
这样的指令,只有一种不同形式的movq xmm0, xmm0
,可以将 XMM 寄存器的低 64 位零扩展为完整的寄存器。
如果您想查看各种编译器尝试对低 dword 进行零扩展,无论是否使用 SSE4.1 insertps
,请查看 asm for __m128 foo(float f) { return _mm_set_ss(f); }
__m128 foo(float f) { return _mm_set_ss(f); }
在上面的 Godbolt 链接中。 例如,仅使用 SSE2,使用 pxor 将寄存器归零,然后movss xmm1, xmm0
。 否则, insertps
或 xor-zero 和blendps
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.