--- a/mpn/x86_64/fat/fat.c 2015-11-01 16:19:48.000000000 +0100 +++ b/mpn/x86_64/fat/fat.c 2015-12-13 15:36:24.683304990 +0100 @@ -141,8 +141,49 @@ } } #endif +int +workaround_intel_skylake_bugs () +{ + char feature_string[49]; + char processor_name_string[49]; + const char *bad_cpus[] = {" G44", " G45", " G39" /* , "6600" */ }; + int i; + + /* Example strings: */ + /* "Intel(R) Pentium(R) CPU G4400 @ 3.30GHz" */ + /* "Intel(R) Core(TM) i5-6600K CPU @ 3.50GHz" */ + /* ^ ^ ^ */ + /* 0x80000002 0x80000003 0x80000004 */ + + /* We match out just the 0x80000003 part here. */ + + /* In there infinitive wisdom, Intel decided to use one register + order for the vendor string, and another for the processor + name string. We shuffle things about, rather than write a new + variant of our assembly cpuid. */ + + unsigned int eax, ebx, ecx, edx; + eax = __gmpn_cpuid (feature_string, 0x80000003); + ebx = ((unsigned int *)feature_string)[0]; + edx = ((unsigned int *)feature_string)[1]; + ecx = ((unsigned int *)feature_string)[2]; + + ((unsigned int *) (processor_name_string))[0] = eax; + ((unsigned int *) (processor_name_string))[1] = ebx; + ((unsigned int *) (processor_name_string))[2] = ecx; + ((unsigned int *) (processor_name_string))[3] = edx; + + processor_name_string[16] = 0; + + for (i = 0; i < sizeof (bad_cpus) / sizeof (char *); i++) + { + if (strstr (processor_name_string, bad_cpus[i]) != 0) + return 1; + } + return 0; +} typedef DECL_preinv_divrem_1 ((*preinv_divrem_1_t)); typedef DECL_preinv_mod_1 ((*preinv_mod_1_t)); @@ -331,11 +372,16 @@ case 0x9e: /* Cabylake */ CPUVEC_SETUP_core2; CPUVEC_SETUP_coreinhm; CPUVEC_SETUP_coreisbr; - CPUVEC_SETUP_coreihwl; - CPUVEC_SETUP_coreibwl; - CPUVEC_SETUP_skylake; + /* Some skylake pentiums also lack BMI1/BMI2. Let them appear as + * sandybridge for now + */ + if (!workaround_intel_skylake_bugs ()) { + CPUVEC_SETUP_coreihwl; + CPUVEC_SETUP_coreibwl; + CPUVEC_SETUP_skylake; + } break; } break;