11db4dbbaSSimon Moll //===----- CodeGen/ExpandVectorPredication.cpp - Expand VP intrinsics -----===// 21db4dbbaSSimon Moll // 31db4dbbaSSimon Moll // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 41db4dbbaSSimon Moll // See https://llvm.org/LICENSE.txt for license information. 51db4dbbaSSimon Moll // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61db4dbbaSSimon Moll // 71db4dbbaSSimon Moll //===----------------------------------------------------------------------===// 81db4dbbaSSimon Moll // 91db4dbbaSSimon Moll // This pass implements IR expansion for vector predication intrinsics, allowing 101db4dbbaSSimon Moll // targets to enable vector predication until just before codegen. 111db4dbbaSSimon Moll // 121db4dbbaSSimon Moll //===----------------------------------------------------------------------===// 131db4dbbaSSimon Moll 141db4dbbaSSimon Moll #include "llvm/CodeGen/ExpandVectorPredication.h" 151db4dbbaSSimon Moll #include "llvm/ADT/Statistic.h" 161db4dbbaSSimon Moll #include "llvm/Analysis/TargetTransformInfo.h" 171db4dbbaSSimon Moll #include "llvm/Analysis/ValueTracking.h" 181db4dbbaSSimon Moll #include "llvm/CodeGen/Passes.h" 191db4dbbaSSimon Moll #include "llvm/IR/Constants.h" 201db4dbbaSSimon Moll #include "llvm/IR/Function.h" 211db4dbbaSSimon Moll #include "llvm/IR/IRBuilder.h" 221db4dbbaSSimon Moll #include "llvm/IR/InstIterator.h" 231db4dbbaSSimon Moll #include "llvm/IR/Instructions.h" 241db4dbbaSSimon Moll #include "llvm/IR/IntrinsicInst.h" 251db4dbbaSSimon Moll #include "llvm/IR/Intrinsics.h" 261db4dbbaSSimon Moll #include "llvm/IR/Module.h" 271db4dbbaSSimon Moll #include "llvm/InitializePasses.h" 281db4dbbaSSimon Moll #include "llvm/Pass.h" 291db4dbbaSSimon Moll #include "llvm/Support/CommandLine.h" 301db4dbbaSSimon Moll #include "llvm/Support/Compiler.h" 311db4dbbaSSimon Moll #include "llvm/Support/Debug.h" 321db4dbbaSSimon Moll #include "llvm/Support/MathExtras.h" 331db4dbbaSSimon Moll 341db4dbbaSSimon Moll using namespace llvm; 351db4dbbaSSimon Moll 361db4dbbaSSimon Moll using VPLegalization = TargetTransformInfo::VPLegalization; 371db4dbbaSSimon Moll using VPTransform = TargetTransformInfo::VPLegalization::VPTransform; 381db4dbbaSSimon Moll 391db4dbbaSSimon Moll // Keep this in sync with TargetTransformInfo::VPLegalization. 401db4dbbaSSimon Moll #define VPINTERNAL_VPLEGAL_CASES \ 411db4dbbaSSimon Moll VPINTERNAL_CASE(Legal) \ 421db4dbbaSSimon Moll VPINTERNAL_CASE(Discard) \ 431db4dbbaSSimon Moll VPINTERNAL_CASE(Convert) 441db4dbbaSSimon Moll 451db4dbbaSSimon Moll #define VPINTERNAL_CASE(X) "|" #X 461db4dbbaSSimon Moll 471db4dbbaSSimon Moll // Override options. 481db4dbbaSSimon Moll static cl::opt<std::string> EVLTransformOverride( 491db4dbbaSSimon Moll "expandvp-override-evl-transform", cl::init(""), cl::Hidden, 501db4dbbaSSimon Moll cl::desc("Options: <empty>" VPINTERNAL_VPLEGAL_CASES 511db4dbbaSSimon Moll ". If non-empty, ignore " 521db4dbbaSSimon Moll "TargetTransformInfo and " 531db4dbbaSSimon Moll "always use this transformation for the %evl parameter (Used in " 541db4dbbaSSimon Moll "testing).")); 551db4dbbaSSimon Moll 561db4dbbaSSimon Moll static cl::opt<std::string> MaskTransformOverride( 571db4dbbaSSimon Moll "expandvp-override-mask-transform", cl::init(""), cl::Hidden, 581db4dbbaSSimon Moll cl::desc("Options: <empty>" VPINTERNAL_VPLEGAL_CASES 591db4dbbaSSimon Moll ". If non-empty, Ignore " 601db4dbbaSSimon Moll "TargetTransformInfo and " 611db4dbbaSSimon Moll "always use this transformation for the %mask parameter (Used in " 621db4dbbaSSimon Moll "testing).")); 631db4dbbaSSimon Moll 641db4dbbaSSimon Moll #undef VPINTERNAL_CASE 651db4dbbaSSimon Moll #define VPINTERNAL_CASE(X) .Case(#X, VPLegalization::X) 661db4dbbaSSimon Moll 671db4dbbaSSimon Moll static VPTransform parseOverrideOption(const std::string &TextOpt) { 681db4dbbaSSimon Moll return StringSwitch<VPTransform>(TextOpt) VPINTERNAL_VPLEGAL_CASES; 691db4dbbaSSimon Moll } 701db4dbbaSSimon Moll 711db4dbbaSSimon Moll #undef VPINTERNAL_VPLEGAL_CASES 721db4dbbaSSimon Moll 731db4dbbaSSimon Moll // Whether any override options are set. 741db4dbbaSSimon Moll static bool anyExpandVPOverridesSet() { 751db4dbbaSSimon Moll return !EVLTransformOverride.empty() || !MaskTransformOverride.empty(); 761db4dbbaSSimon Moll } 771db4dbbaSSimon Moll 781db4dbbaSSimon Moll #define DEBUG_TYPE "expandvp" 791db4dbbaSSimon Moll 801db4dbbaSSimon Moll STATISTIC(NumFoldedVL, "Number of folded vector length params"); 811db4dbbaSSimon Moll STATISTIC(NumLoweredVPOps, "Number of folded vector predication operations"); 821db4dbbaSSimon Moll 831db4dbbaSSimon Moll ///// Helpers { 841db4dbbaSSimon Moll 851db4dbbaSSimon Moll /// \returns Whether the vector mask \p MaskVal has all lane bits set. 861db4dbbaSSimon Moll static bool isAllTrueMask(Value *MaskVal) { 871db4dbbaSSimon Moll auto *ConstVec = dyn_cast<ConstantVector>(MaskVal); 881db4dbbaSSimon Moll return ConstVec && ConstVec->isAllOnesValue(); 891db4dbbaSSimon Moll } 901db4dbbaSSimon Moll 911db4dbbaSSimon Moll /// \returns A non-excepting divisor constant for this type. 921db4dbbaSSimon Moll static Constant *getSafeDivisor(Type *DivTy) { 931db4dbbaSSimon Moll assert(DivTy->isIntOrIntVectorTy() && "Unsupported divisor type"); 941db4dbbaSSimon Moll return ConstantInt::get(DivTy, 1u, false); 951db4dbbaSSimon Moll } 961db4dbbaSSimon Moll 971db4dbbaSSimon Moll /// Transfer operation properties from \p OldVPI to \p NewVal. 981db4dbbaSSimon Moll static void transferDecorations(Value &NewVal, VPIntrinsic &VPI) { 991db4dbbaSSimon Moll auto *NewInst = dyn_cast<Instruction>(&NewVal); 1001db4dbbaSSimon Moll if (!NewInst || !isa<FPMathOperator>(NewVal)) 1011db4dbbaSSimon Moll return; 1021db4dbbaSSimon Moll 1031db4dbbaSSimon Moll auto *OldFMOp = dyn_cast<FPMathOperator>(&VPI); 1041db4dbbaSSimon Moll if (!OldFMOp) 1051db4dbbaSSimon Moll return; 1061db4dbbaSSimon Moll 1071db4dbbaSSimon Moll NewInst->setFastMathFlags(OldFMOp->getFastMathFlags()); 1081db4dbbaSSimon Moll } 1091db4dbbaSSimon Moll 1101db4dbbaSSimon Moll /// Transfer all properties from \p OldOp to \p NewOp and replace all uses. 1111db4dbbaSSimon Moll /// OldVP gets erased. 1121db4dbbaSSimon Moll static void replaceOperation(Value &NewOp, VPIntrinsic &OldOp) { 1131db4dbbaSSimon Moll transferDecorations(NewOp, OldOp); 1141db4dbbaSSimon Moll OldOp.replaceAllUsesWith(&NewOp); 1151db4dbbaSSimon Moll OldOp.eraseFromParent(); 1161db4dbbaSSimon Moll } 1171db4dbbaSSimon Moll 1181db4dbbaSSimon Moll //// } Helpers 1191db4dbbaSSimon Moll 1201db4dbbaSSimon Moll namespace { 1211db4dbbaSSimon Moll 1221db4dbbaSSimon Moll // Expansion pass state at function scope. 1231db4dbbaSSimon Moll struct CachingVPExpander { 1241db4dbbaSSimon Moll Function &F; 1251db4dbbaSSimon Moll const TargetTransformInfo &TTI; 1261db4dbbaSSimon Moll 1271db4dbbaSSimon Moll /// \returns A (fixed length) vector with ascending integer indices 1281db4dbbaSSimon Moll /// (<0, 1, ..., NumElems-1>). 1291db4dbbaSSimon Moll /// \p Builder 1301db4dbbaSSimon Moll /// Used for instruction creation. 1311db4dbbaSSimon Moll /// \p LaneTy 1321db4dbbaSSimon Moll /// Integer element type of the result vector. 1331db4dbbaSSimon Moll /// \p NumElems 1341db4dbbaSSimon Moll /// Number of vector elements. 1351db4dbbaSSimon Moll Value *createStepVector(IRBuilder<> &Builder, Type *LaneTy, 1361db4dbbaSSimon Moll unsigned NumElems); 1371db4dbbaSSimon Moll 1381db4dbbaSSimon Moll /// \returns A bitmask that is true where the lane position is less-than \p 1391db4dbbaSSimon Moll /// EVLParam 1401db4dbbaSSimon Moll /// 1411db4dbbaSSimon Moll /// \p Builder 1421db4dbbaSSimon Moll /// Used for instruction creation. 1431db4dbbaSSimon Moll /// \p VLParam 1441db4dbbaSSimon Moll /// The explicit vector length parameter to test against the lane 1451db4dbbaSSimon Moll /// positions. 1461db4dbbaSSimon Moll /// \p ElemCount 1471db4dbbaSSimon Moll /// Static (potentially scalable) number of vector elements. 1481db4dbbaSSimon Moll Value *convertEVLToMask(IRBuilder<> &Builder, Value *EVLParam, 1491db4dbbaSSimon Moll ElementCount ElemCount); 1501db4dbbaSSimon Moll 1511db4dbbaSSimon Moll Value *foldEVLIntoMask(VPIntrinsic &VPI); 1521db4dbbaSSimon Moll 1531db4dbbaSSimon Moll /// "Remove" the %evl parameter of \p PI by setting it to the static vector 1541db4dbbaSSimon Moll /// length of the operation. 1551db4dbbaSSimon Moll void discardEVLParameter(VPIntrinsic &PI); 1561db4dbbaSSimon Moll 1571db4dbbaSSimon Moll /// \brief Lower this VP binary operator to a unpredicated binary operator. 1581db4dbbaSSimon Moll Value *expandPredicationInBinaryOperator(IRBuilder<> &Builder, 1591db4dbbaSSimon Moll VPIntrinsic &PI); 1601db4dbbaSSimon Moll 1611db4dbbaSSimon Moll /// \brief Query TTI and expand the vector predication in \p P accordingly. 1621db4dbbaSSimon Moll Value *expandPredication(VPIntrinsic &PI); 1631db4dbbaSSimon Moll 1641db4dbbaSSimon Moll /// \brief Determine how and whether the VPIntrinsic \p VPI shall be 1651db4dbbaSSimon Moll /// expanded. This overrides TTI with the cl::opts listed at the top of this 1661db4dbbaSSimon Moll /// file. 1671db4dbbaSSimon Moll VPLegalization getVPLegalizationStrategy(const VPIntrinsic &VPI) const; 1681db4dbbaSSimon Moll bool UsingTTIOverrides; 1691db4dbbaSSimon Moll 1701db4dbbaSSimon Moll public: 1711db4dbbaSSimon Moll CachingVPExpander(Function &F, const TargetTransformInfo &TTI) 1721db4dbbaSSimon Moll : F(F), TTI(TTI), UsingTTIOverrides(anyExpandVPOverridesSet()) {} 1731db4dbbaSSimon Moll 1741db4dbbaSSimon Moll bool expandVectorPredication(); 1751db4dbbaSSimon Moll }; 1761db4dbbaSSimon Moll 1771db4dbbaSSimon Moll //// CachingVPExpander { 1781db4dbbaSSimon Moll 1791db4dbbaSSimon Moll Value *CachingVPExpander::createStepVector(IRBuilder<> &Builder, Type *LaneTy, 1801db4dbbaSSimon Moll unsigned NumElems) { 1811db4dbbaSSimon Moll // TODO add caching 1821db4dbbaSSimon Moll SmallVector<Constant *, 16> ConstElems; 1831db4dbbaSSimon Moll 1841db4dbbaSSimon Moll for (unsigned Idx = 0; Idx < NumElems; ++Idx) 1851db4dbbaSSimon Moll ConstElems.push_back(ConstantInt::get(LaneTy, Idx, false)); 1861db4dbbaSSimon Moll 1871db4dbbaSSimon Moll return ConstantVector::get(ConstElems); 1881db4dbbaSSimon Moll } 1891db4dbbaSSimon Moll 1901db4dbbaSSimon Moll Value *CachingVPExpander::convertEVLToMask(IRBuilder<> &Builder, 1911db4dbbaSSimon Moll Value *EVLParam, 1921db4dbbaSSimon Moll ElementCount ElemCount) { 1931db4dbbaSSimon Moll // TODO add caching 1941db4dbbaSSimon Moll // Scalable vector %evl conversion. 1951db4dbbaSSimon Moll if (ElemCount.isScalable()) { 1961db4dbbaSSimon Moll auto *M = Builder.GetInsertBlock()->getModule(); 1971db4dbbaSSimon Moll Type *BoolVecTy = VectorType::get(Builder.getInt1Ty(), ElemCount); 1981db4dbbaSSimon Moll Function *ActiveMaskFunc = Intrinsic::getDeclaration( 1991db4dbbaSSimon Moll M, Intrinsic::get_active_lane_mask, {BoolVecTy, EVLParam->getType()}); 2001db4dbbaSSimon Moll // `get_active_lane_mask` performs an implicit less-than comparison. 2011db4dbbaSSimon Moll Value *ConstZero = Builder.getInt32(0); 2021db4dbbaSSimon Moll return Builder.CreateCall(ActiveMaskFunc, {ConstZero, EVLParam}); 2031db4dbbaSSimon Moll } 2041db4dbbaSSimon Moll 2051db4dbbaSSimon Moll // Fixed vector %evl conversion. 2061db4dbbaSSimon Moll Type *LaneTy = EVLParam->getType(); 2071db4dbbaSSimon Moll unsigned NumElems = ElemCount.getFixedValue(); 2081db4dbbaSSimon Moll Value *VLSplat = Builder.CreateVectorSplat(NumElems, EVLParam); 2091db4dbbaSSimon Moll Value *IdxVec = createStepVector(Builder, LaneTy, NumElems); 2101db4dbbaSSimon Moll return Builder.CreateICmp(CmpInst::ICMP_ULT, IdxVec, VLSplat); 2111db4dbbaSSimon Moll } 2121db4dbbaSSimon Moll 2131db4dbbaSSimon Moll Value * 2141db4dbbaSSimon Moll CachingVPExpander::expandPredicationInBinaryOperator(IRBuilder<> &Builder, 2151db4dbbaSSimon Moll VPIntrinsic &VPI) { 2161db4dbbaSSimon Moll assert((isSafeToSpeculativelyExecute(&VPI) || 2171db4dbbaSSimon Moll VPI.canIgnoreVectorLengthParam()) && 2181db4dbbaSSimon Moll "Implicitly dropping %evl in non-speculatable operator!"); 2191db4dbbaSSimon Moll 220*66963bf3SSimon Moll auto OC = static_cast<Instruction::BinaryOps>(*VPI.getFunctionalOpcode()); 2211db4dbbaSSimon Moll assert(Instruction::isBinaryOp(OC)); 2221db4dbbaSSimon Moll 2231db4dbbaSSimon Moll Value *Op0 = VPI.getOperand(0); 2241db4dbbaSSimon Moll Value *Op1 = VPI.getOperand(1); 2251db4dbbaSSimon Moll Value *Mask = VPI.getMaskParam(); 2261db4dbbaSSimon Moll 2271db4dbbaSSimon Moll // Blend in safe operands. 2281db4dbbaSSimon Moll if (Mask && !isAllTrueMask(Mask)) { 2291db4dbbaSSimon Moll switch (OC) { 2301db4dbbaSSimon Moll default: 2311db4dbbaSSimon Moll // Can safely ignore the predicate. 2321db4dbbaSSimon Moll break; 2331db4dbbaSSimon Moll 2341db4dbbaSSimon Moll // Division operators need a safe divisor on masked-off lanes (1). 2351db4dbbaSSimon Moll case Instruction::UDiv: 2361db4dbbaSSimon Moll case Instruction::SDiv: 2371db4dbbaSSimon Moll case Instruction::URem: 2381db4dbbaSSimon Moll case Instruction::SRem: 2391db4dbbaSSimon Moll // 2nd operand must not be zero. 2401db4dbbaSSimon Moll Value *SafeDivisor = getSafeDivisor(VPI.getType()); 2411db4dbbaSSimon Moll Op1 = Builder.CreateSelect(Mask, Op1, SafeDivisor); 2421db4dbbaSSimon Moll } 2431db4dbbaSSimon Moll } 2441db4dbbaSSimon Moll 2451db4dbbaSSimon Moll Value *NewBinOp = Builder.CreateBinOp(OC, Op0, Op1, VPI.getName()); 2461db4dbbaSSimon Moll 2471db4dbbaSSimon Moll replaceOperation(*NewBinOp, VPI); 2481db4dbbaSSimon Moll return NewBinOp; 2491db4dbbaSSimon Moll } 2501db4dbbaSSimon Moll 2511db4dbbaSSimon Moll void CachingVPExpander::discardEVLParameter(VPIntrinsic &VPI) { 2521db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "Discard EVL parameter in " << VPI << "\n"); 2531db4dbbaSSimon Moll 2541db4dbbaSSimon Moll if (VPI.canIgnoreVectorLengthParam()) 2551db4dbbaSSimon Moll return; 2561db4dbbaSSimon Moll 2571db4dbbaSSimon Moll Value *EVLParam = VPI.getVectorLengthParam(); 2581db4dbbaSSimon Moll if (!EVLParam) 2591db4dbbaSSimon Moll return; 2601db4dbbaSSimon Moll 2611db4dbbaSSimon Moll ElementCount StaticElemCount = VPI.getStaticVectorLength(); 2621db4dbbaSSimon Moll Value *MaxEVL = nullptr; 2631db4dbbaSSimon Moll Type *Int32Ty = Type::getInt32Ty(VPI.getContext()); 2641db4dbbaSSimon Moll if (StaticElemCount.isScalable()) { 2651db4dbbaSSimon Moll // TODO add caching 2661db4dbbaSSimon Moll auto *M = VPI.getModule(); 2671db4dbbaSSimon Moll Function *VScaleFunc = 2681db4dbbaSSimon Moll Intrinsic::getDeclaration(M, Intrinsic::vscale, Int32Ty); 2691db4dbbaSSimon Moll IRBuilder<> Builder(VPI.getParent(), VPI.getIterator()); 2701db4dbbaSSimon Moll Value *FactorConst = Builder.getInt32(StaticElemCount.getKnownMinValue()); 2711db4dbbaSSimon Moll Value *VScale = Builder.CreateCall(VScaleFunc, {}, "vscale"); 2721db4dbbaSSimon Moll MaxEVL = Builder.CreateMul(VScale, FactorConst, "scalable_size", 2731db4dbbaSSimon Moll /*NUW*/ true, /*NSW*/ false); 2741db4dbbaSSimon Moll } else { 2751db4dbbaSSimon Moll MaxEVL = ConstantInt::get(Int32Ty, StaticElemCount.getFixedValue(), false); 2761db4dbbaSSimon Moll } 2771db4dbbaSSimon Moll VPI.setVectorLengthParam(MaxEVL); 2781db4dbbaSSimon Moll } 2791db4dbbaSSimon Moll 2801db4dbbaSSimon Moll Value *CachingVPExpander::foldEVLIntoMask(VPIntrinsic &VPI) { 2811db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "Folding vlen for " << VPI << '\n'); 2821db4dbbaSSimon Moll 2831db4dbbaSSimon Moll IRBuilder<> Builder(&VPI); 2841db4dbbaSSimon Moll 2851db4dbbaSSimon Moll // Ineffective %evl parameter and so nothing to do here. 2861db4dbbaSSimon Moll if (VPI.canIgnoreVectorLengthParam()) 2871db4dbbaSSimon Moll return &VPI; 2881db4dbbaSSimon Moll 2891db4dbbaSSimon Moll // Only VP intrinsics can have an %evl parameter. 2901db4dbbaSSimon Moll Value *OldMaskParam = VPI.getMaskParam(); 2911db4dbbaSSimon Moll Value *OldEVLParam = VPI.getVectorLengthParam(); 2921db4dbbaSSimon Moll assert(OldMaskParam && "no mask param to fold the vl param into"); 2931db4dbbaSSimon Moll assert(OldEVLParam && "no EVL param to fold away"); 2941db4dbbaSSimon Moll 2951db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "OLD evl: " << *OldEVLParam << '\n'); 2961db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "OLD mask: " << *OldMaskParam << '\n'); 2971db4dbbaSSimon Moll 2981db4dbbaSSimon Moll // Convert the %evl predication into vector mask predication. 2991db4dbbaSSimon Moll ElementCount ElemCount = VPI.getStaticVectorLength(); 3001db4dbbaSSimon Moll Value *VLMask = convertEVLToMask(Builder, OldEVLParam, ElemCount); 3011db4dbbaSSimon Moll Value *NewMaskParam = Builder.CreateAnd(VLMask, OldMaskParam); 3021db4dbbaSSimon Moll VPI.setMaskParam(NewMaskParam); 3031db4dbbaSSimon Moll 3041db4dbbaSSimon Moll // Drop the %evl parameter. 3051db4dbbaSSimon Moll discardEVLParameter(VPI); 3061db4dbbaSSimon Moll assert(VPI.canIgnoreVectorLengthParam() && 3071db4dbbaSSimon Moll "transformation did not render the evl param ineffective!"); 3081db4dbbaSSimon Moll 3091db4dbbaSSimon Moll // Reassess the modified instruction. 3101db4dbbaSSimon Moll return &VPI; 3111db4dbbaSSimon Moll } 3121db4dbbaSSimon Moll 3131db4dbbaSSimon Moll Value *CachingVPExpander::expandPredication(VPIntrinsic &VPI) { 3141db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "Lowering to unpredicated op: " << VPI << '\n'); 3151db4dbbaSSimon Moll 3161db4dbbaSSimon Moll IRBuilder<> Builder(&VPI); 3171db4dbbaSSimon Moll 3181db4dbbaSSimon Moll // Try lowering to a LLVM instruction first. 319*66963bf3SSimon Moll auto OC = VPI.getFunctionalOpcode(); 3201db4dbbaSSimon Moll 321*66963bf3SSimon Moll if (OC && Instruction::isBinaryOp(*OC)) 3221db4dbbaSSimon Moll return expandPredicationInBinaryOperator(Builder, VPI); 3231db4dbbaSSimon Moll 3241db4dbbaSSimon Moll return &VPI; 3251db4dbbaSSimon Moll } 3261db4dbbaSSimon Moll 3271db4dbbaSSimon Moll //// } CachingVPExpander 3281db4dbbaSSimon Moll 3291db4dbbaSSimon Moll struct TransformJob { 3301db4dbbaSSimon Moll VPIntrinsic *PI; 3311db4dbbaSSimon Moll TargetTransformInfo::VPLegalization Strategy; 3321db4dbbaSSimon Moll TransformJob(VPIntrinsic *PI, TargetTransformInfo::VPLegalization InitStrat) 3331db4dbbaSSimon Moll : PI(PI), Strategy(InitStrat) {} 3341db4dbbaSSimon Moll 3351db4dbbaSSimon Moll bool isDone() const { return Strategy.shouldDoNothing(); } 3361db4dbbaSSimon Moll }; 3371db4dbbaSSimon Moll 3381db4dbbaSSimon Moll void sanitizeStrategy(Instruction &I, VPLegalization &LegalizeStrat) { 3391db4dbbaSSimon Moll // Speculatable instructions do not strictly need predication. 3401db4dbbaSSimon Moll if (isSafeToSpeculativelyExecute(&I)) { 3411db4dbbaSSimon Moll // Converting a speculatable VP intrinsic means dropping %mask and %evl. 3421db4dbbaSSimon Moll // No need to expand %evl into the %mask only to ignore that code. 3431db4dbbaSSimon Moll if (LegalizeStrat.OpStrategy == VPLegalization::Convert) 3441db4dbbaSSimon Moll LegalizeStrat.EVLParamStrategy = VPLegalization::Discard; 3451db4dbbaSSimon Moll return; 3461db4dbbaSSimon Moll } 3471db4dbbaSSimon Moll 3481db4dbbaSSimon Moll // We have to preserve the predicating effect of %evl for this 3491db4dbbaSSimon Moll // non-speculatable VP intrinsic. 3501db4dbbaSSimon Moll // 1) Never discard %evl. 3511db4dbbaSSimon Moll // 2) If this VP intrinsic will be expanded to non-VP code, make sure that 3521db4dbbaSSimon Moll // %evl gets folded into %mask. 3531db4dbbaSSimon Moll if ((LegalizeStrat.EVLParamStrategy == VPLegalization::Discard) || 3541db4dbbaSSimon Moll (LegalizeStrat.OpStrategy == VPLegalization::Convert)) { 3551db4dbbaSSimon Moll LegalizeStrat.EVLParamStrategy = VPLegalization::Convert; 3561db4dbbaSSimon Moll } 3571db4dbbaSSimon Moll } 3581db4dbbaSSimon Moll 3591db4dbbaSSimon Moll VPLegalization 3601db4dbbaSSimon Moll CachingVPExpander::getVPLegalizationStrategy(const VPIntrinsic &VPI) const { 3611db4dbbaSSimon Moll auto VPStrat = TTI.getVPLegalizationStrategy(VPI); 3621db4dbbaSSimon Moll if (LLVM_LIKELY(!UsingTTIOverrides)) { 3631db4dbbaSSimon Moll // No overrides - we are in production. 3641db4dbbaSSimon Moll return VPStrat; 3651db4dbbaSSimon Moll } 3661db4dbbaSSimon Moll 3671db4dbbaSSimon Moll // Overrides set - we are in testing, the following does not need to be 3681db4dbbaSSimon Moll // efficient. 3691db4dbbaSSimon Moll VPStrat.EVLParamStrategy = parseOverrideOption(EVLTransformOverride); 3701db4dbbaSSimon Moll VPStrat.OpStrategy = parseOverrideOption(MaskTransformOverride); 3711db4dbbaSSimon Moll return VPStrat; 3721db4dbbaSSimon Moll } 3731db4dbbaSSimon Moll 3741db4dbbaSSimon Moll /// \brief Expand llvm.vp.* intrinsics as requested by \p TTI. 3751db4dbbaSSimon Moll bool CachingVPExpander::expandVectorPredication() { 3761db4dbbaSSimon Moll SmallVector<TransformJob, 16> Worklist; 3771db4dbbaSSimon Moll 3781db4dbbaSSimon Moll // Collect all VPIntrinsics that need expansion and determine their expansion 3791db4dbbaSSimon Moll // strategy. 3801db4dbbaSSimon Moll for (auto &I : instructions(F)) { 3811db4dbbaSSimon Moll auto *VPI = dyn_cast<VPIntrinsic>(&I); 3821db4dbbaSSimon Moll if (!VPI) 3831db4dbbaSSimon Moll continue; 3841db4dbbaSSimon Moll auto VPStrat = getVPLegalizationStrategy(*VPI); 3851db4dbbaSSimon Moll sanitizeStrategy(I, VPStrat); 3861db4dbbaSSimon Moll if (!VPStrat.shouldDoNothing()) 3871db4dbbaSSimon Moll Worklist.emplace_back(VPI, VPStrat); 3881db4dbbaSSimon Moll } 3891db4dbbaSSimon Moll if (Worklist.empty()) 3901db4dbbaSSimon Moll return false; 3911db4dbbaSSimon Moll 3921db4dbbaSSimon Moll // Transform all VPIntrinsics on the worklist. 3931db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "\n:::: Transforming " << Worklist.size() 3941db4dbbaSSimon Moll << " instructions ::::\n"); 3951db4dbbaSSimon Moll for (TransformJob Job : Worklist) { 3961db4dbbaSSimon Moll // Transform the EVL parameter. 3971db4dbbaSSimon Moll switch (Job.Strategy.EVLParamStrategy) { 3981db4dbbaSSimon Moll case VPLegalization::Legal: 3991db4dbbaSSimon Moll break; 4001db4dbbaSSimon Moll case VPLegalization::Discard: 4011db4dbbaSSimon Moll discardEVLParameter(*Job.PI); 4021db4dbbaSSimon Moll break; 4031db4dbbaSSimon Moll case VPLegalization::Convert: 4041db4dbbaSSimon Moll if (foldEVLIntoMask(*Job.PI)) 4051db4dbbaSSimon Moll ++NumFoldedVL; 4061db4dbbaSSimon Moll break; 4071db4dbbaSSimon Moll } 4081db4dbbaSSimon Moll Job.Strategy.EVLParamStrategy = VPLegalization::Legal; 4091db4dbbaSSimon Moll 4101db4dbbaSSimon Moll // Replace with a non-predicated operation. 4111db4dbbaSSimon Moll switch (Job.Strategy.OpStrategy) { 4121db4dbbaSSimon Moll case VPLegalization::Legal: 4131db4dbbaSSimon Moll break; 4141db4dbbaSSimon Moll case VPLegalization::Discard: 4151db4dbbaSSimon Moll llvm_unreachable("Invalid strategy for operators."); 4161db4dbbaSSimon Moll case VPLegalization::Convert: 4171db4dbbaSSimon Moll expandPredication(*Job.PI); 4181db4dbbaSSimon Moll ++NumLoweredVPOps; 4191db4dbbaSSimon Moll break; 4201db4dbbaSSimon Moll } 4211db4dbbaSSimon Moll Job.Strategy.OpStrategy = VPLegalization::Legal; 4221db4dbbaSSimon Moll 4231db4dbbaSSimon Moll assert(Job.isDone() && "incomplete transformation"); 4241db4dbbaSSimon Moll } 4251db4dbbaSSimon Moll 4261db4dbbaSSimon Moll return true; 4271db4dbbaSSimon Moll } 4281db4dbbaSSimon Moll class ExpandVectorPredication : public FunctionPass { 4291db4dbbaSSimon Moll public: 4301db4dbbaSSimon Moll static char ID; 4311db4dbbaSSimon Moll ExpandVectorPredication() : FunctionPass(ID) { 4321db4dbbaSSimon Moll initializeExpandVectorPredicationPass(*PassRegistry::getPassRegistry()); 4331db4dbbaSSimon Moll } 4341db4dbbaSSimon Moll 4351db4dbbaSSimon Moll bool runOnFunction(Function &F) override { 4361db4dbbaSSimon Moll const auto *TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 4371db4dbbaSSimon Moll CachingVPExpander VPExpander(F, *TTI); 4381db4dbbaSSimon Moll return VPExpander.expandVectorPredication(); 4391db4dbbaSSimon Moll } 4401db4dbbaSSimon Moll 4411db4dbbaSSimon Moll void getAnalysisUsage(AnalysisUsage &AU) const override { 4421db4dbbaSSimon Moll AU.addRequired<TargetTransformInfoWrapperPass>(); 4431db4dbbaSSimon Moll AU.setPreservesCFG(); 4441db4dbbaSSimon Moll } 4451db4dbbaSSimon Moll }; 4461db4dbbaSSimon Moll } // namespace 4471db4dbbaSSimon Moll 4481db4dbbaSSimon Moll char ExpandVectorPredication::ID; 4491db4dbbaSSimon Moll INITIALIZE_PASS_BEGIN(ExpandVectorPredication, "expandvp", 4501db4dbbaSSimon Moll "Expand vector predication intrinsics", false, false) 4511db4dbbaSSimon Moll INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 4521db4dbbaSSimon Moll INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 4531db4dbbaSSimon Moll INITIALIZE_PASS_END(ExpandVectorPredication, "expandvp", 4541db4dbbaSSimon Moll "Expand vector predication intrinsics", false, false) 4551db4dbbaSSimon Moll 4561db4dbbaSSimon Moll FunctionPass *llvm::createExpandVectorPredicationPass() { 4571db4dbbaSSimon Moll return new ExpandVectorPredication(); 4581db4dbbaSSimon Moll } 4591db4dbbaSSimon Moll 4601db4dbbaSSimon Moll PreservedAnalyses 4611db4dbbaSSimon Moll ExpandVectorPredicationPass::run(Function &F, FunctionAnalysisManager &AM) { 4621db4dbbaSSimon Moll const auto &TTI = AM.getResult<TargetIRAnalysis>(F); 4631db4dbbaSSimon Moll CachingVPExpander VPExpander(F, TTI); 4641db4dbbaSSimon Moll if (!VPExpander.expandVectorPredication()) 4651db4dbbaSSimon Moll return PreservedAnalyses::all(); 4661db4dbbaSSimon Moll PreservedAnalyses PA; 4671db4dbbaSSimon Moll PA.preserveSet<CFGAnalyses>(); 4681db4dbbaSSimon Moll return PA; 4691db4dbbaSSimon Moll } 470