1//===-- ARMTargetMachine.cpp - Define TargetMachine for ARM ---------------===// 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// 11//===----------------------------------------------------------------------===// 12 13#include "ARM.h" 14#include "ARMFrameLowering.h" 15#include "ARMTargetMachine.h" 16#include "ARMTargetObjectFile.h" 17#include "ARMTargetTransformInfo.h" 18#include "llvm/CodeGen/Passes.h" 19#include "llvm/CodeGen/TargetPassConfig.h" 20#include "llvm/IR/Function.h" 21#include "llvm/IR/LegacyPassManager.h" 22#include "llvm/MC/MCAsmInfo.h" 23#include "llvm/Support/CommandLine.h" 24#include "llvm/Support/FormattedStream.h" 25#include "llvm/Support/TargetRegistry.h" 26#include "llvm/Target/TargetOptions.h" 27#include "llvm/Transforms/Scalar.h" 28using namespace llvm; 29 30static cl::opt<bool> 31DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden, 32 cl::desc("Inhibit optimization of S->D register accesses on A15"), 33 cl::init(false)); 34 35static cl::opt<bool> 36EnableAtomicTidy("arm-atomic-cfg-tidy", cl::Hidden, 37 cl::desc("Run SimplifyCFG after expanding atomic operations" 38 " to make use of cmpxchg flow-based information"), 39 cl::init(true)); 40 41static cl::opt<bool> 42EnableARMLoadStoreOpt("arm-load-store-opt", cl::Hidden, 43 cl::desc("Enable ARM load/store optimization pass"), 44 cl::init(true)); 45 46// FIXME: Unify control over GlobalMerge. 47static cl::opt<cl::boolOrDefault> 48EnableGlobalMerge("arm-global-merge", cl::Hidden, 49 cl::desc("Enable the global merge pass")); 50 51extern "C" void LLVMInitializeARMTarget() { 52 // Register the target. 53 RegisterTargetMachine<ARMLETargetMachine> X(TheARMLETarget); 54 RegisterTargetMachine<ARMBETargetMachine> Y(TheARMBETarget); 55 RegisterTargetMachine<ThumbLETargetMachine> A(TheThumbLETarget); 56 RegisterTargetMachine<ThumbBETargetMachine> B(TheThumbBETarget); 57} 58 59static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) { 60 if (TT.isOSBinFormatMachO()) 61 return make_unique<TargetLoweringObjectFileMachO>(); 62 if (TT.isOSWindows()) 63 return make_unique<TargetLoweringObjectFileCOFF>(); 64 return make_unique<ARMElfTargetObjectFile>(); 65} 66 67static ARMBaseTargetMachine::ARMABI 68computeTargetABI(const Triple &TT, StringRef CPU, 69 const TargetOptions &Options) { 70 if (Options.MCOptions.getABIName() == "aapcs16") 71 return ARMBaseTargetMachine::ARM_ABI_AAPCS16; 72 else if (Options.MCOptions.getABIName().startswith("aapcs")) 73 return ARMBaseTargetMachine::ARM_ABI_AAPCS; 74 else if (Options.MCOptions.getABIName().startswith("apcs")) 75 return ARMBaseTargetMachine::ARM_ABI_APCS; 76 77 assert(Options.MCOptions.getABIName().empty() && 78 "Unknown target-abi option!"); 79 80 ARMBaseTargetMachine::ARMABI TargetABI = 81 ARMBaseTargetMachine::ARM_ABI_UNKNOWN; 82 83 // FIXME: This is duplicated code from the front end and should be unified. 84 if (TT.isOSBinFormatMachO()) { 85 if (TT.getEnvironment() == llvm::Triple::EABI || 86 (TT.getOS() == llvm::Triple::UnknownOS && TT.isOSBinFormatMachO()) || 87 CPU.startswith("cortex-m")) { 88 TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; 89 } else if (TT.isWatchABI()) { 90 TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS16; 91 } else { 92 TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS; 93 } 94 } else if (TT.isOSWindows()) { 95 // FIXME: this is invalid for WindowsCE 96 TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; 97 } else { 98 // Select the default based on the platform. 99 switch (TT.getEnvironment()) { 100 case llvm::Triple::Android: 101 case llvm::Triple::GNUEABI: 102 case llvm::Triple::GNUEABIHF: 103 case llvm::Triple::MuslEABI: 104 case llvm::Triple::MuslEABIHF: 105 case llvm::Triple::EABIHF: 106 case llvm::Triple::EABI: 107 TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; 108 break; 109 case llvm::Triple::GNU: 110 TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS; 111 break; 112 default: 113 if (TT.isOSNetBSD()) 114 TargetABI = ARMBaseTargetMachine::ARM_ABI_APCS; 115 else 116 TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS; 117 break; 118 } 119 } 120 121 return TargetABI; 122} 123 124static std::string computeDataLayout(const Triple &TT, StringRef CPU, 125 const TargetOptions &Options, 126 bool isLittle) { 127 auto ABI = computeTargetABI(TT, CPU, Options); 128 std::string Ret = ""; 129 130 if (isLittle) 131 // Little endian. 132 Ret += "e"; 133 else 134 // Big endian. 135 Ret += "E"; 136 137 Ret += DataLayout::getManglingComponent(TT); 138 139 // Pointers are 32 bits and aligned to 32 bits. 140 Ret += "-p:32:32"; 141 142 // ABIs other than APCS have 64 bit integers with natural alignment. 143 if (ABI != ARMBaseTargetMachine::ARM_ABI_APCS) 144 Ret += "-i64:64"; 145 146 // We have 64 bits floats. The APCS ABI requires them to be aligned to 32 147 // bits, others to 64 bits. We always try to align to 64 bits. 148 if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS) 149 Ret += "-f64:32:64"; 150 151 // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others 152 // to 64. We always ty to give them natural alignment. 153 if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS) 154 Ret += "-v64:32:64-v128:32:128"; 155 else if (ABI != ARMBaseTargetMachine::ARM_ABI_AAPCS16) 156 Ret += "-v128:64:128"; 157 158 // Try to align aggregates to 32 bits (the default is 64 bits, which has no 159 // particular hardware support on 32-bit ARM). 160 Ret += "-a:0:32"; 161 162 // Integer registers are 32 bits. 163 Ret += "-n32"; 164 165 // The stack is 128 bit aligned on NaCl, 64 bit aligned on AAPCS and 32 bit 166 // aligned everywhere else. 167 if (TT.isOSNaCl() || ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16) 168 Ret += "-S128"; 169 else if (ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS) 170 Ret += "-S64"; 171 else 172 Ret += "-S32"; 173 174 return Ret; 175} 176 177static Reloc::Model getEffectiveRelocModel(const Triple &TT, 178 Optional<Reloc::Model> RM) { 179 if (!RM.hasValue()) 180 // Default relocation model on Darwin is PIC. 181 return TT.isOSBinFormatMachO() ? Reloc::PIC_ : Reloc::Static; 182 183 // DynamicNoPIC is only used on darwin. 184 if (*RM == Reloc::DynamicNoPIC && !TT.isOSDarwin()) 185 return Reloc::Static; 186 187 return *RM; 188} 189 190/// Create an ARM architecture model. 191/// 192ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT, 193 StringRef CPU, StringRef FS, 194 const TargetOptions &Options, 195 Optional<Reloc::Model> RM, 196 CodeModel::Model CM, 197 CodeGenOpt::Level OL, bool isLittle) 198 : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, isLittle), TT, 199 CPU, FS, Options, getEffectiveRelocModel(TT, RM), CM, 200 OL), 201 TargetABI(computeTargetABI(TT, CPU, Options)), 202 TLOF(createTLOF(getTargetTriple())), 203 Subtarget(TT, CPU, FS, *this, isLittle), isLittle(isLittle) { 204 205 // Default to triple-appropriate float ABI 206 if (Options.FloatABIType == FloatABI::Default) 207 this->Options.FloatABIType = 208 Subtarget.isTargetHardFloat() ? FloatABI::Hard : FloatABI::Soft; 209 210 // Default to triple-appropriate EABI 211 if (Options.EABIVersion == EABI::Default || 212 Options.EABIVersion == EABI::Unknown) { 213 // musl is compatible with glibc with regard to EABI version 214 if (Subtarget.isTargetGNUAEABI() || Subtarget.isTargetMuslAEABI()) 215 this->Options.EABIVersion = EABI::GNU; 216 else 217 this->Options.EABIVersion = EABI::EABI5; 218 } 219} 220 221ARMBaseTargetMachine::~ARMBaseTargetMachine() {} 222 223const ARMSubtarget * 224ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const { 225 Attribute CPUAttr = F.getFnAttribute("target-cpu"); 226 Attribute FSAttr = F.getFnAttribute("target-features"); 227 228 std::string CPU = !CPUAttr.hasAttribute(Attribute::None) 229 ? CPUAttr.getValueAsString().str() 230 : TargetCPU; 231 std::string FS = !FSAttr.hasAttribute(Attribute::None) 232 ? FSAttr.getValueAsString().str() 233 : TargetFS; 234 235 // FIXME: This is related to the code below to reset the target options, 236 // we need to know whether or not the soft float flag is set on the 237 // function before we can generate a subtarget. We also need to use 238 // it as a key for the subtarget since that can be the only difference 239 // between two functions. 240 bool SoftFloat = 241 F.getFnAttribute("use-soft-float").getValueAsString() == "true"; 242 // If the soft float attribute is set on the function turn on the soft float 243 // subtarget feature. 244 if (SoftFloat) 245 FS += FS.empty() ? "+soft-float" : ",+soft-float"; 246 247 auto &I = SubtargetMap[CPU + FS]; 248 if (!I) { 249 // This needs to be done before we create a new subtarget since any 250 // creation will depend on the TM and the code generation flags on the 251 // function that reside in TargetOptions. 252 resetTargetOptions(F); 253 I = llvm::make_unique<ARMSubtarget>(TargetTriple, CPU, FS, *this, isLittle); 254 } 255 return I.get(); 256} 257 258TargetIRAnalysis ARMBaseTargetMachine::getTargetIRAnalysis() { 259 return TargetIRAnalysis([this](const Function &F) { 260 return TargetTransformInfo(ARMTTIImpl(this, F)); 261 }); 262} 263 264void ARMTargetMachine::anchor() {} 265 266ARMTargetMachine::ARMTargetMachine(const Target &T, const Triple &TT, 267 StringRef CPU, StringRef FS, 268 const TargetOptions &Options, 269 Optional<Reloc::Model> RM, 270 CodeModel::Model CM, CodeGenOpt::Level OL, 271 bool isLittle) 272 : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, isLittle) { 273 initAsmInfo(); 274 if (!Subtarget.hasARMOps()) 275 report_fatal_error("CPU: '" + Subtarget.getCPUString() + "' does not " 276 "support ARM mode execution!"); 277} 278 279void ARMLETargetMachine::anchor() {} 280 281ARMLETargetMachine::ARMLETargetMachine(const Target &T, const Triple &TT, 282 StringRef CPU, StringRef FS, 283 const TargetOptions &Options, 284 Optional<Reloc::Model> RM, 285 CodeModel::Model CM, 286 CodeGenOpt::Level OL) 287 : ARMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} 288 289void ARMBETargetMachine::anchor() {} 290 291ARMBETargetMachine::ARMBETargetMachine(const Target &T, const Triple &TT, 292 StringRef CPU, StringRef FS, 293 const TargetOptions &Options, 294 Optional<Reloc::Model> RM, 295 CodeModel::Model CM, 296 CodeGenOpt::Level OL) 297 : ARMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} 298 299void ThumbTargetMachine::anchor() {} 300 301ThumbTargetMachine::ThumbTargetMachine(const Target &T, const Triple &TT, 302 StringRef CPU, StringRef FS, 303 const TargetOptions &Options, 304 Optional<Reloc::Model> RM, 305 CodeModel::Model CM, 306 CodeGenOpt::Level OL, bool isLittle) 307 : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, isLittle) { 308 initAsmInfo(); 309} 310 311void ThumbLETargetMachine::anchor() {} 312 313ThumbLETargetMachine::ThumbLETargetMachine(const Target &T, const Triple &TT, 314 StringRef CPU, StringRef FS, 315 const TargetOptions &Options, 316 Optional<Reloc::Model> RM, 317 CodeModel::Model CM, 318 CodeGenOpt::Level OL) 319 : ThumbTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} 320 321void ThumbBETargetMachine::anchor() {} 322 323ThumbBETargetMachine::ThumbBETargetMachine(const Target &T, const Triple &TT, 324 StringRef CPU, StringRef FS, 325 const TargetOptions &Options, 326 Optional<Reloc::Model> RM, 327 CodeModel::Model CM, 328 CodeGenOpt::Level OL) 329 : ThumbTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} 330 331namespace { 332/// ARM Code Generator Pass Configuration Options. 333class ARMPassConfig : public TargetPassConfig { 334public: 335 ARMPassConfig(ARMBaseTargetMachine *TM, PassManagerBase &PM) 336 : TargetPassConfig(TM, PM) {} 337 338 ARMBaseTargetMachine &getARMTargetMachine() const { 339 return getTM<ARMBaseTargetMachine>(); 340 } 341 342 void addIRPasses() override; 343 bool addPreISel() override; 344 bool addInstSelector() override; 345 void addPreRegAlloc() override; 346 void addPreSched2() override; 347 void addPreEmitPass() override; 348}; 349} // namespace 350 351TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) { 352 return new ARMPassConfig(this, PM); 353} 354 355void ARMPassConfig::addIRPasses() { 356 if (TM->Options.ThreadModel == ThreadModel::Single) 357 addPass(createLowerAtomicPass()); 358 else 359 addPass(createAtomicExpandPass(TM)); 360 361 // Cmpxchg instructions are often used with a subsequent comparison to 362 // determine whether it succeeded. We can exploit existing control-flow in 363 // ldrex/strex loops to simplify this, but it needs tidying up. 364 if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy) 365 addPass(createCFGSimplificationPass(-1, [this](const Function &F) { 366 const auto &ST = this->TM->getSubtarget<ARMSubtarget>(F); 367 return ST.hasAnyDataBarrier() && !ST.isThumb1Only(); 368 })); 369 370 TargetPassConfig::addIRPasses(); 371 372 // Match interleaved memory accesses to ldN/stN intrinsics. 373 if (TM->getOptLevel() != CodeGenOpt::None) 374 addPass(createInterleavedAccessPass(TM)); 375} 376 377bool ARMPassConfig::addPreISel() { 378 if ((TM->getOptLevel() != CodeGenOpt::None && 379 EnableGlobalMerge == cl::BOU_UNSET) || 380 EnableGlobalMerge == cl::BOU_TRUE) { 381 // FIXME: This is using the thumb1 only constant value for 382 // maximal global offset for merging globals. We may want 383 // to look into using the old value for non-thumb1 code of 384 // 4095 based on the TargetMachine, but this starts to become 385 // tricky when doing code gen per function. 386 bool OnlyOptimizeForSize = (TM->getOptLevel() < CodeGenOpt::Aggressive) && 387 (EnableGlobalMerge == cl::BOU_UNSET); 388 // Merging of extern globals is enabled by default on non-Mach-O as we 389 // expect it to be generally either beneficial or harmless. On Mach-O it 390 // is disabled as we emit the .subsections_via_symbols directive which 391 // means that merging extern globals is not safe. 392 bool MergeExternalByDefault = !TM->getTargetTriple().isOSBinFormatMachO(); 393 addPass(createGlobalMergePass(TM, 127, OnlyOptimizeForSize, 394 MergeExternalByDefault)); 395 } 396 397 return false; 398} 399 400bool ARMPassConfig::addInstSelector() { 401 addPass(createARMISelDag(getARMTargetMachine(), getOptLevel())); 402 return false; 403} 404 405void ARMPassConfig::addPreRegAlloc() { 406 if (getOptLevel() != CodeGenOpt::None) { 407 addPass(createMLxExpansionPass()); 408 409 if (EnableARMLoadStoreOpt) 410 addPass(createARMLoadStoreOptimizationPass(/* pre-register alloc */ true)); 411 412 if (!DisableA15SDOptimization) 413 addPass(createA15SDOptimizerPass()); 414 } 415} 416 417void ARMPassConfig::addPreSched2() { 418 if (getOptLevel() != CodeGenOpt::None) { 419 if (EnableARMLoadStoreOpt) 420 addPass(createARMLoadStoreOptimizationPass()); 421 422 addPass(createExecutionDependencyFixPass(&ARM::DPRRegClass)); 423 } 424 425 // Expand some pseudo instructions into multiple instructions to allow 426 // proper scheduling. 427 addPass(createARMExpandPseudoPass()); 428 429 if (getOptLevel() != CodeGenOpt::None) { 430 // in v8, IfConversion depends on Thumb instruction widths 431 addPass(createThumb2SizeReductionPass([this](const Function &F) { 432 return this->TM->getSubtarget<ARMSubtarget>(F).restrictIT(); 433 })); 434 435 addPass(createIfConverter([this](const Function &F) { 436 return !this->TM->getSubtarget<ARMSubtarget>(F).isThumb1Only(); 437 })); 438 } 439 addPass(createThumb2ITBlockPass()); 440} 441 442void ARMPassConfig::addPreEmitPass() { 443 addPass(createThumb2SizeReductionPass()); 444 445 // Constant island pass work on unbundled instructions. 446 addPass(createUnpackMachineBundles([this](const Function &F) { 447 return this->TM->getSubtarget<ARMSubtarget>(F).isThumb2(); 448 })); 449 450 // Don't optimize barriers at -O0. 451 if (getOptLevel() != CodeGenOpt::None) 452 addPass(createARMOptimizeBarriersPass()); 453 454 addPass(createARMConstantIslandPass()); 455} 456