#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include <stdlib.h>
const char *host_detect_local_cpu (int argc, const char **argv);
#ifdef GCC_VERSION
#define cpuid(num,a,b,c,d) \
asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
: "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
: "0" (num))
#define bit_CMPXCHG8B (1 << 8)
#define bit_CMOV (1 << 15)
#define bit_MMX (1 << 23)
#define bit_SSE (1 << 25)
#define bit_SSE2 (1 << 26)
#define bit_SSE3 (1 << 0)
#define bit_CMPXCHG16B (1 << 13)
#define bit_3DNOW (1 << 31)
#define bit_3DNOWP (1 << 30)
#define bit_LM (1 << 29)
const char *host_detect_local_cpu (int argc, const char **argv)
{
const char *cpu = NULL;
enum processor_type processor = PROCESSOR_I386;
unsigned int eax, ebx, ecx, edx;
unsigned int max_level;
unsigned int vendor;
unsigned int ext_level;
unsigned char has_mmx = 0, has_3dnow = 0, has_3dnowp = 0, has_sse = 0;
unsigned char has_sse2 = 0, has_sse3 = 0, has_cmov = 0;
unsigned char has_longmode = 0, has_cmpxchg8b = 0;
unsigned char is_amd = 0;
unsigned int family = 0;
bool arch;
if (argc < 1)
return NULL;
arch = strcmp (argv[0], "arch") == 0;
if (!arch && strcmp (argv[0], "tune"))
return NULL;
#ifndef __x86_64__
asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
"pushl %0; popfl; pushfl; popl %0; popfl"
: "=&r" (eax), "=&r" (ebx)
: "i" (0x00200000));
if (((eax ^ ebx) & 0x00200000) == 0)
goto done;
#endif
processor = PROCESSOR_PENTIUM;
cpuid (0, eax, ebx, ecx, edx);
max_level = eax;
vendor = ebx;
if (max_level == 0)
goto done;
cpuid (1, eax, ebx, ecx, edx);
has_cmpxchg8b = !!(edx & bit_CMPXCHG8B);
has_cmov = !!(edx & bit_CMOV);
has_mmx = !!(edx & bit_MMX);
has_sse = !!(edx & bit_SSE);
has_sse2 = !!(edx & bit_SSE2);
has_sse3 = !!(ecx & bit_SSE3);
family = (eax >> 8) & ~(1 << 4);
cpuid (0x80000000, eax, ebx, ecx, edx);
ext_level = eax;
if (ext_level >= 0x80000000)
{
cpuid (0x80000001, eax, ebx, ecx, edx);
has_3dnow = !!(edx & bit_3DNOW);
has_3dnowp = !!(edx & bit_3DNOWP);
has_longmode = !!(edx & bit_LM);
}
is_amd = vendor == *(unsigned int*)"Auth";
if (is_amd)
{
if (has_mmx)
processor = PROCESSOR_K6;
if (has_3dnowp)
processor = PROCESSOR_ATHLON;
if (has_sse2 || has_longmode)
processor = PROCESSOR_K8;
}
else
{
switch (family)
{
case 5:
break;
case 6:
processor = PROCESSOR_PENTIUMPRO;
break;
case 15:
processor = PROCESSOR_PENTIUM4;
break;
default:
if (arch)
{
if (has_sse3)
{
if (has_longmode)
cpu = "nocona";
else
cpu = "prescott";
}
else if (has_sse2)
cpu = "pentium4";
else if (has_cmov)
cpu = "pentiumpro";
else if (has_mmx)
cpu = "pentium-mmx";
else if (has_cmpxchg8b)
cpu = "pentium";
else
cpu = "i386";
}
else
cpu = "generic";
goto done;
break;
}
}
switch (processor)
{
case PROCESSOR_I386:
cpu = "i386";
break;
case PROCESSOR_I486:
cpu = "i486";
break;
case PROCESSOR_PENTIUM:
if (has_mmx)
cpu = "pentium-mmx";
else
cpu = "pentium";
break;
case PROCESSOR_PENTIUMPRO:
if (arch)
{
if (has_sse3)
{
if (has_longmode)
{
cpu = "nocona";
}
else
{
cpu = "prescott";
}
}
else if (has_sse2)
{
cpu = "pentium4";
}
else if (has_sse)
{
cpu = "pentium3";
}
else if (has_mmx)
{
cpu = "pentium2";
}
else
{
cpu = "pentiumpro";
}
}
else
{
cpu = "generic";
}
break;
case PROCESSOR_K6:
if (has_3dnow)
cpu = "k6-3";
else
cpu = "k6";
break;
case PROCESSOR_ATHLON:
if (has_sse)
cpu = "athlon-4";
else
cpu = "athlon";
break;
case PROCESSOR_PENTIUM4:
if (has_sse3)
{
if (has_longmode)
cpu = "nocona";
else
cpu = "prescott";
}
else
cpu = "pentium4";
break;
case PROCESSOR_K8:
cpu = "k8";
break;
case PROCESSOR_NOCONA:
cpu = "nocona";
break;
case PROCESSOR_GENERIC32:
case PROCESSOR_GENERIC64:
cpu = "generic";
break;
default:
abort ();
break;
}
done:
return concat ("-m", argv[0], "=", cpu, NULL);
}
#else
const char *host_detect_local_cpu (int argc, const char **argv)
{
const char *cpu;
bool arch;
if (argc < 1)
return NULL;
arch = strcmp (argv[0], "arch") == 0;
if (!arch && strcmp (argv[0], "tune"))
return NULL;
if (arch)
{
cpu = "i386";
}
else
cpu = "generic";
return concat ("-m", argv[0], "=", cpu, NULL);
}
#endif