1 //===-- AArch64Subtarget.cpp - AArch64 Subtarget Information ----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the AArch64 specific subclass of TargetSubtarget.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "AArch64Subtarget.h"
14 
15 #include "AArch64.h"
16 #include "AArch64CallLowering.h"
17 #include "AArch64InstrInfo.h"
18 #include "AArch64LegalizerInfo.h"
19 #include "AArch64PBQPRegAlloc.h"
20 #include "AArch64RegisterBankInfo.h"
21 #include "AArch64TargetMachine.h"
22 #include "MCTargetDesc/AArch64AddressingModes.h"
23 #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
24 #include "llvm/CodeGen/MachineScheduler.h"
25 #include "llvm/IR/GlobalValue.h"
26 #include "llvm/Support/TargetParser.h"
27 
28 using namespace llvm;
29 
30 #define DEBUG_TYPE "aarch64-subtarget"
31 
32 #define GET_SUBTARGETINFO_CTOR
33 #define GET_SUBTARGETINFO_TARGET_DESC
34 #include "AArch64GenSubtargetInfo.inc"
35 
36 static cl::opt<bool>
37 EnableEarlyIfConvert("aarch64-early-ifcvt", cl::desc("Enable the early if "
38                      "converter pass"), cl::init(true), cl::Hidden);
39 
40 // If OS supports TBI, use this flag to enable it.
41 static cl::opt<bool>
42 UseAddressTopByteIgnored("aarch64-use-tbi", cl::desc("Assume that top byte of "
43                          "an address is ignored"), cl::init(false), cl::Hidden);
44 
45 static cl::opt<bool>
46     UseNonLazyBind("aarch64-enable-nonlazybind",
47                    cl::desc("Call nonlazybind functions via direct GOT load"),
48                    cl::init(false), cl::Hidden);
49 
50 AArch64Subtarget &
51 AArch64Subtarget::initializeSubtargetDependencies(StringRef FS,
52                                                   StringRef CPUString) {
53   // Determine default and user-specified characteristics
54 
55   if (CPUString.empty())
56     CPUString = "generic";
57 
58   ParseSubtargetFeatures(CPUString, FS);
59   initializeProperties();
60 
61   return *this;
62 }
63 
64 void AArch64Subtarget::initializeProperties() {
65   // Initialize CPU specific properties. We should add a tablegen feature for
66   // this in the future so we can specify it together with the subtarget
67   // features.
68   switch (ARMProcFamily) {
69   case Others:
70     break;
71   case CortexA35:
72     break;
73   case CortexA53:
74     PrefFunctionLogAlignment = 3;
75     break;
76   case CortexA55:
77     break;
78   case CortexA57:
79     MaxInterleaveFactor = 4;
80     PrefFunctionLogAlignment = 4;
81     break;
82   case CortexA65:
83     PrefFunctionLogAlignment = 3;
84     break;
85   case CortexA72:
86   case CortexA73:
87   case CortexA75:
88   case CortexA76:
89     PrefFunctionLogAlignment = 4;
90     break;
91   case Cyclone:
92     CacheLineSize = 64;
93     PrefetchDistance = 280;
94     MinPrefetchStride = 2048;
95     MaxPrefetchIterationsAhead = 3;
96     break;
97   case ExynosM3:
98     MaxInterleaveFactor = 4;
99     MaxJumpTableSize = 20;
100     PrefFunctionLogAlignment = 5;
101     PrefLoopLogAlignment = 4;
102     break;
103   case Falkor:
104     MaxInterleaveFactor = 4;
105     // FIXME: remove this to enable 64-bit SLP if performance looks good.
106     MinVectorRegisterBitWidth = 128;
107     CacheLineSize = 128;
108     PrefetchDistance = 820;
109     MinPrefetchStride = 2048;
110     MaxPrefetchIterationsAhead = 8;
111     break;
112   case Kryo:
113     MaxInterleaveFactor = 4;
114     VectorInsertExtractBaseCost = 2;
115     CacheLineSize = 128;
116     PrefetchDistance = 740;
117     MinPrefetchStride = 1024;
118     MaxPrefetchIterationsAhead = 11;
119     // FIXME: remove this to enable 64-bit SLP if performance looks good.
120     MinVectorRegisterBitWidth = 128;
121     break;
122   case NeoverseE1:
123     PrefFunctionLogAlignment = 3;
124     break;
125   case NeoverseN1:
126     PrefFunctionLogAlignment = 4;
127     break;
128   case Saphira:
129     MaxInterleaveFactor = 4;
130     // FIXME: remove this to enable 64-bit SLP if performance looks good.
131     MinVectorRegisterBitWidth = 128;
132     break;
133   case ThunderX2T99:
134     CacheLineSize = 64;
135     PrefFunctionLogAlignment = 3;
136     PrefLoopLogAlignment = 2;
137     MaxInterleaveFactor = 4;
138     PrefetchDistance = 128;
139     MinPrefetchStride = 1024;
140     MaxPrefetchIterationsAhead = 4;
141     // FIXME: remove this to enable 64-bit SLP if performance looks good.
142     MinVectorRegisterBitWidth = 128;
143     break;
144   case ThunderX:
145   case ThunderXT88:
146   case ThunderXT81:
147   case ThunderXT83:
148     CacheLineSize = 128;
149     PrefFunctionLogAlignment = 3;
150     PrefLoopLogAlignment = 2;
151     // FIXME: remove this to enable 64-bit SLP if performance looks good.
152     MinVectorRegisterBitWidth = 128;
153     break;
154   case TSV110:
155     CacheLineSize = 64;
156     PrefFunctionLogAlignment = 4;
157     PrefLoopLogAlignment = 2;
158     break;
159   }
160 }
161 
162 AArch64Subtarget::AArch64Subtarget(const Triple &TT, const std::string &CPU,
163                                    const std::string &FS,
164                                    const TargetMachine &TM, bool LittleEndian)
165     : AArch64GenSubtargetInfo(TT, CPU, FS),
166       ReserveXRegister(AArch64::GPR64commonRegClass.getNumRegs()),
167       CustomCallSavedXRegs(AArch64::GPR64commonRegClass.getNumRegs()),
168       IsLittle(LittleEndian),
169       TargetTriple(TT), FrameLowering(),
170       InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(),
171       TLInfo(TM, *this) {
172   if (AArch64::isX18ReservedByDefault(TT))
173     ReserveXRegister.set(18);
174 
175   CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering()));
176   Legalizer.reset(new AArch64LegalizerInfo(*this));
177 
178   auto *RBI = new AArch64RegisterBankInfo(*getRegisterInfo());
179 
180   // FIXME: At this point, we can't rely on Subtarget having RBI.
181   // It's awkward to mix passing RBI and the Subtarget; should we pass
182   // TII/TRI as well?
183   InstSelector.reset(createAArch64InstructionSelector(
184       *static_cast<const AArch64TargetMachine *>(&TM), *this, *RBI));
185 
186   RegBankInfo.reset(RBI);
187 }
188 
189 const CallLowering *AArch64Subtarget::getCallLowering() const {
190   return CallLoweringInfo.get();
191 }
192 
193 InstructionSelector *AArch64Subtarget::getInstructionSelector() const {
194   return InstSelector.get();
195 }
196 
197 const LegalizerInfo *AArch64Subtarget::getLegalizerInfo() const {
198   return Legalizer.get();
199 }
200 
201 const RegisterBankInfo *AArch64Subtarget::getRegBankInfo() const {
202   return RegBankInfo.get();
203 }
204 
205 /// Find the target operand flags that describe how a global value should be
206 /// referenced for the current subtarget.
207 unsigned
208 AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
209                                           const TargetMachine &TM) const {
210   // MachO large model always goes via a GOT, simply to get a single 8-byte
211   // absolute relocation on all global addresses.
212   if (TM.getCodeModel() == CodeModel::Large && isTargetMachO())
213     return AArch64II::MO_GOT;
214 
215   if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) {
216     if (GV->hasDLLImportStorageClass())
217       return AArch64II::MO_GOT | AArch64II::MO_DLLIMPORT;
218     if (getTargetTriple().isOSWindows())
219       return AArch64II::MO_GOT | AArch64II::MO_COFFSTUB;
220     return AArch64II::MO_GOT;
221   }
222 
223   // The small code model's direct accesses use ADRP, which cannot
224   // necessarily produce the value 0 (if the code is above 4GB).
225   // Same for the tiny code model, where we have a pc relative LDR.
226   if ((useSmallAddressing() || TM.getCodeModel() == CodeModel::Tiny) &&
227       GV->hasExternalWeakLinkage())
228     return AArch64II::MO_GOT;
229 
230   // References to tagged globals are marked with MO_NC | MO_TAGGED to indicate
231   // that their nominal addresses are tagged and outside of the code model. In
232   // AArch64ExpandPseudo::expandMI we emit an additional instruction to set the
233   // tag if necessary based on MO_TAGGED.
234   if (AllowTaggedGlobals && !isa<FunctionType>(GV->getValueType()))
235     return AArch64II::MO_NC | AArch64II::MO_TAGGED;
236 
237   return AArch64II::MO_NO_FLAG;
238 }
239 
240 unsigned AArch64Subtarget::classifyGlobalFunctionReference(
241     const GlobalValue *GV, const TargetMachine &TM) const {
242   // MachO large model always goes via a GOT, because we don't have the
243   // relocations available to do anything else..
244   if (TM.getCodeModel() == CodeModel::Large && isTargetMachO() &&
245       !GV->hasInternalLinkage())
246     return AArch64II::MO_GOT;
247 
248   // NonLazyBind goes via GOT unless we know it's available locally.
249   auto *F = dyn_cast<Function>(GV);
250   if (UseNonLazyBind && F && F->hasFnAttribute(Attribute::NonLazyBind) &&
251       !TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
252     return AArch64II::MO_GOT;
253 
254   return AArch64II::MO_NO_FLAG;
255 }
256 
257 void AArch64Subtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
258                                            unsigned NumRegionInstrs) const {
259   // LNT run (at least on Cyclone) showed reasonably significant gains for
260   // bi-directional scheduling. 253.perlbmk.
261   Policy.OnlyTopDown = false;
262   Policy.OnlyBottomUp = false;
263   // Enabling or Disabling the latency heuristic is a close call: It seems to
264   // help nearly no benchmark on out-of-order architectures, on the other hand
265   // it regresses register pressure on a few benchmarking.
266   Policy.DisableLatencyHeuristic = DisableLatencySchedHeuristic;
267 }
268 
269 bool AArch64Subtarget::enableEarlyIfConversion() const {
270   return EnableEarlyIfConvert;
271 }
272 
273 bool AArch64Subtarget::supportsAddressTopByteIgnored() const {
274   if (!UseAddressTopByteIgnored)
275     return false;
276 
277   if (TargetTriple.isiOS()) {
278     unsigned Major, Minor, Micro;
279     TargetTriple.getiOSVersion(Major, Minor, Micro);
280     return Major >= 8;
281   }
282 
283   return false;
284 }
285 
286 std::unique_ptr<PBQPRAConstraint>
287 AArch64Subtarget::getCustomPBQPConstraints() const {
288   return balanceFPOps() ? std::make_unique<A57ChainingConstraint>() : nullptr;
289 }
290 
291 void AArch64Subtarget::mirFileLoaded(MachineFunction &MF) const {
292   // We usually compute max call frame size after ISel. Do the computation now
293   // if the .mir file didn't specify it. Note that this will probably give you
294   // bogus values after PEI has eliminated the callframe setup/destroy pseudo
295   // instructions, specify explicitly if you need it to be correct.
296   MachineFrameInfo &MFI = MF.getFrameInfo();
297   if (!MFI.isMaxCallFrameSizeComputed())
298     MFI.computeMaxCallFrameSize(MF);
299 }
300