1//===- AArch64TargetTransformInfo.h - AArch64 specific TTI ------*- 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/// \file
9/// This file a TargetTransformInfoImplBase conforming object specific to the
10/// AArch64 target machine. It uses the target's detailed information to
11/// provide more precise answers to certain TTI queries, while letting the
12/// target independent and default TTI implementations handle the rest.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
17#define LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
18
19#include "AArch64.h"
20#include "AArch64Subtarget.h"
21#include "AArch64TargetMachine.h"
22#include "llvm/Analysis/TargetTransformInfo.h"
23#include "llvm/CodeGen/BasicTTIImpl.h"
24#include "llvm/IR/FMF.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/Intrinsics.h"
27#include "llvm/Support/InstructionCost.h"
28#include <cstdint>
29#include <optional>
30
31namespace llvm {
32
33class APInt;
34class Instruction;
35class IntrinsicInst;
36class Loop;
37class SCEV;
38class ScalarEvolution;
39class Type;
40class Value;
41class VectorType;
42
43class AArch64TTIImpl final : public BasicTTIImplBase<AArch64TTIImpl> {
44 using BaseT = BasicTTIImplBase<AArch64TTIImpl>;
45 using TTI = TargetTransformInfo;
46
47 friend BaseT;
48
49 const AArch64Subtarget *ST;
50 const AArch64TargetLowering *TLI;
51
52 const AArch64Subtarget *getST() const { return ST; }
53 const AArch64TargetLowering *getTLI() const { return TLI; }
54
55 /// Given a add/sub/mul operation, detect a widening addl/subl/mull pattern
56 /// where both operands can be treated like extends. Returns the minimal type
57 /// needed to compute the operation.
58 Type *isBinExtWideningInstruction(unsigned Opcode, Type *DstTy,
59 ArrayRef<const Value *> Args,
60 Type *SrcOverrideTy = nullptr) const;
61 /// Given a add/sub operation with a single extend operand, detect a
62 /// widening addw/subw pattern.
63 bool isSingleExtWideningInstruction(unsigned Opcode, Type *DstTy,
64 ArrayRef<const Value *> Args,
65 Type *SrcOverrideTy = nullptr) const;
66
67 // A helper function called by 'getVectorInstrCost'.
68 //
69 // 'Val' and 'Index' are forwarded from 'getVectorInstrCost';
70 // \param ScalarUserAndIdx encodes the information about extracts from a
71 /// vector with 'Scalar' being the value being extracted,'User' being the user
72 /// of the extract(nullptr if user is not known before vectorization) and
73 /// 'Idx' being the extract lane.
74 InstructionCost getVectorInstrCostHelper(
75 unsigned Opcode, Type *Val, TTI::TargetCostKind CostKind, unsigned Index,
76 const Instruction *I = nullptr, Value *Scalar = nullptr,
77 ArrayRef<std::tuple<Value *, User *, int>> ScalarUserAndIdx = {},
78 TTI::VectorInstrContext VIC = TTI::VectorInstrContext::None) const;
79
80public:
81 explicit AArch64TTIImpl(const AArch64TargetMachine *TM, const Function &F)
82 : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
83 TLI(ST->getTargetLowering()) {}
84
85 bool areInlineCompatible(const Function *Caller,
86 const Function *Callee) const override;
87
88 bool areTypesABICompatible(const Function *Caller, const Function *Callee,
89 ArrayRef<Type *> Types) const override;
90
91 unsigned getInlineCallPenalty(const Function *F, const CallBase &Call,
92 unsigned DefaultCallPenalty) const override;
93
94 APInt getFeatureMask(const Function &F) const override;
95 APInt getPriorityMask(const Function &F) const override;
96
97 bool isMultiversionedFunction(const Function &F) const override;
98
99 /// \name Scalar TTI Implementations
100 /// @{
101
102 using BaseT::getIntImmCost;
103 InstructionCost getIntImmCost(int64_t Val) const;
104 InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
105 TTI::TargetCostKind CostKind) const override;
106 InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
107 const APInt &Imm, Type *Ty,
108 TTI::TargetCostKind CostKind,
109 Instruction *Inst = nullptr) const override;
110 InstructionCost
111 getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
112 Type *Ty, TTI::TargetCostKind CostKind) const override;
113 TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth) const override;
114
115 /// @}
116
117 /// \name Vector TTI Implementations
118 /// @{
119
120 bool enableInterleavedAccessVectorization() const override { return true; }
121
122 bool enableMaskedInterleavedAccessVectorization() const override {
123 return ST->hasSVE();
124 }
125
126 unsigned getNumberOfRegisters(unsigned ClassID) const override {
127 bool Vector = (ClassID == 1);
128 if (Vector) {
129 if (ST->hasNEON())
130 return 32;
131 return 0;
132 }
133 return 31;
134 }
135
136 InstructionCost
137 getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
138 TTI::TargetCostKind CostKind) const override;
139
140 std::optional<Instruction *>
141 instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const override;
142
143 std::optional<Value *> simplifyDemandedVectorEltsIntrinsic(
144 InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts,
145 APInt &UndefElts2, APInt &UndefElts3,
146 std::function<void(Instruction *, unsigned, APInt, APInt &)>
147 SimplifyAndSetOp) const override;
148
149 TypeSize
150 getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const override;
151
152 unsigned getMinVectorRegisterBitWidth() const override {
153 return ST->getMinVectorRegisterBitWidth();
154 }
155
156 std::optional<unsigned> getVScaleForTuning() const override {
157 return ST->getVScaleForTuning();
158 }
159
160 bool shouldMaximizeVectorBandwidth(
161 TargetTransformInfo::RegisterKind K) const override;
162
163 /// Try to return an estimate cost factor that can be used as a multiplier
164 /// when scalarizing an operation for a vector with ElementCount \p VF.
165 /// For scalable vectors this currently takes the most pessimistic view based
166 /// upon the maximum possible value for vscale.
167 unsigned getMaxNumElements(ElementCount VF) const {
168 if (!VF.isScalable())
169 return VF.getFixedValue();
170
171 return VF.getKnownMinValue() * ST->getVScaleForTuning();
172 }
173
174 unsigned getMaxInterleaveFactor(ElementCount VF,
175 bool HasUnorderedReductions) const override;
176
177 bool prefersVectorizedAddressing() const override;
178
179 /// Check whether Opcode1 has less throughput according to the scheduling
180 /// model than Opcode2.
181 bool hasKnownLowerThroughputFromSchedulingModel(unsigned Opcode1,
182 unsigned Opcode2) const;
183
184 InstructionCost
185 getMemIntrinsicInstrCost(const MemIntrinsicCostAttributes &MICA,
186 TTI::TargetCostKind CostKind) const override;
187
188 InstructionCost getMaskedMemoryOpCost(const MemIntrinsicCostAttributes &MICA,
189 TTI::TargetCostKind CostKind) const;
190
191 InstructionCost getGatherScatterOpCost(const MemIntrinsicCostAttributes &MICA,
192 TTI::TargetCostKind CostKind) const;
193
194 bool isExtPartOfAvgExpr(const Instruction *ExtUser, Type *Dst,
195 Type *Src) const;
196
197 InstructionCost
198 getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
199 TTI::CastContextHint CCH, TTI::TargetCostKind CostKind,
200 const Instruction *I = nullptr) const override;
201
202 InstructionCost
203 getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy,
204 unsigned Index,
205 TTI::TargetCostKind CostKind) const override;
206
207 InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
208 const Instruction *I = nullptr) const override;
209
210 InstructionCost
211 getVectorInstrCost(unsigned Opcode, Type *Val, TTI::TargetCostKind CostKind,
212 unsigned Index, const Value *Op0, const Value *Op1,
213 TTI::VectorInstrContext VIC =
214 TTI::VectorInstrContext::None) const override;
215
216 /// \param ScalarUserAndIdx encodes the information about extracts from a
217 /// vector with 'Scalar' being the value being extracted,'User' being the user
218 /// of the extract(nullptr if user is not known before vectorization) and
219 /// 'Idx' being the extract lane.
220 InstructionCost getVectorInstrCost(
221 unsigned Opcode, Type *Val, TTI::TargetCostKind CostKind, unsigned Index,
222 Value *Scalar,
223 ArrayRef<std::tuple<Value *, User *, int>> ScalarUserAndIdx,
224 TTI::VectorInstrContext VIC =
225 TTI::VectorInstrContext::None) const override;
226
227 InstructionCost
228 getVectorInstrCost(const Instruction &I, Type *Val,
229 TTI::TargetCostKind CostKind, unsigned Index,
230 TTI::VectorInstrContext VIC =
231 TTI::VectorInstrContext::None) const override;
232
233 InstructionCost
234 getIndexedVectorInstrCostFromEnd(unsigned Opcode, Type *Val,
235 TTI::TargetCostKind CostKind,
236 unsigned Index) const override;
237
238 InstructionCost
239 getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty, FastMathFlags FMF,
240 TTI::TargetCostKind CostKind) const override;
241
242 InstructionCost
243 getArithmeticReductionCostSVE(unsigned Opcode, VectorType *ValTy,
244 TTI::TargetCostKind CostKind) const;
245
246 InstructionCost getSpliceCost(VectorType *Tp, int Index,
247 TTI::TargetCostKind CostKind) const;
248
249 InstructionCost getArithmeticInstrCost(
250 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
251 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
252 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
253 ArrayRef<const Value *> Args = {},
254 const Instruction *CxtI = nullptr) const override;
255
256 InstructionCost
257 getAddressComputationCost(Type *PtrTy, ScalarEvolution *SE, const SCEV *Ptr,
258 TTI::TargetCostKind CostKind) const override;
259
260 InstructionCost getCmpSelInstrCost(
261 unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
262 TTI::TargetCostKind CostKind,
263 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
264 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
265 const Instruction *I = nullptr) const override;
266
267 TTI::MemCmpExpansionOptions
268 enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const override;
269 bool useNeonVector(const Type *Ty) const;
270
271 InstructionCost getMemoryOpCost(
272 unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace,
273 TTI::TargetCostKind CostKind,
274 TTI::OperandValueInfo OpInfo = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
275 const Instruction *I = nullptr) const override;
276
277 InstructionCost
278 getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) const override;
279
280 bool isLegalMaskedExpandLoad(Type *DataTy, Align Alignment) const override;
281
282 void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
283 TTI::UnrollingPreferences &UP,
284 OptimizationRemarkEmitter *ORE) const override;
285
286 void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
287 TTI::PeelingPreferences &PP) const override;
288
289 Value *
290 getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst, Type *ExpectedType,
291 bool CanCreate = true) const override;
292
293 bool getTgtMemIntrinsic(IntrinsicInst *Inst,
294 MemIntrinsicInfo &Info) const override;
295
296 bool isElementTypeLegalForScalableVector(Type *Ty) const override {
297 if (Ty->isPointerTy())
298 return true;
299
300 if (Ty->isBFloatTy() && ST->hasBF16())
301 return true;
302
303 if (Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy())
304 return true;
305
306 if (Ty->isIntegerTy(BitWidth: 1) || Ty->isIntegerTy(BitWidth: 8) || Ty->isIntegerTy(BitWidth: 16) ||
307 Ty->isIntegerTy(BitWidth: 32) || Ty->isIntegerTy(BitWidth: 64))
308 return true;
309
310 return false;
311 }
312
313 bool isLegalMaskedLoadStore(Type *DataType, Align Alignment) const {
314 if (!ST->isSVEorStreamingSVEAvailable())
315 return false;
316
317 if (isa<FixedVectorType>(Val: DataType) && !ST->useSVEForFixedLengthVectors()) {
318 unsigned Bits = DataType->getPrimitiveSizeInBits();
319 if (Bits != 64 && Bits != 128)
320 return false; // Fall back to scalarization of masked operations.
321 }
322
323 return isElementTypeLegalForScalableVector(Ty: DataType->getScalarType());
324 }
325
326 bool isLegalMaskedLoad(Type *DataType, Align Alignment,
327 unsigned /*AddressSpace*/,
328 TTI::MaskKind /*MaskKind*/) const override {
329 return isLegalMaskedLoadStore(DataType, Alignment);
330 }
331
332 bool isLegalMaskedStore(Type *DataType, Align Alignment,
333 unsigned /*AddressSpace*/,
334 TTI::MaskKind /*MaskKind*/) const override {
335 return isLegalMaskedLoadStore(DataType, Alignment);
336 }
337
338 bool isElementTypeLegalForCompressStore(Type *Ty) const {
339 return Ty->isFloatTy() || Ty->isDoubleTy() || Ty->isIntegerTy(BitWidth: 32) ||
340 Ty->isIntegerTy(BitWidth: 64);
341 }
342
343 bool isLegalMaskedCompressStore(Type *DataType,
344 Align Alignment) const override {
345 if (!ST->isSVEAvailable())
346 return false;
347
348 if (isa<FixedVectorType>(Val: DataType) &&
349 DataType->getPrimitiveSizeInBits() < 128)
350 return false;
351
352 return isElementTypeLegalForCompressStore(Ty: DataType->getScalarType());
353 }
354
355 bool isLegalMaskedGatherScatter(Type *DataType) const {
356 if (!ST->isSVEAvailable())
357 return false;
358
359 // For fixed vectors, scalarize if not using SVE for them.
360 auto *DataTypeFVTy = dyn_cast<FixedVectorType>(Val: DataType);
361 if (DataTypeFVTy && (!ST->useSVEForFixedLengthVectors() ||
362 DataTypeFVTy->getNumElements() < 2))
363 return false;
364
365 return isElementTypeLegalForScalableVector(Ty: DataType->getScalarType());
366 }
367
368 bool isLegalMaskedGather(Type *DataType, Align Alignment) const override {
369 return isLegalMaskedGatherScatter(DataType);
370 }
371
372 bool isLegalMaskedScatter(Type *DataType, Align Alignment) const override {
373 return isLegalMaskedGatherScatter(DataType);
374 }
375
376 bool isLegalBroadcastLoad(Type *ElementTy,
377 ElementCount NumElements) const override {
378 // Return true if we can generate a `ld1r` splat load instruction.
379 if (!ST->hasNEON() || NumElements.isScalable())
380 return false;
381 switch (unsigned ElementBits = ElementTy->getScalarSizeInBits()) {
382 case 8:
383 case 16:
384 case 32:
385 case 64: {
386 // We accept bit-widths >= 64bits and elements {8,16,32,64} bits.
387 unsigned VectorBits = NumElements.getFixedValue() * ElementBits;
388 return VectorBits >= 64;
389 }
390 }
391 return false;
392 }
393
394 std::optional<bool> isLegalNTStoreLoad(Type *DataType,
395 Align Alignment) const {
396 // Currently we only support NT load and store lowering for little-endian
397 // targets.
398 //
399 // Coordinated with LDNP and STNP constraints in
400 // `llvm/lib/Target/AArch64/AArch64InstrInfo.td` and
401 // `AArch64ISelLowering.cpp`
402 if (!ST->isLittleEndian())
403 return false;
404
405 // NOTE: The logic below is mostly geared towards LV, which calls it with
406 // vectors with 2 elements. We might want to improve that, if other
407 // users show up.
408 // Nontemporal vector loads/stores can be directly lowered to LDNP/STNP, if
409 // the vector can be halved so that each half fits into a register. That's
410 // the case if the element type fits into a register and the number of
411 // elements is a power of 2 > 1.
412 if (auto *DataTypeTy = dyn_cast<FixedVectorType>(Val: DataType)) {
413 unsigned NumElements = DataTypeTy->getNumElements();
414 unsigned EltSize = DataTypeTy->getElementType()->getScalarSizeInBits();
415 return NumElements > 1 && isPowerOf2_64(Value: NumElements) && EltSize >= 8 &&
416 EltSize <= 128 && isPowerOf2_64(Value: EltSize);
417 }
418 return std::nullopt;
419 }
420
421 bool isLegalNTStore(Type *DataType, Align Alignment) const override {
422 if (auto Result = isLegalNTStoreLoad(DataType, Alignment))
423 return *Result;
424 // Fallback to target independent logic
425 return BaseT::isLegalNTStore(DataType, Alignment);
426 }
427
428 bool isLegalNTLoad(Type *DataType, Align Alignment) const override {
429 if (auto Result = isLegalNTStoreLoad(DataType, Alignment))
430 return *Result;
431 // Fallback to target independent logic
432 return BaseT::isLegalNTLoad(DataType, Alignment);
433 }
434
435 InstructionCost getPartialReductionCost(
436 unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
437 ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,
438 TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,
439 TTI::TargetCostKind CostKind,
440 std::optional<FastMathFlags> FMF) const override;
441
442 bool enableOrderedReductions() const override { return true; }
443
444 InstructionCost getInterleavedMemoryOpCost(
445 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
446 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
447 bool UseMaskForCond = false, bool UseMaskForGaps = false) const override;
448
449 bool shouldConsiderAddressTypePromotion(
450 const Instruction &I,
451 bool &AllowPromotionWithoutCommonHeader) const override;
452
453 bool shouldExpandReduction(const IntrinsicInst *II) const override {
454 return false;
455 }
456
457 unsigned getGISelRematGlobalCost() const override { return 2; }
458
459 InstructionCost getBranchMispredictPenalty() const override;
460
461 unsigned getMinTripCountTailFoldingThreshold() const override {
462 return ST->hasSVE() ? 5 : 0;
463 }
464
465 TailFoldingStyle getPreferredTailFoldingStyle() const override {
466 return ST->hasSVE() ? TailFoldingStyle::DataAndControlFlow
467 : TailFoldingStyle::DataWithoutLaneMask;
468 }
469
470 bool preferFixedOverScalableIfEqualCost(bool IsEpilogue) const override;
471
472 unsigned getEpilogueVectorizationMinVF() const override;
473
474 bool preferTailFoldingOverEpilogue(TailFoldingInfo *TFI) const override;
475
476 bool supportsScalableVectors() const override {
477 return ST->isSVEorStreamingSVEAvailable();
478 }
479
480 bool enableScalableVectorization() const override;
481
482 bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc,
483 ElementCount VF) const override;
484
485 bool preferPredicatedReductionSelect() const override { return ST->hasSVE(); }
486
487 /// FP16 and BF16 operations are lowered to fptrunc(op(fpext, fpext) if the
488 /// architecture features are not present.
489 std::optional<InstructionCost> getFP16BF16PromoteCost(
490 Type *Ty, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info,
491 TTI::OperandValueInfo Op2Info, bool IncludeTrunc, bool CanUseSVE,
492 std::function<InstructionCost(Type *)> InstCost) const;
493
494 InstructionCost
495 getArithmeticReductionCost(unsigned Opcode, VectorType *Ty,
496 std::optional<FastMathFlags> FMF,
497 TTI::TargetCostKind CostKind) const override;
498
499 InstructionCost
500 getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy,
501 VectorType *ValTy, std::optional<FastMathFlags> FMF,
502 TTI::TargetCostKind CostKind) const override;
503
504 InstructionCost getMulAccReductionCost(
505 bool IsUnsigned, unsigned RedOpcode, Type *ResTy, VectorType *Ty,
506 TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput) const override;
507
508 InstructionCost
509 getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy,
510 ArrayRef<int> Mask, TTI::TargetCostKind CostKind, int Index,
511 VectorType *SubTp, ArrayRef<const Value *> Args = {},
512 const Instruction *CxtI = nullptr) const override;
513
514 InstructionCost
515 getScalarizationOverhead(VectorType *Ty, const APInt &DemandedElts,
516 bool Insert, bool Extract,
517 TTI::TargetCostKind CostKind,
518 bool ForPoisonSrc = true, ArrayRef<Value *> VL = {},
519 TTI::VectorInstrContext VIC =
520 TTI::VectorInstrContext::None) const override;
521
522 /// Return the cost of the scaling factor used in the addressing
523 /// mode represented by AM for this target, for a load/store
524 /// of the specified type.
525 /// If the AM is supported, the return value must be >= 0.
526 /// If the AM is not supported, it returns an invalid cost.
527 InstructionCost getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
528 StackOffset BaseOffset, bool HasBaseReg,
529 int64_t Scale,
530 unsigned AddrSpace) const override;
531
532 bool enableSelectOptimize() const override {
533 return ST->enableSelectOptimize();
534 }
535
536 bool shouldTreatInstructionLikeSelect(const Instruction *I) const override;
537
538 unsigned getStoreMinimumVF(unsigned VF, Type *ScalarMemTy, Type *ScalarValTy,
539 Align Alignment,
540 unsigned AddrSpace) const override {
541 // We can vectorize store v4i8.
542 if (ScalarMemTy->isIntegerTy(BitWidth: 8) && isPowerOf2_32(Value: VF) && VF >= 4)
543 return 4;
544
545 return BaseT::getStoreMinimumVF(VF, ScalarMemTy, ScalarValTy, Alignment,
546 AddrSpace);
547 }
548
549 std::optional<unsigned> getMinPageSize() const override { return 4096; }
550
551 bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
552 const TargetTransformInfo::LSRCost &C2) const override;
553
554 bool isProfitableToSinkOperands(Instruction *I,
555 SmallVectorImpl<Use *> &Ops) const override;
556
557 bool enableAggressiveInterleaving(bool) const override {
558 return ST->enableAggressiveInterleaving();
559 }
560 /// @}
561};
562
563} // end namespace llvm
564
565#endif // LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
566