C语言 部分- fast-math (FTZ, DAZ)在使用优化(GCC)时被禁用



gcc标志-funsafe-math-optimizations(-ffast-math的一部分)打开FTZDAZ(flush-to-zero和denormals-are-zero)。但是,打开优化会禁用此行为。

#include <stdio.h>
#include <pmmintrin.h>
int main(int argc, char** argv) 
{
//_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
float normal_f = 1.18e-38f;
double normal_d = 2.23e-308;
normal_f *= 0.1f;
if (normal_f != 0.0f) 
printf("FTZ/DAZ disabled for floats (%e)n", (double) normal_f);
normal_d *= 0.1;
if (normal_d != 0.0)
printf("FTZ/DAZ disabled for doubles (%e)n", normal_d);
return 0;
}

当用gcc foo.c -ffast-math编译时,FTZ和DAZ都是启用的(即,没有输出到stdout)。但是,如果包括任何优化(例如,-O1,-O3,-Ofast),则FTZ和DAZ被禁用:

$ ./a.out 
FTZ/DAZ disabled for floats (1.180000e-39)
FTZ/DAZ disabled for doubles (2.230000e-309)

更奇怪的是,当我用_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON)显式启用FTZ和DAZ时,我看到了同样的行为。优化会禁用它。此命令仅在编译时不使用- fast-math时更改任何内容。

我的问题:我如何在使用优化时实现FTZ/DAZ ?另外,是否有其他快速数学行为被优化禁用?

在gcc 10.2和6.3

看起来这个行为是我的单元测试的产物。编译器本身不服从FTZ/DAZ,只有生成的代码才服从。因此,在类似示例的情况下,编译器执行计算,并且知道绕过条件语句并直接移动到printfs是安全的。

将其分解为2个编译单元,问题就消失了:

bar.c

#include <stdio.h>
void check_normalf(float f)
{
if (f != 0.0f)  {
printf("FTZ/DAZ disabled for floats (%e)n", (double) f);
}
}
void check_normal(float d)
{
if (d != 0.0)  {
printf("FTZ/DAZ disabled for doubles (%e)n", d);
}
}

foo.c

#include <pmmintrin.h>
void check_normalf(float f);
void check_normal(float d);
int main(int argc, char** argv) 
{
//_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
float normal_f = 1.18e-38f;
double normal_d = 2.23e-308;
check_normalf(normal_f * 0.1f);
check_normal(normal_d * 0.1);
return 0;
}

当检查函数是同一文件的一部分时,问题仍然存在,但这仍然是编译器优化。

相关内容

  • 没有找到相关文章

最新更新