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 // 9fa92d51fSAlexis Engelke // This file 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" 18f390781cSLorenzo Albano #include "llvm/Analysis/VectorUtils.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/Instructions.h" 231db4dbbaSSimon Moll #include "llvm/IR/IntrinsicInst.h" 241db4dbbaSSimon Moll #include "llvm/IR/Intrinsics.h" 251db4dbbaSSimon Moll #include "llvm/Support/CommandLine.h" 261db4dbbaSSimon Moll #include "llvm/Support/Compiler.h" 271db4dbbaSSimon Moll #include "llvm/Support/Debug.h" 28c315d787SPhilip Reames #include "llvm/Transforms/Utils/LoopUtils.h" 29f3b6dbfdSKrzysztof Parzyszek #include <optional> 301db4dbbaSSimon Moll 311db4dbbaSSimon Moll using namespace llvm; 321db4dbbaSSimon Moll 331db4dbbaSSimon Moll using VPLegalization = TargetTransformInfo::VPLegalization; 341db4dbbaSSimon Moll using VPTransform = TargetTransformInfo::VPLegalization::VPTransform; 351db4dbbaSSimon Moll 361db4dbbaSSimon Moll // Keep this in sync with TargetTransformInfo::VPLegalization. 371db4dbbaSSimon Moll #define VPINTERNAL_VPLEGAL_CASES \ 381db4dbbaSSimon Moll VPINTERNAL_CASE(Legal) \ 391db4dbbaSSimon Moll VPINTERNAL_CASE(Discard) \ 401db4dbbaSSimon Moll VPINTERNAL_CASE(Convert) 411db4dbbaSSimon Moll 421db4dbbaSSimon Moll #define VPINTERNAL_CASE(X) "|" #X 431db4dbbaSSimon Moll 441db4dbbaSSimon Moll // Override options. 451db4dbbaSSimon Moll static cl::opt<std::string> EVLTransformOverride( 461db4dbbaSSimon Moll "expandvp-override-evl-transform", cl::init(""), cl::Hidden, 471db4dbbaSSimon Moll cl::desc("Options: <empty>" VPINTERNAL_VPLEGAL_CASES 481db4dbbaSSimon Moll ". If non-empty, ignore " 491db4dbbaSSimon Moll "TargetTransformInfo and " 501db4dbbaSSimon Moll "always use this transformation for the %evl parameter (Used in " 511db4dbbaSSimon Moll "testing).")); 521db4dbbaSSimon Moll 531db4dbbaSSimon Moll static cl::opt<std::string> MaskTransformOverride( 541db4dbbaSSimon Moll "expandvp-override-mask-transform", cl::init(""), cl::Hidden, 551db4dbbaSSimon Moll cl::desc("Options: <empty>" VPINTERNAL_VPLEGAL_CASES 561db4dbbaSSimon Moll ". If non-empty, Ignore " 571db4dbbaSSimon Moll "TargetTransformInfo and " 581db4dbbaSSimon Moll "always use this transformation for the %mask parameter (Used in " 591db4dbbaSSimon Moll "testing).")); 601db4dbbaSSimon Moll 611db4dbbaSSimon Moll #undef VPINTERNAL_CASE 621db4dbbaSSimon Moll #define VPINTERNAL_CASE(X) .Case(#X, VPLegalization::X) 631db4dbbaSSimon Moll 641db4dbbaSSimon Moll static VPTransform parseOverrideOption(const std::string &TextOpt) { 651db4dbbaSSimon Moll return StringSwitch<VPTransform>(TextOpt) VPINTERNAL_VPLEGAL_CASES; 661db4dbbaSSimon Moll } 671db4dbbaSSimon Moll 681db4dbbaSSimon Moll #undef VPINTERNAL_VPLEGAL_CASES 691db4dbbaSSimon Moll 701db4dbbaSSimon Moll // Whether any override options are set. 711db4dbbaSSimon Moll static bool anyExpandVPOverridesSet() { 721db4dbbaSSimon Moll return !EVLTransformOverride.empty() || !MaskTransformOverride.empty(); 731db4dbbaSSimon Moll } 741db4dbbaSSimon Moll 751db4dbbaSSimon Moll #define DEBUG_TYPE "expandvp" 761db4dbbaSSimon Moll 771db4dbbaSSimon Moll STATISTIC(NumFoldedVL, "Number of folded vector length params"); 781db4dbbaSSimon Moll STATISTIC(NumLoweredVPOps, "Number of folded vector predication operations"); 791db4dbbaSSimon Moll 801db4dbbaSSimon Moll ///// Helpers { 811db4dbbaSSimon Moll 821db4dbbaSSimon Moll /// \returns Whether the vector mask \p MaskVal has all lane bits set. 831db4dbbaSSimon Moll static bool isAllTrueMask(Value *MaskVal) { 84f390781cSLorenzo Albano if (Value *SplattedVal = getSplatValue(MaskVal)) 85f390781cSLorenzo Albano if (auto *ConstValue = dyn_cast<Constant>(SplattedVal)) 86f390781cSLorenzo Albano return ConstValue->isAllOnesValue(); 87f390781cSLorenzo Albano 88f390781cSLorenzo Albano return false; 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 1186e127110SSimon Moll static bool maySpeculateLanes(VPIntrinsic &VPI) { 1196e127110SSimon Moll // The result of VP reductions depends on the mask and evl. 1206e127110SSimon Moll if (isa<VPReductionIntrinsic>(VPI)) 1216e127110SSimon Moll return false; 1226e127110SSimon Moll // Fallback to whether the intrinsic is speculatable. 1232e85123bSLuke Lau if (auto IntrID = VPI.getFunctionalIntrinsicID()) 1242e85123bSLuke Lau return Intrinsic::getAttributes(VPI.getContext(), *IntrID) 1252e85123bSLuke Lau .hasFnAttr(Attribute::AttrKind::Speculatable); 1262e85123bSLuke Lau if (auto Opc = VPI.getFunctionalOpcode()) 1272e85123bSLuke Lau return isSafeToSpeculativelyExecuteWithOpcode(*Opc, &VPI); 1282e85123bSLuke Lau return false; 1296e127110SSimon Moll } 1306e127110SSimon Moll 1311db4dbbaSSimon Moll //// } Helpers 1321db4dbbaSSimon Moll 1331db4dbbaSSimon Moll namespace { 1341db4dbbaSSimon Moll 1351db4dbbaSSimon Moll // Expansion pass state at function scope. 1361db4dbbaSSimon Moll struct CachingVPExpander { 1371db4dbbaSSimon Moll const TargetTransformInfo &TTI; 1381db4dbbaSSimon Moll 1391db4dbbaSSimon Moll /// \returns A bitmask that is true where the lane position is less-than \p 1401db4dbbaSSimon Moll /// EVLParam 1411db4dbbaSSimon Moll /// 1421db4dbbaSSimon Moll /// \p Builder 1431db4dbbaSSimon Moll /// Used for instruction creation. 1441db4dbbaSSimon Moll /// \p VLParam 1451db4dbbaSSimon Moll /// The explicit vector length parameter to test against the lane 1461db4dbbaSSimon Moll /// positions. 1471db4dbbaSSimon Moll /// \p ElemCount 1481db4dbbaSSimon Moll /// Static (potentially scalable) number of vector elements. 1491db4dbbaSSimon Moll Value *convertEVLToMask(IRBuilder<> &Builder, Value *EVLParam, 1501db4dbbaSSimon Moll ElementCount ElemCount); 1511db4dbbaSSimon Moll 152e1a16cd8SRoger Ferrer Ibáñez /// If needed, folds the EVL in the mask operand and discards the EVL 153e1a16cd8SRoger Ferrer Ibáñez /// parameter. Returns a pair of the value of the intrinsic after the change 154e1a16cd8SRoger Ferrer Ibáñez /// (if any) and whether the mask was actually folded. 155e1a16cd8SRoger Ferrer Ibáñez std::pair<Value *, bool> foldEVLIntoMask(VPIntrinsic &VPI); 1561db4dbbaSSimon Moll 1571db4dbbaSSimon Moll /// "Remove" the %evl parameter of \p PI by setting it to the static vector 158e1a16cd8SRoger Ferrer Ibáñez /// length of the operation. Returns true if the %evl (if any) was effectively 159e1a16cd8SRoger Ferrer Ibáñez /// changed. 160e1a16cd8SRoger Ferrer Ibáñez bool discardEVLParameter(VPIntrinsic &PI); 1611db4dbbaSSimon Moll 162a3a9b074SFraser Cormack /// Lower this VP binary operator to a unpredicated binary operator. 1631db4dbbaSSimon Moll Value *expandPredicationInBinaryOperator(IRBuilder<> &Builder, 1641db4dbbaSSimon Moll VPIntrinsic &PI); 1651db4dbbaSSimon Moll 16628e74e61Sliqin.weng /// Lower this VP int call to a unpredicated int call. 16702408d6bSLiqinWeng Value *expandPredicationToIntCall(IRBuilder<> &Builder, VPIntrinsic &PI); 16828e74e61Sliqin.weng 1690b7f53efSSimon Pilgrim /// Lower this VP fp call to a unpredicated fp call. 1700b7f53efSSimon Pilgrim Value *expandPredicationToFPCall(IRBuilder<> &Builder, VPIntrinsic &PI, 1710b7f53efSSimon Pilgrim unsigned UnpredicatedIntrinsicID); 1720b7f53efSSimon Pilgrim 173a3a9b074SFraser Cormack /// Lower this VP reduction to a call to an unpredicated reduction intrinsic. 174f3e90472SFraser Cormack Value *expandPredicationInReduction(IRBuilder<> &Builder, 175f3e90472SFraser Cormack VPReductionIntrinsic &PI); 176f3e90472SFraser Cormack 1771b622fffSliqin.weng /// Lower this VP cast operation to a non-VP intrinsic. 1781b622fffSliqin.weng Value *expandPredicationToCastIntrinsic(IRBuilder<> &Builder, 1791b622fffSliqin.weng VPIntrinsic &VPI); 1801b622fffSliqin.weng 181a3a9b074SFraser Cormack /// Lower this VP memory operation to a non-VP intrinsic. 182f390781cSLorenzo Albano Value *expandPredicationInMemoryIntrinsic(IRBuilder<> &Builder, 183f390781cSLorenzo Albano VPIntrinsic &VPI); 184f390781cSLorenzo Albano 185a3a9b074SFraser Cormack /// Lower this VP comparison to a call to an unpredicated comparison. 1863362e2d5SFraser Cormack Value *expandPredicationInComparison(IRBuilder<> &Builder, 1873362e2d5SFraser Cormack VPCmpIntrinsic &PI); 1883362e2d5SFraser Cormack 189a3a9b074SFraser Cormack /// Query TTI and expand the vector predication in \p P accordingly. 1901db4dbbaSSimon Moll Value *expandPredication(VPIntrinsic &PI); 1911db4dbbaSSimon Moll 192a3a9b074SFraser Cormack /// Determine how and whether the VPIntrinsic \p VPI shall be expanded. This 193a3a9b074SFraser Cormack /// overrides TTI with the cl::opts listed at the top of this file. 1941db4dbbaSSimon Moll VPLegalization getVPLegalizationStrategy(const VPIntrinsic &VPI) const; 1951db4dbbaSSimon Moll bool UsingTTIOverrides; 1961db4dbbaSSimon Moll 1971db4dbbaSSimon Moll public: 198fa92d51fSAlexis Engelke CachingVPExpander(const TargetTransformInfo &TTI) 199fa92d51fSAlexis Engelke : TTI(TTI), UsingTTIOverrides(anyExpandVPOverridesSet()) {} 2001db4dbbaSSimon Moll 201e1a16cd8SRoger Ferrer Ibáñez /// Expand llvm.vp.* intrinsics as requested by \p TTI. 202e1a16cd8SRoger Ferrer Ibáñez /// Returns the details of the expansion. 203e1a16cd8SRoger Ferrer Ibáñez VPExpansionDetails expandVectorPredication(VPIntrinsic &VPI); 2041db4dbbaSSimon Moll }; 2051db4dbbaSSimon Moll 2061db4dbbaSSimon Moll //// CachingVPExpander { 2071db4dbbaSSimon Moll 2081db4dbbaSSimon Moll Value *CachingVPExpander::convertEVLToMask(IRBuilder<> &Builder, 2091db4dbbaSSimon Moll Value *EVLParam, 2101db4dbbaSSimon Moll ElementCount ElemCount) { 2111db4dbbaSSimon Moll // TODO add caching 2121db4dbbaSSimon Moll // Scalable vector %evl conversion. 2131db4dbbaSSimon Moll if (ElemCount.isScalable()) { 2141db4dbbaSSimon Moll Type *BoolVecTy = VectorType::get(Builder.getInt1Ty(), ElemCount); 2151db4dbbaSSimon Moll // `get_active_lane_mask` performs an implicit less-than comparison. 2161db4dbbaSSimon Moll Value *ConstZero = Builder.getInt32(0); 21785c17e40SJay Foad return Builder.CreateIntrinsic(Intrinsic::get_active_lane_mask, 21885c17e40SJay Foad {BoolVecTy, EVLParam->getType()}, 21985c17e40SJay Foad {ConstZero, EVLParam}); 2201db4dbbaSSimon Moll } 2211db4dbbaSSimon Moll 2221db4dbbaSSimon Moll // Fixed vector %evl conversion. 2231db4dbbaSSimon Moll Type *LaneTy = EVLParam->getType(); 2241db4dbbaSSimon Moll unsigned NumElems = ElemCount.getFixedValue(); 2251db4dbbaSSimon Moll Value *VLSplat = Builder.CreateVectorSplat(NumElems, EVLParam); 226*ef77188fSLiqinWeng Value *IdxVec = Builder.CreateStepVector(VectorType::get(LaneTy, ElemCount)); 2271db4dbbaSSimon Moll return Builder.CreateICmp(CmpInst::ICMP_ULT, IdxVec, VLSplat); 2281db4dbbaSSimon Moll } 2291db4dbbaSSimon Moll 2301db4dbbaSSimon Moll Value * 2311db4dbbaSSimon Moll CachingVPExpander::expandPredicationInBinaryOperator(IRBuilder<> &Builder, 2321db4dbbaSSimon Moll VPIntrinsic &VPI) { 2336e127110SSimon Moll assert((maySpeculateLanes(VPI) || VPI.canIgnoreVectorLengthParam()) && 2341db4dbbaSSimon Moll "Implicitly dropping %evl in non-speculatable operator!"); 2351db4dbbaSSimon Moll 23666963bf3SSimon Moll auto OC = static_cast<Instruction::BinaryOps>(*VPI.getFunctionalOpcode()); 2371db4dbbaSSimon Moll assert(Instruction::isBinaryOp(OC)); 2381db4dbbaSSimon Moll 2391db4dbbaSSimon Moll Value *Op0 = VPI.getOperand(0); 2401db4dbbaSSimon Moll Value *Op1 = VPI.getOperand(1); 2411db4dbbaSSimon Moll Value *Mask = VPI.getMaskParam(); 2421db4dbbaSSimon Moll 2431db4dbbaSSimon Moll // Blend in safe operands. 2441db4dbbaSSimon Moll if (Mask && !isAllTrueMask(Mask)) { 2451db4dbbaSSimon Moll switch (OC) { 2461db4dbbaSSimon Moll default: 2471db4dbbaSSimon Moll // Can safely ignore the predicate. 2481db4dbbaSSimon Moll break; 2491db4dbbaSSimon Moll 2501db4dbbaSSimon Moll // Division operators need a safe divisor on masked-off lanes (1). 2511db4dbbaSSimon Moll case Instruction::UDiv: 2521db4dbbaSSimon Moll case Instruction::SDiv: 2531db4dbbaSSimon Moll case Instruction::URem: 2541db4dbbaSSimon Moll case Instruction::SRem: 2551db4dbbaSSimon Moll // 2nd operand must not be zero. 2561db4dbbaSSimon Moll Value *SafeDivisor = getSafeDivisor(VPI.getType()); 2571db4dbbaSSimon Moll Op1 = Builder.CreateSelect(Mask, Op1, SafeDivisor); 2581db4dbbaSSimon Moll } 2591db4dbbaSSimon Moll } 2601db4dbbaSSimon Moll 2611db4dbbaSSimon Moll Value *NewBinOp = Builder.CreateBinOp(OC, Op0, Op1, VPI.getName()); 2621db4dbbaSSimon Moll 2631db4dbbaSSimon Moll replaceOperation(*NewBinOp, VPI); 2641db4dbbaSSimon Moll return NewBinOp; 2651db4dbbaSSimon Moll } 2661db4dbbaSSimon Moll 26702408d6bSLiqinWeng Value *CachingVPExpander::expandPredicationToIntCall(IRBuilder<> &Builder, 26802408d6bSLiqinWeng VPIntrinsic &VPI) { 26902408d6bSLiqinWeng std::optional<unsigned> FID = VPI.getFunctionalIntrinsicID(); 27002408d6bSLiqinWeng if (!FID) 27128e74e61Sliqin.weng return nullptr; 27202408d6bSLiqinWeng SmallVector<Value *, 2> Argument; 27302408d6bSLiqinWeng for (unsigned i = 0; i < VPI.getNumOperands() - 3; i++) { 27402408d6bSLiqinWeng Argument.push_back(VPI.getOperand(i)); 27502408d6bSLiqinWeng } 27602408d6bSLiqinWeng Value *NewOp = Builder.CreateIntrinsic(FID.value(), {VPI.getType()}, Argument, 27702408d6bSLiqinWeng /*FMFSource=*/nullptr, VPI.getName()); 27802408d6bSLiqinWeng replaceOperation(*NewOp, VPI); 27902408d6bSLiqinWeng return NewOp; 28028e74e61Sliqin.weng } 28128e74e61Sliqin.weng 2820b7f53efSSimon Pilgrim Value *CachingVPExpander::expandPredicationToFPCall( 2830b7f53efSSimon Pilgrim IRBuilder<> &Builder, VPIntrinsic &VPI, unsigned UnpredicatedIntrinsicID) { 2840b7f53efSSimon Pilgrim assert((maySpeculateLanes(VPI) || VPI.canIgnoreVectorLengthParam()) && 2850b7f53efSSimon Pilgrim "Implicitly dropping %evl in non-speculatable operator!"); 2860b7f53efSSimon Pilgrim 2870b7f53efSSimon Pilgrim switch (UnpredicatedIntrinsicID) { 2880b7f53efSSimon Pilgrim case Intrinsic::fabs: 28902408d6bSLiqinWeng case Intrinsic::sqrt: 2901eec3574Sliqin.weng case Intrinsic::maxnum: 291f2f18459SNikita Popov case Intrinsic::minnum: { 29202408d6bSLiqinWeng SmallVector<Value *, 2> Argument; 29302408d6bSLiqinWeng for (unsigned i = 0; i < VPI.getNumOperands() - 3; i++) { 29402408d6bSLiqinWeng Argument.push_back(VPI.getOperand(i)); 29502408d6bSLiqinWeng } 29685c17e40SJay Foad Value *NewOp = Builder.CreateIntrinsic( 29702408d6bSLiqinWeng UnpredicatedIntrinsicID, {VPI.getType()}, Argument, 29885c17e40SJay Foad /*FMFSource=*/nullptr, VPI.getName()); 2991eec3574Sliqin.weng replaceOperation(*NewOp, VPI); 3001eec3574Sliqin.weng return NewOp; 3011eec3574Sliqin.weng } 30279726ef5SKevin P. Neal case Intrinsic::fma: 30379726ef5SKevin P. Neal case Intrinsic::fmuladd: 3040b7f53efSSimon Pilgrim case Intrinsic::experimental_constrained_fma: 3050b7f53efSSimon Pilgrim case Intrinsic::experimental_constrained_fmuladd: { 3060b7f53efSSimon Pilgrim Value *Op0 = VPI.getOperand(0); 3070b7f53efSSimon Pilgrim Value *Op1 = VPI.getOperand(1); 3080b7f53efSSimon Pilgrim Value *Op2 = VPI.getOperand(2); 309fa789dffSRahul Joshi Function *Fn = Intrinsic::getOrInsertDeclaration( 3100b7f53efSSimon Pilgrim VPI.getModule(), UnpredicatedIntrinsicID, {VPI.getType()}); 31179726ef5SKevin P. Neal Value *NewOp; 31279726ef5SKevin P. Neal if (Intrinsic::isConstrainedFPIntrinsic(UnpredicatedIntrinsicID)) 31379726ef5SKevin P. Neal NewOp = 3140b7f53efSSimon Pilgrim Builder.CreateConstrainedFPCall(Fn, {Op0, Op1, Op2}, VPI.getName()); 31579726ef5SKevin P. Neal else 31679726ef5SKevin P. Neal NewOp = Builder.CreateCall(Fn, {Op0, Op1, Op2}, VPI.getName()); 3170b7f53efSSimon Pilgrim replaceOperation(*NewOp, VPI); 3180b7f53efSSimon Pilgrim return NewOp; 3190b7f53efSSimon Pilgrim } 3200b7f53efSSimon Pilgrim } 3210b7f53efSSimon Pilgrim 3220b7f53efSSimon Pilgrim return nullptr; 3230b7f53efSSimon Pilgrim } 3240b7f53efSSimon Pilgrim 325f3e90472SFraser Cormack static Value *getNeutralReductionElement(const VPReductionIntrinsic &VPI, 326f3e90472SFraser Cormack Type *EltTy) { 3273d9abfc9SPhilip Reames Intrinsic::ID RdxID = *VPI.getFunctionalIntrinsicID(); 3283d9abfc9SPhilip Reames FastMathFlags FMF; 3293d9abfc9SPhilip Reames if (isa<FPMathOperator>(VPI)) 3303d9abfc9SPhilip Reames FMF = VPI.getFastMathFlags(); 3313d9abfc9SPhilip Reames return getReductionIdentity(RdxID, EltTy, FMF); 332f3e90472SFraser Cormack } 333f3e90472SFraser Cormack 334f3e90472SFraser Cormack Value * 335f3e90472SFraser Cormack CachingVPExpander::expandPredicationInReduction(IRBuilder<> &Builder, 336f3e90472SFraser Cormack VPReductionIntrinsic &VPI) { 3376e127110SSimon Moll assert((maySpeculateLanes(VPI) || VPI.canIgnoreVectorLengthParam()) && 338f3e90472SFraser Cormack "Implicitly dropping %evl in non-speculatable operator!"); 339f3e90472SFraser Cormack 340f3e90472SFraser Cormack Value *Mask = VPI.getMaskParam(); 341f3e90472SFraser Cormack Value *RedOp = VPI.getOperand(VPI.getVectorParamPos()); 342f3e90472SFraser Cormack 343f3e90472SFraser Cormack // Insert neutral element in masked-out positions 344f3e90472SFraser Cormack if (Mask && !isAllTrueMask(Mask)) { 345f3e90472SFraser Cormack auto *NeutralElt = getNeutralReductionElement(VPI, VPI.getType()); 346f3e90472SFraser Cormack auto *NeutralVector = Builder.CreateVectorSplat( 347f3e90472SFraser Cormack cast<VectorType>(RedOp->getType())->getElementCount(), NeutralElt); 348f3e90472SFraser Cormack RedOp = Builder.CreateSelect(Mask, RedOp, NeutralVector); 349f3e90472SFraser Cormack } 350f3e90472SFraser Cormack 351f3e90472SFraser Cormack Value *Reduction; 352f3e90472SFraser Cormack Value *Start = VPI.getOperand(VPI.getStartParamPos()); 353f3e90472SFraser Cormack 354f3e90472SFraser Cormack switch (VPI.getIntrinsicID()) { 355f3e90472SFraser Cormack default: 356f3e90472SFraser Cormack llvm_unreachable("Impossible reduction kind"); 357f3e90472SFraser Cormack case Intrinsic::vp_reduce_add: 358f3e90472SFraser Cormack case Intrinsic::vp_reduce_mul: 359f3e90472SFraser Cormack case Intrinsic::vp_reduce_and: 360f3e90472SFraser Cormack case Intrinsic::vp_reduce_or: 361c315d787SPhilip Reames case Intrinsic::vp_reduce_xor: { 362c315d787SPhilip Reames Intrinsic::ID RedID = *VPI.getFunctionalIntrinsicID(); 363c315d787SPhilip Reames unsigned Opc = getArithmeticReductionInstruction(RedID); 364c315d787SPhilip Reames assert(Instruction::isBinaryOp(Opc)); 365c315d787SPhilip Reames Reduction = Builder.CreateUnaryIntrinsic(RedID, RedOp); 366c315d787SPhilip Reames Reduction = 367c315d787SPhilip Reames Builder.CreateBinOp((Instruction::BinaryOps)Opc, Reduction, Start); 368f3e90472SFraser Cormack break; 369c315d787SPhilip Reames } 370f3e90472SFraser Cormack case Intrinsic::vp_reduce_smax: 371f3e90472SFraser Cormack case Intrinsic::vp_reduce_smin: 372f3e90472SFraser Cormack case Intrinsic::vp_reduce_umax: 373f3e90472SFraser Cormack case Intrinsic::vp_reduce_umin: 374f3e90472SFraser Cormack case Intrinsic::vp_reduce_fmax: 375f3e90472SFraser Cormack case Intrinsic::vp_reduce_fmin: 376f8063ffeSMin-Yih Hsu case Intrinsic::vp_reduce_fmaximum: 377c315d787SPhilip Reames case Intrinsic::vp_reduce_fminimum: { 378c315d787SPhilip Reames Intrinsic::ID RedID = *VPI.getFunctionalIntrinsicID(); 379c315d787SPhilip Reames Intrinsic::ID ScalarID = getMinMaxReductionIntrinsicOp(RedID); 380c315d787SPhilip Reames Reduction = Builder.CreateUnaryIntrinsic(RedID, RedOp); 381f8063ffeSMin-Yih Hsu transferDecorations(*Reduction, VPI); 382c315d787SPhilip Reames Reduction = Builder.CreateBinaryIntrinsic(ScalarID, Reduction, Start); 383f8063ffeSMin-Yih Hsu break; 384c315d787SPhilip Reames } 385f3e90472SFraser Cormack case Intrinsic::vp_reduce_fadd: 386f3e90472SFraser Cormack Reduction = Builder.CreateFAddReduce(Start, RedOp); 387f3e90472SFraser Cormack break; 388f3e90472SFraser Cormack case Intrinsic::vp_reduce_fmul: 389f3e90472SFraser Cormack Reduction = Builder.CreateFMulReduce(Start, RedOp); 390f3e90472SFraser Cormack break; 391f3e90472SFraser Cormack } 392f3e90472SFraser Cormack 393f3e90472SFraser Cormack replaceOperation(*Reduction, VPI); 394f3e90472SFraser Cormack return Reduction; 395f3e90472SFraser Cormack } 396f3e90472SFraser Cormack 3971b622fffSliqin.weng Value *CachingVPExpander::expandPredicationToCastIntrinsic(IRBuilder<> &Builder, 3981b622fffSliqin.weng VPIntrinsic &VPI) { 39902408d6bSLiqinWeng Intrinsic::ID VPID = VPI.getIntrinsicID(); 40002408d6bSLiqinWeng unsigned CastOpcode = VPIntrinsic::getFunctionalOpcodeForVP(VPID).value(); 40102408d6bSLiqinWeng assert(Instruction::isCast(CastOpcode)); 40202408d6bSLiqinWeng Value *CastOp = 40302408d6bSLiqinWeng Builder.CreateCast(Instruction::CastOps(CastOpcode), VPI.getOperand(0), 40402408d6bSLiqinWeng VPI.getType(), VPI.getName()); 4053723ede3Sliqin.weng 4063723ede3Sliqin.weng replaceOperation(*CastOp, VPI); 4073723ede3Sliqin.weng return CastOp; 4081b622fffSliqin.weng } 4091b622fffSliqin.weng 410f390781cSLorenzo Albano Value * 411f390781cSLorenzo Albano CachingVPExpander::expandPredicationInMemoryIntrinsic(IRBuilder<> &Builder, 412f390781cSLorenzo Albano VPIntrinsic &VPI) { 413f390781cSLorenzo Albano assert(VPI.canIgnoreVectorLengthParam()); 414f390781cSLorenzo Albano 415fa92d51fSAlexis Engelke const auto &DL = VPI.getDataLayout(); 416c00a44faSLorenzo Albano 417f390781cSLorenzo Albano Value *MaskParam = VPI.getMaskParam(); 418f390781cSLorenzo Albano Value *PtrParam = VPI.getMemoryPointerParam(); 419f390781cSLorenzo Albano Value *DataParam = VPI.getMemoryDataParam(); 420f390781cSLorenzo Albano bool IsUnmasked = isAllTrueMask(MaskParam); 421f390781cSLorenzo Albano 422f390781cSLorenzo Albano MaybeAlign AlignOpt = VPI.getPointerAlignment(); 423f390781cSLorenzo Albano 424f390781cSLorenzo Albano Value *NewMemoryInst = nullptr; 425f390781cSLorenzo Albano switch (VPI.getIntrinsicID()) { 426f390781cSLorenzo Albano default: 427f390781cSLorenzo Albano llvm_unreachable("Not a VP memory intrinsic"); 428f390781cSLorenzo Albano case Intrinsic::vp_store: 429f390781cSLorenzo Albano if (IsUnmasked) { 430f390781cSLorenzo Albano StoreInst *NewStore = 431f390781cSLorenzo Albano Builder.CreateStore(DataParam, PtrParam, /*IsVolatile*/ false); 43241ae78eaSKazu Hirata if (AlignOpt.has_value()) 43351b68573SFangrui Song NewStore->setAlignment(*AlignOpt); 434f390781cSLorenzo Albano NewMemoryInst = NewStore; 435f390781cSLorenzo Albano } else 436f390781cSLorenzo Albano NewMemoryInst = Builder.CreateMaskedStore( 437f390781cSLorenzo Albano DataParam, PtrParam, AlignOpt.valueOrOne(), MaskParam); 438f390781cSLorenzo Albano 439f390781cSLorenzo Albano break; 440f390781cSLorenzo Albano case Intrinsic::vp_load: 441f390781cSLorenzo Albano if (IsUnmasked) { 442f390781cSLorenzo Albano LoadInst *NewLoad = 443f390781cSLorenzo Albano Builder.CreateLoad(VPI.getType(), PtrParam, /*IsVolatile*/ false); 44441ae78eaSKazu Hirata if (AlignOpt.has_value()) 44551b68573SFangrui Song NewLoad->setAlignment(*AlignOpt); 446f390781cSLorenzo Albano NewMemoryInst = NewLoad; 447f390781cSLorenzo Albano } else 448f390781cSLorenzo Albano NewMemoryInst = Builder.CreateMaskedLoad( 449f390781cSLorenzo Albano VPI.getType(), PtrParam, AlignOpt.valueOrOne(), MaskParam); 450f390781cSLorenzo Albano 451f390781cSLorenzo Albano break; 452c00a44faSLorenzo Albano case Intrinsic::vp_scatter: { 453c00a44faSLorenzo Albano auto *ElementType = 454c00a44faSLorenzo Albano cast<VectorType>(DataParam->getType())->getElementType(); 455c00a44faSLorenzo Albano NewMemoryInst = Builder.CreateMaskedScatter( 456c00a44faSLorenzo Albano DataParam, PtrParam, 457bbbb4393SKazu Hirata AlignOpt.value_or(DL.getPrefTypeAlign(ElementType)), MaskParam); 458c00a44faSLorenzo Albano break; 459c00a44faSLorenzo Albano } 460c00a44faSLorenzo Albano case Intrinsic::vp_gather: { 461c00a44faSLorenzo Albano auto *ElementType = cast<VectorType>(VPI.getType())->getElementType(); 462c00a44faSLorenzo Albano NewMemoryInst = Builder.CreateMaskedGather( 463c00a44faSLorenzo Albano VPI.getType(), PtrParam, 464bbbb4393SKazu Hirata AlignOpt.value_or(DL.getPrefTypeAlign(ElementType)), MaskParam, nullptr, 465bbbb4393SKazu Hirata VPI.getName()); 466c00a44faSLorenzo Albano break; 467c00a44faSLorenzo Albano } 468f390781cSLorenzo Albano } 469f390781cSLorenzo Albano 470f390781cSLorenzo Albano assert(NewMemoryInst); 471f390781cSLorenzo Albano replaceOperation(*NewMemoryInst, VPI); 472f390781cSLorenzo Albano return NewMemoryInst; 473f390781cSLorenzo Albano } 474f390781cSLorenzo Albano 4753362e2d5SFraser Cormack Value *CachingVPExpander::expandPredicationInComparison(IRBuilder<> &Builder, 4763362e2d5SFraser Cormack VPCmpIntrinsic &VPI) { 4773362e2d5SFraser Cormack assert((maySpeculateLanes(VPI) || VPI.canIgnoreVectorLengthParam()) && 4783362e2d5SFraser Cormack "Implicitly dropping %evl in non-speculatable operator!"); 4793362e2d5SFraser Cormack 48008497a78SFraser Cormack assert(*VPI.getFunctionalOpcode() == Instruction::ICmp || 48108497a78SFraser Cormack *VPI.getFunctionalOpcode() == Instruction::FCmp); 4823362e2d5SFraser Cormack 4833362e2d5SFraser Cormack Value *Op0 = VPI.getOperand(0); 4843362e2d5SFraser Cormack Value *Op1 = VPI.getOperand(1); 4853362e2d5SFraser Cormack auto Pred = VPI.getPredicate(); 4863362e2d5SFraser Cormack 4873362e2d5SFraser Cormack auto *NewCmp = Builder.CreateCmp(Pred, Op0, Op1); 4883362e2d5SFraser Cormack 4893362e2d5SFraser Cormack replaceOperation(*NewCmp, VPI); 4903362e2d5SFraser Cormack return NewCmp; 4913362e2d5SFraser Cormack } 4923362e2d5SFraser Cormack 493e1a16cd8SRoger Ferrer Ibáñez bool CachingVPExpander::discardEVLParameter(VPIntrinsic &VPI) { 4941db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "Discard EVL parameter in " << VPI << "\n"); 4951db4dbbaSSimon Moll 4961db4dbbaSSimon Moll if (VPI.canIgnoreVectorLengthParam()) 497e1a16cd8SRoger Ferrer Ibáñez return false; 4981db4dbbaSSimon Moll 4991db4dbbaSSimon Moll Value *EVLParam = VPI.getVectorLengthParam(); 5001db4dbbaSSimon Moll if (!EVLParam) 501e1a16cd8SRoger Ferrer Ibáñez return false; 5021db4dbbaSSimon Moll 5031db4dbbaSSimon Moll ElementCount StaticElemCount = VPI.getStaticVectorLength(); 5041db4dbbaSSimon Moll Value *MaxEVL = nullptr; 5051db4dbbaSSimon Moll Type *Int32Ty = Type::getInt32Ty(VPI.getContext()); 5061db4dbbaSSimon Moll if (StaticElemCount.isScalable()) { 5071db4dbbaSSimon Moll // TODO add caching 508d75f9dd1SStephen Tozer IRBuilder<> Builder(VPI.getParent(), VPI.getIterator()); 5091db4dbbaSSimon Moll Value *FactorConst = Builder.getInt32(StaticElemCount.getKnownMinValue()); 51085c17e40SJay Foad Value *VScale = Builder.CreateIntrinsic(Intrinsic::vscale, Int32Ty, {}, 51185c17e40SJay Foad /*FMFSource=*/nullptr, "vscale"); 5121db4dbbaSSimon Moll MaxEVL = Builder.CreateMul(VScale, FactorConst, "scalable_size", 5131db4dbbaSSimon Moll /*NUW*/ true, /*NSW*/ false); 5141db4dbbaSSimon Moll } else { 5151db4dbbaSSimon Moll MaxEVL = ConstantInt::get(Int32Ty, StaticElemCount.getFixedValue(), false); 5161db4dbbaSSimon Moll } 5171db4dbbaSSimon Moll VPI.setVectorLengthParam(MaxEVL); 518e1a16cd8SRoger Ferrer Ibáñez return true; 5191db4dbbaSSimon Moll } 5201db4dbbaSSimon Moll 521e1a16cd8SRoger Ferrer Ibáñez std::pair<Value *, bool> CachingVPExpander::foldEVLIntoMask(VPIntrinsic &VPI) { 5221db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "Folding vlen for " << VPI << '\n'); 5231db4dbbaSSimon Moll 5241db4dbbaSSimon Moll IRBuilder<> Builder(&VPI); 5251db4dbbaSSimon Moll 5261db4dbbaSSimon Moll // Ineffective %evl parameter and so nothing to do here. 5271db4dbbaSSimon Moll if (VPI.canIgnoreVectorLengthParam()) 528e1a16cd8SRoger Ferrer Ibáñez return {&VPI, false}; 5291db4dbbaSSimon Moll 5301db4dbbaSSimon Moll // Only VP intrinsics can have an %evl parameter. 5311db4dbbaSSimon Moll Value *OldMaskParam = VPI.getMaskParam(); 5321db4dbbaSSimon Moll Value *OldEVLParam = VPI.getVectorLengthParam(); 5331db4dbbaSSimon Moll assert(OldMaskParam && "no mask param to fold the vl param into"); 5341db4dbbaSSimon Moll assert(OldEVLParam && "no EVL param to fold away"); 5351db4dbbaSSimon Moll 5361db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "OLD evl: " << *OldEVLParam << '\n'); 5371db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "OLD mask: " << *OldMaskParam << '\n'); 5381db4dbbaSSimon Moll 5391db4dbbaSSimon Moll // Convert the %evl predication into vector mask predication. 5401db4dbbaSSimon Moll ElementCount ElemCount = VPI.getStaticVectorLength(); 5411db4dbbaSSimon Moll Value *VLMask = convertEVLToMask(Builder, OldEVLParam, ElemCount); 5421db4dbbaSSimon Moll Value *NewMaskParam = Builder.CreateAnd(VLMask, OldMaskParam); 5431db4dbbaSSimon Moll VPI.setMaskParam(NewMaskParam); 5441db4dbbaSSimon Moll 5451db4dbbaSSimon Moll // Drop the %evl parameter. 5461db4dbbaSSimon Moll discardEVLParameter(VPI); 5471db4dbbaSSimon Moll assert(VPI.canIgnoreVectorLengthParam() && 5481db4dbbaSSimon Moll "transformation did not render the evl param ineffective!"); 5491db4dbbaSSimon Moll 5501db4dbbaSSimon Moll // Reassess the modified instruction. 551e1a16cd8SRoger Ferrer Ibáñez return {&VPI, true}; 5521db4dbbaSSimon Moll } 5531db4dbbaSSimon Moll 5541db4dbbaSSimon Moll Value *CachingVPExpander::expandPredication(VPIntrinsic &VPI) { 5551db4dbbaSSimon Moll LLVM_DEBUG(dbgs() << "Lowering to unpredicated op: " << VPI << '\n'); 5561db4dbbaSSimon Moll 5571db4dbbaSSimon Moll IRBuilder<> Builder(&VPI); 5581db4dbbaSSimon Moll 5591db4dbbaSSimon Moll // Try lowering to a LLVM instruction first. 56066963bf3SSimon Moll auto OC = VPI.getFunctionalOpcode(); 5611db4dbbaSSimon Moll 56266963bf3SSimon Moll if (OC && Instruction::isBinaryOp(*OC)) 5631db4dbbaSSimon Moll return expandPredicationInBinaryOperator(Builder, VPI); 5641db4dbbaSSimon Moll 565f3e90472SFraser Cormack if (auto *VPRI = dyn_cast<VPReductionIntrinsic>(&VPI)) 566f3e90472SFraser Cormack return expandPredicationInReduction(Builder, *VPRI); 567f3e90472SFraser Cormack 5683362e2d5SFraser Cormack if (auto *VPCmp = dyn_cast<VPCmpIntrinsic>(&VPI)) 5693362e2d5SFraser Cormack return expandPredicationInComparison(Builder, *VPCmp); 5703362e2d5SFraser Cormack 5711b622fffSliqin.weng if (VPCastIntrinsic::isVPCast(VPI.getIntrinsicID())) { 5721b622fffSliqin.weng return expandPredicationToCastIntrinsic(Builder, VPI); 5731b622fffSliqin.weng } 5741b622fffSliqin.weng 575f390781cSLorenzo Albano switch (VPI.getIntrinsicID()) { 576f390781cSLorenzo Albano default: 577f390781cSLorenzo Albano break; 578be932566SSimon Pilgrim case Intrinsic::vp_fneg: { 579be932566SSimon Pilgrim Value *NewNegOp = Builder.CreateFNeg(VPI.getOperand(0), VPI.getName()); 580be932566SSimon Pilgrim replaceOperation(*NewNegOp, VPI); 581be932566SSimon Pilgrim return NewNegOp; 582be932566SSimon Pilgrim } 58328e74e61Sliqin.weng case Intrinsic::vp_abs: 58428e74e61Sliqin.weng case Intrinsic::vp_smax: 58528e74e61Sliqin.weng case Intrinsic::vp_smin: 58628e74e61Sliqin.weng case Intrinsic::vp_umax: 58728e74e61Sliqin.weng case Intrinsic::vp_umin: 588111c7c1dSLiqinWeng case Intrinsic::vp_bswap: 589111c7c1dSLiqinWeng case Intrinsic::vp_bitreverse: 590d2484127SLiqinWeng case Intrinsic::vp_ctpop: 591d2484127SLiqinWeng case Intrinsic::vp_ctlz: 592d2484127SLiqinWeng case Intrinsic::vp_cttz: 593d2484127SLiqinWeng case Intrinsic::vp_sadd_sat: 594d2484127SLiqinWeng case Intrinsic::vp_uadd_sat: 595d2484127SLiqinWeng case Intrinsic::vp_ssub_sat: 596d2484127SLiqinWeng case Intrinsic::vp_usub_sat: 597d2484127SLiqinWeng case Intrinsic::vp_fshl: 598d2484127SLiqinWeng case Intrinsic::vp_fshr: 59902408d6bSLiqinWeng return expandPredicationToIntCall(Builder, VPI); 6000b7f53efSSimon Pilgrim case Intrinsic::vp_fabs: 6010b7f53efSSimon Pilgrim case Intrinsic::vp_sqrt: 6021eec3574Sliqin.weng case Intrinsic::vp_maxnum: 6031eec3574Sliqin.weng case Intrinsic::vp_minnum: 60458cfd563SSimeon K case Intrinsic::vp_maximum: 60558cfd563SSimeon K case Intrinsic::vp_minimum: 60679726ef5SKevin P. Neal case Intrinsic::vp_fma: 60779726ef5SKevin P. Neal case Intrinsic::vp_fmuladd: 60832f71977SLiqinWeng return expandPredicationToFPCall(Builder, VPI, 60932f71977SLiqinWeng VPI.getFunctionalIntrinsicID().value()); 610f390781cSLorenzo Albano case Intrinsic::vp_load: 611f390781cSLorenzo Albano case Intrinsic::vp_store: 612c00a44faSLorenzo Albano case Intrinsic::vp_gather: 613c00a44faSLorenzo Albano case Intrinsic::vp_scatter: 614f390781cSLorenzo Albano return expandPredicationInMemoryIntrinsic(Builder, VPI); 615f390781cSLorenzo Albano } 616f390781cSLorenzo Albano 6170b7f53efSSimon Pilgrim if (auto CID = VPI.getConstrainedIntrinsicID()) 6180b7f53efSSimon Pilgrim if (Value *Call = expandPredicationToFPCall(Builder, VPI, *CID)) 6190b7f53efSSimon Pilgrim return Call; 6200b7f53efSSimon Pilgrim 6211db4dbbaSSimon Moll return &VPI; 6221db4dbbaSSimon Moll } 6231db4dbbaSSimon Moll 6241db4dbbaSSimon Moll //// } CachingVPExpander 6251db4dbbaSSimon Moll 6266e127110SSimon Moll void sanitizeStrategy(VPIntrinsic &VPI, VPLegalization &LegalizeStrat) { 62718c1ee04SSimon Moll // Operations with speculatable lanes do not strictly need predication. 6286e127110SSimon Moll if (maySpeculateLanes(VPI)) { 6291db4dbbaSSimon Moll // Converting a speculatable VP intrinsic means dropping %mask and %evl. 6301db4dbbaSSimon Moll // No need to expand %evl into the %mask only to ignore that code. 6311db4dbbaSSimon Moll if (LegalizeStrat.OpStrategy == VPLegalization::Convert) 6321db4dbbaSSimon Moll LegalizeStrat.EVLParamStrategy = VPLegalization::Discard; 6331db4dbbaSSimon Moll return; 6341db4dbbaSSimon Moll } 6351db4dbbaSSimon Moll 6361db4dbbaSSimon Moll // We have to preserve the predicating effect of %evl for this 6371db4dbbaSSimon Moll // non-speculatable VP intrinsic. 6381db4dbbaSSimon Moll // 1) Never discard %evl. 6391db4dbbaSSimon Moll // 2) If this VP intrinsic will be expanded to non-VP code, make sure that 6401db4dbbaSSimon Moll // %evl gets folded into %mask. 6411db4dbbaSSimon Moll if ((LegalizeStrat.EVLParamStrategy == VPLegalization::Discard) || 6421db4dbbaSSimon Moll (LegalizeStrat.OpStrategy == VPLegalization::Convert)) { 6431db4dbbaSSimon Moll LegalizeStrat.EVLParamStrategy = VPLegalization::Convert; 6441db4dbbaSSimon Moll } 6451db4dbbaSSimon Moll } 6461db4dbbaSSimon Moll 6471db4dbbaSSimon Moll VPLegalization 6481db4dbbaSSimon Moll CachingVPExpander::getVPLegalizationStrategy(const VPIntrinsic &VPI) const { 6491db4dbbaSSimon Moll auto VPStrat = TTI.getVPLegalizationStrategy(VPI); 6501db4dbbaSSimon Moll if (LLVM_LIKELY(!UsingTTIOverrides)) { 6511db4dbbaSSimon Moll // No overrides - we are in production. 6521db4dbbaSSimon Moll return VPStrat; 6531db4dbbaSSimon Moll } 6541db4dbbaSSimon Moll 6551db4dbbaSSimon Moll // Overrides set - we are in testing, the following does not need to be 6561db4dbbaSSimon Moll // efficient. 6571db4dbbaSSimon Moll VPStrat.EVLParamStrategy = parseOverrideOption(EVLTransformOverride); 6581db4dbbaSSimon Moll VPStrat.OpStrategy = parseOverrideOption(MaskTransformOverride); 6591db4dbbaSSimon Moll return VPStrat; 6601db4dbbaSSimon Moll } 6611db4dbbaSSimon Moll 662e1a16cd8SRoger Ferrer Ibáñez VPExpansionDetails 663e1a16cd8SRoger Ferrer Ibáñez CachingVPExpander::expandVectorPredication(VPIntrinsic &VPI) { 664fa92d51fSAlexis Engelke auto Strategy = getVPLegalizationStrategy(VPI); 665fa92d51fSAlexis Engelke sanitizeStrategy(VPI, Strategy); 6661db4dbbaSSimon Moll 667e1a16cd8SRoger Ferrer Ibáñez VPExpansionDetails Changed = VPExpansionDetails::IntrinsicUnchanged; 668e1a16cd8SRoger Ferrer Ibáñez 6691db4dbbaSSimon Moll // Transform the EVL parameter. 670fa92d51fSAlexis Engelke switch (Strategy.EVLParamStrategy) { 6711db4dbbaSSimon Moll case VPLegalization::Legal: 6721db4dbbaSSimon Moll break; 6731db4dbbaSSimon Moll case VPLegalization::Discard: 674e1a16cd8SRoger Ferrer Ibáñez if (discardEVLParameter(VPI)) 675e1a16cd8SRoger Ferrer Ibáñez Changed = VPExpansionDetails::IntrinsicUpdated; 6761db4dbbaSSimon Moll break; 6771db4dbbaSSimon Moll case VPLegalization::Convert: 678e1a16cd8SRoger Ferrer Ibáñez if (auto [NewVPI, Folded] = foldEVLIntoMask(VPI); Folded) { 679e1a16cd8SRoger Ferrer Ibáñez (void)NewVPI; 680e1a16cd8SRoger Ferrer Ibáñez Changed = VPExpansionDetails::IntrinsicUpdated; 6811db4dbbaSSimon Moll ++NumFoldedVL; 682e1a16cd8SRoger Ferrer Ibáñez } 6831db4dbbaSSimon Moll break; 6841db4dbbaSSimon Moll } 6851db4dbbaSSimon Moll 6861db4dbbaSSimon Moll // Replace with a non-predicated operation. 687fa92d51fSAlexis Engelke switch (Strategy.OpStrategy) { 6881db4dbbaSSimon Moll case VPLegalization::Legal: 6891db4dbbaSSimon Moll break; 6901db4dbbaSSimon Moll case VPLegalization::Discard: 6911db4dbbaSSimon Moll llvm_unreachable("Invalid strategy for operators."); 6921db4dbbaSSimon Moll case VPLegalization::Convert: 693fa92d51fSAlexis Engelke if (Value *V = expandPredication(VPI); V != &VPI) { 6941db4dbbaSSimon Moll ++NumLoweredVPOps; 695e1a16cd8SRoger Ferrer Ibáñez Changed = VPExpansionDetails::IntrinsicReplaced; 6961db4dbbaSSimon Moll } 697fa92d51fSAlexis Engelke break; 6981db4dbbaSSimon Moll } 6991db4dbbaSSimon Moll 700e1a16cd8SRoger Ferrer Ibáñez return Changed; 7011db4dbbaSSimon Moll } 7021db4dbbaSSimon Moll } // namespace 7031db4dbbaSSimon Moll 704e1a16cd8SRoger Ferrer Ibáñez VPExpansionDetails 705e1a16cd8SRoger Ferrer Ibáñez llvm::expandVectorPredicationIntrinsic(VPIntrinsic &VPI, 706fa92d51fSAlexis Engelke const TargetTransformInfo &TTI) { 707fa92d51fSAlexis Engelke return CachingVPExpander(TTI).expandVectorPredication(VPI); 7081db4dbbaSSimon Moll } 709