Detect and select i586/i686 implementation at run-time

Message ID 20150826155705.GA26329@intel.com
State Committed
Headers

Commit Message

Lu, Hongjiu Aug. 26, 2015, 3:57 p.m. UTC
  We detect i586 and i686 features at run-time by checking CX8 and CMOV
CPUID features bits.  We can use these information to select the best
implementation in ix86 multiarch.  HAS_I586/HAS_I686 is true if i586/i686
instructions are available on the processor.

Due to the reordering and the other nifty extensions in i686, it is not
really good to use heavily i586 optimized code on an i686.  It's better
to use i486 or i386 code if it isn't an i586.  USE_I586/USE_I686 is true
if i586/i686 implementation should be used for the processor.  USE_I586
is true only if i686 instructions aren't available.  If i686 instructions
are available, we always choose i686, i486 or i386 implementation, in
that order, and we never choose i586 implementation for i686-class
processors.

OK for master?

H.J.
--
	* sysdeps/i386/init-arch.h: New file.
	* sysdeps/i386/i486/init-arch.h: Likewise.
	* sysdeps/i386/i586/init-arch.h: Likewise.
	* sysdeps/i386/i686/init-arch.h: Likewise.
	* sysdeps/x86/cpu-features.c (init_cpu_features): Set bit_I586
	bit if CX8 is available.  Set bit_I686 bit if CMOV is available.
	* sysdeps/x86/cpu-features.h (bit_I586): New.
	(bit_I686): Likewise.
	(bit_CX8): Likewise.
	(bit_CMOV): Likewise.
	(index_CX8): Likewise.
	(index_CMOV): Likewise.
	(index_I586): Likewise.
	(index_I686): Likewise.
	(reg_CX8): Likewise.
	(reg_CMOV): Likewise.
	(HAS_I586): Defined as HAS_ARCH_FEATURE (I586) if i586 isn't
	available at compile-time.
	(HAS_I686): Defined as HAS_ARCH_FEATURE (I686) if i686 isn't
	available at compile-time.
	* sysdeps/x86/init-arch.h (USE_I586): New macro.
	(USE_I686): Likewise.
---
 sysdeps/i386/i486/init-arch.h | 19 +++++++++++++++++++
 sysdeps/i386/i586/init-arch.h | 19 +++++++++++++++++++
 sysdeps/i386/i686/init-arch.h | 19 +++++++++++++++++++
 sysdeps/i386/init-arch.h      | 19 +++++++++++++++++++
 sysdeps/x86/cpu-features.c    |  8 ++++++++
 sysdeps/x86/cpu-features.h    | 20 +++++++++++++++++---
 sysdeps/x86/init-arch.h       | 13 +++++++++++++
 7 files changed, 114 insertions(+), 3 deletions(-)
 create mode 100644 sysdeps/i386/i486/init-arch.h
 create mode 100644 sysdeps/i386/i586/init-arch.h
 create mode 100644 sysdeps/i386/i686/init-arch.h
 create mode 100644 sysdeps/i386/init-arch.h
  

Comments

Joseph Myers Aug. 26, 2015, 4:31 p.m. UTC | #1
On Wed, 26 Aug 2015, H.J. Lu wrote:

> 	* sysdeps/i386/init-arch.h: New file.
> 	* sysdeps/i386/i486/init-arch.h: Likewise.

Since glibc doesn't support i386 any more, you don't need both these files 
- just put the i486 version directly in sysdeps/i386/ (and in general, any 
i386 file overridden for i486 is dead unless some other file #includes it, 
and again subject to #includes i486 files can be moved directly into the 
i386 sysdeps directories).
  
Zack Weinberg Aug. 26, 2015, 5:47 p.m. UTC | #2
On Wed, Aug 26, 2015 at 12:31 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>
> Since glibc doesn't support i386 any more, you don't need both these files
> - just put the i486 version directly in sysdeps/i386/ (and in general, any
> i386 file overridden for i486 is dead unless some other file #includes it,
> and again subject to #includes i486 files can be moved directly into the
> i386 sysdeps directories).

Maybe, to reduce confusion, sysdeps/i386 should be renamed to
sysdeps/x86-32/ ?  I know that might be a giant pain.

zw
  
Roland McGrath Aug. 26, 2015, 6:15 p.m. UTC | #3
> On Wed, Aug 26, 2015 at 12:31 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> >
> > Since glibc doesn't support i386 any more, you don't need both these files
> > - just put the i486 version directly in sysdeps/i386/ (and in general, any
> > i386 file overridden for i486 is dead unless some other file #includes it,
> > and again subject to #includes i486 files can be moved directly into the
> > i386 sysdeps directories).
> 
> Maybe, to reduce confusion, sysdeps/i386 should be renamed to
> sysdeps/x86-32/ ?  I know that might be a giant pain.

I don't think there is any real confusion.  The first-order sysdeps/
subdirectory names use the configure tuple vocabulary, so it's i386
because that's the CPU name in the tuple.  Indeed using different
names would be a giant pain technically, but I also think it would
create confusion, not reduce it.
  
Joseph Myers Aug. 26, 2015, 7:51 p.m. UTC | #4
On Wed, 26 Aug 2015, Roland McGrath wrote:

> I don't think there is any real confusion.  The first-order sysdeps/
> subdirectory names use the configure tuple vocabulary, so it's i386
> because that's the CPU name in the tuple.  Indeed using different
> names would be a giant pain technically, but I also think it would
> create confusion, not reduce it.

It would be extremely easy technically.  The preconfigure fragments can 
implement whatever mapping they choose from configure tuples to 
base_machine and machine values - mapping i[4567]86 to x86-32 would be no 
different from mapping them to i386 as at present.  (I'm not saying that 
we *should* rename, just that it would not introduce any new technical 
complications.)
  
Ondrej Bilka Aug. 27, 2015, 12:10 p.m. UTC | #5
On Wed, Aug 26, 2015 at 08:57:05AM -0700, H.J. Lu wrote:
> We detect i586 and i686 features at run-time by checking CX8 and CMOV
> CPUID features bits.  We can use these information to select the best
> implementation in ix86 multiarch.  HAS_I586/HAS_I686 is true if i586/i686
> instructions are available on the processor.
> 
> Due to the reordering and the other nifty extensions in i686, it is not
> really good to use heavily i586 optimized code on an i686.  It's better
> to use i486 or i386 code if it isn't an i586.  USE_I586/USE_I686 is true
> if i586/i686 implementation should be used for the processor.  USE_I586
> is true only if i686 instructions aren't available.  If i686 instructions
> are available, we always choose i686, i486 or i386 implementation, in
> that order, and we never choose i586 implementation for i686-class
> processors.
> 
Here I couldn't test if its improvement so I won't help with that.

However as it covers historic extensions a better alternative would be
use corresponding mmx to sse2 variant. Question here is again how much
we support these.
  
H.J. Lu Aug. 27, 2015, 12:35 p.m. UTC | #6
On Thu, Aug 27, 2015 at 5:10 AM, Ondřej Bílka <neleai@seznam.cz> wrote:
> On Wed, Aug 26, 2015 at 08:57:05AM -0700, H.J. Lu wrote:
>> We detect i586 and i686 features at run-time by checking CX8 and CMOV
>> CPUID features bits.  We can use these information to select the best
>> implementation in ix86 multiarch.  HAS_I586/HAS_I686 is true if i586/i686
>> instructions are available on the processor.
>>
>> Due to the reordering and the other nifty extensions in i686, it is not
>> really good to use heavily i586 optimized code on an i686.  It's better
>> to use i486 or i386 code if it isn't an i586.  USE_I586/USE_I686 is true
>> if i586/i686 implementation should be used for the processor.  USE_I586
>> is true only if i686 instructions aren't available.  If i686 instructions
>> are available, we always choose i686, i486 or i386 implementation, in
>> that order, and we never choose i586 implementation for i686-class
>> processors.
>>
> Here I couldn't test if its improvement so I won't help with that.
>
> However as it covers historic extensions a better alternative would be
> use corresponding mmx to sse2 variant. Question here is again how much
> we support these.

The i486, i586, i686 version of multi-arch functions won't be used
on processors with SSE.  The preferred version will be used on
older processors.  It is an improvement for processors with SSE
as well as older processors.
  

Patch

diff --git a/sysdeps/i386/i486/init-arch.h b/sysdeps/i386/i486/init-arch.h
new file mode 100644
index 0000000..0c74ddc
--- /dev/null
+++ b/sysdeps/i386/i486/init-arch.h
@@ -0,0 +1,19 @@ 
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define MINIMUM_ISA 486
+#include <sysdeps/x86/init-arch.h>
diff --git a/sysdeps/i386/i586/init-arch.h b/sysdeps/i386/i586/init-arch.h
new file mode 100644
index 0000000..50c43a2
--- /dev/null
+++ b/sysdeps/i386/i586/init-arch.h
@@ -0,0 +1,19 @@ 
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define MINIMUM_ISA 586
+#include <sysdeps/x86/init-arch.h>
diff --git a/sysdeps/i386/i686/init-arch.h b/sysdeps/i386/i686/init-arch.h
new file mode 100644
index 0000000..b4a2735
--- /dev/null
+++ b/sysdeps/i386/i686/init-arch.h
@@ -0,0 +1,19 @@ 
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define MINIMUM_ISA 686
+#include <sysdeps/x86/init-arch.h>
diff --git a/sysdeps/i386/init-arch.h b/sysdeps/i386/init-arch.h
new file mode 100644
index 0000000..9adb451
--- /dev/null
+++ b/sysdeps/i386/init-arch.h
@@ -0,0 +1,19 @@ 
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define MINIMUM_ISA 386
+#include <sysdeps/x86/init-arch.h>
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 40575de..b03451d 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -150,6 +150,14 @@  init_cpu_features (struct cpu_features *cpu_features)
   else
     kind = arch_kind_other;
 
+  /* Support i586 if CX8 is available.  */
+  if (HAS_CPU_FEATURE (CX8))
+    cpu_features->feature[index_I586] |= bit_I586;
+
+  /* Support i686 if CMOV is available.  */
+  if (HAS_CPU_FEATURE (CMOV))
+    cpu_features->feature[index_I686] |= bit_I686;
+
   if (cpu_features->max_cpuid >= 7)
     __cpuid_count (7, 0,
 		   cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax,
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 6e70624..80edbee 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -31,10 +31,14 @@ 
 #define bit_AVX_Fast_Unaligned_Load	(1 << 11)
 #define bit_AVX512F_Usable		(1 << 12)
 #define bit_AVX512DQ_Usable		(1 << 13)
+#define bit_I586			(1 << 14)
+#define bit_I686			(1 << 15)
 
 /* CPUID Feature flags.  */
 
 /* COMMON_CPUID_INDEX_1.  */
+#define bit_CX8		(1 << 8)
+#define bit_CMOV	(1 << 15)
 #define bit_SSE2	(1 << 26)
 #define bit_SSSE3	(1 << 9)
 #define bit_SSE4_1	(1 << 19)
@@ -69,6 +73,8 @@ 
 # include <ifunc-defines.h>
 # include <rtld-global-offsets.h>
 
+# define index_CX8	COMMON_CPUID_INDEX_1*CPUID_SIZE+CPUID_EDX_OFFSET
+# define index_CMOV	COMMON_CPUID_INDEX_1*CPUID_SIZE+CPUID_EDX_OFFSET
 # define index_SSE2	COMMON_CPUID_INDEX_1*CPUID_SIZE+CPUID_EDX_OFFSET
 # define index_SSSE3	COMMON_CPUID_INDEX_1*CPUID_SIZE+CPUID_ECX_OFFSET
 # define index_SSE4_1	COMMON_CPUID_INDEX_1*CPUID_SIZE+CPUID_ECX_OFFSET
@@ -89,6 +95,8 @@ 
 # define index_AVX_Fast_Unaligned_Load	FEATURE_INDEX_1*FEATURE_SIZE
 # define index_AVX512F_Usable		FEATURE_INDEX_1*FEATURE_SIZE
 # define index_AVX512DQ_Usable		FEATURE_INDEX_1*FEATURE_SIZE
+# define index_I586			FEATURE_INDEX_1*FEATURE_SIZE
+# define index_I686			FEATURE_INDEX_1*FEATURE_SIZE
 
 # if defined (_LIBC) && !IS_IN (nonlib)
 #  ifdef __x86_64__
@@ -193,6 +201,8 @@  extern const struct cpu_features *__get_cpu_features (void)
 # define HAS_ARCH_FEATURE(name) \
   ((__get_cpu_features ()->feature[index_##name] & (bit_##name)) != 0)
 
+# define index_CX8		COMMON_CPUID_INDEX_1
+# define index_CMOV		COMMON_CPUID_INDEX_1
 # define index_SSE2		COMMON_CPUID_INDEX_1
 # define index_SSSE3		COMMON_CPUID_INDEX_1
 # define index_SSE4_1		COMMON_CPUID_INDEX_1
@@ -207,6 +217,8 @@  extern const struct cpu_features *__get_cpu_features (void)
 # define index_POPCOUNT		COMMON_CPUID_INDEX_1
 # define index_OSXSAVE		COMMON_CPUID_INDEX_1
 
+# define reg_CX8		edx
+# define reg_CMOV		edx
 # define reg_SSE2		edx
 # define reg_SSSE3		ecx
 # define reg_SSE4_1		ecx
@@ -234,6 +246,8 @@  extern const struct cpu_features *__get_cpu_features (void)
 # define index_AVX_Fast_Unaligned_Load	FEATURE_INDEX_1
 # define index_AVX512F_Usable		FEATURE_INDEX_1
 # define index_AVX512DQ_Usable		FEATURE_INDEX_1
+# define index_I586			FEATURE_INDEX_1
+# define index_I686			FEATURE_INDEX_1
 
 #endif	/* !__ASSEMBLER__ */
 
@@ -242,7 +256,7 @@  extern const struct cpu_features *__get_cpu_features (void)
 #elif defined __i586__ || defined __pentium__
 # define HAS_CPUID 1
 # define HAS_I586 1
-# define HAS_I686 0
+# define HAS_I686 HAS_ARCH_FEATURE (I686)
 #elif (defined __i686__ || defined __pentiumpro__		\
        || defined __pentium4__ || defined __nocona__		\
        || defined __atom__ || defined __core2__			\
@@ -261,8 +275,8 @@  extern const struct cpu_features *__get_cpu_features (void)
 # define HAS_I686 1
 #else
 # define HAS_CPUID 0
-# define HAS_I586 0
-# define HAS_I686 0
+# define HAS_I586 HAS_ARCH_FEATURE (I586)
+# define HAS_I686 HAS_ARCH_FEATURE (I686)
 #endif
 
 #endif  /* cpu_features_h */
diff --git a/sysdeps/x86/init-arch.h b/sysdeps/x86/init-arch.h
index 2b9988e..5ee0957 100644
--- a/sysdeps/x86/init-arch.h
+++ b/sysdeps/x86/init-arch.h
@@ -20,3 +20,16 @@ 
 #else
 # include <ldsodefs.h>
 #endif
+
+#ifndef __x86_64__
+/* Due to the reordering and the other nifty extensions in i686, it is
+   not really good to use heavily i586 optimized code on an i686.  It's
+   better to use i486 or i386 code if it isn't an i586.  */
+# if MINIMUM_ISA == 686
+#  define USE_I586 0
+#  define USE_I686 1
+# else
+#  define USE_I586 (HAS_ARCH_FEATURE (I586) && !HAS_ARCH_FEATURE (I686))
+#  define USE_I686 HAS_ARCH_FEATURE (I686)
+# endif
+#endif