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