Now you're just using a very arbitrary definition of "broken." The compiler, in this specific instance, is working precisely as intended. It's not like someone accidentally went and implemented -fdelete-null-pointer-checks into GCC, Clang and MSVC and then everyone else went on accepting it without question. It's a concept with quite a bit of thought and care and discussion put into it.
The basic premise of an optimizing compiler is this: produce output that is at least as fast as the original code as-written and adheres to all defined behavior. In this case, it's spot-on -- the only way through the example function with defined behavior is to have a non-NULL pointer, in which case, the branch comparison is a waste of CPU cycles. For undefined behavior, the compiler has no obligations. All bets are off. You don't get to dereference NULL pointers, then complain that your program didn't work as expected, unless you're working with a compiler that honors obligations above and beyond the C standard.
There are some environments in which you DO want to have some say in what happens next -- which I guess in my opinion would be anywhere that dereferencing a NULL pointer is legal, or at the very least, not instantly and reliably fatal. Compiler authors have not forgotten about you. In GCC, for example, you have two options:
1. Do not use -O2 or -O3
2. Use -O2 or -O3 in conjunction with -fno-delete-null-pointer-checks, in which case, your null pointer checks will be left unmolested.
I know after a similar piece of code to the example was discovered in the Linux kernel, they decided to apply -fno-delete-null-pointer-checks. Not sure if that's still true.
A far more egregious example of a compiler exploiting undefined behavior is GCC 1.x which, when given invalid pragmas, would generate code that attempted to exec nethack, rogue, Emacs towers of hanoi, or failing all of those, just generate a printf making fun of you.
In conclusion... know thy optimizer. It's making decisions about your code that can affect you, and it is configured by default to cover the most common use cases. If your program depends on behaviors that are unusual and not covered by the standard (like being able to dereference a null pointer), then you should review your compiler's documentation and see if you need to tune the optimizer a bit for your use case. But if your standards-compliant compiler is applying a well-documented optimization in a manner that breaks you, then it's your project that's broken, either for using that optimization, or for relying on undefined behavior.