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 *Ty, 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 *Ty, 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 *Ty, 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 *Ty,
229 TTI::TargetCostKind CostKind, unsigned Index,
230 TTI::VectorInstrContext VIC =
231 TTI::VectorInstrContext::None) const override;
232
233 InstructionCost
234 getIndexedVectorInstrCostFromEnd(unsigned Opcode, Type *Ty,
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() || Ty->isHalfTy() || Ty->isFloatTy() ||
301 Ty->isDoubleTy())
302 return true;
303
304 if (Ty->isIntegerTy(BitWidth: 1) || Ty->isIntegerTy(BitWidth: 8) || Ty->isIntegerTy(BitWidth: 16) ||
305 Ty->isIntegerTy(BitWidth: 32) || Ty->isIntegerTy(BitWidth: 64))
306 return true;
307
308 return false;
309 }
310
311 bool isLegalMaskedLoadStore(Type *DataType, Align Alignment) const {
312 if (!ST->isSVEorStreamingSVEAvailable())
313 return false;
314
315 if (isa<FixedVectorType>(Val: DataType) && !ST->useSVEForFixedLengthVectors()) {
316 unsigned Bits = DataType->getPrimitiveSizeInBits();
317 if (Bits != 64 && Bits != 128)
318 return false; // Fall back to scalarization of masked operations.
319 }
320
321 return isElementTypeLegalForScalableVector(Ty: DataType->getScalarType());
322 }
323
324 bool isLegalMaskedLoad(Type *DataType, Align Alignment,
325 unsigned /*AddressSpace*/,
326 TTI::MaskKind /*MaskKind*/) const override {
327 return isLegalMaskedLoadStore(DataType, Alignment);
328 }
329
330 bool isLegalMaskedStore(Type *DataType, Align Alignment,
331 unsigned /*AddressSpace*/,
332 TTI::MaskKind /*MaskKind*/) const override {
333 return isLegalMaskedLoadStore(DataType, Alignment);
334 }
335
336 bool isElementTypeLegalForCompressStore(Type *Ty) const {
337 assert(Ty->isIntegerTy() || Ty->isFloatingPointTy());
338 // 32-bit and 64-bit element types are legal if we have SVE.
339 if (is_contained(Set: {32u, 64u}, Element: Ty->getScalarSizeInBits()))
340 return true;
341
342 // 8-bit and 16-bit types require +sve2p2 or +sme2p2.
343 if (is_contained(Set: {8u, 16u}, Element: Ty->getScalarSizeInBits()))
344 return ST->hasSVE2p2() || ST->hasSME2p2();
345
346 return false;
347 }
348
349 bool isLegalMaskedCompressStore(Type *DataType,
350 Align Alignment) const override {
351 if (!(ST->isSVEAvailable() ||
352 (ST->isSVEorStreamingSVEAvailable() && ST->hasSME2p2())))
353 return false;
354
355 if (isa<FixedVectorType>(Val: DataType) &&
356 DataType->getPrimitiveSizeInBits() < 128)
357 return false;
358
359 return isElementTypeLegalForCompressStore(Ty: DataType->getScalarType());
360 }
361
362 bool isLegalMaskedGatherScatter(Type *DataType) const {
363 if (!ST->isSVEAvailable())
364 return false;
365
366 // For fixed vectors, scalarize if not using SVE for them.
367 auto *DataTypeFVTy = dyn_cast<FixedVectorType>(Val: DataType);
368 if (DataTypeFVTy && (!ST->useSVEForFixedLengthVectors() ||
369 DataTypeFVTy->getNumElements() < 2))
370 return false;
371
372 return isElementTypeLegalForScalableVector(Ty: DataType->getScalarType());
373 }
374
375 bool isLegalMaskedGather(Type *DataType, Align Alignment) const override {
376 return isLegalMaskedGatherScatter(DataType);
377 }
378
379 bool isLegalMaskedScatter(Type *DataType, Align Alignment) const override {
380 return isLegalMaskedGatherScatter(DataType);
381 }
382
383 bool isLegalBroadcastLoad(Type *ElementTy,
384 ElementCount NumElements) const override {
385 // Return true if we can generate a `ld1r` splat load instruction.
386 if (!ST->hasNEON() || NumElements.isScalable())
387 return false;
388 switch (unsigned ElementBits = ElementTy->getScalarSizeInBits()) {
389 case 8:
390 case 16:
391 case 32:
392 case 64: {
393 // We accept bit-widths >= 64bits and elements {8,16,32,64} bits.
394 unsigned VectorBits = NumElements.getFixedValue() * ElementBits;
395 return VectorBits >= 64;
396 }
397 }
398 return false;
399 }
400
401 std::optional<bool> isLegalNTStoreLoad(Type *DataType,
402 Align Alignment) const {
403 // Currently we only support NT load and store lowering for little-endian
404 // targets.
405 //
406 // Coordinated with LDNP and STNP constraints in
407 // `llvm/lib/Target/AArch64/AArch64InstrInfo.td` and
408 // `AArch64ISelLowering.cpp`
409 if (!ST->isLittleEndian())
410 return false;
411
412 // NOTE: The logic below is mostly geared towards LV, which calls it with
413 // vectors with 2 elements. We might want to improve that, if other
414 // users show up.
415 // Nontemporal vector loads/stores can be directly lowered to LDNP/STNP, if
416 // the vector can be halved so that each half fits into a register. That's
417 // the case if the element type fits into a register and the number of
418 // elements is a power of 2 > 1.
419 if (auto *DataTypeTy = dyn_cast<FixedVectorType>(Val: DataType)) {
420 unsigned NumElements = DataTypeTy->getNumElements();
421 unsigned EltSize = DataTypeTy->getElementType()->getScalarSizeInBits();
422 return NumElements > 1 && isPowerOf2_64(Value: NumElements) && EltSize >= 8 &&
423 EltSize <= 128 && isPowerOf2_64(Value: EltSize);
424 }
425 return std::nullopt;
426 }
427
428 bool isLegalNTStore(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::isLegalNTStore(DataType, Alignment);
433 }
434
435 bool isLegalNTLoad(Type *DataType, Align Alignment) const override {
436 if (auto Result = isLegalNTStoreLoad(DataType, Alignment))
437 return *Result;
438 // Fallback to target independent logic
439 return BaseT::isLegalNTLoad(DataType, Alignment);
440 }
441
442 InstructionCost getPartialReductionCost(
443 unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
444 ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,
445 TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,
446 TTI::TargetCostKind CostKind,
447 std::optional<FastMathFlags> FMF) const override;
448
449 bool enableOrderedReductions() const override { return true; }
450
451 InstructionCost getInterleavedMemoryOpCost(
452 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
453 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
454 bool UseMaskForCond = false, bool UseMaskForGaps = false) const override;
455
456 bool shouldConsiderAddressTypePromotion(
457 const Instruction &I,
458 bool &AllowPromotionWithoutCommonHeader) const override;
459
460 bool shouldExpandReduction(const IntrinsicInst *II) const override {
461 return false;
462 }
463
464 unsigned getGISelRematGlobalCost() const override { return 2; }
465
466 InstructionCost getBranchMispredictPenalty() const override;
467
468 unsigned getMinTripCountTailFoldingThreshold() const override {
469 return ST->hasSVE() ? 5 : 0;
470 }
471
472 TailFoldingStyle getPreferredTailFoldingStyle() const override {
473 return ST->hasSVE() ? TailFoldingStyle::DataAndControlFlow
474 : TailFoldingStyle::DataWithoutLaneMask;
475 }
476
477 bool preferFixedOverScalableIfEqualCost() const override;
478
479 unsigned getEpilogueVectorizationMinVF() const override;
480
481 bool preferTailFoldingOverEpilogue(TailFoldingInfo *TFI) const override;
482
483 bool supportsScalableVectors() const override {
484 return ST->isSVEorStreamingSVEAvailable();
485 }
486
487 bool enableScalableVectorization() const override;
488
489 bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc,
490 ElementCount VF) const override;
491
492 bool preferPredicatedReductionSelect() const override { return ST->hasSVE(); }
493
494 /// FP16 and BF16 operations are lowered to fptrunc(op(fpext, fpext) if the
495 /// architecture features are not present.
496 std::optional<InstructionCost> getFP16BF16PromoteCost(
497 Type *Ty, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info,
498 TTI::OperandValueInfo Op2Info, bool IncludeTrunc, bool CanUseSVE,
499 std::function<InstructionCost(Type *)> InstCost) const;
500
501 InstructionCost
502 getArithmeticReductionCost(unsigned Opcode, VectorType *Ty,
503 std::optional<FastMathFlags> FMF,
504 TTI::TargetCostKind CostKind) const override;
505
506 InstructionCost
507 getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy,
508 VectorType *ValTy, std::optional<FastMathFlags> FMF,
509 TTI::TargetCostKind CostKind) const override;
510
511 InstructionCost getMulAccReductionCost(
512 bool IsUnsigned, unsigned RedOpcode, Type *ResTy, VectorType *Ty,
513 TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput) const override;
514
515 InstructionCost
516 getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy,
517 TTI::TargetCostKind CostKind, ArrayRef<int> Mask, int Index,
518 VectorType *SubTp, ArrayRef<const Value *> Args = {},
519 const Instruction *CxtI = nullptr) const override;
520
521 InstructionCost
522 getScalarizationOverhead(VectorType *Ty, const APInt &DemandedElts,
523 bool Insert, bool Extract,
524 TTI::TargetCostKind CostKind,
525 bool ForPoisonSrc = true, ArrayRef<Value *> VL = {},
526 TTI::VectorInstrContext VIC =
527 TTI::VectorInstrContext::None) const override;
528
529 /// Return the cost of the scaling factor used in the addressing
530 /// mode represented by AM for this target, for a load/store
531 /// of the specified type.
532 /// If the AM is supported, the return value must be >= 0.
533 /// If the AM is not supported, it returns an invalid cost.
534 InstructionCost getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
535 StackOffset BaseOffset, bool HasBaseReg,
536 int64_t Scale,
537 unsigned AddrSpace) const override;
538
539 bool enableSelectOptimize() const override {
540 return ST->enableSelectOptimize();
541 }
542
543 bool shouldTreatInstructionLikeSelect(const Instruction *I) const override;
544
545 unsigned getStoreMinimumVF(unsigned VF, Type *ScalarMemTy, Type *ScalarValTy,
546 Align Alignment,
547 unsigned AddrSpace) const override {
548 // We can vectorize store v4i8.
549 if (ScalarMemTy->isIntegerTy(BitWidth: 8) && isPowerOf2_32(Value: VF) && VF >= 4)
550 return 4;
551
552 return BaseT::getStoreMinimumVF(VF, ScalarMemTy, ScalarValTy, Alignment,
553 AddrSpace);
554 }
555
556 std::optional<unsigned> getMinPageSize() const override { return 4096; }
557
558 bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
559 const TargetTransformInfo::LSRCost &C2) const override;
560
561 bool isProfitableToSinkOperands(Instruction *I,
562 SmallVectorImpl<Use *> &Ops) const override;
563
564 bool enableAggressiveInterleaving(bool) const override {
565 return ST->enableAggressiveInterleaving();
566 }
567 /// @}
568};
569
570} // end namespace llvm
571
572#endif // LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
573