X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTarget%2FPowerPC%2FPPCSubtarget.cpp;h=3778b0218f1e45ced79523133d0d604322903e74;hp=ca448bf1de252f7ef5bf6ceabdfbb13c5d9643d5;hb=e9da71fc86c48bbca50f3625440e41241d4029a7;hpb=2bd0acd2506c664573d2f0d7671932101c46899e diff --git a/lib/Target/PowerPC/PPCSubtarget.cpp b/lib/Target/PowerPC/PPCSubtarget.cpp index ca448bf1de2..3778b0218f1 100644 --- a/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/lib/Target/PowerPC/PPCSubtarget.cpp @@ -12,190 +12,180 @@ //===----------------------------------------------------------------------===// #include "PPCSubtarget.h" -#include "PPCRegisterInfo.h" #include "PPC.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/GlobalValue.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Support/DataStream.h" -#include "llvm/Support/Debug.h" +#include "PPCRegisterInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineScheduler.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Support/Host.h" #include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" #include +using namespace llvm; + +#define DEBUG_TYPE "ppc-subtarget" + #define GET_SUBTARGETINFO_TARGET_DESC #define GET_SUBTARGETINFO_CTOR #include "PPCGenSubtargetInfo.inc" -using namespace llvm; +/// Return the datalayout string of a subtarget. +static std::string getDataLayoutString(const Triple &T) { + bool is64Bit = T.getArch() == Triple::ppc64 || T.getArch() == Triple::ppc64le; + std::string Ret; -#if defined(__APPLE__) -#include -#include -#include -#include - -/// GetCurrentPowerPCFeatures - Returns the current CPUs features. -static const char *GetCurrentPowerPCCPU() { - host_basic_info_data_t hostInfo; - mach_msg_type_number_t infoCount; - - infoCount = HOST_BASIC_INFO_COUNT; - host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, - &infoCount); - - if (hostInfo.cpu_type != CPU_TYPE_POWERPC) return "generic"; - - switch(hostInfo.cpu_subtype) { - case CPU_SUBTYPE_POWERPC_601: return "601"; - case CPU_SUBTYPE_POWERPC_602: return "602"; - case CPU_SUBTYPE_POWERPC_603: return "603"; - case CPU_SUBTYPE_POWERPC_603e: return "603e"; - case CPU_SUBTYPE_POWERPC_603ev: return "603ev"; - case CPU_SUBTYPE_POWERPC_604: return "604"; - case CPU_SUBTYPE_POWERPC_604e: return "604e"; - case CPU_SUBTYPE_POWERPC_620: return "620"; - case CPU_SUBTYPE_POWERPC_750: return "750"; - case CPU_SUBTYPE_POWERPC_7400: return "7400"; - case CPU_SUBTYPE_POWERPC_7450: return "7450"; - case CPU_SUBTYPE_POWERPC_970: return "970"; - default: ; - } - - return "generic"; -} -#elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__)) -static const char *GetCurrentPowerPCCPU() { - // Access to the Processor Version Register (PVR) on PowerPC is privileged, - // and so we must use an operating-system interface to determine the current - // processor type. On Linux, this is exposed through the /proc/cpuinfo file. - const char *generic = "generic"; - - // Note: We cannot mmap /proc/cpuinfo here and then process the resulting - // memory buffer because the 'file' has 0 size (it can be read from only - // as a stream). - - std::string Err; - DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err); - if (!DS) { - DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n"); - return generic; - } + // Most PPC* platforms are big endian, PPC64LE is little endian. + if (T.getArch() == Triple::ppc64le) + Ret = "e"; + else + Ret = "E"; - // The cpu line is second (after the 'processor: 0' line), so if this - // buffer is too small then something has changed (or is wrong). - char buffer[1024]; - size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer)); - delete DS; - - const char *CPUInfoStart = buffer; - const char *CPUInfoEnd = buffer + CPUInfoSize; - - const char *CIP = CPUInfoStart; - - const char *CPUStart = 0; - size_t CPULen = 0; - - // We need to find the first line which starts with cpu, spaces, and a colon. - // After the colon, there may be some additional spaces and then the cpu type. - while (CIP < CPUInfoEnd && CPUStart == 0) { - if (CIP < CPUInfoEnd && *CIP == '\n') - ++CIP; - - if (CIP < CPUInfoEnd && *CIP == 'c') { - ++CIP; - if (CIP < CPUInfoEnd && *CIP == 'p') { - ++CIP; - if (CIP < CPUInfoEnd && *CIP == 'u') { - ++CIP; - while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) - ++CIP; - - if (CIP < CPUInfoEnd && *CIP == ':') { - ++CIP; - while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) - ++CIP; - - if (CIP < CPUInfoEnd) { - CPUStart = CIP; - while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && - *CIP != ',' && *CIP != '\n')) - ++CIP; - CPULen = CIP - CPUStart; - } - } - } - } - } + Ret += DataLayout::getManglingComponent(T); - if (CPUStart == 0) - while (CIP < CPUInfoEnd && *CIP != '\n') - ++CIP; - } + // PPC32 has 32 bit pointers. The PS3 (OS Lv2) is a PPC64 machine with 32 bit + // pointers. + if (!is64Bit || T.getOS() == Triple::Lv2) + Ret += "-p:32:32"; + + // Note, the alignment values for f64 and i64 on ppc64 in Darwin + // documentation are wrong; these are correct (i.e. "what gcc does"). + if (is64Bit || !T.isOSDarwin()) + Ret += "-i64:64"; + else + Ret += "-f64:32:64"; + + // PPC64 has 32 and 64 bit registers, PPC32 has only 32 bit ones. + if (is64Bit) + Ret += "-n32:64"; + else + Ret += "-n32"; - if (CPUStart == 0) - return generic; - - return StringSwitch(StringRef(CPUStart, CPULen)) - .Case("604e", "604e") - .Case("604", "604") - .Case("7400", "7400") - .Case("7410", "7400") - .Case("7447", "7400") - .Case("7455", "7450") - .Case("G4", "g4") - .Case("POWER4", "g4") - .Case("PPC970FX", "970") - .Case("PPC970MP", "970") - .Case("G5", "g5") - .Case("POWER5", "g5") - .Case("POWER6", "pwr6") - .Case("POWER7", "pwr7") - .Default(generic); + return Ret; } -#endif +PPCSubtarget &PPCSubtarget::initializeSubtargetDependencies(StringRef CPU, + StringRef FS) { + initializeEnvironment(); + resetSubtargetFeatures(CPU, FS); + return *this; +} PPCSubtarget::PPCSubtarget(const std::string &TT, const std::string &CPU, - const std::string &FS, bool is64Bit) - : PPCGenSubtargetInfo(TT, CPU, FS) - , StackAlignment(16) - , DarwinDirective(PPC::DIR_NONE) - , IsGigaProcessor(false) - , Has64BitSupport(false) - , Use64BitRegs(false) - , IsPPC64(is64Bit) - , HasAltivec(false) - , HasFSQRT(false) - , HasSTFIWX(false) - , IsBookE(false) - , HasLazyResolverStubs(false) - , IsJITCodeModel(false) - , TargetTriple(TT) { + const std::string &FS, PPCTargetMachine &TM, + CodeGenOpt::Level OptLevel) + : PPCGenSubtargetInfo(TT, CPU, FS), TargetTriple(TT), + DL(getDataLayoutString(TargetTriple)), + IsPPC64(TargetTriple.getArch() == Triple::ppc64 || + TargetTriple.getArch() == Triple::ppc64le), + OptLevel(OptLevel), TargetABI(PPC_ABI_UNKNOWN), + FrameLowering(initializeSubtargetDependencies(CPU, FS)), InstrInfo(*this), + JITInfo(*this), TLInfo(TM), TSInfo(&DL) {} + +/// SetJITMode - This is called to inform the subtarget info that we are +/// producing code for the JIT. +void PPCSubtarget::SetJITMode() { + // JIT mode doesn't want lazy resolver stubs, it knows exactly where + // everything is. This matters for PPC64, which codegens in PIC mode without + // stubs. + HasLazyResolverStubs = false; + + // Calls to external functions need to use indirect calls + IsJITCodeModel = true; +} +void PPCSubtarget::resetSubtargetFeatures(const MachineFunction *MF) { + AttributeSet FnAttrs = MF->getFunction()->getAttributes(); + Attribute CPUAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex, + "target-cpu"); + Attribute FSAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex, + "target-features"); + std::string CPU = + !CPUAttr.hasAttribute(Attribute::None) ? CPUAttr.getValueAsString() : ""; + std::string FS = + !FSAttr.hasAttribute(Attribute::None) ? FSAttr.getValueAsString() : ""; + if (!FS.empty()) { + initializeEnvironment(); + resetSubtargetFeatures(CPU, FS); + } +} + +void PPCSubtarget::initializeEnvironment() { + StackAlignment = 16; + DarwinDirective = PPC::DIR_NONE; + HasMFOCRF = false; + Has64BitSupport = false; + Use64BitRegs = false; + UseCRBits = false; + HasAltivec = false; + HasSPE = false; + HasQPX = false; + HasVSX = false; + HasFCPSGN = false; + HasFSQRT = false; + HasFRE = false; + HasFRES = false; + HasFRSQRTE = false; + HasFRSQRTES = false; + HasRecipPrec = false; + HasSTFIWX = false; + HasLFIWAX = false; + HasFPRND = false; + HasFPCVT = false; + HasISEL = false; + HasPOPCNTD = false; + HasLDBRX = false; + IsBookE = false; + IsPPC4xx = false; + IsPPC6xx = false; + IsE500 = false; + DeprecatedMFTB = false; + DeprecatedDST = false; + HasLazyResolverStubs = false; + IsJITCodeModel = false; +} + +void PPCSubtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) { // Determine default and user specified characteristics std::string CPUName = CPU; if (CPUName.empty()) CPUName = "generic"; -#if defined(__APPLE__) || \ - (defined(__linux__) && (defined(__ppc__) || defined(__powerpc__))) +#if (defined(__APPLE__) || defined(__linux__)) && \ + (defined(__ppc__) || defined(__powerpc__)) if (CPUName == "generic") - CPUName = GetCurrentPowerPCCPU(); + CPUName = sys::getHostCPUName(); #endif - // Parse features string. - ParseSubtargetFeatures(CPUName, FS); - // Initialize scheduling itinerary for the specified CPU. InstrItins = getInstrItineraryForCPU(CPUName); + // Make sure 64-bit features are available when CPUname is generic + std::string FullFS = FS; + // If we are generating code for ppc64, verify that options make sense. - if (is64Bit) { + if (IsPPC64) { Has64BitSupport = true; // Silently force 64-bit register use on ppc64. Use64BitRegs = true; + if (!FullFS.empty()) + FullFS = "+64bit," + FullFS; + else + FullFS = "+64bit"; } - + + // At -O2 and above, track CR bits as individual registers. + if (OptLevel >= CodeGenOpt::Default) { + if (!FullFS.empty()) + FullFS = "+crbits," + FullFS; + else + FullFS = "+crbits"; + } + + // Parse features string. + ParseSubtargetFeatures(CPUName, FullFS); + // If the user requested use of 64-bit regs, but the cpu selected doesn't // support it, ignore. if (use64BitRegs() && !has64BitSupport()) @@ -204,21 +194,32 @@ PPCSubtarget::PPCSubtarget(const std::string &TT, const std::string &CPU, // Set up darwin-specific properties. if (isDarwin()) HasLazyResolverStubs = true; -} -/// SetJITMode - This is called to inform the subtarget info that we are -/// producing code for the JIT. -void PPCSubtarget::SetJITMode() { - // JIT mode doesn't want lazy resolver stubs, it knows exactly where - // everything is. This matters for PPC64, which codegens in PIC mode without - // stubs. - HasLazyResolverStubs = false; - - // Calls to external functions need to use indirect calls - IsJITCodeModel = true; + // QPX requires a 32-byte aligned stack. Note that we need to do this if + // we're compiling for a BG/Q system regardless of whether or not QPX + // is enabled because external functions will assume this alignment. + if (hasQPX() || isBGQ()) + StackAlignment = 32; + + // Determine endianness. + IsLittleEndian = (TargetTriple.getArch() == Triple::ppc64le); + + // FIXME: For now, we disable VSX in little-endian mode until endian + // issues in those instructions can be addressed. + if (IsLittleEndian) + HasVSX = false; + + // Determine default ABI. + if (TargetABI == PPC_ABI_UNKNOWN) { + if (!isDarwin() && IsPPC64) { + if (IsLittleEndian) + TargetABI = PPC_ABI_ELFv2; + else + TargetABI = PPC_ABI_ELFv1; + } + } } - /// hasLazyResolverStub - Return true if accesses to the specified global have /// to go through a dyld lazy resolution stub. This means that an extra load /// is required to get the address of the global. @@ -236,29 +237,56 @@ bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV, GV->hasCommonLinkage() || isDecl; } -bool PPCSubtarget::enablePostRAScheduler( - CodeGenOpt::Level OptLevel, - TargetSubtargetInfo::AntiDepBreakMode& Mode, - RegClassVector& CriticalPathRCs) const { - // FIXME: It would be best to use TargetSubtargetInfo::ANTIDEP_ALL here, - // but we can't because we can't reassign the cr registers. There is a - // dependence between the cr register and the RLWINM instruction used - // to extract its value which the anti-dependency breaker can't currently - // see. Maybe we should make a late-expanded pseudo to encode this dependency. - // (the relevant code is in PPCDAGToDAGISel::SelectSETCC) +// Embedded cores need aggressive scheduling (and some others also benefit). +static bool needsAggressiveScheduling(unsigned Directive) { + switch (Directive) { + default: return false; + case PPC::DIR_440: + case PPC::DIR_A2: + case PPC::DIR_E500mc: + case PPC::DIR_E5500: + case PPC::DIR_PWR7: + case PPC::DIR_PWR8: + return true; + } +} - Mode = TargetSubtargetInfo::ANTIDEP_CRITICAL; +bool PPCSubtarget::enableMachineScheduler() const { + // Enable MI scheduling for the embedded cores. + // FIXME: Enable this for all cores (some additional modeling + // may be necessary). + return needsAggressiveScheduling(DarwinDirective); +} +// This overrides the PostRAScheduler bit in the SchedModel for each CPU. +bool PPCSubtarget::enablePostMachineScheduler() const { return true; } + +PPCGenSubtargetInfo::AntiDepBreakMode PPCSubtarget::getAntiDepBreakMode() const { + return TargetSubtargetInfo::ANTIDEP_ALL; +} + +void PPCSubtarget::getCriticalPathRCs(RegClassVector &CriticalPathRCs) const { CriticalPathRCs.clear(); + CriticalPathRCs.push_back(isPPC64() ? + &PPC::G8RCRegClass : &PPC::GPRCRegClass); +} - if (isPPC64()) - CriticalPathRCs.push_back(&PPC::G8RCRegClass); - else - CriticalPathRCs.push_back(&PPC::GPRCRegClass); - - CriticalPathRCs.push_back(&PPC::F8RCRegClass); - CriticalPathRCs.push_back(&PPC::VRRCRegClass); +void PPCSubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy, + MachineInstr *begin, + MachineInstr *end, + unsigned NumRegionInstrs) const { + if (needsAggressiveScheduling(DarwinDirective)) { + Policy.OnlyTopDown = false; + Policy.OnlyBottomUp = false; + } + + // Spilling is generally expensive on all PPC cores, so always enable + // register-pressure tracking. + Policy.ShouldTrackPressure = true; +} - return OptLevel >= CodeGenOpt::Default; +bool PPCSubtarget::useAA() const { + // Use AA during code generation for the embedded cores. + return needsAggressiveScheduling(DarwinDirective); }