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