diff options
author | Roger Sayle <roger@nextmovesoftware.com> | 2023-10-27 10:03:53 +0100 |
---|---|---|
committer | Roger Sayle <roger@nextmovesoftware.com> | 2023-10-27 10:03:53 +0100 |
commit | 89e5d902fc55ad375f149f25a84c516ad360a606 (patch) | |
tree | 8e78e96833129965eb69d155f00ceb9e04bd0a21 | |
parent | 8697d3a1dcf32750a3b9dc007586eb5f9ba5f17a (diff) | |
download | gcc-89e5d902fc55ad375f149f25a84c516ad360a606.zip gcc-89e5d902fc55ad375f149f25a84c516ad360a606.tar.gz gcc-89e5d902fc55ad375f149f25a84c516ad360a606.tar.bz2 |
PR target/110551: Fix reg allocation for widening multiplications on x86.
This patch contains clean-ups of the widening multiplication patterns in
i386.md, and provides variants of the existing highpart multiplication
peephole2 transformations (that tidy up register allocation after
reload), and thereby fixes PR target/110551, which is a superfluous
move instruction.
For the new test case, compiled on x86_64 with -O2.
Before:
mulx64: movabsq $-7046029254386353131, %rcx
movq %rcx, %rax
mulq %rdi
xorq %rdx, %rax
ret
After:
mulx64: movabsq $-7046029254386353131, %rax
mulq %rdi
xorq %rdx, %rax
ret
The clean-ups are (i) that operand 1 is consistently made register_operand
and operand 2 becomes nonimmediate_operand, so that predicates match the
constraints, (ii) the representation of the BMI2 mulx instruction is
updated to use the new umul_highpart RTX, and (iii) because operands
0 and 1 have different modes in widening multiplications, "a" is a more
appropriate constraint than "0" (which avoids spills/reloads containing
SUBREGs). The new peephole2 transformations are based upon those at
around line 9951 of i386.md, that begins with the comment
;; Highpart multiplication peephole2s to tweak register allocation.
;; mov imm,%rdx; mov %rdi,%rax; imulq %rdx -> mov imm,%rax; imulq %rdi
2023-10-27 Roger Sayle <roger@nextmovesoftware.com>
gcc/ChangeLog
PR target/110551
* config/i386/i386.md (<u>mul<mode><dwi>3): Make operands 1 and
2 take "regiser_operand" and "nonimmediate_operand" respectively.
(<u>mulqihi3): Likewise.
(*bmi2_umul<mode><dwi>3_1): Operand 2 needs to be register_operand
matching the %d constraint. Use umul_highpart RTX to represent
the highpart multiplication.
(*umul<mode><dwi>3_1): Operand 2 should use regiser_operand
predicate, and "a" rather than "0" as operands 0 and 2 have
different modes.
(define_split): For mul to mulx conversion, use the new
umul_highpart RTX representation.
(*mul<mode><dwi>3_1): Operand 1 should be register_operand
and the constraint %a as operands 0 and 1 have different modes.
(*<u>mulqihi3_1): Operand 1 should be register_operand matching
the constraint %0.
(define_peephole2): Providing widening multiplication variants
of the peephole2s that tweak highpart multiplication register
allocation.
gcc/testsuite/ChangeLog
PR target/110551
* gcc.target/i386/pr110551.c: New test case.
-rw-r--r-- | gcc/config/i386/i386.md | 75 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr110551.c | 12 |
2 files changed, 68 insertions, 19 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 732c7a0..eb4121b 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -9725,33 +9725,29 @@ [(parallel [(set (match_operand:<DWI> 0 "register_operand") (mult:<DWI> (any_extend:<DWI> - (match_operand:DWIH 1 "nonimmediate_operand")) + (match_operand:DWIH 1 "register_operand")) (any_extend:<DWI> - (match_operand:DWIH 2 "register_operand")))) + (match_operand:DWIH 2 "nonimmediate_operand")))) (clobber (reg:CC FLAGS_REG))])]) (define_expand "<u>mulqihi3" [(parallel [(set (match_operand:HI 0 "register_operand") (mult:HI (any_extend:HI - (match_operand:QI 1 "nonimmediate_operand")) + (match_operand:QI 1 "register_operand")) (any_extend:HI - (match_operand:QI 2 "register_operand")))) + (match_operand:QI 2 "nonimmediate_operand")))) (clobber (reg:CC FLAGS_REG))])] "TARGET_QIMODE_MATH") (define_insn "*bmi2_umul<mode><dwi>3_1" [(set (match_operand:DWIH 0 "register_operand" "=r") (mult:DWIH - (match_operand:DWIH 2 "nonimmediate_operand" "%d") + (match_operand:DWIH 2 "register_operand" "%d") (match_operand:DWIH 3 "nonimmediate_operand" "rm"))) (set (match_operand:DWIH 1 "register_operand" "=r") - (truncate:DWIH - (lshiftrt:<DWI> - (mult:<DWI> (zero_extend:<DWI> (match_dup 2)) - (zero_extend:<DWI> (match_dup 3))) - (match_operand:QI 4 "const_int_operand"))))] - "TARGET_BMI2 && INTVAL (operands[4]) == <MODE_SIZE> * BITS_PER_UNIT + (umul_highpart:DWIH (match_dup 2) (match_dup 3)))] + "TARGET_BMI2 && !(MEM_P (operands[2]) && MEM_P (operands[3]))" "mulx\t{%3, %0, %1|%1, %0, %3}" [(set_attr "type" "imulx") @@ -9762,7 +9758,7 @@ [(set (match_operand:<DWI> 0 "register_operand" "=r,A") (mult:<DWI> (zero_extend:<DWI> - (match_operand:DWIH 1 "nonimmediate_operand" "%d,0")) + (match_operand:DWIH 1 "register_operand" "%d,a")) (zero_extend:<DWI> (match_operand:DWIH 2 "nonimmediate_operand" "rm,rm")))) (clobber (reg:CC FLAGS_REG))] @@ -9798,11 +9794,7 @@ [(parallel [(set (match_dup 3) (mult:DWIH (match_dup 1) (match_dup 2))) (set (match_dup 4) - (truncate:DWIH - (lshiftrt:<DWI> - (mult:<DWI> (zero_extend:<DWI> (match_dup 1)) - (zero_extend:<DWI> (match_dup 2))) - (match_dup 5))))])] + (umul_highpart:DWIH (match_dup 1) (match_dup 2)))])] { split_double_mode (<DWI>mode, &operands[0], 1, &operands[3], &operands[4]); @@ -9813,7 +9805,7 @@ [(set (match_operand:<DWI> 0 "register_operand" "=A") (mult:<DWI> (sign_extend:<DWI> - (match_operand:DWIH 1 "nonimmediate_operand" "%0")) + (match_operand:DWIH 1 "register_operand" "%a")) (sign_extend:<DWI> (match_operand:DWIH 2 "nonimmediate_operand" "rm")))) (clobber (reg:CC FLAGS_REG))] @@ -9833,7 +9825,7 @@ [(set (match_operand:HI 0 "register_operand" "=a") (mult:HI (any_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "%0")) + (match_operand:QI 1 "register_operand" "%0")) (any_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) (clobber (reg:CC FLAGS_REG))] @@ -9850,6 +9842,51 @@ (set_attr "bdver1_decode" "direct") (set_attr "mode" "QI")]) +;; Widening multiplication peephole2s to tweak register allocation. +;; mov imm,%rdx; mov %rdi,%rax; mulq %rdx -> mov imm,%rax; mulq %rdi +(define_peephole2 + [(set (match_operand:DWIH 0 "general_reg_operand") + (match_operand:DWIH 1 "immediate_operand")) + (set (match_operand:DWIH 2 "general_reg_operand") + (match_operand:DWIH 3 "general_reg_operand")) + (parallel [(set (match_operand:<DWI> 4 "general_reg_operand") + (mult:<DWI> (zero_extend:<DWI> (match_dup 2)) + (zero_extend:<DWI> (match_dup 0)))) + (clobber (reg:CC FLAGS_REG))])] + "REGNO (operands[3]) != AX_REG + && REGNO (operands[0]) != REGNO (operands[2]) + && REGNO (operands[0]) != REGNO (operands[3]) + && (REGNO (operands[0]) == REGNO (operands[4]) + || REGNO (operands[0]) == DX_REG + || peep2_reg_dead_p (3, operands[0]))" + [(set (match_dup 2) (match_dup 1)) + (parallel [(set (match_dup 4) + (mult:<DWI> (zero_extend:<DWI> (match_dup 2)) + (zero_extend:<DWI> (match_dup 3)))) + (clobber (reg:CC FLAGS_REG))])]) + +;; mov imm,%rax; mov %rdi,%rdx; mulx %rax -> mov imm,%rdx; mulx %rdi +(define_peephole2 + [(set (match_operand:DWIH 0 "general_reg_operand") + (match_operand:DWIH 1 "immediate_operand")) + (set (match_operand:DWIH 2 "general_reg_operand") + (match_operand:DWIH 3 "general_reg_operand")) + (parallel [(set (match_operand:DWIH 4 "general_reg_operand") + (mult:DWIH (match_dup 2) (match_dup 0))) + (set (match_operand:DWIH 5 "general_reg_operand") + (umul_highpart:DWIH (match_dup 2) (match_dup 0)))])] + "REGNO (operands[3]) != DX_REG + && REGNO (operands[0]) != REGNO (operands[2]) + && REGNO (operands[0]) != REGNO (operands[3]) + && (REGNO (operands[0]) == REGNO (operands[4]) + || REGNO (operands[0]) == REGNO (operands[5]) + || peep2_reg_dead_p (3, operands[0]))" + [(set (match_dup 2) (match_dup 1)) + (parallel [(set (match_dup 4) + (mult:DWIH (match_dup 2) (match_dup 3))) + (set (match_dup 5) + (umul_highpart:DWIH (match_dup 2) (match_dup 3)))])]) + ;; Highpart multiplication patterns (define_insn "<s>mul<mode>3_highpart" [(set (match_operand:DWIH 0 "register_operand" "=d") diff --git a/gcc/testsuite/gcc.target/i386/pr110551.c b/gcc/testsuite/gcc.target/i386/pr110551.c new file mode 100644 index 0000000..142b808 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr110551.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +typedef unsigned long long uint64_t; + +uint64_t mulx64(uint64_t x) +{ + __uint128_t r = (__uint128_t)x * 0x9E3779B97F4A7C15ull; + return (uint64_t)r ^ (uint64_t)( r >> 64 ); +} + +/* { dg-final { scan-assembler-not "movq" } } */ |