xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMTargetMachine.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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