https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119164
--- Comment #1 from Vineet Gupta <vineetg at gcc dot gnu.org> --- The RISC-V mode switching state machine tracks transitions into call insn and out of call insn, going from MODE_DYN to MODE_CALL and back to MODE_DYN. However when the call happens to be last insn of BB (not the tail call case), it ends up with wrong transitions, resulting in a FRM write, which can't be optimized away. The gist of problem is around following codegen as it hits mode_sw (following is from subreg3) (jump_insn 7 6 8 2 (set (pc) (if_then_else (eq (reg/f:DI 141 [ a ]) (const_int 0 [0])) (label_ref:DI 10) (pc))) "node_texture_util.c":6:6 377 {*branchdi} (expr_list:REG_DEAD (reg/f:DI 141 [ a ]) (int_list:REG_BR_PROB 499612076 (nil))) -> 10) (note 8 7 9 3 [bb 3] NOTE_INSN_BASIC_BLOCK) (call_insn 9 8 10 3 (parallel [ (call (mem:SI (symbol_ref:DI ("d") [flags 0x41] <function_decl 0x7e5994026a00 d>) [0 d S4 A32]) (const_int 0 [0])) (use (unspec:SI [ (const_int 0 [0]) ] UNSPEC_CALLEE_CC)) (clobber (reg:SI 1 ra)) ]) "node_texture_util.c":7:5 471 {call_internal} (expr_list:REG_CALL_DECL (symbol_ref:DI ("d") [flags 0x41] <function_decl 0x7e5994026a00 d>) (nil)) (nil)) (code_label 10 9 11 4 2 (nil) [1 uses]) (note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK) (insn 12 11 13 4 (set (reg/f:DI 142) (high:DI (symbol_ref:DI ("c") [flags 0x86] <var_decl 0x7e599402fd10 c>))) "node_texture_util.c":8:7 283 {*movdi_64bit} (nil)) In BB 3, there's call_insn 9 followed by code_label 10 which technically (I think) belongs to BB 4, but hoisted before the BB 4 start note. Anyhow in TARGET_MODE_NEEDED / riscv_frm_mode_needed (), handling call_insn 9 uses next_nonnote_nondebug_insn_bb () to check if it is last insn in BB. Somewhat non-intuitively (to me) this API *includes* code_label 10 and deduces it call is not last insn, failing to insert a fresh FRM read at the end of BB. The next insn passed to TARGET_MODE_NEEDED is not code_label 10 but the one after as generic mode_sw skips over labels due to NONDEBUG_INSN_P filter. That insn 12 fails to backreference to call insn 9 (which it anyways would have given this is a different BB anyways). Eventually TARGET_MODE_EMIT ends up with following transitions frm mode set: 7-dyn to 9-call frm mode set: 10-none to 7-dyn scanning new insn with uid = 56. <--- FRM write frm mode set: 10-none to 8-dyn-exit as opposed to (unconditional call test) frm mode set: 7-dyn to 9-call frm mode set: 9-call to 7-dyn scanning new insn with uid = 44. <-- FRM read which gets optimized away frm mode set: 7-dyn to 8-dyn-exit