There are some well-publicised cases of compilers removing NULL-checks[0] on the assumption that the NULL value can't occur as it would be UB.
As another example, the Linux kernel assumes in several places that signed integer overflow wraps, so it is compiling with -f-no-strict-overflow/-fwrapv ever since GCC started optimizing based on this piece of UB (they noticed the compiler behavior change and added the flags before releasing any faulty kernels though, apparently).
People want these optimizations individually. They don't want to keep dead code taking up cycles and they also don't want dead variables taking up registers. So you can't really find much support arguing that those optimizations should be removed entirely. The only real possibilities you can propose here are that the compiler should have magically re-inserted the pruned check during the second optimization, or that it should have performed them in the opposite order. But are you sure these are actually possible and if so, practical? I mean, maybe they are, but they are far from obvious to me. I can easily see the compiler thrashing and failing to reach a fixed point if it re-inserts code that a previous optimization pass pruned. Similarly, I don't see how the compiler can just magically detect an optimization order that ensures "surprising" situations like this don't occur. My guesstimation is that it would carry severe downsides people wouldn't want. Now maybe I'm just not smart enough to see a good solution to this that doesn't carry significant downsides, and there's already one out there. If there is, I'm curious to hear about it, and I hope someone implements it under some flag, but I have yet to hear of one.
For signed integer overflow -- that might be one place where I think it would make sense to just define it to either wrap with 2's complement just like unsigned integers do, or to be unspecified behavior that falls back to the implementation's representation. Though in the latter case... you already have an implementation-specific solution: your compiler flags. But again, we might agree on a couple optimizations here and there, but that's a far cry from saying UB should just fall back to hardware behavior. And honestly, I'm not even here supporting C; I hate it. If you want wrapping, I would suggest it's a sign you might want to use C++ already. Then you can define an integer type that will play Beethoven when you overflow, and people who want their UB on overflow can have that too.
[1] I'm ignoring the validity of address 0 in kernel-mode here; there's also some subtleties on what's a null pointer and what's address zero that are rather beside my point.
That's the sort of thing I would suggest - don't work back from UB (and I agree, I wouldn't expect the optimizer to backtrack optimizations as new facts come up), work forward from actually known facts.
NULL checks are probably a pretty bad example, since the NULL access would surely SEGFAULT if allowed to execute (though the particular case of address 0 vs NULL, and of code catching segfaults like on Windows, throw a wrench in this assumption eve here), but other types of UB are much worse.
If you accidentally issue a read from a point after the end of an array, but only later check that the index was within bounds (e.g. `int x = a[i]; if i < len(a) return x; else return NULL`), the compiler eliding the bounds check by the same logic will take a program that might have been safe in practice to a program that is certainly not safe. Note that I don't know if compilers perform this type of optimization, so this may be a hypothetical.
In general though, I think that the tension here comes from C being used in 2 very different use cases: 1 is C used as portable assembly, where you expect the compiler to keep a pretty 1:1 mapping with your code; and the second one is C used as the ultimate performance language, where you drop to C when you can't optimize further in anything else. I think most of the complaints about "exploiting UB" come from the first camp, whereas the second camp is pretty happy with the current status quo.
In the case of your safety check example, it'd be nice if you could mention something concrete so we know exactly what situation you're talking about. But I mean, I can't rule out that maybe you'll find a couple situations here and there where the standard shouldn't leave things undefined. But the argument I'm rebutting here is that all instances of UB must behave "like the hardware", not that this particular instance is good but another one is bad, so I'm not sure you two would agree. I agree warnings would be nice too (some of which already exist), and I think despite their current efforts compiler still have some ways to go (e.g. a macro expanding to 0 should probably not behave the same as the literal 0 when you multiply, say, by a constant), but again, that's already assuming you're fine with UB...