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 "ARMBaseInstrInfo.h" 16 #include "ARMBaseRegisterInfo.h" 17 #include "llvm/IR/Attributes.h" 18 #include "llvm/IR/GlobalValue.h" 19 #include "llvm/IR/Function.h" 20 #include "llvm/Support/CommandLine.h" 21 #include "llvm/Target/TargetInstrInfo.h" 22 #include "llvm/Target/TargetOptions.h" 23 24 #define GET_SUBTARGETINFO_TARGET_DESC 25 #define GET_SUBTARGETINFO_CTOR 26 #include "ARMGenSubtargetInfo.inc" 27 28 using namespace llvm; 29 30 static cl::opt<bool> 31 ReserveR9("arm-reserve-r9", cl::Hidden, 32 cl::desc("Reserve R9, making it unavailable as GPR")); 33 34 static cl::opt<bool> 35 ArmUseMOVT("arm-use-movt", cl::init(true), cl::Hidden); 36 37 static cl::opt<bool> 38 UseFusedMulOps("arm-use-mulops", 39 cl::init(true), cl::Hidden); 40 41 enum AlignMode { 42 DefaultAlign, 43 StrictAlign, 44 NoStrictAlign 45 }; 46 47 static cl::opt<AlignMode> 48 Align(cl::desc("Load/store alignment support"), 49 cl::Hidden, cl::init(DefaultAlign), 50 cl::values( 51 clEnumValN(DefaultAlign, "arm-default-align", 52 "Generate unaligned accesses only on hardware/OS " 53 "combinations that are known to support them"), 54 clEnumValN(StrictAlign, "arm-strict-align", 55 "Disallow all unaligned memory accesses"), 56 clEnumValN(NoStrictAlign, "arm-no-strict-align", 57 "Allow unaligned memory accesses"), 58 clEnumValEnd)); 59 60 ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &CPU, 61 const std::string &FS, const TargetOptions &Options) 62 : ARMGenSubtargetInfo(TT, CPU, FS) 63 , ARMProcFamily(Others) 64 , stackAlignment(4) 65 , CPUString(CPU) 66 , TargetTriple(TT) 67 , Options(Options) 68 , TargetABI(ARM_ABI_APCS) { 69 initializeEnvironment(); 70 resetSubtargetFeatures(CPU, FS); 71 } 72 73 void ARMSubtarget::initializeEnvironment() { 74 HasV4TOps = false; 75 HasV5TOps = false; 76 HasV5TEOps = false; 77 HasV6Ops = false; 78 HasV6T2Ops = false; 79 HasV7Ops = false; 80 HasV8Ops = false; 81 HasVFPv2 = false; 82 HasVFPv3 = false; 83 HasVFPv4 = false; 84 HasV8FP = false; 85 HasNEON = false; 86 UseNEONForSinglePrecisionFP = false; 87 UseMulOps = UseFusedMulOps; 88 SlowFPVMLx = false; 89 HasVMLxForwarding = false; 90 SlowFPBrcc = false; 91 InThumbMode = false; 92 HasThumb2 = false; 93 IsMClass = false; 94 NoARM = false; 95 PostRAScheduler = false; 96 IsR9Reserved = ReserveR9; 97 UseMovt = false; 98 SupportsTailCall = false; 99 HasFP16 = false; 100 HasD16 = false; 101 HasHardwareDivide = false; 102 HasHardwareDivideInARM = false; 103 HasT2ExtractPack = false; 104 HasDataBarrier = false; 105 Pref32BitThumb = false; 106 AvoidCPSRPartialUpdate = false; 107 AvoidMOVsShifterOperand = false; 108 HasRAS = false; 109 HasMPExtension = false; 110 FPOnlySP = false; 111 HasPerfMon = false; 112 HasTrustZone = false; 113 AllowsUnalignedMem = false; 114 Thumb2DSP = false; 115 UseNaClTrap = false; 116 UnsafeFPMath = false; 117 } 118 119 void ARMSubtarget::resetSubtargetFeatures(const MachineFunction *MF) { 120 AttributeSet FnAttrs = MF->getFunction()->getAttributes(); 121 Attribute CPUAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex, 122 "target-cpu"); 123 Attribute FSAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex, 124 "target-features"); 125 std::string CPU = 126 !CPUAttr.hasAttribute(Attribute::None) ?CPUAttr.getValueAsString() : ""; 127 std::string FS = 128 !FSAttr.hasAttribute(Attribute::None) ? FSAttr.getValueAsString() : ""; 129 if (!FS.empty()) { 130 initializeEnvironment(); 131 resetSubtargetFeatures(CPU, FS); 132 } 133 } 134 135 void ARMSubtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) { 136 if (CPUString.empty()) 137 CPUString = "generic"; 138 139 // Insert the architecture feature derived from the target triple into the 140 // feature string. This is important for setting features that are implied 141 // based on the architecture version. 142 std::string ArchFS = ARM_MC::ParseARMTriple(TargetTriple.getTriple(), 143 CPUString); 144 if (!FS.empty()) { 145 if (!ArchFS.empty()) 146 ArchFS = ArchFS + "," + FS.str(); 147 else 148 ArchFS = FS; 149 } 150 ParseSubtargetFeatures(CPUString, ArchFS); 151 152 // Thumb2 implies at least V6T2. FIXME: Fix tests to explicitly specify a 153 // ARM version or CPU and then remove this. 154 if (!HasV6T2Ops && hasThumb2()) 155 HasV4TOps = HasV5TOps = HasV5TEOps = HasV6Ops = HasV6T2Ops = true; 156 157 // Keep a pointer to static instruction cost data for the specified CPU. 158 SchedModel = getSchedModelForCPU(CPUString); 159 160 // Initialize scheduling itinerary for the specified CPU. 161 InstrItins = getInstrItineraryForCPU(CPUString); 162 163 if ((TargetTriple.getTriple().find("eabi") != std::string::npos) || 164 (isTargetIOS() && isMClass())) 165 // FIXME: We might want to separate AAPCS and EABI. Some systems, e.g. 166 // Darwin-EABI conforms to AACPS but not the rest of EABI. 167 TargetABI = ARM_ABI_AAPCS; 168 169 if (isAAPCS_ABI()) 170 stackAlignment = 8; 171 172 UseMovt = hasV6T2Ops() && ArmUseMOVT; 173 174 if (!isTargetIOS()) { 175 IsR9Reserved = ReserveR9; 176 } else { 177 IsR9Reserved = ReserveR9 | !HasV6Ops; 178 SupportsTailCall = !getTargetTriple().isOSVersionLT(5, 0); 179 } 180 181 if (!isThumb() || hasThumb2()) 182 PostRAScheduler = true; 183 184 switch (Align) { 185 case DefaultAlign: 186 // Assume pre-ARMv6 doesn't support unaligned accesses. 187 // 188 // ARMv6 may or may not support unaligned accesses depending on the 189 // SCTLR.U bit, which is architecture-specific. We assume ARMv6 190 // Darwin targets support unaligned accesses, and others don't. 191 // 192 // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit 193 // which raises an alignment fault on unaligned accesses. Linux 194 // defaults this bit to 0 and handles it as a system-wide (not 195 // per-process) setting. It is therefore safe to assume that ARMv7+ 196 // Linux targets support unaligned accesses. The same goes for NaCl. 197 // 198 // The above behavior is consistent with GCC. 199 AllowsUnalignedMem = ( 200 (hasV7Ops() && (isTargetLinux() || isTargetNaCl())) || 201 (hasV6Ops() && isTargetDarwin())); 202 break; 203 case StrictAlign: 204 AllowsUnalignedMem = false; 205 break; 206 case NoStrictAlign: 207 AllowsUnalignedMem = true; 208 break; 209 } 210 211 // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default. 212 uint64_t Bits = getFeatureBits(); 213 if ((Bits & ARM::ProcA5 || Bits & ARM::ProcA8) && // Where this matters 214 (Options.UnsafeFPMath || isTargetDarwin())) 215 UseNEONForSinglePrecisionFP = true; 216 } 217 218 /// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol. 219 bool 220 ARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV, 221 Reloc::Model RelocM) const { 222 if (RelocM == Reloc::Static) 223 return false; 224 225 // Materializable GVs (in JIT lazy compilation mode) do not require an extra 226 // load from stub. 227 bool isDecl = GV->hasAvailableExternallyLinkage(); 228 if (GV->isDeclaration() && !GV->isMaterializable()) 229 isDecl = true; 230 231 if (!isTargetDarwin()) { 232 // Extra load is needed for all externally visible. 233 if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) 234 return false; 235 return true; 236 } else { 237 if (RelocM == Reloc::PIC_) { 238 // If this is a strong reference to a definition, it is definitely not 239 // through a stub. 240 if (!isDecl && !GV->isWeakForLinker()) 241 return false; 242 243 // Unless we have a symbol with hidden visibility, we have to go through a 244 // normal $non_lazy_ptr stub because this symbol might be resolved late. 245 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 246 return true; 247 248 // If symbol visibility is hidden, we have a stub for common symbol 249 // references and external declarations. 250 if (isDecl || GV->hasCommonLinkage()) 251 // Hidden $non_lazy_ptr reference. 252 return true; 253 254 return false; 255 } else { 256 // If this is a strong reference to a definition, it is definitely not 257 // through a stub. 258 if (!isDecl && !GV->isWeakForLinker()) 259 return false; 260 261 // Unless we have a symbol with hidden visibility, we have to go through a 262 // normal $non_lazy_ptr stub because this symbol might be resolved late. 263 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 264 return true; 265 } 266 } 267 268 return false; 269 } 270 271 unsigned ARMSubtarget::getMispredictionPenalty() const { 272 return SchedModel->MispredictPenalty; 273 } 274 275 bool ARMSubtarget::enablePostRAScheduler( 276 CodeGenOpt::Level OptLevel, 277 TargetSubtargetInfo::AntiDepBreakMode& Mode, 278 RegClassVector& CriticalPathRCs) const { 279 Mode = TargetSubtargetInfo::ANTIDEP_CRITICAL; 280 CriticalPathRCs.clear(); 281 CriticalPathRCs.push_back(&ARM::GPRRegClass); 282 return PostRAScheduler && OptLevel >= CodeGenOpt::Default; 283 } 284