On Fri, Oct 16, 2026 at 2:25 AM liuhongt <[email protected]> wrote:
>
> > This can also handle 32-bit targets with:
> >
> > else if (speed && GET_MODE_SIZE (mode) > GET_MODE_SIZE (word_mode))
> > && ...
> > && GET_MODE (...) == word_mode.
> >
> > (the last check is also semi-redundant, there are no patterns that
> > zext from other modes than word mode, but won't hurt anyway)
> >
> > with a comment updated to something like:
> >
> > Zero extension to a double-word mode (TImode on x86-64, DImode on
> > ia32) is not a single movzx: the upper word must be cleared by a
> > separate instruction. Charge for it; a zero or too-low cost makes the
> > extension look free, so CSE copies the extended value into every
> > TImode store and STV can no longer share one vector register.
> >
> Changed, also updated cost for double-word sign_extend which needs an
> extra cdq.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
> Ok?
>
> The zero movzx cost in Skylake and Ice Lake tunings makes CSE duplicate
> double-word zero extensions into stores, preventing STV conversion.
>
> Use the add cost for standalone double-word zero extensions when
> optimizing for speed, since clearing the upper word requires an extra
> instruction.
>
> Similarly for double-word sign_extend, but cost it one more than
> zero_extend, so that when a value is known non-negative, zero_extend
> is preferred to sign_extend: zero_extend needs an extra xor, while
> sign_extend needs an extra cdq.
>
> gcc/ChangeLog:
>
>         PR target/127020
>         * config/i386/i386.cc (ix86_rtx_costs): Use the add cost for
>         standalone double-word zero extensions when optimizing for speed.
>         Cost standalone double-word sign extensions one more than that.
>
> gcc/testsuite/ChangeLog:
>
>         PR target/127020
>         * gcc.target/i386/pr127020.c: New test.
>         * gcc.target/i386/pr127020-2.c: New test.

OK.

Thanks,
Uros.

>
> Co-authored-by: H.J. Lu <[email protected]>
> ---
>  gcc/config/i386/i386.cc                    | 21 ++++++++++++-
>  gcc/testsuite/gcc.target/i386/pr127020-2.c | 34 ++++++++++++++++++++++
>  gcc/testsuite/gcc.target/i386/pr127020.c   | 16 ++++++++++
>  3 files changed, 70 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr127020-2.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr127020.c
>
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index a8edf28f687..e299fadde8b 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -22982,6 +22982,16 @@ ix86_rtx_costs (rtx x, machine_mode mode, int 
> outer_code_i, int opno,
>        if (TARGET_64BIT && mode == DImode
>           && GET_MODE (XEXP (x, 0)) == SImode)
>         *total = 1;
> +      /* Zero extension to a double-word mode (TImode on x86-64, DImode
> +        on ia32) is not a single movzx: the upper word must be cleared
> +        by a separate instruction.  Charge for it; a zero or too-low
> +        cost makes the extension look free, so CSE copies the extended
> +        value into every double-word store and STV can no longer share
> +        one vector register.  */
> +      else if (speed && GET_MODE_SIZE (mode) > UNITS_PER_WORD
> +              && outer_code == SET
> +              && GET_MODE (XEXP (x, 0)) == word_mode)
> +       *total = cost->add;
>        else if (TARGET_ZERO_EXTEND_WITH_AND)
>         *total = cost->add;
>        else
> @@ -22989,7 +22999,16 @@ ix86_rtx_costs (rtx x, machine_mode mode, int 
> outer_code_i, int opno,
>        return false;
>
>      case SIGN_EXTEND:
> -      *total = cost->movsx;
> +      /* Similarly to zero_extend for a double-word mode, but cost one
> +        more than zero_extend, so that when the sign bit is known to be
> +        zero, zero_extend is preferred to sign_extend: zero_extend needs
> +        an extra xor, while sign_extend needs an extra cdq.  */
> +      if (speed && GET_MODE_SIZE (mode) > UNITS_PER_WORD
> +         && outer_code == SET
> +         && GET_MODE (XEXP (x, 0)) == word_mode)
> +       *total = cost->add + 1;
> +      else
> +       *total = cost->movsx;
>        return false;
>
>      case ASHIFT:
> diff --git a/gcc/testsuite/gcc.target/i386/pr127020-2.c 
> b/gcc/testsuite/gcc.target/i386/pr127020-2.c
> new file mode 100644
> index 00000000000..6a8eb43179d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr127020-2.c
> @@ -0,0 +1,34 @@
> +/* PR target/127020 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mtune=cascadelake" } */
> +
> +/* The source is known to be nonnegative, so expand can use either a
> +   zero or a sign extension.  The zero extension only needs an xor, so
> +   the sign extension must cost more, or a tie makes expand choose
> +   cltd/cqto/sar.  */
> +
> +#ifdef __x86_64__
> +#define HALF long long
> +#define DWORD __int128
> +#define MASK __LONG_LONG_MAX__
> +#else
> +#define HALF int
> +#define DWORD long long
> +#define MASK __INT_MAX__
> +#endif
> +
> +DWORD g;
> +
> +DWORD
> +foo (HALF x)
> +{
> +  return x & MASK;
> +}
> +
> +void
> +bar (HALF x)
> +{
> +  g = x & MASK;
> +}
> +
> +/* { dg-final { scan-assembler-not "cltd|cqto|sar\[lq\]" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr127020.c 
> b/gcc/testsuite/gcc.target/i386/pr127020.c
> new file mode 100644
> index 00000000000..4adc17cfc4c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr127020.c
> @@ -0,0 +1,16 @@
> +/* PR target/127020 */
> +/* { 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)
> +{
> +  m0 = x;
> +  m1 = x;
> +  m2 = x;
> +  m3 = x;
> +}
> +
> +/* { dg-final { scan-assembler-times "(movaps|vmovdqa)" 4 } } */
> --
> 2.34.1
>

Reply via email to