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