-//===- X86Subtarget.cpp - X86 Instruction Information -----------*- C++ -*-===//
+//===-- X86Subtarget.cpp - X86 Subtarget Information ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
#include "X86Subtarget.h"
#include "llvm/Module.h"
+#include "X86GenSubtarget.inc"
using namespace llvm;
-X86Subtarget::X86Subtarget(const Module &M)
- : TargetSubtarget(), stackAlignment(8),
- indirectExternAndWeakGlobals(false), asmDarwinLinkerStubs(false),
- asmLeadingUnderscore(false), asmAlignmentIsInBytes(false),
- asmPrintDotLocalConstants(false), asmPrintDotLCommConstants(false),
- asmPrintConstantAlignment(false) {
- // Declare a boolean for each major platform.
- bool forCygwin = false;
- bool forDarwin = false;
- bool forWindows = false;
+/// GetCpuIDAndInfo - Execute the specified cpuid and return the 4 values in the
+/// specified arguments. If we can't run cpuid on the host, return true.
+static bool GetCpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
+ unsigned *rECX, unsigned *rEDX) {
+#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)
+#if defined(__GNUC__)
+ asm ("pushl\t%%ebx\n\t"
+ "cpuid\n\t"
+ "movl\t%%ebx, %%esi\n\t"
+ "popl\t%%ebx"
+ : "=a" (*rEAX),
+ "=S" (*rEBX),
+ "=c" (*rECX),
+ "=d" (*rEDX)
+ : "a" (value));
+ return false;
+#elif defined(_MSC_VER)
+ __asm {
+ mov eax,value
+ cpuid
+ mov esi,rEAX
+ mov dword ptr [esi],eax
+ mov esi,rEBX
+ mov dword ptr [esi],ebx
+ mov esi,rECX
+ mov dword ptr [esi],ecx
+ mov esi,rEDX
+ mov dword ptr [esi],edx
+ }
+ return false;
+#endif
+#endif
+ return true;
+}
+
+static const char *GetCurrentX86CPU() {
+ unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
+ if (GetCpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX))
+ return "generic";
+ unsigned Family = (EAX & (0xffffffff >> (32 - 4)) << 8) >> 8; // Bits 8 - 11
+ unsigned Model = (EAX & (0xffffffff >> (32 - 4)) << 4) >> 4; // Bits 4 - 7
+ GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
+ bool Em64T = EDX & (1 << 29);
+
+ union {
+ unsigned u[3];
+ char c[12];
+ } text;
+
+ GetCpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1);
+ if (memcmp(text.c, "GenuineIntel", 12) == 0) {
+ switch (Family) {
+ case 3:
+ return "i386";
+ case 4:
+ return "i486";
+ case 5:
+ switch (Model) {
+ case 4: return "pentium-mmx";
+ default: return "pentium";
+ }
+ case 6:
+ switch (Model) {
+ case 1: return "pentiumpro";
+ case 3:
+ case 5:
+ case 6: return "pentium2";
+ case 7:
+ case 8:
+ case 10:
+ case 11: return "pentium3";
+ case 9:
+ case 13: return "pentium-m";
+ case 14: return "yonah";
+ default: return "i686";
+ }
+ case 15: {
+ switch (Model) {
+ case 3:
+ case 4:
+ return (Em64T) ? "nocona" : "prescott";
+ default:
+ return (Em64T) ? "x86-64" : "pentium4";
+ }
+ }
+
+ default:
+ return "generic";
+ }
+ } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) {
+ // FIXME: this poorly matches the generated SubtargetFeatureKV table. There
+ // appears to be no way to generate the wide variety of AMD-specific targets
+ // from the information returned from CPUID.
+ switch (Family) {
+ case 4:
+ return "i486";
+ case 5:
+ switch (Model) {
+ case 6:
+ case 7: return "k6";
+ case 8: return "k6-2";
+ case 9:
+ case 13: return "k6-3";
+ default: return "pentium";
+ }
+ case 6:
+ switch (Model) {
+ case 4: return "athlon-tbird";
+ case 6:
+ case 7:
+ case 8: return "athlon-mp";
+ case 10: return "athlon-xp";
+ default: return "athlon";
+ }
+ case 15:
+ switch (Model) {
+ case 5: return "athlon-fx"; // also opteron
+ default: return "athlon64";
+ }
+ default:
+ return "generic";
+ }
+ } else {
+ return "generic";
+ }
+}
+
+X86Subtarget::X86Subtarget(const Module &M, const std::string &FS) {
+ stackAlignment = 8;
+ // FIXME: this is a known good value for Yonah. Not sure about others.
+ MinRepStrSizeThreshold = 128;
+ X86SSELevel = NoMMXSSE;
+ X863DNowLevel = NoThreeDNow;
+ Is64Bit = false;
+
+ // Determine default and user specified characteristics
+ std::string CPU = GetCurrentX86CPU();
+
+ // Parse features string.
+ ParseSubtargetFeatures(FS, CPU);
+
+ // Default to ELF unless otherwise specified.
+ TargetType = isELF;
+
// Set the boolean corresponding to the current target triple, or the default
// if one cannot be determined, to true.
const std::string& TT = M.getTargetTriple();
if (TT.length() > 5) {
- forCygwin = TT.find("cygwin") != std::string::npos ||
- TT.find("mingw") != std::string::npos;
- forDarwin = TT.find("darwin") != std::string::npos;
- forWindows = TT.find("win32") != std::string::npos;
+ if (TT.find("cygwin") != std::string::npos ||
+ TT.find("mingw") != std::string::npos)
+ TargetType = isCygwin;
+ else if (TT.find("darwin") != std::string::npos)
+ TargetType = isDarwin;
+ else if (TT.find("win32") != std::string::npos)
+ TargetType = isWindows;
} else if (TT.empty()) {
#if defined(__CYGWIN__) || defined(__MINGW32__)
- forCygwin = true;
+ TargetType = isCygwin;
#elif defined(__APPLE__)
- forDarwin = true;
+ TargetType = isDarwin;
#elif defined(_WIN32)
- forWindows = true;
+ TargetType = isWindows;
#endif
}
- if (forCygwin) {
- asmLeadingUnderscore = true;
- } else if (forDarwin) {
+ if (TargetType == isDarwin || TargetType == isCygwin)
stackAlignment = 16;
- indirectExternAndWeakGlobals = true;
- asmDarwinLinkerStubs = true;
- asmLeadingUnderscore = true;
- asmPrintDotLCommConstants = true;
- } else if (forWindows) {
- }
}