x87 FPU状态字中C1
位的目的之一是显示是否将不精确的结果四舍五入。
SSE / AVX是否为标量操作提供任何此类指示?
我没有在MXCSR
寄存器中看到类似的位。如果我需要此信息,是否必须使用x87指令?
最佳答案
SSE / AVX不提供硬件支持来检测此情况,即使对于标量指令(例如addss
)也是如此。 SSE是为SIMD设计的,每个XMM向量具有4个浮点数,并且大概Intel不想在MXCSR中提供4位的位图。尽管那将是可能的设计选择。
正如@Mysticial在评论中指出的那样,可以使用额外的说明来计算它。
(未经测试的想法可能会满足您的要求。我认为即使在次法线下也应如此;对于完全相等的比较与按位比较相同,除了-0.0 == +0.0或NaN之外)
使用AVX512,您可以正常进行add / sub / mul / div / sqrt计算(使用默认舍入),然后再次使用舍入模式覆盖将其截断为0。使用vcmpps
表示结果相等。比较完全相等的元素通过默认的舍入模式舍入为0(或两次均精确)。当然,您可以使用+ Inf的-Inf作为替代来检测它而不是0。
AVX512的EVEX前缀可以在不更改MXCSR的情况下,按指令对舍入模式进行编码。与更改MXCSR相比,这可以高效地执行此操作。例如_mm512_add_round_ps (__m512 a, __m512 b, int);
。请注意,AVX512嵌入式舍入(er
)仅适用于512位向量。不幸的是,您不能将其与AVX512VL一起使用来对256位向量进行舍入覆盖,以避免当前的max-turbo以及在当前的Skylake系列CPU上使用512位向量的其他缺点。使用ER还会应用SAE(全部禁止例外),这意味着该指令根本不需要更新MXCSR。 AVX-512 Instruction Encoding - {er} Meaning。
在asm语法中,rz
=朝零舍入。请参阅表2-36。 EVEX嵌入式广播/舍入/ 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
组合某些矢量,其中您关心的“真值”是符号位。这可能是vblendvps
(也仅查看符号位)或最终vmovmskps
的输入。在没有AVX512的情况下更改舍入模式可能不会造成很大的麻烦,尤其是如果您可以在更改为截断并重做它们之前使用默认值进行一些矢量处理的话。如果您有足够的寄存器来摊销MXCSR对足够的操作的更改,则这可能比舍入方向检测序列(每个向量需要3条或更多指令)的效率更高。
显然,某些Intel CPU确实重命名了MXCSR。 MXCSR rename stall cycles的perf事件在某些微体系结构上存在(不确定哪个):
由于MXCSR寄存器重命名而导致的停顿与之前的MXCSR重命名过于接近。
因此,更改它不必消耗调度程序,但这不是很好。根据该措辞,在附近更改两次可能是不好的。 IDK(如果仅有少量的物理MXCSR条目要重命名),或者其他一些原因导致此限制。
当然,您不会在循环中存储,翻转和重新加载MXCSR值;您的内存中有两个MXCSR值,只需
ldmxcsr
。