4 ms·
Dead Code Elimination can even optimise out blocking loops, a loop like for(;;) can be optimised out.
by octo_t 13y ago
Dead Code Elimination can even optimise out blocking loops, a loop like for(;;) can be optimised out.
- dman 13y agoSo the compiler writers are bringing lazy evaluation to the unsuspecting masses?
- octo_t 13y agoThats not lazy evaluation so much as "this loop literally doesn't do anything"
- jerf 13y agoIt does do something. It loops forever. The optimized version does nothing. This is a major difference in performance. No sarcasm; this sort of thing can manifest in real code, and when it does it will generally be a great deal more complicated. "Bugs that only appear at certain optimization levels" are not the absolute worst types of bugs to debug, but they're certainly up there on the great Hierarchy of Sucky Bugs.
- garenp 13y agoIf an empty loop does no computation (i.e. has no observable side-effects), then arguably there should be no difference in observable behavior from the program. Of course, sometimes we "know" something that the compiler can't "see", and so must indicate as such in our code (e.g. using something stored inside the loop, adding volatile, ...). Probably the most common (or at least my favorite) example of DCE leading to a surprise, is when embedded programmers use so-called "delay loops" which can be eliminated by the compiler because it too is "empty" (the loop produces nothing that is used outside of the loop).
- scott_s 13y agoAn empty loop that has no computation but loops forever has an observable side-effect.
- nhaehnle 13y agoGo read page 14 of this: http://isocpp.org/files/papers/N3690.pdf http://isocpp.org/files/papers/N3690.pdf ;-) Essentially, C++ does not consider looping forever to be a side effect. You have to do something like writing to a volatile variable to ensure that the compiler does what you want.
- gizmo686 13y agoThe relevent part of page 14: "The implementation may assume that any thread will eventually do one of the following: — terminate, — make a call to a library I/O function, — access or modify a volatile object, or — perform a synchronization operation or an atomic operation. [ Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. — end note ]"
- demallien 13y agoYup, when I was young and naive, I would not initialize structs to zero explicitly when they were allocated on the stack. One day I had a bug that only appeared in production code, which is bad, as I was working on an embedded system, so production code = no debugger. Took me a while to figure that one out! The compiler writer that thought that it would be a good idea to zero out stack variables, but only if the code was -O0 deserves to be taken out back and shot!
- knz42 13y agoI don't believe that's right (see below why). Point me to one compiler which does this intentionally (ie not a bug) and I would stand corrected, but in most cases most compiler experts I know (myself included) would frown and disapprove. There was a bug in GCC a while ago to that effect, but it's been corrected since. Why: Computationally, there is no difference between "no code" and "a loop that iterates 100 times and does nothing". It is thus correct to eliminate the latter to preserve the observable behaviour. However, a loop that never terminates is a very different thing entirely: it says "execution will never progress past this point" and everything afterwards will never be reached. This property is so enshrined in theoretical computer science that any half-decent verification tool will consider what comes after the loop as dead code and not check it. In the newer GCC and Clang the code after a never-ending loop will be marked "unreachable" and be killed as dead code. So removing a never-ending loop would be quite the big deal indeed. Technical note: specifically in C and C++ and every language implemented using them, a loop with a counter but no check on the upper bound (eg. "for(i = 0; ; ++i)" ) is very different from the empty loop discussed above. Such a loop would be called "undefined behavior": the program may or may not stop, the world may explode, etc. This is because C and C++ say that overflow has undefined behavior. So this kind of loop does not mean "the programmer intends the control flow to terminate here", but rather "the programmer is playing with fire and it can burn".
- nhaehnle 13y agoWhat you write is perfectly plausible, and yet you're wrong. Such is the magic of the C++ standard ;) There is a part of the C++ standard that says something along the lines of: the compiler may assume that every program will eventually exhibit some side-effect. That part of the standard also explicitly states that this is intended to allow compilers to remove loops with empty bodies (or bodies with only dead code) even if they cannot prove termination of the loop. See e.g. page 14 of http://isocpp.org/files/papers/N3690.pdf http://isocpp.org/files/papers/N3690.pdf This is certainly useful when you think of code that is created indirectly via macros and/or template instantiation. Whether compilers actually perform this "optimization" on explicit endless loops like for(;;); is another question, but at least C++ can claim to be able to run certain endless loops in under a second ;)
- beerscout 13y agoSomewhat related: http://blog.regehr.org/archives/140 http://blog.regehr.org/archives/140