On Thursday, 23 April 2015 at 08:56:38 UTC, rumbu wrote:
On Thursday, 23 April 2015 at 08:33:56 UTC, John Colvin wrote:
Why can no compiler I try optimise this toy example as I would
expect?
// uncomment if using a C compiler
// typedef unsigned int uint;
uint foo(uint a)
{
if (a < 5)
return (a * 3) / 3;
else
return 0;
}
So, I would expect the compiler to be able to see that it is
equivalent to
uint foo(uint a)
{
return (a < 5) ? a : 0;
}
But apparently not a single modern compiler I tried can do
this optimisation, unless it's hidden in some obscure flag I'm
not aware of.
I think because of the potential overflow in a * 3 (if we
ignore the a < 5 condition). To optimize this, a compiler must
figure out that there is no overflow for any a < 5.
If you change the condition to a > 5 and call foo(uint.max),
the two expression above are not equivalent.
int foo(uint a)
{
if (a > 5)
return (a * 3) / 3;
else
return 0;
}
int foo_optimized(uint a)
{
return (a > 5) ? a : 0;
}
assert(foo(uint.max) == foo_optimized(uint.max)) // -> fail.
Yes, the three things making * and / not inverses of each other
on unsigned integer types are:
truncation of integer division
div by 0
overflow
But it still amazes me that the compiler can't use the a < 5
condition here. I regularly watch compilers do what appear to be
magical transformations and simplifications to my code, but here
they are tripping up on some very simple maths.