1*0b57cec5SDimitry Andric //===-- ARMTargetMachine.cpp - Define TargetMachine for ARM ---------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // 10*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11*0b57cec5SDimitry Andric 12*0b57cec5SDimitry Andric #include "ARMTargetMachine.h" 13*0b57cec5SDimitry Andric #include "ARM.h" 14*0b57cec5SDimitry Andric #include "ARMMacroFusion.h" 15*0b57cec5SDimitry Andric #include "ARMSubtarget.h" 16*0b57cec5SDimitry Andric #include "ARMTargetObjectFile.h" 17*0b57cec5SDimitry Andric #include "ARMTargetTransformInfo.h" 18*0b57cec5SDimitry Andric #include "MCTargetDesc/ARMMCTargetDesc.h" 19*0b57cec5SDimitry Andric #include "TargetInfo/ARMTargetInfo.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/Optional.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 22*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 23*0b57cec5SDimitry Andric #include "llvm/ADT/Triple.h" 24*0b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 25*0b57cec5SDimitry Andric #include "llvm/CodeGen/ExecutionDomainFix.h" 26*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CallLowering.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/IRTranslator.h" 28*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" 29*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" 33*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" 34*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 36*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 37*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 38*0b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 39*0b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 40*0b57cec5SDimitry Andric #include "llvm/IR/Function.h" 41*0b57cec5SDimitry Andric #include "llvm/Pass.h" 42*0b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h" 43*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 44*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 45*0b57cec5SDimitry Andric #include "llvm/Support/TargetParser.h" 46*0b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 47*0b57cec5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h" 48*0b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 49*0b57cec5SDimitry Andric #include "llvm/Transforms/Scalar.h" 50*0b57cec5SDimitry Andric #include <cassert> 51*0b57cec5SDimitry Andric #include <memory> 52*0b57cec5SDimitry Andric #include <string> 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric using namespace llvm; 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric static cl::opt<bool> 57*0b57cec5SDimitry Andric DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden, 58*0b57cec5SDimitry Andric cl::desc("Inhibit optimization of S->D register accesses on A15"), 59*0b57cec5SDimitry Andric cl::init(false)); 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric static cl::opt<bool> 62*0b57cec5SDimitry Andric EnableAtomicTidy("arm-atomic-cfg-tidy", cl::Hidden, 63*0b57cec5SDimitry Andric cl::desc("Run SimplifyCFG after expanding atomic operations" 64*0b57cec5SDimitry Andric " to make use of cmpxchg flow-based information"), 65*0b57cec5SDimitry Andric cl::init(true)); 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric static cl::opt<bool> 68*0b57cec5SDimitry Andric EnableARMLoadStoreOpt("arm-load-store-opt", cl::Hidden, 69*0b57cec5SDimitry Andric cl::desc("Enable ARM load/store optimization pass"), 70*0b57cec5SDimitry Andric cl::init(true)); 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric // FIXME: Unify control over GlobalMerge. 73*0b57cec5SDimitry Andric static cl::opt<cl::boolOrDefault> 74*0b57cec5SDimitry Andric EnableGlobalMerge("arm-global-merge", cl::Hidden, 75*0b57cec5SDimitry Andric cl::desc("Enable the global merge pass")); 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric namespace llvm { 78*0b57cec5SDimitry Andric void initializeARMExecutionDomainFixPass(PassRegistry&); 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric extern "C" void LLVMInitializeARMTarget() { 82*0b57cec5SDimitry Andric // Register the target. 83*0b57cec5SDimitry Andric RegisterTargetMachine<ARMLETargetMachine> X(getTheARMLETarget()); 84*0b57cec5SDimitry Andric RegisterTargetMachine<ARMLETargetMachine> A(getTheThumbLETarget()); 85*0b57cec5SDimitry Andric RegisterTargetMachine<ARMBETargetMachine> Y(getTheARMBETarget()); 86*0b57cec5SDimitry Andric RegisterTargetMachine<ARMBETargetMachine> B(getTheThumbBETarget()); 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric PassRegistry &Registry = *PassRegistry::getPassRegistry(); 89*0b57cec5SDimitry Andric initializeGlobalISel(Registry); 90*0b57cec5SDimitry Andric initializeARMLoadStoreOptPass(Registry); 91*0b57cec5SDimitry Andric initializeARMPreAllocLoadStoreOptPass(Registry); 92*0b57cec5SDimitry Andric initializeARMParallelDSPPass(Registry); 93*0b57cec5SDimitry Andric initializeARMCodeGenPreparePass(Registry); 94*0b57cec5SDimitry Andric initializeARMConstantIslandsPass(Registry); 95*0b57cec5SDimitry Andric initializeARMExecutionDomainFixPass(Registry); 96*0b57cec5SDimitry Andric initializeARMExpandPseudoPass(Registry); 97*0b57cec5SDimitry Andric initializeThumb2SizeReducePass(Registry); 98*0b57cec5SDimitry Andric initializeMVEVPTBlockPass(Registry); 99*0b57cec5SDimitry Andric initializeARMLowOverheadLoopsPass(Registry); 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) { 103*0b57cec5SDimitry Andric if (TT.isOSBinFormatMachO()) 104*0b57cec5SDimitry Andric return llvm::make_unique<TargetLoweringObjectFileMachO>(); 105*0b57cec5SDimitry Andric if (TT.isOSWindows()) 106*0b57cec5SDimitry Andric return llvm::make_unique<TargetLoweringObjectFileCOFF>(); 107*0b57cec5SDimitry Andric return llvm::make_unique<ARMElfTargetObjectFile>(); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric static ARMBaseTargetMachine::ARMABI 111*0b57cec5SDimitry Andric computeTargetABI(const Triple &TT, StringRef CPU, 112*0b57cec5SDimitry Andric const TargetOptions &Options) { 113*0b57cec5SDimitry Andric StringRef ABIName = Options.MCOptions.getABIName(); 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric if (ABIName.empty()) 116*0b57cec5SDimitry Andric ABIName = ARM::computeDefaultTargetABI(TT, CPU); 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric if (ABIName == "aapcs16") 119*0b57cec5SDimitry Andric return ARMBaseTargetMachine::ARM_ABI_AAPCS16; 120*0b57cec5SDimitry Andric else if (ABIName.startswith("aapcs")) 121*0b57cec5SDimitry Andric return ARMBaseTargetMachine::ARM_ABI_AAPCS; 122*0b57cec5SDimitry Andric else if (ABIName.startswith("apcs")) 123*0b57cec5SDimitry Andric return ARMBaseTargetMachine::ARM_ABI_APCS; 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric llvm_unreachable("Unhandled/unknown ABI Name!"); 126*0b57cec5SDimitry Andric return ARMBaseTargetMachine::ARM_ABI_UNKNOWN; 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric static std::string computeDataLayout(const Triple &TT, StringRef CPU, 130*0b57cec5SDimitry Andric const TargetOptions &Options, 131*0b57cec5SDimitry Andric bool isLittle) { 132*0b57cec5SDimitry Andric auto ABI = computeTargetABI(TT, CPU, Options); 133*0b57cec5SDimitry Andric std::string Ret; 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric if (isLittle) 136*0b57cec5SDimitry Andric // Little endian. 137*0b57cec5SDimitry Andric Ret += "e"; 138*0b57cec5SDimitry Andric else 139*0b57cec5SDimitry Andric // Big endian. 140*0b57cec5SDimitry Andric Ret += "E"; 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric Ret += DataLayout::getManglingComponent(TT); 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric // Pointers are 32 bits and aligned to 32 bits. 145*0b57cec5SDimitry Andric Ret += "-p:32:32"; 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric // Function pointers are aligned to 8 bits (because the LSB stores the 148*0b57cec5SDimitry Andric // ARM/Thumb state). 149*0b57cec5SDimitry Andric Ret += "-Fi8"; 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric // ABIs other than APCS have 64 bit integers with natural alignment. 152*0b57cec5SDimitry Andric if (ABI != ARMBaseTargetMachine::ARM_ABI_APCS) 153*0b57cec5SDimitry Andric Ret += "-i64:64"; 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric // We have 64 bits floats. The APCS ABI requires them to be aligned to 32 156*0b57cec5SDimitry Andric // bits, others to 64 bits. We always try to align to 64 bits. 157*0b57cec5SDimitry Andric if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS) 158*0b57cec5SDimitry Andric Ret += "-f64:32:64"; 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others 161*0b57cec5SDimitry Andric // to 64. We always ty to give them natural alignment. 162*0b57cec5SDimitry Andric if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS) 163*0b57cec5SDimitry Andric Ret += "-v64:32:64-v128:32:128"; 164*0b57cec5SDimitry Andric else if (ABI != ARMBaseTargetMachine::ARM_ABI_AAPCS16) 165*0b57cec5SDimitry Andric Ret += "-v128:64:128"; 166*0b57cec5SDimitry Andric 167*0b57cec5SDimitry Andric // Try to align aggregates to 32 bits (the default is 64 bits, which has no 168*0b57cec5SDimitry Andric // particular hardware support on 32-bit ARM). 169*0b57cec5SDimitry Andric Ret += "-a:0:32"; 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric // Integer registers are 32 bits. 172*0b57cec5SDimitry Andric Ret += "-n32"; 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric // The stack is 128 bit aligned on NaCl, 64 bit aligned on AAPCS and 32 bit 175*0b57cec5SDimitry Andric // aligned everywhere else. 176*0b57cec5SDimitry Andric if (TT.isOSNaCl() || ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16) 177*0b57cec5SDimitry Andric Ret += "-S128"; 178*0b57cec5SDimitry Andric else if (ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS) 179*0b57cec5SDimitry Andric Ret += "-S64"; 180*0b57cec5SDimitry Andric else 181*0b57cec5SDimitry Andric Ret += "-S32"; 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric return Ret; 184*0b57cec5SDimitry Andric } 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric static Reloc::Model getEffectiveRelocModel(const Triple &TT, 187*0b57cec5SDimitry Andric Optional<Reloc::Model> RM) { 188*0b57cec5SDimitry Andric if (!RM.hasValue()) 189*0b57cec5SDimitry Andric // Default relocation model on Darwin is PIC. 190*0b57cec5SDimitry Andric return TT.isOSBinFormatMachO() ? Reloc::PIC_ : Reloc::Static; 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric if (*RM == Reloc::ROPI || *RM == Reloc::RWPI || *RM == Reloc::ROPI_RWPI) 193*0b57cec5SDimitry Andric assert(TT.isOSBinFormatELF() && 194*0b57cec5SDimitry Andric "ROPI/RWPI currently only supported for ELF"); 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric // DynamicNoPIC is only used on darwin. 197*0b57cec5SDimitry Andric if (*RM == Reloc::DynamicNoPIC && !TT.isOSDarwin()) 198*0b57cec5SDimitry Andric return Reloc::Static; 199*0b57cec5SDimitry Andric 200*0b57cec5SDimitry Andric return *RM; 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric /// Create an ARM architecture model. 204*0b57cec5SDimitry Andric /// 205*0b57cec5SDimitry Andric ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT, 206*0b57cec5SDimitry Andric StringRef CPU, StringRef FS, 207*0b57cec5SDimitry Andric const TargetOptions &Options, 208*0b57cec5SDimitry Andric Optional<Reloc::Model> RM, 209*0b57cec5SDimitry Andric Optional<CodeModel::Model> CM, 210*0b57cec5SDimitry Andric CodeGenOpt::Level OL, bool isLittle) 211*0b57cec5SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, isLittle), TT, 212*0b57cec5SDimitry Andric CPU, FS, Options, getEffectiveRelocModel(TT, RM), 213*0b57cec5SDimitry Andric getEffectiveCodeModel(CM, CodeModel::Small), OL), 214*0b57cec5SDimitry Andric TargetABI(computeTargetABI(TT, CPU, Options)), 215*0b57cec5SDimitry Andric TLOF(createTLOF(getTargetTriple())), isLittle(isLittle) { 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric // Default to triple-appropriate float ABI 218*0b57cec5SDimitry Andric if (Options.FloatABIType == FloatABI::Default) { 219*0b57cec5SDimitry Andric if (isTargetHardFloat()) 220*0b57cec5SDimitry Andric this->Options.FloatABIType = FloatABI::Hard; 221*0b57cec5SDimitry Andric else 222*0b57cec5SDimitry Andric this->Options.FloatABIType = FloatABI::Soft; 223*0b57cec5SDimitry Andric } 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric // Default to triple-appropriate EABI 226*0b57cec5SDimitry Andric if (Options.EABIVersion == EABI::Default || 227*0b57cec5SDimitry Andric Options.EABIVersion == EABI::Unknown) { 228*0b57cec5SDimitry Andric // musl is compatible with glibc with regard to EABI version 229*0b57cec5SDimitry Andric if ((TargetTriple.getEnvironment() == Triple::GNUEABI || 230*0b57cec5SDimitry Andric TargetTriple.getEnvironment() == Triple::GNUEABIHF || 231*0b57cec5SDimitry Andric TargetTriple.getEnvironment() == Triple::MuslEABI || 232*0b57cec5SDimitry Andric TargetTriple.getEnvironment() == Triple::MuslEABIHF) && 233*0b57cec5SDimitry Andric !(TargetTriple.isOSWindows() || TargetTriple.isOSDarwin())) 234*0b57cec5SDimitry Andric this->Options.EABIVersion = EABI::GNU; 235*0b57cec5SDimitry Andric else 236*0b57cec5SDimitry Andric this->Options.EABIVersion = EABI::EABI5; 237*0b57cec5SDimitry Andric } 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric if (TT.isOSBinFormatMachO()) { 240*0b57cec5SDimitry Andric this->Options.TrapUnreachable = true; 241*0b57cec5SDimitry Andric this->Options.NoTrapAfterNoreturn = true; 242*0b57cec5SDimitry Andric } 243*0b57cec5SDimitry Andric 244*0b57cec5SDimitry Andric initAsmInfo(); 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric ARMBaseTargetMachine::~ARMBaseTargetMachine() = default; 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric const ARMSubtarget * 250*0b57cec5SDimitry Andric ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const { 251*0b57cec5SDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 252*0b57cec5SDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric std::string CPU = !CPUAttr.hasAttribute(Attribute::None) 255*0b57cec5SDimitry Andric ? CPUAttr.getValueAsString().str() 256*0b57cec5SDimitry Andric : TargetCPU; 257*0b57cec5SDimitry Andric std::string FS = !FSAttr.hasAttribute(Attribute::None) 258*0b57cec5SDimitry Andric ? FSAttr.getValueAsString().str() 259*0b57cec5SDimitry Andric : TargetFS; 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric // FIXME: This is related to the code below to reset the target options, 262*0b57cec5SDimitry Andric // we need to know whether or not the soft float flag is set on the 263*0b57cec5SDimitry Andric // function before we can generate a subtarget. We also need to use 264*0b57cec5SDimitry Andric // it as a key for the subtarget since that can be the only difference 265*0b57cec5SDimitry Andric // between two functions. 266*0b57cec5SDimitry Andric bool SoftFloat = 267*0b57cec5SDimitry Andric F.getFnAttribute("use-soft-float").getValueAsString() == "true"; 268*0b57cec5SDimitry Andric // If the soft float attribute is set on the function turn on the soft float 269*0b57cec5SDimitry Andric // subtarget feature. 270*0b57cec5SDimitry Andric if (SoftFloat) 271*0b57cec5SDimitry Andric FS += FS.empty() ? "+soft-float" : ",+soft-float"; 272*0b57cec5SDimitry Andric 273*0b57cec5SDimitry Andric // Use the optminsize to identify the subtarget, but don't use it in the 274*0b57cec5SDimitry Andric // feature string. 275*0b57cec5SDimitry Andric std::string Key = CPU + FS; 276*0b57cec5SDimitry Andric if (F.hasMinSize()) 277*0b57cec5SDimitry Andric Key += "+minsize"; 278*0b57cec5SDimitry Andric 279*0b57cec5SDimitry Andric auto &I = SubtargetMap[Key]; 280*0b57cec5SDimitry Andric if (!I) { 281*0b57cec5SDimitry Andric // This needs to be done before we create a new subtarget since any 282*0b57cec5SDimitry Andric // creation will depend on the TM and the code generation flags on the 283*0b57cec5SDimitry Andric // function that reside in TargetOptions. 284*0b57cec5SDimitry Andric resetTargetOptions(F); 285*0b57cec5SDimitry Andric I = llvm::make_unique<ARMSubtarget>(TargetTriple, CPU, FS, *this, isLittle, 286*0b57cec5SDimitry Andric F.hasMinSize()); 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric if (!I->isThumb() && !I->hasARMOps()) 289*0b57cec5SDimitry Andric F.getContext().emitError("Function '" + F.getName() + "' uses ARM " 290*0b57cec5SDimitry Andric "instructions, but the target does not support ARM mode execution."); 291*0b57cec5SDimitry Andric } 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric return I.get(); 294*0b57cec5SDimitry Andric } 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric TargetTransformInfo 297*0b57cec5SDimitry Andric ARMBaseTargetMachine::getTargetTransformInfo(const Function &F) { 298*0b57cec5SDimitry Andric return TargetTransformInfo(ARMTTIImpl(this, F)); 299*0b57cec5SDimitry Andric } 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric ARMLETargetMachine::ARMLETargetMachine(const Target &T, const Triple &TT, 302*0b57cec5SDimitry Andric StringRef CPU, StringRef FS, 303*0b57cec5SDimitry Andric const TargetOptions &Options, 304*0b57cec5SDimitry Andric Optional<Reloc::Model> RM, 305*0b57cec5SDimitry Andric Optional<CodeModel::Model> CM, 306*0b57cec5SDimitry Andric CodeGenOpt::Level OL, bool JIT) 307*0b57cec5SDimitry Andric : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} 308*0b57cec5SDimitry Andric 309*0b57cec5SDimitry Andric ARMBETargetMachine::ARMBETargetMachine(const Target &T, const Triple &TT, 310*0b57cec5SDimitry Andric StringRef CPU, StringRef FS, 311*0b57cec5SDimitry Andric const TargetOptions &Options, 312*0b57cec5SDimitry Andric Optional<Reloc::Model> RM, 313*0b57cec5SDimitry Andric Optional<CodeModel::Model> CM, 314*0b57cec5SDimitry Andric CodeGenOpt::Level OL, bool JIT) 315*0b57cec5SDimitry Andric : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric namespace { 318*0b57cec5SDimitry Andric 319*0b57cec5SDimitry Andric /// ARM Code Generator Pass Configuration Options. 320*0b57cec5SDimitry Andric class ARMPassConfig : public TargetPassConfig { 321*0b57cec5SDimitry Andric public: 322*0b57cec5SDimitry Andric ARMPassConfig(ARMBaseTargetMachine &TM, PassManagerBase &PM) 323*0b57cec5SDimitry Andric : TargetPassConfig(TM, PM) { 324*0b57cec5SDimitry Andric if (TM.getOptLevel() != CodeGenOpt::None) { 325*0b57cec5SDimitry Andric ARMGenSubtargetInfo STI(TM.getTargetTriple(), TM.getTargetCPU(), 326*0b57cec5SDimitry Andric TM.getTargetFeatureString()); 327*0b57cec5SDimitry Andric if (STI.hasFeature(ARM::FeatureUseMISched)) 328*0b57cec5SDimitry Andric substitutePass(&PostRASchedulerID, &PostMachineSchedulerID); 329*0b57cec5SDimitry Andric } 330*0b57cec5SDimitry Andric } 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric ARMBaseTargetMachine &getARMTargetMachine() const { 333*0b57cec5SDimitry Andric return getTM<ARMBaseTargetMachine>(); 334*0b57cec5SDimitry Andric } 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric ScheduleDAGInstrs * 337*0b57cec5SDimitry Andric createMachineScheduler(MachineSchedContext *C) const override { 338*0b57cec5SDimitry Andric ScheduleDAGMILive *DAG = createGenericSchedLive(C); 339*0b57cec5SDimitry Andric // add DAG Mutations here. 340*0b57cec5SDimitry Andric const ARMSubtarget &ST = C->MF->getSubtarget<ARMSubtarget>(); 341*0b57cec5SDimitry Andric if (ST.hasFusion()) 342*0b57cec5SDimitry Andric DAG->addMutation(createARMMacroFusionDAGMutation()); 343*0b57cec5SDimitry Andric return DAG; 344*0b57cec5SDimitry Andric } 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric ScheduleDAGInstrs * 347*0b57cec5SDimitry Andric createPostMachineScheduler(MachineSchedContext *C) const override { 348*0b57cec5SDimitry Andric ScheduleDAGMI *DAG = createGenericSchedPostRA(C); 349*0b57cec5SDimitry Andric // add DAG Mutations here. 350*0b57cec5SDimitry Andric const ARMSubtarget &ST = C->MF->getSubtarget<ARMSubtarget>(); 351*0b57cec5SDimitry Andric if (ST.hasFusion()) 352*0b57cec5SDimitry Andric DAG->addMutation(createARMMacroFusionDAGMutation()); 353*0b57cec5SDimitry Andric return DAG; 354*0b57cec5SDimitry Andric } 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric void addIRPasses() override; 357*0b57cec5SDimitry Andric void addCodeGenPrepare() override; 358*0b57cec5SDimitry Andric bool addPreISel() override; 359*0b57cec5SDimitry Andric bool addInstSelector() override; 360*0b57cec5SDimitry Andric bool addIRTranslator() override; 361*0b57cec5SDimitry Andric bool addLegalizeMachineIR() override; 362*0b57cec5SDimitry Andric bool addRegBankSelect() override; 363*0b57cec5SDimitry Andric bool addGlobalInstructionSelect() override; 364*0b57cec5SDimitry Andric void addPreRegAlloc() override; 365*0b57cec5SDimitry Andric void addPreSched2() override; 366*0b57cec5SDimitry Andric void addPreEmitPass() override; 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric std::unique_ptr<CSEConfigBase> getCSEConfig() const override; 369*0b57cec5SDimitry Andric }; 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric class ARMExecutionDomainFix : public ExecutionDomainFix { 372*0b57cec5SDimitry Andric public: 373*0b57cec5SDimitry Andric static char ID; 374*0b57cec5SDimitry Andric ARMExecutionDomainFix() : ExecutionDomainFix(ID, ARM::DPRRegClass) {} 375*0b57cec5SDimitry Andric StringRef getPassName() const override { 376*0b57cec5SDimitry Andric return "ARM Execution Domain Fix"; 377*0b57cec5SDimitry Andric } 378*0b57cec5SDimitry Andric }; 379*0b57cec5SDimitry Andric char ARMExecutionDomainFix::ID; 380*0b57cec5SDimitry Andric 381*0b57cec5SDimitry Andric } // end anonymous namespace 382*0b57cec5SDimitry Andric 383*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(ARMExecutionDomainFix, "arm-execution-domain-fix", 384*0b57cec5SDimitry Andric "ARM Execution Domain Fix", false, false) 385*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis) 386*0b57cec5SDimitry Andric INITIALIZE_PASS_END(ARMExecutionDomainFix, "arm-execution-domain-fix", 387*0b57cec5SDimitry Andric "ARM Execution Domain Fix", false, false) 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) { 390*0b57cec5SDimitry Andric return new ARMPassConfig(*this, PM); 391*0b57cec5SDimitry Andric } 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric std::unique_ptr<CSEConfigBase> ARMPassConfig::getCSEConfig() const { 394*0b57cec5SDimitry Andric return getStandardCSEConfigForOpt(TM->getOptLevel()); 395*0b57cec5SDimitry Andric } 396*0b57cec5SDimitry Andric 397*0b57cec5SDimitry Andric void ARMPassConfig::addIRPasses() { 398*0b57cec5SDimitry Andric if (TM->Options.ThreadModel == ThreadModel::Single) 399*0b57cec5SDimitry Andric addPass(createLowerAtomicPass()); 400*0b57cec5SDimitry Andric else 401*0b57cec5SDimitry Andric addPass(createAtomicExpandPass()); 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric // Cmpxchg instructions are often used with a subsequent comparison to 404*0b57cec5SDimitry Andric // determine whether it succeeded. We can exploit existing control-flow in 405*0b57cec5SDimitry Andric // ldrex/strex loops to simplify this, but it needs tidying up. 406*0b57cec5SDimitry Andric if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy) 407*0b57cec5SDimitry Andric addPass(createCFGSimplificationPass( 408*0b57cec5SDimitry Andric 1, false, false, true, true, [this](const Function &F) { 409*0b57cec5SDimitry Andric const auto &ST = this->TM->getSubtarget<ARMSubtarget>(F); 410*0b57cec5SDimitry Andric return ST.hasAnyDataBarrier() && !ST.isThumb1Only(); 411*0b57cec5SDimitry Andric })); 412*0b57cec5SDimitry Andric 413*0b57cec5SDimitry Andric TargetPassConfig::addIRPasses(); 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric // Run the parallel DSP pass. 416*0b57cec5SDimitry Andric if (getOptLevel() == CodeGenOpt::Aggressive) 417*0b57cec5SDimitry Andric addPass(createARMParallelDSPPass()); 418*0b57cec5SDimitry Andric 419*0b57cec5SDimitry Andric // Match interleaved memory accesses to ldN/stN intrinsics. 420*0b57cec5SDimitry Andric if (TM->getOptLevel() != CodeGenOpt::None) 421*0b57cec5SDimitry Andric addPass(createInterleavedAccessPass()); 422*0b57cec5SDimitry Andric } 423*0b57cec5SDimitry Andric 424*0b57cec5SDimitry Andric void ARMPassConfig::addCodeGenPrepare() { 425*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 426*0b57cec5SDimitry Andric addPass(createARMCodeGenPreparePass()); 427*0b57cec5SDimitry Andric TargetPassConfig::addCodeGenPrepare(); 428*0b57cec5SDimitry Andric } 429*0b57cec5SDimitry Andric 430*0b57cec5SDimitry Andric bool ARMPassConfig::addPreISel() { 431*0b57cec5SDimitry Andric if ((TM->getOptLevel() != CodeGenOpt::None && 432*0b57cec5SDimitry Andric EnableGlobalMerge == cl::BOU_UNSET) || 433*0b57cec5SDimitry Andric EnableGlobalMerge == cl::BOU_TRUE) { 434*0b57cec5SDimitry Andric // FIXME: This is using the thumb1 only constant value for 435*0b57cec5SDimitry Andric // maximal global offset for merging globals. We may want 436*0b57cec5SDimitry Andric // to look into using the old value for non-thumb1 code of 437*0b57cec5SDimitry Andric // 4095 based on the TargetMachine, but this starts to become 438*0b57cec5SDimitry Andric // tricky when doing code gen per function. 439*0b57cec5SDimitry Andric bool OnlyOptimizeForSize = (TM->getOptLevel() < CodeGenOpt::Aggressive) && 440*0b57cec5SDimitry Andric (EnableGlobalMerge == cl::BOU_UNSET); 441*0b57cec5SDimitry Andric // Merging of extern globals is enabled by default on non-Mach-O as we 442*0b57cec5SDimitry Andric // expect it to be generally either beneficial or harmless. On Mach-O it 443*0b57cec5SDimitry Andric // is disabled as we emit the .subsections_via_symbols directive which 444*0b57cec5SDimitry Andric // means that merging extern globals is not safe. 445*0b57cec5SDimitry Andric bool MergeExternalByDefault = !TM->getTargetTriple().isOSBinFormatMachO(); 446*0b57cec5SDimitry Andric addPass(createGlobalMergePass(TM, 127, OnlyOptimizeForSize, 447*0b57cec5SDimitry Andric MergeExternalByDefault)); 448*0b57cec5SDimitry Andric } 449*0b57cec5SDimitry Andric 450*0b57cec5SDimitry Andric if (TM->getOptLevel() != CodeGenOpt::None) 451*0b57cec5SDimitry Andric addPass(createHardwareLoopsPass()); 452*0b57cec5SDimitry Andric 453*0b57cec5SDimitry Andric return false; 454*0b57cec5SDimitry Andric } 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric bool ARMPassConfig::addInstSelector() { 457*0b57cec5SDimitry Andric addPass(createARMISelDag(getARMTargetMachine(), getOptLevel())); 458*0b57cec5SDimitry Andric return false; 459*0b57cec5SDimitry Andric } 460*0b57cec5SDimitry Andric 461*0b57cec5SDimitry Andric bool ARMPassConfig::addIRTranslator() { 462*0b57cec5SDimitry Andric addPass(new IRTranslator()); 463*0b57cec5SDimitry Andric return false; 464*0b57cec5SDimitry Andric } 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric bool ARMPassConfig::addLegalizeMachineIR() { 467*0b57cec5SDimitry Andric addPass(new Legalizer()); 468*0b57cec5SDimitry Andric return false; 469*0b57cec5SDimitry Andric } 470*0b57cec5SDimitry Andric 471*0b57cec5SDimitry Andric bool ARMPassConfig::addRegBankSelect() { 472*0b57cec5SDimitry Andric addPass(new RegBankSelect()); 473*0b57cec5SDimitry Andric return false; 474*0b57cec5SDimitry Andric } 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric bool ARMPassConfig::addGlobalInstructionSelect() { 477*0b57cec5SDimitry Andric addPass(new InstructionSelect()); 478*0b57cec5SDimitry Andric return false; 479*0b57cec5SDimitry Andric } 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric void ARMPassConfig::addPreRegAlloc() { 482*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 483*0b57cec5SDimitry Andric addPass(createMLxExpansionPass()); 484*0b57cec5SDimitry Andric 485*0b57cec5SDimitry Andric if (EnableARMLoadStoreOpt) 486*0b57cec5SDimitry Andric addPass(createARMLoadStoreOptimizationPass(/* pre-register alloc */ true)); 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric if (!DisableA15SDOptimization) 489*0b57cec5SDimitry Andric addPass(createA15SDOptimizerPass()); 490*0b57cec5SDimitry Andric } 491*0b57cec5SDimitry Andric } 492*0b57cec5SDimitry Andric 493*0b57cec5SDimitry Andric void ARMPassConfig::addPreSched2() { 494*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 495*0b57cec5SDimitry Andric if (EnableARMLoadStoreOpt) 496*0b57cec5SDimitry Andric addPass(createARMLoadStoreOptimizationPass()); 497*0b57cec5SDimitry Andric 498*0b57cec5SDimitry Andric addPass(new ARMExecutionDomainFix()); 499*0b57cec5SDimitry Andric addPass(createBreakFalseDeps()); 500*0b57cec5SDimitry Andric } 501*0b57cec5SDimitry Andric 502*0b57cec5SDimitry Andric // Expand some pseudo instructions into multiple instructions to allow 503*0b57cec5SDimitry Andric // proper scheduling. 504*0b57cec5SDimitry Andric addPass(createARMExpandPseudoPass()); 505*0b57cec5SDimitry Andric 506*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 507*0b57cec5SDimitry Andric // in v8, IfConversion depends on Thumb instruction widths 508*0b57cec5SDimitry Andric addPass(createThumb2SizeReductionPass([this](const Function &F) { 509*0b57cec5SDimitry Andric return this->TM->getSubtarget<ARMSubtarget>(F).restrictIT(); 510*0b57cec5SDimitry Andric })); 511*0b57cec5SDimitry Andric 512*0b57cec5SDimitry Andric addPass(createIfConverter([](const MachineFunction &MF) { 513*0b57cec5SDimitry Andric return !MF.getSubtarget<ARMSubtarget>().isThumb1Only(); 514*0b57cec5SDimitry Andric })); 515*0b57cec5SDimitry Andric } 516*0b57cec5SDimitry Andric addPass(createMVEVPTBlockPass()); 517*0b57cec5SDimitry Andric addPass(createThumb2ITBlockPass()); 518*0b57cec5SDimitry Andric } 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric void ARMPassConfig::addPreEmitPass() { 521*0b57cec5SDimitry Andric addPass(createThumb2SizeReductionPass()); 522*0b57cec5SDimitry Andric 523*0b57cec5SDimitry Andric // Constant island pass work on unbundled instructions. 524*0b57cec5SDimitry Andric addPass(createUnpackMachineBundles([](const MachineFunction &MF) { 525*0b57cec5SDimitry Andric return MF.getSubtarget<ARMSubtarget>().isThumb2(); 526*0b57cec5SDimitry Andric })); 527*0b57cec5SDimitry Andric 528*0b57cec5SDimitry Andric // Don't optimize barriers at -O0. 529*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 530*0b57cec5SDimitry Andric addPass(createARMOptimizeBarriersPass()); 531*0b57cec5SDimitry Andric 532*0b57cec5SDimitry Andric addPass(createARMConstantIslandPass()); 533*0b57cec5SDimitry Andric addPass(createARMLowOverheadLoopsPass()); 534*0b57cec5SDimitry Andric } 535