X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FX86%2FX86Subtarget.cpp;h=8506fa66a645a530f955a3828cab1afd16d23f3e;hb=3d62a412fbe517fbbbf5661ef1a748a39f382aa3;hp=6efe540fabd24ea7f503dfdad91e4b04cc3db3ce;hpb=e51775dc5e3503092313fe77174127f4f4d17374;p=oota-llvm.git diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index 6efe540fabd..8506fa66a64 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -11,19 +11,26 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "subtarget" #include "X86Subtarget.h" #include "X86GenSubtarget.inc" #include "llvm/Module.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" using namespace llvm; -cl::opt +#if defined(_MSC_VER) + #include +#endif + +static cl::opt AsmWriterFlavor("x86-asm-syntax", cl::init(X86Subtarget::Unset), cl::desc("Choose style of code to emit from X86 backend:"), cl::values( - clEnumValN(X86Subtarget::ATT, "att", " Emit AT&T-style assembly"), - clEnumValN(X86Subtarget::Intel, "intel", " Emit Intel-style assembly"), + clEnumValN(X86Subtarget::ATT, "att", "Emit AT&T-style assembly"), + clEnumValN(X86Subtarget::Intel, "intel", "Emit Intel-style assembly"), clEnumValEnd)); @@ -36,67 +43,148 @@ bool X86Subtarget::GVRequiresExtraLoad(const GlobalValue* GV, bool isDirectCall) const { // FIXME: PIC - if (TM.getRelocationModel() != Reloc::Static) + if (TM.getRelocationModel() != Reloc::Static && + TM.getCodeModel() != CodeModel::Large) { if (isTargetDarwin()) { - return (!isDirectCall && - (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || - (GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode()))); - } else if (TM.getRelocationModel() == Reloc::PIC_ && isPICStyleGOT()) { - // Extra load is needed for all non-statics. - return (!isDirectCall && - (GV->isDeclaration() || !GV->hasInternalLinkage())); + if (isDirectCall) + return false; + bool isDecl = GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode(); + if (GV->hasHiddenVisibility() && + (Is64Bit || (!isDecl && !GV->hasCommonLinkage()))) + // If symbol visibility is hidden, the extra load is not needed if + // target is x86-64 or the symbol is definitely defined in the current + // translation unit. + return false; + return !isDirectCall && (isDecl || GV->isWeakForLinker()); + } else if (isTargetELF()) { + // Extra load is needed for all externally visible. + if (isDirectCall) + return false; + if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) + return false; + return true; } else if (isTargetCygMing() || isTargetWindows()) { return (GV->hasDLLImportLinkage()); } - + } return false; } +/// True if accessing the GV requires a register. This is a superset of the +/// cases where GVRequiresExtraLoad is true. Some variations of PIC require +/// a register, but not an extra load. +bool X86Subtarget::GVRequiresRegister(const GlobalValue *GV, + const TargetMachine& TM, + bool isDirectCall) const +{ + if (GVRequiresExtraLoad(GV, TM, isDirectCall)) + return true; + // Code below here need only consider cases where GVRequiresExtraLoad + // returns false. + if (TM.getRelocationModel() == Reloc::PIC_) + return !isDirectCall && + (GV->hasLocalLinkage() || GV->hasExternalLinkage()); + return false; +} + +/// getBZeroEntry - This function returns the name of a function which has an +/// interface like the non-standard bzero function, if such a function exists on +/// the current subtarget and it is considered prefereable over memset with zero +/// passed as the second argument. Otherwise it returns null. +const char *X86Subtarget::getBZeroEntry() const { + // Darwin 10 has a __bzero entry point for this purpose. + if (getDarwinVers() >= 10) + return "__bzero"; + + return 0; +} + +/// IsLegalToCallImmediateAddr - Return true if the subtarget allows calls +/// to immediate address. +bool X86Subtarget::IsLegalToCallImmediateAddr(const TargetMachine &TM) const { + if (Is64Bit) + return false; + return isTargetELF() || TM.getRelocationModel() == Reloc::Static; +} + +/// getSpecialAddressLatency - For targets where it is beneficial to +/// backschedule instructions that compute addresses, return a value +/// indicating the number of scheduling cycles of backscheduling that +/// should be attempted. +unsigned X86Subtarget::getSpecialAddressLatency() const { + // For x86 out-of-order targets, back-schedule address computations so + // that loads and stores aren't blocked. + // This value was chosen arbitrarily. + return 200; +} + /// 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. bool X86::GetCpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__x86_64__) - // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. - asm ("movq\t%%rbx, %%rsi\n\t" - "cpuid\n\t" - "xchgq\t%%rbx, %%rsi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value)); - return false; +#if defined(__x86_64__) || defined(_M_AMD64) + #if defined(__GNUC__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm ("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; + #endif #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) -#if defined(__GNUC__) - asm ("movl\t%%ebx, %%esi\n\t" - "cpuid\n\t" - "xchgl\t%%ebx, %%esi\n\t" - : "=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 + #if defined(__GNUC__) + asm ("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=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 void DetectFamilyModel(unsigned EAX, unsigned &Family, unsigned &Model) { + Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (Family == 6 || Family == 0xf) { + if (Family == 0xf) + // Examine extended family ID if family ID is F. + Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + // Examine extended model ID if family ID is 6 or F. + Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + } +} + void X86Subtarget::AutoDetectSubtargetFeatures() { unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; union { @@ -114,11 +202,26 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { if ((EDX >> 26) & 0x1) X86SSELevel = SSE2; if (ECX & 0x1) X86SSELevel = SSE3; if ((ECX >> 9) & 0x1) X86SSELevel = SSSE3; + if ((ECX >> 19) & 0x1) X86SSELevel = SSE41; + if ((ECX >> 20) & 0x1) X86SSELevel = SSE42; + + bool IsIntel = memcmp(text.c, "GenuineIntel", 12) == 0; + bool IsAMD = !IsIntel && memcmp(text.c, "AuthenticAMD", 12) == 0; + + HasFMA3 = IsIntel && ((ECX >> 12) & 0x1); + HasAVX = ((ECX >> 28) & 0x1); + + if (IsIntel || IsAMD) { + // Determine if bit test memory instructions are slow. + unsigned Family = 0; + unsigned Model = 0; + DetectFamilyModel(EAX, Family, Model); + IsBTMemSlow = IsAMD || (Family == 6 && Model >= 13); - if (memcmp(text.c, "GenuineIntel", 12) == 0 || - memcmp(text.c, "AuthenticAMD", 12) == 0) { X86::GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); HasX86_64 = (EDX >> 29) & 0x1; + HasSSE4A = IsAMD && ((ECX >> 6) & 0x1); + HasFMA4 = IsAMD && ((ECX >> 16) & 0x1); } } @@ -126,10 +229,13 @@ static const char *GetCurrentX86CPU() { unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; if (X86::GetCpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) return "generic"; - unsigned Family = (EAX >> 8) & 0xf; // Bits 8 - 11 - unsigned Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + unsigned Family = 0; + unsigned Model = 0; + DetectFamilyModel(EAX, Family, Model); + X86::GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); bool Em64T = (EDX >> 29) & 0x1; + bool HasSSE3 = (ECX & 0x1); union { unsigned u[3]; @@ -161,14 +267,23 @@ static const char *GetCurrentX86CPU() { case 9: case 13: return "pentium-m"; case 14: return "yonah"; - case 15: return "core2"; + case 15: + case 22: // Celeron M 540 + return "core2"; + case 23: // 45nm: Penryn , Wolfdale, Yorkfield (XE) + return "penryn"; default: return "i686"; } case 15: { switch (Model) { case 3: case 4: + case 6: // same as 4, but 65nm return (Em64T) ? "nocona" : "prescott"; + case 26: + return "corei7"; + case 28: + return "atom"; default: return (Em64T) ? "x86-64" : "pentium4"; } @@ -203,10 +318,20 @@ static const char *GetCurrentX86CPU() { default: return "athlon"; } case 15: + if (HasSSE3) { + switch (Model) { + default: return "k8-sse3"; + } + } else { + switch (Model) { + case 1: return "opteron"; + case 5: return "athlon-fx"; // also opteron + default: return "athlon64"; + } + } + case 16: switch (Model) { - case 1: return "opteron"; - case 5: return "athlon-fx"; // also opteron - default: return "athlon64"; + default: return "amdfam10"; } default: return "generic"; @@ -218,41 +343,53 @@ static const char *GetCurrentX86CPU() { X86Subtarget::X86Subtarget(const Module &M, const std::string &FS, bool is64Bit) : AsmFlavor(AsmWriterFlavor) - , PICStyle(PICStyle::None) + , PICStyle(PICStyles::None) , X86SSELevel(NoMMXSSE) + , X863DNowLevel(NoThreeDNow) , HasX86_64(false) + , HasSSE4A(false) + , HasAVX(false) + , HasFMA3(false) + , HasFMA4(false) + , IsBTMemSlow(false) , DarwinVers(0) + , IsLinux(false) , stackAlignment(8) // FIXME: this is a known good value for Yonah. How about others? , MaxInlineSizeThreshold(128) , Is64Bit(is64Bit) - , HasLow4GUserAddress(true) , TargetType(isELF) { // Default to ELF unless otherwise specified. + // default to hard float ABI + if (FloatABIType == FloatABI::Default) + FloatABIType = FloatABI::Hard; + // Determine default and user specified characteristics if (!FS.empty()) { // If feature string is not empty, parse features string. std::string CPU = GetCurrentX86CPU(); ParseSubtargetFeatures(FS, CPU); - - if (Is64Bit && !HasX86_64) - cerr << "Warning: Generation of 64-bit code for a 32-bit processor " - << "requested.\n"; - if (Is64Bit && X86SSELevel < SSE2) - cerr << "Warning: 64-bit processors all have at least SSE2.\n"; + // All X86-64 CPUs also have SSE2, however user might request no SSE via + // -mattr, so don't force SSELevel here. } else { // Otherwise, use CPUID to auto-detect feature set. AutoDetectSubtargetFeatures(); - } - - // If requesting codegen for X86-64, make sure that 64-bit and SSE2 features - // are enabled. These are available on all x86-64 CPUs. - if (Is64Bit) { - HasX86_64 = true; - if (X86SSELevel < SSE2) + // Make sure SSE2 is enabled; it is available on all X86-64 CPUs. + if (Is64Bit && X86SSELevel < SSE2) X86SSELevel = SSE2; } + // If requesting codegen for X86-64, make sure that 64-bit features + // are enabled. + if (Is64Bit) + HasX86_64 = true; + + DOUT << "Subtarget features: SSELevel " << X86SSELevel + << ", 3DNowLevel " << X863DNowLevel + << ", 64bit " << HasX86_64 << "\n"; + assert((!Is64Bit || HasX86_64) && + "64-bit code requested on a subtarget that doesn't support it!"); + // 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(); @@ -266,17 +403,27 @@ X86Subtarget::X86Subtarget(const Module &M, const std::string &FS, bool is64Bit) DarwinVers = atoi(&TT[Pos+7]); else DarwinVers = 8; // Minimum supported darwin is Tiger. + } else if (TT.find("linux") != std::string::npos) { + // Linux doesn't imply ELF, but we don't currently support anything else. + TargetType = isELF; + IsLinux = true; } else if (TT.find("cygwin") != std::string::npos) { TargetType = isCygwin; } else if (TT.find("mingw") != std::string::npos) { TargetType = isMingw; } else if (TT.find("win32") != std::string::npos) { TargetType = isWindows; + } else if (TT.find("windows") != std::string::npos) { + TargetType = isWindows; + } + else if (TT.find("-cl") != std::string::npos) { + TargetType = isDarwin; + DarwinVers = 9; } } else if (TT.empty()) { #if defined(__CYGWIN__) TargetType = isCygwin; -#elif defined(__MINGW32__) +#elif defined(__MINGW32__) || defined(__MINGW64__) TargetType = isMingw; #elif defined(__APPLE__) TargetType = isDarwin; @@ -286,8 +433,12 @@ X86Subtarget::X86Subtarget(const Module &M, const std::string &FS, bool is64Bit) DarwinVers = 8; // Minimum supported darwin is Tiger. #endif -#elif defined(_WIN32) +#elif defined(_WIN32) || defined(_WIN64) TargetType = isWindows; +#elif defined(__linux__) + // Linux doesn't imply ELF, but we don't currently support anything else. + TargetType = isELF; + IsLinux = true; #endif } @@ -298,12 +449,11 @@ X86Subtarget::X86Subtarget(const Module &M, const std::string &FS, bool is64Bit) ? X86Subtarget::Intel : X86Subtarget::ATT; } - if (TargetType == isDarwin && Is64Bit) - HasLow4GUserAddress = false; - - if (TargetType == isDarwin || - TargetType == isCygwin || - TargetType == isMingw || - (TargetType == isELF && Is64Bit)) + // Stack alignment is 16 bytes on Darwin (both 32 and 64 bit) and for all 64 + // bit targets. + if (TargetType == isDarwin || Is64Bit) stackAlignment = 16; + + if (StackAlignment) + stackAlignment = StackAlignment; }