https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105338
--- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Ok, so at least for the 2nd function, the problem is that we reject it from noce_try_cmove as well from noce_try_cmove_arith based on costs. That is the case for the NEXT_PASS (pass_sink_code, false /* unsplit edges */); compilation too, though it seems the cost is 4 higher in the vanilla trunk case. I think that can be perhaps fixed with: --- gcc/config/i386/i386-expand.cc.jj 2022-04-22 14:18:27.000000000 +0200 +++ gcc/config/i386/i386-expand.cc 2022-04-22 15:13:47.263829089 +0200 @@ -3224,8 +3224,7 @@ ix86_expand_int_movcc (rtx operands[]) } diff = ct - cf; - if (reg_overlap_mentioned_p (out, op0) - || reg_overlap_mentioned_p (out, op1)) + if (reg_overlap_mentioned_p (out, compare_op)) tmp = gen_reg_rtx (mode); if (mode == DImode) - at least I don't really see the point of using yet another temporary when we already emitted the comparison earlier and all we emit is compare_op and assignment to out. Anyway, with NEXT_PASS (pass_sink_code, false /* unsplit edges */); it succeeds then with cond_move_process_if_block. But it doesn't with vanilla trunk, because it punts on: 4060 /* Don't try to handle this if the condition uses the 4061 destination register. */ 4062 if (reg_overlap_mentioned_p (dest, cond)) 4063 return FALSE; I'd say it is reasonable to punt on that, because the whole cond_move_process_if_block is meant to handle multiple cmoves, not just one, and we handle all of them with the same cond. The only case that could be handled is if it is the very last set in then_bb and else_bb is not present, or if it is the last set in else_bb. I must say I'm also quite surprised we don't really check any costs in the cond_move_process_if_block and just blindly assume it will always be a win, so it seems it happily handles even the cases of a single dest assignment that earlier noce_* routines attempt (but those do check the costs and in this case punt).