So I create a thread with a custom stack which is an allocated buffer. At the top, I write a sequence of bytes in some order. Then I periodically read the top of the stack to see if the stack is getting close to overflow. Meanwhile, the thread code is also addressing the same store.
That article is nonsensical. Seymour Cray and colleagues and Tomasula and colleagues invented ILP, branch prediction, etc. in the 1960s before C was thought of. The PDP11 is much more similar to modern x86s than to the weird architectures of the 1970s.
The Chisnall article is a tutorial in incorrect Computer Architecture. PDP11s had caches by the 1970s and always had memory management. IPL was invented in the 1960s and has nothing to do with C. Branch predictors were invented in the 1960s too and one of the first machines C was ported to was the IBM370 which had super sophisticated IPL. Etc.
And switch the i to a size_t and get vector code without the possibility of writing to random memory because your int overflows and GCC wants to pretend it cannot.
This is a poorly written loop. C design model is that if it is not critical, we don't care, and if it is, the programmer should fix it so optimization can work. https://gcc.godbolt.org/z/ErMP4cn6s
in which case the overflow will cause the loop to change some random memory, but its ok since removing a single instruction test that is easy to pipeline is worth incorrect results!
Exactly - it was done for meaningless benchmarking reasons. C programmers would be happy to use "restrict" as an opt-in for those, but this argument about FORTRAN goes back to the initial days of the standard when Dennis Ritchie had to push "noalias" out of the proposed standard.
There is zero evidence that this dichotomy is our only choice. You are also conflating two different things. Ignoring possible out of bounds pointers is perfectly fine. Deleting assignments from aliased pointers is not. Very different things.
Leaving overflow to the processor is an example of ignoring it with unpredictable results. Deleting overflow checks because you assume, incorrectly, that overflow is impossible is not an example of ignoring with unpredictable effects, it does produce unpredictable effects, though.
I bet the performance differences are minimal except perhaps on some contrived cases. The compiler should not assume things it doesn't know.
But show me a benchmark.
e.g. assuming UB can't happen: deleting overflow or null pointer checks, deleting comparisons between pointers that are assumed to point at different objects, ...
That's good example, because nobody would complain if stack layouts changed and those programs failed. But if the compiler chooses to "optimize away" checks on stack layout, that's a different thing altogether. Also note that if you use pthreads or Linux clone or you are writing an operating system you can need to rely on exact stack layouts even today.
More than slightly convoluted. The obvious intention is that the compiler ignores overflow and lets the processor architecture make the decision. Assuming that overflow doesn't happen is assuming something false. There's no excuse for that and it doesn't "optimize" anything.
C programmers prefer control to "optimization". And if you assume UB cannot occur, you should not generate code that makes it happen.
Radical UB is not required for optimization: in fact it appears to mostly do nothing positive. There is not a single paper or study showing significant better performance for substantial C code that depends on assuming UB can't happen - just a bunch of hand waving.
The net result of your argument is the language has no semantics. I write and test with -O0 and show that f(k)=m. Then I run with -O3 and f(k)=random. Am I required to be an expert on C Standard and compiler development in order to know that, with no warning, my code has always been wrong? What about if f(k)=m under Gcc 10, but now under Gcc 10.1 that whole section of code is skipped? What you are asking programmers to do is to both master the fine points of UB (which is impractical) and look into the future to see what changes may be invisibly committed to the compiler code.
For your last point, the extent of UB driven changes to semantics is still not widely known in the programmer community. Programmers don't read the standard - they read K&R, and K&R is right now describing a different language. We've had 15 years of programmers repeatedly filing bug reports to be told that the expected, tested, relied on, behavior was ephemeral. Only very sophisticated projects figure out about UB.
Of course compilers have to make assumptions. The debate is (a) over what assumptions it is proper to make and (b) what are the permissible behaviors. The false dichotomy: either do without any optimizations at all or accept whatever UB gives you, is not a useful approach.