1 //===-- ARMSubtarget.cpp - ARM Subtarget Information ----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the ARM specific subclass of TargetSubtargetInfo. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "ARMSubtarget.h" 15 #include "ARMFrameLowering.h" 16 #include "ARMISelLowering.h" 17 #include "ARMInstrInfo.h" 18 #include "ARMSelectionDAGInfo.h" 19 #include "ARMSubtarget.h" 20 #include "ARMMachineFunctionInfo.h" 21 #include "Thumb1FrameLowering.h" 22 #include "Thumb1InstrInfo.h" 23 #include "Thumb2InstrInfo.h" 24 #include "llvm/IR/Attributes.h" 25 #include "llvm/IR/Function.h" 26 #include "llvm/IR/GlobalValue.h" 27 #include "llvm/Support/CommandLine.h" 28 #include "llvm/Target/TargetInstrInfo.h" 29 #include "llvm/Target/TargetOptions.h" 30 #include "llvm/Target/TargetRegisterInfo.h" 31 #include "llvm/CodeGen/MachineRegisterInfo.h" 32 33 using namespace llvm; 34 35 #define DEBUG_TYPE "arm-subtarget" 36 37 #define GET_SUBTARGETINFO_TARGET_DESC 38 #define GET_SUBTARGETINFO_CTOR 39 #include "ARMGenSubtargetInfo.inc" 40 41 static cl::opt<bool> 42 ReserveR9("arm-reserve-r9", cl::Hidden, 43 cl::desc("Reserve R9, making it unavailable as GPR")); 44 45 static cl::opt<bool> 46 ArmUseMOVT("arm-use-movt", cl::init(true), cl::Hidden); 47 48 static cl::opt<bool> 49 UseFusedMulOps("arm-use-mulops", 50 cl::init(true), cl::Hidden); 51 52 namespace { 53 enum AlignMode { 54 DefaultAlign, 55 StrictAlign, 56 NoStrictAlign 57 }; 58 } 59 60 static cl::opt<AlignMode> 61 Align(cl::desc("Load/store alignment support"), 62 cl::Hidden, cl::init(DefaultAlign), 63 cl::values( 64 clEnumValN(DefaultAlign, "arm-default-align", 65 "Generate unaligned accesses only on hardware/OS " 66 "combinations that are known to support them"), 67 clEnumValN(StrictAlign, "arm-strict-align", 68 "Disallow all unaligned memory accesses"), 69 clEnumValN(NoStrictAlign, "arm-no-strict-align", 70 "Allow unaligned memory accesses"), 71 clEnumValEnd)); 72 73 enum ITMode { 74 DefaultIT, 75 RestrictedIT, 76 NoRestrictedIT 77 }; 78 79 static cl::opt<ITMode> 80 IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), 81 cl::ZeroOrMore, 82 cl::values(clEnumValN(DefaultIT, "arm-default-it", 83 "Generate IT block based on arch"), 84 clEnumValN(RestrictedIT, "arm-restrict-it", 85 "Disallow deprecated IT based on ARMv8"), 86 clEnumValN(NoRestrictedIT, "arm-no-restrict-it", 87 "Allow IT blocks based on ARMv7"), 88 clEnumValEnd)); 89 90 static std::string computeDataLayout(ARMSubtarget &ST) { 91 std::string Ret = ""; 92 93 if (ST.isLittle()) 94 // Little endian. 95 Ret += "e"; 96 else 97 // Big endian. 98 Ret += "E"; 99 100 Ret += DataLayout::getManglingComponent(ST.getTargetTriple()); 101 102 // Pointers are 32 bits and aligned to 32 bits. 103 Ret += "-p:32:32"; 104 105 // ABIs other than APCS have 64 bit integers with natural alignment. 106 if (!ST.isAPCS_ABI()) 107 Ret += "-i64:64"; 108 109 // We have 64 bits floats. The APCS ABI requires them to be aligned to 32 110 // bits, others to 64 bits. We always try to align to 64 bits. 111 if (ST.isAPCS_ABI()) 112 Ret += "-f64:32:64"; 113 114 // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others 115 // to 64. We always ty to give them natural alignment. 116 if (ST.isAPCS_ABI()) 117 Ret += "-v64:32:64-v128:32:128"; 118 else 119 Ret += "-v128:64:128"; 120 121 // Try to align aggregates to 32 bits (the default is 64 bits, which has no 122 // particular hardware support on 32-bit ARM). 123 Ret += "-a:0:32"; 124 125 // Integer registers are 32 bits. 126 Ret += "-n32"; 127 128 // The stack is 128 bit aligned on NaCl, 64 bit aligned on AAPCS and 32 bit 129 // aligned everywhere else. 130 if (ST.isTargetNaCl()) 131 Ret += "-S128"; 132 else if (ST.isAAPCS_ABI()) 133 Ret += "-S64"; 134 else 135 Ret += "-S32"; 136 137 return Ret; 138 } 139 140 /// initializeSubtargetDependencies - Initializes using a CPU and feature string 141 /// so that we can use initializer lists for subtarget initialization. 142 ARMSubtarget &ARMSubtarget::initializeSubtargetDependencies(StringRef CPU, 143 StringRef FS) { 144 initializeEnvironment(); 145 initSubtargetFeatures(CPU, FS); 146 return *this; 147 } 148 149 ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &CPU, 150 const std::string &FS, const TargetMachine &TM, 151 bool IsLittle) 152 : ARMGenSubtargetInfo(TT, CPU, FS), ARMProcFamily(Others), 153 ARMProcClass(None), stackAlignment(4), CPUString(CPU), IsLittle(IsLittle), 154 TargetTriple(TT), Options(TM.Options), TargetABI(ARM_ABI_UNKNOWN), 155 DL(computeDataLayout(initializeSubtargetDependencies(CPU, FS))), 156 TSInfo(DL), 157 InstrInfo(isThumb1Only() 158 ? (ARMBaseInstrInfo *)new Thumb1InstrInfo(*this) 159 : !isThumb() 160 ? (ARMBaseInstrInfo *)new ARMInstrInfo(*this) 161 : (ARMBaseInstrInfo *)new Thumb2InstrInfo(*this)), 162 TLInfo(TM), 163 FrameLowering(!isThumb1Only() 164 ? new ARMFrameLowering(*this) 165 : (ARMFrameLowering *)new Thumb1FrameLowering(*this)) {} 166 167 void ARMSubtarget::initializeEnvironment() { 168 HasV4TOps = false; 169 HasV5TOps = false; 170 HasV5TEOps = false; 171 HasV6Ops = false; 172 HasV6MOps = false; 173 HasV6T2Ops = false; 174 HasV7Ops = false; 175 HasV8Ops = false; 176 HasVFPv2 = false; 177 HasVFPv3 = false; 178 HasVFPv4 = false; 179 HasFPARMv8 = false; 180 HasNEON = false; 181 UseNEONForSinglePrecisionFP = false; 182 UseMulOps = UseFusedMulOps; 183 SlowFPVMLx = false; 184 HasVMLxForwarding = false; 185 SlowFPBrcc = false; 186 InThumbMode = false; 187 HasThumb2 = false; 188 NoARM = false; 189 IsR9Reserved = ReserveR9; 190 UseMovt = false; 191 SupportsTailCall = false; 192 HasFP16 = false; 193 HasD16 = false; 194 HasHardwareDivide = false; 195 HasHardwareDivideInARM = false; 196 HasT2ExtractPack = false; 197 HasDataBarrier = false; 198 Pref32BitThumb = false; 199 AvoidCPSRPartialUpdate = false; 200 AvoidMOVsShifterOperand = false; 201 HasRAS = false; 202 HasMPExtension = false; 203 HasVirtualization = false; 204 FPOnlySP = false; 205 HasPerfMon = false; 206 HasTrustZone = false; 207 HasCrypto = false; 208 HasCRC = false; 209 HasZeroCycleZeroing = false; 210 AllowsUnalignedMem = false; 211 Thumb2DSP = false; 212 UseNaClTrap = false; 213 UnsafeFPMath = false; 214 } 215 216 void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { 217 if (CPUString.empty()) { 218 if (isTargetIOS() && TargetTriple.getArchName().endswith("v7s")) 219 // Default to the Swift CPU when targeting armv7s/thumbv7s. 220 CPUString = "swift"; 221 else 222 CPUString = "generic"; 223 } 224 225 // Insert the architecture feature derived from the target triple into the 226 // feature string. This is important for setting features that are implied 227 // based on the architecture version. 228 std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple.getTriple(), 229 CPUString); 230 if (!FS.empty()) { 231 if (!ArchFS.empty()) 232 ArchFS = ArchFS + "," + FS.str(); 233 else 234 ArchFS = FS; 235 } 236 ParseSubtargetFeatures(CPUString, ArchFS); 237 238 // FIXME: This used enable V6T2 support implicitly for Thumb2 mode. 239 // Assert this for now to make the change obvious. 240 assert(hasV6T2Ops() || !hasThumb2()); 241 242 // Keep a pointer to static instruction cost data for the specified CPU. 243 SchedModel = getSchedModelForCPU(CPUString); 244 245 // Initialize scheduling itinerary for the specified CPU. 246 InstrItins = getInstrItineraryForCPU(CPUString); 247 248 if (TargetABI == ARM_ABI_UNKNOWN) { 249 switch (TargetTriple.getEnvironment()) { 250 case Triple::Android: 251 case Triple::EABI: 252 case Triple::EABIHF: 253 case Triple::GNUEABI: 254 case Triple::GNUEABIHF: 255 TargetABI = ARM_ABI_AAPCS; 256 break; 257 default: 258 if (TargetTriple.isOSBinFormatMachO() && 259 TargetTriple.getOS() == Triple::UnknownOS) 260 TargetABI = ARM_ABI_AAPCS; 261 else 262 TargetABI = ARM_ABI_APCS; 263 break; 264 } 265 } 266 267 // FIXME: this is invalid for WindowsCE 268 if (isTargetWindows()) { 269 TargetABI = ARM_ABI_AAPCS; 270 NoARM = true; 271 } 272 273 if (isAAPCS_ABI()) 274 stackAlignment = 8; 275 if (isTargetNaCl()) 276 stackAlignment = 16; 277 278 UseMovt = hasV6T2Ops() && ArmUseMOVT; 279 280 if (isTargetMachO()) { 281 IsR9Reserved = ReserveR9 || !HasV6Ops; 282 SupportsTailCall = !isTargetIOS() || !getTargetTriple().isOSVersionLT(5, 0); 283 } else { 284 IsR9Reserved = ReserveR9; 285 SupportsTailCall = !isThumb1Only(); 286 } 287 288 if (Align == DefaultAlign) { 289 // Assume pre-ARMv6 doesn't support unaligned accesses. 290 // 291 // ARMv6 may or may not support unaligned accesses depending on the 292 // SCTLR.U bit, which is architecture-specific. We assume ARMv6 293 // Darwin and NetBSD targets support unaligned accesses, and others don't. 294 // 295 // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit 296 // which raises an alignment fault on unaligned accesses. Linux 297 // defaults this bit to 0 and handles it as a system-wide (not 298 // per-process) setting. It is therefore safe to assume that ARMv7+ 299 // Linux targets support unaligned accesses. The same goes for NaCl. 300 // 301 // The above behavior is consistent with GCC. 302 AllowsUnalignedMem = 303 (hasV7Ops() && (isTargetLinux() || isTargetNaCl() || 304 isTargetNetBSD())) || 305 (hasV6Ops() && (isTargetMachO() || isTargetNetBSD())); 306 } else { 307 AllowsUnalignedMem = !(Align == StrictAlign); 308 } 309 310 // No v6M core supports unaligned memory access (v6M ARM ARM A3.2) 311 if (isV6M()) 312 AllowsUnalignedMem = false; 313 314 switch (IT) { 315 case DefaultIT: 316 RestrictIT = hasV8Ops() ? true : false; 317 break; 318 case RestrictedIT: 319 RestrictIT = true; 320 break; 321 case NoRestrictedIT: 322 RestrictIT = false; 323 break; 324 } 325 326 // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default. 327 uint64_t Bits = getFeatureBits(); 328 if ((Bits & ARM::ProcA5 || Bits & ARM::ProcA8) && // Where this matters 329 (Options.UnsafeFPMath || isTargetDarwin())) 330 UseNEONForSinglePrecisionFP = true; 331 } 332 333 /// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol. 334 bool 335 ARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV, 336 Reloc::Model RelocM) const { 337 if (RelocM == Reloc::Static) 338 return false; 339 340 // Materializable GVs (in JIT lazy compilation mode) do not require an extra 341 // load from stub. 342 bool isDecl = GV->hasAvailableExternallyLinkage(); 343 if (GV->isDeclaration() && !GV->isMaterializable()) 344 isDecl = true; 345 346 if (!isTargetMachO()) { 347 // Extra load is needed for all externally visible. 348 if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) 349 return false; 350 return true; 351 } else { 352 if (RelocM == Reloc::PIC_) { 353 // If this is a strong reference to a definition, it is definitely not 354 // through a stub. 355 if (!isDecl && !GV->isWeakForLinker()) 356 return false; 357 358 // Unless we have a symbol with hidden visibility, we have to go through a 359 // normal $non_lazy_ptr stub because this symbol might be resolved late. 360 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 361 return true; 362 363 // If symbol visibility is hidden, we have a stub for common symbol 364 // references and external declarations. 365 if (isDecl || GV->hasCommonLinkage()) 366 // Hidden $non_lazy_ptr reference. 367 return true; 368 369 return false; 370 } else { 371 // If this is a strong reference to a definition, it is definitely not 372 // through a stub. 373 if (!isDecl && !GV->isWeakForLinker()) 374 return false; 375 376 // Unless we have a symbol with hidden visibility, we have to go through a 377 // normal $non_lazy_ptr stub because this symbol might be resolved late. 378 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 379 return true; 380 } 381 } 382 383 return false; 384 } 385 386 unsigned ARMSubtarget::getMispredictionPenalty() const { 387 return SchedModel.MispredictPenalty; 388 } 389 390 bool ARMSubtarget::hasSinCos() const { 391 return getTargetTriple().isiOS() && !getTargetTriple().isOSVersionLT(7, 0); 392 } 393 394 // This overrides the PostRAScheduler bit in the SchedModel for any CPU. 395 bool ARMSubtarget::enablePostMachineScheduler() const { 396 return (!isThumb() || hasThumb2()); 397 } 398 399 bool ARMSubtarget::enableAtomicExpand() const { 400 return hasAnyDataBarrier() && !isThumb1Only(); 401 } 402 403 bool ARMSubtarget::useMovt(const MachineFunction &MF) const { 404 // NOTE Windows on ARM needs to use mov.w/mov.t pairs to materialise 32-bit 405 // immediates as it is inherently position independent, and may be out of 406 // range otherwise. 407 return UseMovt && (isTargetWindows() || 408 !MF.getFunction()->getAttributes().hasAttribute( 409 AttributeSet::FunctionIndex, Attribute::MinSize)); 410 } 411