https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107866
--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> --- For some reason we think that the .UBSAN_NULL call doesn't clobber the load from nullptr: <bb 2> [local count: 118111600]: + # VUSE <.MEM_3(D)> + pretmp_7 = MEM[(int *)0B]; <bb 3> [local count: 1073741824]: - # .MEM_2 = PHI <.MEM_3(D)(2), .MEM_6(5)> + # .MEM_2 = PHI <.MEM_3(D)(2), .MEM_6(3)> # .MEM_4 = VDEF <.MEM_2> a = 0B; # .MEM_6 = VDEF <.MEM_4> # USE = nonlocal escaped # CLB = nonlocal escaped .UBSAN_NULL (0B, 0B, 4); - # VUSE <.MEM_6> - _1 = MEM[(int *)0B]; - if (_1 != 0) + if (pretmp_7 != 0) that's because DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW, ". R . ") and thus .UBSAN_NULL only _reads_ from the first argument passed (but also possibly constant NULL(?) valued operands are considered special). The same happens at -O2 btw. At -O1 we eliminate the load. Ah, and call_may_clobber_ref_p_1 has if (gimple_call_internal_p (call)) switch (auto fn = gimple_call_internal_fn (call)) { /* Treat these internal calls like ECF_PURE for aliasing, they don't write to any memory the program should care about. They have important other side-effects, and read memory, so can't be ECF_NOVOPS. */ case IFN_UBSAN_NULL: case IFN_UBSAN_BOUNDS: case IFN_UBSAN_VPTR: case IFN_UBSAN_OBJECT_SIZE: case IFN_UBSAN_PTR: case IFN_ASAN_CHECK: return false; so they are not a barrier for the motion of loads which is what happens here. Note that only at -O3 we keep the trapping load because we fail to eliminate the conditional there and have <bb 2> [local count: 118111600]: # VUSE <.MEM_3(D)> pretmp_7 = MEM[(int *)0B]; if (pretmp_7 != 0) goto <bb 4>; [11.00%] else goto <bb 3>; [89.00%] <bb 3> [local count: 955630224]: # .MEM_1 = PHI <.MEM_3(D)(2)> # .MEM_8 = VDEF <.MEM_1> a = 0B; # .MEM_11 = VDEF <.MEM_8> # USE = anything # CLB = anything __builtin___ubsan_handle_type_mismatch_v1_abort (&*.Lubsan_data0, 0); <bb 4> [local count: 118111600]: # .MEM_4 = VDEF <.MEM_3(D)> a = 0B; # .MEM_10 = VDEF <.MEM_4> # USE = anything # CLB = anything __builtin___ubsan_handle_type_mismatch_v1_abort (&*.Lubsan_data1, 0); in the end.