Hi,
We have a problem concerning LLVM optimizations and overflows in MacRuby.
I reduced that to the following (architecture x86-64):
$ cat e.c
#include <stdio.h>
long foo(void);
int main() {
const long a = foo();
const long b = foo();
const long res = a * b;
fprintf(stderr, "0x%lx 0x%lx 0x%lx 0x%lx\n", res, a, b, res / a);
return 0;
}
$ cat e2.c
long foo(void) {
return 0x100000000;
}
$ llvm-gcc --emit-llvm e.c -c -o e.bc
$ opt -O3 e.bc -o=eopt.bc
$ llc eopt.bc
$ gcc -o e e2.c eopt.s
$ ./e
0x0 0x100000000 0x100000000 0x100000000
I was expecting the 4th number to be 0, but the CES pass that res / a
= a * res / a = b and so optimizes the division out.
If I use directly a C compiler (same result with gcc, llvm-gcc or
clang) I get the result I was expecting:
$ gcc -O3 -o e e.c e2.c
$ ./e
0x0 0x100000000 0x100000000 0x0
How could I tell opt, and the optimization passes enabled in MacRuby
not to do this optimization when there might be an overflow?
PS: I know if an overflow occurs result is undefined but I guess
there's probably a flag or option for that.
Cheers
Hi Vincent,
We have a problem concerning LLVM optimizations and overflows in MacRuby.
I reduced that to the following (architecture x86-64):
$ cat e.c
#include<stdio.h>
long foo(void);
int main() {
const long a = foo();
const long b = foo();
const long res = a * b;
fprintf(stderr, "0x%lx 0x%lx 0x%lx 0x%lx\n", res, a, b, res / a);
return 0;
}
$ cat e2.c
long foo(void) {
return 0x100000000;
}
$ llvm-gcc --emit-llvm e.c -c -o e.bc
$ opt -O3 e.bc -o=eopt.bc
$ llc eopt.bc
$ gcc -o e e2.c eopt.s
$ ./e
0x0 0x100000000 0x100000000 0x100000000
I was expecting the 4th number to be 0, but the CES pass that res / a
= a * res / a = b and so optimizes the division out.
this is correct, because the result of a signed multiplication that overflows
is undefined in C. Either the signed multiplication does not overflow, in which
case the simplification is obviously correct, or it does overflow and the
compiler is allowed to insert code that erases your hard-drive or anything else
it feels like. Since we are not so mean, we just replaced res/a with a random
value we picked out of the air. Let's see, how about we use... b
If I use directly a C compiler (same result with gcc, llvm-gcc or
clang) I get the result I was expecting:
You just got lucky, see What Every C Programmer Should Know About Undefined Behavior #1/3 - The LLVM Project Blog
$ gcc -O3 -o e e.c e2.c
$ ./e
0x0 0x100000000 0x100000000 0x0
How could I tell opt, and the optimization passes enabled in MacRuby
not to do this optimization when there might be an overflow?
Unsigned multiplication results in a well defined value, there are also some
compiler flags, see below.
PS: I know if an overflow occurs result is undefined but I guess
there's probably a flag or option for that.
Try -fwrapv or -fno-strict-overflow.
Ciao, Duncan.