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 "AArch64InstrInfo.h"
17 #include "AArch64PBQPRegAlloc.h"
18 #include "AArch64TargetMachine.h"
19 #include "GISel/AArch64CallLowering.h"
20 #include "GISel/AArch64LegalizerInfo.h"
21 #include "GISel/AArch64RegisterBankInfo.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 static cl::opt<bool> UseAA("aarch64-use-aa", cl::init(true),
51                            cl::desc("Enable the use of AA during codegen."));
52 
53 AArch64Subtarget &AArch64Subtarget::initializeSubtargetDependencies(
54     StringRef FS, StringRef CPUString, StringRef TuneCPUString) {
55   // Determine default and user-specified characteristics
56 
57   if (CPUString.empty())
58     CPUString = "generic";
59 
60   if (TuneCPUString.empty())
61     TuneCPUString = CPUString;
62 
63   ParseSubtargetFeatures(CPUString, TuneCPUString, FS);
64   initializeProperties();
65 
66   return *this;
67 }
68 
69 void AArch64Subtarget::initializeProperties() {
70   // Initialize CPU specific properties. We should add a tablegen feature for
71   // this in the future so we can specify it together with the subtarget
72   // features.
73   switch (ARMProcFamily) {
74   case Others:
75     break;
76   case Carmel:
77     CacheLineSize = 64;
78     break;
79   case CortexA35:
80     break;
81   case CortexA53:
82   case CortexA55:
83     PrefFunctionLogAlignment = 4;
84     break;
85   case CortexA510:
86     PrefFunctionLogAlignment = 4;
87     VScaleForTuning = 1;
88     break;
89   case CortexA57:
90     MaxInterleaveFactor = 4;
91     PrefFunctionLogAlignment = 4;
92     break;
93   case CortexA65:
94     PrefFunctionLogAlignment = 3;
95     break;
96   case CortexA72:
97   case CortexA73:
98   case CortexA75:
99   case CortexA76:
100   case CortexA77:
101   case CortexA78:
102   case CortexA78C:
103   case CortexR82:
104   case CortexX1:
105     PrefFunctionLogAlignment = 4;
106     break;
107   case A64FX:
108     CacheLineSize = 256;
109     PrefFunctionLogAlignment = 3;
110     PrefLoopLogAlignment = 2;
111     MaxInterleaveFactor = 4;
112     PrefetchDistance = 128;
113     MinPrefetchStride = 1024;
114     MaxPrefetchIterationsAhead = 4;
115     VScaleForTuning = 4;
116     break;
117   case AppleA7:
118   case AppleA10:
119   case AppleA11:
120   case AppleA12:
121   case AppleA13:
122   case AppleA14:
123     CacheLineSize = 64;
124     PrefetchDistance = 280;
125     MinPrefetchStride = 2048;
126     MaxPrefetchIterationsAhead = 3;
127     break;
128   case ExynosM3:
129     MaxInterleaveFactor = 4;
130     MaxJumpTableSize = 20;
131     PrefFunctionLogAlignment = 5;
132     PrefLoopLogAlignment = 4;
133     break;
134   case Falkor:
135     MaxInterleaveFactor = 4;
136     // FIXME: remove this to enable 64-bit SLP if performance looks good.
137     MinVectorRegisterBitWidth = 128;
138     CacheLineSize = 128;
139     PrefetchDistance = 820;
140     MinPrefetchStride = 2048;
141     MaxPrefetchIterationsAhead = 8;
142     break;
143   case Kryo:
144     MaxInterleaveFactor = 4;
145     VectorInsertExtractBaseCost = 2;
146     CacheLineSize = 128;
147     PrefetchDistance = 740;
148     MinPrefetchStride = 1024;
149     MaxPrefetchIterationsAhead = 11;
150     // FIXME: remove this to enable 64-bit SLP if performance looks good.
151     MinVectorRegisterBitWidth = 128;
152     break;
153   case NeoverseE1:
154     PrefFunctionLogAlignment = 3;
155     break;
156   case NeoverseN1:
157     PrefFunctionLogAlignment = 4;
158     break;
159   case NeoverseN2:
160     PrefFunctionLogAlignment = 4;
161     VScaleForTuning = 1;
162     break;
163   case NeoverseV1:
164     PrefFunctionLogAlignment = 4;
165     VScaleForTuning = 2;
166     break;
167   case Saphira:
168     MaxInterleaveFactor = 4;
169     // FIXME: remove this to enable 64-bit SLP if performance looks good.
170     MinVectorRegisterBitWidth = 128;
171     break;
172   case ThunderX2T99:
173     CacheLineSize = 64;
174     PrefFunctionLogAlignment = 3;
175     PrefLoopLogAlignment = 2;
176     MaxInterleaveFactor = 4;
177     PrefetchDistance = 128;
178     MinPrefetchStride = 1024;
179     MaxPrefetchIterationsAhead = 4;
180     // FIXME: remove this to enable 64-bit SLP if performance looks good.
181     MinVectorRegisterBitWidth = 128;
182     break;
183   case ThunderX:
184   case ThunderXT88:
185   case ThunderXT81:
186   case ThunderXT83:
187     CacheLineSize = 128;
188     PrefFunctionLogAlignment = 3;
189     PrefLoopLogAlignment = 2;
190     // FIXME: remove this to enable 64-bit SLP if performance looks good.
191     MinVectorRegisterBitWidth = 128;
192     break;
193   case TSV110:
194     CacheLineSize = 64;
195     PrefFunctionLogAlignment = 4;
196     PrefLoopLogAlignment = 2;
197     break;
198   case ThunderX3T110:
199     CacheLineSize = 64;
200     PrefFunctionLogAlignment = 4;
201     PrefLoopLogAlignment = 2;
202     MaxInterleaveFactor = 4;
203     PrefetchDistance = 128;
204     MinPrefetchStride = 1024;
205     MaxPrefetchIterationsAhead = 4;
206     // FIXME: remove this to enable 64-bit SLP if performance looks good.
207     MinVectorRegisterBitWidth = 128;
208     break;
209   }
210 }
211 
212 AArch64Subtarget::AArch64Subtarget(const Triple &TT, const std::string &CPU,
213                                    const std::string &TuneCPU,
214                                    const std::string &FS,
215                                    const TargetMachine &TM, bool LittleEndian,
216                                    unsigned MinSVEVectorSizeInBitsOverride,
217                                    unsigned MaxSVEVectorSizeInBitsOverride)
218     : AArch64GenSubtargetInfo(TT, CPU, TuneCPU, FS),
219       ReserveXRegister(AArch64::GPR64commonRegClass.getNumRegs()),
220       CustomCallSavedXRegs(AArch64::GPR64commonRegClass.getNumRegs()),
221       IsLittle(LittleEndian),
222       MinSVEVectorSizeInBits(MinSVEVectorSizeInBitsOverride),
223       MaxSVEVectorSizeInBits(MaxSVEVectorSizeInBitsOverride), TargetTriple(TT),
224       FrameLowering(),
225       InstrInfo(initializeSubtargetDependencies(FS, CPU, TuneCPU)), TSInfo(),
226       TLInfo(TM, *this) {
227   if (AArch64::isX18ReservedByDefault(TT))
228     ReserveXRegister.set(18);
229 
230   CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering()));
231   InlineAsmLoweringInfo.reset(new InlineAsmLowering(getTargetLowering()));
232   Legalizer.reset(new AArch64LegalizerInfo(*this));
233 
234   auto *RBI = new AArch64RegisterBankInfo(*getRegisterInfo());
235 
236   // FIXME: At this point, we can't rely on Subtarget having RBI.
237   // It's awkward to mix passing RBI and the Subtarget; should we pass
238   // TII/TRI as well?
239   InstSelector.reset(createAArch64InstructionSelector(
240       *static_cast<const AArch64TargetMachine *>(&TM), *this, *RBI));
241 
242   RegBankInfo.reset(RBI);
243 }
244 
245 const CallLowering *AArch64Subtarget::getCallLowering() const {
246   return CallLoweringInfo.get();
247 }
248 
249 const InlineAsmLowering *AArch64Subtarget::getInlineAsmLowering() const {
250   return InlineAsmLoweringInfo.get();
251 }
252 
253 InstructionSelector *AArch64Subtarget::getInstructionSelector() const {
254   return InstSelector.get();
255 }
256 
257 const LegalizerInfo *AArch64Subtarget::getLegalizerInfo() const {
258   return Legalizer.get();
259 }
260 
261 const RegisterBankInfo *AArch64Subtarget::getRegBankInfo() const {
262   return RegBankInfo.get();
263 }
264 
265 /// Find the target operand flags that describe how a global value should be
266 /// referenced for the current subtarget.
267 unsigned
268 AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
269                                           const TargetMachine &TM) const {
270   // MachO large model always goes via a GOT, simply to get a single 8-byte
271   // absolute relocation on all global addresses.
272   if (TM.getCodeModel() == CodeModel::Large && isTargetMachO())
273     return AArch64II::MO_GOT;
274 
275   if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) {
276     if (GV->hasDLLImportStorageClass())
277       return AArch64II::MO_GOT | AArch64II::MO_DLLIMPORT;
278     if (getTargetTriple().isOSWindows())
279       return AArch64II::MO_GOT | AArch64II::MO_COFFSTUB;
280     return AArch64II::MO_GOT;
281   }
282 
283   // The small code model's direct accesses use ADRP, which cannot
284   // necessarily produce the value 0 (if the code is above 4GB).
285   // Same for the tiny code model, where we have a pc relative LDR.
286   if ((useSmallAddressing() || TM.getCodeModel() == CodeModel::Tiny) &&
287       GV->hasExternalWeakLinkage())
288     return AArch64II::MO_GOT;
289 
290   // References to tagged globals are marked with MO_NC | MO_TAGGED to indicate
291   // that their nominal addresses are tagged and outside of the code model. In
292   // AArch64ExpandPseudo::expandMI we emit an additional instruction to set the
293   // tag if necessary based on MO_TAGGED.
294   if (AllowTaggedGlobals && !isa<FunctionType>(GV->getValueType()))
295     return AArch64II::MO_NC | AArch64II::MO_TAGGED;
296 
297   return AArch64II::MO_NO_FLAG;
298 }
299 
300 unsigned AArch64Subtarget::classifyGlobalFunctionReference(
301     const GlobalValue *GV, const TargetMachine &TM) const {
302   // MachO large model always goes via a GOT, because we don't have the
303   // relocations available to do anything else..
304   if (TM.getCodeModel() == CodeModel::Large && isTargetMachO() &&
305       !GV->hasInternalLinkage())
306     return AArch64II::MO_GOT;
307 
308   // NonLazyBind goes via GOT unless we know it's available locally.
309   auto *F = dyn_cast<Function>(GV);
310   if (UseNonLazyBind && F && F->hasFnAttribute(Attribute::NonLazyBind) &&
311       !TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
312     return AArch64II::MO_GOT;
313 
314   // Use ClassifyGlobalReference for setting MO_DLLIMPORT/MO_COFFSTUB.
315   if (getTargetTriple().isOSWindows())
316     return ClassifyGlobalReference(GV, TM);
317 
318   return AArch64II::MO_NO_FLAG;
319 }
320 
321 void AArch64Subtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
322                                            unsigned NumRegionInstrs) const {
323   // LNT run (at least on Cyclone) showed reasonably significant gains for
324   // bi-directional scheduling. 253.perlbmk.
325   Policy.OnlyTopDown = false;
326   Policy.OnlyBottomUp = false;
327   // Enabling or Disabling the latency heuristic is a close call: It seems to
328   // help nearly no benchmark on out-of-order architectures, on the other hand
329   // it regresses register pressure on a few benchmarking.
330   Policy.DisableLatencyHeuristic = DisableLatencySchedHeuristic;
331 }
332 
333 bool AArch64Subtarget::enableEarlyIfConversion() const {
334   return EnableEarlyIfConvert;
335 }
336 
337 bool AArch64Subtarget::supportsAddressTopByteIgnored() const {
338   if (!UseAddressTopByteIgnored)
339     return false;
340 
341   if (TargetTriple.isiOS()) {
342     unsigned Major, Minor, Micro;
343     TargetTriple.getiOSVersion(Major, Minor, Micro);
344     return Major >= 8;
345   }
346 
347   return false;
348 }
349 
350 std::unique_ptr<PBQPRAConstraint>
351 AArch64Subtarget::getCustomPBQPConstraints() const {
352   return balanceFPOps() ? std::make_unique<A57ChainingConstraint>() : nullptr;
353 }
354 
355 void AArch64Subtarget::mirFileLoaded(MachineFunction &MF) const {
356   // We usually compute max call frame size after ISel. Do the computation now
357   // if the .mir file didn't specify it. Note that this will probably give you
358   // bogus values after PEI has eliminated the callframe setup/destroy pseudo
359   // instructions, specify explicitly if you need it to be correct.
360   MachineFrameInfo &MFI = MF.getFrameInfo();
361   if (!MFI.isMaxCallFrameSizeComputed())
362     MFI.computeMaxCallFrameSize(MF);
363 }
364 
365 bool AArch64Subtarget::useSVEForFixedLengthVectors() const {
366   // Prefer NEON unless larger SVE registers are available.
367   return hasSVE() && getMinSVEVectorSizeInBits() >= 256;
368 }
369 
370 bool AArch64Subtarget::useAA() const { return UseAA; }
371