This is only true because compiler authors are interpreting "undefined behavior" as a license for "user-hostile behavior". There are other choices one can make.
UB can also be things that the compiler is unable to express. It's NOT "haha, now I can do anything", it's like asking what the correct answer is to a logically inconsistent question. The compiler cannot even express the question.
Let's say the compiler encodes some GC information in the low two bits of int pointers. What does it mean if a function is called with an unaligned pointer, then? Mu, unask the question. It's UB, and no diagnostic required nor even feasible.
The GCC compiler is very unpredictable about what it considers unreachable code. Once, I wanted to avoid reading an array x[i] to save L1 cache space, so I used a computed goto (goto base + delta * i;) followed by return x1; return x2; ... return xn;. However, the compiler decided that only the first two return values were reachable and optimized away the rest of the code
I put labels on each return, and took their addresses to get the base and delta. The creator of c++ always says that such kind of code has to work "because it is c++", meaning the programmer should be able to do whatever he wants. Anyways I also used assembler to make it work (had to include nop instructions to pad the addresses, because the goto can't go to any byte. So it consumed a lot of instruction l1 cache, which is not as bad as data cache, but it ended being slow anyways because gotos trigger branch prediction. In the end the fastest method was to pack the array in uint64 and do (x >> i) & 111b
But did you use the address of every single return or did you assume they all had the same delta?
I can't find the quote you're talking about but I'll be surprised if it extends to assuming memory locations. If any pointer has to support touching any variable, even ones you never took the address of, that ruins so many basic and sensible optimizations.
Unless I'm misunderstanding, a normal computed goto would have an array of all the destinations. And hopefully it would compile to a delta multiply. But if you need to force it... maybe a compile time check that all the labels are delta bytes apart would let you do that math? I don't know, it's not part of the actual standard, it might be janky.
Did a plain old switch statement compile into something you didn't like?
Quote: "A zero-overhead principle. It basically says that if you have an abstraction, it should not cost anything compared to writing the equivalent code at a lower level."
I don't think that's a very close spirit? Saying abstractions that do exist should have no runtime cost is very different from saying which controls need to be available. This isn't really about abstractions at all, this is about micromanaging which variant of MOV the compiler uses because of knock-on effects on the cache.
You don't get Marssaxman's point: the problem is that "compiler authors treat undefined behavior as a license for user-hostile behavior".
Bjarne Stroustrup's criterion for language design is that C++ is an abstraction in itself over writing in assembly, and the language design should not get in the way by introducing overhead costs. C++ should allow the programmer to express their intent without losing performance relative to assembly, and it fails in this case due to undefined behavior.
So when the compiler doesn't let you implement your low-level code, it is a failure of the language and compiler relative to the design criteria of C++.
14 comments
[ 0.31 ms ] story [ 22.8 ms ] threadUB can also be things that the compiler is unable to express. It's NOT "haha, now I can do anything", it's like asking what the correct answer is to a logically inconsistent question. The compiler cannot even express the question.
Let's say the compiler encodes some GC information in the low two bits of int pointers. What does it mean if a function is called with an unaligned pointer, then? Mu, unask the question. It's UB, and no diagnostic required nor even feasible.
Did you calculate delta from the first two return values?
I can't find the quote you're talking about but I'll be surprised if it extends to assuming memory locations. If any pointer has to support touching any variable, even ones you never took the address of, that ruins so many basic and sensible optimizations.
Unless I'm misunderstanding, a normal computed goto would have an array of all the destinations. And hopefully it would compile to a delta multiply. But if you need to force it... maybe a compile time check that all the labels are delta bytes apart would let you do that math? I don't know, it's not part of the actual standard, it might be janky.
Did a plain old switch statement compile into something you didn't like?
Not that exact quote, but the spirit of it at 44:22.
https://youtu.be/uTxRF5ag27A?t=2662
Quote: "A zero-overhead principle. It basically says that if you have an abstraction, it should not cost anything compared to writing the equivalent code at a lower level."
Bjarne Stroustrup's criterion for language design is that C++ is an abstraction in itself over writing in assembly, and the language design should not get in the way by introducing overhead costs. C++ should allow the programmer to express their intent without losing performance relative to assembly, and it fails in this case due to undefined behavior.
So when the compiler doesn't let you implement your low-level code, it is a failure of the language and compiler relative to the design criteria of C++.