Fix codegen for x86-64 on systems (like ppc or i386) that don't have 64-bit
[oota-llvm.git] / lib / Target / X86 / X86Subtarget.cpp
1 //===-- X86Subtarget.cpp - X86 Subtarget Information ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Nate Begeman and is distributed under the
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the X86 specific subclass of TargetSubtarget.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "X86Subtarget.h"
15 #include "X86GenSubtarget.inc"
16 #include "llvm/Module.h"
17 #include "llvm/Support/CommandLine.h"
18 #include <iostream>
19 using namespace llvm;
20
21 cl::opt<X86Subtarget::AsmWriterFlavorTy>
22 AsmWriterFlavor("x86-asm-syntax", cl::init(X86Subtarget::unset),
23   cl::desc("Choose style of code to emit from X86 backend:"),
24   cl::values(
25     clEnumValN(X86Subtarget::att,   "att",   "  Emit AT&T-style assembly"),
26     clEnumValN(X86Subtarget::intel, "intel", "  Emit Intel-style assembly"),
27     clEnumValEnd));
28
29
30 /// GetCpuIDAndInfo - Execute the specified cpuid and return the 4 values in the
31 /// specified arguments.  If we can't run cpuid on the host, return true.
32 bool X86::GetCpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
33                           unsigned *rECX, unsigned *rEDX) {
34 #if defined(__x86_64__)
35   // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually.
36   asm ("movq\t%%rbx, %%rsi\n\t"
37        "cpuid\n\t"
38        "xchgq\t%%rbx, %%rsi\n\t"
39        : "=a" (*rEAX),
40          "=S" (*rEBX),
41          "=c" (*rECX),
42          "=d" (*rEDX)
43        :  "a" (value));
44   return false;
45 #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)
46 #if defined(__GNUC__)
47   asm ("movl\t%%ebx, %%esi\n\t"
48        "cpuid\n\t"
49        "xchgl\t%%ebx, %%esi\n\t"
50        : "=a" (*rEAX),
51          "=S" (*rEBX),
52          "=c" (*rECX),
53          "=d" (*rEDX)
54        :  "a" (value));
55   return false;
56 #elif defined(_MSC_VER)
57   __asm {
58     mov   eax,value
59     cpuid
60     mov   esi,rEAX
61     mov   dword ptr [esi],eax
62     mov   esi,rEBX
63     mov   dword ptr [esi],ebx
64     mov   esi,rECX
65     mov   dword ptr [esi],ecx
66     mov   esi,rEDX
67     mov   dword ptr [esi],edx
68   }
69   return false;
70 #endif
71 #endif
72   return true;
73 }
74
75 void X86Subtarget::AutoDetectSubtargetFeatures() {
76   unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
77   union {
78     unsigned u[3];
79     char     c[12];
80   } text;
81   
82   if (X86::GetCpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1))
83     return;
84   
85   // FIXME: support for AMD family of processors.
86   if (memcmp(text.c, "GenuineIntel", 12) == 0) {
87     X86::GetCpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX);
88
89     if ((EDX >> 23) & 0x1) X86SSELevel = MMX;
90     if ((EDX >> 25) & 0x1) X86SSELevel = SSE1;
91     if ((EDX >> 26) & 0x1) X86SSELevel = SSE2;
92     if (ECX & 0x1)         X86SSELevel = SSE3;
93
94     X86::GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
95     HasX86_64 = (EDX >> 29) & 0x1;
96   }
97 }
98
99 static const char *GetCurrentX86CPU() {
100   unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
101   if (X86::GetCpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX))
102     return "generic";
103   unsigned Family  = (EAX >> 8) & 0xf; // Bits 8 - 11
104   unsigned Model   = (EAX >> 4) & 0xf; // Bits 4 - 7
105   X86::GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
106   bool Em64T = (EDX >> 29) & 0x1;
107
108   union {
109     unsigned u[3];
110     char     c[12];
111   } text;
112
113   X86::GetCpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1);
114   if (memcmp(text.c, "GenuineIntel", 12) == 0) {
115     switch (Family) {
116       case 3:
117         return "i386";
118       case 4:
119         return "i486";
120       case 5:
121         switch (Model) {
122         case 4:  return "pentium-mmx";
123         default: return "pentium";
124         }
125       case 6:
126         switch (Model) {
127         case 1:  return "pentiumpro";
128         case 3:
129         case 5:
130         case 6:  return "pentium2";
131         case 7:
132         case 8:
133         case 10:
134         case 11: return "pentium3";
135         case 9:
136         case 13: return "pentium-m";
137         case 14: return "yonah";
138         case 15: return "core2";
139         default: return "i686";
140         }
141       case 15: {
142         switch (Model) {
143         case 3:  
144         case 4:
145           return (Em64T) ? "nocona" : "prescott";
146         default:
147           return (Em64T) ? "x86-64" : "pentium4";
148         }
149       }
150         
151     default:
152       return "generic";
153     }
154   } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) {
155     // FIXME: this poorly matches the generated SubtargetFeatureKV table.  There
156     // appears to be no way to generate the wide variety of AMD-specific targets
157     // from the information returned from CPUID.
158     switch (Family) {
159       case 4:
160         return "i486";
161       case 5:
162         switch (Model) {
163         case 6:
164         case 7:  return "k6";
165         case 8:  return "k6-2";
166         case 9:
167         case 13: return "k6-3";
168         default: return "pentium";
169         }
170       case 6:
171         switch (Model) {
172         case 4:  return "athlon-tbird";
173         case 6:
174         case 7:
175         case 8:  return "athlon-mp";
176         case 10: return "athlon-xp";
177         default: return "athlon";
178         }
179       case 15:
180         switch (Model) {
181         case 5:  return "athlon-fx"; // also opteron
182         default: return "athlon64";
183         }
184
185     default:
186       return "generic";
187     }
188   } else {
189     return "generic";
190   }
191 }
192
193 X86Subtarget::X86Subtarget(const Module &M, const std::string &FS, bool is64Bit)
194   : AsmFlavor(AsmWriterFlavor)
195   , X86SSELevel(NoMMXSSE)
196   , HasX86_64(false)
197   , stackAlignment(8)
198   // FIXME: this is a known good value for Yonah. How about others?
199   , MinRepStrSizeThreshold(128)
200   , Is64Bit(is64Bit)
201   , TargetType(isELF) { // Default to ELF unless otherwise specified.
202
203   // Determine default and user specified characteristics
204   if (!FS.empty()) {
205     // If feature string is not empty, parse features string.
206     std::string CPU = GetCurrentX86CPU();
207     ParseSubtargetFeatures(FS, CPU);
208     
209     if (Is64Bit && !HasX86_64)
210       std::cerr << "Warning: Generation of 64-bit code for a 32-bit processor "
211                    "requested.\n";
212     if (Is64Bit && X86SSELevel < SSE2)
213       std::cerr << "Warning: 64-bit processors all have at least SSE2.\n";
214   } else {
215     // Otherwise, use CPUID to auto-detect feature set.
216     AutoDetectSubtargetFeatures();
217   }
218     
219   // If requesting codegen for X86-64, make sure that 64-bit and SSE2 features
220   // are enabled.  These are available on all x86-64 CPUs.
221   if (Is64Bit) {
222     HasX86_64 = true;
223     if (X86SSELevel < SSE2)
224       X86SSELevel = SSE2;
225   }
226
227   // Set the boolean corresponding to the current target triple, or the default
228   // if one cannot be determined, to true.
229   const std::string& TT = M.getTargetTriple();
230   if (TT.length() > 5) {
231     if (TT.find("cygwin") != std::string::npos ||
232         TT.find("mingw")  != std::string::npos)
233       TargetType = isCygwin;
234     else if (TT.find("darwin") != std::string::npos)
235       TargetType = isDarwin;
236     else if (TT.find("win32") != std::string::npos)
237       TargetType = isWindows;
238   } else if (TT.empty()) {
239 #if defined(__CYGWIN__) || defined(__MINGW32__)
240     TargetType = isCygwin;
241 #elif defined(__APPLE__)
242     TargetType = isDarwin;
243 #elif defined(_WIN32)
244     TargetType = isWindows;
245 #endif
246   }
247
248   // If the asm syntax hasn't been overridden on the command line, use whatever
249   // the target wants.
250   if (AsmFlavor == X86Subtarget::unset) {
251     if (TargetType == isWindows) {
252       AsmFlavor = X86Subtarget::intel;
253     } else {
254       AsmFlavor = X86Subtarget::att;
255     }
256   }
257
258   if (TargetType == isDarwin || TargetType == isCygwin)
259     stackAlignment = 16;
260 }