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