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