diff mbox series

[v3] x86: Disable x86-64 level marker [BZ #27318]

Message ID CAMe9rOqjnzvZMpRw_CcaN+eXZ8q5FB+FyL6c7UpcEgXcFJi1JA@mail.gmail.com
State New
Headers show
Series [v3] x86: Disable x86-64 level marker [BZ #27318] | expand

Commit Message

H.J. Lu Feb. 9, 2021, 12:29 a.m. UTC
On Mon, Feb 8, 2021 at 8:09 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Feb 8, 2021 at 7:06 AM Florian Weimer <fweimer@redhat.com> wrote:
> >
> > * H. J. Lu via Libc-alpha:
> >
> > > It is used to check if INCLUDE_X86_ISA_LEVEL should be defined in
> > > config.h.   INCLUDE_X86_ISA_LEVEL is defined only if GCC enables
> > > the full ISAs of a level without any ISAs of the higher ISA levels.   Since
> > > I want to support GCC older than GCC 11,  || is used to detect any
> > > ISAs in a level and !|| is used to check if any ISAs are missing.
> >
> > But isn't && the right construct anyway?  As in, if GCC was built to
> > include *all* feature flags for a specific level, require that level at
> > run time?
>
> isa-level.c serves 2 purposes:
>
> 1.  Add ISA level marker (|| path) when INCLUDE_X86_ISA_LEVEL is defined.
> "# error" path will never be hit.
> 2.  Used by sysdeps/x86/configure.ac to check if INCLUDE_X86_ISA_LEVEL
> should be defined.  If any ISAs (!|| path) are missing, INCLUDE_X86_ISA_LEVEL
> won't be defined.
>
> Since GCC 10 doesn't define __LAHF_SAHF__, __MOVBE__ nor __XSAVE__,
> "&&" doesn't work for GCC 10.  However, I can move ISAs check to
> sysdeps/x86/configure.ac and define INCLUDE_X86_ISA_LEVEL to

This patch does it.

> #define INCLUDE_X86_ISA_LEVEL GNU_PROPERTY_X86_ISA_1_XXX
>
> > >> Are ISA levels really defined for 32-bit?
> > >
> > > 32-bit can just use the same x86-64 ISA level.
> >
> > At least it requires figuring out the baseline level between i386 and
> > x86-64-v2, probably based on what GCC's -march=x86-64 option does with
> > -m32.
> >
>
> Yes, we can make the minimum i386 ISAs for glibc as i386 baseline.
>

Since i386 is legacy, this patch disables x86-64 ISA level marker for
32-bit build.
Here is the v3 patch.   Changes from v2:

1. Disable x86-64 ISA level marker for 32-bit build.
2. Disable x86-64 ISA level marker for -march=XXX if its ISA set isn't a
complete subnet of a ISA level.

Comments

Florian Weimer Feb. 22, 2021, 10:40 a.m. UTC | #1
* H. J. Lu via Libc-alpha:

> +#if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
> +   || defined __LAHF_SAHF__ || defined __POPCNT__ || defined __SSE3__ \
> +   || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
> +/* NB: Some ISAs in x86-64 ISA level v2 are used.  */
> +# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
> +     && defined __LAHF_SAHF__ && defined __POPCNT__ && defined __SSE3__ \
> +     && defined __SSSE3__ && defined __SSE4_1__ && defined __SSE4_2__
> +/* NB: Enable x86-64 ISA level v2 marker only if all ISAs are enabled.  */
> +#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
> +# else
> +/* NB: We can't use the lesser x86-64 ISA level marker since some v2 ISAs
> +   are used.  */
> +#  error "Missing ISAs for x86-64 ISA level v2"
> +# endif
> +#else
> +# define ISA_V2	0
> +#endif
> +
> +#if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
> +    || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__
> +/* NB: Some ISAs in x86-64 ISA level v3 are used.  */
> +# if defined __AVX__ && defined __AVX2__ && defined __F16C__ \
> +     && defined __FMA__ && defined __LZCNT__ && defined __MOVBE__
> +/* NB: Enable x86-64 ISA level v3 marker only if all ISAs are enabled.  */
> +#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
> +# else
> +/* NB: We can't use the lesser x86-64 ISA level marker since some v3 ISAs
> +   are used.  */
> +#  error "Missing ISAs for x86-64 ISA level v3"
> +# endif
> +#else
> +# define ISA_V3	0
> +#endif

I think this will produce an #error for if there is a lone -mavx in
addition to x86-64-v2 coverage in the compiler.  The first block would
define ISA_V2, but the second block produces the error.  I assume that
causes inclusion of the build note to be skipped.

Is this really helpful?  If glibc was built to run with on x86-64-v2
CPUs with some extra, wouldn't it still make sense to perform the
x86-64-v2 diagnostic upon startup?

Thanks,
Florian
H.J. Lu Feb. 22, 2021, 12:51 p.m. UTC | #2
On Mon, Feb 22, 2021 at 2:40 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu via Libc-alpha:
>
> > +#if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
> > +   || defined __LAHF_SAHF__ || defined __POPCNT__ || defined __SSE3__ \
> > +   || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
> > +/* NB: Some ISAs in x86-64 ISA level v2 are used.  */
> > +# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
> > +     && defined __LAHF_SAHF__ && defined __POPCNT__ && defined __SSE3__ \
> > +     && defined __SSSE3__ && defined __SSE4_1__ && defined __SSE4_2__
> > +/* NB: Enable x86-64 ISA level v2 marker only if all ISAs are enabled.  */
> > +#  define ISA_V2     GNU_PROPERTY_X86_ISA_1_V2
> > +# else
> > +/* NB: We can't use the lesser x86-64 ISA level marker since some v2 ISAs
> > +   are used.  */
> > +#  error "Missing ISAs for x86-64 ISA level v2"
> > +# endif
> > +#else
> > +# define ISA_V2      0
> > +#endif
> > +
> > +#if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
> > +    || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__
> > +/* NB: Some ISAs in x86-64 ISA level v3 are used.  */
> > +# if defined __AVX__ && defined __AVX2__ && defined __F16C__ \
> > +     && defined __FMA__ && defined __LZCNT__ && defined __MOVBE__
> > +/* NB: Enable x86-64 ISA level v3 marker only if all ISAs are enabled.  */
> > +#  define ISA_V3     GNU_PROPERTY_X86_ISA_1_V3
> > +# else
> > +/* NB: We can't use the lesser x86-64 ISA level marker since some v3 ISAs
> > +   are used.  */
> > +#  error "Missing ISAs for x86-64 ISA level v3"
> > +# endif
> > +#else
> > +# define ISA_V3      0
> > +#endif
>
> I think this will produce an #error for if there is a lone -mavx in
> addition to x86-64-v2 coverage in the compiler.  The first block would
> define ISA_V2, but the second block produces the error.  I assume that
> causes inclusion of the build note to be skipped.

Correct.

> Is this really helpful?  If glibc was built to run with on x86-64-v2
> CPUs with some extra, wouldn't it still make sense to perform the
> x86-64-v2 diagnostic upon startup?

Since libc.so now contains x86-64-v2 + extra, we can't mark it as
x86-64-v2 since it may UD on x86-64-v2 machines.  Or we can
change the meaning of the ISA level marker from "this shared library
REQUIRES ONLY x86-64-v2 to run" to "this shared library WON'T
run without x86-64-v2".
Florian Weimer Feb. 22, 2021, 1:51 p.m. UTC | #3
* H. J. Lu via Libc-alpha:

> On Mon, Feb 22, 2021 at 2:40 AM Florian Weimer <fweimer@redhat.com> wrote:
>> I think this will produce an #error for if there is a lone -mavx in
>> addition to x86-64-v2 coverage in the compiler.  The first block would
>> define ISA_V2, but the second block produces the error.  I assume that
>> causes inclusion of the build note to be skipped.
>
> Correct.

Okay, that explains why the checks are the way they are.  Thanks.

>> Is this really helpful?  If glibc was built to run with on x86-64-v2
>> CPUs with some extra, wouldn't it still make sense to perform the
>> x86-64-v2 diagnostic upon startup?
>
> Since libc.so now contains x86-64-v2 + extra, we can't mark it as
> x86-64-v2 since it may UD on x86-64-v2 machines.  Or we can
> change the meaning of the ISA level marker from "this shared library
> REQUIRES ONLY x86-64-v2 to run" to "this shared library WON'T
> run without x86-64-v2".

I think the loader check is worthwhile to add because otherwise people
will end up with half-working systems.  In my experience, this can lead
to lots of bug reports because people assume that if only some things
are crashing, it must be a distribution bug.  So the loader check is
quite valuable for documenting an baseline increase.

I also think that the ELF markers are valuable if they specify the exact
ABI level to which the object has been built.  But I do think we need
GCC and perhaps binutils support for generating them because otherwise,
new GCC features may silently build glibc with the wrong ABI level.  For
example, with this patch and building on GCC 10 with
-march=icelake-server, it seems like I still get a property note:

Displaying notes found in: .note.gnu.property
  Owner                Data size 	Description
  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0	      Properties: <procesor-specific type 0xc0008002 data: 0f 00 00 00 >

But -march=icelake-server is a superset of x86-64-v4, so that's not
correct, I think.  glibc can't know a bout all these extra features, so
the generated note will always be misleading.  A note produced elsewhere
in the toolchain would not have this problem.

But we could still check for all the preprocessor macros we know that
should constitute x86-64-v2 &c, and error out in the dynamic loader if
there isn't support for them in the current process.

Thanks,
Florian
Florian Weimer March 1, 2021, 4:07 p.m. UTC | #4
* Florian Weimer:

> * H. J. Lu via Libc-alpha:
>
>> On Mon, Feb 22, 2021 at 2:40 AM Florian Weimer <fweimer@redhat.com> wrote:
>>> I think this will produce an #error for if there is a lone -mavx in
>>> addition to x86-64-v2 coverage in the compiler.  The first block would
>>> define ISA_V2, but the second block produces the error.  I assume that
>>> causes inclusion of the build note to be skipped.
>>
>> Correct.
>
> Okay, that explains why the checks are the way they are.  Thanks.
>
>>> Is this really helpful?  If glibc was built to run with on x86-64-v2
>>> CPUs with some extra, wouldn't it still make sense to perform the
>>> x86-64-v2 diagnostic upon startup?
>>
>> Since libc.so now contains x86-64-v2 + extra, we can't mark it as
>> x86-64-v2 since it may UD on x86-64-v2 machines.  Or we can
>> change the meaning of the ISA level marker from "this shared library
>> REQUIRES ONLY x86-64-v2 to run" to "this shared library WON'T
>> run without x86-64-v2".
>
> I think the loader check is worthwhile to add because otherwise people
> will end up with half-working systems.  In my experience, this can lead
> to lots of bug reports because people assume that if only some things
> are crashing, it must be a distribution bug.  So the loader check is
> quite valuable for documenting an baseline increase.
>
> I also think that the ELF markers are valuable if they specify the exact
> ABI level to which the object has been built.  But I do think we need
> GCC and perhaps binutils support for generating them because otherwise,
> new GCC features may silently build glibc with the wrong ABI level.  For
> example, with this patch and building on GCC 10 with
> -march=icelake-server, it seems like I still get a property note:
>
> Displaying notes found in: .note.gnu.property
>   Owner                Data size 	Description
>   GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0	      Properties: <procesor-specific type 0xc0008002 data: 0f 00 00 00 >
>
> But -march=icelake-server is a superset of x86-64-v4, so that's not
> correct, I think.  glibc can't know a bout all these extra features, so
> the generated note will always be misleading.  A note produced elsewhere
> in the toolchain would not have this problem.
>
> But we could still check for all the preprocessor macros we know that
> should constitute x86-64-v2 &c, and error out in the dynamic loader if
> there isn't support for them in the current process.

Any further comments here?

This bug keeps hitting more and more people.

I think we should do the following: (a) disable the build note
generation in glibc, (b) backport --list-diagnostics or something
similar.  The second part will hopefully help with analyzing failures
due to CPU support mismatches.

Thanks,
Florian
H.J. Lu March 1, 2021, 6 p.m. UTC | #5
On Mon, Mar 1, 2021 at 8:06 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * Florian Weimer:
>
> > * H. J. Lu via Libc-alpha:
> >
> >> On Mon, Feb 22, 2021 at 2:40 AM Florian Weimer <fweimer@redhat.com> wrote:
> >>> I think this will produce an #error for if there is a lone -mavx in
> >>> addition to x86-64-v2 coverage in the compiler.  The first block would
> >>> define ISA_V2, but the second block produces the error.  I assume that
> >>> causes inclusion of the build note to be skipped.
> >>
> >> Correct.
> >
> > Okay, that explains why the checks are the way they are.  Thanks.
> >
> >>> Is this really helpful?  If glibc was built to run with on x86-64-v2
> >>> CPUs with some extra, wouldn't it still make sense to perform the
> >>> x86-64-v2 diagnostic upon startup?
> >>
> >> Since libc.so now contains x86-64-v2 + extra, we can't mark it as
> >> x86-64-v2 since it may UD on x86-64-v2 machines.  Or we can
> >> change the meaning of the ISA level marker from "this shared library
> >> REQUIRES ONLY x86-64-v2 to run" to "this shared library WON'T
> >> run without x86-64-v2".
> >
> > I think the loader check is worthwhile to add because otherwise people
> > will end up with half-working systems.  In my experience, this can lead
> > to lots of bug reports because people assume that if only some things
> > are crashing, it must be a distribution bug.  So the loader check is
> > quite valuable for documenting an baseline increase.
> >
> > I also think that the ELF markers are valuable if they specify the exact
> > ABI level to which the object has been built.  But I do think we need
> > GCC and perhaps binutils support for generating them because otherwise,
> > new GCC features may silently build glibc with the wrong ABI level.  For
> > example, with this patch and building on GCC 10 with
> > -march=icelake-server, it seems like I still get a property note:
> >
> > Displaying notes found in: .note.gnu.property
> >   Owner                Data size      Description
> >   GNU                  0x00000010     NT_GNU_PROPERTY_TYPE_0        Properties: <procesor-specific type 0xc0008002 data: 0f 00 00 00 >
> >
> > But -march=icelake-server is a superset of x86-64-v4, so that's not
> > correct, I think.  glibc can't know a bout all these extra features, so
> > the generated note will always be misleading.  A note produced elsewhere
> > in the toolchain would not have this problem.
> >
> > But we could still check for all the preprocessor macros we know that
> > should constitute x86-64-v2 &c, and error out in the dynamic loader if
> > there isn't support for them in the current process.
>
> Any further comments here?
>
> This bug keeps hitting more and more people.
>
> I think we should do the following: (a) disable the build note
> generation in glibc, (b) backport --list-diagnostics or something
> similar.  The second part will hopefully help with analyzing failures
> due to CPU support mismatches.

My patch does (a).  But I think the ISA level meaning should be changed
from "works on processors with the ISA level" to "require processors with
the ISA level to work".
Florian Weimer March 1, 2021, 6:06 p.m. UTC | #6
* H. J. Lu:

>> I think we should do the following: (a) disable the build note
>> generation in glibc, (b) backport --list-diagnostics or something
>> similar.  The second part will hopefully help with analyzing failures
>> due to CPU support mismatches.
>
> My patch does (a).

But not completely so, see the issue regarding post-v4 flags.

> But I think the ISA level meaning should be changed from "works on
> processors with the ISA level" to "require processors with the ISA
> level to work".

Hmm.  Is this compatible with the glibc-hwcaps directory assignment
logic in ldconfig?

Thanks,
Florian
H.J. Lu March 1, 2021, 7:09 p.m. UTC | #7
On Mon, Mar 1, 2021 at 10:05 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> >> I think we should do the following: (a) disable the build note
> >> generation in glibc, (b) backport --list-diagnostics or something
> >> similar.  The second part will hopefully help with analyzing failures
> >> due to CPU support mismatches.
> >
> > My patch does (a).
>
> But not completely so, see the issue regarding post-v4 flags.

It is the issue of "works on processors with the ISA level" since
we don't check if other ISA features are required.

> > But I think the ISA level meaning should be changed from "works on
> > processors with the ISA level" to "require processors with the ISA
> > level to work".
>
> Hmm.  Is this compatible with the glibc-hwcaps directory assignment
> logic in ldconfig?

Given that we don't check the extra ISA features in the binary, this
is a logical change.
diff mbox series

Patch

From 432402b377b9ded33fd294cb2f819be139161472 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 2 Feb 2021 13:45:58 -0800
Subject: [PATCH v3] x86: Disable x86-64 level marker [BZ #27318]

Since -march=sandybridge enables some ISAs in x86-64 ISA level v3, the v3
marker is set on libc.so.  We couldn't set the needed ISA marker to v2
since this libc won't run on all v2 machines.  Technically, the v3 marker
is correct.  But the resulting libc.so won't run on Sandybrigde, which
isn't a v3 machine, even when libc is compiled with -march=sandybridge:

$ ./elf/ld.so ./libc.so
./libc.so: (p) CPU ISA level is lower than required: needed: 7; got: 3

1. Disable x86-64 ISA level marker for 32-bit build.
2. Disable x86-64 ISA level marker for -march=XXX if its ISA set isn't a
complete subnet of a ISA level.
---
 config.h.in              |   3 +
 sysdeps/x86/configure    | 119 ++++++++++++++++++++++++++++++++++++++-
 sysdeps/x86/configure.ac | 101 ++++++++++++++++++++++++++++++++-
 sysdeps/x86/isa-level.c  |  33 +----------
 4 files changed, 222 insertions(+), 34 deletions(-)

diff --git a/config.h.in b/config.h.in
index 06ee8ae26a..3c9035c2f2 100644
--- a/config.h.in
+++ b/config.h.in
@@ -275,4 +275,7 @@ 
 /* Define if x86 ISA level should be included in shared libraries.  */
 #undef INCLUDE_X86_ISA_LEVEL
 
+/* The default x86 ISA level.  */
+#define DEFAULT_ISA_LEVEL 0
+
 #endif
diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure
index 5e32dc62b3..3812ba288e 100644
--- a/sysdeps/x86/configure
+++ b/sysdeps/x86/configure
@@ -134,7 +134,120 @@  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest c
   test $ac_status = 0; }; }; then
   count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
   if test "$count" = 1; then
-    libc_cv_include_x86_isa_level=yes
+    cat > conftest.c <<EOF
+extern long double fmodl(long double x, long double y);
+extern long double x, y;
+long double
+foo (void)
+{
+  return fmodl (x, y);
+}
+EOF
+    ISA_LEVEL_CPPFLAGS=
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Os -ffast-math -S -o - conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } | grep -q "	sahf"; then
+      ISA_LEVEL_CPPFLAGS=-D__LAHF_SAHF__
+    fi
+    cat > conftest.c <<EOF
+extern int x;
+int
+bar ()
+{
+  return __builtin_bswap32 (x);
+}
+EOF
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -O2 -S -o - conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } | grep -q "	movbe"; then
+      ISA_LEVEL_CPPFLAGS="$ISA_LEVEL_CPPFLAGS -D__MOVBE__"
+    fi
+    cat > conftest.c <<EOF
+#ifndef __x86_64__
+# error "x86-64 ISA level is only for x86-64"
+#endif
+
+#if defined __SSE__ || defined __SSE2__
+/* NB: Some ISAs in x86-64 ISA level baseline are used.  */
+# if defined __SSE__ && defined __SSE2__
+/* NB: Enable x86-64 ISA level baseline marker only if all ISAs are
+   enabled.  */
+#  define ISA_BASELINE	GNU_PROPERTY_X86_ISA_1_BASELINE
+# else
+#  error "Missing ISAs for x86-64 ISA level baseline"
+# endif
+#else
+# define ISA_BASELINE	0
+#endif
+
+#if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+   || defined __LAHF_SAHF__ || defined __POPCNT__ || defined __SSE3__ \
+   || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
+/* NB: Some ISAs in x86-64 ISA level v2 are used.  */
+# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+     && defined __LAHF_SAHF__ && defined __POPCNT__ && defined __SSE3__ \
+     && defined __SSSE3__ && defined __SSE4_1__ && defined __SSE4_2__
+/* NB: Enable x86-64 ISA level v2 marker only if all ISAs are enabled.  */
+#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v2 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v2"
+# endif
+#else
+# define ISA_V2	0
+#endif
+
+#if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
+    || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__
+/* NB: Some ISAs in x86-64 ISA level v3 are used.  */
+# if defined __AVX__ && defined __AVX2__ && defined __F16C__ \
+     && defined __FMA__ && defined __LZCNT__ && defined __MOVBE__
+/* NB: Enable x86-64 ISA level v3 marker only if all ISAs are enabled.  */
+#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v3 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v3"
+# endif
+#else
+# define ISA_V3	0
+#endif
+
+#if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
+    || defined __AVX512DQ__ || defined __AVX512VL__
+/* NB: Some ISAs in x86-64 ISA level v4 are used.  */
+# if defined __AVX512F__ && defined __AVX512BW__ \
+     && defined __AVX512CD__ && defined __AVX512DQ__ \
+     && defined __AVX512VL__
+/* NB: Enable x86-64 ISA level v4 marker only if all ISAs are enabled.  */
+#  define ISA_V4	GNU_PROPERTY_X86_ISA_1_V4
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v4 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v4"
+# endif
+#else
+# define ISA_V4	0
+#endif
+
+DEFAULT_ISA_LEVEL=(ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+EOF
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $ISA_LEVEL_CPPFLAGS -E -o conftest.i conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+      eval `grep DEFAULT_ISA_LEVEL= conftest.i | sed -e "s/DEFAULT_ISA_LEVEL=\(.*\)/DEFAULT_ISA_LEVEL=\"\1\"/"`
+      libc_cv_include_x86_isa_level=yes
+    fi
   fi
 fi
 rm -f conftest*
@@ -144,6 +257,10 @@  $as_echo "$libc_cv_include_x86_isa_level" >&6; }
 if test $libc_cv_include_x86_isa_level = yes; then
   $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h
 
+  cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ISA_LEVEL $DEFAULT_ISA_LEVEL
+_ACEOF
+
 fi
 config_vars="$config_vars
 enable-x86-isa-level = $libc_cv_include_x86_isa_level"
diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac
index f94088f377..39d307a6d1 100644
--- a/sysdeps/x86/configure.ac
+++ b/sysdeps/x86/configure.ac
@@ -101,11 +101,110 @@  libc_cv_include_x86_isa_level=no
 if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S); then
   count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
   if test "$count" = 1; then
-    libc_cv_include_x86_isa_level=yes
+    cat > conftest.c <<EOF
+extern long double fmodl(long double x, long double y);
+extern long double x, y;
+long double
+foo (void)
+{
+  return fmodl (x, y);
+}
+EOF
+    ISA_LEVEL_CPPFLAGS=
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -Os -ffast-math -S -o - conftest.c) | grep -q "	sahf"; then
+      ISA_LEVEL_CPPFLAGS=-D__LAHF_SAHF__
+    fi
+    cat > conftest.c <<EOF
+extern int x;
+int
+bar ()
+{
+  return __builtin_bswap32 (x);
+}
+EOF
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -O2 -S -o - conftest.c) | grep -q "	movbe"; then
+      ISA_LEVEL_CPPFLAGS="$ISA_LEVEL_CPPFLAGS -D__MOVBE__"
+    fi
+    cat > conftest.c <<EOF
+#ifndef __x86_64__
+# error "x86-64 ISA level is only for x86-64"
+#endif
+
+#if defined __SSE__ || defined __SSE2__
+/* NB: Some ISAs in x86-64 ISA level baseline are used.  */
+# if defined __SSE__ && defined __SSE2__
+/* NB: Enable x86-64 ISA level baseline marker only if all ISAs are
+   enabled.  */
+#  define ISA_BASELINE	GNU_PROPERTY_X86_ISA_1_BASELINE
+# else
+#  error "Missing ISAs for x86-64 ISA level baseline"
+# endif
+#else
+# define ISA_BASELINE	0
+#endif
+
+#if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+   || defined __LAHF_SAHF__ || defined __POPCNT__ || defined __SSE3__ \
+   || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
+/* NB: Some ISAs in x86-64 ISA level v2 are used.  */
+# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+     && defined __LAHF_SAHF__ && defined __POPCNT__ && defined __SSE3__ \
+     && defined __SSSE3__ && defined __SSE4_1__ && defined __SSE4_2__
+/* NB: Enable x86-64 ISA level v2 marker only if all ISAs are enabled.  */
+#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v2 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v2"
+# endif
+#else
+# define ISA_V2	0
+#endif
+
+#if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
+    || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__
+/* NB: Some ISAs in x86-64 ISA level v3 are used.  */
+# if defined __AVX__ && defined __AVX2__ && defined __F16C__ \
+     && defined __FMA__ && defined __LZCNT__ && defined __MOVBE__
+/* NB: Enable x86-64 ISA level v3 marker only if all ISAs are enabled.  */
+#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v3 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v3"
+# endif
+#else
+# define ISA_V3	0
+#endif
+
+#if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
+    || defined __AVX512DQ__ || defined __AVX512VL__
+/* NB: Some ISAs in x86-64 ISA level v4 are used.  */
+# if defined __AVX512F__ && defined __AVX512BW__ \
+     && defined __AVX512CD__ && defined __AVX512DQ__ \
+     && defined __AVX512VL__
+/* NB: Enable x86-64 ISA level v4 marker only if all ISAs are enabled.  */
+#  define ISA_V4	GNU_PROPERTY_X86_ISA_1_V4
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v4 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v4"
+# endif
+#else
+# define ISA_V4	0
+#endif
+
+DEFAULT_ISA_LEVEL=(ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+EOF
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $ISA_LEVEL_CPPFLAGS -E -o conftest.i conftest.c); then
+      eval `grep DEFAULT_ISA_LEVEL= conftest.i | sed -e "s/DEFAULT_ISA_LEVEL=\(.*\)/DEFAULT_ISA_LEVEL=\"\1\"/"`
+      libc_cv_include_x86_isa_level=yes
+    fi
   fi
 fi
 rm -f conftest*])
 if test $libc_cv_include_x86_isa_level = yes; then
   AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
+  AC_DEFINE_UNQUOTED([DEFAULT_ISA_LEVEL], [$DEFAULT_ISA_LEVEL])
 fi
 LIBC_CONFIG_VAR([enable-x86-isa-level], [$libc_cv_include_x86_isa_level])
diff --git a/sysdeps/x86/isa-level.c b/sysdeps/x86/isa-level.c
index aaf524cb56..cb7667d9d5 100644
--- a/sysdeps/x86/isa-level.c
+++ b/sysdeps/x86/isa-level.c
@@ -29,39 +29,8 @@ 
 
 /* ELF program property for x86 ISA level.  */
 #ifdef INCLUDE_X86_ISA_LEVEL
-# if defined __x86_64__ || defined __FXSR__ || !defined _SOFT_FLOAT \
-     || defined  __MMX__ || defined __SSE__ || defined __SSE2__
-#  define ISA_BASELINE	GNU_PROPERTY_X86_ISA_1_BASELINE
-# else
-#  define ISA_BASELINE	0
-# endif
-
-# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
-     || (defined __x86_64__ && defined __LAHF_SAHF__) \
-     || defined __POPCNT__ || defined __SSE3__ \
-     || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
-#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
-# else
-#  define ISA_V2	0
-# endif
-
-# if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
-     || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__ \
-     || defined __XSAVE__
-#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
-# else
-#  define ISA_V3	0
-# endif
-
-# if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
-     || defined __AVX512DQ__ || defined __AVX512VL__
-#  define ISA_V4	GNU_PROPERTY_X86_ISA_1_V4
-# else
-#  define ISA_V4	0
-# endif
-
 # ifndef ISA_LEVEL
-#  define ISA_LEVEL (ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+#  define ISA_LEVEL DEFAULT_ISA_LEVEL
 # endif
 
 # if ISA_LEVEL
-- 
2.29.2