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