https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88070
--- Comment #3 from Uroš Bizjak <ubizjak at gmail dot com> --- For reference: The assert in create_pre_exit at mode-switching.c expects return copy pair with nothing in between. However, the compiler starts mode switching pass with the following sequence: (insn 19 18 16 2 (set (reg:V2SF 21 xmm0) (mem/c:V2SF (plus:DI (reg/f:DI 7 sp) (const_int -72 [0xffffffffffffffb8])) [0 S8 A64])) "pr88070.c":8 1157 {*movv2sf_internal} (nil)) (insn 16 19 20 2 (set (reg:V2SF 0 ax [orig:91 <retval> ] [91]) (reg:V2SF 0 ax [89])) "pr88070.c":8 1157 {*movv2sf_internal} (nil)) (insn 20 16 21 2 (unspec_volatile [ (const_int 0 [0]) ] UNSPECV_BLOCKAGE) "pr88070.c":8 710 {blockage} (nil)) (insn 21 20 23 2 (use (reg:V2SF 21 xmm0)) "pr88070.c":8 -1 (nil)) Please note how (insn 16) interferes with (insn 19)-(insn 21) return copy pair. The culprit for this is the blockage instruction (insn 20), which causes sched1 pass (pre reload scheduler) to skip marking (insn 19) as unmovable instruction (as a dependent insn on return use insn), so the scheduler is free to schedule (insn 16) between return copy pair (insn 19)-(insn 21). The extra instruction is generated as a kludge in expand_function_end to prevent instructions that may trap to be scheduled into function epilogue. However, the same blockage is generated under exactly the same conditions earlier in the expand_function_end. The first blockage should prevent unwanted scheduling into the epilogue, so there is actually no need for the second one.