106f32e7eSjoerg //===-- AArch64Subtarget.cpp - AArch64 Subtarget Information ----*- C++ -*-===//
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 // This file implements the AArch64 specific subclass of TargetSubtarget.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg
1306f32e7eSjoerg #include "AArch64Subtarget.h"
1406f32e7eSjoerg
1506f32e7eSjoerg #include "AArch64.h"
1606f32e7eSjoerg #include "AArch64InstrInfo.h"
1706f32e7eSjoerg #include "AArch64PBQPRegAlloc.h"
1806f32e7eSjoerg #include "AArch64TargetMachine.h"
19*da58b97aSjoerg #include "GISel/AArch64CallLowering.h"
20*da58b97aSjoerg #include "GISel/AArch64LegalizerInfo.h"
21*da58b97aSjoerg #include "GISel/AArch64RegisterBankInfo.h"
2206f32e7eSjoerg #include "MCTargetDesc/AArch64AddressingModes.h"
2306f32e7eSjoerg #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
2406f32e7eSjoerg #include "llvm/CodeGen/MachineScheduler.h"
2506f32e7eSjoerg #include "llvm/IR/GlobalValue.h"
2606f32e7eSjoerg #include "llvm/Support/TargetParser.h"
2706f32e7eSjoerg
2806f32e7eSjoerg using namespace llvm;
2906f32e7eSjoerg
3006f32e7eSjoerg #define DEBUG_TYPE "aarch64-subtarget"
3106f32e7eSjoerg
3206f32e7eSjoerg #define GET_SUBTARGETINFO_CTOR
3306f32e7eSjoerg #define GET_SUBTARGETINFO_TARGET_DESC
3406f32e7eSjoerg #include "AArch64GenSubtargetInfo.inc"
3506f32e7eSjoerg
3606f32e7eSjoerg static cl::opt<bool>
3706f32e7eSjoerg EnableEarlyIfConvert("aarch64-early-ifcvt", cl::desc("Enable the early if "
3806f32e7eSjoerg "converter pass"), cl::init(true), cl::Hidden);
3906f32e7eSjoerg
4006f32e7eSjoerg // If OS supports TBI, use this flag to enable it.
4106f32e7eSjoerg static cl::opt<bool>
4206f32e7eSjoerg UseAddressTopByteIgnored("aarch64-use-tbi", cl::desc("Assume that top byte of "
4306f32e7eSjoerg "an address is ignored"), cl::init(false), cl::Hidden);
4406f32e7eSjoerg
4506f32e7eSjoerg static cl::opt<bool>
4606f32e7eSjoerg UseNonLazyBind("aarch64-enable-nonlazybind",
4706f32e7eSjoerg cl::desc("Call nonlazybind functions via direct GOT load"),
4806f32e7eSjoerg cl::init(false), cl::Hidden);
4906f32e7eSjoerg
50*da58b97aSjoerg static cl::opt<unsigned> SVEVectorBitsMax(
51*da58b97aSjoerg "aarch64-sve-vector-bits-max",
52*da58b97aSjoerg cl::desc("Assume SVE vector registers are at most this big, "
53*da58b97aSjoerg "with zero meaning no maximum size is assumed."),
54*da58b97aSjoerg cl::init(0), cl::Hidden);
55*da58b97aSjoerg
56*da58b97aSjoerg static cl::opt<unsigned> SVEVectorBitsMin(
57*da58b97aSjoerg "aarch64-sve-vector-bits-min",
58*da58b97aSjoerg cl::desc("Assume SVE vector registers are at least this big, "
59*da58b97aSjoerg "with zero meaning no minimum size is assumed."),
60*da58b97aSjoerg cl::init(0), cl::Hidden);
61*da58b97aSjoerg
62*da58b97aSjoerg static cl::opt<bool> UseAA("aarch64-use-aa", cl::init(true),
63*da58b97aSjoerg cl::desc("Enable the use of AA during codegen."));
64*da58b97aSjoerg
6506f32e7eSjoerg AArch64Subtarget &
initializeSubtargetDependencies(StringRef FS,StringRef CPUString)6606f32e7eSjoerg AArch64Subtarget::initializeSubtargetDependencies(StringRef FS,
6706f32e7eSjoerg StringRef CPUString) {
6806f32e7eSjoerg // Determine default and user-specified characteristics
6906f32e7eSjoerg
7006f32e7eSjoerg if (CPUString.empty())
7106f32e7eSjoerg CPUString = "generic";
7206f32e7eSjoerg
73*da58b97aSjoerg ParseSubtargetFeatures(CPUString, /*TuneCPU*/ CPUString, FS);
7406f32e7eSjoerg initializeProperties();
7506f32e7eSjoerg
7606f32e7eSjoerg return *this;
7706f32e7eSjoerg }
7806f32e7eSjoerg
initializeProperties()7906f32e7eSjoerg void AArch64Subtarget::initializeProperties() {
8006f32e7eSjoerg // Initialize CPU specific properties. We should add a tablegen feature for
8106f32e7eSjoerg // this in the future so we can specify it together with the subtarget
8206f32e7eSjoerg // features.
8306f32e7eSjoerg switch (ARMProcFamily) {
8406f32e7eSjoerg case Others:
8506f32e7eSjoerg break;
86*da58b97aSjoerg case Carmel:
87*da58b97aSjoerg CacheLineSize = 64;
88*da58b97aSjoerg break;
8906f32e7eSjoerg case CortexA35:
9006f32e7eSjoerg break;
9106f32e7eSjoerg case CortexA53:
9206f32e7eSjoerg case CortexA55:
93*da58b97aSjoerg PrefFunctionLogAlignment = 4;
9406f32e7eSjoerg break;
9506f32e7eSjoerg case CortexA57:
9606f32e7eSjoerg MaxInterleaveFactor = 4;
9706f32e7eSjoerg PrefFunctionLogAlignment = 4;
9806f32e7eSjoerg break;
9906f32e7eSjoerg case CortexA65:
10006f32e7eSjoerg PrefFunctionLogAlignment = 3;
10106f32e7eSjoerg break;
10206f32e7eSjoerg case CortexA72:
10306f32e7eSjoerg case CortexA73:
10406f32e7eSjoerg case CortexA75:
10506f32e7eSjoerg case CortexA76:
106*da58b97aSjoerg case CortexA77:
107*da58b97aSjoerg case CortexA78:
108*da58b97aSjoerg case CortexA78C:
109*da58b97aSjoerg case CortexR82:
110*da58b97aSjoerg case CortexX1:
11106f32e7eSjoerg PrefFunctionLogAlignment = 4;
11206f32e7eSjoerg break;
113*da58b97aSjoerg case A64FX:
114*da58b97aSjoerg CacheLineSize = 256;
115*da58b97aSjoerg PrefFunctionLogAlignment = 3;
116*da58b97aSjoerg PrefLoopLogAlignment = 2;
117*da58b97aSjoerg MaxInterleaveFactor = 4;
118*da58b97aSjoerg PrefetchDistance = 128;
119*da58b97aSjoerg MinPrefetchStride = 1024;
120*da58b97aSjoerg MaxPrefetchIterationsAhead = 4;
121*da58b97aSjoerg break;
122*da58b97aSjoerg case AppleA7:
123*da58b97aSjoerg case AppleA10:
124*da58b97aSjoerg case AppleA11:
125*da58b97aSjoerg case AppleA12:
126*da58b97aSjoerg case AppleA13:
127*da58b97aSjoerg case AppleA14:
12806f32e7eSjoerg CacheLineSize = 64;
12906f32e7eSjoerg PrefetchDistance = 280;
13006f32e7eSjoerg MinPrefetchStride = 2048;
13106f32e7eSjoerg MaxPrefetchIterationsAhead = 3;
13206f32e7eSjoerg break;
13306f32e7eSjoerg case ExynosM3:
13406f32e7eSjoerg MaxInterleaveFactor = 4;
13506f32e7eSjoerg MaxJumpTableSize = 20;
13606f32e7eSjoerg PrefFunctionLogAlignment = 5;
13706f32e7eSjoerg PrefLoopLogAlignment = 4;
13806f32e7eSjoerg break;
13906f32e7eSjoerg case Falkor:
14006f32e7eSjoerg MaxInterleaveFactor = 4;
14106f32e7eSjoerg // FIXME: remove this to enable 64-bit SLP if performance looks good.
14206f32e7eSjoerg MinVectorRegisterBitWidth = 128;
14306f32e7eSjoerg CacheLineSize = 128;
14406f32e7eSjoerg PrefetchDistance = 820;
14506f32e7eSjoerg MinPrefetchStride = 2048;
14606f32e7eSjoerg MaxPrefetchIterationsAhead = 8;
14706f32e7eSjoerg break;
14806f32e7eSjoerg case Kryo:
14906f32e7eSjoerg MaxInterleaveFactor = 4;
15006f32e7eSjoerg VectorInsertExtractBaseCost = 2;
15106f32e7eSjoerg CacheLineSize = 128;
15206f32e7eSjoerg PrefetchDistance = 740;
15306f32e7eSjoerg MinPrefetchStride = 1024;
15406f32e7eSjoerg MaxPrefetchIterationsAhead = 11;
15506f32e7eSjoerg // FIXME: remove this to enable 64-bit SLP if performance looks good.
15606f32e7eSjoerg MinVectorRegisterBitWidth = 128;
15706f32e7eSjoerg break;
15806f32e7eSjoerg case NeoverseE1:
15906f32e7eSjoerg PrefFunctionLogAlignment = 3;
16006f32e7eSjoerg break;
16106f32e7eSjoerg case NeoverseN1:
162*da58b97aSjoerg case NeoverseN2:
163*da58b97aSjoerg case NeoverseV1:
16406f32e7eSjoerg PrefFunctionLogAlignment = 4;
16506f32e7eSjoerg break;
16606f32e7eSjoerg case Saphira:
16706f32e7eSjoerg MaxInterleaveFactor = 4;
16806f32e7eSjoerg // FIXME: remove this to enable 64-bit SLP if performance looks good.
16906f32e7eSjoerg MinVectorRegisterBitWidth = 128;
17006f32e7eSjoerg break;
17106f32e7eSjoerg case ThunderX2T99:
17206f32e7eSjoerg CacheLineSize = 64;
17306f32e7eSjoerg PrefFunctionLogAlignment = 3;
17406f32e7eSjoerg PrefLoopLogAlignment = 2;
17506f32e7eSjoerg MaxInterleaveFactor = 4;
17606f32e7eSjoerg PrefetchDistance = 128;
17706f32e7eSjoerg MinPrefetchStride = 1024;
17806f32e7eSjoerg MaxPrefetchIterationsAhead = 4;
17906f32e7eSjoerg // FIXME: remove this to enable 64-bit SLP if performance looks good.
18006f32e7eSjoerg MinVectorRegisterBitWidth = 128;
18106f32e7eSjoerg break;
18206f32e7eSjoerg case ThunderX:
18306f32e7eSjoerg case ThunderXT88:
18406f32e7eSjoerg case ThunderXT81:
18506f32e7eSjoerg case ThunderXT83:
18606f32e7eSjoerg CacheLineSize = 128;
18706f32e7eSjoerg PrefFunctionLogAlignment = 3;
18806f32e7eSjoerg PrefLoopLogAlignment = 2;
18906f32e7eSjoerg // FIXME: remove this to enable 64-bit SLP if performance looks good.
19006f32e7eSjoerg MinVectorRegisterBitWidth = 128;
19106f32e7eSjoerg break;
19206f32e7eSjoerg case TSV110:
19306f32e7eSjoerg CacheLineSize = 64;
19406f32e7eSjoerg PrefFunctionLogAlignment = 4;
19506f32e7eSjoerg PrefLoopLogAlignment = 2;
19606f32e7eSjoerg break;
197*da58b97aSjoerg case ThunderX3T110:
198*da58b97aSjoerg CacheLineSize = 64;
199*da58b97aSjoerg PrefFunctionLogAlignment = 4;
200*da58b97aSjoerg PrefLoopLogAlignment = 2;
201*da58b97aSjoerg MaxInterleaveFactor = 4;
202*da58b97aSjoerg PrefetchDistance = 128;
203*da58b97aSjoerg MinPrefetchStride = 1024;
204*da58b97aSjoerg MaxPrefetchIterationsAhead = 4;
205*da58b97aSjoerg // FIXME: remove this to enable 64-bit SLP if performance looks good.
206*da58b97aSjoerg MinVectorRegisterBitWidth = 128;
207*da58b97aSjoerg break;
20806f32e7eSjoerg }
20906f32e7eSjoerg }
21006f32e7eSjoerg
AArch64Subtarget(const Triple & TT,const std::string & CPU,const std::string & FS,const TargetMachine & TM,bool LittleEndian)21106f32e7eSjoerg AArch64Subtarget::AArch64Subtarget(const Triple &TT, const std::string &CPU,
21206f32e7eSjoerg const std::string &FS,
21306f32e7eSjoerg const TargetMachine &TM, bool LittleEndian)
214*da58b97aSjoerg : AArch64GenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),
21506f32e7eSjoerg ReserveXRegister(AArch64::GPR64commonRegClass.getNumRegs()),
21606f32e7eSjoerg CustomCallSavedXRegs(AArch64::GPR64commonRegClass.getNumRegs()),
21706f32e7eSjoerg IsLittle(LittleEndian),
21806f32e7eSjoerg TargetTriple(TT), FrameLowering(),
21906f32e7eSjoerg InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(),
22006f32e7eSjoerg TLInfo(TM, *this) {
22106f32e7eSjoerg if (AArch64::isX18ReservedByDefault(TT))
22206f32e7eSjoerg ReserveXRegister.set(18);
22306f32e7eSjoerg
22406f32e7eSjoerg CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering()));
225*da58b97aSjoerg InlineAsmLoweringInfo.reset(new InlineAsmLowering(getTargetLowering()));
22606f32e7eSjoerg Legalizer.reset(new AArch64LegalizerInfo(*this));
22706f32e7eSjoerg
22806f32e7eSjoerg auto *RBI = new AArch64RegisterBankInfo(*getRegisterInfo());
22906f32e7eSjoerg
23006f32e7eSjoerg // FIXME: At this point, we can't rely on Subtarget having RBI.
23106f32e7eSjoerg // It's awkward to mix passing RBI and the Subtarget; should we pass
23206f32e7eSjoerg // TII/TRI as well?
23306f32e7eSjoerg InstSelector.reset(createAArch64InstructionSelector(
23406f32e7eSjoerg *static_cast<const AArch64TargetMachine *>(&TM), *this, *RBI));
23506f32e7eSjoerg
23606f32e7eSjoerg RegBankInfo.reset(RBI);
23706f32e7eSjoerg }
23806f32e7eSjoerg
getCallLowering() const23906f32e7eSjoerg const CallLowering *AArch64Subtarget::getCallLowering() const {
24006f32e7eSjoerg return CallLoweringInfo.get();
24106f32e7eSjoerg }
24206f32e7eSjoerg
getInlineAsmLowering() const243*da58b97aSjoerg const InlineAsmLowering *AArch64Subtarget::getInlineAsmLowering() const {
244*da58b97aSjoerg return InlineAsmLoweringInfo.get();
245*da58b97aSjoerg }
246*da58b97aSjoerg
getInstructionSelector() const24706f32e7eSjoerg InstructionSelector *AArch64Subtarget::getInstructionSelector() const {
24806f32e7eSjoerg return InstSelector.get();
24906f32e7eSjoerg }
25006f32e7eSjoerg
getLegalizerInfo() const25106f32e7eSjoerg const LegalizerInfo *AArch64Subtarget::getLegalizerInfo() const {
25206f32e7eSjoerg return Legalizer.get();
25306f32e7eSjoerg }
25406f32e7eSjoerg
getRegBankInfo() const25506f32e7eSjoerg const RegisterBankInfo *AArch64Subtarget::getRegBankInfo() const {
25606f32e7eSjoerg return RegBankInfo.get();
25706f32e7eSjoerg }
25806f32e7eSjoerg
25906f32e7eSjoerg /// Find the target operand flags that describe how a global value should be
26006f32e7eSjoerg /// referenced for the current subtarget.
26106f32e7eSjoerg unsigned
ClassifyGlobalReference(const GlobalValue * GV,const TargetMachine & TM) const26206f32e7eSjoerg AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
26306f32e7eSjoerg const TargetMachine &TM) const {
26406f32e7eSjoerg // MachO large model always goes via a GOT, simply to get a single 8-byte
26506f32e7eSjoerg // absolute relocation on all global addresses.
26606f32e7eSjoerg if (TM.getCodeModel() == CodeModel::Large && isTargetMachO())
26706f32e7eSjoerg return AArch64II::MO_GOT;
26806f32e7eSjoerg
26906f32e7eSjoerg if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) {
27006f32e7eSjoerg if (GV->hasDLLImportStorageClass())
27106f32e7eSjoerg return AArch64II::MO_GOT | AArch64II::MO_DLLIMPORT;
27206f32e7eSjoerg if (getTargetTriple().isOSWindows())
27306f32e7eSjoerg return AArch64II::MO_GOT | AArch64II::MO_COFFSTUB;
27406f32e7eSjoerg return AArch64II::MO_GOT;
27506f32e7eSjoerg }
27606f32e7eSjoerg
27706f32e7eSjoerg // The small code model's direct accesses use ADRP, which cannot
27806f32e7eSjoerg // necessarily produce the value 0 (if the code is above 4GB).
27906f32e7eSjoerg // Same for the tiny code model, where we have a pc relative LDR.
28006f32e7eSjoerg if ((useSmallAddressing() || TM.getCodeModel() == CodeModel::Tiny) &&
28106f32e7eSjoerg GV->hasExternalWeakLinkage())
28206f32e7eSjoerg return AArch64II::MO_GOT;
28306f32e7eSjoerg
28406f32e7eSjoerg // References to tagged globals are marked with MO_NC | MO_TAGGED to indicate
28506f32e7eSjoerg // that their nominal addresses are tagged and outside of the code model. In
28606f32e7eSjoerg // AArch64ExpandPseudo::expandMI we emit an additional instruction to set the
28706f32e7eSjoerg // tag if necessary based on MO_TAGGED.
28806f32e7eSjoerg if (AllowTaggedGlobals && !isa<FunctionType>(GV->getValueType()))
28906f32e7eSjoerg return AArch64II::MO_NC | AArch64II::MO_TAGGED;
29006f32e7eSjoerg
29106f32e7eSjoerg return AArch64II::MO_NO_FLAG;
29206f32e7eSjoerg }
29306f32e7eSjoerg
classifyGlobalFunctionReference(const GlobalValue * GV,const TargetMachine & TM) const29406f32e7eSjoerg unsigned AArch64Subtarget::classifyGlobalFunctionReference(
29506f32e7eSjoerg const GlobalValue *GV, const TargetMachine &TM) const {
29606f32e7eSjoerg // MachO large model always goes via a GOT, because we don't have the
29706f32e7eSjoerg // relocations available to do anything else..
29806f32e7eSjoerg if (TM.getCodeModel() == CodeModel::Large && isTargetMachO() &&
29906f32e7eSjoerg !GV->hasInternalLinkage())
30006f32e7eSjoerg return AArch64II::MO_GOT;
30106f32e7eSjoerg
30206f32e7eSjoerg // NonLazyBind goes via GOT unless we know it's available locally.
30306f32e7eSjoerg auto *F = dyn_cast<Function>(GV);
30406f32e7eSjoerg if (UseNonLazyBind && F && F->hasFnAttribute(Attribute::NonLazyBind) &&
30506f32e7eSjoerg !TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
30606f32e7eSjoerg return AArch64II::MO_GOT;
30706f32e7eSjoerg
308*da58b97aSjoerg // Use ClassifyGlobalReference for setting MO_DLLIMPORT/MO_COFFSTUB.
309*da58b97aSjoerg if (getTargetTriple().isOSWindows())
310*da58b97aSjoerg return ClassifyGlobalReference(GV, TM);
311*da58b97aSjoerg
31206f32e7eSjoerg return AArch64II::MO_NO_FLAG;
31306f32e7eSjoerg }
31406f32e7eSjoerg
overrideSchedPolicy(MachineSchedPolicy & Policy,unsigned NumRegionInstrs) const31506f32e7eSjoerg void AArch64Subtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
31606f32e7eSjoerg unsigned NumRegionInstrs) const {
31706f32e7eSjoerg // LNT run (at least on Cyclone) showed reasonably significant gains for
31806f32e7eSjoerg // bi-directional scheduling. 253.perlbmk.
31906f32e7eSjoerg Policy.OnlyTopDown = false;
32006f32e7eSjoerg Policy.OnlyBottomUp = false;
32106f32e7eSjoerg // Enabling or Disabling the latency heuristic is a close call: It seems to
32206f32e7eSjoerg // help nearly no benchmark on out-of-order architectures, on the other hand
32306f32e7eSjoerg // it regresses register pressure on a few benchmarking.
32406f32e7eSjoerg Policy.DisableLatencyHeuristic = DisableLatencySchedHeuristic;
32506f32e7eSjoerg }
32606f32e7eSjoerg
enableEarlyIfConversion() const32706f32e7eSjoerg bool AArch64Subtarget::enableEarlyIfConversion() const {
32806f32e7eSjoerg return EnableEarlyIfConvert;
32906f32e7eSjoerg }
33006f32e7eSjoerg
supportsAddressTopByteIgnored() const33106f32e7eSjoerg bool AArch64Subtarget::supportsAddressTopByteIgnored() const {
33206f32e7eSjoerg if (!UseAddressTopByteIgnored)
33306f32e7eSjoerg return false;
33406f32e7eSjoerg
33506f32e7eSjoerg if (TargetTriple.isiOS()) {
33606f32e7eSjoerg unsigned Major, Minor, Micro;
33706f32e7eSjoerg TargetTriple.getiOSVersion(Major, Minor, Micro);
33806f32e7eSjoerg return Major >= 8;
33906f32e7eSjoerg }
34006f32e7eSjoerg
34106f32e7eSjoerg return false;
34206f32e7eSjoerg }
34306f32e7eSjoerg
34406f32e7eSjoerg std::unique_ptr<PBQPRAConstraint>
getCustomPBQPConstraints() const34506f32e7eSjoerg AArch64Subtarget::getCustomPBQPConstraints() const {
34606f32e7eSjoerg return balanceFPOps() ? std::make_unique<A57ChainingConstraint>() : nullptr;
34706f32e7eSjoerg }
34806f32e7eSjoerg
mirFileLoaded(MachineFunction & MF) const34906f32e7eSjoerg void AArch64Subtarget::mirFileLoaded(MachineFunction &MF) const {
35006f32e7eSjoerg // We usually compute max call frame size after ISel. Do the computation now
35106f32e7eSjoerg // if the .mir file didn't specify it. Note that this will probably give you
35206f32e7eSjoerg // bogus values after PEI has eliminated the callframe setup/destroy pseudo
35306f32e7eSjoerg // instructions, specify explicitly if you need it to be correct.
35406f32e7eSjoerg MachineFrameInfo &MFI = MF.getFrameInfo();
35506f32e7eSjoerg if (!MFI.isMaxCallFrameSizeComputed())
35606f32e7eSjoerg MFI.computeMaxCallFrameSize(MF);
35706f32e7eSjoerg }
358*da58b97aSjoerg
getMaxSVEVectorSizeInBits() const359*da58b97aSjoerg unsigned AArch64Subtarget::getMaxSVEVectorSizeInBits() const {
360*da58b97aSjoerg assert(HasSVE && "Tried to get SVE vector length without SVE support!");
361*da58b97aSjoerg assert(SVEVectorBitsMax % 128 == 0 &&
362*da58b97aSjoerg "SVE requires vector length in multiples of 128!");
363*da58b97aSjoerg assert((SVEVectorBitsMax >= SVEVectorBitsMin || SVEVectorBitsMax == 0) &&
364*da58b97aSjoerg "Minimum SVE vector size should not be larger than its maximum!");
365*da58b97aSjoerg if (SVEVectorBitsMax == 0)
366*da58b97aSjoerg return 0;
367*da58b97aSjoerg return (std::max(SVEVectorBitsMin, SVEVectorBitsMax) / 128) * 128;
368*da58b97aSjoerg }
369*da58b97aSjoerg
getMinSVEVectorSizeInBits() const370*da58b97aSjoerg unsigned AArch64Subtarget::getMinSVEVectorSizeInBits() const {
371*da58b97aSjoerg assert(HasSVE && "Tried to get SVE vector length without SVE support!");
372*da58b97aSjoerg assert(SVEVectorBitsMin % 128 == 0 &&
373*da58b97aSjoerg "SVE requires vector length in multiples of 128!");
374*da58b97aSjoerg assert((SVEVectorBitsMax >= SVEVectorBitsMin || SVEVectorBitsMax == 0) &&
375*da58b97aSjoerg "Minimum SVE vector size should not be larger than its maximum!");
376*da58b97aSjoerg if (SVEVectorBitsMax == 0)
377*da58b97aSjoerg return (SVEVectorBitsMin / 128) * 128;
378*da58b97aSjoerg return (std::min(SVEVectorBitsMin, SVEVectorBitsMax) / 128) * 128;
379*da58b97aSjoerg }
380*da58b97aSjoerg
useSVEForFixedLengthVectors() const381*da58b97aSjoerg bool AArch64Subtarget::useSVEForFixedLengthVectors() const {
382*da58b97aSjoerg // Prefer NEON unless larger SVE registers are available.
383*da58b97aSjoerg return hasSVE() && getMinSVEVectorSizeInBits() >= 256;
384*da58b97aSjoerg }
385*da58b97aSjoerg
useAA() const386*da58b97aSjoerg bool AArch64Subtarget::useAA() const { return UseAA; }
387