https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127900
--- Comment #10 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Uros Bizjak <[email protected]>: https://gcc.gnu.org/g:f9eedd09c994e73405f6ac19acfda4ce866e9d22 commit r17-5304-gf9eedd09c994e73405f6ac19acfda4ce866e9d22 Author: Uros Bizjak <[email protected]> Date: Fri Oct 16 16:34:19 2026 +0200 i386: Use MULX for highpart-only multiplications [PR127900] For the testcase u64 mulh (u64 a, u64 b) { return ((unsigned __int128) a * b) >> 64; } GCC emits MUL, which clobbers both %rax and %rdx and the flags, even with -mbmi2, because the highpart-only multiplication patterns have no MULX alternative. MULX can write the high half to any register and doesn't clobber flags, so it avoids the extra register moves and frees %rax. Split the unsigned highpart multiplication patterns from the signed ones, since only the unsigned ones have a MULX form. Convert the unsigned patterns to define_insn_and_split with two alternatives: a BMI2 one that takes operand 1 in %rdx and is split after reload to MULX, and the existing MUL one. The splitters generate the existing *bmi2_umul<mode>3_highpart pattern, or the new *bmi2_umulsi3_highpart_zext pattern for the zero-extended SImode form. The signed patterns keep a single IMUL alternative, with the mnemonic written explicitly instead of through <sgnprefix>. Also use register_operand for operand 1 of the highpart patterns that used nonimmediate_operand, which makes the !(MEM_P (operands[1]) && MEM_P (operands[2])) conditions redundant, and remove them. Mark operand 1 of *bmi2_umul<mode>3_highpart as commutative. The second multiplication in g++.target/i386/pr113560.C needs only the high part and now uses MULX instead of MULQ, and the register allocator no longer needs to preserve %rax across it, so the return value increment becomes ADDQ instead of LEAQ. PR target/127900 gcc/ChangeLog: * config/i386/i386.md (*bmi2_umul<mode>3_highpart): Mark operand 1 as commutative. (<s>mul<mode>3_highpart): Split into... (umul<mode>3_highpart): ... a define_insn_and_split with a BMI2 alternative and ... (smul<mode>3_highpart): ... a define_insn. (*bmi2_umulsi3_highpart_zext): New pattern. (*<s>mulsi3_highpart_zext): Split into... (*umulsi3_highpart_zext): ... a define_insn_and_split with a BMI2 alternative and ... (*smulsi3_highpart_zext): ... a define_insn. (*<s>muldi3_highpart_1): Split into... (*umuldi3_highpart_1): ... a define_insn_and_split with a BMI2 alternative and ... (*smuldi3_highpart_1): ... a define_insn. Use register_operand for operand 1 and remove redundant MEM_P condition. (*<s>mulsi3_highpart_zext): Split into... (*umulsi3_highpart_1_zext): ... a define_insn_and_split with a BMI2 alternative and ... (*smulsi3_highpart_1_zext): ... a define_insn. Use register_operand for operand 1 and remove redundant MEM_P condition. (*<s>mulsi3_highpart_1): Split into... (*umulsi3_highpart_1): ... a define_insn_and_split with a BMI2 alternative and ... (*smulsi3_highpart_1): ... a define_insn. Use register_operand for operand 1 and remove redundant MEM_P condition. gcc/testsuite/ChangeLog: * gcc.target/i386/pr127900.c: New test.
