On Mon, Aug 31, 2026 at 3:43 PM Hongtao Liu <[email protected]> wrote:
>
> On Mon, Aug 31, 2026 at 7:34 AM H.J. Lu <[email protected]> wrote:
> >
> > Since ZERO_EXTEND TImode store isn't an SSE to integer register move,
> > treat it as store.
> For a single ZERO_EXTEND TImode store, movq + movaps is generated, so
> treating it as store is not correct.
> The issue in your PR, is not related to the cost of ZERO_EXTEND with
> memory dest, it's pass_stv is not aware that movq can be CSEed if
> they're from the same GPR.

I added zero_extend and zero_extend_multiple to track zero-extended
DImode registers in the v2 patch.

> I don't think it's correct to adjust the cost of ZERO_EXTEND when dest
> is memory, it's more like limitation of stv don't know further
> optimization in later rtl passes.
>

-- 
H.J.
---
There are 4 zero-extend TImode stores

(set (mem/c:TI (symbol_ref:DI ("m0") (zero_extend:TI (reg/v:DI 101)))))

in

void
foo (unsigned long x)
{
  __int128 m = x;
  m0 = m;
  m1 = m;
  m2 = m;
  m3 = m;
}

When converting them to V1TI store, we need to zero-extend to V2DImode
first:

(set (reg:V2DI 102) (vec_concat:V2DI (reg/v:DI 101) (const_int 0 [0])))
(set (mem/c:V1TI (symbol_ref:DI ("m0")) (subreg:V1TI (reg:V2DI 102) 0)))

Since we only need to zero-extend to V2DImode once for multiple V1TImode
stores, ignore SSE to integer move cost of multiple zero-extend stores
of the same register if cost of integer store >= cost of SSE to integer
move so that all zero-extend stores are converted to V2DImode stores.

gcc/

PR target/127020
* config/i386/i386-features.cc
(general_scalar_chain::compute_convert_gain): Add an auto_bitmap
argument.
(timode_scalar_chain::compute_convert_gain): Likewise.  Ignore
SSE to integer move cost for multiple zero-extend stores of the
same register if cost of integer store >= cost of SSE to integer
move.
* config/i386/i386-features.h (scalar_chain::compute_convert_gain):
Add an auto_bitmap argument.
(general_scalar_chain::compute_convert_gain): Likewise.
(timode_scalar_chain::compute_convert_gain): Likewise.

gcc/testsuite/

PR target/127020
* gcc.target/i386/sse4_1-stv-15.c: New file.
* gcc.target/i386/sse4_1-stv-16.c: Likewise.
From 4896ac2bef07577290cc0a8e6c944b87fc16aad3 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Tue, 25 Aug 2026 04:13:54 +0800
Subject: [PATCH v2] x86-64: Ignore SSE to integer move cost of multiple
 zero-extend stores

There are 4 zero-extend TImode stores

(set (mem/c:TI (symbol_ref:DI ("m0") (zero_extend:TI (reg/v:DI 101)))))

in

void
foo (unsigned long x)
{
  __int128 m = x;
  m0 = m;
  m1 = m;
  m2 = m;
  m3 = m;
}

When converting them to V1TI store, we need to zero-extend to V2DImode
first:

(set (reg:V2DI 102) (vec_concat:V2DI (reg/v:DI 101) (const_int 0 [0])))
(set (mem/c:V1TI (symbol_ref:DI ("m0")) (subreg:V1TI (reg:V2DI 102) 0)))

Since we only need to zero-extend to V2DImode once for multiple V1TImode
stores, ignore SSE to integer move cost of multiple zero-extend stores
of the same register if cost of integer store >= cost of SSE to integer
move so that all zero-extend stores are converted to V2DImode stores.

gcc/

	PR target/127020
	* config/i386/i386-features.cc
	(general_scalar_chain::compute_convert_gain): Add an auto_bitmap
	argument.
	(timode_scalar_chain::compute_convert_gain): Likewise.  Ignore
	SSE to integer move cost for multiple zero-extend stores of the
	same register if cost of integer store >= cost of SSE to integer
	move.
	* config/i386/i386-features.h (scalar_chain::compute_convert_gain):
	Add an auto_bitmap argument.
	(general_scalar_chain::compute_convert_gain): Likewise.
	(timode_scalar_chain::compute_convert_gain): Likewise.

gcc/testsuite/

	PR target/127020
	* gcc.target/i386/sse4_1-stv-15.c: New file.
	* gcc.target/i386/sse4_1-stv-16.c: Likewise.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/config/i386/i386-features.cc              | 56 +++++++++++++++----
 gcc/config/i386/i386-features.h               |  6 +-
 gcc/testsuite/gcc.target/i386/sse4_1-stv-15.c | 15 +++++
 gcc/testsuite/gcc.target/i386/sse4_1-stv-16.c | 19 +++++++
 4 files changed, 83 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/sse4_1-stv-15.c
 create mode 100644 gcc/testsuite/gcc.target/i386/sse4_1-stv-16.c

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 1d26aa0c336..ed85053e7e0 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -612,7 +612,7 @@ general_scalar_chain::vector_const_cost (rtx exp, basic_block bb)
 /* Return true if it's cost profitable for chain conversion.  */
 
 bool
-general_scalar_chain::compute_convert_gain ()
+general_scalar_chain::compute_convert_gain (auto_bitmap &)
 {
   bitmap_iterator bi;
   unsigned insn_uid;
@@ -1641,7 +1641,8 @@ timode_immed_const_gain (rtx cst, basic_block bb)
 /* Return true it's cost profitable for for chain conversion.  */
 
 bool
-timode_scalar_chain::compute_convert_gain ()
+timode_scalar_chain::compute_convert_gain
+  (auto_bitmap &zero_extend_multiple)
 {
   /* Assume that if we have to move TImode values between units,
      then transforming this chain isn't worth it.  */
@@ -1927,9 +1928,29 @@ timode_scalar_chain::compute_convert_gain ()
 
 	case ZERO_EXTEND:
 	  if (GET_MODE (XEXP (src, 0)) == DImode)
-	    /* xor (2 bytes) vs. vmovq (5 bytes).  */
-	    igain = speed_p ? COSTS_N_INSNS (1) - ix86_cost->sse_to_integer
-			    : -COSTS_N_BYTES (3);
+	    {
+	      if (MEM_P (dst))
+		{
+		  /* xor (2 bytes) vs. vmovq (5 bytes).  */
+		  if (speed_p)
+		    {
+		      igain = COSTS_N_INSNS (1);
+		      int sse_to_integer_cost = ix86_cost->sse_to_integer;
+		      /* If there are multiple zero-extend stores of the
+			 same register and cost of integer store >= cost
+			 of SSE to integer move, ignore SSE to integer
+			 move cost.  */
+		      if (bitmap_bit_p (zero_extend_multiple,
+					REGNO (XEXP (src, 0)))
+			  && (ix86_cost->int_store[2]
+			      >= sse_to_integer_cost))
+			sse_to_integer_cost = 0;
+		      igain -= sse_to_integer_cost;
+		    }
+		  else
+		    igain = -COSTS_N_BYTES (3);
+		}
+	    }
 	  break;
 
 	default:
@@ -2561,7 +2582,9 @@ timode_mem_p (rtx x)
 /* The TImode version of scalar_to_vector_candidate_p.  */
 
 static bool
-timode_scalar_to_vector_candidate_p (rtx_insn *insn)
+timode_scalar_to_vector_candidate_p (rtx_insn *insn,
+				     auto_bitmap &zero_extend,
+				     auto_bitmap &zero_extend_multiple)
 {
   rtx def_set = pseudo_reg_set (insn);
 
@@ -2673,8 +2696,15 @@ timode_scalar_to_vector_candidate_p (rtx_insn *insn)
       return timode_concatdi_p (src);
 
     case ZERO_EXTEND:
-      return REG_P (XEXP (src, 0))
-	     && GET_MODE (XEXP (src, 0)) == DImode;
+      if (REG_P (XEXP (src, 0)) && GET_MODE (XEXP (src, 0)) == DImode)
+	{
+	  if (bitmap_bit_p (zero_extend, REGNO (XEXP (src, 0))))
+	    bitmap_set_bit (zero_extend_multiple, REGNO (XEXP (src, 0)));
+	  else
+	    bitmap_set_bit (zero_extend, REGNO (XEXP (src, 0)));
+	  return true;
+	}
+      /* Fallthru.  */
 
     default:
       return false;
@@ -2820,6 +2850,10 @@ convert_scalars_to_vector (bool timode_p)
   df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
   df_analyze ();
 
+  /* Track zero-extended DImode registers.  */
+  auto_bitmap zero_extend;
+  auto_bitmap zero_extend_multiple;
+
   /* Find all instructions we want to convert into vector mode.  */
   if (dump_file)
     fprintf (dump_file, "Searching for mode conversion candidates...\n");
@@ -2829,7 +2863,9 @@ convert_scalars_to_vector (bool timode_p)
       rtx_insn *insn;
       FOR_BB_INSNS (bb, insn)
 	if (timode_p
-	    && timode_scalar_to_vector_candidate_p (insn))
+	    && timode_scalar_to_vector_candidate_p (insn,
+						    zero_extend,
+						    zero_extend_multiple))
 	  {
 	    if (dump_file)
 	      fprintf (dump_file, "  insn %d is marked as a TImode candidate\n",
@@ -2881,7 +2917,7 @@ convert_scalars_to_vector (bool timode_p)
 	     conversions.  */
 	  if (chain->build (&candidates[i], uid, disallowed))
 	    {
-	      if (chain->compute_convert_gain ())
+	      if (chain->compute_convert_gain (zero_extend_multiple))
 		converted_insns += chain->convert ();
 	      else if (dump_file)
 		fprintf (dump_file, "Chain #%d conversion is not profitable\n",
diff --git a/gcc/config/i386/i386-features.h b/gcc/config/i386/i386-features.h
index febcf62e72d..5949522ad6c 100644
--- a/gcc/config/i386/i386-features.h
+++ b/gcc/config/i386/i386-features.h
@@ -159,7 +159,7 @@ class scalar_chain
   auto_vec<rtx_insn *> control_flow_insns;
 
   bool build (bitmap candidates, unsigned insn_uid, bitmap disallowed);
-  virtual bool compute_convert_gain () = 0;
+  virtual bool compute_convert_gain (auto_bitmap &) = 0;
   int convert ();
 
  protected:
@@ -185,7 +185,7 @@ class general_scalar_chain : public scalar_chain
  public:
   general_scalar_chain (enum machine_mode smode_, enum machine_mode vmode_)
     : scalar_chain (smode_, vmode_) {}
-  bool compute_convert_gain () final override;
+  bool compute_convert_gain (auto_bitmap &) final override;
 
  private:
   void convert_insn (rtx_insn *insn) final override;
@@ -197,7 +197,7 @@ class timode_scalar_chain : public scalar_chain
 {
  public:
   timode_scalar_chain () : scalar_chain (TImode, V1TImode) {}
-  bool compute_convert_gain () final override;
+  bool compute_convert_gain (auto_bitmap &) final override;
 
  private:
   void fix_debug_reg_uses (rtx reg);
diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-stv-15.c b/gcc/testsuite/gcc.target/i386/sse4_1-stv-15.c
new file mode 100644
index 00000000000..10a476555ab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse4_1-stv-15.c
@@ -0,0 +1,15 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2 -msse4.1 -mtune=cascadelake -mstv -mno-stackrealign" } */
+
+extern __int128 m0,m1,m2,m3;
+void
+foo (unsigned long x)
+{
+  __int128 m = x;
+  m0 = m;
+  m1 = m;
+  m2 = m;
+  m3 = m;
+}
+
+/* { dg-final { scan-assembler-times "(movaps|vmovdqa)" 4 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-stv-16.c b/gcc/testsuite/gcc.target/i386/sse4_1-stv-16.c
new file mode 100644
index 00000000000..b1561454ff3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse4_1-stv-16.c
@@ -0,0 +1,19 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2 -msse4.1 -mtune=cascadelake -mstv -mno-stackrealign" } */
+
+extern __int128 m0,m1,m2,m3;
+void
+foo (unsigned long x0, unsigned long x1, unsigned long x2,
+     unsigned long x3)
+{
+  __int128 i0 = x0;
+  m0 = i0;
+  __int128 i1 = x1;
+  m1 = i1;
+  __int128 i2 = x2;
+  m2 = i2;
+  __int128 i3 = x3;
+  m3 = i3;
+}
+
+/* { dg-final { scan-assembler-not "(movaps|vmovdqa)" } } */
-- 
2.55.0

Reply via email to