1. Can generate mulh.w[u] instruction.
        2. Can generate mulw.d.wu instruction.

gcc/ChangeLog:

        * config/loongarch/loongarch.md (mulsidi3_64bit):
        (<u>muldi3_highpart): Modify template name.
        (<u>mulsi3_highpart): Likewise.
        (<u>mulsidi3_64bit): Field unsigned extension support.
        (<su>muldi3_highpart): Modify muldi3_highpart to
        smuldi3_highpart.
        (<su>mulsi3_highpart): Modify mulsi3_highpart to
        smulsi3_highpart.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/mulw_d_wu.c: New test.
        * gcc.target/loongarch/smuldi3_highpart.c: New test.
        * gcc.target/loongarch/smulsi3_highpart.c: New test.
        * gcc.target/loongarch/umulsi3_highpart.c: New test.
---
 gcc/config/loongarch/loongarch.md             | 66 ++++++++++++-------
 .../gcc.target/loongarch/mulw_d_wu.c          |  9 +++
 .../gcc.target/loongarch/smuldi3_highpart.c   | 13 ++++
 .../gcc.target/loongarch/smulsi3_highpart.c   | 15 +++++
 .../gcc.target/loongarch/umulsi3_highpart.c   | 14 ++++
 5 files changed, 94 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/mulw_d_wu.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/smuldi3_highpart.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/smulsi3_highpart.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/umulsi3_highpart.c

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index 25e2e1e0597..5e9a3ec15e0 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -721,15 +721,6 @@ (define_insn "mul<mode>3"
   [(set_attr "type" "imul")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "mulsidi3_64bit"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
-                (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
-  "TARGET_64BIT"
-  "mulw.d.w\t%0,%1,%2"
-  [(set_attr "type" "imul")
-   (set_attr "mode" "DI")])
-
 (define_insn "*mulsi3_extended"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (sign_extend:DI
@@ -758,14 +749,14 @@ (define_expand "<u>mulditi3"
   emit_insn (gen_muldi3 (low, operands[1], operands[2]));
 
   rtx high = gen_reg_rtx (DImode);
-  emit_insn (gen_<u>muldi3_highpart (high, operands[1], operands[2]));
+  emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
 
   emit_move_insn (gen_lowpart (DImode, operands[0]), low);
   emit_move_insn (gen_highpart (DImode, operands[0]), high);
   DONE;
 })
 
-(define_insn "<u>muldi3_highpart"
+(define_insn "<su>muldi3_highpart"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (truncate:DI
          (lshiftrt:TI
@@ -780,22 +771,34 @@ (define_insn "<u>muldi3_highpart"
    (set_attr "mode" "DI")])
 
 (define_expand "<u>mulsidi3"
-  [(set (match_operand:DI 0 "register_operand" "=r")
+  [(set (match_operand:DI 0 "register_operand")
        (mult:DI (any_extend:DI
-                  (match_operand:SI 1 "register_operand" " r"))
+                  (match_operand:SI 1 "register_operand"))
                 (any_extend:DI
-                  (match_operand:SI 2 "register_operand" " r"))))]
-  "!TARGET_64BIT"
+                  (match_operand:SI 2 "register_operand"))))]
+  ""
 {
-  rtx temp = gen_reg_rtx (SImode);
-  emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
-  emit_insn (gen_<u>mulsi3_highpart (loongarch_subword (operands[0], true),
-                                    operands[1], operands[2]));
-  emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
-  DONE;
+  if (!TARGET_64BIT)
+  {
+    rtx temp = gen_reg_rtx (SImode);
+    emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
+    emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
+                                      operands[1], operands[2]));
+    emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
+    DONE;
+  }
 })
 
-(define_insn "<u>mulsi3_highpart"
+(define_insn "<u>mulsidi3_64bit"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_64BIT"
+  "mulw.d.w<u>\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "DI")])
+
+(define_insn "<su>mulsi3_highpart"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (truncate:SI
          (lshiftrt:DI
@@ -804,11 +807,28 @@ (define_insn "<u>mulsi3_highpart"
                     (any_extend:DI
                       (match_operand:SI 2 "register_operand" " r")))
            (const_int 32))))]
-  "!TARGET_64BIT"
+  ""
   "mulh.w<u>\t%0,%1,%2"
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")])
 
+;; Under the LoongArch architecture, the mulh.w[u] instruction performs
+;; sign extension by default, so the sign extension instruction can be
+;; eliminated.
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand")
+       (truncate:SI
+         (lshiftrt:DI
+           (mult:DI (any_extend:DI
+                      (match_operand:SI 1 "register_operand"))
+                    (any_extend:DI
+                      (match_operand:SI 2 "register_operand")))
+           (const_int 32))))
+   (set (match_operand:DI 3 "register_operand")
+       (sign_extend:DI (match_dup 0)))]
+   "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
+   "mulh.w<u>\t%0,%1,%2")
+
 ;;
 ;;  ....................
 ;;
diff --git a/gcc/testsuite/gcc.target/loongarch/mulw_d_wu.c 
b/gcc/testsuite/gcc.target/loongarch/mulw_d_wu.c
new file mode 100644
index 00000000000..16163d6675d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/mulw_d_wu.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mabi=lp64d" } */
+/* { dg-final { scan-assembler "mulw.d.wu" } } */
+
+__attribute__((noipa, noinline)) unsigned long
+f(unsigned long a, unsigned long b)
+{
+  return (unsigned long)(unsigned int)a * (unsigned long)(unsigned int)b;
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/smuldi3_highpart.c 
b/gcc/testsuite/gcc.target/loongarch/smuldi3_highpart.c
new file mode 100644
index 00000000000..6f5c686ca38
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/smuldi3_highpart.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O2 -fdump-rtl-expand-all" } */
+
+typedef int TI __attribute ((mode(TI)));
+typedef int DI __attribute__((mode(DI)));
+
+DI
+test (DI x, DI y)
+{
+  return ((TI)x * y) >> 64;
+}
+
+/* { dg-final { scan-rtl-dump "highparttmp" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/loongarch/smulsi3_highpart.c 
b/gcc/testsuite/gcc.target/loongarch/smulsi3_highpart.c
new file mode 100644
index 00000000000..c4dbf8afc24
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/smulsi3_highpart.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-rtl-expand-all" } */
+
+typedef unsigned int DI __attribute__((mode(DI)));
+typedef unsigned int SI __attribute__((mode(SI)));
+
+SI
+f (SI x, SI y)
+{
+  return ((DI) x * y) >> 32;
+}
+
+/* { dg-final { scan-rtl-dump "highparttmp" "expand" } } */
+/* { dg-final { scan-assembler "mulh\\.w" } } */
+/* { dg-final { scan-assembler-not "slli\\.w" } } */
diff --git a/gcc/testsuite/gcc.target/loongarch/umulsi3_highpart.c 
b/gcc/testsuite/gcc.target/loongarch/umulsi3_highpart.c
new file mode 100644
index 00000000000..e208803e2d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/umulsi3_highpart.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef unsigned int DI __attribute__((mode(DI)));
+typedef unsigned int SI __attribute__((mode(SI)));
+
+SI
+f (SI x, SI y)
+{
+  return ((DI) x * y) >> 32;
+}
+
+/* { dg-final { scan-assembler "mulh\\.wu" } } */
+/* { dg-final { scan-assembler-not "slli\\.w" } } */
-- 
2.31.1

Reply via email to