gcc旗-funsafe-math-optimizations (-ffast-math的一部分)打开FTZ和DAZ (同花顺到零和非正态-零)。但是,打开优化将禁用此行为。
#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 (即没有输出到标准输出)。但是,如果包括任何优化(例如,-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时,我看到了相同的行为。优化禁用它。此命令仅在编译时更改任何内容,而不使用-ffast-数学。
我的问题是:如何在使用优化时实现FTZ/DAZ?此外,还有其他的数学行为是禁用的优化吗?
我在gcc 10.2和6.3中都注意到了这一点
发布于 2022-11-19 08:14:38
看起来,这种行为是我的单元测试的产物。编译器本身不服从FTZ/DAZ,只服从生成的代码。因此,在这里示例的情况下,编译器执行计算,并知道绕过条件语句并直接移到printfs是安全的。
将其分解为两个编译单元,问题就消失了:
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;
}当check函数是同一个文件的一部分时,问题仍然存在,但这还是编译器优化的结果。
https://stackoverflow.com/questions/74498156
复制相似问题