diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp index 0f6b579ace5..4d7dbb875e4 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp @@ -16,6 +16,8 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Target/TargetRegistry.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Host.h" #define GET_REGINFO_MC_DESC #include "X86GenRegisterInfo.inc" @@ -28,6 +30,104 @@ using namespace llvm; + +std::string X86_MC::ParseX86Triple(StringRef TT) { + Triple TheTriple(TT); + if (TheTriple.getArch() == Triple::x86_64) + return "+64bit-mode"; + return ""; +} + +/// 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_MC::GetCpuIDAndInfo(unsigned value, unsigned *rEAX, + unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + #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 +#endif + return true; +} + +void X86_MC::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 + } +} + +static bool hasX86_64() { + // FIXME: Code duplication. See X86Subtarget::AutoDetectSubtargetFeatures. + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + union { + unsigned u[3]; + char c[12]; + } text; + + if (X86_MC::GetCpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1)) + return false; + + bool IsIntel = memcmp(text.c, "GenuineIntel", 12) == 0; + bool IsAMD = !IsIntel && memcmp(text.c, "AuthenticAMD", 12) == 0; + if (IsIntel || IsAMD) { + X86_MC::GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + if ((EDX >> 29) & 0x1) + return true; + } + + return false; +} + MCInstrInfo *createX86MCInstrInfo() { MCInstrInfo *X = new MCInstrInfo(); InitX86MCInstrInfo(X); @@ -42,8 +142,24 @@ MCRegisterInfo *createX86MCRegisterInfo() { MCSubtargetInfo *createX86MCSubtargetInfo(StringRef TT, StringRef CPU, StringRef FS) { + std::string ArchFS = X86_MC::ParseX86Triple(TT); + if (!FS.empty()) { + if (!ArchFS.empty()) + ArchFS = ArchFS + "," + FS.str(); + else + ArchFS = FS; + } + + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = sys::getHostCPUName(); + + if (ArchFS.empty() && CPUName.empty() && hasX86_64()) + // Auto-detect if host is 64-bit capable, it's the default if true. + ArchFS = "+64bit-mode"; + MCSubtargetInfo *X = new MCSubtargetInfo(); - InitX86MCSubtargetInfo(X, CPU, FS); + InitX86MCSubtargetInfo(X, CPU, ArchFS); return X; } diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h index 499a8db7f40..17c905227a7 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h @@ -14,10 +14,24 @@ #ifndef X86MCTARGETDESC_H #define X86MCTARGETDESC_H +#include + namespace llvm { class Target; +class StringRef; extern Target TheX86_32Target, TheX86_64Target; + +namespace X86_MC { + std::string ParseX86Triple(StringRef TT); + + /// 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 GetCpuIDAndInfo(unsigned value, unsigned *rEAX, + unsigned *rEBX, unsigned *rECX, unsigned *rEDX); + + void DetectFamilyModel(unsigned EAX, unsigned &Family, unsigned &Model); +} } // End llvm namespace // Defines symbolic names for X86 registers. This defines a mapping from diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index 7bb96766cce..4ccb43fe18c 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -16,6 +16,13 @@ // include "llvm/Target/Target.td" +//===----------------------------------------------------------------------===// +// X86 Subtarget state. +// + +def Mode64Bit : SubtargetFeature<"64bit-mode", "In64BitMode", "true", + "64-bit mode (x86_64)">; + //===----------------------------------------------------------------------===// // X86 Subtarget features. //===----------------------------------------------------------------------===// diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index 1c1a10d56ff..cba048482ea 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -158,7 +158,7 @@ const char *X86Subtarget::getBZeroEntry() const { /// IsLegalToCallImmediateAddr - Return true if the subtarget allows calls /// to immediate address. bool X86Subtarget::IsLegalToCallImmediateAddr(const TargetMachine &TM) const { - if (Is64Bit) + if (In64BitMode) return false; return isTargetELF() || TM.getRelocationModel() == Reloc::Static; } @@ -174,73 +174,6 @@ unsigned X86Subtarget::getSpecialAddressLatency() const { 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. -static bool GetCpuIDAndInfo(unsigned value, unsigned *rEAX, - unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) - #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 -#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 { @@ -248,10 +181,10 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { char c[12]; } text; - if (GetCpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1)) + if (X86_MC::GetCpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1)) return; - GetCpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX); + X86_MC::GetCpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX); if ((EDX >> 15) & 1) HasCMov = true; if ((EDX >> 23) & 1) X86SSELevel = MMX; @@ -276,13 +209,13 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { // Determine if bit test memory instructions are slow. unsigned Family = 0; unsigned Model = 0; - DetectFamilyModel(EAX, Family, Model); + X86_MC::DetectFamilyModel(EAX, Family, Model); IsBTMemSlow = IsAMD || (Family == 6 && Model >= 13); // If it's Nehalem, unaligned memory access is fast. if (Family == 15 && Model == 26) IsUAMemFast = true; - GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + X86_MC::GetCpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); HasX86_64 = (EDX >> 29) & 0x1; HasSSE4A = IsAMD && ((ECX >> 6) & 0x1); HasFMA4 = IsAMD && ((ECX >> 16) & 0x1); @@ -291,7 +224,7 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, const std::string &FS, - bool is64Bit, unsigned StackAlignOverride) + unsigned StackAlignOverride) : X86GenSubtargetInfo(TT, CPU, FS) , PICStyle(PICStyles::None) , X86SSELevel(NoMMXSSE) @@ -312,15 +245,26 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, // FIXME: this is a known good value for Yonah. How about others? , MaxInlineSizeThreshold(128) , TargetTriple(TT) - , Is64Bit(is64Bit) { + , In64BitMode(false) { + // Insert the architecture feature derived from the target triple into the + // feature string. This is important for setting features that are implied + // based on the architecture version. + std::string ArchFS = X86_MC::ParseX86Triple(TT); + if (!FS.empty()) { + if (!ArchFS.empty()) + ArchFS = ArchFS + "," + FS; + else + ArchFS = FS; + } + + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = sys::getHostCPUName(); // Determine default and user specified characteristics - if (!CPU.empty() || !FS.empty()) { + if (!CPUName.empty() || !ArchFS.empty()) { // If feature string is not empty, parse features string. - std::string CPUName = CPU; - if (CPUName.empty()) - CPUName = sys::getHostCPUName(); - ParseSubtargetFeatures(CPUName, FS); + ParseSubtargetFeatures(CPUName, ArchFS); // All X86-64 CPUs also have SSE2, however user might request no SSE via // -mattr, so don't force SSELevel here. if (HasAVX) @@ -328,14 +272,19 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, } else { // Otherwise, use CPUID to auto-detect feature set. AutoDetectSubtargetFeatures(); + + // If CPU is 64-bit capable, default to 64-bit mode if not specified. + In64BitMode = HasX86_64; + // Make sure SSE2 is enabled; it is available on all X86-64 CPUs. - if (Is64Bit && !HasAVX && X86SSELevel < SSE2) + if (In64BitMode && !HasAVX && X86SSELevel < SSE2) X86SSELevel = SSE2; } // If requesting codegen for X86-64, make sure that 64-bit features // are enabled. - if (Is64Bit) { + // FIXME: Remove this feature since it's not actually being used. + if (In64BitMode) { HasX86_64 = true; // All 64-bit cpus have cmov support. @@ -345,7 +294,7 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, DEBUG(dbgs() << "Subtarget features: SSELevel " << X86SSELevel << ", 3DNowLevel " << X863DNowLevel << ", 64bit " << HasX86_64 << "\n"); - assert((!Is64Bit || HasX86_64) && + assert((!In64BitMode || HasX86_64) && "64-bit code requested on a subtarget that doesn't support it!"); // Stack alignment is 16 bytes on Darwin, FreeBSD, Linux and Solaris (both @@ -353,6 +302,6 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, if (StackAlignOverride) stackAlignment = StackAlignOverride; else if (isTargetDarwin() || isTargetFreeBSD() || isTargetLinux() || - isTargetSolaris() || Is64Bit) + isTargetSolaris() || In64BitMode) stackAlignment = 16; } diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index f6250b6ecf1..e5a4f28cd54 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -112,9 +112,8 @@ protected: Triple TargetTriple; private: - /// Is64Bit - True if the processor supports 64-bit instructions and - /// pointer size is 64 bit. - bool Is64Bit; + /// In64BitMode - True if compiling for 64-bit, false for 32-bit. + bool In64BitMode; public: @@ -122,7 +121,7 @@ public: /// of the specified triple. /// X86Subtarget(const std::string &TT, const std::string &CPU, - const std::string &FS, bool is64Bit, + const std::string &FS, unsigned StackAlignOverride); /// getStackAlignment - Returns the minimum alignment known to hold of the @@ -142,7 +141,7 @@ public: /// instruction. void AutoDetectSubtargetFeatures(); - bool is64Bit() const { return Is64Bit; } + bool is64Bit() const { return In64BitMode; } PICStyles::Style getPICStyle() const { return PICStyle; } void setPICStyle(PICStyles::Style Style) { PICStyle = Style; } @@ -200,7 +199,7 @@ public: } bool isTargetWin64() const { - return Is64Bit && (isTargetMingw() || isTargetWindows()); + return In64BitMode && (isTargetMingw() || isTargetWindows()); } bool isTargetEnvMacho() const { @@ -208,7 +207,7 @@ public: } bool isTargetWin32() const { - return !Is64Bit && (isTargetMingw() || isTargetWindows()); + return !In64BitMode && (isTargetMingw() || isTargetWindows()); } bool isPICStyleSet() const { return PICStyle != PICStyles::None; } diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index 1b6fa308f3e..aaf15fdee7a 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -120,7 +120,7 @@ X86TargetMachine::X86TargetMachine(const Target &T, const std::string &TT, const std::string &CPU, const std::string &FS, bool is64Bit) : LLVMTargetMachine(T, TT), - Subtarget(TT, CPU, FS, is64Bit, StackAlignmentOverride), + Subtarget(TT, CPU, FS, StackAlignmentOverride), FrameLowering(*this, Subtarget), ELFWriterInfo(is64Bit, true) { DefRelocModel = getRelocationModel(); diff --git a/test/CodeGen/X86/2010-04-08-CoalescerBug.ll b/test/CodeGen/X86/2010-04-08-CoalescerBug.ll index 1c7c28c68e9..9a5958e62a0 100644 --- a/test/CodeGen/X86/2010-04-08-CoalescerBug.ll +++ b/test/CodeGen/X86/2010-04-08-CoalescerBug.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=core2 | FileCheck %s ; rdar://7842028 ; Do not delete partially dead copy instructions. diff --git a/test/CodeGen/X86/2010-06-25-CoalescerSubRegDefDead.ll b/test/CodeGen/X86/2010-06-25-CoalescerSubRegDefDead.ll index bb1db598d41..05f581a0883 100644 --- a/test/CodeGen/X86/2010-06-25-CoalescerSubRegDefDead.ll +++ b/test/CodeGen/X86/2010-06-25-CoalescerSubRegDefDead.ll @@ -1,4 +1,4 @@ -; RUN: llc -O1 -mtriple=x86_64-unknown-linux-gnu -relocation-model=pic -disable-fp-elim < %s | FileCheck %s +; RUN: llc -O1 -mtriple=x86_64-unknown-linux-gnu -mcpu=core2 -relocation-model=pic -disable-fp-elim < %s | FileCheck %s ; %struct.type = type { %struct.subtype*, i32, i8, i32, i8, i32, i32, i32, i32, i32, i8, i32, i32, i32, i32, i32, [256 x i32], i32, [257 x i32], [257 x i32], i32*, i16*, i8*, i32, i32, i32, i32, i32, [256 x i8], [16 x i8], [256 x i8], [4096 x i8], [16 x i32], [18002 x i8], [18002 x i8], [6 x [258 x i8]], [6 x [258 x i32]], [6 x [258 x i32]], [6 x [258 x i32]], [6 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32*, i32*, i32* } diff --git a/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll b/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll index eaede30f9b5..1b339777f57 100644 --- a/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll +++ b/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -combiner-alias-analysis -march=x86-64 | FileCheck %s +; RUN: llc < %s -combiner-alias-analysis -march=x86-64 -mcpu=core2 | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-apple-darwin10.4" diff --git a/test/CodeGen/X86/memcpy.ll b/test/CodeGen/X86/memcpy.ll index 72342cbacb4..f43b0bf509c 100644 --- a/test/CodeGen/X86/memcpy.ll +++ b/test/CodeGen/X86/memcpy.ll @@ -1,5 +1,5 @@ -; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s -check-prefix=LINUX -; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s -check-prefix=DARWIN +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=core2 | FileCheck %s -check-prefix=LINUX +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=core2 | FileCheck %s -check-prefix=DARWIN declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind diff --git a/test/CodeGen/X86/tlv-1.ll b/test/CodeGen/X86/tlv-1.ll index 42940f147ed..5773260f68d 100644 --- a/test/CodeGen/X86/tlv-1.ll +++ b/test/CodeGen/X86/tlv-1.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple x86_64-apple-darwin | FileCheck %s +; RUN: llc < %s -mtriple x86_64-apple-darwin -mcpu=core2 | FileCheck %s %struct.A = type { [48 x i8], i32, i32, i32 }