我正在处理一些代码,这些代码使用内联 Intel X86_64 程序集来设置处理器的 SSE 标志,以包括“flush-denormal-to-zero”和“treat-denormals-as-zero:”,stmxcsr然后ldmxcsr.
我不太喜欢这种方法(我们将其表示为方法 1)。关于非正规化的维基百科页面建议了一些其他选项:
#include <fenv.h>
// ...
fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);
Run Code Online (Sandbox Code Playgroud)
#include <xmmintrin.h>
// ...
_mm_setcsr( _mm_getcsr() | 0x0040 | 0x8000 );
Run Code Online (Sandbox Code Playgroud)
#include <pmmintrin.h>
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#include <xmmintrin.h>
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
Run Code Online (Sandbox Code Playgroud)
...但我也不太喜欢这些。它们不在任何通用/标准库中;当然,它们是英特尔特定的。如果我使用 ARM 怎么办?我可能还想这样做。我也不确定其中哪些可以与哪个编译器一起使用(维基百科说其中一些它们“可以工作”)。
那么,我应该如何最好地告诉我的处理器将非正规数刷新为零?
注意:我的问题并没有真正区分 C 和 C++。我对 C++ 习惯用法感兴趣,但如果只有“C'ish”习惯用法,我可以接受。
出于某种原因,有时在我的程序中我看到
cmpeqpd xmm3,xmm0
Run Code Online (Sandbox Code Playgroud)
where xmm0 == {0x2cd000000000, 0x2cd000000000}
andxmm3 == {0x0, 0x2011d0800000000}
恰好{0xffffffffffffffff, 0x0}在 xmm3 中返回,这是错误的,因为(double)0x0不等于(double)0x2cd000000000.
我注意到它只是偶尔发生。我已经用 rr 记录了程序的执行,以便一致地重现它。有趣的是,在一个超级简化的简单程序中,我无法再重现这个问题。我想知道,是否有任何隐藏的微架构状态可以改变 cmpeqpd (cmppd) 行为?
请注意,我检查了相应 ymm 寄存器中的高 128 位是否为零。