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 "ARMMachineFunctionInfo.h" 19 #include "ARMSelectionDAGInfo.h" 20 #include "ARMSubtarget.h" 21 #include "ARMTargetMachine.h" 22 #include "Thumb1FrameLowering.h" 23 #include "Thumb1InstrInfo.h" 24 #include "Thumb2InstrInfo.h" 25 #include "llvm/CodeGen/MachineRegisterInfo.h" 26 #include "llvm/IR/Attributes.h" 27 #include "llvm/IR/Function.h" 28 #include "llvm/IR/GlobalValue.h" 29 #include "llvm/Support/CommandLine.h" 30 #include "llvm/Target/TargetInstrInfo.h" 31 #include "llvm/Target/TargetOptions.h" 32 #include "llvm/Target/TargetRegisterInfo.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 namespace { 54 enum AlignMode { 55 DefaultAlign, 56 StrictAlign, 57 NoStrictAlign 58 }; 59 } 60 61 static cl::opt<AlignMode> 62 Align(cl::desc("Load/store alignment support"), 63 cl::Hidden, cl::init(DefaultAlign), 64 cl::values( 65 clEnumValN(DefaultAlign, "arm-default-align", 66 "Generate unaligned accesses only on hardware/OS " 67 "combinations that are known to support them"), 68 clEnumValN(StrictAlign, "arm-strict-align", 69 "Disallow all unaligned memory accesses"), 70 clEnumValN(NoStrictAlign, "arm-no-strict-align", 71 "Allow unaligned memory accesses"), 72 clEnumValEnd)); 73 74 enum ITMode { 75 DefaultIT, 76 RestrictedIT, 77 NoRestrictedIT 78 }; 79 80 static cl::opt<ITMode> 81 IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), 82 cl::ZeroOrMore, 83 cl::values(clEnumValN(DefaultIT, "arm-default-it", 84 "Generate IT block based on arch"), 85 clEnumValN(RestrictedIT, "arm-restrict-it", 86 "Disallow deprecated IT based on ARMv8"), 87 clEnumValN(NoRestrictedIT, "arm-no-restrict-it", 88 "Allow IT blocks based on ARMv7"), 89 clEnumValEnd)); 90 91 /// initializeSubtargetDependencies - Initializes using a CPU and feature string 92 /// so that we can use initializer lists for subtarget initialization. 93 ARMSubtarget &ARMSubtarget::initializeSubtargetDependencies(StringRef CPU, 94 StringRef FS) { 95 initializeEnvironment(); 96 initSubtargetFeatures(CPU, FS); 97 return *this; 98 } 99 100 ARMFrameLowering *ARMSubtarget::initializeFrameLowering(StringRef CPU, 101 StringRef FS) { 102 ARMSubtarget &STI = initializeSubtargetDependencies(CPU, FS); 103 if (STI.isThumb1Only()) 104 return (ARMFrameLowering *)new Thumb1FrameLowering(STI); 105 106 return new ARMFrameLowering(STI); 107 } 108 109 ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU, 110 const std::string &FS, 111 const ARMBaseTargetMachine &TM, bool IsLittle) 112 : ARMGenSubtargetInfo(TT, CPU, FS), ARMProcFamily(Others), 113 ARMProcClass(None), stackAlignment(4), CPUString(CPU), IsLittle(IsLittle), 114 TargetTriple(TT), Options(TM.Options), TM(TM), 115 FrameLowering(initializeFrameLowering(CPU, FS)), 116 // At this point initializeSubtargetDependencies has been called so 117 // we can query directly. 118 InstrInfo(isThumb1Only() 119 ? (ARMBaseInstrInfo *)new Thumb1InstrInfo(*this) 120 : !isThumb() 121 ? (ARMBaseInstrInfo *)new ARMInstrInfo(*this) 122 : (ARMBaseInstrInfo *)new Thumb2InstrInfo(*this)), 123 TLInfo(TM, *this) {} 124 125 void ARMSubtarget::initializeEnvironment() { 126 HasV4TOps = false; 127 HasV5TOps = false; 128 HasV5TEOps = false; 129 HasV6Ops = false; 130 HasV6MOps = false; 131 HasV6KOps = false; 132 HasV6T2Ops = false; 133 HasV7Ops = false; 134 HasV8Ops = false; 135 HasV8_1aOps = false; 136 HasVFPv2 = false; 137 HasVFPv3 = false; 138 HasVFPv4 = false; 139 HasFPARMv8 = false; 140 HasNEON = false; 141 UseNEONForSinglePrecisionFP = false; 142 UseMulOps = UseFusedMulOps; 143 SlowFPVMLx = false; 144 HasVMLxForwarding = false; 145 SlowFPBrcc = false; 146 InThumbMode = false; 147 UseSoftFloat = false; 148 HasThumb2 = false; 149 NoARM = false; 150 IsR9Reserved = ReserveR9; 151 UseMovt = false; 152 SupportsTailCall = false; 153 HasFP16 = false; 154 HasD16 = false; 155 HasHardwareDivide = false; 156 HasHardwareDivideInARM = false; 157 HasT2ExtractPack = false; 158 HasDataBarrier = false; 159 Pref32BitThumb = false; 160 AvoidCPSRPartialUpdate = false; 161 AvoidMOVsShifterOperand = false; 162 HasRAS = false; 163 HasMPExtension = false; 164 HasVirtualization = false; 165 FPOnlySP = false; 166 HasPerfMon = false; 167 HasTrustZone = false; 168 HasCrypto = false; 169 HasCRC = false; 170 HasZeroCycleZeroing = false; 171 AllowsUnalignedMem = false; 172 Thumb2DSP = false; 173 UseNaClTrap = false; 174 GenLongCalls = false; 175 UnsafeFPMath = false; 176 } 177 178 void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { 179 if (CPUString.empty()) { 180 if (isTargetDarwin() && TargetTriple.getArchName().endswith("v7s")) 181 // Default to the Swift CPU when targeting armv7s/thumbv7s. 182 CPUString = "swift"; 183 else 184 CPUString = "generic"; 185 } 186 187 // Insert the architecture feature derived from the target triple into the 188 // feature string. This is important for setting features that are implied 189 // based on the architecture version. 190 std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple, CPUString); 191 if (!FS.empty()) { 192 if (!ArchFS.empty()) 193 ArchFS = (Twine(ArchFS) + "," + FS).str(); 194 else 195 ArchFS = FS; 196 } 197 ParseSubtargetFeatures(CPUString, ArchFS); 198 199 // FIXME: This used enable V6T2 support implicitly for Thumb2 mode. 200 // Assert this for now to make the change obvious. 201 assert(hasV6T2Ops() || !hasThumb2()); 202 203 // Keep a pointer to static instruction cost data for the specified CPU. 204 SchedModel = getSchedModelForCPU(CPUString); 205 206 // Initialize scheduling itinerary for the specified CPU. 207 InstrItins = getInstrItineraryForCPU(CPUString); 208 209 // FIXME: this is invalid for WindowsCE 210 if (isTargetWindows()) 211 NoARM = true; 212 213 if (isAAPCS_ABI()) 214 stackAlignment = 8; 215 if (isTargetNaCl()) 216 stackAlignment = 16; 217 218 UseMovt = hasV6T2Ops() && ArmUseMOVT; 219 220 if (isTargetMachO()) { 221 IsR9Reserved = ReserveR9 || !HasV6Ops; 222 SupportsTailCall = !isTargetIOS() || !getTargetTriple().isOSVersionLT(5, 0); 223 } else { 224 IsR9Reserved = ReserveR9; 225 SupportsTailCall = !isThumb1Only(); 226 } 227 228 if (Align == DefaultAlign) { 229 // Assume pre-ARMv6 doesn't support unaligned accesses. 230 // 231 // ARMv6 may or may not support unaligned accesses depending on the 232 // SCTLR.U bit, which is architecture-specific. We assume ARMv6 233 // Darwin and NetBSD targets support unaligned accesses, and others don't. 234 // 235 // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit 236 // which raises an alignment fault on unaligned accesses. Linux 237 // defaults this bit to 0 and handles it as a system-wide (not 238 // per-process) setting. It is therefore safe to assume that ARMv7+ 239 // Linux targets support unaligned accesses. The same goes for NaCl. 240 // 241 // The above behavior is consistent with GCC. 242 AllowsUnalignedMem = 243 (hasV7Ops() && (isTargetLinux() || isTargetNaCl() || 244 isTargetNetBSD())) || 245 (hasV6Ops() && (isTargetMachO() || isTargetNetBSD())); 246 } else { 247 AllowsUnalignedMem = !(Align == StrictAlign); 248 } 249 250 // No v6M core supports unaligned memory access (v6M ARM ARM A3.2) 251 if (isV6M()) 252 AllowsUnalignedMem = false; 253 254 switch (IT) { 255 case DefaultIT: 256 RestrictIT = hasV8Ops(); 257 break; 258 case RestrictedIT: 259 RestrictIT = true; 260 break; 261 case NoRestrictedIT: 262 RestrictIT = false; 263 break; 264 } 265 266 // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default. 267 const FeatureBitset &Bits = getFeatureBits(); 268 if ((Bits[ARM::ProcA5] || Bits[ARM::ProcA8]) && // Where this matters 269 (Options.UnsafeFPMath || isTargetDarwin())) 270 UseNEONForSinglePrecisionFP = true; 271 } 272 273 bool ARMSubtarget::isAPCS_ABI() const { 274 assert(TM.TargetABI != ARMBaseTargetMachine::ARM_ABI_UNKNOWN); 275 return TM.TargetABI == ARMBaseTargetMachine::ARM_ABI_APCS; 276 } 277 bool ARMSubtarget::isAAPCS_ABI() const { 278 assert(TM.TargetABI != ARMBaseTargetMachine::ARM_ABI_UNKNOWN); 279 return TM.TargetABI == ARMBaseTargetMachine::ARM_ABI_AAPCS; 280 } 281 282 /// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol. 283 bool 284 ARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV, 285 Reloc::Model RelocM) const { 286 if (RelocM == Reloc::Static) 287 return false; 288 289 bool isDef = GV->isStrongDefinitionForLinker(); 290 291 if (!isTargetMachO()) { 292 // Extra load is needed for all externally visible. 293 if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) 294 return false; 295 return true; 296 } else { 297 // If this is a strong reference to a definition, it is definitely not 298 // through a stub. 299 if (isDef) 300 return false; 301 302 // Unless we have a symbol with hidden visibility, we have to go through a 303 // normal $non_lazy_ptr stub because this symbol might be resolved late. 304 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 305 return true; 306 307 if (RelocM == Reloc::PIC_) { 308 // If symbol visibility is hidden, we have a stub for common symbol 309 // references and external declarations. 310 if (GV->isDeclarationForLinker() || GV->hasCommonLinkage()) 311 // Hidden $non_lazy_ptr reference. 312 return true; 313 } 314 } 315 316 return false; 317 } 318 319 unsigned ARMSubtarget::getMispredictionPenalty() const { 320 return SchedModel.MispredictPenalty; 321 } 322 323 bool ARMSubtarget::hasSinCos() const { 324 return getTargetTriple().isiOS() && !getTargetTriple().isOSVersionLT(7, 0); 325 } 326 327 // This overrides the PostRAScheduler bit in the SchedModel for any CPU. 328 bool ARMSubtarget::enablePostRAScheduler() const { 329 return (!isThumb() || hasThumb2()); 330 } 331 332 bool ARMSubtarget::enableAtomicExpand() const { 333 return hasAnyDataBarrier() && !isThumb1Only(); 334 } 335 336 bool ARMSubtarget::useMovt(const MachineFunction &MF) const { 337 // NOTE Windows on ARM needs to use mov.w/mov.t pairs to materialise 32-bit 338 // immediates as it is inherently position independent, and may be out of 339 // range otherwise. 340 return UseMovt && (isTargetWindows() || 341 !MF.getFunction()->hasFnAttribute(Attribute::MinSize)); 342 } 343 344 bool ARMSubtarget::useFastISel() const { 345 // Thumb2 support on iOS; ARM support on iOS, Linux and NaCl. 346 return TM.Options.EnableFastISel && 347 ((isTargetMachO() && !isThumb1Only()) || 348 (isTargetLinux() && !isThumb()) || (isTargetNaCl() && !isThumb())); 349 } 350