k<16; dd=d[++k]
, whenever the code reached the end of the loop, effectively becomes dd=d[++k]
if(k<16) goto startOfLoop;
That, in turn is equivalent to: k+=1
dd=d[k]
if(k<16) goto startOfLoop
In the second line, k is used to index into array d. Conforming programs do not access memory outside of arrays, so the compiler can infer that 0 <= k < 16
Given that, it is clear that the goto startOfLoop branch will always be taken. Inside the loop, the program accesses some memory, but that data never is visible to the outside world, so the compiler can optimize away the memory reads and writes.The compiler is that aggressive because it has to be in real world programs. For example, compilers using C as their target instruction set may generate bounds checks for every array access, trusting the C compiler to remove as many as possible of them. Macros are another common cause of superfluous source statements that programmers will expect the compiler to optimize away.
I think it will be very tricky to detect cases where compilers should be wary of applying 'obvious' optimizations.
for (i=0; i<16; i++) { if (i>=0 && i<16) do something with a[i] else report an error;
you can certainly optimize the if to if(1). That's an optimization*.
For your example, the Pascal code (at least, I hope this is Pascal; it has been a while since I wrote any):
if (i>=0 and i<16) then
begin
x := a[i]
end
else
begin
ReportError;
end
is equivalent to the C code: if (i>=0 && i<16)
{
if(i>=0 && i<16)
{
x = a[i]
} else {
RuntimeAbort(“Array access outside bounds");
}
} else {
ReportError();
}
A good Pascal compiler, like a good C compiler, would optimise away that second boundary check and the call to RuntimeAbort. Neither compiler is allowed to optimise away the first check.See also this related SO question, and ones it links to: http://stackoverflow.com/questions/24296571/why-does-this-lo...
(disclaimer: I am a programmer, not a compiler)