If SImode reg is continuous left shifted twice, combine related
instruction to one.

extsv_ashlsi3 combines the mov and shift operations into sign_extrace
and shift, cause optimization template of slli.d + and + add.w =>
and + alsl.w fail to match.
Add new template to match this optimization.

(set (reg:DI 91)
    (ashift:DI (sign_extract:DI (reg:DI 96 [ x ])
            (const_int 31 [0x1f])
            (const_int 0 [0]))
        (const_int 1 [0x1])))
(insn 9 7 10 2 (set (reg:DI 93)
        (const_int 7710 [0x1e1e])) "main.c":10:29 153 {*movdi_64bit}
     (nil))
(insn 10 9 11 2 (set (reg:DI 92)
        (ior:DI (reg:DI 91)
            (reg:DI 93))) "main.c":10:29 98 {*iordi3})

->
(set (reg:DI 95)
    (sign_extend:DI (plus:SI (subreg:SI (ior:DI (subreg:DI (ashift:SI
                                (subreg:SI (reg:DI 96 [ x ]) 0)
                            (const_int 1 [0x1])) 0)
                    (const_int 7710 [0x1e1e])) 0)
            (subreg:SI (reg:DI 97 [ y ]) 0))))

gcc/ChangeLog:

        * config/loongarch/loongarch.md: New template.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/slli-1.c: New test.

Change-Id: I10138f7eaaf6f6ebaa2a6db1c8a89ece3d2d17e5
---
 gcc/config/loongarch/loongarch.md           | 66 +++++++++++++++++++++
 gcc/testsuite/gcc.target/loongarch/slli-1.c | 10 ++++
 2 files changed, 76 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/slli-1.c

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index e23c973c38b..47b9445aa95 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -3127,6 +3127,19 @@ (define_insn "sign_extend_ashift<GPR:mode><SHORT:mode>"
   [(set_attr "type" "shift")
    (set_attr "mode" "<GPR:MODE>")])
 
+(define_insn "extsv_ashlsi3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI
+          (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
+                           (match_operand:SI 2 "const_uimm5_operand")
+                           (const_int 0))
+          (match_operand:SI 3 "const_uimm5_operand")))]
+  "TARGET_64BIT
+    &&(INTVAL (operands[2]) + INTVAL (operands[3])) == 0x20"
+  "slli.w\t%0,%1,%3"
+  [(set_attr "type" "shift")
+   (set_attr "mode" "SI")])
+
 (define_insn "*rotr<mode>3"
   [(set (match_operand:GPR 0 "register_operand" "=r,r")
        (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
@@ -3293,6 +3306,59 @@ (define_insn_and_split "<optab>_alsl_reversesi_extended"
       }
   })
 
+(define_insn_and_split "<optab>_alsl_reversesi_1_extended"
+  [(set (match_operand:DI 0 "register_operand" "=&r")
+       (sign_extend:DI
+         (plus:SI
+           (subreg:SI
+             (any_bitwise:DI
+               (subreg:DI
+                 (ashift:SI
+                   (subreg:SI
+                     (match_operand:DI 1 "register_operand" "r0")
+                   0)
+                 (match_operand:SI 2 "const_immalsl_operand" ""))
+               0)
+             (match_operand:DI 3 "const_int_operand" "i"))
+           0)
+         (match_operand:SI 4 "register_operand" "r"))))]
+  "TARGET_64BIT
+   && loongarch_reassoc_shift_bitwise (<is_and>, operands[2], operands[3],
+                                      SImode)"
+  "#"
+  "&& reload_completed"
+  [; r0 = r1 [&|^] r3 is emitted in PREPARATION-STATEMENTS because we
+   ; need to handle a special case, see below.
+   (set (match_dup 0)
+       (sign_extend:DI
+         (plus:SI (ashift:SI (subreg:SI (match_dup 0) 0) (match_dup 2))
+                  (match_dup 4))))]
+  {
+    operands[3] = loongarch_reassoc_shift_bitwise (<is_and>,
+                                                 operands[2],
+                                                  operands[3],
+                                                  SImode);
+
+    if (ins_zero_bitmask_operand (operands[3], SImode))
+      {
+       gcc_checking_assert (<is_and>);
+       emit_move_insn (operands[0], operands[1]);
+       operands[1] = operands[0];
+      }
+
+    if (operands[3] != CONSTM1_RTX (SImode))
+      emit_insn (gen_<optab>di3 (operands[0], operands[1], operands[3]));
+    else
+      {
+       /* Hmm would we really reach here?  If we reach here we'd have
+          a miss-optimization in the generic code (as it should have
+          optimized this to alslsi3_extend_subreg).  But let's be safe
+          than sorry.  */
+       gcc_checking_assert (<is_and>);
+       emit_move_insn (operands[0], operands[1]);
+      }
+  })
+
 
 
 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
diff --git a/gcc/testsuite/gcc.target/loongarch/slli-1.c 
b/gcc/testsuite/gcc.target/loongarch/slli-1.c
new file mode 100644
index 00000000000..891d6457b12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/slli-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int
+foo (int x)
+{
+  return (x << 2) * 8;
+}
+
+/* { dg-final { scan-assembler-times "slli\.\[dw\]" 1} } */
-- 
2.20.1

Reply via email to