Liu*_*Wei 1 c++ glibc g++ lto fast-math
最近我遇到了一个关于 LTO 的奇怪问题,根据是否使用,-ffast-math我的“pow”(in)调用得到了不一致的结果。cmath-flto
$ g++ --version
g++ (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ll /lib64/libc.so.6
lrwxrwxrwx 1 root root 12 Sep 3 2019 /lib64/libc.so.6 -> libc-2.17.so
$ ll /lib64/libm.so.6
lrwxrwxrwx 1 root root 12 Sep 3 2019 /lib64/libm.so.6 -> libm-2.17.so
$ cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
Run Code Online (Sandbox Code Playgroud)
fixed.hxx#include <cstdint>
double Power10f(const int16_t power);
Run Code Online (Sandbox Code Playgroud)
fixed.cxx#include "fixed.hxx"
#include <cmath>
double Power10f(const int16_t power)
{
return pow(10.0, (double) power);
}
Run Code Online (Sandbox Code Playgroud)
test.cxx#include <iostream>
#include <cmath>
#include <iomanip>
#include <cstdint>
#include "fixed.hxx"
int main(int argc, char** argv)
{
if (argc >= 3) {
int64_t value = (int64_t)atoi(argv[1]);
int16_t power = (int16_t)atoi(argv[2]);
double x = Power10f(power);
std::cout.precision(17);
std::cout << std::scientific << x << std::endl;
std::cout << std::scientific << (double)value * x << std::endl;
return 0;
}
return 1;
}
Run Code Online (Sandbox Code Playgroud)
-ffast-math使用和使用/不使用它进行编译-flto会给出不同的结果
-flto最终将调用该__pow_finite版本并给出“准确”的结果:$ g++ -O3 -DNDEBUG -ffast-math -std=c++17 -flto -o fixed.cxx.o -c fixed.cxx
$ g++ -O3 -DNDEBUG -o fdtest fixed.cxx.o test.cxx
$ ./fdtest 81 20
1.00000000000000000e+20
8.10000000000000000e+21
$ objdump -DC fdtest > fdtest.dump
$ cat fdtest.dump
...
0000000000400930 <Power10f(short)>:
400930: 0f bf ff movswl %di,%edi
400933: 66 0f ef c9 pxor %xmm1,%xmm1
400937: f2 0f 10 05 99 00 00 movsd 0x99(%rip),%xmm0 # 4009d8 <_IO_stdin_used+0x8>
40093e: 00
40093f: f2 0f 2a cf cvtsi2sd %edi,%xmm1
400943: e9 d8 fd ff ff jmpq 400720 <__pow_finite@plt>
400948: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40094f: 00
...
Run Code Online (Sandbox Code Playgroud)
-flto最终调用__exp_finite(如果我猜对的话,作为启用的优化-ffast-math),并给出“不准确”的结果。$ g++ -O3 -DNDEBUG -ffast-math -std=c++17 -o fixed.cxx.o -c fixed.cxx
$ g++ -O3 -DNDEBUG -o fdtest fixed.cxx.o test.cxx
$ ./fdtest 81 20
1.00000000000000786e+20
8.10000000000006396e+21
$ objdump -DC fdtest > fdtest.dump
$ cat fdtest.dump
...
0000000000400930 <Power10f(short)>:
400930: 0f bf ff movswl %di,%edi
400933: 66 0f ef c0 pxor %xmm0,%xmm0
400937: f2 0f 2a c7 cvtsi2sd %edi,%xmm0
40093b: f2 0f 59 05 95 00 00 mulsd 0x95(%rip),%xmm0 # 4009d8 <_IO_stdin_used+0x8>
400942: 00
400943: e9 88 fd ff ff jmpq 4006d0 <__exp_finite@plt>
400948: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40094f: 00
...
Run Code Online (Sandbox Code Playgroud)
上面的示例是预期的行为还是我的代码有问题导致了这种意外的行为?
在其他一些平台上也可以观察到相同的结果(例如带有 g++ 12.1 和 glibc 2.35 的 ArchLinux )。
海湾合作委员会人:
要使用链接时优化器,
-flto应在编译时和最终链接期间指定优化选项。建议您使用相同的选项编译参与同一链接的所有文件,并在链接时指定这些选项。例如:Run Code Online (Sandbox Code Playgroud)gcc -c -O2 -flto foo.c gcc -c -O2 -flto bar.c gcc -o myprog -flto -O2 foo.o bar.o
| 归档时间: |
|
| 查看次数: |
139 次 |
| 最近记录: |