在混合上下文中选择 SSE 指令执行域
Choosing SSE instruction execution domains in mixed contexts
我正在玩一些 SSE 汇编代码,其中我没有足够的 xmm
寄存器来同时将所有临时结果和有用的常量保存在寄存器中。
作为一种解决方法,对于一些具有相同组件的常数向量,我将几个向量“压缩”到一个 xmm
寄存器中,如下 xmm14
。我使用 pshufd
指令来解压缩我需要的常数向量。该指令有一点延迟,但由于它需要一个源寄存器和一个目标寄存器,否则非常方便:
…
Lfour_15_9:
.long 4
.long 1549556828
.long 909522486
.long 0
…
movdqa Lfour_15_9(%rip), %xmm14
…
pshufd [=10=], %xmm14, %xmm4
paddd %xmm4, %xmm3
…
pshufd [=10=]b10101010, %xmm14, %xmm5
…
pshufd [=10=]b10101010, %xmm14, %xmm5
…
pshufd [=10=]b01010101, %xmm14, %xmm5
xorps %xmm5, %xmm2
movaps %xmm5, 112(%rax)
以上代码采用 gas/AT&T 语法,我的目标是从 Core 2 到 Westmere 的 Intel 处理器,它们提供高达 SSSE3 的指令。
Agner Fog's manuals 中的一位指出,对于某些用途,使用“类型”错误的向量指令可能更有利。例如,即使移动的数据不是浮点数,memcpy
也有利于使用 movaps
指令写入,因为 movaps
比 movdqa
短,可用于更多处理器,并且由于它不使用数据进行计算,因此适用 none 关于次正规的常见警告。对于改组单词也给出了相同的建议(我之前链接到的手册中的第 13.2 和 13.3 节)。
我的情况有点特殊,因为我打算重构常量向量,如有必要,有些可以仅与单精度“类型”指令一起使用:这些将仅涉及 movaps
, shufps
, xorps
计算。并且一些常数向量将不得不参与只能使用整数类型指令完成的计算:paddd
(因此我可以使用 movdqa
、pshufd
和 pxor
指令根据需要保留在整数执行域中)。
这个问题的一般版本是:考虑到我的目标是 Core 2 和 Westmere 之间的 Intel 处理器,我应该分别使用什么类型的指令从内存(重新)加载 xmm14
,解压缩它到一个只能看到单精度计算的寄存器,将它解压缩到一个寄存器,它将看到一些不能用单精度指令完成的计算,以及那些可以用单精度指令完成的操作在后者案例?
编辑:哈罗德在评论中回答了这一点以下的问题部分。
还有一个包含在一般问题中的更具体的子问题:当我用浮点指令随机替换一些整数执行域指令时(例如 movdqa
指令由movaps
说明),函数能计算错吗?我预计唯一的后果是执行延迟,而不是错误的结果。
例如,如果在上面我只将 pshufd [=29=], %xmm14, %xmm4
指令更改为 shufps
指令,则计算将完全错误(xmm4
是涉及的寄存器paddd
以后)。更改其他指令而不是那个指令会导致其他类型的错误。
对于 xor
之类的东西,更喜欢整数域指令。在 Intel CPU 上,只有一个执行端口可以处理 FP 域逻辑(XORPS
等),但是大多数执行单元(在 SnB 上到 Haswell:p015,但不是 Haswell 的端口 6)可以处理向量整数逻辑说明(PAND/POR/PXOR
)。
根据 Agner Fog 的测试,如果需要 FP 域指令的结果作为向量整数域指令的输入,有时会花费额外的 1 个周期的延迟。 (请参阅微体系结构文档)。这适用于 AMD 和英特尔。这仅在指令位于关键路径上时才重要。 (循环中最长的 dep 链)。
正确性不是问题,除非您发现指令的非正交性让您感到困惑。 shufps
做的事情与 pshufd
不一样。我认为 vpermilps ymm, ymm, imm
确实与 pshufd
做同样的事情,并且似乎只是为了让您可以将随机播放与内存加载结合起来而引入的。 (否则,您可以只使用 shufps
的 AVX 版本,使用与两个源相同的寄存器,并获得相同的行为)。
IDK 如果有人彻底测试了所有使用较短指令编码 ...ps
版本的事物没有额外延迟的情况。不过,SnB 和后来的 Intel CPU 中的 uop 缓存使得内部循环的问题减少了。 (指令解码只是第一次通过循环的瓶颈。)
编辑:uop-cacheline 边界除外,如果您的代码可以以其他方式维持完整的 4 uops/周期,这可能是瓶颈。 IDK 是否有任何工具可帮助对齐 x86 指令,以便 uop 缓存行保持 4 uops 的倍数。
我正在玩一些 SSE 汇编代码,其中我没有足够的 xmm
寄存器来同时将所有临时结果和有用的常量保存在寄存器中。
作为一种解决方法,对于一些具有相同组件的常数向量,我将几个向量“压缩”到一个 xmm
寄存器中,如下 xmm14
。我使用 pshufd
指令来解压缩我需要的常数向量。该指令有一点延迟,但由于它需要一个源寄存器和一个目标寄存器,否则非常方便:
…
Lfour_15_9:
.long 4
.long 1549556828
.long 909522486
.long 0
…
movdqa Lfour_15_9(%rip), %xmm14
…
pshufd [=10=], %xmm14, %xmm4
paddd %xmm4, %xmm3
…
pshufd [=10=]b10101010, %xmm14, %xmm5
…
pshufd [=10=]b10101010, %xmm14, %xmm5
…
pshufd [=10=]b01010101, %xmm14, %xmm5
xorps %xmm5, %xmm2
movaps %xmm5, 112(%rax)
以上代码采用 gas/AT&T 语法,我的目标是从 Core 2 到 Westmere 的 Intel 处理器,它们提供高达 SSSE3 的指令。
Agner Fog's manuals 中的一位指出,对于某些用途,使用“类型”错误的向量指令可能更有利。例如,即使移动的数据不是浮点数,memcpy
也有利于使用 movaps
指令写入,因为 movaps
比 movdqa
短,可用于更多处理器,并且由于它不使用数据进行计算,因此适用 none 关于次正规的常见警告。对于改组单词也给出了相同的建议(我之前链接到的手册中的第 13.2 和 13.3 节)。
我的情况有点特殊,因为我打算重构常量向量,如有必要,有些可以仅与单精度“类型”指令一起使用:这些将仅涉及 movaps
, shufps
, xorps
计算。并且一些常数向量将不得不参与只能使用整数类型指令完成的计算:paddd
(因此我可以使用 movdqa
、pshufd
和 pxor
指令根据需要保留在整数执行域中)。
这个问题的一般版本是:考虑到我的目标是 Core 2 和 Westmere 之间的 Intel 处理器,我应该分别使用什么类型的指令从内存(重新)加载 xmm14
,解压缩它到一个只能看到单精度计算的寄存器,将它解压缩到一个寄存器,它将看到一些不能用单精度指令完成的计算,以及那些可以用单精度指令完成的操作在后者案例?
编辑:哈罗德在评论中回答了这一点以下的问题部分。
还有一个包含在一般问题中的更具体的子问题:当我用浮点指令随机替换一些整数执行域指令时(例如 movdqa
指令由movaps
说明),函数能计算错吗?我预计唯一的后果是执行延迟,而不是错误的结果。
例如,如果在上面我只将 pshufd [=29=], %xmm14, %xmm4
指令更改为 shufps
指令,则计算将完全错误(xmm4
是涉及的寄存器paddd
以后)。更改其他指令而不是那个指令会导致其他类型的错误。
对于 xor
之类的东西,更喜欢整数域指令。在 Intel CPU 上,只有一个执行端口可以处理 FP 域逻辑(XORPS
等),但是大多数执行单元(在 SnB 上到 Haswell:p015,但不是 Haswell 的端口 6)可以处理向量整数逻辑说明(PAND/POR/PXOR
)。
根据 Agner Fog 的测试,如果需要 FP 域指令的结果作为向量整数域指令的输入,有时会花费额外的 1 个周期的延迟。 (请参阅微体系结构文档)。这适用于 AMD 和英特尔。这仅在指令位于关键路径上时才重要。 (循环中最长的 dep 链)。
正确性不是问题,除非您发现指令的非正交性让您感到困惑。 shufps
做的事情与 pshufd
不一样。我认为 vpermilps ymm, ymm, imm
确实与 pshufd
做同样的事情,并且似乎只是为了让您可以将随机播放与内存加载结合起来而引入的。 (否则,您可以只使用 shufps
的 AVX 版本,使用与两个源相同的寄存器,并获得相同的行为)。
IDK 如果有人彻底测试了所有使用较短指令编码 ...ps
版本的事物没有额外延迟的情况。不过,SnB 和后来的 Intel CPU 中的 uop 缓存使得内部循环的问题减少了。 (指令解码只是第一次通过循环的瓶颈。)
编辑:uop-cacheline 边界除外,如果您的代码可以以其他方式维持完整的 4 uops/周期,这可能是瓶颈。 IDK 是否有任何工具可帮助对齐 x86 指令,以便 uop 缓存行保持 4 uops 的倍数。