https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88470
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So, we have in *.csa still correct: (note 6 1 4 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (note 4 6 11 2 NOTE_INSN_FUNCTION_BEG) (insn 11 4 12 2 (set (reg:CCNO 17 flags) (compare:CCNO (reg:DI 5 di [orig:91 x ] [91]) (const_int 0 [0]))) "pr88470.c":9:3 8 {*cmpdi_ccno_1} (nil)) (jump_insn 12 11 33 2 (set (pc) (if_then_else (le (reg:CCNO 17 flags) (const_int 0 [0])) (label_ref:DI 62) (pc))) "pr88470.c":9:3 657 {*jcc} (expr_list:REG_DEAD (reg:CCNO 17 flags) (int_list:REG_BR_PROB 7 (nil))) -> 62) ... // prologue that changes CFA, sp etc. ... (note 27 25 28 6 [bb 6] NOTE_INSN_BASIC_BLOCK) (note 28 27 29 6 NOTE_INSN_DELETED) (jump_insn 29 28 30 6 (set (pc) (mem/f:DI (reg:DI 5 di [97]) [2 *c.2_4+0 S8 A64])) "pr88470.c":15:3 660 {*indirect_jump} (expr_list:REG_DEAD (reg:DI 5 di [97]) (nil))) ;; succ: ;; lr out 7 [sp] ;; live out 7 [sp] (barrier 30 29 41) (note 41 30 62 NOTE_INSN_DELETED) ;; basic block 7, loop depth 0, count 0 (precise), probably never executed ;; prev block 6, next block 1, flags: (REACHABLE, RTL) ;; pred: 2 [never] count:0 (precise) ;; bb 7 artificial_defs: { } ;; bb 7 artificial_uses: { u-1(7){ }} ;; lr in 5 [di] 7 [sp] ;; lr use 5 [di] 7 [sp] ;; lr def ;; live in 5 [di] 7 [sp] ;; live gen ;; live kill (code_label 62 41 59 7 6 (nil) [1 uses]) (note 59 62 58 7 [bb 7] NOTE_INSN_BASIC_BLOCK) (jump_insn 58 59 61 7 (set (pc) (mem/f:DI (reg:DI 5 di [97]) [2 *c.2_4+0 S8 A64])) "pr88470.c":15:3 660 {*indirect_jump} (expr_list:REG_DEAD (reg:DI 5 di [97]) (nil))) where bb6 is reachable from within the body of the function where the post-prologue CFI state is in effect, and bb7 which is reachable from the start of the function before the prologue, where a different CFI state is in effect. During jump2 pass we decide to crossjump this and turn it into invalid IL. Now, it is completely unclear what should have prevented this, if the crossjumping needs to compute the CFI state to figure this out it would be bad. The problem here is that because of the UB in the testcase those basic blocks have no successors. In outgoing_edges_match we have: /* If we performed shrink-wrapping, edges to the exit block can only be distinguished for JUMP_INSNs. The two paths may differ in whether they went through the prologue. Sibcalls are fine, we know that we either didn't need or inserted an epilogue before them. */ if (crtl->shrink_wrapped && single_succ_p (bb1) && single_succ (bb1) == EXIT_BLOCK_PTR_FOR_FN (cfun) && !JUMP_P (BB_END (bb1)) && !(CALL_P (BB_END (bb1)) && SIBLING_CALL_P (BB_END (bb1)))) return false; That has been introduced in r179553, more details in https://gcc.gnu.org/ml/gcc-patches/2011-09/msg00775.html Maybe we need to do something similar for this case (crtl->shrink_wrapped && EDGE_COUNT (bb1->succs) == 0 && JUMP_P (BB_END (bb1))?