https://gcc.gnu.org/g:abaf4268958a49d7dfd5f0d36bdb65983582b9d5
commit r17-5244-gabaf4268958a49d7dfd5f0d36bdb65983582b9d5 Author: liuhongt <[email protected]> Date: Mon Oct 12 23:10:04 2026 -0700 i386: Fix double-word zero-extension cost [PR127020] 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. Co-authored-by: H.J. Lu <[email protected]> Diff: --- 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(-) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index c3548e5d65ae..0b29d9a4026a 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -23031,6 +23031,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 @@ -23038,7 +23048,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 000000000000..6a8eb43179d5 --- /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 000000000000..4adc17cfc4cb --- /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 } } */
