Essentially, undefined behaviour exposed to the user is an extra layer of "types"/rules on top of the underlying type system, both of which the compiler can use for optimisation purposes (but only one of which the compiler checks for the programmer). More and more advanced type systems can push more of the former into the latter (e.g. for index-out-of-bounds, in the limit, dependent typing can allow one to statically ensure that all integers are in range of the arrays they index).
EDIT: More information here http://blog.llvm.org/2011/05/what-every-c-programmer-should-...
int v = *p;
if (p == NULL) { /* ... */ }
The compiler uses UB to annotate the type information on p to indicate it's non-null, and then performs type-directed optimization.which can mean erasure of the if block, to be perfectly clear here.
edit: any good compiler will warn about the assignment or throw an error, though, using the right compiler options.