xref: /netbsd/external/lgpl3/gmp/dist/mpn/x86_64/fat/fat.c (revision 122966f8)
1d25e02daSmrg /* x86_64 fat binary initializers.
24a1767b4Smrg 
34a1767b4Smrg    Contributed to the GNU project by Kevin Ryde (original x86_32 code) and
44a1767b4Smrg    Torbjorn Granlund (port to x86_64)
54a1767b4Smrg 
64a1767b4Smrg    THE FUNCTIONS AND VARIABLES IN THIS FILE ARE FOR INTERNAL USE ONLY.
74a1767b4Smrg    THEY'RE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
84a1767b4Smrg    COMPLETELY IN FUTURE GNU MP RELEASES.
94a1767b4Smrg 
10671ea119Smrg Copyright 2003, 2004, 2009, 2011-2015, 2017 Free Software Foundation, Inc.
114a1767b4Smrg 
124a1767b4Smrg This file is part of the GNU MP Library.
134a1767b4Smrg 
144a1767b4Smrg The GNU MP Library is free software; you can redistribute it and/or modify
15f81b1c5bSmrg it under the terms of either:
16f81b1c5bSmrg 
17f81b1c5bSmrg   * the GNU Lesser General Public License as published by the Free
18f81b1c5bSmrg     Software Foundation; either version 3 of the License, or (at your
194a1767b4Smrg     option) any later version.
204a1767b4Smrg 
21f81b1c5bSmrg or
22f81b1c5bSmrg 
23f81b1c5bSmrg   * the GNU General Public License as published by the Free Software
24f81b1c5bSmrg     Foundation; either version 2 of the License, or (at your option) any
25f81b1c5bSmrg     later version.
26f81b1c5bSmrg 
27f81b1c5bSmrg or both in parallel, as here.
28f81b1c5bSmrg 
294a1767b4Smrg The GNU MP Library is distributed in the hope that it will be useful, but
304a1767b4Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31f81b1c5bSmrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
32f81b1c5bSmrg for more details.
334a1767b4Smrg 
34f81b1c5bSmrg You should have received copies of the GNU General Public License and the
35f81b1c5bSmrg GNU Lesser General Public License along with the GNU MP Library.  If not,
36f81b1c5bSmrg see https://www.gnu.org/licenses/.  */
374a1767b4Smrg 
384a1767b4Smrg #include <stdio.h>    /* for printf */
394a1767b4Smrg #include <stdlib.h>   /* for getenv */
404a1767b4Smrg #include <string.h>
414a1767b4Smrg 
424a1767b4Smrg #include "gmp-impl.h"
434a1767b4Smrg 
444a1767b4Smrg /* Change this to "#define TRACE(x) x" for some traces. */
454a1767b4Smrg #define TRACE(x)
464a1767b4Smrg 
474a1767b4Smrg 
484a1767b4Smrg /* fat_entry.asm */
49d25e02daSmrg long __gmpn_cpuid (char [12], int);
50d25e02daSmrg 
51d25e02daSmrg 
52d25e02daSmrg #if WANT_FAKE_CPUID
53d25e02daSmrg /* The "name"s in the table are values for the GMP_CPU_TYPE environment
54d25e02daSmrg    variable.  Anything can be used, but for now it's the canonical cpu types
55d25e02daSmrg    as per config.guess/config.sub.  */
56d25e02daSmrg 
57d25e02daSmrg #define __gmpn_cpuid            fake_cpuid
58d25e02daSmrg 
59d25e02daSmrg #define MAKE_FMS(family, model)						\
60d25e02daSmrg   ((((family) & 0xf) << 8) + (((family) & 0xff0) << 20)			\
61d25e02daSmrg    + (((model) & 0xf) << 4) + (((model)  &  0xf0) << 12))
62d25e02daSmrg 
63d25e02daSmrg static struct {
64d25e02daSmrg   const char  *name;
65f81b1c5bSmrg   const char  *vendor;
66d25e02daSmrg   unsigned    fms;
67d25e02daSmrg } fake_cpuid_table[] = {
68d25e02daSmrg   { "core2",      "GenuineIntel", MAKE_FMS (6, 0xf) },
69f81b1c5bSmrg   { "nehalem",    "GenuineIntel", MAKE_FMS (6, 0x1a) },
70f81b1c5bSmrg   { "nhm",        "GenuineIntel", MAKE_FMS (6, 0x1a) },
71d25e02daSmrg   { "atom",       "GenuineIntel", MAKE_FMS (6, 0x1c) },
72f81b1c5bSmrg   { "westmere",   "GenuineIntel", MAKE_FMS (6, 0x25) },
73f81b1c5bSmrg   { "wsm",        "GenuineIntel", MAKE_FMS (6, 0x25) },
74f81b1c5bSmrg   { "sandybridge","GenuineIntel", MAKE_FMS (6, 0x2a) },
75f81b1c5bSmrg   { "sbr",        "GenuineIntel", MAKE_FMS (6, 0x2a) },
76f81b1c5bSmrg   { "silvermont", "GenuineIntel", MAKE_FMS (6, 0x37) },
77f81b1c5bSmrg   { "slm",        "GenuineIntel", MAKE_FMS (6, 0x37) },
78f81b1c5bSmrg   { "haswell",    "GenuineIntel", MAKE_FMS (6, 0x3c) },
79f81b1c5bSmrg   { "hwl",        "GenuineIntel", MAKE_FMS (6, 0x3c) },
80f81b1c5bSmrg   { "broadwell",  "GenuineIntel", MAKE_FMS (6, 0x3d) },
81f81b1c5bSmrg   { "bwl",        "GenuineIntel", MAKE_FMS (6, 0x3d) },
82f81b1c5bSmrg   { "skylake",    "GenuineIntel", MAKE_FMS (6, 0x5e) },
83f81b1c5bSmrg   { "sky",        "GenuineIntel", MAKE_FMS (6, 0x5e) },
84d25e02daSmrg   { "pentium4",   "GenuineIntel", MAKE_FMS (15, 3) },
85d25e02daSmrg 
86d25e02daSmrg   { "k8",         "AuthenticAMD", MAKE_FMS (15, 0) },
87d25e02daSmrg   { "k10",        "AuthenticAMD", MAKE_FMS (16, 0) },
88d25e02daSmrg   { "bobcat",     "AuthenticAMD", MAKE_FMS (20, 1) },
89d25e02daSmrg   { "bulldozer",  "AuthenticAMD", MAKE_FMS (21, 1) },
90f81b1c5bSmrg   { "piledriver", "AuthenticAMD", MAKE_FMS (21, 2) },
91f81b1c5bSmrg   { "steamroller","AuthenticAMD", MAKE_FMS (21, 0x30) },
92f81b1c5bSmrg   { "excavator",  "AuthenticAMD", MAKE_FMS (21, 0x60) },
93f81b1c5bSmrg   { "jaguar",     "AuthenticAMD", MAKE_FMS (22, 1) },
94671ea119Smrg   { "zen",        "AuthenticAMD", MAKE_FMS (23, 1) },
95d25e02daSmrg 
96d25e02daSmrg   { "nano",       "CentaurHauls", MAKE_FMS (6, 15) },
97d25e02daSmrg };
98d25e02daSmrg 
99d25e02daSmrg static int
fake_cpuid_lookup(void)100d25e02daSmrg fake_cpuid_lookup (void)
101d25e02daSmrg {
102d25e02daSmrg   char  *s;
103d25e02daSmrg   int   i;
104d25e02daSmrg 
105d25e02daSmrg   s = getenv ("GMP_CPU_TYPE");
106d25e02daSmrg   if (s == NULL)
107d25e02daSmrg     {
108d25e02daSmrg       printf ("Need GMP_CPU_TYPE environment variable for fake cpuid\n");
109d25e02daSmrg       abort ();
110d25e02daSmrg     }
111d25e02daSmrg 
112d25e02daSmrg   for (i = 0; i < numberof (fake_cpuid_table); i++)
113d25e02daSmrg     if (strcmp (s, fake_cpuid_table[i].name) == 0)
114d25e02daSmrg       return i;
115d25e02daSmrg 
116d25e02daSmrg   printf ("GMP_CPU_TYPE=%s unknown\n", s);
117d25e02daSmrg   abort ();
118d25e02daSmrg }
119d25e02daSmrg 
120d25e02daSmrg static long
fake_cpuid(char dst[12],unsigned int id)121f81b1c5bSmrg fake_cpuid (char dst[12], unsigned int id)
122d25e02daSmrg {
123d25e02daSmrg   int  i = fake_cpuid_lookup();
124d25e02daSmrg 
125d25e02daSmrg   switch (id) {
126d25e02daSmrg   case 0:
127d25e02daSmrg     memcpy (dst, fake_cpuid_table[i].vendor, 12);
128d25e02daSmrg     return 0;
129d25e02daSmrg   case 1:
130d25e02daSmrg     return fake_cpuid_table[i].fms;
131f81b1c5bSmrg   case 7:
132f81b1c5bSmrg     dst[0] = 0xff;				/* BMI1, AVX2, etc */
133f81b1c5bSmrg     dst[1] = 0xff;				/* BMI2, etc */
134f81b1c5bSmrg     return 0;
135f81b1c5bSmrg   case 0x80000001:
136f81b1c5bSmrg     dst[4 + 29 / 8] = (1 << (29 % 8));		/* "long" mode */
137f81b1c5bSmrg     return 0;
138d25e02daSmrg   default:
139d25e02daSmrg     printf ("fake_cpuid(): oops, unknown id %d\n", id);
140d25e02daSmrg     abort ();
141d25e02daSmrg   }
142d25e02daSmrg }
143d25e02daSmrg #endif
1444a1767b4Smrg 
1454a1767b4Smrg 
1464a1767b4Smrg typedef DECL_preinv_divrem_1 ((*preinv_divrem_1_t));
1474a1767b4Smrg typedef DECL_preinv_mod_1    ((*preinv_mod_1_t));
1484a1767b4Smrg 
1494a1767b4Smrg struct cpuvec_t __gmpn_cpuvec = {
1504a1767b4Smrg   __MPN(add_n_init),
151d25e02daSmrg   __MPN(addlsh1_n_init),
152d25e02daSmrg   __MPN(addlsh2_n_init),
1534a1767b4Smrg   __MPN(addmul_1_init),
154d25e02daSmrg   __MPN(addmul_2_init),
155d25e02daSmrg   __MPN(bdiv_dbm1c_init),
156f81b1c5bSmrg   __MPN(cnd_add_n_init),
157f81b1c5bSmrg   __MPN(cnd_sub_n_init),
158d25e02daSmrg   __MPN(com_init),
1594a1767b4Smrg   __MPN(copyd_init),
1604a1767b4Smrg   __MPN(copyi_init),
1614a1767b4Smrg   __MPN(divexact_1_init),
1624a1767b4Smrg   __MPN(divrem_1_init),
163671ea119Smrg   __MPN(gcd_11_init),
1644a1767b4Smrg   __MPN(lshift_init),
165d25e02daSmrg   __MPN(lshiftc_init),
1664a1767b4Smrg   __MPN(mod_1_init),
167d25e02daSmrg   __MPN(mod_1_1p_init),
168d25e02daSmrg   __MPN(mod_1_1p_cps_init),
169d25e02daSmrg   __MPN(mod_1s_2p_init),
170d25e02daSmrg   __MPN(mod_1s_2p_cps_init),
171d25e02daSmrg   __MPN(mod_1s_4p_init),
172d25e02daSmrg   __MPN(mod_1s_4p_cps_init),
1734a1767b4Smrg   __MPN(mod_34lsub1_init),
1744a1767b4Smrg   __MPN(modexact_1c_odd_init),
1754a1767b4Smrg   __MPN(mul_1_init),
1764a1767b4Smrg   __MPN(mul_basecase_init),
177d25e02daSmrg   __MPN(mullo_basecase_init),
1784a1767b4Smrg   __MPN(preinv_divrem_1_init),
1794a1767b4Smrg   __MPN(preinv_mod_1_init),
180d25e02daSmrg   __MPN(redc_1_init),
181d25e02daSmrg   __MPN(redc_2_init),
1824a1767b4Smrg   __MPN(rshift_init),
1834a1767b4Smrg   __MPN(sqr_basecase_init),
1844a1767b4Smrg   __MPN(sub_n_init),
185d25e02daSmrg   __MPN(sublsh1_n_init),
1864a1767b4Smrg   __MPN(submul_1_init),
1874a1767b4Smrg   0
1884a1767b4Smrg };
1894a1767b4Smrg 
190d25e02daSmrg int __gmpn_cpuvec_initialized = 0;
1914a1767b4Smrg 
1924a1767b4Smrg /* The following setups start with generic x86, then overwrite with
1934a1767b4Smrg    specifics for a chip, and higher versions of that chip.
1944a1767b4Smrg 
1954a1767b4Smrg    The arrangement of the setups here will normally be the same as the $path
1964a1767b4Smrg    selections in configure.in for the respective chips.
1974a1767b4Smrg 
1984a1767b4Smrg    This code is reentrant and thread safe.  We always calculate the same
1994a1767b4Smrg    decided_cpuvec, so if two copies of the code are running it doesn't
2004a1767b4Smrg    matter which completes first, both write the same to __gmpn_cpuvec.
2014a1767b4Smrg 
2024a1767b4Smrg    We need to go via decided_cpuvec because if one thread has completed
2034a1767b4Smrg    __gmpn_cpuvec then it may be making use of the threshold values in that
2044a1767b4Smrg    vector.  If another thread is still running __gmpn_cpuvec_init then we
2054a1767b4Smrg    don't want it to write different values to those fields since some of the
2064a1767b4Smrg    asm routines only operate correctly up to their own defined threshold,
2074a1767b4Smrg    not an arbitrary value.  */
2084a1767b4Smrg 
209f81b1c5bSmrg static int
gmp_workaround_skylake_cpuid_bug()210f81b1c5bSmrg gmp_workaround_skylake_cpuid_bug ()
211f81b1c5bSmrg {
212f81b1c5bSmrg   char feature_string[49];
213f81b1c5bSmrg   char processor_name_string[49];
214f81b1c5bSmrg   static const char *bad_cpus[] = {" G44", " G45", " G39" /* , "6600" */ };
215f81b1c5bSmrg   int i;
216f81b1c5bSmrg 
217f81b1c5bSmrg   /* Example strings:                                   */
218f81b1c5bSmrg   /* "Intel(R) Pentium(R) CPU G4400 @ 3.30GHz"          */
219f81b1c5bSmrg   /* "Intel(R) Core(TM) i5-6600K CPU @ 3.50GHz"         */
220f81b1c5bSmrg   /*                  ^               ^               ^ */
221f81b1c5bSmrg   /*     0x80000002       0x80000003      0x80000004    */
222f81b1c5bSmrg   /* We match out just the 0x80000003 part here. */
223f81b1c5bSmrg 
224f81b1c5bSmrg   /* In their infinitive wisdom, Intel decided to use one register order for
225f81b1c5bSmrg      the vendor string, and another for the processor name string.  We shuffle
226f81b1c5bSmrg      things about here, rather than write a new variant of our assembly cpuid.
227f81b1c5bSmrg   */
228f81b1c5bSmrg 
229f81b1c5bSmrg   unsigned int eax, ebx, ecx, edx;
230f81b1c5bSmrg   eax = __gmpn_cpuid (feature_string, 0x80000003);
231f81b1c5bSmrg   ebx = ((unsigned int *)feature_string)[0];
232f81b1c5bSmrg   edx = ((unsigned int *)feature_string)[1];
233f81b1c5bSmrg   ecx = ((unsigned int *)feature_string)[2];
234f81b1c5bSmrg 
235f81b1c5bSmrg   ((unsigned int *) (processor_name_string))[0] = eax;
236f81b1c5bSmrg   ((unsigned int *) (processor_name_string))[1] = ebx;
237f81b1c5bSmrg   ((unsigned int *) (processor_name_string))[2] = ecx;
238f81b1c5bSmrg   ((unsigned int *) (processor_name_string))[3] = edx;
239f81b1c5bSmrg 
240f81b1c5bSmrg   processor_name_string[16] = 0;
241f81b1c5bSmrg 
242f81b1c5bSmrg   for (i = 0; i < sizeof (bad_cpus) / sizeof (char *); i++)
243f81b1c5bSmrg     {
244f81b1c5bSmrg       if (strstr (processor_name_string, bad_cpus[i]) != 0)
245f81b1c5bSmrg 	return 1;
246f81b1c5bSmrg     }
247f81b1c5bSmrg   return 0;
248f81b1c5bSmrg }
249f81b1c5bSmrg 
250f81b1c5bSmrg enum {BMI2_BIT = 8};
251f81b1c5bSmrg 
2524a1767b4Smrg void
__gmpn_cpuvec_init(void)2534a1767b4Smrg __gmpn_cpuvec_init (void)
2544a1767b4Smrg {
2554a1767b4Smrg   struct cpuvec_t  decided_cpuvec;
256d25e02daSmrg   char vendor_string[13];
257d25e02daSmrg   char dummy_string[12];
258d25e02daSmrg   long fms;
259d25e02daSmrg   int family, model;
2604a1767b4Smrg 
2614a1767b4Smrg   TRACE (printf ("__gmpn_cpuvec_init:\n"));
2624a1767b4Smrg 
2634a1767b4Smrg   memset (&decided_cpuvec, '\0', sizeof (decided_cpuvec));
2644a1767b4Smrg 
2654a1767b4Smrg   CPUVEC_SETUP_x86_64;
2664a1767b4Smrg   CPUVEC_SETUP_fat;
2674a1767b4Smrg 
2684a1767b4Smrg   __gmpn_cpuid (vendor_string, 0);
2694a1767b4Smrg   vendor_string[12] = 0;
2704a1767b4Smrg 
2714a1767b4Smrg   fms = __gmpn_cpuid (dummy_string, 1);
2724a1767b4Smrg   family = ((fms >> 8) & 0xf) + ((fms >> 20) & 0xff);
2734a1767b4Smrg   model = ((fms >> 4) & 0xf) + ((fms >> 12) & 0xf0);
2744a1767b4Smrg 
275d25e02daSmrg   /* Check extended feature flags */
276d25e02daSmrg   __gmpn_cpuid (dummy_string, 0x80000001);
277d25e02daSmrg   if ((dummy_string[4 + 29 / 8] & (1 << (29 % 8))) == 0)
278d25e02daSmrg     abort (); /* longmode-capable-bit turned off! */
279d25e02daSmrg 
280d25e02daSmrg   /*********************************************************/
281d25e02daSmrg   /*** WARNING: keep this list in sync with config.guess ***/
282d25e02daSmrg   /*********************************************************/
2834a1767b4Smrg   if (strcmp (vendor_string, "GenuineIntel") == 0)
2844a1767b4Smrg     {
2854a1767b4Smrg       switch (family)
2864a1767b4Smrg 	{
287d25e02daSmrg 	case 6:
288d25e02daSmrg 	  switch (model)
289d25e02daSmrg 	    {
290d25e02daSmrg 	    case 0x0f:		/* Conroe Merom Kentsfield Allendale */
291d25e02daSmrg 	    case 0x10:
292d25e02daSmrg 	    case 0x11:
293d25e02daSmrg 	    case 0x12:
294d25e02daSmrg 	    case 0x13:
295d25e02daSmrg 	    case 0x14:
296d25e02daSmrg 	    case 0x15:
297d25e02daSmrg 	    case 0x16:
298d25e02daSmrg 	    case 0x17:		/* PNR Wolfdale Yorkfield */
299d25e02daSmrg 	    case 0x18:
300d25e02daSmrg 	    case 0x19:
301d25e02daSmrg 	    case 0x1d:		/* PNR Dunnington */
302d25e02daSmrg 	      CPUVEC_SETUP_core2;
3034a1767b4Smrg 	      break;
3044a1767b4Smrg 
305d25e02daSmrg 	    case 0x1c:		/* Atom Silverthorne */
306d25e02daSmrg 	    case 0x26:		/* Atom Lincroft */
307d25e02daSmrg 	    case 0x27:		/* Atom Saltwell? */
308d25e02daSmrg 	    case 0x36:		/* Atom Cedarview/Saltwell */
3094a1767b4Smrg 	      CPUVEC_SETUP_atom;
310d25e02daSmrg 	      break;
311d25e02daSmrg 
312d25e02daSmrg 	    case 0x1a:		/* NHM Gainestown */
313d25e02daSmrg 	    case 0x1b:
314d25e02daSmrg 	    case 0x1e:		/* NHM Lynnfield/Jasper */
315d25e02daSmrg 	    case 0x1f:
316d25e02daSmrg 	    case 0x20:
317d25e02daSmrg 	    case 0x21:
318d25e02daSmrg 	    case 0x22:
319d25e02daSmrg 	    case 0x23:
320d25e02daSmrg 	    case 0x24:
321d25e02daSmrg 	    case 0x25:		/* WSM Clarkdale/Arrandale */
322d25e02daSmrg 	    case 0x28:
323d25e02daSmrg 	    case 0x29:
324d25e02daSmrg 	    case 0x2b:
325d25e02daSmrg 	    case 0x2c:		/* WSM Gulftown */
326d25e02daSmrg 	    case 0x2e:		/* NHM Beckton */
327d25e02daSmrg 	    case 0x2f:		/* WSM Eagleton */
328671ea119Smrg 	      CPUVEC_SETUP_core2;
329671ea119Smrg 	      CPUVEC_SETUP_coreinhm;
330671ea119Smrg 	      break;
331671ea119Smrg 
332f81b1c5bSmrg 	    case 0x37:		/* Silvermont */
333f81b1c5bSmrg 	    case 0x4a:		/* Silvermont */
334f81b1c5bSmrg 	    case 0x4c:		/* Airmont */
335f81b1c5bSmrg 	    case 0x4d:		/* Silvermont/Avoton */
336f81b1c5bSmrg 	    case 0x5a:		/* Silvermont */
337671ea119Smrg 	      CPUVEC_SETUP_atom;
338671ea119Smrg 	      CPUVEC_SETUP_silvermont;
339671ea119Smrg 	      break;
340671ea119Smrg 
341f81b1c5bSmrg 	    case 0x5c:		/* Goldmont */
342f81b1c5bSmrg 	    case 0x5f:		/* Goldmont */
343671ea119Smrg 	    case 0x7a:		/* Goldmont Plus */
344671ea119Smrg 	      CPUVEC_SETUP_atom;
345671ea119Smrg 	      CPUVEC_SETUP_silvermont;
346671ea119Smrg 	      CPUVEC_SETUP_goldmont;
347d25e02daSmrg 	      break;
348d25e02daSmrg 
349d25e02daSmrg 	    case 0x2a:		/* SB */
350d25e02daSmrg 	    case 0x2d:		/* SBC-EP */
351d25e02daSmrg 	    case 0x3a:		/* IBR */
352f81b1c5bSmrg 	    case 0x3e:		/* IBR Ivytown */
353d25e02daSmrg 	      CPUVEC_SETUP_core2;
354d25e02daSmrg 	      CPUVEC_SETUP_coreinhm;
355d25e02daSmrg 	      CPUVEC_SETUP_coreisbr;
356d25e02daSmrg 	      break;
357f81b1c5bSmrg 	    case 0x3c:		/* Haswell client */
358f81b1c5bSmrg 	    case 0x3f:		/* Haswell server */
359f81b1c5bSmrg 	    case 0x45:		/* Haswell ULT */
360f81b1c5bSmrg 	    case 0x46:		/* Crystal Well */
361f81b1c5bSmrg 	      CPUVEC_SETUP_core2;
362f81b1c5bSmrg 	      CPUVEC_SETUP_coreinhm;
363f81b1c5bSmrg 	      CPUVEC_SETUP_coreisbr;
364f81b1c5bSmrg 	      /* Some Haswells lack BMI2.  Let them appear as Sandybridges for
365f81b1c5bSmrg 		 now.  */
366f81b1c5bSmrg 	      __gmpn_cpuid (dummy_string, 7);
367f81b1c5bSmrg 	      if ((dummy_string[0 + BMI2_BIT / 8] & (1 << (BMI2_BIT % 8))) == 0)
368f81b1c5bSmrg 		break;
369f81b1c5bSmrg 	      CPUVEC_SETUP_coreihwl;
370f81b1c5bSmrg 	      break;
371f81b1c5bSmrg 	    case 0x3d:		/* Broadwell */
372f81b1c5bSmrg 	    case 0x47:		/* Broadwell */
373f81b1c5bSmrg 	    case 0x4f:		/* Broadwell server */
374f81b1c5bSmrg 	    case 0x56:		/* Broadwell microserver */
375f81b1c5bSmrg 	      CPUVEC_SETUP_core2;
376f81b1c5bSmrg 	      CPUVEC_SETUP_coreinhm;
377f81b1c5bSmrg 	      CPUVEC_SETUP_coreisbr;
378f81b1c5bSmrg 	      if ((dummy_string[0 + BMI2_BIT / 8] & (1 << (BMI2_BIT % 8))) == 0)
379f81b1c5bSmrg 		break;
380f81b1c5bSmrg 	      CPUVEC_SETUP_coreihwl;
381f81b1c5bSmrg 	      CPUVEC_SETUP_coreibwl;
382f81b1c5bSmrg 	      break;
383f81b1c5bSmrg 	    case 0x4e:		/* Skylake client */
384f81b1c5bSmrg 	    case 0x55:		/* Skylake server */
385f81b1c5bSmrg 	    case 0x5e:		/* Skylake */
386f81b1c5bSmrg 	    case 0x8e:		/* Kabylake */
387f81b1c5bSmrg 	    case 0x9e:		/* Kabylake */
388f81b1c5bSmrg 	      CPUVEC_SETUP_core2;
389f81b1c5bSmrg 	      CPUVEC_SETUP_coreinhm;
390f81b1c5bSmrg 	      CPUVEC_SETUP_coreisbr;
391f81b1c5bSmrg 	      if ((dummy_string[0 + BMI2_BIT / 8] & (1 << (BMI2_BIT % 8))) == 0)
392f81b1c5bSmrg 		break;
393f81b1c5bSmrg 	      if (gmp_workaround_skylake_cpuid_bug ())
394f81b1c5bSmrg 		break;
395f81b1c5bSmrg 	      CPUVEC_SETUP_coreihwl;
396f81b1c5bSmrg 	      CPUVEC_SETUP_coreibwl;
397f81b1c5bSmrg 	      CPUVEC_SETUP_skylake;
398f81b1c5bSmrg 	      break;
399d25e02daSmrg 	    }
4004a1767b4Smrg 	  break;
4014a1767b4Smrg 
4024a1767b4Smrg 	case 15:
4034a1767b4Smrg 	  CPUVEC_SETUP_pentium4;
4044a1767b4Smrg 	  break;
4054a1767b4Smrg 	}
4064a1767b4Smrg     }
4074a1767b4Smrg   else if (strcmp (vendor_string, "AuthenticAMD") == 0)
4084a1767b4Smrg     {
4094a1767b4Smrg       switch (family)
4104a1767b4Smrg 	{
411d25e02daSmrg 	case 0x0f:		/* k8 */
412d25e02daSmrg 	case 0x11:		/* "fam 11h", mix of k8 and k10 */
413d25e02daSmrg 	case 0x13:
414d25e02daSmrg 	  CPUVEC_SETUP_k8;
4154a1767b4Smrg 	  break;
416d25e02daSmrg 
417d25e02daSmrg 	case 0x10:		/* k10 */
418d25e02daSmrg 	case 0x12:		/* k10 (llano) */
419d25e02daSmrg 	  CPUVEC_SETUP_k8;
420d25e02daSmrg 	  CPUVEC_SETUP_k10;
4214a1767b4Smrg 	  break;
422d25e02daSmrg 
423d25e02daSmrg 	case 0x14:		/* bobcat */
424671ea119Smrg 	  CPUVEC_SETUP_k8;
425671ea119Smrg 	  CPUVEC_SETUP_k10;
426671ea119Smrg 	  CPUVEC_SETUP_bt1;
427671ea119Smrg 	  break;
428671ea119Smrg 
429f81b1c5bSmrg 	case 0x16:		/* jaguar */
430d25e02daSmrg 	  CPUVEC_SETUP_k8;
431d25e02daSmrg 	  CPUVEC_SETUP_k10;
432671ea119Smrg 	  CPUVEC_SETUP_bt1;
433671ea119Smrg 	  CPUVEC_SETUP_bt2;
434d25e02daSmrg 	  break;
435d25e02daSmrg 
436f81b1c5bSmrg 	case 0x15:		/* bulldozer, piledriver, steamroller, excavator */
437d25e02daSmrg 	  CPUVEC_SETUP_k8;
438d25e02daSmrg 	  CPUVEC_SETUP_k10;
439d25e02daSmrg 	  CPUVEC_SETUP_bd1;
440671ea119Smrg 	  break;
441671ea119Smrg 
442671ea119Smrg 	case 0x17:		/* zen */
443*122966f8Smrg 	case 0x19:		/* zen3 */
444671ea119Smrg 	  CPUVEC_SETUP_zen;
445671ea119Smrg 	  break;
4464a1767b4Smrg 	}
4474a1767b4Smrg     }
448d25e02daSmrg   else if (strcmp (vendor_string, "CentaurHauls") == 0)
449d25e02daSmrg     {
450d25e02daSmrg       switch (family)
451d25e02daSmrg 	{
452d25e02daSmrg 	case 6:
453d25e02daSmrg 	  if (model >= 15)
454d25e02daSmrg 	    CPUVEC_SETUP_nano;
455d25e02daSmrg 	  break;
456d25e02daSmrg 	}
4574a1767b4Smrg     }
4584a1767b4Smrg 
4594a1767b4Smrg   /* There's no x86 generic mpn_preinv_divrem_1 or mpn_preinv_mod_1.
4604a1767b4Smrg      Instead default to the plain versions from whichever CPU we detected.
4614a1767b4Smrg      The function arguments are compatible, no need for any glue code.  */
4624a1767b4Smrg   if (decided_cpuvec.preinv_divrem_1 == NULL)
4634a1767b4Smrg     decided_cpuvec.preinv_divrem_1 =(preinv_divrem_1_t)decided_cpuvec.divrem_1;
4644a1767b4Smrg   if (decided_cpuvec.preinv_mod_1 == NULL)
4654a1767b4Smrg     decided_cpuvec.preinv_mod_1    =(preinv_mod_1_t)   decided_cpuvec.mod_1;
4664a1767b4Smrg 
4674a1767b4Smrg   ASSERT_CPUVEC (decided_cpuvec);
4684a1767b4Smrg   CPUVEC_INSTALL (decided_cpuvec);
4694a1767b4Smrg 
4704a1767b4Smrg   /* Set this once the threshold fields are ready.
4714a1767b4Smrg      Use volatile to prevent it getting moved.  */
472d25e02daSmrg   *((volatile int *) &__gmpn_cpuvec_initialized) = 1;
4734a1767b4Smrg }
474