[PATCH v2 3/3] i386: Add peephole2 to convert highpart mul to mulx

H.J. Lu hjl.tools@gmail.com
Sun May 3 06:49:38 GMT 2026


On Sun, May 3, 2026 at 1:36 PM <herumi@nifty.com> wrote:
>
> From: MITSUNARI Shigeo <herumi@nifty.com>
>
> When the register allocator selects the MUL-based highpart pattern
> (umuldi3_highpart) with the source value already in %rdx, it inserts
> a redundant mov to %rax before the mul instruction.  Add a peephole2
> that detects this mov + mul sequence and converts it to a single mulx,
> eliminating the extra mov.
>
> This improves inlined loops that perform multiple unsigned divisions
> by constants.  For example, a loop with three div-by-constant
> operations now generates 15 instructions (matching LLVM) instead
> of 18.
>
> Before (loop body excerpt):
>         mov     rax, rdx
>         mul     r9
>
> After:
>         mulx    rdx, rax, r9

Please add a test with check-function-bodies, like

[hjl@gnu-tgl-3 testsuite]$ cat gcc.target/i386/pr14907-3.c
/* { dg-do compile } */
/* { dg-options "-O2 -g0" } */
/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux*
*-*-gnu* } {^\t?\.} } } */

/*
x86*c1:
x86*.LFB0:
x86* .cfi_startproc
x86* jmp c2
x86* .cfi_endproc
x86*...
*/

extern char c2 (char);

char
c1 (char c)
{
  return c2 (c);
}
[hjl@gnu-tgl-3 testsuite]$

> gcc/ChangeLog:
>
>         * config/i386/i386.md: Add peephole2 to convert
>         mov + umul_highpart to mulx on BMI2 targets.
> ---
>  gcc/config/i386/i386.md | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
> index 472f9d41332..1c394690b04 100644
> --- a/gcc/config/i386/i386.md
> +++ b/gcc/config/i386/i386.md
> @@ -11522,6 +11522,23 @@
>     (set_attr "prefix" "vex")
>     (set_attr "mode" "<MODE>")])
>
> +;; Convert mov + highpart mul to mulx when the mov source is %rdx.
> +;; mov %rdx, %rax; mulq %src -> mulx %src, %rax, %out
> +(define_peephole2
> +  [(set (match_operand:DWIH 0 "register_operand")
> +       (match_operand:DWIH 1 "register_operand"))
> +   (parallel [(set (match_operand:DWIH 2 "register_operand")
> +                  (umul_highpart:DWIH (match_dup 0)
> +                       (match_operand:DWIH 3 "nonimmediate_operand")))
> +             (clobber (match_dup 0))
> +             (clobber (reg:CC FLAGS_REG))])]
> +  "TARGET_BMI2
> +   && REGNO (operands[1]) == DX_REG
> +   && REGNO (operands[0]) != REGNO (operands[2])"
> +  [(parallel [(set (match_dup 2)
> +                  (umul_highpart:DWIH (match_dup 1) (match_dup 3)))
> +             (clobber (match_dup 0))])])
> +
>  ;; Highpart multiplication patterns
>  (define_insn "<s>mul<mode>3_highpart"
>    [(set (match_operand:DWIH 0 "register_operand" "=d")
> --
> 2.43.0
>


-- 
H.J.


More information about the Gcc-patches mailing list