5 ms·
You are joking, right? Regehr's paper covers a proposed CHANGE to Clang/LVM UB behavior, while I was asking for studies that show advantages of UB "optimization
by vyodaiken 8y ago
You are joking, right? Regehr's paper covers a proposed CHANGE to Clang/LVM UB behavior, while I was asking for studies that show advantages of UB "optimization" itself. The numbers show minor changes of performance on an artificial benchmark - some better some worse. Try better.
The absence of any actual studies showing benefits of UB "optimizations" is glaring. I don't care about motivations, which could simply be incompetance.
- pcwalton 8y agoThe point of giving that example is to show that there are studies that examine the benefit of undefined behavior, and in this case measure the performance of dialing back some degree of that UB exploitation. It's trivial to show that if you try to completely eliminate undefined behavior from the C language then performance will collapse. Even register allocation depends on exploiting undefined behavior—who's to say that some wild pointer you created didn't accidentally point to some local variable? The reason why you don't see any studies on it is that it's obvious. When it comes to signed overflow, the status quo comes from two inconvenient facts: (1) lots of C code out there loops over arrays using int for indices; (2) lots of C code out there assumes int is 32 bits. The latter means that, during the 64-bit transition, no compiler could switch to ILP64 and was forced to settle on LP64 (or LLP64 in the case of Windows). Confronted with these facts, compiler developers did the best they could, exploiting signed overflow in order to provide sensible codegen for idiomatic loops in C on 64-bit. The real world is complicated, and sometimes the right solution to an engineering problem is messy. Regarding the charge of incompetence, with all due respect, my friends who work on Clang and GCC are better programmers than 99% of commenters on this site.
- vyodaiken 8y ago>The point of giving that example is to show that there are studies that examine the benefit of undefined behavior, Of course, that is exactly what Regehr's paper does not show. It shows that a modification of Clang/LVM UB operations has some good properties. I am asking for studies showing significant benefits for UB "optimizations" that are not available otherwise. I never advocated eliminating undefined behavior from C, I advocate eliminating UB based "optimizations" from C compilers, particularly "optimizations" which rely on assuming code will never do what emitted code does! >The reason why you don't see any studies on it is that it's obvious. And that is the classic tell for a serious mistake in engineering. We don't need to study it, its obvious. Your response is flat out wrong. C is not defined as a memory safe language. You are inventing a false dichotomy: if the compiler cannot assume UB never happens, it must ensure UB never happens. Nope.
- pcwalton 8y ago> I never advocated eliminating undefined behavior from C, I advocate eliminating UB based "optimizations" from C compilers, particularly "optimizations" which rely on assuming code will never do what emitted code does! OK, then that definition excludes register allocation as a permitted optimization. If you want to compile C code without any exploitation of undefined behavior, that's readily available! Just pass -O0 to your compiler.
- vyodaiken 8y ago>OK, then that definition excludes register allocation as a permitted optimization Oh come on.
- deleted 8y ago[deleted]
- nkurz 8y agowith all due respect, my friends who work on Clang and GCC are better programmers than 99% of commenters on this site I presume that both you and the majority of the people who work on compilers are great programmers. Which makes difficulty in communication even stranger. Summarizing the anti-UB side, we really don't like it when the compiler drops explicit error checking code on the basis that error check would only be used if undefined behavior occurred. That is, I'd like a naive check for overflow to either emit an error message, or to compile as written with the behavior dependent on the underlying architecture. Even register allocation depends on exploiting undefined behavior—who's to say that some wild pointer you created didn't accidentally point to some local variable? The confusing part is that you (and many other smart people) seem to feel that "don't drop explicit error checks" is completely equivalent to "don't store local variables in registers". To me (to us) these are completely independent, with the dropped errors checking being a "real problem" and the possibly clobbered variables being a "not a problem", and in fact, everything working the way it should. Could you explain more why you feel these two are equivalent? My guess is that the difference is philosophical, between those who feel that the source code is a recipe, versus those who feel the source code is a mathematical proof. In my view, the goal of the compiler isn't to create a perfect program suitable for an perfect abstract machine, rather it's to translate the intent of the programmer into assembly language suitable for a particular deterministic processor. I have no problem with a compiler that produces code that crashes on malformed input (division by zero, reading a NULL pointer) but I want it to leave the actual crash up to the processor. With overflow as with the case of clobbered aliased variables, I'm fine if the compiler generates code that only works correctly if the runtime error does not occur, but I'm not OK with reasoning non-locally that the error checks can be omitted because the error is logically impossible. Do you really not distinguish these two cases?
- BeeOnRope 8y agoDropping "explicit error checks" is no doubt bad from the user's point of view, but the primary difficulty is that to the compiler, working at the abstract level of multi-pass optimization of the IR, the good and bad cases all look the same. Pruning paths that lead to UB leads to some significant actual real-world optimizations (and these extend beyond these various signed-wrapping examples), and people want those whether they know it or not. Unfortunately, to the compilers, your overflow check just looks like another one of these cases. That is, it is very hard for the compiler to guess the programmer's intent, and say "oh, this is actually a check which is trying to avoid overflow, and despite that it uses UB, we should compile this part with wrapping semantics instead", and yet apply the optimization in all the other places you would want it. You could probably come up with some type of pattern recognition, or some heuristics like "if the optimization makes some of the original source code dead unconditionally, don't make it", but I think this is both very difficult and in many cases worse than the current disease. I think you can make a strong argument that the optimizations enabled by some types of UB exploitation are not worth the bugs and vulnerabilities they cause, and so the UB should be removed entirely, making it defined or implementation defined. Trying to have your cake (yes, it should still make these optimizations x and y) but eating it too (oh, but case z is different, see?) is a tougher proposition.