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 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 DarwinUseMOVT("arm-darwin-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 if (!isTargetIOS()) 173 UseMovt = hasV6T2Ops(); 174 else { 175 IsR9Reserved = ReserveR9 | !HasV6Ops; 176 UseMovt = DarwinUseMOVT && hasV6T2Ops(); 177 SupportsTailCall = !getTargetTriple().isOSVersionLT(5, 0); 178 } 179 180 if (!isThumb() || hasThumb2()) 181 PostRAScheduler = true; 182 183 switch (Align) { 184 case DefaultAlign: 185 // Assume pre-ARMv6 doesn't support unaligned accesses. 186 // 187 // ARMv6 may or may not support unaligned accesses depending on the 188 // SCTLR.U bit, which is architecture-specific. We assume ARMv6 189 // Darwin targets support unaligned accesses, and others don't. 190 // 191 // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit 192 // which raises an alignment fault on unaligned accesses. Linux 193 // defaults this bit to 0 and handles it as a system-wide (not 194 // per-process) setting. It is therefore safe to assume that ARMv7+ 195 // Linux targets support unaligned accesses. The same goes for NaCl. 196 // 197 // The above behavior is consistent with GCC. 198 AllowsUnalignedMem = ( 199 (hasV7Ops() && (isTargetLinux() || isTargetNaCl())) || 200 (hasV6Ops() && isTargetDarwin())); 201 break; 202 case StrictAlign: 203 AllowsUnalignedMem = false; 204 break; 205 case NoStrictAlign: 206 AllowsUnalignedMem = true; 207 break; 208 } 209 210 // NEON f32 ops are non-IEEE 754 compliant. Darwin is ok with it by default. 211 uint64_t Bits = getFeatureBits(); 212 if ((Bits & ARM::ProcA5 || Bits & ARM::ProcA8) && // Where this matters 213 (Options.UnsafeFPMath || isTargetDarwin())) 214 UseNEONForSinglePrecisionFP = true; 215 } 216 217 /// GVIsIndirectSymbol - true if the GV will be accessed via an indirect symbol. 218 bool 219 ARMSubtarget::GVIsIndirectSymbol(const GlobalValue *GV, 220 Reloc::Model RelocM) const { 221 if (RelocM == Reloc::Static) 222 return false; 223 224 // Materializable GVs (in JIT lazy compilation mode) do not require an extra 225 // load from stub. 226 bool isDecl = GV->hasAvailableExternallyLinkage(); 227 if (GV->isDeclaration() && !GV->isMaterializable()) 228 isDecl = true; 229 230 if (!isTargetDarwin()) { 231 // Extra load is needed for all externally visible. 232 if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) 233 return false; 234 return true; 235 } else { 236 if (RelocM == Reloc::PIC_) { 237 // If this is a strong reference to a definition, it is definitely not 238 // through a stub. 239 if (!isDecl && !GV->isWeakForLinker()) 240 return false; 241 242 // Unless we have a symbol with hidden visibility, we have to go through a 243 // normal $non_lazy_ptr stub because this symbol might be resolved late. 244 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 245 return true; 246 247 // If symbol visibility is hidden, we have a stub for common symbol 248 // references and external declarations. 249 if (isDecl || GV->hasCommonLinkage()) 250 // Hidden $non_lazy_ptr reference. 251 return true; 252 253 return false; 254 } else { 255 // If this is a strong reference to a definition, it is definitely not 256 // through a stub. 257 if (!isDecl && !GV->isWeakForLinker()) 258 return false; 259 260 // Unless we have a symbol with hidden visibility, we have to go through a 261 // normal $non_lazy_ptr stub because this symbol might be resolved late. 262 if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. 263 return true; 264 } 265 } 266 267 return false; 268 } 269 270 unsigned ARMSubtarget::getMispredictionPenalty() const { 271 return SchedModel->MispredictPenalty; 272 } 273 274 bool ARMSubtarget::enablePostRAScheduler( 275 CodeGenOpt::Level OptLevel, 276 TargetSubtargetInfo::AntiDepBreakMode& Mode, 277 RegClassVector& CriticalPathRCs) const { 278 Mode = TargetSubtargetInfo::ANTIDEP_CRITICAL; 279 CriticalPathRCs.clear(); 280 CriticalPathRCs.push_back(&ARM::GPRRegClass); 281 return PostRAScheduler && OptLevel >= CodeGenOpt::Default; 282 } 283