106f32e7eSjoerg //===- AArch64TargetTransformInfo.h - AArch64 specific TTI ------*- 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 /// \file
906f32e7eSjoerg /// This file a TargetTransformInfo::Concept conforming object specific to the
1006f32e7eSjoerg /// AArch64 target machine. It uses the target's detailed information to
1106f32e7eSjoerg /// provide more precise answers to certain TTI queries, while letting the
1206f32e7eSjoerg /// target independent and default TTI implementations handle the rest.
1306f32e7eSjoerg ///
1406f32e7eSjoerg //===----------------------------------------------------------------------===//
1506f32e7eSjoerg 
1606f32e7eSjoerg #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
1706f32e7eSjoerg #define LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
1806f32e7eSjoerg 
1906f32e7eSjoerg #include "AArch64.h"
2006f32e7eSjoerg #include "AArch64Subtarget.h"
2106f32e7eSjoerg #include "AArch64TargetMachine.h"
2206f32e7eSjoerg #include "llvm/ADT/ArrayRef.h"
2306f32e7eSjoerg #include "llvm/Analysis/TargetTransformInfo.h"
2406f32e7eSjoerg #include "llvm/CodeGen/BasicTTIImpl.h"
2506f32e7eSjoerg #include "llvm/IR/Function.h"
2606f32e7eSjoerg #include "llvm/IR/Intrinsics.h"
2706f32e7eSjoerg #include <cstdint>
2806f32e7eSjoerg 
2906f32e7eSjoerg namespace llvm {
3006f32e7eSjoerg 
3106f32e7eSjoerg class APInt;
3206f32e7eSjoerg class Instruction;
3306f32e7eSjoerg class IntrinsicInst;
3406f32e7eSjoerg class Loop;
3506f32e7eSjoerg class SCEV;
3606f32e7eSjoerg class ScalarEvolution;
3706f32e7eSjoerg class Type;
3806f32e7eSjoerg class Value;
3906f32e7eSjoerg class VectorType;
4006f32e7eSjoerg 
4106f32e7eSjoerg class AArch64TTIImpl : public BasicTTIImplBase<AArch64TTIImpl> {
4206f32e7eSjoerg   using BaseT = BasicTTIImplBase<AArch64TTIImpl>;
4306f32e7eSjoerg   using TTI = TargetTransformInfo;
4406f32e7eSjoerg 
4506f32e7eSjoerg   friend BaseT;
4606f32e7eSjoerg 
4706f32e7eSjoerg   const AArch64Subtarget *ST;
4806f32e7eSjoerg   const AArch64TargetLowering *TLI;
4906f32e7eSjoerg 
getST()5006f32e7eSjoerg   const AArch64Subtarget *getST() const { return ST; }
getTLI()5106f32e7eSjoerg   const AArch64TargetLowering *getTLI() const { return TLI; }
5206f32e7eSjoerg 
5306f32e7eSjoerg   enum MemIntrinsicType {
5406f32e7eSjoerg     VECTOR_LDST_TWO_ELEMENTS,
5506f32e7eSjoerg     VECTOR_LDST_THREE_ELEMENTS,
5606f32e7eSjoerg     VECTOR_LDST_FOUR_ELEMENTS
5706f32e7eSjoerg   };
5806f32e7eSjoerg 
5906f32e7eSjoerg   bool isWideningInstruction(Type *Ty, unsigned Opcode,
6006f32e7eSjoerg                              ArrayRef<const Value *> Args);
6106f32e7eSjoerg 
6206f32e7eSjoerg public:
AArch64TTIImpl(const AArch64TargetMachine * TM,const Function & F)6306f32e7eSjoerg   explicit AArch64TTIImpl(const AArch64TargetMachine *TM, const Function &F)
6406f32e7eSjoerg       : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
6506f32e7eSjoerg         TLI(ST->getTargetLowering()) {}
6606f32e7eSjoerg 
6706f32e7eSjoerg   bool areInlineCompatible(const Function *Caller,
6806f32e7eSjoerg                            const Function *Callee) const;
6906f32e7eSjoerg 
7006f32e7eSjoerg   /// \name Scalar TTI Implementations
7106f32e7eSjoerg   /// @{
7206f32e7eSjoerg 
7306f32e7eSjoerg   using BaseT::getIntImmCost;
74*da58b97aSjoerg   InstructionCost getIntImmCost(int64_t Val);
75*da58b97aSjoerg   InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
76*da58b97aSjoerg                                 TTI::TargetCostKind CostKind);
77*da58b97aSjoerg   InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
78*da58b97aSjoerg                                     const APInt &Imm, Type *Ty,
79*da58b97aSjoerg                                     TTI::TargetCostKind CostKind,
80*da58b97aSjoerg                                     Instruction *Inst = nullptr);
81*da58b97aSjoerg   InstructionCost getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
82*da58b97aSjoerg                                       const APInt &Imm, Type *Ty,
83*da58b97aSjoerg                                       TTI::TargetCostKind CostKind);
8406f32e7eSjoerg   TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth);
8506f32e7eSjoerg 
8606f32e7eSjoerg   /// @}
8706f32e7eSjoerg 
8806f32e7eSjoerg   /// \name Vector TTI Implementations
8906f32e7eSjoerg   /// @{
9006f32e7eSjoerg 
enableInterleavedAccessVectorization()9106f32e7eSjoerg   bool enableInterleavedAccessVectorization() { return true; }
9206f32e7eSjoerg 
getNumberOfRegisters(unsigned ClassID)9306f32e7eSjoerg   unsigned getNumberOfRegisters(unsigned ClassID) const {
9406f32e7eSjoerg     bool Vector = (ClassID == 1);
9506f32e7eSjoerg     if (Vector) {
9606f32e7eSjoerg       if (ST->hasNEON())
9706f32e7eSjoerg         return 32;
9806f32e7eSjoerg       return 0;
9906f32e7eSjoerg     }
10006f32e7eSjoerg     return 31;
10106f32e7eSjoerg   }
10206f32e7eSjoerg 
103*da58b97aSjoerg   InstructionCost getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
104*da58b97aSjoerg                                         TTI::TargetCostKind CostKind);
105*da58b97aSjoerg 
106*da58b97aSjoerg   Optional<Instruction *> instCombineIntrinsic(InstCombiner &IC,
107*da58b97aSjoerg                                                IntrinsicInst &II) const;
108*da58b97aSjoerg 
getRegisterBitWidth(TargetTransformInfo::RegisterKind K)109*da58b97aSjoerg   TypeSize getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const {
110*da58b97aSjoerg     switch (K) {
111*da58b97aSjoerg     case TargetTransformInfo::RGK_Scalar:
112*da58b97aSjoerg       return TypeSize::getFixed(64);
113*da58b97aSjoerg     case TargetTransformInfo::RGK_FixedWidthVector:
114*da58b97aSjoerg       if (ST->hasSVE())
115*da58b97aSjoerg         return TypeSize::getFixed(
116*da58b97aSjoerg             std::max(ST->getMinSVEVectorSizeInBits(), 128u));
117*da58b97aSjoerg       return TypeSize::getFixed(ST->hasNEON() ? 128 : 0);
118*da58b97aSjoerg     case TargetTransformInfo::RGK_ScalableVector:
119*da58b97aSjoerg       return TypeSize::getScalable(ST->hasSVE() ? 128 : 0);
12006f32e7eSjoerg     }
121*da58b97aSjoerg     llvm_unreachable("Unsupported register kind");
12206f32e7eSjoerg   }
12306f32e7eSjoerg 
getMinVectorRegisterBitWidth()12406f32e7eSjoerg   unsigned getMinVectorRegisterBitWidth() {
12506f32e7eSjoerg     return ST->getMinVectorRegisterBitWidth();
12606f32e7eSjoerg   }
12706f32e7eSjoerg 
getMaxVScale()128*da58b97aSjoerg   Optional<unsigned> getMaxVScale() const {
129*da58b97aSjoerg     if (ST->hasSVE())
130*da58b97aSjoerg       return AArch64::SVEMaxBitsPerVector / AArch64::SVEBitsPerBlock;
131*da58b97aSjoerg     return BaseT::getMaxVScale();
132*da58b97aSjoerg   }
133*da58b97aSjoerg 
13406f32e7eSjoerg   unsigned getMaxInterleaveFactor(unsigned VF);
13506f32e7eSjoerg 
136*da58b97aSjoerg   InstructionCost getMaskedMemoryOpCost(unsigned Opcode, Type *Src,
137*da58b97aSjoerg                                         Align Alignment, unsigned AddressSpace,
138*da58b97aSjoerg                                         TTI::TargetCostKind CostKind);
139*da58b97aSjoerg 
140*da58b97aSjoerg   InstructionCost getGatherScatterOpCost(unsigned Opcode, Type *DataTy,
141*da58b97aSjoerg                                          const Value *Ptr, bool VariableMask,
142*da58b97aSjoerg                                          Align Alignment,
143*da58b97aSjoerg                                          TTI::TargetCostKind CostKind,
14406f32e7eSjoerg                                          const Instruction *I = nullptr);
14506f32e7eSjoerg 
146*da58b97aSjoerg   InstructionCost getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
147*da58b97aSjoerg                                    TTI::CastContextHint CCH,
148*da58b97aSjoerg                                    TTI::TargetCostKind CostKind,
149*da58b97aSjoerg                                    const Instruction *I = nullptr);
150*da58b97aSjoerg 
151*da58b97aSjoerg   InstructionCost getExtractWithExtendCost(unsigned Opcode, Type *Dst,
152*da58b97aSjoerg                                            VectorType *VecTy, unsigned Index);
153*da58b97aSjoerg 
154*da58b97aSjoerg   InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
155*da58b97aSjoerg                                  const Instruction *I = nullptr);
156*da58b97aSjoerg 
157*da58b97aSjoerg   InstructionCost getVectorInstrCost(unsigned Opcode, Type *Val,
15806f32e7eSjoerg                                      unsigned Index);
15906f32e7eSjoerg 
160*da58b97aSjoerg   InstructionCost getMinMaxReductionCost(VectorType *Ty, VectorType *CondTy,
161*da58b97aSjoerg                                          bool IsPairwise, bool IsUnsigned,
162*da58b97aSjoerg                                          TTI::TargetCostKind CostKind);
16306f32e7eSjoerg 
164*da58b97aSjoerg   InstructionCost getArithmeticReductionCostSVE(unsigned Opcode,
165*da58b97aSjoerg                                                 VectorType *ValTy,
166*da58b97aSjoerg                                                 bool IsPairwiseForm,
167*da58b97aSjoerg                                                 TTI::TargetCostKind CostKind);
168*da58b97aSjoerg 
169*da58b97aSjoerg   InstructionCost getArithmeticInstrCost(
17006f32e7eSjoerg       unsigned Opcode, Type *Ty,
171*da58b97aSjoerg       TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput,
17206f32e7eSjoerg       TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
17306f32e7eSjoerg       TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
17406f32e7eSjoerg       TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
17506f32e7eSjoerg       TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
176*da58b97aSjoerg       ArrayRef<const Value *> Args = ArrayRef<const Value *>(),
177*da58b97aSjoerg       const Instruction *CxtI = nullptr);
17806f32e7eSjoerg 
179*da58b97aSjoerg   InstructionCost getAddressComputationCost(Type *Ty, ScalarEvolution *SE,
180*da58b97aSjoerg                                             const SCEV *Ptr);
18106f32e7eSjoerg 
182*da58b97aSjoerg   InstructionCost getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy,
183*da58b97aSjoerg                                      CmpInst::Predicate VecPred,
184*da58b97aSjoerg                                      TTI::TargetCostKind CostKind,
18506f32e7eSjoerg                                      const Instruction *I = nullptr);
18606f32e7eSjoerg 
18706f32e7eSjoerg   TTI::MemCmpExpansionOptions enableMemCmpExpansion(bool OptSize,
18806f32e7eSjoerg                                                     bool IsZeroCmp) const;
189*da58b97aSjoerg   bool useNeonVector(const Type *Ty) const;
19006f32e7eSjoerg 
191*da58b97aSjoerg   InstructionCost getMemoryOpCost(unsigned Opcode, Type *Src,
192*da58b97aSjoerg                                   MaybeAlign Alignment, unsigned AddressSpace,
193*da58b97aSjoerg                                   TTI::TargetCostKind CostKind,
194*da58b97aSjoerg                                   const Instruction *I = nullptr);
19506f32e7eSjoerg 
196*da58b97aSjoerg   InstructionCost getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys);
19706f32e7eSjoerg 
19806f32e7eSjoerg   void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
19906f32e7eSjoerg                                TTI::UnrollingPreferences &UP);
20006f32e7eSjoerg 
201*da58b97aSjoerg   void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
202*da58b97aSjoerg                              TTI::PeelingPreferences &PP);
203*da58b97aSjoerg 
20406f32e7eSjoerg   Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
20506f32e7eSjoerg                                            Type *ExpectedType);
20606f32e7eSjoerg 
20706f32e7eSjoerg   bool getTgtMemIntrinsic(IntrinsicInst *Inst, MemIntrinsicInfo &Info);
20806f32e7eSjoerg 
isLegalElementTypeForSVE(Type * Ty)209*da58b97aSjoerg   bool isLegalElementTypeForSVE(Type *Ty) const {
210*da58b97aSjoerg     if (Ty->isPointerTy())
211*da58b97aSjoerg       return true;
21206f32e7eSjoerg 
213*da58b97aSjoerg     if (Ty->isBFloatTy() && ST->hasBF16())
214*da58b97aSjoerg       return true;
215*da58b97aSjoerg 
21606f32e7eSjoerg     if (Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy())
21706f32e7eSjoerg       return true;
21806f32e7eSjoerg 
21906f32e7eSjoerg     if (Ty->isIntegerTy(8) || Ty->isIntegerTy(16) ||
22006f32e7eSjoerg         Ty->isIntegerTy(32) || Ty->isIntegerTy(64))
22106f32e7eSjoerg       return true;
22206f32e7eSjoerg 
22306f32e7eSjoerg     return false;
22406f32e7eSjoerg   }
22506f32e7eSjoerg 
isLegalMaskedLoadStore(Type * DataType,Align Alignment)226*da58b97aSjoerg   bool isLegalMaskedLoadStore(Type *DataType, Align Alignment) {
227*da58b97aSjoerg     if (!ST->hasSVE())
228*da58b97aSjoerg       return false;
229*da58b97aSjoerg 
230*da58b97aSjoerg     // For fixed vectors, avoid scalarization if using SVE for them.
231*da58b97aSjoerg     if (isa<FixedVectorType>(DataType) && !ST->useSVEForFixedLengthVectors())
232*da58b97aSjoerg       return false; // Fall back to scalarization of masked operations.
233*da58b97aSjoerg 
234*da58b97aSjoerg     return isLegalElementTypeForSVE(DataType->getScalarType());
235*da58b97aSjoerg   }
236*da58b97aSjoerg 
isLegalMaskedLoad(Type * DataType,Align Alignment)237*da58b97aSjoerg   bool isLegalMaskedLoad(Type *DataType, Align Alignment) {
238*da58b97aSjoerg     return isLegalMaskedLoadStore(DataType, Alignment);
239*da58b97aSjoerg   }
240*da58b97aSjoerg 
isLegalMaskedStore(Type * DataType,Align Alignment)241*da58b97aSjoerg   bool isLegalMaskedStore(Type *DataType, Align Alignment) {
242*da58b97aSjoerg     return isLegalMaskedLoadStore(DataType, Alignment);
243*da58b97aSjoerg   }
244*da58b97aSjoerg 
isLegalMaskedGatherScatter(Type * DataType)245*da58b97aSjoerg   bool isLegalMaskedGatherScatter(Type *DataType) const {
246*da58b97aSjoerg     if (isa<FixedVectorType>(DataType) || !ST->hasSVE())
247*da58b97aSjoerg       return false;
248*da58b97aSjoerg 
249*da58b97aSjoerg     return isLegalElementTypeForSVE(DataType->getScalarType());
250*da58b97aSjoerg   }
251*da58b97aSjoerg 
isLegalMaskedGather(Type * DataType,Align Alignment)252*da58b97aSjoerg   bool isLegalMaskedGather(Type *DataType, Align Alignment) const {
253*da58b97aSjoerg     return isLegalMaskedGatherScatter(DataType);
254*da58b97aSjoerg   }
isLegalMaskedScatter(Type * DataType,Align Alignment)255*da58b97aSjoerg   bool isLegalMaskedScatter(Type *DataType, Align Alignment) const {
256*da58b97aSjoerg     return isLegalMaskedGatherScatter(DataType);
257*da58b97aSjoerg   }
258*da58b97aSjoerg 
isLegalNTStore(Type * DataType,Align Alignment)259*da58b97aSjoerg   bool isLegalNTStore(Type *DataType, Align Alignment) {
260*da58b97aSjoerg     // NOTE: The logic below is mostly geared towards LV, which calls it with
261*da58b97aSjoerg     //       vectors with 2 elements. We might want to improve that, if other
262*da58b97aSjoerg     //       users show up.
263*da58b97aSjoerg     // Nontemporal vector stores can be directly lowered to STNP, if the vector
264*da58b97aSjoerg     // can be halved so that each half fits into a register. That's the case if
265*da58b97aSjoerg     // the element type fits into a register and the number of elements is a
266*da58b97aSjoerg     // power of 2 > 1.
267*da58b97aSjoerg     if (auto *DataTypeVTy = dyn_cast<VectorType>(DataType)) {
268*da58b97aSjoerg       unsigned NumElements =
269*da58b97aSjoerg           cast<FixedVectorType>(DataTypeVTy)->getNumElements();
270*da58b97aSjoerg       unsigned EltSize = DataTypeVTy->getElementType()->getScalarSizeInBits();
271*da58b97aSjoerg       return NumElements > 1 && isPowerOf2_64(NumElements) && EltSize >= 8 &&
272*da58b97aSjoerg              EltSize <= 128 && isPowerOf2_64(EltSize);
273*da58b97aSjoerg     }
274*da58b97aSjoerg     return BaseT::isLegalNTStore(DataType, Alignment);
275*da58b97aSjoerg   }
276*da58b97aSjoerg 
277*da58b97aSjoerg   InstructionCost getInterleavedMemoryOpCost(
278*da58b97aSjoerg       unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
279*da58b97aSjoerg       Align Alignment, unsigned AddressSpace,
280*da58b97aSjoerg       TTI::TargetCostKind CostKind = TTI::TCK_SizeAndLatency,
281*da58b97aSjoerg       bool UseMaskForCond = false, bool UseMaskForGaps = false);
28206f32e7eSjoerg 
28306f32e7eSjoerg   bool
28406f32e7eSjoerg   shouldConsiderAddressTypePromotion(const Instruction &I,
28506f32e7eSjoerg                                      bool &AllowPromotionWithoutCommonHeader);
28606f32e7eSjoerg 
shouldExpandReduction(const IntrinsicInst * II)287*da58b97aSjoerg   bool shouldExpandReduction(const IntrinsicInst *II) const { return false; }
28806f32e7eSjoerg 
getGISelRematGlobalCost()28906f32e7eSjoerg   unsigned getGISelRematGlobalCost() const {
29006f32e7eSjoerg     return 2;
29106f32e7eSjoerg   }
29206f32e7eSjoerg 
supportsScalableVectors()293*da58b97aSjoerg   bool supportsScalableVectors() const { return ST->hasSVE(); }
29406f32e7eSjoerg 
295*da58b97aSjoerg   bool isLegalToVectorizeReduction(RecurrenceDescriptor RdxDesc,
296*da58b97aSjoerg                                    ElementCount VF) const;
29706f32e7eSjoerg 
298*da58b97aSjoerg   InstructionCost getArithmeticReductionCost(
299*da58b97aSjoerg       unsigned Opcode, VectorType *Ty, bool IsPairwiseForm,
300*da58b97aSjoerg       TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput);
301*da58b97aSjoerg 
302*da58b97aSjoerg   InstructionCost getShuffleCost(TTI::ShuffleKind Kind, VectorType *Tp,
303*da58b97aSjoerg                                  ArrayRef<int> Mask, int Index,
304*da58b97aSjoerg                                  VectorType *SubTp);
30506f32e7eSjoerg   /// @}
30606f32e7eSjoerg };
30706f32e7eSjoerg 
30806f32e7eSjoerg } // end namespace llvm
30906f32e7eSjoerg 
31006f32e7eSjoerg #endif // LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
311