根据GCC版本的不同内在行为

Dar*_*ver 6 c++ gcc intrinsics undefined-behavior

我对内在函数很陌生,我面对的代码使用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;
}
Run Code Online (Sandbox Code Playgroud)

在b.cpp中,我们基本上只是__v4sf从float变量构造两个并执行除法

bh:

#ifndef B_H
#define B_H

void foo(const float num, const float denom);

#endif
Run Code Online (Sandbox Code Playgroud)

a.cpp:

#include "b.h"

int main (void)
{
    const float denominator = 1.0f;
    const float numerator = 12.0f;
    foo(numerator, denominator);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们只是从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
Run Code Online (Sandbox Code Playgroud)

但是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
Run Code Online (Sandbox Code Playgroud)

所以我的问题是-为什么使用不同版本的GCC会收到不同的结果?它是未定义的行为吗?

Pet*_*des 4

您在 gcc8 及更高版本中发现了一个错误,无论启用/不启用优化都会发生该错误。感谢您的举报

启用优化后,很容易看到 asm 正在做什么,因为这些__v4sf东西会优化掉:它只是标量除法并打印结果 4 次。(加上 4 次刷新 cout 调用,因为您std::endl出于某种原因使用了。)

gcc7 正确地优化了它以divss xmm0, xmm1执行num / denom. 然后它转换为double因为输出函数只接受double而不是float将其传递给iostream函数。(GCC7 将double位模式保存在整数寄存器r14而不是内存中,而-mtune=skylake.GCC8 和更高版本只使用内存,这可能更有意义。)

gcc8 及更高版本执行divss xmm0, .LC0[rip]内存中常量所在的位置0( 的位模式+0.0)。所以它将除以num零,忽略denom

在Godbolt 编译器浏览器上查看一下。

使用alignas(16) float res_arr[4];来消除潜在的对齐不足__v4sf *res没有帮助。(通常不再需要__attribute__((aligned(16)));C++11 引入了对齐的标准语法。)