In a single SET, all bits of the source YMM/ZMM register are zero when

1. The source is contant zero.
2. The source YMM/ZMM operand are defined from contant zero.

and we don't set AVX_U128_DIRTY.

gcc/

        PR target/101456
        * config/i386/i386.c (ix86_avx_u128_mode_needed): Don't set
        AVX_U128_DIRTY when all bits are zero.

gcc/testsuite/

        PR target/101456
        * gcc.target/i386/pr101456-1.c: New test.
---
 gcc/config/i386/i386.c                     | 47 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr101456-1.c | 28 +++++++++++++
 2 files changed, 75 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr101456-1.c

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index cff26909292..c2b06934053 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -14129,6 +14129,53 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
       return AVX_U128_CLEAN;
     }
 
+  rtx set = single_set (insn);
+  if (set)
+    {
+      rtx dest = SET_DEST (set);
+      rtx src = SET_SRC (set);
+      if (ix86_check_avx_upper_register (dest))
+       {
+         /* It is not dirty if the source is known zero.  */
+         if (standard_sse_constant_p (src, GET_MODE (dest)) == 1)
+           return AVX_U128_ANY;
+         else
+           return AVX_U128_DIRTY;
+       }
+      else if (ix86_check_avx_upper_register (src))
+       {
+         /* Check for the source operand with all DEFs from constant
+            zero.  */
+         df_ref def = DF_REG_DEF_CHAIN (REGNO (src));
+         if (!def)
+           return AVX_U128_DIRTY;
+
+         for (; def; def = DF_REF_NEXT_REG (def))
+           if (DF_REF_REG_DEF_P (def)
+               && !DF_REF_IS_ARTIFICIAL (def))
+             {
+               rtx_insn *def_insn = DF_REF_INSN (def);
+               set = single_set (def_insn);
+               if (!set)
+                 return AVX_U128_DIRTY;
+
+               dest = SET_DEST (set);
+               if (ix86_check_avx_upper_register (dest))
+                 {
+                   src = SET_SRC (set);
+                   /* It is dirty if the source operand isn't constant
+                      zero.  */
+                   if (standard_sse_constant_p (src, GET_MODE (dest))
+                       != 1)
+                     return AVX_U128_DIRTY;
+                 }
+             }
+
+         /* It is not dirty only if all sources are known zero.  */
+         return AVX_U128_ANY;
+       }
+    }
+
   /* Require DIRTY mode if a 256bit or 512bit AVX register is referenced.
      Hardware changes state only when a 256bit register is written to,
      but we need to prevent the compiler from moving optimal insertion
diff --git a/gcc/testsuite/gcc.target/i386/pr101456-1.c 
b/gcc/testsuite/gcc.target/i386/pr101456-1.c
new file mode 100644
index 00000000000..6a0f6ccd756
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr101456-1.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=skylake" } */
+
+#include <x86intrin.h>
+
+extern __m256 x1;
+extern __m256d x2;
+extern __m256i x3;
+
+void
+foo1 (void)
+{
+  x1 = _mm256_setzero_ps ();
+}
+
+void
+foo2 (void)
+{
+  x2 = _mm256_setzero_pd ();
+}
+
+void
+foo3 (void)
+{
+  x3 = _mm256_setzero_si256 ();
+}
+
+/* { dg-final { scan-assembler-not "vzeroupper" } } */
-- 
2.31.1

Reply via email to