make this work on non-native hosts
[oota-llvm.git] / lib / Target / X86 / X86Subtarget.cpp
index 1c161562c37522fe17a45c613e4e8921ea376853..3553c60cada7c8af35a06527f67453a059043128 100644 (file)
@@ -1,4 +1,4 @@
-//===- 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(M), 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;
+// FIXME: temporary.
+#include "llvm/Support/CommandLine.h"
+namespace {
+  cl::opt<bool> EnableSSE("enable-x86-sse", cl::Hidden,
+                          cl::desc("Enable sse on X86"));
+}
+
+/// 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 *EAX, unsigned *EBX,
+                            unsigned *ECX, unsigned *EDX) {
+#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" (*EAX),
+         "=S" (*EBX),
+         "=c" (*ECX),
+         "=d" (*EDX)
+       :  "a" (value));
+  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);
+
+  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";
+  }
+}
+
+X86Subtarget::X86Subtarget(const Module &M, const std::string &FS) {
+  stackAlignment = 8;
+  indirectExternAndWeakGlobals = false;
+  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;
   
+  // FIXME: Force these off until they work.  An llc-beta option should turn
+  // them back on.
+  if (!EnableSSE) {
+    X86SSELevel = NoMMXSSE;
+    X863DNowLevel = NoThreeDNow;
+  }
+      
   // 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) {
     stackAlignment = 16;
     indirectExternAndWeakGlobals = true;
-    asmDarwinLinkerStubs = true;
-    asmLeadingUnderscore = true;
-    asmPrintDotLCommConstants = true;
-  } else if (forWindows) {
   }
 }