5 ms·
Really cool, it surprised me to see even trivial code give very different results in gcc,icc and clang. int retNum(int num, int num2) { return (num * n
by jerven 10y ago
Really cool, it surprised me to see even trivial code give very different results in gcc,icc and clang.
int retNum(int num, int num2) {
return (num * num2)/num;
}
gives this in clang
retNum(int, int): # @retNum(int, int)
mov eax, esi
ret
While icc and gcc give
retNum(int, int):
mov eax, esi
imul eax, edi
cdq
idiv edi
ret
retNum(int, int):
imul esi, edi
mov eax, esi
cdq
idiv edi
ret
The clang version at first sight seem right. But then thinking about it this is integer math.
4/3 := 1
1 * 3 := 3
leads to
3 != 4
I believe gcc and icc returning 3 there is correct, while clang returning 4 is not. Maybe someone more C/int versed
can tell us which are acceptable (knowing C both might be ok)
- comex 10y agoThe product of 'num' and 'num2' is always going to be a multiple of 'num', so there won't be any error introduced by flooring when dividing by 'num' again. One thing that can happen is an integer overflow: if you pass (0x10000, 0x10000), icc's and gcc's versions will calculate 0x10000 * 0x10000 = 0, 0 / 0x10000 = 0, while clang will return 0x10000. But clang's not wrong: signed integer overflow is undefined behavior in C, so compilers are allowed to just assume it never happens when making optimizations.
- AstralStorm 10y agoThere is a flag that enables such optimization behaviour for GCC. I think it is part of Ofast. If it does not work in new GCC it is a bug.
- chrisseaton 10y ago(num * num2)/num = num2 The division cancels out the multiplication. Just like if you were doing arithmetic on paper as you did in school. There's nothing more to it than that is there? What inputs do you think it's incorrect for in clang? Overflow is of course undefined.
- cyphar 10y agoUnless num is zero. In which case you won't get a floating point signal, you get a number that doesn't male sense.
- chrisseaton 10y agoBut a program with division by zero is undefined anyway.
- yoklov 10y agoErr, it's always ok, and shouldn't ever return the wrong answer... Unless I'm misreading it. What arguments do you think it will do the wrong thing with?
- anonymouz 10y agoFunny, if you swap the order of the operands in the multiplication, GCC 7.0 with -O3 does optimize it away: int retNum(int num, int num2) { return (num2 * num)/num; } now becomes retNum(int, int): mov eax, esi ret
- harpocrates 10y agoIt would be an interesting project to take in some (small) source program, and try all sorts of algebraic rearrangements (maybe just associativity and commutativity of addition and multiplication) to see if there is any noticeable performance change.
- matt_d 10y agoSTOKE, a stochastic superoptimizer, is pretty interesting in this context: http://stoke.stanford.edu/ http://stoke.stanford.edu/ & https://github.com/StanfordPL/stoke https://github.com/StanfordPL/stoke
- dspig 10y agothe performance definitely varies doing this by hand - I guess the current optimizers don't rearrange the code as much as a human can while seeing that it's still equivalent. But sometimes (I'm using LLVM) just rearranging the parentheses to force a different evaluation order makes a difference where I thought it wouldn't have after optimization.
- makapuf 10y agoThis seems to be the case in 6.1 but not in 5.4. What this proves is also that this tool is really useful to check easily between gcc versions without installing all compilers /toolchains
- jerven 10y agoMy thinking was for this C return (num / num2) * num2; Where the division happens first. That is what I get for thinking about this before coffee.