| ▲ | dgrunwald an hour ago | |
A surprising number of those optimizations are only valid by "reasoning from undefined behavior". Under the as-is rule, optimizations must not change program behavior. A C program could theoretically use out-of-bounds pointers to scan its own stack, observing whether a value occurs on the stack. Thus, the as-is rule prohibits storing local variables in registers! But because out-of-bounds pointers are undefined behavior, the compiler can ignore the programs doing stack scanning, and so register allocation becomes possible under the as-is. So boring old register allocation is one of those "assume that UB doesn't happen" optimizations! Of course, the compiler never actually reasons "this pointer arithmetic is out of bounds therefore I can put that variable over there into a register" -- the reasoning from undefined behavior doesn't happen at compile-time, it already happened when the "register allocation" optimization was designed. But that's the case for most "assume that UB doesn't happen" optimizations! (this is also why it's so difficult for compilers to warn about undefined behavior -- they optimize based on it without ever detecting it!) If you want to eliminate "reasoning from undefined behavior", you'd also need to replace the "as-is" rule with something else -- an explicit list of allowed optimizations in the language standard? | ||
| ▲ | afdbcreid 11 minutes ago | parent [-] | |
Indeed. No UB is something no mainstream C/C++ compiler does (and maybe ever did). Benchmarking the performance impact will require basically rewriting GCC or LLVM, an insurmountable task, because the assumptions are so ingrained. Though it might be possible to have more "sensible" UB. For example, assuming daemonic non-determinism for allocation address it is possible to turn stack storage into registers, without the need for an aliasing model. Benchmarking it has the same difficulty. | ||