For a signed bit-field copy with field width W and shift amount S,
W + S <= 32 implies

        ((X << S)[31:0] >> S)[W-1:0] = X[W-1:0],

where X is the DImode source and >> is an arithmetic right shift.
Fold this to zero_extract(X, W, 0) so the existing insv pattern emits
only bstrins.w.

gcc/ChangeLog:

        * config/loongarch/loongarch.md: New split to eliminate redundant
        shifts before bstrins.w.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/la64/slli-srai-bstrins-w.c: New test.

---
 gcc/config/loongarch/loongarch.md             | 17 +++++++++++++++++
 .../loongarch/la64/slli-srai-bstrins-w.c      | 19 +++++++++++++++++++
 2 files changed, 36 insertions(+)
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/la64/slli-srai-bstrins-w.c

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index ceacc5995e6..1c0b2755572 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -2340,6 +2340,23 @@ (define_insn "*insv<mode>"
 }
   [(set_attr "type" "arith")
    (set_attr "mode" "<MODE>")])
+
+(define_split
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand")
+                        (match_operand:SI 1 "const_int_operand")
+                        (const_int 0))
+       (ashiftrt:SI
+         (subreg:SI
+           (ashift:DI (match_operand:DI 2 "register_operand")
+                      (match_operand:SI 3 "const_uimm5_operand")) 0)
+         (match_dup 3)))]
+  "TARGET_64BIT
+   && INTVAL (operands[1]) > 0
+   && INTVAL (operands[1]) + INTVAL (operands[3]) <= 32"
+  [(set (zero_extract:SI (match_dup 0)
+                        (match_dup 1)
+                        (const_int 0))
+       (subreg:SI (match_dup 2) 0))])
 
 ;;
 ;;  ....................
diff --git a/gcc/testsuite/gcc.target/loongarch/la64/slli-srai-bstrins-w.c 
b/gcc/testsuite/gcc.target/loongarch/la64/slli-srai-bstrins-w.c
new file mode 100644
index 00000000000..8745f963fc4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/la64/slli-srai-bstrins-w.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { scan-assembler-not "slli\\.w" } } */
+/* { dg-final { scan-assembler-not "srai\\.w" } } */
+
+struct
+{
+  int a : 23, b : 9;
+} foo;
+struct
+{
+  int a : 23, b : 9;
+} bar;
+
+void
+f (void)
+{
+  bar.a = foo.a;
+}
-- 
2.55.0

Reply via email to