From dea5d386a64d9483b8d879cae37b49c19ba4e73b Mon Sep 17 00:00:00 2001
From: Lulu Cheng <chenglulu@loongson.cn>
Date: Wed, 13 Aug 2025 11:04:35 +0800
Subject: [PATCH 01/14] LoongArch: Define hook
 TARGET_COMPUTE_PRESSURE_CLASSES[PR120476].

The rtx cost value defined by the target backend affects the
calculation of register pressure classes in the IRA, thus affecting
scheduling.  This may cause program performance degradation.
For example, OpenSSL 3.5.1 SHA512 and SPEC CPU 2017 exchange_r.

This problem can be avoided by defining a set of register pressure
classes in the target backend instead of using the default IRA to
automatically calculate them.

gcc/ChangeLog:

	PR target/120476
	* config/loongarch/loongarch.cc
	(loongarch_compute_pressure_classes): New function.
	(TARGET_COMPUTE_PRESSURE_CLASSES): Define.

(cherry picked from commit d94178d9b3fb1cb869b90d6f061990eae75c770e)
(cherry picked from commit c4e96a094636b3c15b5e3bfde8673ec3b8172993)
---
 gcc/config/loongarch/loongarch.cc | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index ac24c6d768f..734a3cccc58 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -11152,6 +11152,18 @@ loongarch_c_mode_for_suffix (char suffix)
   return VOIDmode;
 }
 
+/* Implement TARGET_COMPUTE_PRESSURE_CLASSES.  */
+
+static int
+loongarch_compute_pressure_classes (reg_class *classes)
+{
+  int i = 0;
+  classes[i++] = GENERAL_REGS;
+  classes[i++] = FP_REGS;
+  classes[i++] = FCC_REGS;
+  return i;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -11426,6 +11438,9 @@ loongarch_c_mode_for_suffix (char suffix)
 #undef TARGET_C_MODE_FOR_SUFFIX
 #define TARGET_C_MODE_FOR_SUFFIX loongarch_c_mode_for_suffix
 
+#undef TARGET_COMPUTE_PRESSURE_CLASSES
+#define TARGET_COMPUTE_PRESSURE_CLASSES loongarch_compute_pressure_classes
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-loongarch.h"
-- 
2.53.0

From a164df07613288dcd7f6316e811a4df755039a53 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Fri, 22 Aug 2025 21:00:53 +0800
Subject: [PATCH 02/14] LoongArch: Fix ICE in highway-1.3.0 testsuite
 [PR121634]

I can't believe I made such a stupid pasto and the regression test
didn't detect anything wrong.

	PR target/121634

gcc/

	* config/loongarch/simd.md (simd_maddw_evod_<mode>_<su>): Use
	WVEC_HALF instead of WVEC for the mode of the sign_extend for
	the rhs of multiplication.

gcc/testsuite/

	* gcc.target/loongarch/pr121634.c: New test.

(cherry picked from commit 64932714a0786c6ba164cff3468f633cc67b23f5)
(cherry picked from commit 1276b391b4b068655b1d4511d51421302c1a7849)
---
 gcc/config/loongarch/simd.md                  |  2 +-
 gcc/testsuite/gcc.target/loongarch/pr121634.c | 15 +++++++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/pr121634.c

diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
index dd17cd13fc5..4156b269f9a 100644
--- a/gcc/config/loongarch/simd.md
+++ b/gcc/config/loongarch/simd.md
@@ -773,7 +773,7 @@ (define_insn "simd_maddw_evod_<mode>_<su>"
 	      (vec_select:<VEC_HALF>
 		(match_operand:IVEC 2 "register_operand" "f")
 		(match_operand:IVEC 4 "vect_par_cnst_even_or_odd_half")))
-	    (any_extend:<WVEC>
+	    (any_extend:<WVEC_HALF>
 	      (vec_select:<VEC_HALF>
 		(match_operand:IVEC 3 "register_operand" "f")
 		(match_dup 4))))
diff --git a/gcc/testsuite/gcc.target/loongarch/pr121634.c b/gcc/testsuite/gcc.target/loongarch/pr121634.c
new file mode 100644
index 00000000000..325173ad798
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/pr121634.c
@@ -0,0 +1,15 @@
+/* PR target/121634: ICE in highway-1.3.0 testsuite */
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=la464 -mabi=lp64d" } */
+
+typedef short v8i16 __attribute__ ((vector_size (16)));
+typedef int v4i32 __attribute__ ((vector_size (16)));
+typedef long __m128i __attribute__ ((__vector_size__ (16)));
+__m128i x, y;
+
+__m128i
+WidenMulPairwiseAdd (__m128i a, __m128i b)
+{
+  y = (__m128i)__builtin_lsx_vmaddwod_w_h ((v4i32)x, (v8i16){}, (v8i16){});
+  return y;
+}
-- 
2.53.0

From a8da9c4893d1d0143f3868d8991688869c4715a0 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Tue, 8 Jul 2025 14:39:11 +0800
Subject: [PATCH 03/14] lra: Reallow reloading user hard registers if the insn
 is not asm [PR 120983]

The PR 87600 fix has disallowed reloading user hard registers to resolve
earlyclobber-induced conflict.

However before reload, recog completely ignores the constraints of
insns, so the RTL passes may produce insns where some user hard
registers violate an earlyclobber.  Then we'll get an ICE without
reloading them, like what we are recently encountering in LoongArch test
suite.

IIUC "recog does not look at constraints until reload" has been a
well-established rule in GCC for years and I don't have enough skill to
challange it.  So reallow reloading user hard registers (but still
disallow doing so for asm) to fix the ICE.

gcc/ChangeLog:

	PR rtl-optimization/120983
	* lra-constraints.cc (process_alt_operands): Allow reloading
	user hard registers unless the insn is an asm.

(cherry picked from commit e6d3c88e7bb07f94308074f9751e4384a191e022)
(cherry picked from commit 21a87ad785fe1e7c6504c3cf7984e74fe5a5067a)
---
 gcc/lra-constraints.cc | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 7dbc7fe1e00..535991dad06 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -2423,14 +2423,15 @@ process_alt_operands (int only_alternative)
 			if (curr_static_id->operand[nop].type == OP_INOUT
 			    || curr_static_id->operand[m].type == OP_INOUT)
 			  break;
-			/* Operands don't match.  If the operands are
-			   different user defined explicit hard
+			/* Operands don't match.  For asm if the operands
+			   are different user defined explicit hard
 			   registers, then we cannot make them match
 			   when one is early clobber operand.  */
 			if ((REG_P (*curr_id->operand_loc[nop])
 			     || SUBREG_P (*curr_id->operand_loc[nop]))
 			    && (REG_P (*curr_id->operand_loc[m])
-				|| SUBREG_P (*curr_id->operand_loc[m])))
+				|| SUBREG_P (*curr_id->operand_loc[m]))
+			    && INSN_CODE (curr_insn) < 0)
 			  {
 			    rtx nop_reg = *curr_id->operand_loc[nop];
 			    if (SUBREG_P (nop_reg))
@@ -3335,19 +3336,15 @@ process_alt_operands (int only_alternative)
 		  first_conflict_j = j;
 		last_conflict_j = j;
 		/* Both the earlyclobber operand and conflicting operand
-		   cannot both be user defined hard registers.  */
+		   cannot both be user defined hard registers for asm.
+		   Let curr_insn_transform diagnose it.  */
 		if (HARD_REGISTER_P (operand_reg[i])
 		    && REG_USERVAR_P (operand_reg[i])
 		    && operand_reg[j] != NULL_RTX
 		    && HARD_REGISTER_P (operand_reg[j])
-		    && REG_USERVAR_P (operand_reg[j]))
-		  {
-		    /* For asm, let curr_insn_transform diagnose it.  */
-		    if (INSN_CODE (curr_insn) < 0)
+		    && REG_USERVAR_P (operand_reg[j])
+		    && INSN_CODE (curr_insn) < 0)
 		      return false;
-		    fatal_insn ("unable to generate reloads for "
-				"impossible constraints:", curr_insn);
-		  }
 	      }
 	  if (last_conflict_j < 0)
 	    continue;
-- 
2.53.0

From a871f49d95f1220da115b74ff0374d69137afb99 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Fri, 12 Sep 2025 15:57:08 +0800
Subject: [PATCH 04/14] LoongArch: Fix wrong code from bstrpick split

After late-combine is added, split1 can see an input like

    (insn 56 55 169 5
      (set (reg/v:DI 87 [ n ])
        (ior:DI (and:DI (reg/v:DI 87 [ n ])
                        (const_int 281474976710655 [0xffffffffffff]))
                (and:DI (reg:DI 131 [ _45 ])
                        (const_int -281474976710656 [0xffff000000000000]))))
      "pr121906.c":22:8 108 {*bstrins_di_for_ior_mask}
      (nil))

And the splitter ends up emitting

    (insn 184 55 185 5
      (set (reg/v:DI 87 [ n ])
           (reg:DI 131 [ _45 ]))
      "pr121906.c":22:8 -1
      (nil))
    (insn 185 184 169 5
      (set (zero_extract:DI (reg/v:DI 87 [ n ])
                            (const_int 48 [0x30])
                            (const_int 0 [0]))
           (reg/v:DI 87 [ n ]))
      "pr121906.c":22:8 -1
      (nil))

which obviously lost everything in r87, instead of retaining its lower
bits as we expect.  It's because the splitter didn't anticipate the
output register may be one of the input registers.

	PR target/121906

gcc/

	* config/loongarch/loongarch.md (*bstrins_<mode>_for_ior_mask):
	Always create a new pseudo for the input register of the bstrins
	instruction.

gcc/testsuite/

	* gcc.target/loongarch/pr121906.c: New test.

(cherry picked from commit 290851e63a5b99c99eb196f2823ea3051c0f0214)
(cherry picked from commit 4dd2885905afde80da0498f381b0818b05bc9844)
---
 gcc/config/loongarch/loongarch.md             | 14 ++++-----
 gcc/testsuite/gcc.target/loongarch/pr121906.c | 31 +++++++++++++++++++
 2 files changed, 38 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/pr121906.c

diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index 32ef9809b10..f42dc102d10 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -1619,13 +1619,13 @@ (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
     operands[2] = GEN_INT (len);
     operands[4] = GEN_INT (lo);
 
-    if (lo)
-      {
-	rtx tmp = gen_reg_rtx (<MODE>mode);
-	emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
-					      GEN_INT (lo)));
-	operands[3] = tmp;
-      }
+    /* Use a new pseudo register even if lo == 0 or we'll wreck havoc
+       when operands[0] is same as operands[3].  See PR 121906.  */
+    rtx tmp = gen_reg_rtx (<MODE>mode);
+    rtx val = lo ? gen_rtx_ASHIFTRT (<MODE>mode, operands[3], GEN_INT (lo))
+		 : operands[3];
+    emit_move_insn (tmp, val);
+    operands[3] = tmp;
   })
 
 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
diff --git a/gcc/testsuite/gcc.target/loongarch/pr121906.c b/gcc/testsuite/gcc.target/loongarch/pr121906.c
new file mode 100644
index 00000000000..b4fde5f0c85
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/pr121906.c
@@ -0,0 +1,31 @@
+/* PR target/121906 */
+/* { dg-do run } */
+/* { dg-options "-O2 -mno-lsx" } */
+
+typedef unsigned short u16;
+typedef unsigned long u64;
+typedef u16 v4hi __attribute__ ((vector_size (8)));
+typedef u16 v8hi __attribute__ ((vector_size (16)));
+
+u64 d;
+int e, i;
+u16 x;
+
+int
+main ()
+{
+  v4hi n = { 1 };
+  u64 *o = &d;
+p:
+  asm goto ("" : : : : q);
+  n[3] = (-(v8hi){ 0, 0, 0, 0, x })[7];
+  for (; e >= 0; e--)
+    {
+      *o = n[0];
+      if (i)
+        goto p;
+    q:
+    }
+  if (d != 1)
+    __builtin_trap ();
+}
-- 
2.53.0

From 0fe9364512b4a432151171b263b480748206f603 Mon Sep 17 00:00:00 2001
From: Jinyang He <hejinyang@loongson.cn>
Date: Wed, 29 Oct 2025 16:07:35 +0800
Subject: [PATCH 05/14] LoongArch: Only allow valid binary op when optimize
 conditional move

It is wrong that optimize from `if (cond) dest op= 1 << shift` to
`dest op= (cond ? 1 : 0) << shift` when `dest op 0 != dest`.
Like `and`, `mul` or `div`.
And in this optimization `mul` and `div` is optimized to shift.

gcc/ChangeLog:

	* config/loongarch/loongarch.cc
	(loongarch_expand_conditional_move): Only allow valid binary
	op when optimize conditional move.

gcc/testsuite/ChangeLog:

	* gcc.target/loongarch/conditional-move-opt-1.c: Remove mul.
	* gcc.target/loongarch/conditional-move-opt-2.c: Remove and.
	* gcc.target/loongarch/conditional-move-opt-3.c: New test.

Co-Authored-By: Peng Fan <fanpeng@loongson.cn>

(cherry picked from commit 824eae920f0f64dd7687c969a2436b129161fdc9)
(cherry picked from commit c250cb592dd2fa189136a7fa0e25460395244403)
---
 gcc/config/loongarch/loongarch.cc             | 26 ++++++++++++++++---
 .../loongarch/conditional-move-opt-1.c        |  4 +--
 .../loongarch/conditional-move-opt-2.c        |  2 +-
 .../loongarch/conditional-move-opt-3.c        | 14 ++++++++++
 4 files changed, 40 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c

diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 734a3cccc58..6e882986472 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -5436,12 +5436,32 @@ loongarch_expand_conditional_move (rtx *operands)
 	    }
 	}
 
+      auto is_binary_op_0_keep_orig = [](enum rtx_code code)
+	{
+	  switch (code)
+	    {
+	    case PLUS:
+	    case MINUS:
+	    case IOR:
+	    case XOR:
+	    case ROTATE:
+	    case ROTATERT:
+	    case ASHIFT:
+	    case ASHIFTRT:
+	    case LSHIFTRT:
+	      return true;
+	    default:
+	      return false;
+	    }
+	};
+
       /* Check if the optimization conditions are met.  */
       if (value_if_true_insn
 	  && value_if_false_insn
-	  /* Make sure that value_if_false and var are the same.  */
-	  && BINARY_P (value_if_true_insn_src
-		       = SET_SRC (single_set (value_if_true_insn)))
+	  /* Make sure that the orig value OP 0 keep orig.  */
+	  && (value_if_true_insn_src
+	      = SET_SRC (single_set (value_if_true_insn)))
+	  && is_binary_op_0_keep_orig ( GET_CODE (value_if_true_insn_src))
 	  /* Make sure that both value_if_true and value_if_false
 	     has the same var.  */
 	  && rtx_equal_p (XEXP (value_if_true_insn_src, 0),
diff --git a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c
index ed13471aa90..47802aa9688 100644
--- a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c
+++ b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c
@@ -27,7 +27,7 @@ void
 test_lt ()
 {
   if (lm < ln)
-    lr *= (1 << 16);
+    lr += (1 << 16);
   lr += lm;
 }
 
@@ -35,7 +35,7 @@ void
 test_le ()
 {
   if (lm <= ln)
-    lr = lm * ((long)1 << 32);
+    lr = lm + ((long)1 << 32);
   else
     lr = lm;
   lr += lm;
diff --git a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c
index ac72d4d933a..743fd5e670e 100644
--- a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c
+++ b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c
@@ -29,7 +29,7 @@ void
 test_lez ()
 {
   if (lm <= 0)
-    lr &= (1 << 16);
+    lr |= (1 << 16);
   lr += lm;
 }
 
diff --git a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c
new file mode 100644
index 00000000000..95887980cc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler "maskeqz" } } */
+/* { dg-final { scan-assembler "masknez" } } */
+
+extern long lm, ln, lr;
+
+void
+test_and ()
+{
+  if (lm < 0)
+    lr &= (1 << 16);
+  lr += lm;
+}
-- 
2.53.0

From 129f17bd81642fd3ebd90f53e91a447316aec0c1 Mon Sep 17 00:00:00 2001
From: Lulu Cheng <chenglulu@loongson.cn>
Date: Thu, 16 Oct 2025 15:45:09 +0800
Subject: [PATCH 06/14] LoongArch: Move vector templates of and xor ior to
 simd.md.

gcc/ChangeLog:

	* config/loongarch/lasx.md (xor<mode>3): Delete.
	(ior<mode>3): Delete.
	(and<mode>3): Delete.
	* config/loongarch/lsx.md (xor<mode>3): Delete.
	(ior<mode>3): Delete.
	(and<mode>3): Delete.
	* config/loongarch/simd.md (xor<mode>3): Define.
	(ior<mode>3): Likewise.
	(and<mode>3): Likewise.

(cherry picked from commit 03c25c976da07b260f7acb757688eefb22ff9017)
(cherry picked from commit ee46a136fa8fe30bf2a3dc7c524ad46719e146eb)
---
 gcc/config/loongarch/lasx.md | 53 ------------------------------------
 gcc/config/loongarch/lsx.md  | 53 ------------------------------------
 gcc/config/loongarch/simd.md | 53 ++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 106 deletions(-)

diff --git a/gcc/config/loongarch/lasx.md b/gcc/config/loongarch/lasx.md
index 3d71f30a54b..5bed8d89747 100644
--- a/gcc/config/loongarch/lasx.md
+++ b/gcc/config/loongarch/lasx.md
@@ -792,59 +792,6 @@ (define_insn "umod<mode>3"
   [(set_attr "type" "simd_div")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "xor<mode>3"
-  [(set (match_operand:LASX 0 "register_operand" "=f,f,f")
-	(xor:LASX
-	  (match_operand:LASX 1 "register_operand" "f,f,f")
-	  (match_operand:LASX 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
-  "ISA_HAS_LASX"
-  "@
-   xvxor.v\t%u0,%u1,%u2
-   xvbitrevi.%v0\t%u0,%u1,%V2
-   xvxori.b\t%u0,%u1,%B2"
-  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
-   (set_attr "mode" "<MODE>")])
-
-(define_insn "ior<mode>3"
-  [(set (match_operand:LASX 0 "register_operand" "=f,f,f")
-	(ior:LASX
-	  (match_operand:LASX 1 "register_operand" "f,f,f")
-	  (match_operand:LASX 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
-  "ISA_HAS_LASX"
-  "@
-   xvor.v\t%u0,%u1,%u2
-   xvbitseti.%v0\t%u0,%u1,%V2
-   xvori.b\t%u0,%u1,%B2"
-  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
-   (set_attr "mode" "<MODE>")])
-
-(define_insn "and<mode>3"
-  [(set (match_operand:LASX 0 "register_operand" "=f,f,f")
-	(and:LASX
-	  (match_operand:LASX 1 "register_operand" "f,f,f")
-	  (match_operand:LASX 2 "reg_or_vector_same_val_operand" "f,YZ,Urv8")))]
-  "ISA_HAS_LASX"
-{
-  switch (which_alternative)
-    {
-    case 0:
-      return "xvand.v\t%u0,%u1,%u2";
-    case 1:
-      {
-	rtx elt0 = CONST_VECTOR_ELT (operands[2], 0);
-	unsigned HOST_WIDE_INT val = ~UINTVAL (elt0);
-	operands[2] = loongarch_gen_const_int_vector (<MODE>mode, val & (-val));
-	return "xvbitclri.%v0\t%u0,%u1,%V2";
-      }
-    case 2:
-      return "xvandi.b\t%u0,%u1,%B2";
-    default:
-      gcc_unreachable ();
-    }
-}
-  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "one_cmpl<mode>2"
   [(set (match_operand:ILASX 0 "register_operand" "=f")
 	(not:ILASX (match_operand:ILASX 1 "register_operand" "f")))]
diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md
index fb0236ba0f1..7131a53edd3 100644
--- a/gcc/config/loongarch/lsx.md
+++ b/gcc/config/loongarch/lsx.md
@@ -654,59 +654,6 @@ (define_insn "umod<mode>3"
   [(set_attr "type" "simd_div")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "xor<mode>3"
-  [(set (match_operand:LSX 0 "register_operand" "=f,f,f")
-	(xor:LSX
-	  (match_operand:LSX 1 "register_operand" "f,f,f")
-	  (match_operand:LSX 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
-  "ISA_HAS_LSX"
-  "@
-   vxor.v\t%w0,%w1,%w2
-   vbitrevi.%v0\t%w0,%w1,%V2
-   vxori.b\t%w0,%w1,%B2"
-  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
-   (set_attr "mode" "<MODE>")])
-
-(define_insn "ior<mode>3"
-  [(set (match_operand:LSX 0 "register_operand" "=f,f,f")
-	(ior:LSX
-	  (match_operand:LSX 1 "register_operand" "f,f,f")
-	  (match_operand:LSX 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
-  "ISA_HAS_LSX"
-  "@
-   vor.v\t%w0,%w1,%w2
-   vbitseti.%v0\t%w0,%w1,%V2
-   vori.b\t%w0,%w1,%B2"
-  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
-   (set_attr "mode" "<MODE>")])
-
-(define_insn "and<mode>3"
-  [(set (match_operand:LSX 0 "register_operand" "=f,f,f")
-	(and:LSX
-	  (match_operand:LSX 1 "register_operand" "f,f,f")
-	  (match_operand:LSX 2 "reg_or_vector_same_val_operand" "f,YZ,Urv8")))]
-  "ISA_HAS_LSX"
-{
-  switch (which_alternative)
-    {
-    case 0:
-      return "vand.v\t%w0,%w1,%w2";
-    case 1:
-      {
-	rtx elt0 = CONST_VECTOR_ELT (operands[2], 0);
-	unsigned HOST_WIDE_INT val = ~UINTVAL (elt0);
-	operands[2] = loongarch_gen_const_int_vector (<MODE>mode, val & (-val));
-	return "vbitclri.%v0\t%w0,%w1,%V2";
-      }
-    case 2:
-      return "vandi.b\t%w0,%w1,%B2";
-    default:
-      gcc_unreachable ();
-    }
-}
-  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "one_cmpl<mode>2"
   [(set (match_operand:ILSX 0 "register_operand" "=f")
 	(not:ILSX (match_operand:ILSX 1 "register_operand" "f")))]
diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
index 4156b269f9a..3334a59da80 100644
--- a/gcc/config/loongarch/simd.md
+++ b/gcc/config/loongarch/simd.md
@@ -972,6 +972,59 @@ (define_expand "<simd_isa>_<x>v<insn>ri_<simdfmt>"
   DONE;
 })
 
+(define_insn "xor<mode>3"
+  [(set (match_operand:ALLVEC 0 "register_operand" "=f,f,f")
+	(xor:ALLVEC
+	  (match_operand:ALLVEC 1 "register_operand" "f,f,f")
+	  (match_operand:ALLVEC 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
+  ""
+  "@
+   <x>vxor.v\t%<wu>0,%<wu>1,%<wu>2
+   <x>vbitrevi.%v0\t%<wu>0,%<wu>1,%V2
+   <x>vxori.b\t%<wu>0,%<wu>1,%B2"
+  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "ior<mode>3"
+  [(set (match_operand:ALLVEC 0 "register_operand" "=f,f,f")
+	(ior:ALLVEC
+	  (match_operand:ALLVEC 1 "register_operand" "f,f,f")
+	  (match_operand:ALLVEC 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
+  ""
+  "@
+   <x>vor.v\t%<wu>0,%<wu>1,%<wu>2
+   <x>vbitseti.%v0\t%<wu>0,%<wu>1,%V2
+   <x>vori.b\t%<wu>0,%<wu>1,%B2"
+  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "and<mode>3"
+  [(set (match_operand:ALLVEC 0 "register_operand" "=f,f,f")
+	(and:ALLVEC
+	  (match_operand:ALLVEC 1 "register_operand" "f,f,f")
+	  (match_operand:ALLVEC 2 "reg_or_vector_same_val_operand" "f,YZ,Urv8")))]
+  ""
+{
+  switch (which_alternative)
+    {
+    case 0:
+      return "<x>vand.v\t%<wu>0,%<wu>1,%<wu>2";
+    case 1:
+      {
+	rtx elt0 = CONST_VECTOR_ELT (operands[2], 0);
+	unsigned HOST_WIDE_INT val = ~UINTVAL (elt0);
+	operands[2] = loongarch_gen_const_int_vector (<MODE>mode, val & (-val));
+	return "<x>vbitclri.%v0\t%<wu>0,%<wu>1,%V2";
+      }
+    case 2:
+      return "<x>vandi.b\t%<wu>0,%<wu>1,%B2";
+    default:
+      gcc_unreachable ();
+    }
+}
+  [(set_attr "type" "simd_logic,simd_bit,simd_logic")
+   (set_attr "mode" "<MODE>")])
+
 ; The LoongArch SX Instructions.
 (include "lsx.md")
 
-- 
2.53.0

From 12b22ef410154cf3ada39a37d396c449a36cc38e Mon Sep 17 00:00:00 2001
From: Lulu Cheng <chenglulu@loongson.cn>
Date: Tue, 30 Sep 2025 11:32:47 +0800
Subject: [PATCH 07/14] LoongArch: Fix bug for PR122097.

When implementing the vector template for copysign, we used vector
floating-point AND and IOR operations. This allows AND and IOR operands
to be vector floating-point types. However, the constraint YC does not
handle vector floating-point constants, resulting in ICE.

	PR target/122097

gcc/ChangeLog:

	* config/loongarch/loongarch.cc
	(loongarch_const_vector_bitimm_set_p): Add support for vector float.
	(loongarch_const_vector_bitimm_clr_p): Likewise.
	(loongarch_print_operand): Likewise.
	* config/loongarch/simd.md (and<mode>3): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/loongarch/pr122097.c: New test.

(cherry picked from commit dbd0e8fc50e990e999217cc3a2fc5b6fbc74a09d)
(cherry picked from commit 08be034b67d82072b04d3924d4fa473a712a5b8b)
---
 gcc/config/loongarch/loongarch.cc             |  78 ++++-
 gcc/config/loongarch/simd.md                  |  22 +-
 gcc/testsuite/gcc.target/loongarch/pr122097.c | 271 ++++++++++++++++++
 3 files changed, 362 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/pr122097.c

diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 6e882986472..537109610fe 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -1718,14 +1718,36 @@ loongarch_symbol_binds_local_p (const_rtx x)
 bool
 loongarch_const_vector_bitimm_set_p (rtx op, machine_mode mode)
 {
-  if (GET_CODE (op) == CONST_VECTOR && op != CONST0_RTX (mode))
+  if (GET_CODE (op) == CONST_VECTOR
+      && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+	  || GET_MODE_CLASS (mode) == MODE_VECTOR_INT))
     {
-      unsigned HOST_WIDE_INT val = UINTVAL (CONST_VECTOR_ELT (op, 0));
+      unsigned HOST_WIDE_INT val;
+
+      if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+	{
+	  rtx val_s = CONST_VECTOR_ELT (op, 0);
+	  const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (val_s);
+	  if (GET_MODE (val_s) == DFmode)
+	    {
+	      long tmp[2];
+	      REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
+	      val = (unsigned HOST_WIDE_INT) tmp[1] << 32 | tmp[0];
+	    }
+	  else
+	    {
+	      long tmp;
+	      REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
+	      val = (unsigned HOST_WIDE_INT) tmp;
+	    }
+	}
+      else
+	val = UINTVAL (CONST_VECTOR_ELT (op, 0));
+
       int vlog2 = exact_log2 (val & GET_MODE_MASK (GET_MODE_INNER (mode)));
 
       if (vlog2 != -1)
 	{
-	  gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_INT);
 	  gcc_assert (vlog2 >= 0 && vlog2 <= GET_MODE_UNIT_BITSIZE (mode) - 1);
 	  return loongarch_const_vector_same_val_p (op, mode);
 	}
@@ -1740,14 +1762,35 @@ loongarch_const_vector_bitimm_set_p (rtx op, machine_mode mode)
 bool
 loongarch_const_vector_bitimm_clr_p (rtx op, machine_mode mode)
 {
-  if (GET_CODE (op) == CONST_VECTOR && op != CONSTM1_RTX (mode))
+  if (GET_CODE (op) == CONST_VECTOR
+      && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+	  || GET_MODE_CLASS (mode) == MODE_VECTOR_INT))
     {
-      unsigned HOST_WIDE_INT val = ~UINTVAL (CONST_VECTOR_ELT (op, 0));
+      unsigned HOST_WIDE_INT val;
+      if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+	{
+	  rtx val_s = CONST_VECTOR_ELT (op, 0);
+	  const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (val_s);
+	  if (GET_MODE (val_s) == DFmode)
+	    {
+	      long tmp[2];
+	      REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
+	      val = ~((unsigned HOST_WIDE_INT) tmp[1] << 32 | tmp[0]);
+	    }
+	  else
+	    {
+	      long tmp;
+	      REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
+	      val = ~((unsigned HOST_WIDE_INT) tmp);
+	    }
+	}
+      else
+	val = ~UINTVAL (CONST_VECTOR_ELT (op, 0));
+
       int vlog2 = exact_log2 (val & GET_MODE_MASK (GET_MODE_INNER (mode)));
 
       if (vlog2 != -1)
 	{
-	  gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_INT);
 	  gcc_assert (vlog2 >= 0 && vlog2 <= GET_MODE_UNIT_BITSIZE (mode) - 1);
 	  return loongarch_const_vector_same_val_p (op, mode);
 	}
@@ -6418,7 +6461,28 @@ loongarch_print_operand (FILE *file, rtx op, int letter)
       if (CONST_VECTOR_P (op))
 	{
 	  machine_mode mode = GET_MODE_INNER (GET_MODE (op));
-	  unsigned HOST_WIDE_INT val = UINTVAL (CONST_VECTOR_ELT (op, 0));
+	  rtx val_s = CONST_VECTOR_ELT (op, 0);
+	  unsigned HOST_WIDE_INT val;
+
+	  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+	    {
+	      const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (val_s);
+	      if (GET_MODE (val_s) == DFmode)
+		{
+		  long tmp[2];
+		  REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
+		  val = (unsigned HOST_WIDE_INT) (tmp[1] << 32 | tmp[0]);
+		}
+	      else
+		{
+		  long tmp;
+		  REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
+		  val = (unsigned HOST_WIDE_INT) tmp;
+		}
+	    }
+	  else
+	    val = UINTVAL (val_s);
+
 	  int vlog2 = exact_log2 (val & GET_MODE_MASK (mode));
 	  if (vlog2 != -1)
 	    fprintf (file, "%d", vlog2);
diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
index 3334a59da80..9f4525a25f0 100644
--- a/gcc/config/loongarch/simd.md
+++ b/gcc/config/loongarch/simd.md
@@ -1012,8 +1012,26 @@ (define_insn "and<mode>3"
     case 1:
       {
 	rtx elt0 = CONST_VECTOR_ELT (operands[2], 0);
-	unsigned HOST_WIDE_INT val = ~UINTVAL (elt0);
-	operands[2] = loongarch_gen_const_int_vector (<MODE>mode, val & (-val));
+	unsigned HOST_WIDE_INT val;
+	if (GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_FLOAT)
+	  {
+	  const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (elt0);
+	  if (GET_MODE (elt0) == DFmode)
+	    {
+	      long tmp[2];
+	      REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
+	      val = ~((unsigned HOST_WIDE_INT) tmp[1] << 32 | tmp[0]);
+	    }
+	  else
+	    {
+	      long tmp;
+	      REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
+	      val = ~((unsigned HOST_WIDE_INT) tmp);
+	    }
+	  }
+	else
+	  val = ~UINTVAL (elt0);
+	operands[2] = loongarch_gen_const_int_vector (<VIMODE>mode, val & (-val));
 	return "<x>vbitclri.%v0\t%<wu>0,%<wu>1,%V2";
       }
     case 2:
diff --git a/gcc/testsuite/gcc.target/loongarch/pr122097.c b/gcc/testsuite/gcc.target/loongarch/pr122097.c
new file mode 100644
index 00000000000..5d32b191baf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/pr122097.c
@@ -0,0 +1,271 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -mabi=lp64d -mlsx" } */
+/* { dg-final { scan-assembler "vbitseti\.d\t\\\$vr\[0-9\]+,\\\$vr\[0-9\]+,63" } } */
+
+typedef long unsigned int size_t;
+typedef unsigned char simde__mmask8;
+typedef long simde__m128i __attribute__ ((__aligned__ ((16))))
+__attribute__ ((__vector_size__ (16))) __attribute__ ((__may_alias__));
+typedef union
+{
+
+  __attribute__ ((__aligned__ ((16)))) long i64
+      __attribute__ ((__vector_size__ (16))) __attribute__ ((__may_alias__));
+} simde__m128i_private;
+typedef double simde_float64;
+typedef simde_float64 simde__m128d __attribute__ ((__aligned__ ((16))))
+__attribute__ ((__vector_size__ (16))) __attribute__ ((__may_alias__));
+typedef long int int_fast32_t;
+typedef union
+{
+
+  __attribute__ ((__aligned__ ((16)))) int_fast32_t i32f
+      __attribute__ ((__vector_size__ (16))) __attribute__ ((__may_alias__));
+  __attribute__ ((__aligned__ ((16)))) long i64
+      __attribute__ ((__vector_size__ (16))) __attribute__ ((__may_alias__));
+  __attribute__ ((__aligned__ ((16)))) simde_float64 f64
+      __attribute__ ((__vector_size__ (16))) __attribute__ ((__may_alias__));
+} simde__m128d_private;
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde__m128d_from_private (simde__m128d_private v)
+{
+  simde__m128d r;
+  __builtin_memcpy (&r, &v, sizeof (r));
+  return r;
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_set_pd (simde_float64 e1, simde_float64 e0)
+{
+
+  simde__m128d_private r_;
+  r_.f64[0] = e0;
+  r_.f64[1] = e1;
+
+  return simde__m128d_from_private (r_);
+}
+__attribute__ ((__always_inline__)) inline static simde__m128i
+simde_mm_castpd_si128 (simde__m128d a)
+{
+  simde__m128i r;
+  __builtin_memcpy (&r, &a, sizeof (a));
+  return r;
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128i
+simde__m128i_from_private (simde__m128i_private v)
+{
+  simde__m128i r;
+  __builtin_memcpy (&r, &v, sizeof (r));
+  return r;
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128i_private
+simde__m128i_to_private (simde__m128i v)
+{
+  simde__m128i_private r;
+  __builtin_memcpy (&r, &v, sizeof (r));
+  return r;
+}
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_castsi128_pd (simde__m128i a)
+{
+  simde__m128d r;
+  __builtin_memcpy (&r, &a, sizeof (a));
+  return r;
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128i
+simde_mm_mask_mov_epi64 (simde__m128i src, simde__mmask8 k, simde__m128i a)
+{
+
+  simde__m128i_private src_ = simde__m128i_to_private (src),
+                       a_ = simde__m128i_to_private (a), r_;
+
+  for (size_t i = 0; i < (sizeof (r_.i64) / sizeof (r_.i64[0])); i++)
+    {
+      r_.i64[i] = ((k >> i) & 1) ? a_.i64[i] : src_.i64[i];
+    }
+
+  return simde__m128i_from_private (r_);
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_mask_mov_pd (simde__m128d src, simde__mmask8 k, simde__m128d a)
+{
+  return simde_mm_castsi128_pd (simde_mm_mask_mov_epi64 (
+      simde_mm_castpd_si128 (src), k, simde_mm_castpd_si128 (a)));
+}
+
+static double
+simde_test_f64_precision_to_slop (int precision)
+{
+  return __builtin_expect (!!(precision == 0x7fffffff), 0)
+             ? 0.0
+             : __builtin_pow (10.0, -((double)(precision)));
+}
+__attribute__ ((__always_inline__)) inline static void
+simde_mm_storeu_pd (simde_float64 *mem_addr, simde__m128d a)
+{
+
+  __builtin_memcpy (mem_addr, &a, sizeof (a));
+}
+int simde_test_equal_f64 (simde_float64 a, simde_float64 b,
+                          simde_float64 slop);
+void simde_test_debug_printf_ (const char *format, ...);
+static int
+simde_assert_equal_vf64_ (size_t vec_len, simde_float64 const a[(vec_len)],
+                          simde_float64 const b[(vec_len)], simde_float64 slop,
+                          const char *filename, int line, const char *astr,
+                          const char *bstr)
+{
+  for (size_t i = 0; i < vec_len; i++)
+    {
+      if (__builtin_expect (!!(!simde_test_equal_f64 (a[i], b[i], slop)), 0))
+        {
+          simde_test_debug_printf_ (
+              "%s:%d: assertion failed: %s[%zu] ~= %s[%zu] (%f ~= %f)\n",
+              filename, line, astr, i, bstr, i, ((double)(a[i])),
+              ((double)(b[i])));
+          return 1;
+        }
+    }
+  return 0;
+}
+static int
+simde_test_x86_assert_equal_f64x2_ (simde__m128d a, simde__m128d b,
+                                    simde_float64 slop, const char *filename,
+                                    int line, const char *astr,
+                                    const char *bstr)
+{
+  simde_float64 a_[sizeof (a) / sizeof (simde_float64)],
+      b_[sizeof (a) / sizeof (simde_float64)];
+  simde_mm_storeu_pd (a_, a);
+  simde_mm_storeu_pd (b_, b);
+  return simde_assert_equal_vf64_ (sizeof (a_) / sizeof (a_[0]), a_, b_, slop,
+                                   filename, line, astr, bstr);
+}
+__attribute__ ((__always_inline__)) inline static simde__m128d_private
+simde__m128d_to_private (simde__m128d v)
+{
+  simde__m128d_private r;
+  __builtin_memcpy (&r, &v, sizeof (r));
+  return r;
+}
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_min_pd (simde__m128d a, simde__m128d b)
+{
+
+  simde__m128d_private r_, a_ = simde__m128d_to_private (a),
+                           b_ = simde__m128d_to_private (b);
+
+  for (size_t i = 0; i < (sizeof (r_.f64) / sizeof (r_.f64[0])); i++)
+    {
+      r_.f64[i] = (a_.f64[i] < b_.f64[i]) ? a_.f64[i] : b_.f64[i];
+    }
+
+  return simde__m128d_from_private (r_);
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_max_pd (simde__m128d a, simde__m128d b)
+{
+
+  simde__m128d_private r_, a_ = simde__m128d_to_private (a),
+                           b_ = simde__m128d_to_private (b);
+
+  for (size_t i = 0; i < (sizeof (r_.f64) / sizeof (r_.f64[0])); i++)
+    {
+      r_.f64[i] = (a_.f64[i] > b_.f64[i]) ? a_.f64[i] : b_.f64[i];
+    }
+
+  return simde__m128d_from_private (r_);
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_x_mm_abs_pd (simde__m128d a)
+{
+
+  simde__m128d_private r_, a_ = simde__m128d_to_private (a);
+  for (size_t i = 0; i < (sizeof (r_.f64) / sizeof (r_.f64[0])); i++)
+    {
+      r_.f64[i] = __builtin_fabs (a_.f64[i]);
+    }
+
+  return simde__m128d_from_private (r_);
+}
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_cmple_pd (simde__m128d a, simde__m128d b)
+{
+
+  simde__m128d_private r_, a_ = simde__m128d_to_private (a),
+                           b_ = simde__m128d_to_private (b);
+
+  r_.i64 = ((__typeof__ (r_.i64))((a_.f64 <= b_.f64)));
+  return simde__m128d_from_private (r_);
+}
+
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_x_mm_select_pd (simde__m128d a, simde__m128d b, simde__m128d mask)
+{
+  simde__m128d_private r_, a_ = simde__m128d_to_private (a),
+                           b_ = simde__m128d_to_private (b),
+                           mask_ = simde__m128d_to_private (mask);
+
+  r_.i64 = a_.i64 ^ ((a_.i64 ^ b_.i64) & mask_.i64);
+  return simde__m128d_from_private (r_);
+}
+simde__m128d simde_mm_cmpge_pd (simde__m128d a, simde__m128d b);
+
+simde__m128d
+simde_x_mm_copysign_pd (simde__m128d dest, simde__m128d src)
+{
+  simde__m128d_private r_, dest_ = simde__m128d_to_private (dest),
+                           src_ = simde__m128d_to_private (src);
+  for (size_t i = 0; i < (sizeof (r_.f64) / sizeof (r_.f64[0])); i++)
+    {
+      r_.f64[i] = __builtin_copysign (dest_.f64[i], src_.f64[i]);
+    }
+
+  return simde__m128d_from_private (r_);
+}
+simde__m128d simde_mm_or_pd (simde__m128d a, simde__m128d b);
+
+simde__m128d simde_mm_set1_pd (simde_float64 a);
+
+__attribute__ ((__always_inline__)) inline static simde__m128d
+simde_mm_range_pd (simde__m128d a, simde__m128d b, int imm8)
+{
+  simde__m128d r;
+
+  r = simde_x_mm_select_pd (
+      b, a, simde_mm_cmple_pd (simde_x_mm_abs_pd (a), simde_x_mm_abs_pd (b)));
+
+  r = simde_x_mm_copysign_pd (r, a);
+
+  return r;
+}
+int
+test_simde_mm_mask_range_pd (void)
+{
+
+  simde__m128d src, a, b, e, r;
+
+  src = simde_mm_set_pd (-2.92, -85.39);
+  a = simde_mm_set_pd (-47.59, -122.31);
+  b = simde_mm_set_pd (877.42, 69.15);
+  e = simde_mm_set_pd (-47.59, -69.15);
+  r = simde_mm_mask_mov_pd (src, 143, simde_mm_range_pd (a, b, 2));
+  do
+    {
+      if (simde_test_x86_assert_equal_f64x2_ (
+              r, e, simde_test_f64_precision_to_slop (1),
+              "../test/x86/avx512/range.c", 1454, "r", "e"))
+        {
+          return 1;
+        }
+    }
+  while (0);
+
+  return 0;
+}
-- 
2.53.0

From fc61678db5e4505155973079300ee006c3479a34 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Sun, 16 Nov 2025 00:30:43 +0800
Subject: [PATCH 08/14] LoongArch: Fix wrong code from
 loongarch_expand_vec_perm_1 [PR 122695]

	PR target/122695

gcc/

	* config/loongarch/loongarch.cc (loongarch_expand_vec_perm_1):
	Simplify and fix the logic preventing the xvshuf.* unpredictable
	behavior.

gcc/testsuite/

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

(cherry picked from commit f168d62bc552176572832bf129c9b392aeff46ad)
(cherry picked from commit 9c92b2ba08e85aa835c439f93902f80e0b48cb83)
---
 gcc/config/loongarch/loongarch.cc             | 56 ++-----------------
 .../gcc.target/loongarch/pr122695-1.c         | 22 ++++++++
 .../gcc.target/loongarch/pr122695-2.c         | 22 ++++++++
 3 files changed, 50 insertions(+), 50 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/pr122695-1.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/pr122695-2.c

diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 537109610fe..e5411ea3a49 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -8967,57 +8967,13 @@ loongarch_expand_vec_perm_1 (rtx operands[])
   /* Number of elements in the vector.  */
   w = GET_MODE_NUNITS (mode);
 
-  rtx round_data[MAX_VECT_LEN];
-  rtx round_reg, round_data_rtx;
-
-  if (mode != E_V32QImode)
+  /* If we are using xvshuf.*, clamp the selector to avoid unpredictable
+     output.  */
+  if (maskmode != V8SImode && maskmode != V4DImode)
     {
-      for (int i = 0; i < w; i += 1)
-	{
-	  round_data[i] = GEN_INT (0x1f);
-	}
-
-      if (mode == E_V4DFmode)
-	{
-	  round_data_rtx = gen_rtx_CONST_VECTOR (E_V4DImode,
-						 gen_rtvec_v (w, round_data));
-	  round_reg = gen_reg_rtx (E_V4DImode);
-	}
-      else if (mode == E_V8SFmode)
-	{
-
-	  round_data_rtx = gen_rtx_CONST_VECTOR (E_V8SImode,
-						 gen_rtvec_v (w, round_data));
-	  round_reg = gen_reg_rtx (E_V8SImode);
-	}
-      else
-	{
-	  round_data_rtx = gen_rtx_CONST_VECTOR (mode,
-						 gen_rtvec_v (w, round_data));
-	  round_reg = gen_reg_rtx (mode);
-	}
-
-      emit_move_insn (round_reg, round_data_rtx);
-      switch (mode)
-	{
-	case E_V32QImode:
-	  emit_insn (gen_andv32qi3 (mask, mask, round_reg));
-	  break;
-	case E_V16HImode:
-	  emit_insn (gen_andv16hi3 (mask, mask, round_reg));
-	  break;
-	case E_V8SImode:
-	case E_V8SFmode:
-	  emit_insn (gen_andv8si3 (mask, mask, round_reg));
-	  break;
-	case E_V4DImode:
-	case E_V4DFmode:
-	  emit_insn (gen_andv4di3 (mask, mask, round_reg));
-	  break;
-	default:
-	  gcc_unreachable ();
-	  break;
-	}
+      rtx t = gen_const_vec_duplicate (maskmode, GEN_INT (0x1f));
+      mask = expand_binop (maskmode, and_optab, mask, t, NULL_RTX, false,
+			   OPTAB_DIRECT);
     }
 
   if (mode == V4DImode || mode == V4DFmode)
diff --git a/gcc/testsuite/gcc.target/loongarch/pr122695-1.c b/gcc/testsuite/gcc.target/loongarch/pr122695-1.c
new file mode 100644
index 00000000000..d7c906cc0ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/pr122695-1.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -mlasx" } */
+/* { dg-require-effective-target loongarch_asx_hw } */
+
+[[gnu::vector_size (32)]] char a, b, c;
+
+[[gnu::noipa]] void
+test (void)
+{
+  a = __builtin_shuffle (a, b, c);
+}
+
+int
+main (void)
+{
+  a = (typeof (a)){} + 5;
+  b = (typeof (a)){} + 6;
+  c = (typeof (a)){} + 64;
+  test ();
+  if (a[0] != 5)
+    __builtin_trap ();
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/pr122695-2.c b/gcc/testsuite/gcc.target/loongarch/pr122695-2.c
new file mode 100644
index 00000000000..79fc139b55f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/pr122695-2.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -mlasx" } */
+/* { dg-require-effective-target loongarch_asx_hw } */
+
+[[gnu::vector_size(32)]] short a, b, c;
+
+[[gnu::noipa]] void
+test (void)
+{
+  a = __builtin_shuffle(a, b, c) + c;
+}
+
+int
+main (void)
+{
+  a = (typeof (a)){} + 1;
+  b = (typeof (b)){} + 2;
+  c = (typeof (c)){} + 128;
+  test ();
+  if (a[0] != 129)
+    __builtin_trap ();
+}
-- 
2.53.0

From e6d152dfc9ea19c73e0253a247d701dc3089f380 Mon Sep 17 00:00:00 2001
From: Lulu Cheng <chenglulu@loongson.cn>
Date: Mon, 12 Jan 2026 17:23:41 +0800
Subject: [PATCH 09/14] LoongArch: Fix bug123521.

In the vector initialization process, optimization can be performed
if it can be determined that all elements are the same, or if the
upper or lower halves are identical.  However, during this
optimization, when the identical element is an immediate value
larger than 10 bits, an internal compiler error (ICE) occurs.
The reason is that in such cases, the function
`simplify_gen_subreg (imode, reg_tmp, GET_MODE (reg_tmp), 0)` is
called, where `imode` is `E_DImode`.  The mode of `reg_tmp` in
`GET_MODE (reg_tmp)` is taken from the immediate value's mode,
which is `E_VOIDmode`.  This results in a move from `E_VOIDmode`
to `E_DImode`, an operation not supported by LoongArch.

	PR target/123521

gcc/ChangeLog:

	* config/loongarch/loongarch.cc
	(loongarch_expand_vector_init_same): Fixed a bug in the
	vector initialization section..

gcc/testsuite/ChangeLog:

	* gcc.target/loongarch/vector/lasx/pr123521.c: New test.

Suggested-by: Xi Ruoyao <xry111@xry111.site>

(cherry picked from commit 1a4eb0479ce0827b55a6190ddf13ade330d619e6)
(cherry picked from commit c3e93759b5123581232931761b9c90fc1a9f3c15)
---
 gcc/config/loongarch/loongarch.cc             | 27 +------------------
 .../loongarch/vector/lasx/pr123521.c          | 11 ++++++++
 2 files changed, 12 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123521.c

diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index e5411ea3a49..d2d18d98e9f 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -10186,32 +10186,7 @@ loongarch_expand_vector_init_same (rtx target, rtx vals, unsigned nvar)
 	}
     }
 
-  if (imode == GET_MODE (same))
-    temp = same;
-  else if (GET_MODE_SIZE (imode) >= UNITS_PER_WORD)
-    {
-      if (GET_CODE (same) == MEM)
-	{
-	  rtx reg_tmp = gen_reg_rtx (GET_MODE (same));
-	  loongarch_emit_move (reg_tmp, same);
-	  temp = simplify_gen_subreg (imode, reg_tmp, GET_MODE (reg_tmp), 0);
-	}
-      else
-	temp = simplify_gen_subreg (imode, same, GET_MODE (same), 0);
-    }
-  else
-    {
-      if (GET_CODE (same) == MEM)
-	{
-	  rtx reg_tmp = gen_reg_rtx (GET_MODE (same));
-	  loongarch_emit_move (reg_tmp, same);
-	  temp = lowpart_subreg (imode, reg_tmp, GET_MODE (reg_tmp));
-	}
-      else
-	temp = lowpart_subreg (imode, same, GET_MODE (same));
-    }
-
-  temp = force_reg (imode, temp);
+  temp = force_reg (imode, same);
 
   switch (vmode)
     {
diff --git a/gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123521.c b/gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123521.c
new file mode 100644
index 00000000000..9ccf391d38d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123521.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -msimd=lasx" } */
+
+typedef long long v4i64 __attribute__ ((vector_size (32), aligned (32)));
+extern long long *x_si;
+v4i64
+test (void)
+{
+  v4i64 a = { x_si[1], x_si[0], 0x411, 0x411 };
+  return a;
+}
-- 
2.53.0

From 2176b3bb4b997fa23d04d8f642336f268ff085d8 Mon Sep 17 00:00:00 2001
From: Lulu Cheng <chenglulu@loongson.cn>
Date: Sat, 17 Jan 2026 15:12:46 +0800
Subject: [PATCH 10/14] LoongArch: Fix bug117575.

In the template "vec_set<mode>", a call is made to
"lasx_xvinsve0_<lasxfmt_f>_scalar", but there is an issue due to
the different ranges of operand1 between the two templates.
The range of operand1 in the template
"lasx_xvinsve0_<lasxfmt_f>_scalar" is now set to be the same as
that in "vec_set<mode>".

	PR target/117575

gcc/ChangeLog:

	* config/loongarch/lasx.md: Modify the range of operand1.

gcc/testsuite/ChangeLog:

	* g++.target/loongarch/pr117575.C: New test.

(cherry picked from commit 27f040591aeb611030c990944731f84485887f97)
(cherry picked from commit 5a1680b05d6d91feeb9767d1f2fc713a6cd9a0d8)
---
 gcc/config/loongarch/lasx.md                  |  2 +-
 gcc/testsuite/g++.target/loongarch/pr117575.C | 81 +++++++++++++++++++
 2 files changed, 82 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.target/loongarch/pr117575.C

diff --git a/gcc/config/loongarch/lasx.md b/gcc/config/loongarch/lasx.md
index 5bed8d89747..7bb78aba493 100644
--- a/gcc/config/loongarch/lasx.md
+++ b/gcc/config/loongarch/lasx.md
@@ -3445,7 +3445,7 @@ (define_insn "lasx_xvinsve0_<lasxfmt_f>_scalar"
   [(set (match_operand:FLASX 0 "register_operand" "=f")
     (vec_merge:FLASX
       (vec_duplicate:FLASX
-        (match_operand:<UNITMODE> 1 "register_operand" "f"))
+        (match_operand:<UNITMODE> 1 "reg_or_0_operand" "f"))
       (match_operand:FLASX 2 "register_operand" "0")
       (match_operand 3 "const_<bitmask256>_operand" "")))]
   "ISA_HAS_LASX"
diff --git a/gcc/testsuite/g++.target/loongarch/pr117575.C b/gcc/testsuite/g++.target/loongarch/pr117575.C
new file mode 100644
index 00000000000..1870d4c890a
--- /dev/null
+++ b/gcc/testsuite/g++.target/loongarch/pr117575.C
@@ -0,0 +1,81 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -mlasx" } */
+
+typedef long unsigned int size_t;
+typedef unsigned char simde__mmask8;
+typedef double simde_float64;
+typedef simde_float64 simde__m512d __attribute__ ((__aligned__ ((64))))
+__attribute__ ((__vector_size__ (64))) __attribute__ ((__may_alias__));
+typedef simde_float64 simde__m256d __attribute__ ((__aligned__ ((32))))
+__attribute__ ((__vector_size__ (32))) __attribute__ ((__may_alias__));
+simde__m512d simde_mm512_set_pd (simde_float64 e7, simde_float64 e6,
+                                 simde_float64 e5, simde_float64 e4,
+                                 simde_float64 e3, simde_float64 e2,
+                                 simde_float64 e1, simde_float64 e0);
+simde__m256d simde_mm256_maskz_mov_pd (simde__mmask8 k, simde__m256d a);
+int simde_test_x86_assert_equal_f64x4_ (simde__m256d a, simde__m256d b);
+
+typedef union
+{
+
+  __attribute__ ((__aligned__ ((32)))) simde_float64 f64
+      __attribute__ ((__vector_size__ (32))) __attribute__ ((__may_alias__));
+} simde__m256d_private;
+__attribute__ ((__always_inline__)) inline static simde__m256d
+simde__m256d_from_private (simde__m256d_private v)
+{
+  simde__m256d r;
+  __builtin_memcpy (&r, &v, sizeof (r));
+  return r;
+}
+simde__m256d
+simde_mm256_set_pd (simde_float64 e3, simde_float64 e2, simde_float64 e1,
+                    simde_float64 e0)
+{
+
+  simde__m256d_private r_;
+
+  r_.f64[0] = e0;
+  r_.f64[1] = e1;
+  r_.f64[2] = e2;
+  r_.f64[3] = e3;
+
+  return simde__m256d_from_private (r_);
+}
+
+simde__m256d simde_mm512_extractf64x4_pd (simde__m512d a, int imm8);
+int
+test_simde_mm512_maskz_extractf64x4_pd (void)
+{
+  const struct
+  {
+    simde__mmask8 k;
+    simde__m512d a;
+    simde__m256d r0;
+    simde__m256d r1;
+  } test_vec[2] = {
+    { 21,
+      simde_mm512_set_pd (-139.11, -172.36, -268.86, 393.53, -71.72, 36.69,
+                          98.47, -135.52),
+      simde_mm256_set_pd (0.00, 36.69, 0.00, -135.52),
+      simde_mm256_set_pd (0.00, -172.36, 0.00, 393.53) },
+    { 150,
+      simde_mm512_set_pd (-556.90, 522.06, 160.98, -932.28, 391.82, 600.12,
+                          -569.99, -491.12),
+      simde_mm256_set_pd (0.00, 600.12, -569.99, 0.00),
+      simde_mm256_set_pd (0.00, 522.06, 160.98, 0.00) },
+  };
+
+  for (size_t i = 0; i < (sizeof (test_vec) / sizeof (test_vec[0])); i++)
+    {
+      simde__m256d r;
+      r = simde_mm256_maskz_mov_pd (
+          test_vec[i].k, simde_mm512_extractf64x4_pd (test_vec[i].a, 0));
+      if (simde_test_x86_assert_equal_f64x4_ (r, test_vec[i].r0))
+        {
+          return 1;
+        }
+    }
+
+  return 0;
+}
-- 
2.53.0

From 5d49f0c56919dda9deb51b64ab3fc223dcc27b79 Mon Sep 17 00:00:00 2001
From: Lulu Cheng <chenglulu@loongson.cn>
Date: Tue, 27 Jan 2026 10:31:36 +0800
Subject: [PATCH 11/14] LoongArch: Fix bug123766.

The pointer parameter type for the original store class builtin
functions is CVPOINTER (const volatile void *).
Taking the following test as an example:

	```
	v4i64 v = {0, 0, 0, 0};
	void try_store() {
  	  long r[4];
  	  __lasx_xvst(v, r, 0);
	}
	```
At this point, the type of r is CVPOINTER, which means data in memory
can only be read through r.  Therefore, if the array r is not
initialized, an uninitialized warning will be issued.
This patch changes the pointer type of store-class builtin functions
from CVPOINTER to VPOINTER (volatile void *).

	PR target/123766

gcc/ChangeLog:

	* config/loongarch/loongarch-builtins.cc
	(loongarch_build_vpointer_type): New function.  Return a type
	for 'volatile void *'.
	(LARCH_ATYPE_VPOINTER): New macro.
	* config/loongarch/loongarch-ftypes.def: Change the pointer
	type of the store class function from CVPOINTER to VPOINTER.

gcc/testsuite/ChangeLog:

	* gcc.target/loongarch/vector/lasx/pr123766.c: New test.
	* gcc.target/loongarch/vector/lsx/pr123766.c: New test.

(cherry picked from commit fde8a3008586b2b469b42813613e582d4724afa0)
(cherry picked from commit 3534d9af5dce3775351595d3f7012ab7d4d34b89)
---
 gcc/config/loongarch/loongarch-builtins.cc    | 38 +++++++++++++------
 gcc/config/loongarch/loongarch-ftypes.def     | 24 ++++++------
 .../loongarch/vector/lasx/pr123766.c          | 28 ++++++++++++++
 .../loongarch/vector/lsx/pr123766.c           | 28 ++++++++++++++
 4 files changed, 94 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123766.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123766.c

diff --git a/gcc/config/loongarch/loongarch-builtins.cc b/gcc/config/loongarch/loongarch-builtins.cc
index 9493dedcab7..b37a7ac7031 100644
--- a/gcc/config/loongarch/loongarch-builtins.cc
+++ b/gcc/config/loongarch/loongarch-builtins.cc
@@ -1468,10 +1468,10 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
   LSX_BUILTIN (vfrintrp_d, LARCH_V2DF_FTYPE_V2DF),
   LSX_BUILTIN (vfrintrm_s, LARCH_V4SF_FTYPE_V4SF),
   LSX_BUILTIN (vfrintrm_d, LARCH_V2DF_FTYPE_V2DF),
-  LSX_NO_TARGET_BUILTIN (vstelm_b, LARCH_VOID_FTYPE_V16QI_CVPOINTER_SI_UQI),
-  LSX_NO_TARGET_BUILTIN (vstelm_h, LARCH_VOID_FTYPE_V8HI_CVPOINTER_SI_UQI),
-  LSX_NO_TARGET_BUILTIN (vstelm_w, LARCH_VOID_FTYPE_V4SI_CVPOINTER_SI_UQI),
-  LSX_NO_TARGET_BUILTIN (vstelm_d, LARCH_VOID_FTYPE_V2DI_CVPOINTER_SI_UQI),
+  LSX_NO_TARGET_BUILTIN (vstelm_b, LARCH_VOID_FTYPE_V16QI_VPOINTER_SI_UQI),
+  LSX_NO_TARGET_BUILTIN (vstelm_h, LARCH_VOID_FTYPE_V8HI_VPOINTER_SI_UQI),
+  LSX_NO_TARGET_BUILTIN (vstelm_w, LARCH_VOID_FTYPE_V4SI_VPOINTER_SI_UQI),
+  LSX_NO_TARGET_BUILTIN (vstelm_d, LARCH_VOID_FTYPE_V2DI_VPOINTER_SI_UQI),
   LSX_BUILTIN (vaddwev_d_w, LARCH_V2DI_FTYPE_V4SI_V4SI),
   LSX_BUILTIN (vaddwev_w_h, LARCH_V4SI_FTYPE_V8HI_V8HI),
   LSX_BUILTIN (vaddwev_h_b, LARCH_V8HI_FTYPE_V16QI_V16QI),
@@ -1641,7 +1641,7 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
   LSX_BUILTIN (vssrarni_du_q, LARCH_UV2DI_FTYPE_UV2DI_V2DI_USI),
   LSX_BUILTIN (vpermi_w, LARCH_V4SI_FTYPE_V4SI_V4SI_USI),
   LSX_BUILTIN (vld, LARCH_V16QI_FTYPE_CVPOINTER_SI),
-  LSX_NO_TARGET_BUILTIN (vst, LARCH_VOID_FTYPE_V16QI_CVPOINTER_SI),
+  LSX_NO_TARGET_BUILTIN (vst, LARCH_VOID_FTYPE_V16QI_VPOINTER_SI),
   LSX_BUILTIN (vssrlrn_b_h, LARCH_V16QI_FTYPE_V8HI_V8HI),
   LSX_BUILTIN (vssrlrn_h_w, LARCH_V8HI_FTYPE_V4SI_V4SI),
   LSX_BUILTIN (vssrlrn_w_d, LARCH_V4SI_FTYPE_V2DI_V2DI),
@@ -1652,7 +1652,7 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
   LSX_BUILTIN (vldi, LARCH_V2DI_FTYPE_HI),
   LSX_BUILTIN (vshuf_b, LARCH_V16QI_FTYPE_V16QI_V16QI_V16QI),
   LSX_BUILTIN (vldx, LARCH_V16QI_FTYPE_CVPOINTER_DI),
-  LSX_NO_TARGET_BUILTIN (vstx, LARCH_VOID_FTYPE_V16QI_CVPOINTER_DI),
+  LSX_NO_TARGET_BUILTIN (vstx, LARCH_VOID_FTYPE_V16QI_VPOINTER_DI),
   LSX_BUILTIN (vextl_qu_du, LARCH_UV2DI_FTYPE_UV2DI),
 
   /* Built-in functions for LASX */
@@ -2181,11 +2181,11 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
   LASX_BUILTIN (xvfrintrm_s, LARCH_V8SF_FTYPE_V8SF),
   LASX_BUILTIN (xvfrintrm_d, LARCH_V4DF_FTYPE_V4DF),
   LASX_BUILTIN (xvld, LARCH_V32QI_FTYPE_CVPOINTER_SI),
-  LASX_NO_TARGET_BUILTIN (xvst, LARCH_VOID_FTYPE_V32QI_CVPOINTER_SI),
-  LASX_NO_TARGET_BUILTIN (xvstelm_b, LARCH_VOID_FTYPE_V32QI_CVPOINTER_SI_UQI),
-  LASX_NO_TARGET_BUILTIN (xvstelm_h, LARCH_VOID_FTYPE_V16HI_CVPOINTER_SI_UQI),
-  LASX_NO_TARGET_BUILTIN (xvstelm_w, LARCH_VOID_FTYPE_V8SI_CVPOINTER_SI_UQI),
-  LASX_NO_TARGET_BUILTIN (xvstelm_d, LARCH_VOID_FTYPE_V4DI_CVPOINTER_SI_UQI),
+  LASX_NO_TARGET_BUILTIN (xvst, LARCH_VOID_FTYPE_V32QI_VPOINTER_SI),
+  LASX_NO_TARGET_BUILTIN (xvstelm_b, LARCH_VOID_FTYPE_V32QI_VPOINTER_SI_UQI),
+  LASX_NO_TARGET_BUILTIN (xvstelm_h, LARCH_VOID_FTYPE_V16HI_VPOINTER_SI_UQI),
+  LASX_NO_TARGET_BUILTIN (xvstelm_w, LARCH_VOID_FTYPE_V8SI_VPOINTER_SI_UQI),
+  LASX_NO_TARGET_BUILTIN (xvstelm_d, LARCH_VOID_FTYPE_V4DI_VPOINTER_SI_UQI),
   LASX_BUILTIN (xvinsve0_w, LARCH_V8SI_FTYPE_V8SI_V8SI_UQI),
   LASX_BUILTIN (xvinsve0_d, LARCH_V4DI_FTYPE_V4DI_V4DI_UQI),
   LASX_BUILTIN (xvpickve_w, LARCH_V8SI_FTYPE_V8SI_UQI),
@@ -2201,7 +2201,7 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
   LASX_BUILTIN (xvorn_v, LARCH_UV32QI_FTYPE_UV32QI_UV32QI),
   LASX_BUILTIN (xvldi, LARCH_V4DI_FTYPE_HI),
   LASX_BUILTIN (xvldx, LARCH_V32QI_FTYPE_CVPOINTER_DI),
-  LASX_NO_TARGET_BUILTIN (xvstx, LARCH_VOID_FTYPE_V32QI_CVPOINTER_DI),
+  LASX_NO_TARGET_BUILTIN (xvstx, LARCH_VOID_FTYPE_V32QI_VPOINTER_DI),
   LASX_BUILTIN (xvextl_qu_du, LARCH_UV4DI_FTYPE_UV4DI),
 
   /* LASX */
@@ -2451,11 +2451,25 @@ loongarch_build_cvpointer_type (void)
   return cache;
 }
 
+/* Return a type for 'volatile void *'.  */
+
+static tree
+loongarch_build_vpointer_type (void)
+{
+  static tree cache;
+
+  if (cache == NULL_TREE)
+    cache = build_pointer_type (build_qualified_type (void_type_node,
+						      TYPE_QUAL_VOLATILE));
+  return cache;
+}
+
 /* Source-level argument types.  */
 #define LARCH_ATYPE_VOID void_type_node
 #define LARCH_ATYPE_INT integer_type_node
 #define LARCH_ATYPE_POINTER ptr_type_node
 #define LARCH_ATYPE_CVPOINTER loongarch_build_cvpointer_type ()
+#define LARCH_ATYPE_VPOINTER loongarch_build_vpointer_type ()
 #define LARCH_ATYPE_BOOLEAN boolean_type_node
 /* Standard mode-based argument types.  */
 #define LARCH_ATYPE_QI intQI_type_node
diff --git a/gcc/config/loongarch/loongarch-ftypes.def b/gcc/config/loongarch/loongarch-ftypes.def
index 337f2c2c229..3dad8073bc7 100644
--- a/gcc/config/loongarch/loongarch-ftypes.def
+++ b/gcc/config/loongarch/loongarch-ftypes.def
@@ -497,10 +497,10 @@ DEF_LARCH_FTYPE (2, (VOID, SI, SI))
 DEF_LARCH_FTYPE (2, (VOID, UQI, SI))
 DEF_LARCH_FTYPE (2, (VOID, USI, UQI))
 DEF_LARCH_FTYPE (1, (VOID, UHI))
-DEF_LARCH_FTYPE (3, (VOID, V16QI, CVPOINTER, SI))
-DEF_LARCH_FTYPE (3, (VOID, V16QI, CVPOINTER, DI))
-DEF_LARCH_FTYPE (3, (VOID, V32QI, CVPOINTER, SI))
-DEF_LARCH_FTYPE (3, (VOID, V32QI, CVPOINTER, DI))
+DEF_LARCH_FTYPE (3, (VOID, V16QI, VPOINTER, SI))
+DEF_LARCH_FTYPE (3, (VOID, V16QI, VPOINTER, DI))
+DEF_LARCH_FTYPE (3, (VOID, V32QI, VPOINTER, SI))
+DEF_LARCH_FTYPE (3, (VOID, V32QI, VPOINTER, DI))
 DEF_LARCH_FTYPE (3, (VOID, V4DF, POINTER, SI))
 DEF_LARCH_FTYPE (3, (VOID, V2DF, POINTER, SI))
 DEF_LARCH_FTYPE (3, (VOID, V2DI, CVPOINTER, SI))
@@ -682,10 +682,10 @@ DEF_LARCH_FTYPE(3,(V4DI,V4DI,UV16HI,V16HI))
 DEF_LARCH_FTYPE(2,(UV8SI,UV32QI,UV32QI))
 DEF_LARCH_FTYPE(2,(V8SI,UV32QI,V32QI))
 
-DEF_LARCH_FTYPE(4,(VOID,V16QI,CVPOINTER,SI,UQI))
-DEF_LARCH_FTYPE(4,(VOID,V8HI,CVPOINTER,SI,UQI))
-DEF_LARCH_FTYPE(4,(VOID,V4SI,CVPOINTER,SI,UQI))
-DEF_LARCH_FTYPE(4,(VOID,V2DI,CVPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V16QI,VPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V8HI,VPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V4SI,VPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V2DI,VPOINTER,SI,UQI))
 
 DEF_LARCH_FTYPE (2, (DI, V16QI, UQI))
 DEF_LARCH_FTYPE (2, (DI, V8HI, UQI))
@@ -707,10 +707,10 @@ DEF_LARCH_FTYPE (3, (UV16HI, UV16HI, V16HI, USI))
 DEF_LARCH_FTYPE (3, (UV8SI, UV8SI, V8SI, USI))
 DEF_LARCH_FTYPE (3, (UV4DI, UV4DI, V4DI, USI))
 
-DEF_LARCH_FTYPE(4,(VOID,V32QI,CVPOINTER,SI,UQI))
-DEF_LARCH_FTYPE(4,(VOID,V16HI,CVPOINTER,SI,UQI))
-DEF_LARCH_FTYPE(4,(VOID,V8SI,CVPOINTER,SI,UQI))
-DEF_LARCH_FTYPE(4,(VOID,V4DI,CVPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V32QI,VPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V16HI,VPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V8SI,VPOINTER,SI,UQI))
+DEF_LARCH_FTYPE(4,(VOID,V4DI,VPOINTER,SI,UQI))
 
 DEF_LARCH_FTYPE (1, (BOOLEAN,V16QI))
 DEF_LARCH_FTYPE(2,(V16QI,CVPOINTER,CVPOINTER))
diff --git a/gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123766.c b/gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123766.c
new file mode 100644
index 00000000000..88170cd6aef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lasx/pr123766.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlasx  -Werror -Wextra" } */
+
+#include <lasxintrin.h>
+
+__m256i v = {0, 0, 0, 0};
+
+#define TEST(NAME)			  \
+  void test_##NAME (void)		  \
+  {					  \
+    long long r[4];			  \
+    __lasx_##NAME (v, r, 0);		  \
+  }
+
+TEST (xvst);
+TEST (xvstx);
+
+#define TEST1(NAME, TYPE, NUM)		  \
+  void test_##NAME (void)		  \
+  {					  \
+    TYPE r[NUM];			  \
+    __lasx_##NAME (v, r, 0, 0);		  \
+  }
+
+TEST1 (xvstelm_b, char, 32);
+TEST1 (xvstelm_h, short, 16);
+TEST1 (xvstelm_w, int, 8);
+TEST1 (xvstelm_d, long long, 4);
diff --git a/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123766.c b/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123766.c
new file mode 100644
index 00000000000..54f57e61113
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123766.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlsx  -Werror -Wextra" } */
+
+#include <lsxintrin.h>
+
+__m128i v = {0, 0};
+
+#define TEST(NAME)			  \
+  void test_##NAME (void)		  \
+  {					  \
+    long long r[2];			  \
+    __lsx_##NAME (v, r, 0);		  \
+  }
+
+TEST (vst);
+TEST (vstx);
+
+#define TEST1(NAME, TYPE, NUM)		  \
+  void test_##NAME (void)		  \
+  {					  \
+    TYPE r[NUM];			  \
+    __lsx_##NAME (v, r, 0, 0);		  \
+  }
+
+TEST1 (vstelm_b, char, 16);
+TEST1 (vstelm_h, short, 8);
+TEST1 (vstelm_w, int, 4);
+TEST1 (vstelm_d, long long, 2);
-- 
2.53.0

From 8d82e3c4780d237b84542df18062cdbede4bebb4 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Thu, 29 Jan 2026 17:08:02 +0800
Subject: [PATCH 12/14] LoongArch: rework copysign and xorsign implementation

The copysign and xorsign implementation had two significant bugs:

1. The GCC Internal documentation explicitly says the IOR, XOR, and AND
   optabs are only for fixed-point modes, i.e. they cannot be used for
   floating-point modes.
2. The handling of "%V" uses a very nasty way to pun floating-point
   const value to integer representation, invoking undefined behavior on
   32-bit hosts by shifting left a "long" by 32 bits.  In fact
   lowpart_subreg handles punning of const values correctly despite the
   name contains "reg."

Fix the bugs by using lowpart_subreg to pun the modes in the expanders.

gcc/

	* config/loongarch/predicates.md (const_vector_neg_fp_operand):
	New define_predicate.
	(reg_or_vector_neg_fp_operand): New define_predicate.
	* config/loongarch/lasx.md (copysign<mode>3): Remove.
	(xorsign<mode>3): Remove.
	* config/loongarch/lsx.md (copysign<mode>3): Remove.
	(@xorsign<mode>3): Remove.
	* config/loongarch/simd.md (copysign<mode>3): New define_expand.
	(@xorsign<mode>3): New define_expand.
	(and<mode>3): Only allow IVEC instead of ALLVEC.
	(ior<mode>3): Likewise.
	(xor<mode>3): Likewise.
	* config/loongarch/loongarch.cc (loongarch_print_operand): No
	longer allow floating-point vector constants for %V.
	(loongarch_const_vector_bitimm_set_p): Always return false for
	floating-point vector constants.
	(loongarch_build_signbit_mask): Factor out force_reg.
	(loongarch_emit_swrsqrtsf): Use integer vector mode instead of
	floating-point vector mode when masking zero inputs.

(cherry picked from commit 77527ecae9275e34a6a6dc0b7abfce27c607ee3d)
(cherry picked from commit bd78356f72b03118178d17f79415574149d4ad97)
---
 gcc/config/loongarch/lasx.md       | 53 -----------------
 gcc/config/loongarch/loongarch.cc  | 65 +++++----------------
 gcc/config/loongarch/lsx.md        | 53 -----------------
 gcc/config/loongarch/predicates.md | 16 +++++
 gcc/config/loongarch/simd.md       | 94 +++++++++++++++++++-----------
 5 files changed, 91 insertions(+), 190 deletions(-)

diff --git a/gcc/config/loongarch/lasx.md b/gcc/config/loongarch/lasx.md
index 7bb78aba493..93c9ca89139 100644
--- a/gcc/config/loongarch/lasx.md
+++ b/gcc/config/loongarch/lasx.md
@@ -2646,59 +2646,6 @@ (define_insn "lasx_xvsigncov_<lasxfmt>"
   [(set_attr "type" "simd_int_arith")
    (set_attr "mode" "<MODE>")])
 
-(define_expand "copysign<mode>3"
-  [(set (match_dup 4)
-	(and:FLASX
-	  (not:FLASX (match_dup 3))
-	  (match_operand:FLASX 1 "register_operand")))
-   (set (match_dup 5)
-	(and:FLASX (match_dup 3)
-		   (match_operand:FLASX 2 "reg_or_vector_same_val_operand")))
-   (set (match_operand:FLASX 0 "register_operand")
-	(ior:FLASX (match_dup 4) (match_dup 5)))]
-  "ISA_HAS_LASX"
-{
-  /* copysign (x, -1) should instead be expanded as setting the sign
-     bit.  */
-  if (!REG_P (operands[2]))
-    {
-      rtx op2_elt = unwrap_const_vec_duplicate (operands[2]);
-      if (GET_CODE (op2_elt) == CONST_DOUBLE
-	  && real_isneg (CONST_DOUBLE_REAL_VALUE (op2_elt)))
-	{
-	  rtx n = GEN_INT (8 * GET_MODE_SIZE (<UNITMODE>mode) - 1);
-	  operands[0] = lowpart_subreg (<VIMODE256>mode, operands[0],
-					<MODE>mode);
-	  operands[1] = lowpart_subreg (<VIMODE256>mode, operands[1],
-					<MODE>mode);
-	  emit_insn (gen_lasx_xvbitseti_<lasxfmt> (operands[0],
-						   operands[1], n));
-	  DONE;
-	}
-    }
-
-  operands[2] = force_reg (<MODE>mode, operands[2]);
-  operands[3] = loongarch_build_signbit_mask (<MODE>mode, 1, 0);
-
-  operands[4] = gen_reg_rtx (<MODE>mode);
-  operands[5] = gen_reg_rtx (<MODE>mode);
-})
-
-(define_expand "xorsign<mode>3"
-  [(set (match_dup 4)
-    (and:FLASX (match_dup 3)
-        (match_operand:FLASX 2 "register_operand")))
-   (set (match_operand:FLASX 0 "register_operand")
-    (xor:FLASX (match_dup 4)
-         (match_operand:FLASX 1 "register_operand")))]
-  "ISA_HAS_LASX"
-{
-  operands[3] = loongarch_build_signbit_mask (<MODE>mode, 1, 0);
-
-  operands[4] = gen_reg_rtx (<MODE>mode);
-})
-
-
 (define_insn "absv4df2"
   [(set (match_operand:V4DF 0 "register_operand" "=f")
 	(abs:V4DF (match_operand:V4DF 1 "register_operand" "f")))]
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index d2d18d98e9f..e013e1b9f57 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -1722,28 +1722,7 @@ loongarch_const_vector_bitimm_set_p (rtx op, machine_mode mode)
       && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
 	  || GET_MODE_CLASS (mode) == MODE_VECTOR_INT))
     {
-      unsigned HOST_WIDE_INT val;
-
-      if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
-	{
-	  rtx val_s = CONST_VECTOR_ELT (op, 0);
-	  const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (val_s);
-	  if (GET_MODE (val_s) == DFmode)
-	    {
-	      long tmp[2];
-	      REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
-	      val = (unsigned HOST_WIDE_INT) tmp[1] << 32 | tmp[0];
-	    }
-	  else
-	    {
-	      long tmp;
-	      REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
-	      val = (unsigned HOST_WIDE_INT) tmp;
-	    }
-	}
-      else
-	val = UINTVAL (CONST_VECTOR_ELT (op, 0));
-
+      unsigned HOST_WIDE_INT val = UINTVAL (CONST_VECTOR_ELT (op, 0));
       int vlog2 = exact_log2 (val & GET_MODE_MASK (GET_MODE_INNER (mode)));
 
       if (vlog2 != -1)
@@ -6462,35 +6441,18 @@ loongarch_print_operand (FILE *file, rtx op, int letter)
 	{
 	  machine_mode mode = GET_MODE_INNER (GET_MODE (op));
 	  rtx val_s = CONST_VECTOR_ELT (op, 0);
-	  unsigned HOST_WIDE_INT val;
-
-	  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+	  if (CONST_INT_P (val_s))
 	    {
-	      const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (val_s);
-	      if (GET_MODE (val_s) == DFmode)
-		{
-		  long tmp[2];
-		  REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
-		  val = (unsigned HOST_WIDE_INT) (tmp[1] << 32 | tmp[0]);
-		}
-	      else
+	      unsigned HOST_WIDE_INT val = UINTVAL (val_s);
+	      int vlog2 = exact_log2 (val & GET_MODE_MASK (mode));
+	      if (vlog2 != -1)
 		{
-		  long tmp;
-		  REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
-		  val = (unsigned HOST_WIDE_INT) tmp;
+		  fprintf (file, "%d", vlog2);
+		  break;
 		}
 	    }
-	  else
-	    val = UINTVAL (val_s);
-
-	  int vlog2 = exact_log2 (val & GET_MODE_MASK (mode));
-	  if (vlog2 != -1)
-	    fprintf (file, "%d", vlog2);
-	  else
-	    output_operand_lossage ("invalid use of '%%%c'", letter);
 	}
-      else
-	output_operand_lossage ("invalid use of '%%%c'", letter);
+      output_operand_lossage ("invalid use of '%%%c'", letter);
       break;
 
     case 'W':
@@ -10935,7 +10897,7 @@ loongarch_build_signbit_mask (machine_mode mode, bool vect, bool invert)
     return force_reg (inner_mode, mask);
 
   v = loongarch_build_const_vector (vec_mode, vect, mask);
-  return force_reg (vec_mode, v);
+  return v;
 }
 
 /* Use rsqrte instruction and Newton-Rhapson to compute the approximation of
@@ -10984,10 +10946,11 @@ void loongarch_emit_swrsqrtsf (rtx res, rtx a, machine_mode mode, bool recip)
       if (VECTOR_MODE_P (mode))
 	{
 	  machine_mode imode = related_int_vector_mode (mode).require ();
-	  rtx mask = gen_reg_rtx (imode);
-	  emit_insn (gen_rtx_SET (mask, gen_rtx_NE (imode, a, zero)));
-	  emit_insn (gen_rtx_SET (x0, gen_rtx_AND (mode, x0,
-						   gen_lowpart (mode, mask))));
+	  rtx mask = force_reg (imode, gen_rtx_NE (imode, a, zero));
+	  emit_move_insn (gen_lowpart (imode, x0),
+			  gen_rtx_AND (imode,
+				       gen_lowpart (imode, x0),
+				       mask));
 	}
       else
 	{
diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md
index 7131a53edd3..ee823c8b665 100644
--- a/gcc/config/loongarch/lsx.md
+++ b/gcc/config/loongarch/lsx.md
@@ -2236,59 +2236,6 @@ (define_insn "lsx_vsigncov_<lsxfmt>"
   [(set_attr "type" "simd_int_arith")
    (set_attr "mode" "<MODE>")])
 
-(define_expand "copysign<mode>3"
-  [(set (match_dup 4)
-	(and:FLSX
-	  (not:FLSX (match_dup 3))
-	  (match_operand:FLSX 1 "register_operand")))
-   (set (match_dup 5)
-	(and:FLSX (match_dup 3)
-		  (match_operand:FLSX 2 "reg_or_vector_same_val_operand")))
-   (set (match_operand:FLSX 0 "register_operand")
-	(ior:FLSX (match_dup 4) (match_dup 5)))]
-  "ISA_HAS_LSX"
-{
-  /* copysign (x, -1) should instead be expanded as setting the sign
-     bit.  */
-  if (!REG_P (operands[2]))
-    {
-      rtx op2_elt = unwrap_const_vec_duplicate (operands[2]);
-      if (GET_CODE (op2_elt) == CONST_DOUBLE
-	  && real_isneg (CONST_DOUBLE_REAL_VALUE (op2_elt)))
-	{
-	  rtx n = GEN_INT (8 * GET_MODE_SIZE (<UNITMODE>mode) - 1);
-	  operands[0] = lowpart_subreg (<VIMODE>mode, operands[0],
-					<MODE>mode);
-	  operands[1] = lowpart_subreg (<VIMODE>mode, operands[1],
-					<MODE>mode);
-	  emit_insn (gen_lsx_vbitseti_<lsxfmt> (operands[0], operands[1],
-						n));
-	  DONE;
-	}
-    }
-
-  operands[2] = force_reg (<MODE>mode, operands[2]);
-  operands[3] = loongarch_build_signbit_mask (<MODE>mode, 1, 0);
-
-  operands[4] = gen_reg_rtx (<MODE>mode);
-  operands[5] = gen_reg_rtx (<MODE>mode);
-})
-
-(define_expand "@xorsign<mode>3"
-  [(set (match_dup 4)
-    (and:FLSX (match_dup 3)
-        (match_operand:FLSX 2 "register_operand")))
-   (set (match_operand:FLSX 0 "register_operand")
-    (xor:FLSX (match_dup 4)
-         (match_operand:FLSX 1 "register_operand")))]
-  "ISA_HAS_LSX"
-{
-  operands[3] = loongarch_build_signbit_mask (<MODE>mode, 1, 0);
-
-  operands[4] = gen_reg_rtx (<MODE>mode);
-})
-
-
 (define_insn "absv2df2"
   [(set (match_operand:V2DF 0 "register_operand" "=f")
 	(abs:V2DF (match_operand:V2DF 1 "register_operand" "f")))]
diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md
index fd2d7b9ab55..d4ff2522881 100644
--- a/gcc/config/loongarch/predicates.md
+++ b/gcc/config/loongarch/predicates.md
@@ -647,6 +647,18 @@ (define_predicate "const_vector_same_uimm_operand"
   return loongarch_const_vector_same_int_p (op, mode);
 })
 
+(define_predicate "const_vector_neg_fp_operand"
+  (match_code "const_vector")
+{
+  machine_mode imode = related_int_vector_mode (mode).require ();
+  rtx mask = loongarch_build_signbit_mask (imode, 1, 0);
+
+  op = gen_lowpart (imode, op);
+  return rtx_equal_p (mask,
+		      simplify_const_binary_operation (AND, imode, mask,
+						       op));
+})
+
 (define_predicate "par_const_vector_shf_set_operand"
   (match_code "parallel")
 {
@@ -673,6 +685,10 @@ (define_predicate "reg_or_vector_same_uimm_operand"
   (ior (match_operand 0 "register_operand")
        (match_operand 0 "const_vector_same_uimm_operand")))
 
+(define_predicate "reg_or_vector_neg_fp_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "const_vector_neg_fp_operand")))
+
 ;; PARALLEL for a vec_select that selects all the even or all the odd
 ;; elements of a vector of MODE.
 (define_special_predicate "vect_par_cnst_even_or_odd_half"
diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
index 9f4525a25f0..1fdc443e4ac 100644
--- a/gcc/config/loongarch/simd.md
+++ b/gcc/config/loongarch/simd.md
@@ -973,10 +973,10 @@ (define_expand "<simd_isa>_<x>v<insn>ri_<simdfmt>"
 })
 
 (define_insn "xor<mode>3"
-  [(set (match_operand:ALLVEC 0 "register_operand" "=f,f,f")
-	(xor:ALLVEC
-	  (match_operand:ALLVEC 1 "register_operand" "f,f,f")
-	  (match_operand:ALLVEC 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
+  [(set (match_operand:IVEC 0 "register_operand" "=f,f,f")
+	(xor:IVEC
+	  (match_operand:IVEC 1 "register_operand" "f,f,f")
+	  (match_operand:IVEC 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
   ""
   "@
    <x>vxor.v\t%<wu>0,%<wu>1,%<wu>2
@@ -986,10 +986,10 @@ (define_insn "xor<mode>3"
    (set_attr "mode" "<MODE>")])
 
 (define_insn "ior<mode>3"
-  [(set (match_operand:ALLVEC 0 "register_operand" "=f,f,f")
-	(ior:ALLVEC
-	  (match_operand:ALLVEC 1 "register_operand" "f,f,f")
-	  (match_operand:ALLVEC 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
+  [(set (match_operand:IVEC 0 "register_operand" "=f,f,f")
+	(ior:IVEC
+	  (match_operand:IVEC 1 "register_operand" "f,f,f")
+	  (match_operand:IVEC 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
   ""
   "@
    <x>vor.v\t%<wu>0,%<wu>1,%<wu>2
@@ -999,10 +999,10 @@ (define_insn "ior<mode>3"
    (set_attr "mode" "<MODE>")])
 
 (define_insn "and<mode>3"
-  [(set (match_operand:ALLVEC 0 "register_operand" "=f,f,f")
-	(and:ALLVEC
-	  (match_operand:ALLVEC 1 "register_operand" "f,f,f")
-	  (match_operand:ALLVEC 2 "reg_or_vector_same_val_operand" "f,YZ,Urv8")))]
+  [(set (match_operand:IVEC 0 "register_operand" "=f,f,f")
+	(and:IVEC
+	  (match_operand:IVEC 1 "register_operand" "f,f,f")
+	  (match_operand:IVEC 2 "reg_or_vector_same_val_operand" "f,YZ,Urv8")))]
   ""
 {
   switch (which_alternative)
@@ -1011,27 +1011,9 @@ (define_insn "and<mode>3"
       return "<x>vand.v\t%<wu>0,%<wu>1,%<wu>2";
     case 1:
       {
-	rtx elt0 = CONST_VECTOR_ELT (operands[2], 0);
-	unsigned HOST_WIDE_INT val;
-	if (GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_FLOAT)
-	  {
-	  const REAL_VALUE_TYPE *x = CONST_DOUBLE_REAL_VALUE (elt0);
-	  if (GET_MODE (elt0) == DFmode)
-	    {
-	      long tmp[2];
-	      REAL_VALUE_TO_TARGET_DOUBLE (*x, tmp);
-	      val = ~((unsigned HOST_WIDE_INT) tmp[1] << 32 | tmp[0]);
-	    }
-	  else
-	    {
-	      long tmp;
-	      REAL_VALUE_TO_TARGET_SINGLE (*x, tmp);
-	      val = ~((unsigned HOST_WIDE_INT) tmp);
-	    }
-	  }
-	else
-	  val = ~UINTVAL (elt0);
-	operands[2] = loongarch_gen_const_int_vector (<VIMODE>mode, val & (-val));
+	operands[2] = simplify_const_unary_operation (NOT, <MODE>mode,
+						      operands[2],
+						      <MODE>mode);
 	return "<x>vbitclri.%v0\t%<wu>0,%<wu>1,%V2";
       }
     case 2:
@@ -1043,6 +1025,52 @@ (define_insn "and<mode>3"
   [(set_attr "type" "simd_logic,simd_bit,simd_logic")
    (set_attr "mode" "<MODE>")])
 
+(define_expand "copysign<mode>3"
+  [(match_operand:FVEC 0 "register_operand")
+   (match_operand:FVEC 1 "register_operand")
+   (match_operand:FVEC 2 "reg_or_vector_neg_fp_operand")]
+  ""
+{
+  machine_mode imode = <VIMODE>mode;
+  rtx op[3], mask = loongarch_build_signbit_mask (imode, 1, 0);
+
+  /* Pun the operation into fixed-point bitwise operations.  */
+  for (int i = 0; i < 3; i++)
+    op[i] = lowpart_subreg (imode, operands[i], <MODE>mode);
+
+  /* Copysign from a positive const should have been already simplified
+     to abs, ignore the case here.  Copysign from a negative const is
+     a simple vbitset which is an alternative of ior (see above).  */
+  if (const_vector_neg_fp_operand (operands[2], <MODE>mode))
+    emit_insn (gen_ior<vimode>3 (op[0], op[1], mask));
+  else
+    {
+      mask = force_reg (imode, mask);
+      emit_insn (gen_<simd_isa>_<x>vbitsel_<simdfmt_as_i> (op[0], op[1],
+							   op[2], mask));
+    }
+
+  DONE;
+})
+
+(define_expand "@xorsign<mode>3"
+  [(match_operand:FVEC 0 "register_operand")
+   (match_operand:FVEC 1 "register_operand")
+   (match_operand:FVEC 2 "register_operand")]
+  ""
+{
+  machine_mode imode = <VIMODE>mode;
+  rtx op[3];
+
+  for (int i = 0; i < 3; i++)
+    op[i] = lowpart_subreg (imode, operands[i], <MODE>mode);
+
+  rtx t = loongarch_build_signbit_mask (imode, 1, 0);
+  t = force_reg (imode, simplify_gen_binary (AND, imode, op[2], t));
+  emit_move_insn (op[0], simplify_gen_binary (XOR, imode, op[1], t));
+  DONE;
+})
+
 ; The LoongArch SX Instructions.
 (include "lsx.md")
 
-- 
2.53.0

From 6babea3603ad6f90e61173bedfed123585f10632 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Thu, 26 Feb 2026 11:55:22 +0800
Subject: [PATCH 13/14] middle-end: extend the narrower shift amount before
 broadcasting it [PR 124250]

The comment above expand_vector_broadcast() states a precondition that
the mode of op must be the element mode of vmode.  But when
expand_binop() called expand_vector_broadcast() to broadcast the shift
amount, it only truncated the shift amount if it's too wide, but no
action is performed if the shift amount is too narrow.

Note that the assertion in expand_vector_broadcast is deliberately
skipped in the backport, in order not to wake up latent "harmless" bugs.

	PR middle-end/124250
	PR target/123807

gcc/
	* optabs.cc (expand_binop): Extend the shift amount if it's
	narrower than the element of the shifted vector.

gcc/testsuite/

	* gcc.c-torture/compile/pr124250.c: New test.

(cherry picked from commit 1139fdadc85a0b602a2833e6b7f2cfe2a8a90cdb)
---
 gcc/optabs.cc                                 | 32 ++++++++++++-------
 .../gcc.c-torture/compile/pr124250.c          |  8 +++++
 2 files changed, 29 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr124250.c

diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 0a14b1eef8a..45c692747fd 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -422,9 +422,9 @@ force_expand_binop (machine_mode mode, optab binoptab,
   return true;
 }
 
-/* Create a new vector value in VMODE with all elements set to OP.  The
-   mode of OP must be the element mode of VMODE.  If OP is a constant,
-   then the return value will be a constant.  */
+/* Create a new vector value in VMODE with all elements set to OP.  If OP
+   is not a constant, the mode of it must be the element mode of VMODE.
+   If OP is a constant, then the return value will be a constant.  */
 
 rtx
 expand_vector_broadcast (machine_mode vmode, rtx op)
@@ -1623,15 +1623,25 @@ expand_binop (machine_mode mode, optab binoptab, rtx op0, rtx op1,
       if (otheroptab
 	  && (icode = optab_handler (otheroptab, mode)) != CODE_FOR_nothing)
 	{
-	  /* The scalar may have been extended to be too wide.  Truncate
-	     it back to the proper size to fit in the broadcast vector.  */
+	  /* The scalar may be wider or narrower than the vector element.
+	     Truncate or extend it to the proper size to fit in the
+	     broadcast vector.  */
 	  scalar_mode inner_mode = GET_MODE_INNER (mode);
-	  if (!CONST_INT_P (op1)
-	      && (GET_MODE_BITSIZE (as_a <scalar_int_mode> (GET_MODE (op1)))
-		  > GET_MODE_BITSIZE (inner_mode)))
-	    op1 = force_reg (inner_mode,
-			     simplify_gen_unary (TRUNCATE, inner_mode, op1,
-						 GET_MODE (op1)));
+	  if (!CONST_INT_P (op1))
+	    {
+	      auto mode1 = as_a <scalar_int_mode> (GET_MODE (op1));
+	      int size1 = GET_MODE_BITSIZE (mode1);
+	      int inner_size = GET_MODE_BITSIZE (inner_mode);
+
+	      if (size1 != inner_size)
+		{
+		  auto unary = size1 > inner_size ? TRUNCATE : ZERO_EXTEND;
+		  op1 = force_reg (inner_mode,
+				   simplify_gen_unary (unary, inner_mode,
+						       op1, mode1));
+		}
+	    }
+
 	  rtx vop1 = expand_vector_broadcast (mode, op1);
 	  if (vop1)
 	    {
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr124250.c b/gcc/testsuite/gcc.c-torture/compile/pr124250.c
new file mode 100644
index 00000000000..1435091dc0b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr124250.c
@@ -0,0 +1,8 @@
+typedef long long v2i64 __attribute__ ((vector_size (16), aligned (16)));
+v2i64 a, b;
+
+void
+test (int l)
+{
+  a = b >> (-l);
+}
-- 
2.53.0

From 3be2126fb41c485c2aeee5c4279fb90e885025c2 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao <xry111@xry111.site>
Date: Fri, 27 Feb 2026 10:55:16 +0800
Subject: [PATCH 14/14] LoongArch: testsuite: drop scan-assembler from
 pr122097.c

This test case is backported from 16, but in 14/15 the tree optimization
doesn't produce a .COPYSIGN from negative constant vector.  Thus
scan-assembler fails in 14/15.

Simply drop it for 14/15.

gcc/testsuite/

	PR target/122097
	* gcc.target/loongarch/pr122097.c (dg-final): Remove.

(cherry picked from commit d7e89271ec6dac05574200e1e9a2d11e0ff467e7)
---
 gcc/testsuite/gcc.target/loongarch/pr122097.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gcc/testsuite/gcc.target/loongarch/pr122097.c b/gcc/testsuite/gcc.target/loongarch/pr122097.c
index 5d32b191baf..4ed0375bb61 100644
--- a/gcc/testsuite/gcc.target/loongarch/pr122097.c
+++ b/gcc/testsuite/gcc.target/loongarch/pr122097.c
@@ -1,6 +1,5 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -mabi=lp64d -mlsx" } */
-/* { dg-final { scan-assembler "vbitseti\.d\t\\\$vr\[0-9\]+,\\\$vr\[0-9\]+,63" } } */
 
 typedef long unsigned int size_t;
 typedef unsigned char simde__mmask8;
-- 
2.53.0

