[v2] x86: Add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO

Message ID Yg5UEedj2AO/loc9@gmail.com
State New
Headers
Series [v2] x86: Add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO |

Commit Message

H.J. Lu Feb. 17, 2022, 1:56 p.m. UTC
  On Thu, Feb 17, 2022 at 08:51:31AM +0100, Uros Bizjak wrote:
> On Thu, Feb 17, 2022 at 6:25 AM Hongtao Liu via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > On Thu, Feb 17, 2022 at 12:26 PM H.J. Lu via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > > transition penalty.  Add TARGET_READ_ZERO_YMM_ZMM_NEED_VZEROUPPER to
> > > generate vzeroupper instruction after loading all-zero YMM/YMM registers
> > > and enable it by default.
> > Shouldn't TARGET_READ_ZERO_YMM_ZMM_NONEED_VZEROUPPER sounds a bit smoother?
> > Because originally we needed to add vzeroupper to all avx<->sse cases,
> > now it's a tune to indicate that we don't need to add it in some
> 
> Perhaps we should go from the other side and use
> X86_TUNE_OPTIMIZE_AVX_READ for new processors?
> 

Here is the v2 patch to add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.


H.J.
---
Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
transition penalty.  Add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO to
omit vzeroupper instruction after loading all-zero YMM/ZMM registers.

gcc/

	PR target/101456
	* config/i386/i386.cc (ix86_avx_u128_mode_needed): Omit
	vzeroupper after reading all-zero YMM/ZMM registers for
	TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
	* config/i386/i386.h (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO):
	New.
	* config/i386/x86-tune.def
	(X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO): New.

gcc/testsuite/

	PR target/101456
	* gcc.target/i386/pr101456-1.c (dg-options): Add
	-mtune-ctrl=-mtune-ctrl=omit_vzeroupper_after_avx_read_zero.
	* gcc.target/i386/pr101456-2.c: Likewise.
	* gcc.target/i386/pr101456-3.c: New test.
	* gcc.target/i386/pr101456-4.c: Likewise.
---
 gcc/config/i386/i386.cc                    | 51 ++++++++++++----------
 gcc/config/i386/i386.h                     |  2 +
 gcc/config/i386/x86-tune.def               |  5 +++
 gcc/testsuite/gcc.target/i386/pr101456-1.c |  2 +-
 gcc/testsuite/gcc.target/i386/pr101456-2.c |  2 +-
 gcc/testsuite/gcc.target/i386/pr101456-3.c | 33 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr101456-4.c | 33 ++++++++++++++
 7 files changed, 103 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-4.c
  

Comments

Hongtao Liu Feb. 21, 2022, 2:01 a.m. UTC | #1
On Thu, Feb 17, 2022 at 9:56 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Thu, Feb 17, 2022 at 08:51:31AM +0100, Uros Bizjak wrote:
> > On Thu, Feb 17, 2022 at 6:25 AM Hongtao Liu via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > > On Thu, Feb 17, 2022 at 12:26 PM H.J. Lu via Gcc-patches
> > > <gcc-patches@gcc.gnu.org> wrote:
> > > >
> > > > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > > > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > > > transition penalty.  Add TARGET_READ_ZERO_YMM_ZMM_NEED_VZEROUPPER to
> > > > generate vzeroupper instruction after loading all-zero YMM/YMM registers
> > > > and enable it by default.
> > > Shouldn't TARGET_READ_ZERO_YMM_ZMM_NONEED_VZEROUPPER sounds a bit smoother?
> > > Because originally we needed to add vzeroupper to all avx<->sse cases,
> > > now it's a tune to indicate that we don't need to add it in some
> >
> > Perhaps we should go from the other side and use
> > X86_TUNE_OPTIMIZE_AVX_READ for new processors?
> >
>
> Here is the v2 patch to add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
>
The patch LGTM in general, but please rebase against
https://gcc.gnu.org/pipermail/gcc-patches/2022-February/590541.html
and resend the patch, also wait a couple days in case Uros(and others)
have any comments.
>
> H.J.
> ---
> Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> transition penalty.  Add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO to
> omit vzeroupper instruction after loading all-zero YMM/ZMM registers.
>
> gcc/
>
>         PR target/101456
>         * config/i386/i386.cc (ix86_avx_u128_mode_needed): Omit
>         vzeroupper after reading all-zero YMM/ZMM registers for
>         TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
>         * config/i386/i386.h (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO):
>         New.
>         * config/i386/x86-tune.def
>         (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO): New.
>
> gcc/testsuite/
>
>         PR target/101456
>         * gcc.target/i386/pr101456-1.c (dg-options): Add
>         -mtune-ctrl=-mtune-ctrl=omit_vzeroupper_after_avx_read_zero.
>         * gcc.target/i386/pr101456-2.c: Likewise.
>         * gcc.target/i386/pr101456-3.c: New test.
>         * gcc.target/i386/pr101456-4.c: Likewise.
> ---
>  gcc/config/i386/i386.cc                    | 51 ++++++++++++----------
>  gcc/config/i386/i386.h                     |  2 +
>  gcc/config/i386/x86-tune.def               |  5 +++
>  gcc/testsuite/gcc.target/i386/pr101456-1.c |  2 +-
>  gcc/testsuite/gcc.target/i386/pr101456-2.c |  2 +-
>  gcc/testsuite/gcc.target/i386/pr101456-3.c | 33 ++++++++++++++
>  gcc/testsuite/gcc.target/i386/pr101456-4.c | 33 ++++++++++++++
>  7 files changed, 103 insertions(+), 25 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-3.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-4.c
>
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index cf246e74e57..60c72ceb72d 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -14502,33 +14502,38 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
>
>    subrtx_iterator::array_type array;
>
> -  rtx set = single_set (insn);
> -  if (set)
> +  if (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO)
>      {
> -      rtx dest = SET_DEST (set);
> -      rtx src = SET_SRC (set);
> -      if (ix86_check_avx_upper_register (dest))
> +      /* Perform this vzeroupper optimization if target doesn't need
> +        vzeroupper after reading all-zero YMM/YMM registers.  */
> +      rtx set = single_set (insn);
> +      if (set)
>         {
> -         /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> -            source isn't zero.  */
> -         if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> -           return AVX_U128_DIRTY;
> +         rtx dest = SET_DEST (set);
> +         rtx src = SET_SRC (set);
> +         if (ix86_check_avx_upper_register (dest))
> +           {
> +             /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> +                source isn't zero.  */
> +             if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> +               return AVX_U128_DIRTY;
> +             else
> +               return AVX_U128_ANY;
> +           }
>           else
> -           return AVX_U128_ANY;
> -       }
> -      else
> -       {
> -         FOR_EACH_SUBRTX (iter, array, src, NONCONST)
> -           if (ix86_check_avx_upper_register (*iter))
> -             {
> -               int status = ix86_avx_u128_mode_source (insn, *iter);
> -               if (status == AVX_U128_DIRTY)
> -                 return status;
> -             }
> -       }
> +           {
> +             FOR_EACH_SUBRTX (iter, array, src, NONCONST)
> +               if (ix86_check_avx_upper_register (*iter))
> +                 {
> +                   int status = ix86_avx_u128_mode_source (insn, *iter);
> +                   if (status == AVX_U128_DIRTY)
> +                     return status;
> +                 }
> +           }
>
> -      /* This isn't YMM/ZMM load/store.  */
> -      return AVX_U128_ANY;
> +         /* This isn't YMM/ZMM load/store.  */
> +         return AVX_U128_ANY;
> +       }
>      }
>
>    /* Require DIRTY mode if a 256bit or 512bit AVX register is referenced.
> diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
> index f41e0908250..46379d2231b 100644
> --- a/gcc/config/i386/i386.h
> +++ b/gcc/config/i386/i386.h
> @@ -425,6 +425,8 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST];
>  #define TARGET_AVOID_MFENCE ix86_tune_features[X86_TUNE_AVOID_MFENCE]
>  #define TARGET_EMIT_VZEROUPPER \
>         ix86_tune_features[X86_TUNE_EMIT_VZEROUPPER]
> +#define TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO \
> +       ix86_tune_features[X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO]
>  #define TARGET_EXPAND_ABS \
>         ix86_tune_features[X86_TUNE_EXPAND_ABS]
>  #define TARGET_V2DF_REDUCTION_PREFER_HADDPD \
> diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
> index 82ca0ae63ac..132de2db2eb 100644
> --- a/gcc/config/i386/x86-tune.def
> +++ b/gcc/config/i386/x86-tune.def
> @@ -649,3 +649,8 @@ DEF_TUNE (X86_TUNE_PROMOTE_QI_REGS, "promote_qi_regs", m_NONE)
>  /* X86_TUNE_EMIT_VZEROUPPER: This enables vzeroupper instruction insertion
>     before a transfer of control flow out of the function.  */
>  DEF_TUNE (X86_TUNE_EMIT_VZEROUPPER, "emit_vzeroupper", ~m_KNL)
> +
> +/* X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO: This omits vzeroupper
> +   instruction after reading all-zero YMM/ZMM registers.  */
> +DEF_TUNE (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO,
> +         "omit_vzeroupper_after_avx_read_zero", 0)
> diff --git a/gcc/testsuite/gcc.target/i386/pr101456-1.c b/gcc/testsuite/gcc.target/i386/pr101456-1.c
> index 803fc6e0207..f653197da7c 100644
> --- a/gcc/testsuite/gcc.target/i386/pr101456-1.c
> +++ b/gcc/testsuite/gcc.target/i386/pr101456-1.c
> @@ -1,5 +1,5 @@
>  /* { dg-do compile } */
> -/* { dg-options "-O2 -march=skylake" } */
> +/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
>
>  #include <x86intrin.h>
>
> diff --git a/gcc/testsuite/gcc.target/i386/pr101456-2.c b/gcc/testsuite/gcc.target/i386/pr101456-2.c
> index 554a0f1702c..9aac3ece14d 100644
> --- a/gcc/testsuite/gcc.target/i386/pr101456-2.c
> +++ b/gcc/testsuite/gcc.target/i386/pr101456-2.c
> @@ -1,5 +1,5 @@
>  /* { dg-do compile } */
> -/* { dg-options "-O2 -march=skylake" } */
> +/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
>
>  #include <x86intrin.h>
>
> diff --git a/gcc/testsuite/gcc.target/i386/pr101456-3.c b/gcc/testsuite/gcc.target/i386/pr101456-3.c
> new file mode 100644
> index 00000000000..8389d18ed6c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr101456-3.c
> @@ -0,0 +1,33 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -march=skylake -mtune=alderlake" } */
> +
> +#include <x86intrin.h>
> +
> +extern __m256 x1;
> +extern __m256d x2;
> +extern __m256i x3;
> +
> +extern void bar (void);
> +
> +void
> +foo1 (void)
> +{
> +  x1 = _mm256_setzero_ps ();
> +  bar ();
> +}
> +
> +void
> +foo2 (void)
> +{
> +  x2 = _mm256_setzero_pd ();
> +  bar ();
> +}
> +
> +void
> +foo3 (void)
> +{
> +  x3 = _mm256_setzero_si256 ();
> +  bar ();
> +}
> +
> +/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr101456-4.c b/gcc/testsuite/gcc.target/i386/pr101456-4.c
> new file mode 100644
> index 00000000000..3e4cdcc4d28
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr101456-4.c
> @@ -0,0 +1,33 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -march=haswell" } */
> +
> +#include <x86intrin.h>
> +
> +extern __m256 x1;
> +extern __m256d x2;
> +extern __m256i x3;
> +
> +extern void bar (void);
> +
> +void
> +foo1 (void)
> +{
> +  x1 = _mm256_setzero_ps ();
> +  bar ();
> +}
> +
> +void
> +foo2 (void)
> +{
> +  x2 = _mm256_setzero_pd ();
> +  bar ();
> +}
> +
> +void
> +foo3 (void)
> +{
> +  x3 = _mm256_setzero_si256 ();
> +  bar ();
> +}
> +
> +/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
> --
> 2.35.1
>
  
H.J. Lu Feb. 21, 2022, 6:35 p.m. UTC | #2
On Sun, Feb 20, 2022 at 6:01 PM Hongtao Liu <crazylht@gmail.com> wrote:
>
> On Thu, Feb 17, 2022 at 9:56 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Thu, Feb 17, 2022 at 08:51:31AM +0100, Uros Bizjak wrote:
> > > On Thu, Feb 17, 2022 at 6:25 AM Hongtao Liu via Gcc-patches
> > > <gcc-patches@gcc.gnu.org> wrote:
> > > >
> > > > On Thu, Feb 17, 2022 at 12:26 PM H.J. Lu via Gcc-patches
> > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > >
> > > > > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > > > > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > > > > transition penalty.  Add TARGET_READ_ZERO_YMM_ZMM_NEED_VZEROUPPER to
> > > > > generate vzeroupper instruction after loading all-zero YMM/YMM registers
> > > > > and enable it by default.
> > > > Shouldn't TARGET_READ_ZERO_YMM_ZMM_NONEED_VZEROUPPER sounds a bit smoother?
> > > > Because originally we needed to add vzeroupper to all avx<->sse cases,
> > > > now it's a tune to indicate that we don't need to add it in some
> > >
> > > Perhaps we should go from the other side and use
> > > X86_TUNE_OPTIMIZE_AVX_READ for new processors?
> > >
> >
> > Here is the v2 patch to add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
> >
> The patch LGTM in general, but please rebase against
> https://gcc.gnu.org/pipermail/gcc-patches/2022-February/590541.html
> and resend the patch, also wait a couple days in case Uros(and others)
> have any comments.

I am dropping my patch since it causes the compile-time regression.

> >
> > H.J.
> > ---
> > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > transition penalty.  Add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO to
> > omit vzeroupper instruction after loading all-zero YMM/ZMM registers.
> >
> > gcc/
> >
> >         PR target/101456
> >         * config/i386/i386.cc (ix86_avx_u128_mode_needed): Omit
> >         vzeroupper after reading all-zero YMM/ZMM registers for
> >         TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
> >         * config/i386/i386.h (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO):
> >         New.
> >         * config/i386/x86-tune.def
> >         (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO): New.
> >
> > gcc/testsuite/
> >
> >         PR target/101456
> >         * gcc.target/i386/pr101456-1.c (dg-options): Add
> >         -mtune-ctrl=-mtune-ctrl=omit_vzeroupper_after_avx_read_zero.
> >         * gcc.target/i386/pr101456-2.c: Likewise.
> >         * gcc.target/i386/pr101456-3.c: New test.
> >         * gcc.target/i386/pr101456-4.c: Likewise.
> > ---
> >  gcc/config/i386/i386.cc                    | 51 ++++++++++++----------
> >  gcc/config/i386/i386.h                     |  2 +
> >  gcc/config/i386/x86-tune.def               |  5 +++
> >  gcc/testsuite/gcc.target/i386/pr101456-1.c |  2 +-
> >  gcc/testsuite/gcc.target/i386/pr101456-2.c |  2 +-
> >  gcc/testsuite/gcc.target/i386/pr101456-3.c | 33 ++++++++++++++
> >  gcc/testsuite/gcc.target/i386/pr101456-4.c | 33 ++++++++++++++
> >  7 files changed, 103 insertions(+), 25 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-3.c
> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-4.c
> >
> > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > index cf246e74e57..60c72ceb72d 100644
> > --- a/gcc/config/i386/i386.cc
> > +++ b/gcc/config/i386/i386.cc
> > @@ -14502,33 +14502,38 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
> >
> >    subrtx_iterator::array_type array;
> >
> > -  rtx set = single_set (insn);
> > -  if (set)
> > +  if (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO)
> >      {
> > -      rtx dest = SET_DEST (set);
> > -      rtx src = SET_SRC (set);
> > -      if (ix86_check_avx_upper_register (dest))
> > +      /* Perform this vzeroupper optimization if target doesn't need
> > +        vzeroupper after reading all-zero YMM/YMM registers.  */
> > +      rtx set = single_set (insn);
> > +      if (set)
> >         {
> > -         /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> > -            source isn't zero.  */
> > -         if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> > -           return AVX_U128_DIRTY;
> > +         rtx dest = SET_DEST (set);
> > +         rtx src = SET_SRC (set);
> > +         if (ix86_check_avx_upper_register (dest))
> > +           {
> > +             /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> > +                source isn't zero.  */
> > +             if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> > +               return AVX_U128_DIRTY;
> > +             else
> > +               return AVX_U128_ANY;
> > +           }
> >           else
> > -           return AVX_U128_ANY;
> > -       }
> > -      else
> > -       {
> > -         FOR_EACH_SUBRTX (iter, array, src, NONCONST)
> > -           if (ix86_check_avx_upper_register (*iter))
> > -             {
> > -               int status = ix86_avx_u128_mode_source (insn, *iter);
> > -               if (status == AVX_U128_DIRTY)
> > -                 return status;
> > -             }
> > -       }
> > +           {
> > +             FOR_EACH_SUBRTX (iter, array, src, NONCONST)
> > +               if (ix86_check_avx_upper_register (*iter))
> > +                 {
> > +                   int status = ix86_avx_u128_mode_source (insn, *iter);
> > +                   if (status == AVX_U128_DIRTY)
> > +                     return status;
> > +                 }
> > +           }
> >
> > -      /* This isn't YMM/ZMM load/store.  */
> > -      return AVX_U128_ANY;
> > +         /* This isn't YMM/ZMM load/store.  */
> > +         return AVX_U128_ANY;
> > +       }
> >      }
> >
> >    /* Require DIRTY mode if a 256bit or 512bit AVX register is referenced.
> > diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
> > index f41e0908250..46379d2231b 100644
> > --- a/gcc/config/i386/i386.h
> > +++ b/gcc/config/i386/i386.h
> > @@ -425,6 +425,8 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST];
> >  #define TARGET_AVOID_MFENCE ix86_tune_features[X86_TUNE_AVOID_MFENCE]
> >  #define TARGET_EMIT_VZEROUPPER \
> >         ix86_tune_features[X86_TUNE_EMIT_VZEROUPPER]
> > +#define TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO \
> > +       ix86_tune_features[X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO]
> >  #define TARGET_EXPAND_ABS \
> >         ix86_tune_features[X86_TUNE_EXPAND_ABS]
> >  #define TARGET_V2DF_REDUCTION_PREFER_HADDPD \
> > diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
> > index 82ca0ae63ac..132de2db2eb 100644
> > --- a/gcc/config/i386/x86-tune.def
> > +++ b/gcc/config/i386/x86-tune.def
> > @@ -649,3 +649,8 @@ DEF_TUNE (X86_TUNE_PROMOTE_QI_REGS, "promote_qi_regs", m_NONE)
> >  /* X86_TUNE_EMIT_VZEROUPPER: This enables vzeroupper instruction insertion
> >     before a transfer of control flow out of the function.  */
> >  DEF_TUNE (X86_TUNE_EMIT_VZEROUPPER, "emit_vzeroupper", ~m_KNL)
> > +
> > +/* X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO: This omits vzeroupper
> > +   instruction after reading all-zero YMM/ZMM registers.  */
> > +DEF_TUNE (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO,
> > +         "omit_vzeroupper_after_avx_read_zero", 0)
> > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-1.c b/gcc/testsuite/gcc.target/i386/pr101456-1.c
> > index 803fc6e0207..f653197da7c 100644
> > --- a/gcc/testsuite/gcc.target/i386/pr101456-1.c
> > +++ b/gcc/testsuite/gcc.target/i386/pr101456-1.c
> > @@ -1,5 +1,5 @@
> >  /* { dg-do compile } */
> > -/* { dg-options "-O2 -march=skylake" } */
> > +/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
> >
> >  #include <x86intrin.h>
> >
> > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-2.c b/gcc/testsuite/gcc.target/i386/pr101456-2.c
> > index 554a0f1702c..9aac3ece14d 100644
> > --- a/gcc/testsuite/gcc.target/i386/pr101456-2.c
> > +++ b/gcc/testsuite/gcc.target/i386/pr101456-2.c
> > @@ -1,5 +1,5 @@
> >  /* { dg-do compile } */
> > -/* { dg-options "-O2 -march=skylake" } */
> > +/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
> >
> >  #include <x86intrin.h>
> >
> > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-3.c b/gcc/testsuite/gcc.target/i386/pr101456-3.c
> > new file mode 100644
> > index 00000000000..8389d18ed6c
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr101456-3.c
> > @@ -0,0 +1,33 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -march=skylake -mtune=alderlake" } */
> > +
> > +#include <x86intrin.h>
> > +
> > +extern __m256 x1;
> > +extern __m256d x2;
> > +extern __m256i x3;
> > +
> > +extern void bar (void);
> > +
> > +void
> > +foo1 (void)
> > +{
> > +  x1 = _mm256_setzero_ps ();
> > +  bar ();
> > +}
> > +
> > +void
> > +foo2 (void)
> > +{
> > +  x2 = _mm256_setzero_pd ();
> > +  bar ();
> > +}
> > +
> > +void
> > +foo3 (void)
> > +{
> > +  x3 = _mm256_setzero_si256 ();
> > +  bar ();
> > +}
> > +
> > +/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
> > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-4.c b/gcc/testsuite/gcc.target/i386/pr101456-4.c
> > new file mode 100644
> > index 00000000000..3e4cdcc4d28
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr101456-4.c
> > @@ -0,0 +1,33 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -march=haswell" } */
> > +
> > +#include <x86intrin.h>
> > +
> > +extern __m256 x1;
> > +extern __m256d x2;
> > +extern __m256i x3;
> > +
> > +extern void bar (void);
> > +
> > +void
> > +foo1 (void)
> > +{
> > +  x1 = _mm256_setzero_ps ();
> > +  bar ();
> > +}
> > +
> > +void
> > +foo2 (void)
> > +{
> > +  x2 = _mm256_setzero_pd ();
> > +  bar ();
> > +}
> > +
> > +void
> > +foo3 (void)
> > +{
> > +  x3 = _mm256_setzero_si256 ();
> > +  bar ();
> > +}
> > +
> > +/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
> > --
> > 2.35.1
> >
>
>
> --
> BR,
> Hongtao
  
Hongtao Liu Feb. 22, 2022, 2:43 a.m. UTC | #3
On Tue, Feb 22, 2022 at 2:35 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Sun, Feb 20, 2022 at 6:01 PM Hongtao Liu <crazylht@gmail.com> wrote:
> >
> > On Thu, Feb 17, 2022 at 9:56 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > On Thu, Feb 17, 2022 at 08:51:31AM +0100, Uros Bizjak wrote:
> > > > On Thu, Feb 17, 2022 at 6:25 AM Hongtao Liu via Gcc-patches
> > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > >
> > > > > On Thu, Feb 17, 2022 at 12:26 PM H.J. Lu via Gcc-patches
> > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > >
> > > > > > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > > > > > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > > > > > transition penalty.  Add TARGET_READ_ZERO_YMM_ZMM_NEED_VZEROUPPER to
> > > > > > generate vzeroupper instruction after loading all-zero YMM/YMM registers
> > > > > > and enable it by default.
> > > > > Shouldn't TARGET_READ_ZERO_YMM_ZMM_NONEED_VZEROUPPER sounds a bit smoother?
> > > > > Because originally we needed to add vzeroupper to all avx<->sse cases,
> > > > > now it's a tune to indicate that we don't need to add it in some
> > > >
> > > > Perhaps we should go from the other side and use
> > > > X86_TUNE_OPTIMIZE_AVX_READ for new processors?
> > > >
> > >
> > > Here is the v2 patch to add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
> > >
> > The patch LGTM in general, but please rebase against
> > https://gcc.gnu.org/pipermail/gcc-patches/2022-February/590541.html
> > and resend the patch, also wait a couple days in case Uros(and others)
> > have any comments.
>
> I am dropping my patch since it causes the compile-time regression.
I think only vextractif128 part is reverted, but we still have
vmovdqu(below) which should also cause penalty?
> > > +         if (ix86_check_avx_upper_register (dest))
> > > +           {
> > > +             /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> > > +                source isn't zero.  */
> > > +             if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> > > +               return AVX_U128_DIRTY;
> > > +             else
> > > +               return AVX_U128_ANY;
> > > +           }
>
> > >
> > > H.J.
> > > ---
> > > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > > transition penalty.  Add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO to
> > > omit vzeroupper instruction after loading all-zero YMM/ZMM registers.
> > >
> > > gcc/
> > >
> > >         PR target/101456
> > >         * config/i386/i386.cc (ix86_avx_u128_mode_needed): Omit
> > >         vzeroupper after reading all-zero YMM/ZMM registers for
> > >         TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
> > >         * config/i386/i386.h (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO):
> > >         New.
> > >         * config/i386/x86-tune.def
> > >         (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO): New.
> > >
> > > gcc/testsuite/
> > >
> > >         PR target/101456
> > >         * gcc.target/i386/pr101456-1.c (dg-options): Add
> > >         -mtune-ctrl=-mtune-ctrl=omit_vzeroupper_after_avx_read_zero.
> > >         * gcc.target/i386/pr101456-2.c: Likewise.
> > >         * gcc.target/i386/pr101456-3.c: New test.
> > >         * gcc.target/i386/pr101456-4.c: Likewise.
> > > ---
> > >  gcc/config/i386/i386.cc                    | 51 ++++++++++++----------
> > >  gcc/config/i386/i386.h                     |  2 +
> > >  gcc/config/i386/x86-tune.def               |  5 +++
> > >  gcc/testsuite/gcc.target/i386/pr101456-1.c |  2 +-
> > >  gcc/testsuite/gcc.target/i386/pr101456-2.c |  2 +-
> > >  gcc/testsuite/gcc.target/i386/pr101456-3.c | 33 ++++++++++++++
> > >  gcc/testsuite/gcc.target/i386/pr101456-4.c | 33 ++++++++++++++
> > >  7 files changed, 103 insertions(+), 25 deletions(-)
> > >  create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-3.c
> > >  create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-4.c
> > >
> > > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > > index cf246e74e57..60c72ceb72d 100644
> > > --- a/gcc/config/i386/i386.cc
> > > +++ b/gcc/config/i386/i386.cc
> > > @@ -14502,33 +14502,38 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
> > >
> > >    subrtx_iterator::array_type array;
> > >
> > > -  rtx set = single_set (insn);
> > > -  if (set)
> > > +  if (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO)
> > >      {
> > > -      rtx dest = SET_DEST (set);
> > > -      rtx src = SET_SRC (set);
> > > -      if (ix86_check_avx_upper_register (dest))
> > > +      /* Perform this vzeroupper optimization if target doesn't need
> > > +        vzeroupper after reading all-zero YMM/YMM registers.  */
> > > +      rtx set = single_set (insn);
> > > +      if (set)
> > >         {
> > > -         /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> > > -            source isn't zero.  */
> > > -         if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> > > -           return AVX_U128_DIRTY;
> > > +         rtx dest = SET_DEST (set);
> > > +         rtx src = SET_SRC (set);
> > > +         if (ix86_check_avx_upper_register (dest))
> > > +           {
> > > +             /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
> > > +                source isn't zero.  */
> > > +             if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
> > > +               return AVX_U128_DIRTY;
> > > +             else
> > > +               return AVX_U128_ANY;
> > > +           }
> > >           else
> > > -           return AVX_U128_ANY;
> > > -       }
> > > -      else
> > > -       {
> > > -         FOR_EACH_SUBRTX (iter, array, src, NONCONST)
> > > -           if (ix86_check_avx_upper_register (*iter))
> > > -             {
> > > -               int status = ix86_avx_u128_mode_source (insn, *iter);
> > > -               if (status == AVX_U128_DIRTY)
> > > -                 return status;
> > > -             }
> > > -       }
> > > +           {
> > > +             FOR_EACH_SUBRTX (iter, array, src, NONCONST)
> > > +               if (ix86_check_avx_upper_register (*iter))
> > > +                 {
> > > +                   int status = ix86_avx_u128_mode_source (insn, *iter);
> > > +                   if (status == AVX_U128_DIRTY)
> > > +                     return status;
> > > +                 }
> > > +           }
> > >
> > > -      /* This isn't YMM/ZMM load/store.  */
> > > -      return AVX_U128_ANY;
> > > +         /* This isn't YMM/ZMM load/store.  */
> > > +         return AVX_U128_ANY;
> > > +       }
> > >      }
> > >
> > >    /* Require DIRTY mode if a 256bit or 512bit AVX register is referenced.
> > > diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
> > > index f41e0908250..46379d2231b 100644
> > > --- a/gcc/config/i386/i386.h
> > > +++ b/gcc/config/i386/i386.h
> > > @@ -425,6 +425,8 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST];
> > >  #define TARGET_AVOID_MFENCE ix86_tune_features[X86_TUNE_AVOID_MFENCE]
> > >  #define TARGET_EMIT_VZEROUPPER \
> > >         ix86_tune_features[X86_TUNE_EMIT_VZEROUPPER]
> > > +#define TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO \
> > > +       ix86_tune_features[X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO]
> > >  #define TARGET_EXPAND_ABS \
> > >         ix86_tune_features[X86_TUNE_EXPAND_ABS]
> > >  #define TARGET_V2DF_REDUCTION_PREFER_HADDPD \
> > > diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
> > > index 82ca0ae63ac..132de2db2eb 100644
> > > --- a/gcc/config/i386/x86-tune.def
> > > +++ b/gcc/config/i386/x86-tune.def
> > > @@ -649,3 +649,8 @@ DEF_TUNE (X86_TUNE_PROMOTE_QI_REGS, "promote_qi_regs", m_NONE)
> > >  /* X86_TUNE_EMIT_VZEROUPPER: This enables vzeroupper instruction insertion
> > >     before a transfer of control flow out of the function.  */
> > >  DEF_TUNE (X86_TUNE_EMIT_VZEROUPPER, "emit_vzeroupper", ~m_KNL)
> > > +
> > > +/* X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO: This omits vzeroupper
> > > +   instruction after reading all-zero YMM/ZMM registers.  */
> > > +DEF_TUNE (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO,
> > > +         "omit_vzeroupper_after_avx_read_zero", 0)
> > > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-1.c b/gcc/testsuite/gcc.target/i386/pr101456-1.c
> > > index 803fc6e0207..f653197da7c 100644
> > > --- a/gcc/testsuite/gcc.target/i386/pr101456-1.c
> > > +++ b/gcc/testsuite/gcc.target/i386/pr101456-1.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-options "-O2 -march=skylake" } */
> > > +/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
> > >
> > >  #include <x86intrin.h>
> > >
> > > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-2.c b/gcc/testsuite/gcc.target/i386/pr101456-2.c
> > > index 554a0f1702c..9aac3ece14d 100644
> > > --- a/gcc/testsuite/gcc.target/i386/pr101456-2.c
> > > +++ b/gcc/testsuite/gcc.target/i386/pr101456-2.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-options "-O2 -march=skylake" } */
> > > +/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
> > >
> > >  #include <x86intrin.h>
> > >
> > > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-3.c b/gcc/testsuite/gcc.target/i386/pr101456-3.c
> > > new file mode 100644
> > > index 00000000000..8389d18ed6c
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/i386/pr101456-3.c
> > > @@ -0,0 +1,33 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-options "-O2 -march=skylake -mtune=alderlake" } */
> > > +
> > > +#include <x86intrin.h>
> > > +
> > > +extern __m256 x1;
> > > +extern __m256d x2;
> > > +extern __m256i x3;
> > > +
> > > +extern void bar (void);
> > > +
> > > +void
> > > +foo1 (void)
> > > +{
> > > +  x1 = _mm256_setzero_ps ();
> > > +  bar ();
> > > +}
> > > +
> > > +void
> > > +foo2 (void)
> > > +{
> > > +  x2 = _mm256_setzero_pd ();
> > > +  bar ();
> > > +}
> > > +
> > > +void
> > > +foo3 (void)
> > > +{
> > > +  x3 = _mm256_setzero_si256 ();
> > > +  bar ();
> > > +}
> > > +
> > > +/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
> > > diff --git a/gcc/testsuite/gcc.target/i386/pr101456-4.c b/gcc/testsuite/gcc.target/i386/pr101456-4.c
> > > new file mode 100644
> > > index 00000000000..3e4cdcc4d28
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/i386/pr101456-4.c
> > > @@ -0,0 +1,33 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-options "-O2 -march=haswell" } */
> > > +
> > > +#include <x86intrin.h>
> > > +
> > > +extern __m256 x1;
> > > +extern __m256d x2;
> > > +extern __m256i x3;
> > > +
> > > +extern void bar (void);
> > > +
> > > +void
> > > +foo1 (void)
> > > +{
> > > +  x1 = _mm256_setzero_ps ();
> > > +  bar ();
> > > +}
> > > +
> > > +void
> > > +foo2 (void)
> > > +{
> > > +  x2 = _mm256_setzero_pd ();
> > > +  bar ();
> > > +}
> > > +
> > > +void
> > > +foo3 (void)
> > > +{
> > > +  x3 = _mm256_setzero_si256 ();
> > > +  bar ();
> > > +}
> > > +
> > > +/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
> > > --
> > > 2.35.1
> > >
> >
> >
> > --
> > BR,
> > Hongtao
>
>
>
> --
> H.J.
  
H.J. Lu Feb. 22, 2022, 2:21 p.m. UTC | #4
On Mon, Feb 21, 2022 at 6:43 PM Hongtao Liu <crazylht@gmail.com> wrote:
>
> On Tue, Feb 22, 2022 at 2:35 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Sun, Feb 20, 2022 at 6:01 PM Hongtao Liu <crazylht@gmail.com> wrote:
> > >
> > > On Thu, Feb 17, 2022 at 9:56 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > >
> > > > On Thu, Feb 17, 2022 at 08:51:31AM +0100, Uros Bizjak wrote:
> > > > > On Thu, Feb 17, 2022 at 6:25 AM Hongtao Liu via Gcc-patches
> > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > >
> > > > > > On Thu, Feb 17, 2022 at 12:26 PM H.J. Lu via Gcc-patches
> > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > >
> > > > > > > Reading YMM registers with all zero bits needs VZEROUPPER on Sandy Bride,
> > > > > > > Ivy Bridge, Haswell, Broadwell and Alder Lake to avoid SSE <-> AVX
> > > > > > > transition penalty.  Add TARGET_READ_ZERO_YMM_ZMM_NEED_VZEROUPPER to
> > > > > > > generate vzeroupper instruction after loading all-zero YMM/YMM registers
> > > > > > > and enable it by default.
> > > > > > Shouldn't TARGET_READ_ZERO_YMM_ZMM_NONEED_VZEROUPPER sounds a bit smoother?
> > > > > > Because originally we needed to add vzeroupper to all avx<->sse cases,
> > > > > > now it's a tune to indicate that we don't need to add it in some
> > > > >
> > > > > Perhaps we should go from the other side and use
> > > > > X86_TUNE_OPTIMIZE_AVX_READ for new processors?
> > > > >
> > > >
> > > > Here is the v2 patch to add TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO.
> > > >
> > > The patch LGTM in general, but please rebase against
> > > https://gcc.gnu.org/pipermail/gcc-patches/2022-February/590541.html
> > > and resend the patch, also wait a couple days in case Uros(and others)
> > > have any comments.
> >
> > I am dropping my patch since it causes the compile-time regression.
> I think only vextractif128 part is reverted, but we still have
> vmovdqu(below) which should also cause penalty?

commit fe79d652c96b53384ddfa43e312cb0010251391b
Author: Richard Biener <rguenther@suse.de>
Date:   Thu Feb 17 14:40:16 2022 +0100

    target/104581 - compile-time regression in mode-switching

has

diff --git a/gcc/testsuite/gcc.target/i386/pr101456-1.c
b/gcc/testsuite/gcc.target/i386/pr101456-1.c
index 803fc6e0207..7fb3a3f055c 100644
--- a/gcc/testsuite/gcc.target/i386/pr101456-1.c
+++ b/gcc/testsuite/gcc.target/i386/pr101456-1.c
@@ -30,4 +30,5 @@ foo3 (void)
   bar ();
 }

-/* { dg-final { scan-assembler-not "vzeroupper" } } */
+/* See PR104581 for the XFAIL reason.  */
+/* { dg-final { scan-assembler-not "vzeroupper" { xfail *-*-* } } } */

and I checked in:

commit 1931cbad498e625b1e24452dcfffe02539b12224
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Feb 18 10:36:53 2022 -0800

    pieces-memset-21.c: Expect vzeroupper for ia32

    Update gcc.target/i386/pieces-memset-21.c to expect vzeroupper for ia32
    caused by

    commit fe79d652c96b53384ddfa43e312cb0010251391b
    Author: Richard Biener <rguenther@suse.de>
    Date:   Thu Feb 17 14:40:16 2022 +0100

        target/104581 - compile-time regression in mode-switching

            PR target/104581
            * gcc.target/i386/pieces-memset-21.c: Expect vzeroupper for ia32.

I believe that vmovdqu is also covered.
  

Patch

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index cf246e74e57..60c72ceb72d 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -14502,33 +14502,38 @@  ix86_avx_u128_mode_needed (rtx_insn *insn)
 
   subrtx_iterator::array_type array;
 
-  rtx set = single_set (insn);
-  if (set)
+  if (TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO)
     {
-      rtx dest = SET_DEST (set);
-      rtx src = SET_SRC (set);
-      if (ix86_check_avx_upper_register (dest))
+      /* Perform this vzeroupper optimization if target doesn't need
+	 vzeroupper after reading all-zero YMM/YMM registers.  */
+      rtx set = single_set (insn);
+      if (set)
 	{
-	  /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
-	     source isn't zero.  */
-	  if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
-	    return AVX_U128_DIRTY;
+	  rtx dest = SET_DEST (set);
+	  rtx src = SET_SRC (set);
+	  if (ix86_check_avx_upper_register (dest))
+	    {
+	      /* This is an YMM/ZMM load.  Return AVX_U128_DIRTY if the
+		 source isn't zero.  */
+	      if (standard_sse_constant_p (src, GET_MODE (dest)) != 1)
+		return AVX_U128_DIRTY;
+	      else
+		return AVX_U128_ANY;
+	    }
 	  else
-	    return AVX_U128_ANY;
-	}
-      else
-	{
-	  FOR_EACH_SUBRTX (iter, array, src, NONCONST)
-	    if (ix86_check_avx_upper_register (*iter))
-	      {
-		int status = ix86_avx_u128_mode_source (insn, *iter);
-		if (status == AVX_U128_DIRTY)
-		  return status;
-	      }
-	}
+	    {
+	      FOR_EACH_SUBRTX (iter, array, src, NONCONST)
+		if (ix86_check_avx_upper_register (*iter))
+		  {
+		    int status = ix86_avx_u128_mode_source (insn, *iter);
+		    if (status == AVX_U128_DIRTY)
+		      return status;
+		  }
+	    }
 
-      /* This isn't YMM/ZMM load/store.  */
-      return AVX_U128_ANY;
+	  /* This isn't YMM/ZMM load/store.  */
+	  return AVX_U128_ANY;
+	}
     }
 
   /* Require DIRTY mode if a 256bit or 512bit AVX register is referenced.
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index f41e0908250..46379d2231b 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -425,6 +425,8 @@  extern unsigned char ix86_tune_features[X86_TUNE_LAST];
 #define TARGET_AVOID_MFENCE ix86_tune_features[X86_TUNE_AVOID_MFENCE]
 #define TARGET_EMIT_VZEROUPPER \
 	ix86_tune_features[X86_TUNE_EMIT_VZEROUPPER]
+#define TARGET_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO \
+	ix86_tune_features[X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO]
 #define TARGET_EXPAND_ABS \
 	ix86_tune_features[X86_TUNE_EXPAND_ABS]
 #define TARGET_V2DF_REDUCTION_PREFER_HADDPD \
diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
index 82ca0ae63ac..132de2db2eb 100644
--- a/gcc/config/i386/x86-tune.def
+++ b/gcc/config/i386/x86-tune.def
@@ -649,3 +649,8 @@  DEF_TUNE (X86_TUNE_PROMOTE_QI_REGS, "promote_qi_regs", m_NONE)
 /* X86_TUNE_EMIT_VZEROUPPER: This enables vzeroupper instruction insertion
    before a transfer of control flow out of the function.  */
 DEF_TUNE (X86_TUNE_EMIT_VZEROUPPER, "emit_vzeroupper", ~m_KNL)
+
+/* X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO: This omits vzeroupper
+   instruction after reading all-zero YMM/ZMM registers.  */
+DEF_TUNE (X86_TUNE_OMIT_VZEROUPPER_AFTER_AVX_READ_ZERO,
+	  "omit_vzeroupper_after_avx_read_zero", 0)
diff --git a/gcc/testsuite/gcc.target/i386/pr101456-1.c b/gcc/testsuite/gcc.target/i386/pr101456-1.c
index 803fc6e0207..f653197da7c 100644
--- a/gcc/testsuite/gcc.target/i386/pr101456-1.c
+++ b/gcc/testsuite/gcc.target/i386/pr101456-1.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-O2 -march=skylake" } */
+/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/pr101456-2.c b/gcc/testsuite/gcc.target/i386/pr101456-2.c
index 554a0f1702c..9aac3ece14d 100644
--- a/gcc/testsuite/gcc.target/i386/pr101456-2.c
+++ b/gcc/testsuite/gcc.target/i386/pr101456-2.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-O2 -march=skylake" } */
+/* { dg-options "-O2 -march=skylake -mtune-ctrl=omit_vzeroupper_after_avx_read_zero" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/pr101456-3.c b/gcc/testsuite/gcc.target/i386/pr101456-3.c
new file mode 100644
index 00000000000..8389d18ed6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr101456-3.c
@@ -0,0 +1,33 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=skylake -mtune=alderlake" } */
+
+#include <x86intrin.h>
+
+extern __m256 x1;
+extern __m256d x2;
+extern __m256i x3;
+
+extern void bar (void);
+
+void
+foo1 (void)
+{
+  x1 = _mm256_setzero_ps ();
+  bar ();
+}
+
+void
+foo2 (void)
+{
+  x2 = _mm256_setzero_pd ();
+  bar ();
+}
+
+void
+foo3 (void)
+{
+  x3 = _mm256_setzero_si256 ();
+  bar ();
+}
+
+/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr101456-4.c b/gcc/testsuite/gcc.target/i386/pr101456-4.c
new file mode 100644
index 00000000000..3e4cdcc4d28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr101456-4.c
@@ -0,0 +1,33 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=haswell" } */
+
+#include <x86intrin.h>
+
+extern __m256 x1;
+extern __m256d x2;
+extern __m256i x3;
+
+extern void bar (void);
+
+void
+foo1 (void)
+{
+  x1 = _mm256_setzero_ps ();
+  bar ();
+}
+
+void
+foo2 (void)
+{
+  x2 = _mm256_setzero_pd ();
+  bar ();
+}
+
+void
+foo3 (void)
+{
+  x3 = _mm256_setzero_si256 ();
+  bar ();
+}
+
+/* { dg-final { scan-assembler-times "vzeroupper" 3 } } */