我对内在函数还很陌生,我面对的代码使用GCC-7.4和GCC-8.3的行为不同
我的代码很简单
b.cpp:
#include <iostream>
#include <xmmintrin.h>
void foo(const float num, const float denom)
{
const __v4sf num4 = {
num,
num,
num,
num,
};
const __v4sf denom4 = {
denom,
denom,
denom,
denom,
};
float res_arr[] = {0, 0, 0, 0};
__v4sf *res = (__v4sf*)res_arr;
*res = num4 / denom4;
std::cout << res_arr[0] << std::endl;
std::cout << res_arr[1] << std::endl;
std::cout << res_arr[2] << std::endl;
std::cout << res_arr[3] << std::endl;
}
在b.cpp中,我们基本上只是从float变量构造两个__v4sf
并执行除法
b.h:
#ifndef B_H
#define B_H
void foo(const float num, const float denom);
#endif
a.cpp:
#include "b.h"
int main (void)
{
const float denominator = 1.0f;
const float numerator = 12.0f;
foo(numerator, denominator);
return 0;
}
在这里,我们只是从b.cpp调用函数
GCC 7.4可以正常运行:
g++-7 -c b.cpp -o b.o && g++-7 a.cpp b.o -o a.out && ./a.out
12
12
12
12
但是GCC 8.3出了点问题
g++-8 -c b.cpp -o b.o && g++-8 a.cpp b.o -o a.out && ./a.out
inf
inf
inf
inf
所以我的问题是-为什么我在使用不同版本的GCC时会收到不同的结果?它是未定义的行为吗?
答案 0 :(得分:4)
您发现gcc8及更高版本中存在一个错误,该错误在启用/未启用优化的情况下发生。感谢reporting it。
启用优化后,很容易看到asm在做什么,因为__v4sf
东西已经优化掉了:它只是标量除法并将结果打印4次。 (由于您出于某些原因使用了std::endl
,所以加上了4个调用flush cout的调用。)
gcc7正确地将其优化为divss xmm0, xmm1
以执行num / denom
。然后它将转换为double
,因为输出函数仅使用double
,而不是float
,将其传递给iostream
函数。 (GCC7使用double
将r14
位模式保存在整数寄存器-mtune=skylake
中而不是内存中,而将divss xmm0, .LC0[rip]
保存在整数寄存器中。GCC8及更高版本仅使用可能更有意义的内存。)
gcc8和更高版本执行0
,其中来自内存的常量为+0.0
(num
的位模式)。因此,它将denom
除以零,而忽略了alignas(16) float res_arr[4];
。
在the Godbolt compiler explorer上签出。
使用__v4sf *res
来消除__attribute__((aligned(16)))
可能存在的未对准问题没有帮助。 (您通常不再需要c.print_a
; C ++ 11引入了用于对齐的标准语法。)