Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

clang++ wrong result on -O3 and above #49688

Open Quuxplusone opened 3 years ago

Quuxplusone commented 3 years ago
Bugzilla Link PR50719
Status NEW
Importance P enhancement
Reported by Shaohua Li (shaohua.li@inf.ethz.ch)
Reported on 2021-06-15 08:59:09 -0700
Last modified on 2021-06-16 11:17:08 -0700
Version 12.0
Hardware PC Linux
CC blitzrakete@gmail.com, dgregor@apple.com, efriedma@quicinc.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk, zhendong.su@inf.ethz.ch
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
Hi there,

I found that for a piece of code, clang++ would give out different results when
compiled with different opt flags.

$ clang++ -v
Ubuntu clang version 12.0.1-++20210605063018+0826268d59c6-
1~exp1~20210605043737.99
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64
$
$ clang++ -O0 a.cpp ; ./a.out
492559612348245.812500
$
$ clang++ -O3 a.cpp ; ./a.out
492559612348245.875000
$
$ cat a.cpp

#include <iostream>
#include <cstdint>
#include <iomanip>
#include <math.h>
#include <vector>

int main() {
    std::vector<unsigned short>  value = {19126};
    double out = pow(2.0, value[0]/384.0-1.0);
    std::cout << std::fixed << out << std::endl;
}

$
Quuxplusone commented 3 years ago

The C library pow() libcall is not correctly rounded. This means the result isn't predictable across targets, and across optimizations that use alternate methods to compute the result.

Here, the compiler is transforming the pow() libcall to the more efficient exp2() libcall. This is loosely equivalent, but the rounding is slightly different.

If you want predictable results, you should use your own implementation of pow() using operations using correctly rounded arithmetic.

You can use -fno-builtin to disable this sort of optimization.