On Tue, Sep 29, 2026 at 1:21 PM Richard Biener <[email protected]> wrote:
>
> For the testcase in PR127633 we combine two adjacent DFmode loads from
> the stack into a V2DFmode via a peephole2 that uses adjust_address.
> That unfortunately leaves both the MEM_EXPR and the MEM_ALIAS_SET
> unaltered causing later scheduling to move the widened load before
> the store. The fix is to instead use widen_memory_access which
> attempts to fixup MEM_EXPR and resets MEM_ALIAS_SET.
>
> To avoid regressing gcc.target/i386/sse{2,4_1}-init-v2df-2.c where
> ix86_split_stlf_stall_load splitted a V2DF load from a parameter
> but this being no longer visible with a cleared MEM_EXPR this
> adjusts ix86_operands_ok_for_move_multiple instead to avoid
> merging two loads from different parameters, not only those
> that ix86_split_stlf_stall_load handles.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
>
> OK?
LGTM, but please move the testcase to gcc.target/i386.
Converting a negative double to unsigned is UB. On x86 it happens to
wrap through cvttsd2si, but aarch64's fcvtzu saturates to 0, so the
hard-coded 0xfff97f7f will fail on other targets.
Thanks,
Uros.
> Thanks,
> Richard.
>
> PR target/127633
> * config/i386/sse.md (movsd/movhpd to movupd): Use
> widen_memory_access instead of adjust_address to merge
> the MEMs.
> * config/i386/i386.cc (ix86_operands_ok_for_move_multiple):
> Avoid merging loads from different parameters.
>
> * gcc.dg/pr127633.c: New testcase.
> * gcc.target/i386/sse2-init-v2df-2.c: Adjust.
> * gcc.target/i386/sse4_1-init-v2df-2.c: Likewise.
> ---
> gcc/config/i386/i386.cc | 9 +++
> gcc/config/i386/sse.md | 6 +-
> gcc/testsuite/gcc.dg/pr127633.c | 68 +++++++++++++++++++
> .../gcc.target/i386/sse2-init-v2df-2.c | 4 +-
> .../gcc.target/i386/sse4_1-init-v2df-2.c | 4 +-
> 5 files changed, 84 insertions(+), 7 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/pr127633.c
>
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index b09a5077820..74a6b39856f 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -28079,6 +28079,15 @@ ix86_operands_ok_for_move_multiple (rtx *operands,
> bool load,
> {
> mem_1 = operands[1];
> mem_2 = operands[3];
> + /* Avoid fusing two loads from distinct parameters as that might
> + cause STLF failure. */
> + tree base_1;
> + if (MEM_EXPR (mem_1)
> + && MEM_EXPR (mem_2)
> + && (TREE_CODE (base_1 = get_base_address (MEM_EXPR (mem_1)))
> + == PARM_DECL)
> + && get_base_address (MEM_EXPR (mem_2)) != base_1)
> + return false;
> reg_1 = operands[0];
> reg_2 = operands[2];
> }
> diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
> index 0ce82789dc6..2b6d7de1f7f 100644
> --- a/gcc/config/i386/sse.md
> +++ b/gcc/config/i386/sse.md
> @@ -2021,7 +2021,7 @@
> "TARGET_SSE2 && TARGET_SSE_UNALIGNED_LOAD_OPTIMAL
> && ix86_operands_ok_for_move_multiple (operands, true, DFmode)"
> [(set (match_dup 2) (match_dup 5))]
> - "operands[5] = adjust_address (operands[1], V2DFmode, 0);")
> + "operands[5] = widen_memory_access (operands[1], V2DFmode, 0);")
>
> (define_peephole2
> [(set (match_operand:DF 0 "sse_reg_operand")
> @@ -2033,7 +2033,7 @@
> && REGNO (operands[4]) == REGNO (operands[2])
> && ix86_operands_ok_for_move_multiple (operands, true, DFmode)"
> [(set (match_dup 2) (match_dup 5))]
> - "operands[5] = adjust_address (operands[1], V2DFmode, 0);")
> + "operands[5] = widen_memory_access (operands[1], V2DFmode, 0);")
>
> ;; Merge movlpd/movhpd to movupd for TARGET_SSE_UNALIGNED_STORE_OPTIMAL
> targets.
> (define_peephole2
> @@ -2046,7 +2046,7 @@
> "TARGET_SSE2 && TARGET_SSE_UNALIGNED_STORE_OPTIMAL
> && ix86_operands_ok_for_move_multiple (operands, false, DFmode)"
> [(set (match_dup 4) (match_dup 1))]
> - "operands[4] = adjust_address (operands[0], V2DFmode, 0);")
> + "operands[4] = widen_memory_access (operands[0], V2DFmode, 0);")
>
> (define_insn "<sse3>_lddqu<avxsizesuffix>"
> [(set (match_operand:VI1 0 "register_operand" "=x,x")
> diff --git a/gcc/testsuite/gcc.dg/pr127633.c b/gcc/testsuite/gcc.dg/pr127633.c
> new file mode 100644
> index 00000000000..500e84f66ff
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr127633.c
> @@ -0,0 +1,68 @@
> +/* { dg-do run } */
> +/* { dg-require-effective-target int32plus } */
> +/* { dg-options "-O3 -funroll-all-loops -fno-vect-cost-model" } */
> +
> +int d, ab = -104, ac, ad = -170, ae = -51, af = -151, ag = -1966532803, ah,
> ai,
> + aj, ak, al, am, an, *ao, v, ap, aq;
> +short w, y, z, ar, as, at, au, av, aw, ax = -156, ay, az, ba;
> +long bb = -38, bc, bd, be, bf;
> +double bg, bh, *bi;
> +char bj;
> +int a(unsigned bk, unsigned bl) {
> + return bk^bl;
> +}
> +[[gnu::noinline,gnu::noclone]]
> +int aa(short bn) {
> + return bn;
> +}
> +[[gnu::noinline,gnu::noclone]]
> +int s(long bk, short bl, short bm, long bn, int bo, short bp, int bq) {
> + int bt, bu = aa(-1);
> + double bv, bw, *by, *bz, **ca;
> + __attribute__((__vector_size__(8 * sizeof(double)))) double cb;
> + cb[4] = 1.75;
> + cb[5] = -8.0;
> + cb[7] = 1.75;
> + ca = &by;
> + bt = bu;
> + bv = -65536;
> + bz = &bw;
> + cb[2] = 0 + (bm ? -8.0 : bg);
> + if (-bl >= 0) {
> + if (bm)
> + goto bx;
> + ca = &bz;
> + }
> + cb[3] = 524420 + bt;
> + az = bl - (1646 ^ bl);
> + bw = 2.0 * bv;
> + bv = 2.0 * bw;
> + *ca = &bv;
> +bx:
> + cb[1] = -4.0 + 2.5 * bv;
> + bc = 267503909 - bn;
> + bi = *ca;
> + *by = 131072 - 5.0 * bw;
> + *bz = 3.0 * bg + 0.375 * bv;
> + ay = ba = bl + 15 * az;
> + bj = -__builtin_popcount((unsigned char)(109 + az));
> + an = 0;
> +
> + an = a(an, cb[1]);
> + an = a(an, cb[2]);
> + an = a(an, cb[3]);
> + an = a(an, cb[4]);
> + an = a(an, cb[5]);
> + an = a(an, cb[7]);
> +
> + an = a(an, bw);
> + an = an^(int)bg;
> + return an;
> +}
> +int main() {
> + am = s(1, 1, 1, 1, 3, 1, 1);
> + al = am;
> + if (al != 0xfff97f7f)
> + __builtin_abort ();
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
> b/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
> index 3f58098af8d..17131422939 100644
> --- a/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
> +++ b/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
> @@ -15,9 +15,9 @@ v2df f0m() { return (v2df){ 0.0, m }; }
> v2df fmm() { return (v2df){ m, m }; }
> v2df fmn() { return (v2df){ m, n }; }
>
> -/* { dg-final { scan-assembler-times "movq" 5 } } */
> +/* { dg-final { scan-assembler-times "movq" 4 } } */
> /* { dg-final { scan-assembler-times "pslldq" 2 } } */
> /* { dg-final { scan-assembler-times "unpcklpd" 2 } } */
> -/* { dg-final { scan-assembler-times "movsd" 3 } } */
> +/* { dg-final { scan-assembler-times "movsd" 4 } } */
> /* { dg-final { scan-assembler-times "movhpd" 2 } } */
>
> diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-init-v2df-2.c
> b/gcc/testsuite/gcc.target/i386/sse4_1-init-v2df-2.c
> index 218cc8bf896..f1d8e8367aa 100644
> --- a/gcc/testsuite/gcc.target/i386/sse4_1-init-v2df-2.c
> +++ b/gcc/testsuite/gcc.target/i386/sse4_1-init-v2df-2.c
> @@ -15,9 +15,9 @@ v2df f0m() { return (v2df){ 0.0, m }; }
> v2df fmm() { return (v2df){ m, m }; }
> v2df fmn() { return (v2df){ m, n }; }
>
> -/* { dg-final { scan-assembler-times "movq" 5 } } */
> +/* { dg-final { scan-assembler-times "movq" 4 } } */
> /* { dg-final { scan-assembler-times "pslldq" 2 } } */
> /* { dg-final { scan-assembler-times "movddup" 2 } } */
> -/* { dg-final { scan-assembler-times "movsd" 1 } } */
> +/* { dg-final { scan-assembler-times "movsd" 2 } } */
> /* { dg-final { scan-assembler-times "movhpd" 2 } } */
>
> --
> 2.51.0