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