SSE/AVX 是否提供了一种方法来确定结果是否被四舍五入?
Does SSE/AVX provide a means of determining if a result was rounded up?
x87 FPU 状态字中 C1
位的目的之一是显示是否对不精确的结果进行了舍入。
SSE/AVX是否为标量运算提供任何此类指示?
我在 MXCSR
寄存器中没有看到类似的位。如果我需要此信息,是否必须使用 x87 指令?
SSE/AVX 不提供检测这一点的硬件支持,即使对于 addss
这样的标量指令也是如此。 SSE 是为 SIMD 设计的,每个 XMM 向量有 4 个浮点数,大概英特尔不想在 MXCSR 中提供 4 位的位图。尽管那将是一个可能的设计选择。
正如@Mysticial 在评论中指出的那样,可以使用额外的指令来计算它。
(未经测试的想法可能会做你想做的事。我认为这应该适用于次正规等等;比较完全相等与按位比较相同,除了 -0.0 == +0.0 或 NaN)
使用 AVX512,您可以正常进行 add/sub/mul/div/sqrt 计算(使用默认舍入),然后 再次使用舍入模式覆盖 以截断为 0。 使用vcmpps
来获得结果 的相等性。比较完全相等的元素通过默认舍入模式向 0 舍入(或者两次都是精确的)。当然,您可以使用 towards -Inf 或 towards +Inf 作为覆盖来检测它而不是 toward 0.
AVX512 的 EVEX 前缀可以在每条指令的基础上对舍入模式覆盖进行编码,而无需更改 MXCSR。这使得可以高效地执行此操作,比更改 MXCSR 的效率要高得多。例如_mm512_add_round_ps (__m512 a, __m512 b, int);
。请注意,AVX512 嵌入舍入 (er
) 仅适用于 512 位向量;不幸的是,您不能将它与 AVX512VL 一起使用来对 256 位向量进行舍入覆盖,以避免当前最大涡轮增压和在当前 Skylake 系列 CPU 上使用 512 位向量的其他缺点。使用 ER 也适用 SAE(抑制所有异常),这意味着该指令根本不必更新 MXCSR。 .
在 asm 语法中,rz
= 向零舍入。参见 Table 2-36。 EVEX 嵌入式 Broadcast/Rounding/SAE 和矢量指令上的矢量长度 in Intel's vol.2 x86 manual。
vaddpd zmm2, zmm1, zmm0 ; no override, or {rne-sae} would be Nearest-Even
vaddpd zmm3, zmm1, zmm0, {rz-sae} ; rounding = truncation toward Zero
vcmpneqpd k1, zmm2, zmm3 ; compare for not-equal
;;; k1 = bitmask
;; 0 means rounded toward 0 or exact
;; 1 means rounded away from 0
如果您不需要主要结果是 512 位向量,您可以这样做并与 XMM 或 YMM 寄存器进行比较,但 {rz-sae}
操作必须是 ZMM。 YMM 比较让您可以选择与另一个 YMM 寄存器 (AVX1) 进行比较,而不是与 AVX512 掩码寄存器进行比较。但是,如果您使用的是 AVX512,掩码寄存器通常非常好。
这总是需要 2 条额外的指令:重复操作和比较。 Mysticial 建议在 mulps
之后使用 FMA 可能会避免这种情况,如果您只是直接使用符号位而不是与零进行比较。例如vmovmskps
获取整数位图,或 vxorps
或 vandps
组合一些向量,其中您关心的 "truth value" 是符号位。这可能是 vblendvps
(也只查看符号位)或最终 vmovmskps
.
的输入
在没有 AVX512 的情况下更改舍入模式可能不是一场彻底的灾难,尤其是如果您可以在更改为截断并重做之前使用默认设置执行一些向量。 可能 使它比舍入方向检测序列更有效,如果您有足够的寄存器可以使用以分摊 MXCSR 更改足够多的操作,则每个向量需要 3 个或更多指令。
显然有些 Intel CPU 会重命名 MXCSR; MXCSR rename stall cycles 的 perf 事件存在于某些微体系结构中(不确定是哪个):
Stalls due to the MXCSR register rename occurring too close to a previous MXCSR rename.
所以改变它不会耗尽调度程序,但它不是很好。而且按照那个说法,就近改两次可能就不好了。 IDK 如果可能只有有限数量的物理 MXCSR 条目可以重命名,或者该限制的其他原因。
当然,在循环中您不会存储、位翻转和重新加载 MXCSR 值;你在内存中有两个 MXCSR 值,只有 ldmxcsr
它们。
x87 FPU 状态字中 C1
位的目的之一是显示是否对不精确的结果进行了舍入。
SSE/AVX是否为标量运算提供任何此类指示?
我在 MXCSR
寄存器中没有看到类似的位。如果我需要此信息,是否必须使用 x87 指令?
SSE/AVX 不提供检测这一点的硬件支持,即使对于 addss
这样的标量指令也是如此。 SSE 是为 SIMD 设计的,每个 XMM 向量有 4 个浮点数,大概英特尔不想在 MXCSR 中提供 4 位的位图。尽管那将是一个可能的设计选择。
正如@Mysticial 在评论中指出的那样,可以使用额外的指令来计算它。
(未经测试的想法可能会做你想做的事。我认为这应该适用于次正规等等;比较完全相等与按位比较相同,除了 -0.0 == +0.0 或 NaN)
使用 AVX512,您可以正常进行 add/sub/mul/div/sqrt 计算(使用默认舍入),然后 再次使用舍入模式覆盖 以截断为 0。 使用vcmpps
来获得结果 的相等性。比较完全相等的元素通过默认舍入模式向 0 舍入(或者两次都是精确的)。当然,您可以使用 towards -Inf 或 towards +Inf 作为覆盖来检测它而不是 toward 0.
AVX512 的 EVEX 前缀可以在每条指令的基础上对舍入模式覆盖进行编码,而无需更改 MXCSR。这使得可以高效地执行此操作,比更改 MXCSR 的效率要高得多。例如_mm512_add_round_ps (__m512 a, __m512 b, int);
。请注意,AVX512 嵌入舍入 (er
) 仅适用于 512 位向量;不幸的是,您不能将它与 AVX512VL 一起使用来对 256 位向量进行舍入覆盖,以避免当前最大涡轮增压和在当前 Skylake 系列 CPU 上使用 512 位向量的其他缺点。使用 ER 也适用 SAE(抑制所有异常),这意味着该指令根本不必更新 MXCSR。
在 asm 语法中,rz
= 向零舍入。参见 Table 2-36。 EVEX 嵌入式 Broadcast/Rounding/SAE 和矢量指令上的矢量长度 in Intel's vol.2 x86 manual。
vaddpd zmm2, zmm1, zmm0 ; no override, or {rne-sae} would be Nearest-Even
vaddpd zmm3, zmm1, zmm0, {rz-sae} ; rounding = truncation toward Zero
vcmpneqpd k1, zmm2, zmm3 ; compare for not-equal
;;; k1 = bitmask
;; 0 means rounded toward 0 or exact
;; 1 means rounded away from 0
如果您不需要主要结果是 512 位向量,您可以这样做并与 XMM 或 YMM 寄存器进行比较,但 {rz-sae}
操作必须是 ZMM。 YMM 比较让您可以选择与另一个 YMM 寄存器 (AVX1) 进行比较,而不是与 AVX512 掩码寄存器进行比较。但是,如果您使用的是 AVX512,掩码寄存器通常非常好。
这总是需要 2 条额外的指令:重复操作和比较。 Mysticial 建议在 mulps
之后使用 FMA 可能会避免这种情况,如果您只是直接使用符号位而不是与零进行比较。例如vmovmskps
获取整数位图,或 vxorps
或 vandps
组合一些向量,其中您关心的 "truth value" 是符号位。这可能是 vblendvps
(也只查看符号位)或最终 vmovmskps
.
在没有 AVX512 的情况下更改舍入模式可能不是一场彻底的灾难,尤其是如果您可以在更改为截断并重做之前使用默认设置执行一些向量。 可能 使它比舍入方向检测序列更有效,如果您有足够的寄存器可以使用以分摊 MXCSR 更改足够多的操作,则每个向量需要 3 个或更多指令。
显然有些 Intel CPU 会重命名 MXCSR; MXCSR rename stall cycles 的 perf 事件存在于某些微体系结构中(不确定是哪个):
Stalls due to the MXCSR register rename occurring too close to a previous MXCSR rename.
所以改变它不会耗尽调度程序,但它不是很好。而且按照那个说法,就近改两次可能就不好了。 IDK 如果可能只有有限数量的物理 MXCSR 条目可以重命名,或者该限制的其他原因。
当然,在循环中您不会存储、位翻转和重新加载 MXCSR 值;你在内存中有两个 MXCSR 值,只有 ldmxcsr
它们。