1234353Sdim//===-- ARMSubtarget.cpp - ARM Subtarget Information ----------------------===// 2193323Sed// 3193323Sed// The LLVM Compiler Infrastructure 4193323Sed// 5193323Sed// This file is distributed under the University of Illinois Open Source 6193323Sed// License. See LICENSE.TXT for details. 7193323Sed// 8193323Sed//===----------------------------------------------------------------------===// 9193323Sed// 10224145Sdim// This file implements the ARM specific subclass of TargetSubtargetInfo. 11193323Sed// 12193323Sed//===----------------------------------------------------------------------===// 13193323Sed 14193323Sed#include "ARMSubtarget.h" 15249423Sdim#include "ARMBaseInstrInfo.h" 16218893Sdim#include "ARMBaseRegisterInfo.h" 17249423Sdim#include "llvm/IR/Attributes.h" 18249423Sdim#include "llvm/IR/GlobalValue.h" 19249423Sdim#include "llvm/IR/Function.h" 20249423Sdim#include "llvm/Support/CommandLine.h" 21243830Sdim#include "llvm/Target/TargetInstrInfo.h" 22249423Sdim#include "llvm/Target/TargetOptions.h" 23224145Sdim 24224145Sdim#define GET_SUBTARGETINFO_TARGET_DESC 25224145Sdim#define GET_SUBTARGETINFO_CTOR 26224145Sdim#include "ARMGenSubtargetInfo.inc" 27224145Sdim 28193323Sedusing namespace llvm; 29193323Sed 30194710Sedstatic cl::opt<bool> 31194710SedReserveR9("arm-reserve-r9", cl::Hidden, 32194710Sed cl::desc("Reserve R9, making it unavailable as GPR")); 33194710Sed 34199989Srdivackystatic cl::opt<bool> 35263508SdimArmUseMOVT("arm-use-movt", cl::init(true), cl::Hidden); 36199989Srdivacky 37218893Sdimstatic cl::opt<bool> 38243830SdimUseFusedMulOps("arm-use-mulops", 39243830Sdim cl::init(true), cl::Hidden); 40243830Sdim 41263508Sdimenum AlignMode { 42263508Sdim DefaultAlign, 43263508Sdim StrictAlign, 44263508Sdim NoStrictAlign 45263508Sdim}; 46218893Sdim 47263508Sdimstatic cl::opt<AlignMode> 48263508SdimAlign(cl::desc("Load/store alignment support"), 49263508Sdim cl::Hidden, cl::init(DefaultAlign), 50263508Sdim cl::values( 51263508Sdim clEnumValN(DefaultAlign, "arm-default-align", 52263508Sdim "Generate unaligned accesses only on hardware/OS " 53263508Sdim "combinations that are known to support them"), 54263508Sdim clEnumValN(StrictAlign, "arm-strict-align", 55263508Sdim "Disallow all unaligned memory accesses"), 56263508Sdim clEnumValN(NoStrictAlign, "arm-no-strict-align", 57263508Sdim "Allow unaligned memory accesses"), 58263508Sdim clEnumValEnd)); 59263508Sdim 60263508Sdimenum ITMode { 61263508Sdim DefaultIT, 62263508Sdim RestrictedIT, 63263508Sdim NoRestrictedIT 64263508Sdim}; 65263508Sdim 66263508Sdimstatic cl::opt<ITMode> 67263508SdimIT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), 68263508Sdim cl::ZeroOrMore, 69263508Sdim cl::values(clEnumValN(DefaultIT, "arm-default-it", 70263508Sdim "Generate IT block based on arch"), 71263508Sdim clEnumValN(RestrictedIT, "arm-restrict-it", 72263508Sdim "Disallow deprecated IT based on ARMv8"), 73263508Sdim clEnumValN(NoRestrictedIT, "arm-no-restrict-it", 74263508Sdim "Allow IT blocks based on ARMv7"), 75263508Sdim clEnumValEnd)); 76263508Sdim 77224145SdimARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &CPU, 78249423Sdim const std::string &FS, const TargetOptions &Options) 79224145Sdim : ARMGenSubtargetInfo(TT, CPU, FS) 80218893Sdim , ARMProcFamily(Others) 81263508Sdim , ARMProcClass(None) 82193323Sed , stackAlignment(4) 83224145Sdim , CPUString(CPU) 84218893Sdim , TargetTriple(TT) 85249423Sdim , Options(Options) 86193323Sed , TargetABI(ARM_ABI_APCS) { 87249423Sdim initializeEnvironment(); 88249423Sdim resetSubtargetFeatures(CPU, FS); 89249423Sdim} 90249423Sdim 91249423Sdimvoid ARMSubtarget::initializeEnvironment() { 92249423Sdim HasV4TOps = false; 93249423Sdim HasV5TOps = false; 94249423Sdim HasV5TEOps = false; 95249423Sdim HasV6Ops = false; 96263508Sdim HasV6MOps = false; 97249423Sdim HasV6T2Ops = false; 98249423Sdim HasV7Ops = false; 99263508Sdim HasV8Ops = false; 100249423Sdim HasVFPv2 = false; 101249423Sdim HasVFPv3 = false; 102249423Sdim HasVFPv4 = false; 103263508Sdim HasFPARMv8 = false; 104249423Sdim HasNEON = false; 105249423Sdim UseNEONForSinglePrecisionFP = false; 106249423Sdim UseMulOps = UseFusedMulOps; 107249423Sdim SlowFPVMLx = false; 108249423Sdim HasVMLxForwarding = false; 109249423Sdim SlowFPBrcc = false; 110249423Sdim InThumbMode = false; 111249423Sdim HasThumb2 = false; 112249423Sdim NoARM = false; 113249423Sdim PostRAScheduler = false; 114249423Sdim IsR9Reserved = ReserveR9; 115249423Sdim UseMovt = false; 116249423Sdim SupportsTailCall = false; 117249423Sdim HasFP16 = false; 118249423Sdim HasD16 = false; 119249423Sdim HasHardwareDivide = false; 120249423Sdim HasHardwareDivideInARM = false; 121249423Sdim HasT2ExtractPack = false; 122249423Sdim HasDataBarrier = false; 123249423Sdim Pref32BitThumb = false; 124249423Sdim AvoidCPSRPartialUpdate = false; 125249423Sdim AvoidMOVsShifterOperand = false; 126249423Sdim HasRAS = false; 127249423Sdim HasMPExtension = false; 128263508Sdim HasVirtualization = false; 129249423Sdim FPOnlySP = false; 130263508Sdim HasPerfMon = false; 131251662Sdim HasTrustZone = false; 132263508Sdim HasCrypto = false; 133263508Sdim HasCRC = false; 134249423Sdim AllowsUnalignedMem = false; 135249423Sdim Thumb2DSP = false; 136249423Sdim UseNaClTrap = false; 137249423Sdim UnsafeFPMath = false; 138249423Sdim} 139249423Sdim 140249423Sdimvoid ARMSubtarget::resetSubtargetFeatures(const MachineFunction *MF) { 141249423Sdim AttributeSet FnAttrs = MF->getFunction()->getAttributes(); 142249423Sdim Attribute CPUAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex, 143249423Sdim "target-cpu"); 144249423Sdim Attribute FSAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex, 145249423Sdim "target-features"); 146249423Sdim std::string CPU = 147249423Sdim !CPUAttr.hasAttribute(Attribute::None) ?CPUAttr.getValueAsString() : ""; 148249423Sdim std::string FS = 149249423Sdim !FSAttr.hasAttribute(Attribute::None) ? FSAttr.getValueAsString() : ""; 150249423Sdim if (!FS.empty()) { 151249423Sdim initializeEnvironment(); 152249423Sdim resetSubtargetFeatures(CPU, FS); 153249423Sdim } 154249423Sdim} 155249423Sdim 156249423Sdimvoid ARMSubtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) { 157263508Sdim if (CPUString.empty()) { 158263508Sdim if (isTargetIOS() && TargetTriple.getArchName().endswith("v7s")) 159263508Sdim // Default to the Swift CPU when targeting armv7s/thumbv7s. 160263508Sdim CPUString = "swift"; 161263508Sdim else 162263508Sdim CPUString = "generic"; 163263508Sdim } 164193323Sed 165224145Sdim // Insert the architecture feature derived from the target triple into the 166224145Sdim // feature string. This is important for setting features that are implied 167224145Sdim // based on the architecture version. 168249423Sdim std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple.getTriple(), 169249423Sdim CPUString); 170224145Sdim if (!FS.empty()) { 171224145Sdim if (!ArchFS.empty()) 172249423Sdim ArchFS = ArchFS + "," + FS.str(); 173224145Sdim else 174224145Sdim ArchFS = FS; 175218893Sdim } 176224145Sdim ParseSubtargetFeatures(CPUString, ArchFS); 177204961Srdivacky 178224145Sdim // Thumb2 implies at least V6T2. FIXME: Fix tests to explicitly specify a 179224145Sdim // ARM version or CPU and then remove this. 180224145Sdim if (!HasV6T2Ops && hasThumb2()) 181263508Sdim HasV4TOps = HasV5TOps = HasV5TEOps = HasV6Ops = HasV6MOps = HasV6T2Ops = true; 182193323Sed 183239462Sdim // Keep a pointer to static instruction cost data for the specified CPU. 184239462Sdim SchedModel = getSchedModelForCPU(CPUString); 185239462Sdim 186224145Sdim // Initialize scheduling itinerary for the specified CPU. 187224145Sdim InstrItins = getInstrItineraryForCPU(CPUString); 188193323Sed 189249423Sdim if ((TargetTriple.getTriple().find("eabi") != std::string::npos) || 190249423Sdim (isTargetIOS() && isMClass())) 191234353Sdim // FIXME: We might want to separate AAPCS and EABI. Some systems, e.g. 192234353Sdim // Darwin-EABI conforms to AACPS but not the rest of EABI. 193224145Sdim TargetABI = ARM_ABI_AAPCS; 194198090Srdivacky 195193323Sed if (isAAPCS_ABI()) 196193323Sed stackAlignment = 8; 197193323Sed 198263508Sdim UseMovt = hasV6T2Ops() && ArmUseMOVT; 199263508Sdim 200263508Sdim if (!isTargetIOS()) { 201263508Sdim IsR9Reserved = ReserveR9; 202263508Sdim } else { 203224145Sdim IsR9Reserved = ReserveR9 | !HasV6Ops; 204234353Sdim SupportsTailCall = !getTargetTriple().isOSVersionLT(5, 0); 205218893Sdim } 206198090Srdivacky 207198396Srdivacky if (!isThumb() || hasThumb2()) 208198396Srdivacky PostRAScheduler = true; 209218893Sdim 210263508Sdim switch (Align) { 211263508Sdim case DefaultAlign: 212263508Sdim // Assume pre-ARMv6 doesn't support unaligned accesses. 213263508Sdim // 214263508Sdim // ARMv6 may or may not support unaligned accesses depending on the 215263508Sdim // SCTLR.U bit, which is architecture-specific. We assume ARMv6 216263508Sdim // Darwin targets support unaligned accesses, and others don't. 217263508Sdim // 218263508Sdim // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit 219263508Sdim // which raises an alignment fault on unaligned accesses. Linux 220263508Sdim // defaults this bit to 0 and handles it as a system-wide (not 221263508Sdim // per-process) setting. It is therefore safe to assume that ARMv7+ 222263508Sdim // Linux targets support unaligned accesses. The same goes for NaCl. 223263508Sdim // 224263508Sdim // The above behavior is consistent with GCC. 225263508Sdim AllowsUnalignedMem = ( 226263508Sdim (hasV7Ops() && (isTargetLinux() || isTargetNaCl())) || 227263508Sdim (hasV6Ops() && isTargetDarwin())); 228263508Sdim break; 229263508Sdim case StrictAlign: 230263508Sdim AllowsUnalignedMem = false; 231263508Sdim break; 232263508Sdim case NoStrictAlign: 233263508Sdim AllowsUnalignedMem = true; 234263508Sdim break; 235263508Sdim } 236249423Sdim 237263508Sdim switch (IT) { 238263508Sdim case DefaultIT: 239263508Sdim RestrictIT = hasV8Ops() ? true : false; 240263508Sdim break; 241263508Sdim case RestrictedIT: 242263508Sdim RestrictIT = true; 243263508Sdim break; 244263508Sdim case NoRestrictedIT: 245263508Sdim RestrictIT = false; 246263508Sdim break; 247263508Sdim } 248263508Sdim 249249423Sdim // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default. 250249423Sdim uint64_t Bits = getFeatureBits(); 251249423Sdim if ((Bits & ARM::ProcA5 || Bits & ARM::ProcA8) && // Where this matters 252249423Sdim (Options.UnsafeFPMath || isTargetDarwin())) 253249423Sdim UseNEONForSinglePrecisionFP = true; 254193323Sed} 255198090Srdivacky 256198090Srdivacky/// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol. 257198090Srdivackybool 258207618SrdivackyARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV, 259207618Srdivacky Reloc::Model RelocM) const { 260198090Srdivacky if (RelocM == Reloc::Static) 261198090Srdivacky return false; 262198090Srdivacky 263203954Srdivacky // Materializable GVs (in JIT lazy compilation mode) do not require an extra 264203954Srdivacky // load from stub. 265219077Sdim bool isDecl = GV->hasAvailableExternallyLinkage(); 266219077Sdim if (GV->isDeclaration() && !GV->isMaterializable()) 267219077Sdim isDecl = true; 268198090Srdivacky 269198090Srdivacky if (!isTargetDarwin()) { 270198090Srdivacky // Extra load is needed for all externally visible. 271198090Srdivacky if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) 272198090Srdivacky return false; 273198090Srdivacky return true; 274198090Srdivacky } else { 275198090Srdivacky if (RelocM == Reloc::PIC_) { 276198090Srdivacky // If this is a strong reference to a definition, it is definitely not 277198090Srdivacky // through a stub. 278198090Srdivacky if (!isDecl && !GV->isWeakForLinker()) 279198090Srdivacky return false; 280198090Srdivacky 281198090Srdivacky // Unless we have a symbol with hidden visibility, we have to go through a 282198090Srdivacky // normal $non_lazy_ptr stub because this symbol might be resolved late. 283198090Srdivacky if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 284198090Srdivacky return true; 285198090Srdivacky 286198090Srdivacky // If symbol visibility is hidden, we have a stub for common symbol 287198090Srdivacky // references and external declarations. 288198090Srdivacky if (isDecl || GV->hasCommonLinkage()) 289198090Srdivacky // Hidden $non_lazy_ptr reference. 290198090Srdivacky return true; 291198090Srdivacky 292198090Srdivacky return false; 293198090Srdivacky } else { 294198090Srdivacky // If this is a strong reference to a definition, it is definitely not 295198090Srdivacky // through a stub. 296198090Srdivacky if (!isDecl && !GV->isWeakForLinker()) 297198090Srdivacky return false; 298218893Sdim 299198090Srdivacky // Unless we have a symbol with hidden visibility, we have to go through a 300198090Srdivacky // normal $non_lazy_ptr stub because this symbol might be resolved late. 301198090Srdivacky if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 302198090Srdivacky return true; 303198090Srdivacky } 304198090Srdivacky } 305198090Srdivacky 306198090Srdivacky return false; 307198090Srdivacky} 308199481Srdivacky 309218893Sdimunsigned ARMSubtarget::getMispredictionPenalty() const { 310239462Sdim return SchedModel->MispredictPenalty; 311218893Sdim} 312218893Sdim 313263508Sdimbool ARMSubtarget::hasSinCos() const { 314263508Sdim return getTargetTriple().getOS() == Triple::IOS && 315263508Sdim !getTargetTriple().isOSVersionLT(7, 0); 316263508Sdim} 317263508Sdim 318199481Srdivackybool ARMSubtarget::enablePostRAScheduler( 319199481Srdivacky CodeGenOpt::Level OptLevel, 320224145Sdim TargetSubtargetInfo::AntiDepBreakMode& Mode, 321199481Srdivacky RegClassVector& CriticalPathRCs) const { 322263508Sdim Mode = TargetSubtargetInfo::ANTIDEP_NONE; 323199481Srdivacky return PostRAScheduler && OptLevel >= CodeGenOpt::Default; 324199481Srdivacky} 325