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