457 lines · cpp
1//===- HexagonTargetTransformInfo.cpp - Hexagon specific TTI pass ---------===//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-exception6//7/// \file8/// This file implements a TargetTransformInfo analysis pass specific to the9/// Hexagon target machine. It uses the target's detailed information to provide10/// more precise answers to certain TTI queries, while letting the target11/// independent and default TTI implementations handle the rest.12///13//===----------------------------------------------------------------------===//14 15#include "HexagonTargetTransformInfo.h"16#include "HexagonSubtarget.h"17#include "llvm/Analysis/TargetTransformInfo.h"18#include "llvm/CodeGen/ValueTypes.h"19#include "llvm/IR/InstrTypes.h"20#include "llvm/IR/Instructions.h"21#include "llvm/IR/User.h"22#include "llvm/Support/Casting.h"23#include "llvm/Support/CommandLine.h"24#include "llvm/Transforms/Utils/LoopPeel.h"25#include "llvm/Transforms/Utils/UnrollLoop.h"26 27using namespace llvm;28 29#define DEBUG_TYPE "hexagontti"30 31static cl::opt<bool> HexagonAutoHVX("hexagon-autohvx", cl::init(false),32 cl::Hidden, cl::desc("Enable loop vectorizer for HVX"));33 34cl::opt<bool> HexagonAllowScatterGatherHVX(35 "hexagon-allow-scatter-gather-hvx", cl::init(false), cl::Hidden,36 cl::desc("Allow auto-generation of HVX scatter-gather"));37 38static cl::opt<bool> EnableV68FloatAutoHVX(39 "force-hvx-float", cl::Hidden,40 cl::desc("Enable auto-vectorization of floatint point types on v68."));41 42static cl::opt<bool> EmitLookupTables("hexagon-emit-lookup-tables",43 cl::init(true), cl::Hidden,44 cl::desc("Control lookup table emission on Hexagon target"));45 46static cl::opt<bool> HexagonMaskedVMem("hexagon-masked-vmem", cl::init(true),47 cl::Hidden, cl::desc("Enable masked loads/stores for HVX"));48 49// Constant "cost factor" to make floating point operations more expensive50// in terms of vectorization cost. This isn't the best way, but it should51// do. Ultimately, the cost should use cycles.52static const unsigned FloatFactor = 4;53 54bool HexagonTTIImpl::useHVX() const {55 return ST.useHVXOps() && HexagonAutoHVX;56}57 58bool HexagonTTIImpl::isHVXVectorType(Type *Ty) const {59 auto *VecTy = dyn_cast<VectorType>(Ty);60 if (!VecTy)61 return false;62 if (!ST.isTypeForHVX(VecTy))63 return false;64 if (ST.useHVXV69Ops() || !VecTy->getElementType()->isFloatingPointTy())65 return true;66 return ST.useHVXV68Ops() && EnableV68FloatAutoHVX;67}68 69unsigned HexagonTTIImpl::getTypeNumElements(Type *Ty) const {70 if (auto *VTy = dyn_cast<FixedVectorType>(Ty))71 return VTy->getNumElements();72 assert((Ty->isIntegerTy() || Ty->isFloatingPointTy()) &&73 "Expecting scalar type");74 return 1;75}76 77TargetTransformInfo::PopcntSupportKind78HexagonTTIImpl::getPopcntSupport(unsigned IntTyWidthInBit) const {79 // Return fast hardware support as every input < 64 bits will be promoted80 // to 64 bits.81 return TargetTransformInfo::PSK_FastHardware;82}83 84// The Hexagon target can unroll loops with run-time trip counts.85void HexagonTTIImpl::getUnrollingPreferences(86 Loop *L, ScalarEvolution &SE, TTI::UnrollingPreferences &UP,87 OptimizationRemarkEmitter *ORE) const {88 UP.Runtime = UP.Partial = true;89}90 91void HexagonTTIImpl::getPeelingPreferences(Loop *L, ScalarEvolution &SE,92 TTI::PeelingPreferences &PP) const {93 BaseT::getPeelingPreferences(L, SE, PP);94 // Only try to peel innermost loops with small runtime trip counts.95 if (L && L->isInnermost() && canPeel(L) &&96 SE.getSmallConstantTripCount(L) == 0 &&97 SE.getSmallConstantMaxTripCount(L) > 0 &&98 SE.getSmallConstantMaxTripCount(L) <= 5) {99 PP.PeelCount = 2;100 }101}102 103TTI::AddressingModeKind104HexagonTTIImpl::getPreferredAddressingMode(const Loop *L,105 ScalarEvolution *SE) const {106 return TTI::AMK_PostIndexed;107}108 109/// --- Vector TTI begin ---110 111unsigned HexagonTTIImpl::getNumberOfRegisters(unsigned ClassID) const {112 bool Vector = ClassID == 1;113 if (Vector)114 return useHVX() ? 32 : 0;115 return 32;116}117 118unsigned HexagonTTIImpl::getMaxInterleaveFactor(ElementCount VF) const {119 return useHVX() ? 2 : 1;120}121 122TypeSize123HexagonTTIImpl::getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const {124 switch (K) {125 case TargetTransformInfo::RGK_Scalar:126 return TypeSize::getFixed(32);127 case TargetTransformInfo::RGK_FixedWidthVector:128 return TypeSize::getFixed(getMinVectorRegisterBitWidth());129 case TargetTransformInfo::RGK_ScalableVector:130 return TypeSize::getScalable(0);131 }132 133 llvm_unreachable("Unsupported register kind");134}135 136unsigned HexagonTTIImpl::getMinVectorRegisterBitWidth() const {137 return useHVX() ? ST.getVectorLength()*8 : 32;138}139 140ElementCount HexagonTTIImpl::getMinimumVF(unsigned ElemWidth,141 bool IsScalable) const {142 assert(!IsScalable && "Scalable VFs are not supported for Hexagon");143 return ElementCount::getFixed((8 * ST.getVectorLength()) / ElemWidth);144}145 146InstructionCost147HexagonTTIImpl::getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys,148 TTI::TargetCostKind CostKind) const {149 return BaseT::getCallInstrCost(F, RetTy, Tys, CostKind);150}151 152InstructionCost153HexagonTTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,154 TTI::TargetCostKind CostKind) const {155 if (ICA.getID() == Intrinsic::bswap) {156 std::pair<InstructionCost, MVT> LT =157 getTypeLegalizationCost(ICA.getReturnType());158 return LT.first + 2;159 }160 return BaseT::getIntrinsicInstrCost(ICA, CostKind);161}162 163InstructionCost164HexagonTTIImpl::getAddressComputationCost(Type *PtrTy, ScalarEvolution *SE,165 const SCEV *S,166 TTI::TargetCostKind CostKind) const {167 return 0;168}169 170InstructionCost HexagonTTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src,171 Align Alignment,172 unsigned AddressSpace,173 TTI::TargetCostKind CostKind,174 TTI::OperandValueInfo OpInfo,175 const Instruction *I) const {176 assert(Opcode == Instruction::Load || Opcode == Instruction::Store);177 // TODO: Handle other cost kinds.178 if (CostKind != TTI::TCK_RecipThroughput)179 return 1;180 181 if (Opcode == Instruction::Store)182 return BaseT::getMemoryOpCost(Opcode, Src, Alignment, AddressSpace,183 CostKind, OpInfo, I);184 185 if (Src->isVectorTy()) {186 VectorType *VecTy = cast<VectorType>(Src);187 unsigned VecWidth = VecTy->getPrimitiveSizeInBits().getFixedValue();188 if (isHVXVectorType(VecTy)) {189 unsigned RegWidth =190 getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector)191 .getFixedValue();192 assert(RegWidth && "Non-zero vector register width expected");193 // Cost of HVX loads.194 if (VecWidth % RegWidth == 0)195 return VecWidth / RegWidth;196 // Cost of constructing HVX vector from scalar loads197 const Align RegAlign(RegWidth / 8);198 if (Alignment > RegAlign)199 Alignment = RegAlign;200 unsigned AlignWidth = 8 * Alignment.value();201 unsigned NumLoads = alignTo(VecWidth, AlignWidth) / AlignWidth;202 return 3 * NumLoads;203 }204 205 // Non-HVX vectors.206 // Add extra cost for floating point types.207 unsigned Cost =208 VecTy->getElementType()->isFloatingPointTy() ? FloatFactor : 1;209 210 // At this point unspecified alignment is considered as Align(1).211 const Align BoundAlignment = std::min(Alignment, Align(8));212 unsigned AlignWidth = 8 * BoundAlignment.value();213 unsigned NumLoads = alignTo(VecWidth, AlignWidth) / AlignWidth;214 if (Alignment == Align(4) || Alignment == Align(8))215 return Cost * NumLoads;216 // Loads of less than 32 bits will need extra inserts to compose a vector.217 assert(BoundAlignment <= Align(8));218 unsigned LogA = Log2(BoundAlignment);219 return (3 - LogA) * Cost * NumLoads;220 }221 222 return BaseT::getMemoryOpCost(Opcode, Src, Alignment, AddressSpace, CostKind,223 OpInfo, I);224}225 226InstructionCost227HexagonTTIImpl::getMaskedMemoryOpCost(const MemIntrinsicCostAttributes &MICA,228 TTI::TargetCostKind CostKind) const {229 return BaseT::getMaskedMemoryOpCost(MICA, CostKind);230}231 232InstructionCost233HexagonTTIImpl::getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy,234 VectorType *SrcTy, ArrayRef<int> Mask,235 TTI::TargetCostKind CostKind, int Index,236 VectorType *SubTp, ArrayRef<const Value *> Args,237 const Instruction *CxtI) const {238 return 1;239}240 241InstructionCost HexagonTTIImpl::getGatherScatterOpCost(242 unsigned Opcode, Type *DataTy, const Value *Ptr, bool VariableMask,243 Align Alignment, TTI::TargetCostKind CostKind, const Instruction *I) const {244 return BaseT::getGatherScatterOpCost(Opcode, DataTy, Ptr, VariableMask,245 Alignment, CostKind, I);246}247 248InstructionCost HexagonTTIImpl::getInterleavedMemoryOpCost(249 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,250 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,251 bool UseMaskForCond, bool UseMaskForGaps) const {252 if (Indices.size() != Factor || UseMaskForCond || UseMaskForGaps)253 return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices,254 Alignment, AddressSpace,255 CostKind,256 UseMaskForCond, UseMaskForGaps);257 return getMemoryOpCost(Opcode, VecTy, Alignment, AddressSpace, CostKind);258}259 260InstructionCost HexagonTTIImpl::getCmpSelInstrCost(261 unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,262 TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info,263 TTI::OperandValueInfo Op2Info, const Instruction *I) const {264 if (ValTy->isVectorTy() && CostKind == TTI::TCK_RecipThroughput) {265 if (!isHVXVectorType(ValTy) && ValTy->isFPOrFPVectorTy())266 return InstructionCost::getMax();267 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(ValTy);268 if (Opcode == Instruction::FCmp)269 return LT.first + FloatFactor * getTypeNumElements(ValTy);270 }271 return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy, VecPred, CostKind,272 Op1Info, Op2Info, I);273}274 275InstructionCost HexagonTTIImpl::getArithmeticInstrCost(276 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,277 TTI::OperandValueInfo Op1Info, TTI::OperandValueInfo Op2Info,278 ArrayRef<const Value *> Args, const Instruction *CxtI) const {279 // TODO: Handle more cost kinds.280 if (CostKind != TTI::TCK_RecipThroughput)281 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info,282 Op2Info, Args, CxtI);283 284 if (Ty->isVectorTy()) {285 if (!isHVXVectorType(Ty) && Ty->isFPOrFPVectorTy())286 return InstructionCost::getMax();287 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Ty);288 if (LT.second.isFloatingPoint())289 return LT.first + FloatFactor * getTypeNumElements(Ty);290 }291 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info, Op2Info,292 Args, CxtI);293}294 295InstructionCost HexagonTTIImpl::getCastInstrCost(unsigned Opcode, Type *DstTy,296 Type *SrcTy,297 TTI::CastContextHint CCH,298 TTI::TargetCostKind CostKind,299 const Instruction *I) const {300 auto isNonHVXFP = [this] (Type *Ty) {301 return Ty->isVectorTy() && !isHVXVectorType(Ty) && Ty->isFPOrFPVectorTy();302 };303 if (isNonHVXFP(SrcTy) || isNonHVXFP(DstTy))304 return InstructionCost::getMax();305 306 if (SrcTy->isFPOrFPVectorTy() || DstTy->isFPOrFPVectorTy()) {307 unsigned SrcN = SrcTy->isFPOrFPVectorTy() ? getTypeNumElements(SrcTy) : 0;308 unsigned DstN = DstTy->isFPOrFPVectorTy() ? getTypeNumElements(DstTy) : 0;309 310 std::pair<InstructionCost, MVT> SrcLT = getTypeLegalizationCost(SrcTy);311 std::pair<InstructionCost, MVT> DstLT = getTypeLegalizationCost(DstTy);312 InstructionCost Cost =313 std::max(SrcLT.first, DstLT.first) + FloatFactor * (SrcN + DstN);314 // TODO: Allow non-throughput costs that aren't binary.315 if (CostKind != TTI::TCK_RecipThroughput)316 return Cost == 0 ? 0 : 1;317 return Cost;318 }319 return 1;320}321 322InstructionCost HexagonTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val,323 TTI::TargetCostKind CostKind,324 unsigned Index,325 const Value *Op0,326 const Value *Op1) const {327 Type *ElemTy = Val->isVectorTy() ? cast<VectorType>(Val)->getElementType()328 : Val;329 if (Opcode == Instruction::InsertElement) {330 // Need two rotations for non-zero index.331 unsigned Cost = (Index != 0) ? 2 : 0;332 if (ElemTy->isIntegerTy(32))333 return Cost;334 // If it's not a 32-bit value, there will need to be an extract.335 return Cost + getVectorInstrCost(Instruction::ExtractElement, Val, CostKind,336 Index, Op0, Op1);337 }338 339 if (Opcode == Instruction::ExtractElement)340 return 2;341 342 return 1;343}344 345bool HexagonTTIImpl::isLegalMaskedStore(Type *DataType, Align /*Alignment*/,346 unsigned /*AddressSpace*/,347 TTI::MaskKind /*MaskKind*/) const {348 // This function is called from scalarize-masked-mem-intrin, which runs349 // in pre-isel. Use ST directly instead of calling isHVXVectorType.350 return HexagonMaskedVMem && ST.isTypeForHVX(DataType);351}352 353bool HexagonTTIImpl::isLegalMaskedLoad(Type *DataType, Align /*Alignment*/,354 unsigned /*AddressSpace*/,355 TTI::MaskKind /*MaskKind*/) const {356 // This function is called from scalarize-masked-mem-intrin, which runs357 // in pre-isel. Use ST directly instead of calling isHVXVectorType.358 return HexagonMaskedVMem && ST.isTypeForHVX(DataType);359}360 361bool HexagonTTIImpl::isLegalMaskedGather(Type *Ty, Align Alignment) const {362 // For now assume we can not deal with all HVX datatypes.363 if (!Ty->isVectorTy() || !ST.isTypeForHVX(Ty) ||364 !HexagonAllowScatterGatherHVX)365 return false;366 // This must be in sync with HexagonVectorCombine pass.367 switch (Ty->getScalarSizeInBits()) {368 case 8:369 return (getTypeNumElements(Ty) == 128);370 case 16:371 if (getTypeNumElements(Ty) == 64 || getTypeNumElements(Ty) == 32)372 return (Alignment >= 2);373 break;374 case 32:375 if (getTypeNumElements(Ty) == 32)376 return (Alignment >= 4);377 break;378 default:379 break;380 }381 return false;382}383 384bool HexagonTTIImpl::isLegalMaskedScatter(Type *Ty, Align Alignment) const {385 if (!Ty->isVectorTy() || !ST.isTypeForHVX(Ty) ||386 !HexagonAllowScatterGatherHVX)387 return false;388 // This must be in sync with HexagonVectorCombine pass.389 switch (Ty->getScalarSizeInBits()) {390 case 8:391 return (getTypeNumElements(Ty) == 128);392 case 16:393 if (getTypeNumElements(Ty) == 64)394 return (Alignment >= 2);395 break;396 case 32:397 if (getTypeNumElements(Ty) == 32)398 return (Alignment >= 4);399 break;400 default:401 break;402 }403 return false;404}405 406bool HexagonTTIImpl::forceScalarizeMaskedGather(VectorType *VTy,407 Align Alignment) const {408 return !isLegalMaskedGather(VTy, Alignment);409}410 411bool HexagonTTIImpl::forceScalarizeMaskedScatter(VectorType *VTy,412 Align Alignment) const {413 return !isLegalMaskedScatter(VTy, Alignment);414}415 416/// --- Vector TTI end ---417 418unsigned HexagonTTIImpl::getPrefetchDistance() const {419 return ST.getL1PrefetchDistance();420}421 422unsigned HexagonTTIImpl::getCacheLineSize() const {423 return ST.getL1CacheLineSize();424}425 426InstructionCost427HexagonTTIImpl::getInstructionCost(const User *U,428 ArrayRef<const Value *> Operands,429 TTI::TargetCostKind CostKind) const {430 auto isCastFoldedIntoLoad = [this](const CastInst *CI) -> bool {431 if (!CI->isIntegerCast())432 return false;433 // Only extensions from an integer type shorter than 32-bit to i32434 // can be folded into the load.435 const DataLayout &DL = getDataLayout();436 unsigned SBW = DL.getTypeSizeInBits(CI->getSrcTy());437 unsigned DBW = DL.getTypeSizeInBits(CI->getDestTy());438 if (DBW != 32 || SBW >= DBW)439 return false;440 441 const LoadInst *LI = dyn_cast<const LoadInst>(CI->getOperand(0));442 // Technically, this code could allow multiple uses of the load, and443 // check if all the uses are the same extension operation, but this444 // should be sufficient for most cases.445 return LI && LI->hasOneUse();446 };447 448 if (const CastInst *CI = dyn_cast<const CastInst>(U))449 if (isCastFoldedIntoLoad(CI))450 return TargetTransformInfo::TCC_Free;451 return BaseT::getInstructionCost(U, Operands, CostKind);452}453 454bool HexagonTTIImpl::shouldBuildLookupTables() const {455 return EmitLookupTables;456}457