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.

Reply via email to