UB means the compiler is free to perform whatever optimizations it wants. Are you really saying that no optimizations are allowed once the compiler notices UB?
Michael Chastain (GDB developer, one of the few people with commit rights to the root of Google's monorepo) told me about the worst bug he ever helped a Googler debug, eventually boiling it down to:
static const double y = 1.0;
static const double x = 2 * y;
printf("Before\n");
if (x > 0.0) {
printf("x\n");
} else {
printf("Not x\n"):
}
printf("After\n");
It was printing "Before\nAfter\n", with nothing in-between.It turns out that the value of x depended upon the initialization order of statically-scoped doubles. There was no malicious optimization in GCC that got rid of both branches, but both branches got optimized away through a series of intermediate steps where the compiler basically split the control flow graph into something equivalent to:
static const double y = 1.0;
static const double x = 2 * y;
printf("Before\n");
if (x > 0.0) {
printf("x\n");
}
if (!(x > 0.0)) {
printf("Not x\n"):
}
printf("After\n");
GCC determined that x was statically determinied and UB. In both places an optimization pass determined that the fastest choice for if(UB) is to branch over the code in question. Since it's UB, the compiler wasn't required to pick some self-consistent value for x. It's free to optimize away all if(UB) blocks to if(false) blocks.(Note that this particular case of UB is specific to floating point types and would not occur with integer types. I believe the intention of the spec is to avoid the requirement for floating point hardware to behave identically, including the state bits that affect rounding etc., to behave identically on the machine where the compiler is run and on the machine where the program is run. My naive hot take would be that this should be ID, not UB, but I'm sure the standards committee put a lot more thought into this than I have.)
It wasn't some malicious or two-clever optimization. It was the emergent behavior of a series of optimizations, each one correct.
Anyway, long story short, once the compiler notices UB, all optimizations are on the table. You seem to be implying that compilers need to be conservative when they detect UB. Compilers are generally recklessly aggressive in optimizing when they detect UB.