gcc 如何将 sin(x) 和 cos(x) 的单独调用优化为单个 sincos?

问题描述 投票:0回答:1

这个c++代码是

#include<cmath>
double f1(double a){
    return std::cos(a);
}

double f2(double a){
    return std::cos(a) + std::sin(a);
}

被编译成以下程序集(https://godbolt.org/z/Y578h1TKx

f1(double):
        jmp     cos
f2(double):
        sub     rsp, 24
        lea     rdi, [rsp+8]
        mov     rsi, rsp
        call    sincos
        movsd   xmm0, QWORD PTR [rsp+8]
        addsd   xmm0, QWORD PTR [rsp]
        add     rsp, 24
        ret

这是否意味着 gcc 知道 glibc 的标准函数并且拥有针对使用它们的特定情况的优化技术?

c++ gcc compiler-optimization glibc
1个回答
0
投票

编译 GCC 本身时,您指定一个目标三元组,其中包含有关平台的信息以及(可能间接)编译后的 GCC 将编译的目标上使用的 C 标准库实现的信息。

例如,

x86_64-linux-gnu
是一个典型的目标三元组,适用于在 x86_64 处理器上运行 Linux 并使用 glibc 作为 C 标准库实现的目标。

同样,

x86_64-linux-musl
将是一个类似的目标,但使用 musl C 标准库实现。

此外还有

-m
编译器开关(例如
-mglibc
-mmusl
...)来更改假定的目标 C 标准库实现。

通过这种方式,GCC 知道目标是否支持非标准

sincos
函数,如果支持,那么它可以重写对
std::cos
std::sin
的调用,它们的语义始终是已知的,因为它们是由 C++ 和 C 标准指定,以您所看到的方式调用
sincos

例如,如果您使用 uclibc C 标准库实现对 Linux 目标使用

-muclibc
进行编译,则 GCC 会假定
sincos
不存在,并且不会重写为
sincos
。 (虽然我认为uclibc确实支持sincos。)

使用默认配置(即没有任何

-std=c*
-ansi
标志),编译器可以重写非标准
sincos
函数,即使
sincos
不是任何标准保留的名称,并且因此,用户可以将其用于不同的目的,因为 GCC 的默认选项假定 GNU 扩展(即
-std=gnu++XX
而不是
-std=c++XX
),不严格符合标准。

不幸的是,即使在严格的标准一致性模式下,GCC 仍然会执行这种转换,而这是不应该发生的。请参阅错误报告此处

© www.soinside.com 2019 - 2024. All rights reserved.