3 ms·
It's not an evil scheme to do whatever. It's a bunch of general-purpose optimizations that add up to this. There's a pass that looks at the condition, and check
by pornel 4y ago
It's not an evil scheme to do whatever. It's a bunch of general-purpose optimizations that add up to this. There's a pass that looks at the condition, and checks if "for all cases that C cares about, is this always true?" replaces it with true. This pass ruins your loop, but also the very same pass cleverly removes redundant instructions in many other cases.
Not doing this to the loop would require special-casing this particular code, and it's a burden to special-case such code (and many other pathological cases) on top of all the other complexity there is already in optimizers. C gets "lowered" into blocks of assembly-like instructions, so there's no `for` loop any more even before the optimizer touches it. This format is used, because it's easier to correctly optimize than anything which looks like C (partly because C requires supporting wicked things like `case` in places you wouldn't believe are legal).
For the most part, C optimizers simulate running code on a Low-Level Virtual Machine described in the C spec, not a specific target CPU. This isn't to screw you for looking at this from perspective of what x86 would do. It's to support lots of different CPUs in one codebase, with the best possible optimizations, in a spec-compliant way. But it means your code will first "run" on an imaginary CPU that really can't overflow an int.
Just as a bunch of optimizations that are sensible in isolation can add up to surprising UB bomb, a bunch of "just do the simple thing that the code says" rules can add up to surprisingly inefficient code. If `i++` was simply implemented as `add 1 with overflow`, you couldn't get some strength reduction optimizations in the loop, or index arrays with CPU's native addressing modes (they overflow differently than an int).