4 ms·
Others have shown that your degenerate example really does optimize it all away, but I'll just say that we really do exist in a theoretical fairy dust C++ spec
by turndown 3y ago
Others have shown that your degenerate example really does optimize it all away, but I'll just say that we really do exist in a theoretical fairy dust C++ spec environment, because when we compile a piece of code we compile it against the abstract machine. This is one of those insane gotchas of programming languages - unless you're writing assembly yourself you must pass the bar set by the abstract machine and nothing else. I recommend [0], along with every link in the article, and every article on the blog.
0: https://research.swtch.com/ub https://research.swtch.com/ub
- userbinator 3y agoThis is one of those insane gotchas of programming languages ...created only by adversarial compiler writers who seem to be as user-hostile as a lot of other "developers" these days. They can get away with being pedantic assholes, because they know that realistically no one is going to switch compilers that easily. That said, C and even C++ used to not be like this.
- sweetjuly 3y agoCompiler authors aren't doing this because they hate you, they're doing this because we want ever high performance. C and C++ didn't use to be like this because compilers were not capable of making the optimizations they can today.
- userbinator 3y agoMSVC and especially ICC got higher performance than GCC without exploiting UB, so how do you explain that?
- spacechild1 3y ago> MSVC Citation needed. This does not match my experience. > ICC If I'm not mistaken, this is largely because ICC uses unsafe math optimizations by default.
- userbinator 3y agoHere's some examples where ICC comes out ahead, often far ahead: https://keyj.emphy.de/compiler-benchmark/ https://keyj.emphy.de/compiler-benchmark/ https://iitd-plos.github.io/col729/labs/lab0/lab0_submissions/siy187504.pdf https://iitd-plos.github.io/col729/labs/lab0/lab0_submission... As for MSVC, my experience has been that it often generates smaller and slightly faster code than the others (except for ICC), but there's definitely some styles of code which it won't want to optimise.
- kaba0 3y agoThey definitely “exploit” UBs, any proof on the contrary?
- hoseja 3y agoSomebody removed all the insane UB-"optimizations" and the result wasn't even any slower. Can't find the blog now.
- tyg13 3y agoI'd be quite interested to read that post, given that one of the big UB hammers is strict aliasing which gets used a _lot_
- ynik 3y agoHow do you decide whether an UB-optimization is insane or not? "I know it when I see it" may work for lawmakers, but it's not good enough for compiler developers. Because if you want to disable all UB-based optimizations, there's already a compiler flag that does that: -O0. Seriously, in a language as low level as C++, every optimization needs some form of assumptions, and UB is how we currently allow compilers to make those assumptions. Example: because it's undefined behavior to read pointers out-of-bounds, it is not possible for a valid program to scan a whole stack frame, so it is okay for the compiler to remove variables from the stack frame and instead store them in registers. Without UB-optimizations, you would need some others justification of why it is okay for the compiler to change the result of a stack scan. Or use -O0 which keeps all variables on the stack. (but that certainly will be slower!)
- userbinator 3y agoLook at Intel's compiler or MSVC, vs. GCC and LLVM. The former two are known to rarely exploit UB, yet are competitive and even faster with certain code (especially ICC) compared to the latter two. and UB is how we currently allow compilers to make those assumptions. No, the behaviour of the target hardware is what should guide that. Example: because it's undefined behavior to read pointers out-of-bounds, it is not possible for a valid program to scan a whole stack frame, so it is okay for the compiler to remove variables from the stack frame and instead store them in registers. UB has no bearing on that. If a variable has never had its address taken, then there's no expectation that it ever be in memory.
- tyg13 3y agoThis seems like the sort of a comment that can only be written by completely refusing to understand why compiler writers take advantage of UB. Compiler writers are not engaging in "adversarial" behavior with their users -- they are their own users! The simple truth is a lot of UB exists to allow for optimizations that programmers entirely take for granted. In order to optimize something, you have to make assumptions, particularly when dealing with languages as permissive as C and C++. By programming to an abstract machine and explicitly specifying which behavior is defined and which is not, we allow a compiler to make these assumptions. Despite what you may wish, a compiler is not able to read your mind to know when a given piece of UB is actually code that you intended to execute with particular semantics, or whether it's the result of some other optimizations on a code path that will never execute.
- eru 3y ago> Compiler writers are not engaging in "adversarial" behavior with their users -- they are their own users! Only if your language is self-hosting, isn't it?
- arcticbull 3y agoThat's usually a major checkpoint for a programming language maturing no? Go became self-hosting in 2015 (1.5) [1] Rust was originally written in OCaml and became self-hosted in 2011 - excluding LLVM of course, but I guess, that's kind of up to you where you draw that specific line. [1] https://go.dev/blog/go1.5 https://go.dev/blog/go1.5
- tialaramex 3y agoIt might make sense for a General Purpose language, but really only if the language's goals make it suitable. For example suppose you decided goal #1 is ease of use for beginners so you consciously choose verbose syntax. It's unlikely that your compiler is written by beginners and they may get sick of needing all this verbosity. For Special Purpose languages it only makes sense if their purpose is centrally writing compilers. It doesn't make sense to write your Verilog "compiler" in Verilog.