For example:
unsigned long zero_extend_ashift (unsigned int a) { return a * 4; }

Before:
      bstrpick.d  $r4,$r4,29,0
      slli.d      $r4,$r4,2

After:
      alsl.wu $r4,$r4,$r0,2

gcc/ChangeLog:

        * config/loongarch/loongarch.md (*ashlsi3_zero_extend): New insn.
        (*ashlsi3_zero_extend_subreg): New insn.
        (define_split): Split AND-shift operations into zero-extended
        SI shifts.
        (define_peephole2): Combine zero-extension loads with redundant
        AND operations.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/la64/zero-extend-1.c: New test.
---
 gcc/config/loongarch/loongarch.md             | 51 +++++++++++++++++++
 .../gcc.target/loongarch/la64/zero-extend-1.c | 19 +++++++
 2 files changed, 70 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/la64/zero-extend-1.c

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index 9cbc4d44956..c44e4eea187 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -3460,6 +3460,57 @@ (define_insn "*alslsi3_extend_subreg"
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
+(define_insn "*ashlsi3_zero_extend"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+    (zero_extend:DI
+     (ashift:SI
+       (match_operand:SI 1 "register_operand" "r")
+       (match_operand 2 "const_immalsl_operand" ""))))]
+  "TARGET_64BIT"
+  "alsl.wu\t%0,%1,$r0,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "*ashlsi3_zero_extend_subreg"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+    (zero_extend:DI
+     (ashift:SI
+       (subreg:SI (match_operand:DI 1 "register_operand" "r") 0)
+       (match_operand 2 "const_immalsl_operand" ""))))]
+  "TARGET_64BIT"
+  "alsl.wu\t%0,%1,$r0,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+    (and:DI
+      (ashift:DI (match_operand:DI 1 "register_operand")
+            (match_operand 2 "const_immalsl_operand"))
+      (match_operand 3 "const_int_operand")))]
+  "TARGET_64BIT
+   && INTVAL (operands[3]) == (0xffffffff << INTVAL (operands[2]))"
+  [(set (match_dup 0)
+        (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))]
+{
+   operands[1] = gen_lowpart (SImode, operands[1]);
+})
+
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand")
+    (zero_extend:SI
+      (match_operand:SHORT 1 "memory_operand")))
+   (set (match_operand:DI 2 "register_operand")
+     (and:DI (match_operand:DI 3 "register_operand")
+       (match_operand 4 "const_int_operand")))]
+  "REGNO (operands[0]) == REGNO (operands[3])
+   && (peep2_reg_dead_p (2, operands[0])
+       || REGNO (operands[0]) == REGNO (operands[2]))
+   && (GET_MODE (operands[1]) == HImode
+       ? hi_mask_operand (operands[4], VOIDmode)
+       : qi_mask_operand (operands[4], VOIDmode))"
+  [(set (match_dup 2) (zero_extend:DI (match_dup 1)))])
+
 ;; The generic code prefers "(reg << shamt) [&|^] (mask << shamt)"
 ;; instead of "(reg [&|^] mask) << shamt" but we want the latter if
 ;; we don't need to load mask into an register, and either:
diff --git a/gcc/testsuite/gcc.target/loongarch/la64/zero-extend-1.c 
b/gcc/testsuite/gcc.target/loongarch/la64/zero-extend-1.c
new file mode 100644
index 00000000000..c36a6683885
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/la64/zero-extend-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=loongarch64 -mabi=lp64d" } */
+/* { dg-final { scan-assembler-times "alsl.wu" 1 } } */
+/* { dg-final { scan-assembler-not "bstrpick.d" } } */
+
+unsigned long
+f1 (unsigned int a)
+{
+  return a * 4;
+}
+
+extern unsigned short b;
+
+unsigned long
+f2 ()
+{
+  return b * 4;
+}
+
-- 
2.20.1

Reply via email to