106f32e7eSjoerg //===-- ARMTargetMachine.cpp - Define TargetMachine for ARM ---------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg //
1006f32e7eSjoerg //===----------------------------------------------------------------------===//
1106f32e7eSjoerg 
1206f32e7eSjoerg #include "ARMTargetMachine.h"
1306f32e7eSjoerg #include "ARM.h"
1406f32e7eSjoerg #include "ARMMacroFusion.h"
1506f32e7eSjoerg #include "ARMSubtarget.h"
1606f32e7eSjoerg #include "ARMTargetObjectFile.h"
1706f32e7eSjoerg #include "ARMTargetTransformInfo.h"
1806f32e7eSjoerg #include "MCTargetDesc/ARMMCTargetDesc.h"
1906f32e7eSjoerg #include "TargetInfo/ARMTargetInfo.h"
2006f32e7eSjoerg #include "llvm/ADT/Optional.h"
2106f32e7eSjoerg #include "llvm/ADT/STLExtras.h"
2206f32e7eSjoerg #include "llvm/ADT/StringRef.h"
2306f32e7eSjoerg #include "llvm/ADT/Triple.h"
2406f32e7eSjoerg #include "llvm/Analysis/TargetTransformInfo.h"
2506f32e7eSjoerg #include "llvm/CodeGen/ExecutionDomainFix.h"
2606f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/CallLowering.h"
2706f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
2806f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
2906f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
3006f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/Legalizer.h"
3106f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
3206f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
3306f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
3406f32e7eSjoerg #include "llvm/CodeGen/MachineFunction.h"
3506f32e7eSjoerg #include "llvm/CodeGen/MachineScheduler.h"
3606f32e7eSjoerg #include "llvm/CodeGen/Passes.h"
3706f32e7eSjoerg #include "llvm/CodeGen/TargetPassConfig.h"
3806f32e7eSjoerg #include "llvm/IR/Attributes.h"
3906f32e7eSjoerg #include "llvm/IR/DataLayout.h"
4006f32e7eSjoerg #include "llvm/IR/Function.h"
4106f32e7eSjoerg #include "llvm/Pass.h"
4206f32e7eSjoerg #include "llvm/Support/CodeGen.h"
4306f32e7eSjoerg #include "llvm/Support/CommandLine.h"
4406f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
4506f32e7eSjoerg #include "llvm/Support/TargetParser.h"
4606f32e7eSjoerg #include "llvm/Support/TargetRegistry.h"
4706f32e7eSjoerg #include "llvm/Target/TargetLoweringObjectFile.h"
4806f32e7eSjoerg #include "llvm/Target/TargetOptions.h"
4906f32e7eSjoerg #include "llvm/Transforms/CFGuard.h"
5006f32e7eSjoerg #include "llvm/Transforms/Scalar.h"
5106f32e7eSjoerg #include <cassert>
5206f32e7eSjoerg #include <memory>
5306f32e7eSjoerg #include <string>
5406f32e7eSjoerg 
5506f32e7eSjoerg using namespace llvm;
5606f32e7eSjoerg 
5706f32e7eSjoerg static cl::opt<bool>
5806f32e7eSjoerg DisableA15SDOptimization("disable-a15-sd-optimization", cl::Hidden,
5906f32e7eSjoerg                    cl::desc("Inhibit optimization of S->D register accesses on A15"),
6006f32e7eSjoerg                    cl::init(false));
6106f32e7eSjoerg 
6206f32e7eSjoerg static cl::opt<bool>
6306f32e7eSjoerg EnableAtomicTidy("arm-atomic-cfg-tidy", cl::Hidden,
6406f32e7eSjoerg                  cl::desc("Run SimplifyCFG after expanding atomic operations"
6506f32e7eSjoerg                           " to make use of cmpxchg flow-based information"),
6606f32e7eSjoerg                  cl::init(true));
6706f32e7eSjoerg 
6806f32e7eSjoerg static cl::opt<bool>
6906f32e7eSjoerg EnableARMLoadStoreOpt("arm-load-store-opt", cl::Hidden,
7006f32e7eSjoerg                       cl::desc("Enable ARM load/store optimization pass"),
7106f32e7eSjoerg                       cl::init(true));
7206f32e7eSjoerg 
7306f32e7eSjoerg // FIXME: Unify control over GlobalMerge.
7406f32e7eSjoerg static cl::opt<cl::boolOrDefault>
7506f32e7eSjoerg EnableGlobalMerge("arm-global-merge", cl::Hidden,
7606f32e7eSjoerg                   cl::desc("Enable the global merge pass"));
7706f32e7eSjoerg 
7806f32e7eSjoerg namespace llvm {
7906f32e7eSjoerg   void initializeARMExecutionDomainFixPass(PassRegistry&);
8006f32e7eSjoerg }
8106f32e7eSjoerg 
LLVMInitializeARMTarget()82*da58b97aSjoerg extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARMTarget() {
8306f32e7eSjoerg   // Register the target.
8406f32e7eSjoerg   RegisterTargetMachine<ARMLETargetMachine> X(getTheARMLETarget());
8506f32e7eSjoerg   RegisterTargetMachine<ARMLETargetMachine> A(getTheThumbLETarget());
8606f32e7eSjoerg   RegisterTargetMachine<ARMBETargetMachine> Y(getTheARMBETarget());
8706f32e7eSjoerg   RegisterTargetMachine<ARMBETargetMachine> B(getTheThumbBETarget());
8806f32e7eSjoerg 
8906f32e7eSjoerg   PassRegistry &Registry = *PassRegistry::getPassRegistry();
9006f32e7eSjoerg   initializeGlobalISel(Registry);
9106f32e7eSjoerg   initializeARMLoadStoreOptPass(Registry);
9206f32e7eSjoerg   initializeARMPreAllocLoadStoreOptPass(Registry);
9306f32e7eSjoerg   initializeARMParallelDSPPass(Registry);
9406f32e7eSjoerg   initializeARMConstantIslandsPass(Registry);
9506f32e7eSjoerg   initializeARMExecutionDomainFixPass(Registry);
9606f32e7eSjoerg   initializeARMExpandPseudoPass(Registry);
9706f32e7eSjoerg   initializeThumb2SizeReducePass(Registry);
9806f32e7eSjoerg   initializeMVEVPTBlockPass(Registry);
99*da58b97aSjoerg   initializeMVETPAndVPTOptimisationsPass(Registry);
10006f32e7eSjoerg   initializeMVETailPredicationPass(Registry);
10106f32e7eSjoerg   initializeARMLowOverheadLoopsPass(Registry);
102*da58b97aSjoerg   initializeARMBlockPlacementPass(Registry);
103*da58b97aSjoerg   initializeMVEGatherScatterLoweringPass(Registry);
104*da58b97aSjoerg   initializeARMSLSHardeningPass(Registry);
105*da58b97aSjoerg   initializeMVELaneInterleavingPass(Registry);
10606f32e7eSjoerg }
10706f32e7eSjoerg 
createTLOF(const Triple & TT)10806f32e7eSjoerg static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
10906f32e7eSjoerg   if (TT.isOSBinFormatMachO())
11006f32e7eSjoerg     return std::make_unique<TargetLoweringObjectFileMachO>();
11106f32e7eSjoerg   if (TT.isOSWindows())
11206f32e7eSjoerg     return std::make_unique<TargetLoweringObjectFileCOFF>();
11306f32e7eSjoerg   return std::make_unique<ARMElfTargetObjectFile>();
11406f32e7eSjoerg }
11506f32e7eSjoerg 
11606f32e7eSjoerg static ARMBaseTargetMachine::ARMABI
computeTargetABI(const Triple & TT,StringRef CPU,const TargetOptions & Options)11706f32e7eSjoerg computeTargetABI(const Triple &TT, StringRef CPU,
11806f32e7eSjoerg                  const TargetOptions &Options) {
11906f32e7eSjoerg   StringRef ABIName = Options.MCOptions.getABIName();
12006f32e7eSjoerg 
12106f32e7eSjoerg   if (ABIName.empty())
12206f32e7eSjoerg     ABIName = ARM::computeDefaultTargetABI(TT, CPU);
12306f32e7eSjoerg 
12406f32e7eSjoerg   if (ABIName == "aapcs16")
12506f32e7eSjoerg     return ARMBaseTargetMachine::ARM_ABI_AAPCS16;
12606f32e7eSjoerg   else if (ABIName.startswith("aapcs"))
12706f32e7eSjoerg     return ARMBaseTargetMachine::ARM_ABI_AAPCS;
12806f32e7eSjoerg   else if (ABIName.startswith("apcs"))
12906f32e7eSjoerg     return ARMBaseTargetMachine::ARM_ABI_APCS;
13006f32e7eSjoerg 
13106f32e7eSjoerg   llvm_unreachable("Unhandled/unknown ABI Name!");
13206f32e7eSjoerg   return ARMBaseTargetMachine::ARM_ABI_UNKNOWN;
13306f32e7eSjoerg }
13406f32e7eSjoerg 
computeDataLayout(const Triple & TT,StringRef CPU,const TargetOptions & Options,bool isLittle)13506f32e7eSjoerg static std::string computeDataLayout(const Triple &TT, StringRef CPU,
13606f32e7eSjoerg                                      const TargetOptions &Options,
13706f32e7eSjoerg                                      bool isLittle) {
13806f32e7eSjoerg   auto ABI = computeTargetABI(TT, CPU, Options);
13906f32e7eSjoerg   std::string Ret;
14006f32e7eSjoerg 
14106f32e7eSjoerg   if (isLittle)
14206f32e7eSjoerg     // Little endian.
14306f32e7eSjoerg     Ret += "e";
14406f32e7eSjoerg   else
14506f32e7eSjoerg     // Big endian.
14606f32e7eSjoerg     Ret += "E";
14706f32e7eSjoerg 
14806f32e7eSjoerg   Ret += DataLayout::getManglingComponent(TT);
14906f32e7eSjoerg 
15006f32e7eSjoerg   // Pointers are 32 bits and aligned to 32 bits.
15106f32e7eSjoerg   Ret += "-p:32:32";
15206f32e7eSjoerg 
15306f32e7eSjoerg   // Function pointers are aligned to 8 bits (because the LSB stores the
15406f32e7eSjoerg   // ARM/Thumb state).
15506f32e7eSjoerg   Ret += "-Fi8";
15606f32e7eSjoerg 
15706f32e7eSjoerg   // ABIs other than APCS have 64 bit integers with natural alignment.
15806f32e7eSjoerg   if (ABI != ARMBaseTargetMachine::ARM_ABI_APCS)
15906f32e7eSjoerg     Ret += "-i64:64";
16006f32e7eSjoerg 
16106f32e7eSjoerg   // We have 64 bits floats. The APCS ABI requires them to be aligned to 32
16206f32e7eSjoerg   // bits, others to 64 bits. We always try to align to 64 bits.
16306f32e7eSjoerg   if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS)
16406f32e7eSjoerg     Ret += "-f64:32:64";
16506f32e7eSjoerg 
16606f32e7eSjoerg   // We have 128 and 64 bit vectors. The APCS ABI aligns them to 32 bits, others
16706f32e7eSjoerg   // to 64. We always ty to give them natural alignment.
16806f32e7eSjoerg   if (ABI == ARMBaseTargetMachine::ARM_ABI_APCS)
16906f32e7eSjoerg     Ret += "-v64:32:64-v128:32:128";
17006f32e7eSjoerg   else if (ABI != ARMBaseTargetMachine::ARM_ABI_AAPCS16)
17106f32e7eSjoerg     Ret += "-v128:64:128";
17206f32e7eSjoerg 
17306f32e7eSjoerg   // Try to align aggregates to 32 bits (the default is 64 bits, which has no
17406f32e7eSjoerg   // particular hardware support on 32-bit ARM).
17506f32e7eSjoerg   Ret += "-a:0:32";
17606f32e7eSjoerg 
17706f32e7eSjoerg   // Integer registers are 32 bits.
17806f32e7eSjoerg   Ret += "-n32";
17906f32e7eSjoerg 
18006f32e7eSjoerg   // The stack is 128 bit aligned on NaCl, 64 bit aligned on AAPCS and 32 bit
18106f32e7eSjoerg   // aligned everywhere else.
18206f32e7eSjoerg   if (TT.isOSNaCl() || ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16)
18306f32e7eSjoerg     Ret += "-S128";
18406f32e7eSjoerg   else if (ABI == ARMBaseTargetMachine::ARM_ABI_AAPCS)
18506f32e7eSjoerg     Ret += "-S64";
18606f32e7eSjoerg   else
18706f32e7eSjoerg     Ret += "-S32";
18806f32e7eSjoerg 
18906f32e7eSjoerg   return Ret;
19006f32e7eSjoerg }
19106f32e7eSjoerg 
getEffectiveRelocModel(const Triple & TT,Optional<Reloc::Model> RM)19206f32e7eSjoerg static Reloc::Model getEffectiveRelocModel(const Triple &TT,
19306f32e7eSjoerg                                            Optional<Reloc::Model> RM) {
19406f32e7eSjoerg   if (!RM.hasValue())
19506f32e7eSjoerg     // Default relocation model on Darwin is PIC.
19606f32e7eSjoerg     return TT.isOSBinFormatMachO() ? Reloc::PIC_ : Reloc::Static;
19706f32e7eSjoerg 
19806f32e7eSjoerg   if (*RM == Reloc::ROPI || *RM == Reloc::RWPI || *RM == Reloc::ROPI_RWPI)
19906f32e7eSjoerg     assert(TT.isOSBinFormatELF() &&
20006f32e7eSjoerg            "ROPI/RWPI currently only supported for ELF");
20106f32e7eSjoerg 
20206f32e7eSjoerg   // DynamicNoPIC is only used on darwin.
20306f32e7eSjoerg   if (*RM == Reloc::DynamicNoPIC && !TT.isOSDarwin())
20406f32e7eSjoerg     return Reloc::Static;
20506f32e7eSjoerg 
20606f32e7eSjoerg   return *RM;
20706f32e7eSjoerg }
20806f32e7eSjoerg 
20906f32e7eSjoerg /// Create an ARM architecture model.
21006f32e7eSjoerg ///
ARMBaseTargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,Optional<Reloc::Model> RM,Optional<CodeModel::Model> CM,CodeGenOpt::Level OL,bool isLittle)21106f32e7eSjoerg ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT,
21206f32e7eSjoerg                                            StringRef CPU, StringRef FS,
21306f32e7eSjoerg                                            const TargetOptions &Options,
21406f32e7eSjoerg                                            Optional<Reloc::Model> RM,
21506f32e7eSjoerg                                            Optional<CodeModel::Model> CM,
21606f32e7eSjoerg                                            CodeGenOpt::Level OL, bool isLittle)
21706f32e7eSjoerg     : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, isLittle), TT,
21806f32e7eSjoerg                         CPU, FS, Options, getEffectiveRelocModel(TT, RM),
21906f32e7eSjoerg                         getEffectiveCodeModel(CM, CodeModel::Small), OL),
22006f32e7eSjoerg       TargetABI(computeTargetABI(TT, CPU, Options)),
22106f32e7eSjoerg       TLOF(createTLOF(getTargetTriple())), isLittle(isLittle) {
22206f32e7eSjoerg 
22306f32e7eSjoerg   // Default to triple-appropriate float ABI
22406f32e7eSjoerg   if (Options.FloatABIType == FloatABI::Default) {
22506f32e7eSjoerg     if (isTargetHardFloat())
22606f32e7eSjoerg       this->Options.FloatABIType = FloatABI::Hard;
22706f32e7eSjoerg     else
22806f32e7eSjoerg       this->Options.FloatABIType = FloatABI::Soft;
22906f32e7eSjoerg   }
23006f32e7eSjoerg 
23106f32e7eSjoerg   // Default to triple-appropriate EABI
23206f32e7eSjoerg   if (Options.EABIVersion == EABI::Default ||
23306f32e7eSjoerg       Options.EABIVersion == EABI::Unknown) {
23406f32e7eSjoerg     // musl is compatible with glibc with regard to EABI version
23506f32e7eSjoerg     if ((TargetTriple.getEnvironment() == Triple::GNUEABI ||
23606f32e7eSjoerg          TargetTriple.getEnvironment() == Triple::GNUEABIHF ||
23706f32e7eSjoerg          TargetTriple.getEnvironment() == Triple::MuslEABI ||
23806f32e7eSjoerg          TargetTriple.getEnvironment() == Triple::MuslEABIHF) &&
23906f32e7eSjoerg         !(TargetTriple.isOSWindows() || TargetTriple.isOSDarwin()))
24006f32e7eSjoerg       this->Options.EABIVersion = EABI::GNU;
24106f32e7eSjoerg     else
24206f32e7eSjoerg       this->Options.EABIVersion = EABI::EABI5;
24306f32e7eSjoerg   }
24406f32e7eSjoerg 
24506f32e7eSjoerg   if (TT.isOSBinFormatMachO()) {
24606f32e7eSjoerg     this->Options.TrapUnreachable = true;
24706f32e7eSjoerg     this->Options.NoTrapAfterNoreturn = true;
24806f32e7eSjoerg   }
24906f32e7eSjoerg 
250*da58b97aSjoerg   // ARM supports the debug entry values.
251*da58b97aSjoerg   setSupportsDebugEntryValues(true);
252*da58b97aSjoerg 
25306f32e7eSjoerg   initAsmInfo();
254*da58b97aSjoerg 
255*da58b97aSjoerg   // ARM supports the MachineOutliner.
256*da58b97aSjoerg   setMachineOutliner(true);
257*da58b97aSjoerg   setSupportsDefaultOutlining(true);
25806f32e7eSjoerg }
25906f32e7eSjoerg 
26006f32e7eSjoerg ARMBaseTargetMachine::~ARMBaseTargetMachine() = default;
26106f32e7eSjoerg 
26206f32e7eSjoerg const ARMSubtarget *
getSubtargetImpl(const Function & F) const26306f32e7eSjoerg ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const {
26406f32e7eSjoerg   Attribute CPUAttr = F.getFnAttribute("target-cpu");
26506f32e7eSjoerg   Attribute FSAttr = F.getFnAttribute("target-features");
26606f32e7eSjoerg 
267*da58b97aSjoerg   std::string CPU =
268*da58b97aSjoerg       CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
269*da58b97aSjoerg   std::string FS =
270*da58b97aSjoerg       FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
27106f32e7eSjoerg 
27206f32e7eSjoerg   // FIXME: This is related to the code below to reset the target options,
27306f32e7eSjoerg   // we need to know whether or not the soft float flag is set on the
27406f32e7eSjoerg   // function before we can generate a subtarget. We also need to use
27506f32e7eSjoerg   // it as a key for the subtarget since that can be the only difference
27606f32e7eSjoerg   // between two functions.
277*da58b97aSjoerg   bool SoftFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
27806f32e7eSjoerg   // If the soft float attribute is set on the function turn on the soft float
27906f32e7eSjoerg   // subtarget feature.
28006f32e7eSjoerg   if (SoftFloat)
28106f32e7eSjoerg     FS += FS.empty() ? "+soft-float" : ",+soft-float";
28206f32e7eSjoerg 
28306f32e7eSjoerg   // Use the optminsize to identify the subtarget, but don't use it in the
28406f32e7eSjoerg   // feature string.
28506f32e7eSjoerg   std::string Key = CPU + FS;
28606f32e7eSjoerg   if (F.hasMinSize())
28706f32e7eSjoerg     Key += "+minsize";
28806f32e7eSjoerg 
28906f32e7eSjoerg   auto &I = SubtargetMap[Key];
29006f32e7eSjoerg   if (!I) {
29106f32e7eSjoerg     // This needs to be done before we create a new subtarget since any
29206f32e7eSjoerg     // creation will depend on the TM and the code generation flags on the
29306f32e7eSjoerg     // function that reside in TargetOptions.
29406f32e7eSjoerg     resetTargetOptions(F);
29506f32e7eSjoerg     I = std::make_unique<ARMSubtarget>(TargetTriple, CPU, FS, *this, isLittle,
29606f32e7eSjoerg                                         F.hasMinSize());
29706f32e7eSjoerg 
29806f32e7eSjoerg     if (!I->isThumb() && !I->hasARMOps())
29906f32e7eSjoerg       F.getContext().emitError("Function '" + F.getName() + "' uses ARM "
30006f32e7eSjoerg           "instructions, but the target does not support ARM mode execution.");
30106f32e7eSjoerg   }
30206f32e7eSjoerg 
30306f32e7eSjoerg   return I.get();
30406f32e7eSjoerg }
30506f32e7eSjoerg 
30606f32e7eSjoerg TargetTransformInfo
getTargetTransformInfo(const Function & F)30706f32e7eSjoerg ARMBaseTargetMachine::getTargetTransformInfo(const Function &F) {
30806f32e7eSjoerg   return TargetTransformInfo(ARMTTIImpl(this, F));
30906f32e7eSjoerg }
31006f32e7eSjoerg 
ARMLETargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,Optional<Reloc::Model> RM,Optional<CodeModel::Model> CM,CodeGenOpt::Level OL,bool JIT)31106f32e7eSjoerg ARMLETargetMachine::ARMLETargetMachine(const Target &T, const Triple &TT,
31206f32e7eSjoerg                                        StringRef CPU, StringRef FS,
31306f32e7eSjoerg                                        const TargetOptions &Options,
31406f32e7eSjoerg                                        Optional<Reloc::Model> RM,
31506f32e7eSjoerg                                        Optional<CodeModel::Model> CM,
31606f32e7eSjoerg                                        CodeGenOpt::Level OL, bool JIT)
31706f32e7eSjoerg     : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {}
31806f32e7eSjoerg 
ARMBETargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,Optional<Reloc::Model> RM,Optional<CodeModel::Model> CM,CodeGenOpt::Level OL,bool JIT)31906f32e7eSjoerg ARMBETargetMachine::ARMBETargetMachine(const Target &T, const Triple &TT,
32006f32e7eSjoerg                                        StringRef CPU, StringRef FS,
32106f32e7eSjoerg                                        const TargetOptions &Options,
32206f32e7eSjoerg                                        Optional<Reloc::Model> RM,
32306f32e7eSjoerg                                        Optional<CodeModel::Model> CM,
32406f32e7eSjoerg                                        CodeGenOpt::Level OL, bool JIT)
32506f32e7eSjoerg     : ARMBaseTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
32606f32e7eSjoerg 
32706f32e7eSjoerg namespace {
32806f32e7eSjoerg 
32906f32e7eSjoerg /// ARM Code Generator Pass Configuration Options.
33006f32e7eSjoerg class ARMPassConfig : public TargetPassConfig {
33106f32e7eSjoerg public:
ARMPassConfig(ARMBaseTargetMachine & TM,PassManagerBase & PM)33206f32e7eSjoerg   ARMPassConfig(ARMBaseTargetMachine &TM, PassManagerBase &PM)
333*da58b97aSjoerg       : TargetPassConfig(TM, PM) {}
33406f32e7eSjoerg 
getARMTargetMachine() const33506f32e7eSjoerg   ARMBaseTargetMachine &getARMTargetMachine() const {
33606f32e7eSjoerg     return getTM<ARMBaseTargetMachine>();
33706f32e7eSjoerg   }
33806f32e7eSjoerg 
33906f32e7eSjoerg   ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext * C) const34006f32e7eSjoerg   createMachineScheduler(MachineSchedContext *C) const override {
34106f32e7eSjoerg     ScheduleDAGMILive *DAG = createGenericSchedLive(C);
34206f32e7eSjoerg     // add DAG Mutations here.
34306f32e7eSjoerg     const ARMSubtarget &ST = C->MF->getSubtarget<ARMSubtarget>();
34406f32e7eSjoerg     if (ST.hasFusion())
34506f32e7eSjoerg       DAG->addMutation(createARMMacroFusionDAGMutation());
34606f32e7eSjoerg     return DAG;
34706f32e7eSjoerg   }
34806f32e7eSjoerg 
34906f32e7eSjoerg   ScheduleDAGInstrs *
createPostMachineScheduler(MachineSchedContext * C) const35006f32e7eSjoerg   createPostMachineScheduler(MachineSchedContext *C) const override {
35106f32e7eSjoerg     ScheduleDAGMI *DAG = createGenericSchedPostRA(C);
35206f32e7eSjoerg     // add DAG Mutations here.
35306f32e7eSjoerg     const ARMSubtarget &ST = C->MF->getSubtarget<ARMSubtarget>();
35406f32e7eSjoerg     if (ST.hasFusion())
35506f32e7eSjoerg       DAG->addMutation(createARMMacroFusionDAGMutation());
35606f32e7eSjoerg     return DAG;
35706f32e7eSjoerg   }
35806f32e7eSjoerg 
35906f32e7eSjoerg   void addIRPasses() override;
36006f32e7eSjoerg   void addCodeGenPrepare() override;
36106f32e7eSjoerg   bool addPreISel() override;
36206f32e7eSjoerg   bool addInstSelector() override;
36306f32e7eSjoerg   bool addIRTranslator() override;
36406f32e7eSjoerg   bool addLegalizeMachineIR() override;
36506f32e7eSjoerg   bool addRegBankSelect() override;
36606f32e7eSjoerg   bool addGlobalInstructionSelect() override;
36706f32e7eSjoerg   void addPreRegAlloc() override;
36806f32e7eSjoerg   void addPreSched2() override;
36906f32e7eSjoerg   void addPreEmitPass() override;
370*da58b97aSjoerg   void addPreEmitPass2() override;
37106f32e7eSjoerg 
37206f32e7eSjoerg   std::unique_ptr<CSEConfigBase> getCSEConfig() const override;
37306f32e7eSjoerg };
37406f32e7eSjoerg 
37506f32e7eSjoerg class ARMExecutionDomainFix : public ExecutionDomainFix {
37606f32e7eSjoerg public:
37706f32e7eSjoerg   static char ID;
ARMExecutionDomainFix()37806f32e7eSjoerg   ARMExecutionDomainFix() : ExecutionDomainFix(ID, ARM::DPRRegClass) {}
getPassName() const37906f32e7eSjoerg   StringRef getPassName() const override {
38006f32e7eSjoerg     return "ARM Execution Domain Fix";
38106f32e7eSjoerg   }
38206f32e7eSjoerg };
38306f32e7eSjoerg char ARMExecutionDomainFix::ID;
38406f32e7eSjoerg 
38506f32e7eSjoerg } // end anonymous namespace
38606f32e7eSjoerg 
38706f32e7eSjoerg INITIALIZE_PASS_BEGIN(ARMExecutionDomainFix, "arm-execution-domain-fix",
38806f32e7eSjoerg   "ARM Execution Domain Fix", false, false)
INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis)38906f32e7eSjoerg INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis)
39006f32e7eSjoerg INITIALIZE_PASS_END(ARMExecutionDomainFix, "arm-execution-domain-fix",
39106f32e7eSjoerg   "ARM Execution Domain Fix", false, false)
39206f32e7eSjoerg 
39306f32e7eSjoerg TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) {
39406f32e7eSjoerg   return new ARMPassConfig(*this, PM);
39506f32e7eSjoerg }
39606f32e7eSjoerg 
getCSEConfig() const39706f32e7eSjoerg std::unique_ptr<CSEConfigBase> ARMPassConfig::getCSEConfig() const {
39806f32e7eSjoerg   return getStandardCSEConfigForOpt(TM->getOptLevel());
39906f32e7eSjoerg }
40006f32e7eSjoerg 
addIRPasses()40106f32e7eSjoerg void ARMPassConfig::addIRPasses() {
40206f32e7eSjoerg   if (TM->Options.ThreadModel == ThreadModel::Single)
40306f32e7eSjoerg     addPass(createLowerAtomicPass());
40406f32e7eSjoerg   else
40506f32e7eSjoerg     addPass(createAtomicExpandPass());
40606f32e7eSjoerg 
40706f32e7eSjoerg   // Cmpxchg instructions are often used with a subsequent comparison to
40806f32e7eSjoerg   // determine whether it succeeded. We can exploit existing control-flow in
40906f32e7eSjoerg   // ldrex/strex loops to simplify this, but it needs tidying up.
41006f32e7eSjoerg   if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy)
41106f32e7eSjoerg     addPass(createCFGSimplificationPass(
412*da58b97aSjoerg         SimplifyCFGOptions().hoistCommonInsts(true).sinkCommonInsts(true),
413*da58b97aSjoerg         [this](const Function &F) {
41406f32e7eSjoerg           const auto &ST = this->TM->getSubtarget<ARMSubtarget>(F);
41506f32e7eSjoerg           return ST.hasAnyDataBarrier() && !ST.isThumb1Only();
41606f32e7eSjoerg         }));
41706f32e7eSjoerg 
418*da58b97aSjoerg   addPass(createMVEGatherScatterLoweringPass());
419*da58b97aSjoerg   addPass(createMVELaneInterleavingPass());
420*da58b97aSjoerg 
42106f32e7eSjoerg   TargetPassConfig::addIRPasses();
42206f32e7eSjoerg 
42306f32e7eSjoerg   // Run the parallel DSP pass.
42406f32e7eSjoerg   if (getOptLevel() == CodeGenOpt::Aggressive)
42506f32e7eSjoerg     addPass(createARMParallelDSPPass());
42606f32e7eSjoerg 
42706f32e7eSjoerg   // Match interleaved memory accesses to ldN/stN intrinsics.
42806f32e7eSjoerg   if (TM->getOptLevel() != CodeGenOpt::None)
42906f32e7eSjoerg     addPass(createInterleavedAccessPass());
43006f32e7eSjoerg 
43106f32e7eSjoerg   // Add Control Flow Guard checks.
43206f32e7eSjoerg   if (TM->getTargetTriple().isOSWindows())
43306f32e7eSjoerg     addPass(createCFGuardCheckPass());
43406f32e7eSjoerg }
43506f32e7eSjoerg 
addCodeGenPrepare()43606f32e7eSjoerg void ARMPassConfig::addCodeGenPrepare() {
43706f32e7eSjoerg   if (getOptLevel() != CodeGenOpt::None)
438*da58b97aSjoerg     addPass(createTypePromotionPass());
43906f32e7eSjoerg   TargetPassConfig::addCodeGenPrepare();
44006f32e7eSjoerg }
44106f32e7eSjoerg 
addPreISel()44206f32e7eSjoerg bool ARMPassConfig::addPreISel() {
44306f32e7eSjoerg   if ((TM->getOptLevel() != CodeGenOpt::None &&
44406f32e7eSjoerg        EnableGlobalMerge == cl::BOU_UNSET) ||
44506f32e7eSjoerg       EnableGlobalMerge == cl::BOU_TRUE) {
44606f32e7eSjoerg     // FIXME: This is using the thumb1 only constant value for
44706f32e7eSjoerg     // maximal global offset for merging globals. We may want
44806f32e7eSjoerg     // to look into using the old value for non-thumb1 code of
44906f32e7eSjoerg     // 4095 based on the TargetMachine, but this starts to become
45006f32e7eSjoerg     // tricky when doing code gen per function.
45106f32e7eSjoerg     bool OnlyOptimizeForSize = (TM->getOptLevel() < CodeGenOpt::Aggressive) &&
45206f32e7eSjoerg                                (EnableGlobalMerge == cl::BOU_UNSET);
45306f32e7eSjoerg     // Merging of extern globals is enabled by default on non-Mach-O as we
45406f32e7eSjoerg     // expect it to be generally either beneficial or harmless. On Mach-O it
45506f32e7eSjoerg     // is disabled as we emit the .subsections_via_symbols directive which
45606f32e7eSjoerg     // means that merging extern globals is not safe.
45706f32e7eSjoerg     bool MergeExternalByDefault = !TM->getTargetTriple().isOSBinFormatMachO();
45806f32e7eSjoerg     addPass(createGlobalMergePass(TM, 127, OnlyOptimizeForSize,
45906f32e7eSjoerg                                   MergeExternalByDefault));
46006f32e7eSjoerg   }
46106f32e7eSjoerg 
46206f32e7eSjoerg   if (TM->getOptLevel() != CodeGenOpt::None) {
46306f32e7eSjoerg     addPass(createHardwareLoopsPass());
46406f32e7eSjoerg     addPass(createMVETailPredicationPass());
46506f32e7eSjoerg   }
46606f32e7eSjoerg 
46706f32e7eSjoerg   return false;
46806f32e7eSjoerg }
46906f32e7eSjoerg 
addInstSelector()47006f32e7eSjoerg bool ARMPassConfig::addInstSelector() {
47106f32e7eSjoerg   addPass(createARMISelDag(getARMTargetMachine(), getOptLevel()));
47206f32e7eSjoerg   return false;
47306f32e7eSjoerg }
47406f32e7eSjoerg 
addIRTranslator()47506f32e7eSjoerg bool ARMPassConfig::addIRTranslator() {
476*da58b97aSjoerg   addPass(new IRTranslator(getOptLevel()));
47706f32e7eSjoerg   return false;
47806f32e7eSjoerg }
47906f32e7eSjoerg 
addLegalizeMachineIR()48006f32e7eSjoerg bool ARMPassConfig::addLegalizeMachineIR() {
48106f32e7eSjoerg   addPass(new Legalizer());
48206f32e7eSjoerg   return false;
48306f32e7eSjoerg }
48406f32e7eSjoerg 
addRegBankSelect()48506f32e7eSjoerg bool ARMPassConfig::addRegBankSelect() {
48606f32e7eSjoerg   addPass(new RegBankSelect());
48706f32e7eSjoerg   return false;
48806f32e7eSjoerg }
48906f32e7eSjoerg 
addGlobalInstructionSelect()49006f32e7eSjoerg bool ARMPassConfig::addGlobalInstructionSelect() {
491*da58b97aSjoerg   addPass(new InstructionSelect(getOptLevel()));
49206f32e7eSjoerg   return false;
49306f32e7eSjoerg }
49406f32e7eSjoerg 
addPreRegAlloc()49506f32e7eSjoerg void ARMPassConfig::addPreRegAlloc() {
49606f32e7eSjoerg   if (getOptLevel() != CodeGenOpt::None) {
497*da58b97aSjoerg     addPass(createMVETPAndVPTOptimisationsPass());
498*da58b97aSjoerg 
49906f32e7eSjoerg     addPass(createMLxExpansionPass());
50006f32e7eSjoerg 
50106f32e7eSjoerg     if (EnableARMLoadStoreOpt)
50206f32e7eSjoerg       addPass(createARMLoadStoreOptimizationPass(/* pre-register alloc */ true));
50306f32e7eSjoerg 
50406f32e7eSjoerg     if (!DisableA15SDOptimization)
50506f32e7eSjoerg       addPass(createA15SDOptimizerPass());
50606f32e7eSjoerg   }
50706f32e7eSjoerg }
50806f32e7eSjoerg 
addPreSched2()50906f32e7eSjoerg void ARMPassConfig::addPreSched2() {
51006f32e7eSjoerg   if (getOptLevel() != CodeGenOpt::None) {
51106f32e7eSjoerg     if (EnableARMLoadStoreOpt)
51206f32e7eSjoerg       addPass(createARMLoadStoreOptimizationPass());
51306f32e7eSjoerg 
51406f32e7eSjoerg     addPass(new ARMExecutionDomainFix());
51506f32e7eSjoerg     addPass(createBreakFalseDeps());
51606f32e7eSjoerg   }
51706f32e7eSjoerg 
51806f32e7eSjoerg   // Expand some pseudo instructions into multiple instructions to allow
51906f32e7eSjoerg   // proper scheduling.
52006f32e7eSjoerg   addPass(createARMExpandPseudoPass());
52106f32e7eSjoerg 
52206f32e7eSjoerg   if (getOptLevel() != CodeGenOpt::None) {
523*da58b97aSjoerg     // When optimising for size, always run the Thumb2SizeReduction pass before
524*da58b97aSjoerg     // IfConversion. Otherwise, check whether IT blocks are restricted
525*da58b97aSjoerg     // (e.g. in v8, IfConversion depends on Thumb instruction widths)
52606f32e7eSjoerg     addPass(createThumb2SizeReductionPass([this](const Function &F) {
527*da58b97aSjoerg       return this->TM->getSubtarget<ARMSubtarget>(F).hasMinSize() ||
528*da58b97aSjoerg              this->TM->getSubtarget<ARMSubtarget>(F).restrictIT();
52906f32e7eSjoerg     }));
53006f32e7eSjoerg 
53106f32e7eSjoerg     addPass(createIfConverter([](const MachineFunction &MF) {
53206f32e7eSjoerg       return !MF.getSubtarget<ARMSubtarget>().isThumb1Only();
53306f32e7eSjoerg     }));
53406f32e7eSjoerg   }
53506f32e7eSjoerg   addPass(createMVEVPTBlockPass());
53606f32e7eSjoerg   addPass(createThumb2ITBlockPass());
537*da58b97aSjoerg 
538*da58b97aSjoerg   // Add both scheduling passes to give the subtarget an opportunity to pick
539*da58b97aSjoerg   // between them.
540*da58b97aSjoerg   if (getOptLevel() != CodeGenOpt::None) {
541*da58b97aSjoerg     addPass(&PostMachineSchedulerID);
542*da58b97aSjoerg     addPass(&PostRASchedulerID);
543*da58b97aSjoerg   }
544*da58b97aSjoerg 
545*da58b97aSjoerg   addPass(createARMIndirectThunks());
546*da58b97aSjoerg   addPass(createARMSLSHardeningPass());
54706f32e7eSjoerg }
54806f32e7eSjoerg 
addPreEmitPass()54906f32e7eSjoerg void ARMPassConfig::addPreEmitPass() {
55006f32e7eSjoerg   addPass(createThumb2SizeReductionPass());
55106f32e7eSjoerg 
55206f32e7eSjoerg   // Constant island pass work on unbundled instructions.
55306f32e7eSjoerg   addPass(createUnpackMachineBundles([](const MachineFunction &MF) {
55406f32e7eSjoerg     return MF.getSubtarget<ARMSubtarget>().isThumb2();
55506f32e7eSjoerg   }));
55606f32e7eSjoerg 
557*da58b97aSjoerg   // Don't optimize barriers or block placement at -O0.
558*da58b97aSjoerg   if (getOptLevel() != CodeGenOpt::None) {
559*da58b97aSjoerg     addPass(createARMBlockPlacementPass());
56006f32e7eSjoerg     addPass(createARMOptimizeBarriersPass());
561*da58b97aSjoerg   }
562*da58b97aSjoerg }
56306f32e7eSjoerg 
addPreEmitPass2()564*da58b97aSjoerg void ARMPassConfig::addPreEmitPass2() {
56506f32e7eSjoerg   addPass(createARMConstantIslandPass());
56606f32e7eSjoerg   addPass(createARMLowOverheadLoopsPass());
56706f32e7eSjoerg 
568*da58b97aSjoerg   if (TM->getTargetTriple().isOSWindows()) {
56906f32e7eSjoerg     // Identify valid longjmp targets for Windows Control Flow Guard.
57006f32e7eSjoerg     addPass(createCFGuardLongjmpPass());
571*da58b97aSjoerg     // Identify valid eh continuation targets for Windows EHCont Guard.
572*da58b97aSjoerg     addPass(createEHContGuardCatchretPass());
573*da58b97aSjoerg   }
57406f32e7eSjoerg }
575