brintos

brintos / llvm-project-archived public Read only

0
0
Text · 165.7 KiB · 6491a2c Raw
4426 lines · cpp
1//===- VPlanRecipes.cpp - Implementations for VPlan recipes ---------------===//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//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains implementations for different VPlan recipes.11///12//===----------------------------------------------------------------------===//13 14#include "LoopVectorizationPlanner.h"15#include "VPlan.h"16#include "VPlanAnalysis.h"17#include "VPlanHelpers.h"18#include "VPlanPatternMatch.h"19#include "VPlanUtils.h"20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/SmallVector.h"22#include "llvm/ADT/Twine.h"23#include "llvm/Analysis/AssumptionCache.h"24#include "llvm/Analysis/IVDescriptors.h"25#include "llvm/Analysis/LoopInfo.h"26#include "llvm/IR/BasicBlock.h"27#include "llvm/IR/IRBuilder.h"28#include "llvm/IR/Instruction.h"29#include "llvm/IR/Instructions.h"30#include "llvm/IR/Intrinsics.h"31#include "llvm/IR/Type.h"32#include "llvm/IR/Value.h"33#include "llvm/Support/Casting.h"34#include "llvm/Support/CommandLine.h"35#include "llvm/Support/Debug.h"36#include "llvm/Support/raw_ostream.h"37#include "llvm/Transforms/Utils/BasicBlockUtils.h"38#include "llvm/Transforms/Utils/LoopUtils.h"39#include <cassert>40 41using namespace llvm;42using namespace llvm::VPlanPatternMatch;43 44using VectorParts = SmallVector<Value *, 2>;45 46#define LV_NAME "loop-vectorize"47#define DEBUG_TYPE LV_NAME48 49bool VPRecipeBase::mayWriteToMemory() const {50  switch (getVPDefID()) {51  case VPExpressionSC:52    return cast<VPExpressionRecipe>(this)->mayReadOrWriteMemory();53  case VPInstructionSC: {54    auto *VPI = cast<VPInstruction>(this);55    // Loads read from memory but don't write to memory.56    if (VPI->getOpcode() == Instruction::Load)57      return false;58    return VPI->opcodeMayReadOrWriteFromMemory();59  }60  case VPInterleaveEVLSC:61  case VPInterleaveSC:62    return cast<VPInterleaveBase>(this)->getNumStoreOperands() > 0;63  case VPWidenStoreEVLSC:64  case VPWidenStoreSC:65    return true;66  case VPReplicateSC:67    return cast<Instruction>(getVPSingleValue()->getUnderlyingValue())68        ->mayWriteToMemory();69  case VPWidenCallSC:70    return !cast<VPWidenCallRecipe>(this)71                ->getCalledScalarFunction()72                ->onlyReadsMemory();73  case VPWidenIntrinsicSC:74    return cast<VPWidenIntrinsicRecipe>(this)->mayWriteToMemory();75  case VPCanonicalIVPHISC:76  case VPBranchOnMaskSC:77  case VPDerivedIVSC:78  case VPFirstOrderRecurrencePHISC:79  case VPReductionPHISC:80  case VPScalarIVStepsSC:81  case VPPredInstPHISC:82    return false;83  case VPBlendSC:84  case VPReductionEVLSC:85  case VPReductionSC:86  case VPVectorPointerSC:87  case VPWidenCanonicalIVSC:88  case VPWidenCastSC:89  case VPWidenGEPSC:90  case VPWidenIntOrFpInductionSC:91  case VPWidenLoadEVLSC:92  case VPWidenLoadSC:93  case VPWidenPHISC:94  case VPWidenPointerInductionSC:95  case VPWidenSC:96  case VPWidenSelectSC: {97    const Instruction *I =98        dyn_cast_or_null<Instruction>(getVPSingleValue()->getUnderlyingValue());99    (void)I;100    assert((!I || !I->mayWriteToMemory()) &&101           "underlying instruction may write to memory");102    return false;103  }104  default:105    return true;106  }107}108 109bool VPRecipeBase::mayReadFromMemory() const {110  switch (getVPDefID()) {111  case VPExpressionSC:112    return cast<VPExpressionRecipe>(this)->mayReadOrWriteMemory();113  case VPInstructionSC:114    return cast<VPInstruction>(this)->opcodeMayReadOrWriteFromMemory();115  case VPWidenLoadEVLSC:116  case VPWidenLoadSC:117    return true;118  case VPReplicateSC:119    return cast<Instruction>(getVPSingleValue()->getUnderlyingValue())120        ->mayReadFromMemory();121  case VPWidenCallSC:122    return !cast<VPWidenCallRecipe>(this)123                ->getCalledScalarFunction()124                ->onlyWritesMemory();125  case VPWidenIntrinsicSC:126    return cast<VPWidenIntrinsicRecipe>(this)->mayReadFromMemory();127  case VPBranchOnMaskSC:128  case VPDerivedIVSC:129  case VPFirstOrderRecurrencePHISC:130  case VPPredInstPHISC:131  case VPScalarIVStepsSC:132  case VPWidenStoreEVLSC:133  case VPWidenStoreSC:134    return false;135  case VPBlendSC:136  case VPReductionEVLSC:137  case VPReductionSC:138  case VPVectorPointerSC:139  case VPWidenCanonicalIVSC:140  case VPWidenCastSC:141  case VPWidenGEPSC:142  case VPWidenIntOrFpInductionSC:143  case VPWidenPHISC:144  case VPWidenPointerInductionSC:145  case VPWidenSC:146  case VPWidenSelectSC: {147    const Instruction *I =148        dyn_cast_or_null<Instruction>(getVPSingleValue()->getUnderlyingValue());149    (void)I;150    assert((!I || !I->mayReadFromMemory()) &&151           "underlying instruction may read from memory");152    return false;153  }154  default:155    // FIXME: Return false if the recipe represents an interleaved store.156    return true;157  }158}159 160bool VPRecipeBase::mayHaveSideEffects() const {161  switch (getVPDefID()) {162  case VPExpressionSC:163    return cast<VPExpressionRecipe>(this)->mayHaveSideEffects();164  case VPDerivedIVSC:165  case VPFirstOrderRecurrencePHISC:166  case VPPredInstPHISC:167  case VPVectorEndPointerSC:168    return false;169  case VPInstructionSC: {170    auto *VPI = cast<VPInstruction>(this);171    return mayWriteToMemory() ||172           VPI->getOpcode() == VPInstruction::BranchOnCount ||173           VPI->getOpcode() == VPInstruction::BranchOnCond;174  }175  case VPWidenCallSC: {176    Function *Fn = cast<VPWidenCallRecipe>(this)->getCalledScalarFunction();177    return mayWriteToMemory() || !Fn->doesNotThrow() || !Fn->willReturn();178  }179  case VPWidenIntrinsicSC:180    return cast<VPWidenIntrinsicRecipe>(this)->mayHaveSideEffects();181  case VPBlendSC:182  case VPReductionEVLSC:183  case VPReductionSC:184  case VPScalarIVStepsSC:185  case VPVectorPointerSC:186  case VPWidenCanonicalIVSC:187  case VPWidenCastSC:188  case VPWidenGEPSC:189  case VPWidenIntOrFpInductionSC:190  case VPWidenPHISC:191  case VPWidenPointerInductionSC:192  case VPWidenSC:193  case VPWidenSelectSC: {194    const Instruction *I =195        dyn_cast_or_null<Instruction>(getVPSingleValue()->getUnderlyingValue());196    (void)I;197    assert((!I || !I->mayHaveSideEffects()) &&198           "underlying instruction has side-effects");199    return false;200  }201  case VPInterleaveEVLSC:202  case VPInterleaveSC:203    return mayWriteToMemory();204  case VPWidenLoadEVLSC:205  case VPWidenLoadSC:206  case VPWidenStoreEVLSC:207  case VPWidenStoreSC:208    assert(209        cast<VPWidenMemoryRecipe>(this)->getIngredient().mayHaveSideEffects() ==210            mayWriteToMemory() &&211        "mayHaveSideffects result for ingredient differs from this "212        "implementation");213    return mayWriteToMemory();214  case VPReplicateSC: {215    auto *R = cast<VPReplicateRecipe>(this);216    return R->getUnderlyingInstr()->mayHaveSideEffects();217  }218  default:219    return true;220  }221}222 223void VPRecipeBase::insertBefore(VPRecipeBase *InsertPos) {224  assert(!Parent && "Recipe already in some VPBasicBlock");225  assert(InsertPos->getParent() &&226         "Insertion position not in any VPBasicBlock");227  InsertPos->getParent()->insert(this, InsertPos->getIterator());228}229 230void VPRecipeBase::insertBefore(VPBasicBlock &BB,231                                iplist<VPRecipeBase>::iterator I) {232  assert(!Parent && "Recipe already in some VPBasicBlock");233  assert(I == BB.end() || I->getParent() == &BB);234  BB.insert(this, I);235}236 237void VPRecipeBase::insertAfter(VPRecipeBase *InsertPos) {238  assert(!Parent && "Recipe already in some VPBasicBlock");239  assert(InsertPos->getParent() &&240         "Insertion position not in any VPBasicBlock");241  InsertPos->getParent()->insert(this, std::next(InsertPos->getIterator()));242}243 244void VPRecipeBase::removeFromParent() {245  assert(getParent() && "Recipe not in any VPBasicBlock");246  getParent()->getRecipeList().remove(getIterator());247  Parent = nullptr;248}249 250iplist<VPRecipeBase>::iterator VPRecipeBase::eraseFromParent() {251  assert(getParent() && "Recipe not in any VPBasicBlock");252  return getParent()->getRecipeList().erase(getIterator());253}254 255void VPRecipeBase::moveAfter(VPRecipeBase *InsertPos) {256  removeFromParent();257  insertAfter(InsertPos);258}259 260void VPRecipeBase::moveBefore(VPBasicBlock &BB,261                              iplist<VPRecipeBase>::iterator I) {262  removeFromParent();263  insertBefore(BB, I);264}265 266InstructionCost VPRecipeBase::cost(ElementCount VF, VPCostContext &Ctx) {267  // Get the underlying instruction for the recipe, if there is one. It is used268  // to269  //   * decide if cost computation should be skipped for this recipe,270  //   * apply forced target instruction cost.271  Instruction *UI = nullptr;272  if (auto *S = dyn_cast<VPSingleDefRecipe>(this))273    UI = dyn_cast_or_null<Instruction>(S->getUnderlyingValue());274  else if (auto *IG = dyn_cast<VPInterleaveBase>(this))275    UI = IG->getInsertPos();276  else if (auto *WidenMem = dyn_cast<VPWidenMemoryRecipe>(this))277    UI = &WidenMem->getIngredient();278 279  InstructionCost RecipeCost;280  if (UI && Ctx.skipCostComputation(UI, VF.isVector())) {281    RecipeCost = 0;282  } else {283    RecipeCost = computeCost(VF, Ctx);284    RecipeCost = computeCost(VF, Ctx);285    if (ForceTargetInstructionCost.getNumOccurrences() > 0 &&286        RecipeCost.isValid()) {287      if (UI)288        RecipeCost = InstructionCost(ForceTargetInstructionCost);289      else290        RecipeCost = InstructionCost(0);291    }292  }293 294  LLVM_DEBUG({295    dbgs() << "Cost of " << RecipeCost << " for VF " << VF << ": ";296    dump();297  });298  return RecipeCost;299}300 301InstructionCost VPRecipeBase::computeCost(ElementCount VF,302                                          VPCostContext &Ctx) const {303  llvm_unreachable("subclasses should implement computeCost");304}305 306bool VPRecipeBase::isPhi() const {307  return (getVPDefID() >= VPFirstPHISC && getVPDefID() <= VPLastPHISC) ||308         isa<VPPhi, VPIRPhi>(this);309}310 311bool VPRecipeBase::isScalarCast() const {312  auto *VPI = dyn_cast<VPInstruction>(this);313  return VPI && Instruction::isCast(VPI->getOpcode());314}315 316void VPIRFlags::intersectFlags(const VPIRFlags &Other) {317  assert(OpType == Other.OpType && "OpType must match");318  switch (OpType) {319  case OperationType::OverflowingBinOp:320    WrapFlags.HasNUW &= Other.WrapFlags.HasNUW;321    WrapFlags.HasNSW &= Other.WrapFlags.HasNSW;322    break;323  case OperationType::Trunc:324    TruncFlags.HasNUW &= Other.TruncFlags.HasNUW;325    TruncFlags.HasNSW &= Other.TruncFlags.HasNSW;326    break;327  case OperationType::DisjointOp:328    DisjointFlags.IsDisjoint &= Other.DisjointFlags.IsDisjoint;329    break;330  case OperationType::PossiblyExactOp:331    ExactFlags.IsExact &= Other.ExactFlags.IsExact;332    break;333  case OperationType::GEPOp:334    GEPFlags &= Other.GEPFlags;335    break;336  case OperationType::FPMathOp:337  case OperationType::FCmp:338    assert((OpType != OperationType::FCmp ||339            FCmpFlags.Pred == Other.FCmpFlags.Pred) &&340           "Cannot drop CmpPredicate");341    getFMFsRef().NoNaNs &= Other.getFMFsRef().NoNaNs;342    getFMFsRef().NoInfs &= Other.getFMFsRef().NoInfs;343    break;344  case OperationType::NonNegOp:345    NonNegFlags.NonNeg &= Other.NonNegFlags.NonNeg;346    break;347  case OperationType::Cmp:348    assert(CmpPredicate == Other.CmpPredicate && "Cannot drop CmpPredicate");349    break;350  case OperationType::Other:351    assert(AllFlags == Other.AllFlags && "Cannot drop other flags");352    break;353  }354}355 356FastMathFlags VPIRFlags::getFastMathFlags() const {357  assert((OpType == OperationType::FPMathOp || OpType == OperationType::FCmp) &&358         "recipe doesn't have fast math flags");359  const FastMathFlagsTy &F = getFMFsRef();360  FastMathFlags Res;361  Res.setAllowReassoc(F.AllowReassoc);362  Res.setNoNaNs(F.NoNaNs);363  Res.setNoInfs(F.NoInfs);364  Res.setNoSignedZeros(F.NoSignedZeros);365  Res.setAllowReciprocal(F.AllowReciprocal);366  Res.setAllowContract(F.AllowContract);367  Res.setApproxFunc(F.ApproxFunc);368  return Res;369}370 371#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)372void VPSingleDefRecipe::dump() const { VPDef::dump(); }373 374void VPRecipeBase::print(raw_ostream &O, const Twine &Indent,375                         VPSlotTracker &SlotTracker) const {376  printRecipe(O, Indent, SlotTracker);377  if (auto DL = getDebugLoc()) {378    O << ", !dbg ";379    DL.print(O);380  }381}382#endif383 384template <unsigned PartOpIdx>385VPValue *386VPUnrollPartAccessor<PartOpIdx>::getUnrollPartOperand(const VPUser &U) const {387  if (U.getNumOperands() == PartOpIdx + 1)388    return U.getOperand(PartOpIdx);389  return nullptr;390}391 392template <unsigned PartOpIdx>393unsigned VPUnrollPartAccessor<PartOpIdx>::getUnrollPart(const VPUser &U) const {394  if (auto *UnrollPartOp = getUnrollPartOperand(U))395    return cast<ConstantInt>(UnrollPartOp->getLiveInIRValue())->getZExtValue();396  return 0;397}398 399namespace llvm {400template class VPUnrollPartAccessor<1>;401template class VPUnrollPartAccessor<2>;402template class VPUnrollPartAccessor<3>;403}404 405VPInstruction::VPInstruction(unsigned Opcode, ArrayRef<VPValue *> Operands,406                             const VPIRFlags &Flags, const VPIRMetadata &MD,407                             DebugLoc DL, const Twine &Name)408    : VPRecipeWithIRFlags(VPDef::VPInstructionSC, Operands, Flags, DL),409      VPIRMetadata(MD), Opcode(Opcode), Name(Name.str()) {410  assert(flagsValidForOpcode(getOpcode()) &&411         "Set flags not supported for the provided opcode");412  assert((getNumOperandsForOpcode(Opcode) == -1u ||413          getNumOperandsForOpcode(Opcode) == getNumOperands()) &&414         "number of operands does not match opcode");415}416 417#ifndef NDEBUG418unsigned VPInstruction::getNumOperandsForOpcode(unsigned Opcode) {419  if (Instruction::isUnaryOp(Opcode) || Instruction::isCast(Opcode))420    return 1;421 422  if (Instruction::isBinaryOp(Opcode))423    return 2;424 425  switch (Opcode) {426  case VPInstruction::StepVector:427  case VPInstruction::VScale:428    return 0;429  case Instruction::Alloca:430  case Instruction::ExtractValue:431  case Instruction::Freeze:432  case Instruction::Load:433  case VPInstruction::BranchOnCond:434  case VPInstruction::Broadcast:435  case VPInstruction::BuildStructVector:436  case VPInstruction::BuildVector:437  case VPInstruction::CalculateTripCountMinusVF:438  case VPInstruction::CanonicalIVIncrementForPart:439  case VPInstruction::ExplicitVectorLength:440  case VPInstruction::ExtractLastElement:441  case VPInstruction::ExtractLastLanePerPart:442  case VPInstruction::ExtractPenultimateElement:443  case VPInstruction::Not:444  case VPInstruction::ResumeForEpilogue:445  case VPInstruction::Unpack:446    return 1;447  case Instruction::ICmp:448  case Instruction::FCmp:449  case Instruction::ExtractElement:450  case Instruction::Store:451  case VPInstruction::BranchOnCount:452  case VPInstruction::ComputeReductionResult:453  case VPInstruction::ExtractLane:454  case VPInstruction::FirstOrderRecurrenceSplice:455  case VPInstruction::LogicalAnd:456  case VPInstruction::PtrAdd:457  case VPInstruction::WidePtrAdd:458  case VPInstruction::WideIVStep:459    return 2;460  case Instruction::Select:461  case VPInstruction::ActiveLaneMask:462  case VPInstruction::ComputeAnyOfResult:463  case VPInstruction::ReductionStartVector:464    return 3;465  case VPInstruction::ComputeFindIVResult:466    return 4;467  case Instruction::Call:468  case Instruction::GetElementPtr:469  case Instruction::PHI:470  case Instruction::Switch:471  case VPInstruction::AnyOf:472  case VPInstruction::FirstActiveLane:473  case VPInstruction::LastActiveLane:474  case VPInstruction::SLPLoad:475  case VPInstruction::SLPStore:476    // Cannot determine the number of operands from the opcode.477    return -1u;478  }479  llvm_unreachable("all cases should be handled above");480}481#endif482 483bool VPInstruction::doesGeneratePerAllLanes() const {484  return Opcode == VPInstruction::PtrAdd && !vputils::onlyFirstLaneUsed(this);485}486 487bool VPInstruction::canGenerateScalarForFirstLane() const {488  if (Instruction::isBinaryOp(getOpcode()) || Instruction::isCast(getOpcode()))489    return true;490  if (isSingleScalar() || isVectorToScalar())491    return true;492  switch (Opcode) {493  case Instruction::Freeze:494  case Instruction::ICmp:495  case Instruction::PHI:496  case Instruction::Select:497  case VPInstruction::BranchOnCond:498  case VPInstruction::BranchOnCount:499  case VPInstruction::CalculateTripCountMinusVF:500  case VPInstruction::CanonicalIVIncrementForPart:501  case VPInstruction::PtrAdd:502  case VPInstruction::ExplicitVectorLength:503  case VPInstruction::AnyOf:504  case VPInstruction::Not:505    return true;506  default:507    return false;508  }509}510 511/// Create a conditional branch using \p Cond branching to the successors of \p512/// VPBB. Note that the first successor is always forward (i.e. not created yet)513/// while the second successor may already have been created (if it is a header514/// block and VPBB is a latch).515static BranchInst *createCondBranch(Value *Cond, VPBasicBlock *VPBB,516                                    VPTransformState &State) {517  // Replace the temporary unreachable terminator with a new conditional518  // branch, hooking it up to backward destination (header) for latch blocks519  // now, and to forward destination(s) later when they are created.520  // Second successor may be backwards - iff it is already in VPBB2IRBB.521  VPBasicBlock *SecondVPSucc = cast<VPBasicBlock>(VPBB->getSuccessors()[1]);522  BasicBlock *SecondIRSucc = State.CFG.VPBB2IRBB.lookup(SecondVPSucc);523  BasicBlock *IRBB = State.CFG.VPBB2IRBB[VPBB];524  BranchInst *CondBr = State.Builder.CreateCondBr(Cond, IRBB, SecondIRSucc);525  // First successor is always forward, reset it to nullptr526  CondBr->setSuccessor(0, nullptr);527  IRBB->getTerminator()->eraseFromParent();528  return CondBr;529}530 531Value *VPInstruction::generate(VPTransformState &State) {532  IRBuilderBase &Builder = State.Builder;533 534  if (Instruction::isBinaryOp(getOpcode())) {535    bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);536    Value *A = State.get(getOperand(0), OnlyFirstLaneUsed);537    Value *B = State.get(getOperand(1), OnlyFirstLaneUsed);538    auto *Res =539        Builder.CreateBinOp((Instruction::BinaryOps)getOpcode(), A, B, Name);540    if (auto *I = dyn_cast<Instruction>(Res))541      applyFlags(*I);542    return Res;543  }544 545  switch (getOpcode()) {546  case VPInstruction::Not: {547    bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);548    Value *A = State.get(getOperand(0), OnlyFirstLaneUsed);549    return Builder.CreateNot(A, Name);550  }551  case Instruction::ExtractElement: {552    assert(State.VF.isVector() && "Only extract elements from vectors");553    if (getOperand(1)->isLiveIn()) {554      unsigned IdxToExtract =555          cast<ConstantInt>(getOperand(1)->getLiveInIRValue())->getZExtValue();556      return State.get(getOperand(0), VPLane(IdxToExtract));557    }558    Value *Vec = State.get(getOperand(0));559    Value *Idx = State.get(getOperand(1), /*IsScalar=*/true);560    return Builder.CreateExtractElement(Vec, Idx, Name);561  }562  case Instruction::Freeze: {563    Value *Op = State.get(getOperand(0), vputils::onlyFirstLaneUsed(this));564    return Builder.CreateFreeze(Op, Name);565  }566  case Instruction::FCmp:567  case Instruction::ICmp: {568    bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);569    Value *A = State.get(getOperand(0), OnlyFirstLaneUsed);570    Value *B = State.get(getOperand(1), OnlyFirstLaneUsed);571    return Builder.CreateCmp(getPredicate(), A, B, Name);572  }573  case Instruction::PHI: {574    llvm_unreachable("should be handled by VPPhi::execute");575  }576  case Instruction::Select: {577    bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this);578    Value *Cond =579        State.get(getOperand(0),580                  OnlyFirstLaneUsed || vputils::isSingleScalar(getOperand(0)));581    Value *Op1 = State.get(getOperand(1), OnlyFirstLaneUsed);582    Value *Op2 = State.get(getOperand(2), OnlyFirstLaneUsed);583    return Builder.CreateSelect(Cond, Op1, Op2, Name);584  }585  case VPInstruction::ActiveLaneMask: {586    // Get first lane of vector induction variable.587    Value *VIVElem0 = State.get(getOperand(0), VPLane(0));588    // Get the original loop tripcount.589    Value *ScalarTC = State.get(getOperand(1), VPLane(0));590 591    // If this part of the active lane mask is scalar, generate the CMP directly592    // to avoid unnecessary extracts.593    if (State.VF.isScalar())594      return Builder.CreateCmp(CmpInst::Predicate::ICMP_ULT, VIVElem0, ScalarTC,595                               Name);596 597    ElementCount EC = State.VF.multiplyCoefficientBy(598        cast<ConstantInt>(getOperand(2)->getLiveInIRValue())->getZExtValue());599    auto *PredTy = VectorType::get(Builder.getInt1Ty(), EC);600    return Builder.CreateIntrinsic(Intrinsic::get_active_lane_mask,601                                   {PredTy, ScalarTC->getType()},602                                   {VIVElem0, ScalarTC}, nullptr, Name);603  }604  case VPInstruction::FirstOrderRecurrenceSplice: {605    // Generate code to combine the previous and current values in vector v3.606    //607    //   vector.ph:608    //     v_init = vector(..., ..., ..., a[-1])609    //     br vector.body610    //611    //   vector.body612    //     i = phi [0, vector.ph], [i+4, vector.body]613    //     v1 = phi [v_init, vector.ph], [v2, vector.body]614    //     v2 = a[i, i+1, i+2, i+3];615    //     v3 = vector(v1(3), v2(0, 1, 2))616 617    auto *V1 = State.get(getOperand(0));618    if (!V1->getType()->isVectorTy())619      return V1;620    Value *V2 = State.get(getOperand(1));621    return Builder.CreateVectorSplice(V1, V2, -1, Name);622  }623  case VPInstruction::CalculateTripCountMinusVF: {624    unsigned UF = getParent()->getPlan()->getUF();625    Value *ScalarTC = State.get(getOperand(0), VPLane(0));626    Value *Step = createStepForVF(Builder, ScalarTC->getType(), State.VF, UF);627    Value *Sub = Builder.CreateSub(ScalarTC, Step);628    Value *Cmp = Builder.CreateICmp(CmpInst::Predicate::ICMP_UGT, ScalarTC, Step);629    Value *Zero = ConstantInt::getNullValue(ScalarTC->getType());630    return Builder.CreateSelect(Cmp, Sub, Zero);631  }632  case VPInstruction::ExplicitVectorLength: {633    // TODO: Restructure this code with an explicit remainder loop, vsetvli can634    // be outside of the main loop.635    Value *AVL = State.get(getOperand(0), /*IsScalar*/ true);636    // Compute EVL637    assert(AVL->getType()->isIntegerTy() &&638           "Requested vector length should be an integer.");639 640    assert(State.VF.isScalable() && "Expected scalable vector factor.");641    Value *VFArg = Builder.getInt32(State.VF.getKnownMinValue());642 643    Value *EVL = Builder.CreateIntrinsic(644        Builder.getInt32Ty(), Intrinsic::experimental_get_vector_length,645        {AVL, VFArg, Builder.getTrue()});646    return EVL;647  }648  case VPInstruction::CanonicalIVIncrementForPart: {649    unsigned Part = getUnrollPart(*this);650    auto *IV = State.get(getOperand(0), VPLane(0));651    assert(Part != 0 && "Must have a positive part");652    // The canonical IV is incremented by the vectorization factor (num of653    // SIMD elements) times the unroll part.654    Value *Step = createStepForVF(Builder, IV->getType(), State.VF, Part);655    return Builder.CreateAdd(IV, Step, Name, hasNoUnsignedWrap(),656                             hasNoSignedWrap());657  }658  case VPInstruction::BranchOnCond: {659    Value *Cond = State.get(getOperand(0), VPLane(0));660    auto *Br = createCondBranch(Cond, getParent(), State);661    applyMetadata(*Br);662    return Br;663  }664  case VPInstruction::BranchOnCount: {665    // First create the compare.666    Value *IV = State.get(getOperand(0), /*IsScalar*/ true);667    Value *TC = State.get(getOperand(1), /*IsScalar*/ true);668    Value *Cond = Builder.CreateICmpEQ(IV, TC);669    return createCondBranch(Cond, getParent(), State);670  }671  case VPInstruction::Broadcast: {672    return Builder.CreateVectorSplat(673        State.VF, State.get(getOperand(0), /*IsScalar*/ true), "broadcast");674  }675  case VPInstruction::BuildStructVector: {676    // For struct types, we need to build a new 'wide' struct type, where each677    // element is widened, i.e., we create a struct of vectors.678    auto *StructTy =679        cast<StructType>(State.TypeAnalysis.inferScalarType(getOperand(0)));680    Value *Res = PoisonValue::get(toVectorizedTy(StructTy, State.VF));681    for (const auto &[LaneIndex, Op] : enumerate(operands())) {682      for (unsigned FieldIndex = 0; FieldIndex != StructTy->getNumElements();683           FieldIndex++) {684        Value *ScalarValue =685            Builder.CreateExtractValue(State.get(Op, true), FieldIndex);686        Value *VectorValue = Builder.CreateExtractValue(Res, FieldIndex);687        VectorValue =688            Builder.CreateInsertElement(VectorValue, ScalarValue, LaneIndex);689        Res = Builder.CreateInsertValue(Res, VectorValue, FieldIndex);690      }691    }692    return Res;693  }694  case VPInstruction::BuildVector: {695    auto *ScalarTy = State.TypeAnalysis.inferScalarType(getOperand(0));696    auto NumOfElements = ElementCount::getFixed(getNumOperands());697    Value *Res = PoisonValue::get(toVectorizedTy(ScalarTy, NumOfElements));698    for (const auto &[Idx, Op] : enumerate(operands()))699      Res = Builder.CreateInsertElement(Res, State.get(Op, true),700                                        Builder.getInt32(Idx));701    return Res;702  }703  case VPInstruction::ReductionStartVector: {704    if (State.VF.isScalar())705      return State.get(getOperand(0), true);706    IRBuilderBase::FastMathFlagGuard FMFG(Builder);707    Builder.setFastMathFlags(getFastMathFlags());708    // If this start vector is scaled then it should produce a vector with fewer709    // elements than the VF.710    ElementCount VF = State.VF.divideCoefficientBy(711        cast<ConstantInt>(getOperand(2)->getLiveInIRValue())->getZExtValue());712    auto *Iden = Builder.CreateVectorSplat(VF, State.get(getOperand(1), true));713    return Builder.CreateInsertElement(Iden, State.get(getOperand(0), true),714                                       Builder.getInt32(0));715  }716  case VPInstruction::ComputeAnyOfResult: {717    // FIXME: The cross-recipe dependency on VPReductionPHIRecipe is temporary718    // and will be removed by breaking up the recipe further.719    auto *PhiR = cast<VPReductionPHIRecipe>(getOperand(0));720    auto *OrigPhi = cast<PHINode>(PhiR->getUnderlyingValue());721    Value *ReducedPartRdx = State.get(getOperand(2));722    for (unsigned Idx = 3; Idx < getNumOperands(); ++Idx)723      ReducedPartRdx =724          Builder.CreateBinOp(Instruction::Or, State.get(getOperand(Idx)),725                              ReducedPartRdx, "bin.rdx");726    return createAnyOfReduction(Builder, ReducedPartRdx,727                                State.get(getOperand(1), VPLane(0)), OrigPhi);728  }729  case VPInstruction::ComputeFindIVResult: {730    // FIXME: The cross-recipe dependency on VPReductionPHIRecipe is temporary731    // and will be removed by breaking up the recipe further.732    auto *PhiR = cast<VPReductionPHIRecipe>(getOperand(0));733    // Get its reduction variable descriptor.734    RecurKind RK = PhiR->getRecurrenceKind();735    assert(RecurrenceDescriptor::isFindIVRecurrenceKind(RK) &&736           "Unexpected reduction kind");737    assert(!PhiR->isInLoop() &&738           "In-loop FindLastIV reduction is not supported yet");739 740    // The recipe's operands are the reduction phi, the start value, the741    // sentinel value, followed by one operand for each part of the reduction.742    unsigned UF = getNumOperands() - 3;743    Value *ReducedPartRdx = State.get(getOperand(3));744    RecurKind MinMaxKind;745    bool IsSigned = RecurrenceDescriptor::isSignedRecurrenceKind(RK);746    if (RecurrenceDescriptor::isFindLastIVRecurrenceKind(RK))747      MinMaxKind = IsSigned ? RecurKind::SMax : RecurKind::UMax;748    else749      MinMaxKind = IsSigned ? RecurKind::SMin : RecurKind::UMin;750    for (unsigned Part = 1; Part < UF; ++Part)751      ReducedPartRdx = createMinMaxOp(Builder, MinMaxKind, ReducedPartRdx,752                                      State.get(getOperand(3 + Part)));753 754    Value *Start = State.get(getOperand(1), true);755    Value *Sentinel = getOperand(2)->getLiveInIRValue();756    return createFindLastIVReduction(Builder, ReducedPartRdx, RK, Start,757                                     Sentinel);758  }759  case VPInstruction::ComputeReductionResult: {760    // FIXME: The cross-recipe dependency on VPReductionPHIRecipe is temporary761    // and will be removed by breaking up the recipe further.762    auto *PhiR = cast<VPReductionPHIRecipe>(getOperand(0));763    // Get its reduction variable descriptor.764 765    RecurKind RK = PhiR->getRecurrenceKind();766    assert(!RecurrenceDescriptor::isFindIVRecurrenceKind(RK) &&767           "should be handled by ComputeFindIVResult");768 769    // The recipe's operands are the reduction phi, followed by one operand for770    // each part of the reduction.771    unsigned UF = getNumOperands() - 1;772    VectorParts RdxParts(UF);773    for (unsigned Part = 0; Part < UF; ++Part)774      RdxParts[Part] = State.get(getOperand(1 + Part), PhiR->isInLoop());775 776    IRBuilderBase::FastMathFlagGuard FMFG(Builder);777    if (hasFastMathFlags())778      Builder.setFastMathFlags(getFastMathFlags());779 780    // Reduce all of the unrolled parts into a single vector.781    Value *ReducedPartRdx = RdxParts[0];782    if (PhiR->isOrdered()) {783      ReducedPartRdx = RdxParts[UF - 1];784    } else {785      // Floating-point operations should have some FMF to enable the reduction.786      for (unsigned Part = 1; Part < UF; ++Part) {787        Value *RdxPart = RdxParts[Part];788        if (RecurrenceDescriptor::isMinMaxRecurrenceKind(RK))789          ReducedPartRdx = createMinMaxOp(Builder, RK, ReducedPartRdx, RdxPart);790        else {791          // For sub-recurrences, each UF's reduction variable is already792          // negative, we need to do: reduce.add(-acc_uf0 + -acc_uf1)793          Instruction::BinaryOps Opcode =794              RK == RecurKind::Sub795                  ? Instruction::Add796                  : (Instruction::BinaryOps)RecurrenceDescriptor::getOpcode(RK);797          ReducedPartRdx =798              Builder.CreateBinOp(Opcode, RdxPart, ReducedPartRdx, "bin.rdx");799        }800      }801    }802 803    // Create the reduction after the loop. Note that inloop reductions create804    // the target reduction in the loop using a Reduction recipe.805    if (State.VF.isVector() && !PhiR->isInLoop()) {806      // TODO: Support in-order reductions based on the recurrence descriptor.807      // All ops in the reduction inherit fast-math-flags from the recurrence808      // descriptor.809      ReducedPartRdx = createSimpleReduction(Builder, ReducedPartRdx, RK);810    }811 812    return ReducedPartRdx;813  }814  case VPInstruction::ExtractLastLanePerPart:815  case VPInstruction::ExtractLastElement:816  case VPInstruction::ExtractPenultimateElement: {817    unsigned Offset =818        getOpcode() == VPInstruction::ExtractPenultimateElement ? 2 : 1;819    Value *Res;820    if (State.VF.isVector()) {821      assert(Offset <= State.VF.getKnownMinValue() &&822             "invalid offset to extract from");823      // Extract lane VF - Offset from the operand.824      Res = State.get(getOperand(0), VPLane::getLaneFromEnd(State.VF, Offset));825    } else {826      assert(Offset <= 1 && "invalid offset to extract from");827      Res = State.get(getOperand(0));828    }829    if (isa<ExtractElementInst>(Res))830      Res->setName(Name);831    return Res;832  }833  case VPInstruction::LogicalAnd: {834    Value *A = State.get(getOperand(0));835    Value *B = State.get(getOperand(1));836    return Builder.CreateLogicalAnd(A, B, Name);837  }838  case VPInstruction::PtrAdd: {839    assert(vputils::onlyFirstLaneUsed(this) &&840           "can only generate first lane for PtrAdd");841    Value *Ptr = State.get(getOperand(0), VPLane(0));842    Value *Addend = State.get(getOperand(1), VPLane(0));843    return Builder.CreatePtrAdd(Ptr, Addend, Name, getGEPNoWrapFlags());844  }845  case VPInstruction::WidePtrAdd: {846    Value *Ptr =847        State.get(getOperand(0), vputils::isSingleScalar(getOperand(0)));848    Value *Addend = State.get(getOperand(1));849    return Builder.CreatePtrAdd(Ptr, Addend, Name, getGEPNoWrapFlags());850  }851  case VPInstruction::AnyOf: {852    Value *Res = Builder.CreateFreeze(State.get(getOperand(0)));853    for (VPValue *Op : drop_begin(operands()))854      Res = Builder.CreateOr(Res, Builder.CreateFreeze(State.get(Op)));855    return State.VF.isScalar() ? Res : Builder.CreateOrReduce(Res);856  }857  case VPInstruction::ExtractLane: {858    Value *LaneToExtract = State.get(getOperand(0), true);859    Type *IdxTy = State.TypeAnalysis.inferScalarType(getOperand(0));860    Value *Res = nullptr;861    Value *RuntimeVF = getRuntimeVF(Builder, IdxTy, State.VF);862 863    for (unsigned Idx = 1; Idx != getNumOperands(); ++Idx) {864      Value *VectorStart =865          Builder.CreateMul(RuntimeVF, ConstantInt::get(IdxTy, Idx - 1));866      Value *VectorIdx = Idx == 1867                             ? LaneToExtract868                             : Builder.CreateSub(LaneToExtract, VectorStart);869      Value *Ext = State.VF.isScalar()870                       ? State.get(getOperand(Idx))871                       : Builder.CreateExtractElement(872                             State.get(getOperand(Idx)), VectorIdx);873      if (Res) {874        Value *Cmp = Builder.CreateICmpUGE(LaneToExtract, VectorStart);875        Res = Builder.CreateSelect(Cmp, Ext, Res);876      } else {877        Res = Ext;878      }879    }880    return Res;881  }882  case VPInstruction::FirstActiveLane: {883    if (getNumOperands() == 1) {884      Value *Mask = State.get(getOperand(0));885      return Builder.CreateCountTrailingZeroElems(Builder.getInt64Ty(), Mask,886                                                  /*ZeroIsPoison=*/false, Name);887    }888    // If there are multiple operands, create a chain of selects to pick the889    // first operand with an active lane and add the number of lanes of the890    // preceding operands.891    Value *RuntimeVF = getRuntimeVF(Builder, Builder.getInt64Ty(), State.VF);892    unsigned LastOpIdx = getNumOperands() - 1;893    Value *Res = nullptr;894    for (int Idx = LastOpIdx; Idx >= 0; --Idx) {895      Value *TrailingZeros =896          State.VF.isScalar()897              ? Builder.CreateZExt(898                    Builder.CreateICmpEQ(State.get(getOperand(Idx)),899                                         Builder.getFalse()),900                    Builder.getInt64Ty())901              : Builder.CreateCountTrailingZeroElems(902                    Builder.getInt64Ty(), State.get(getOperand(Idx)),903                    /*ZeroIsPoison=*/false, Name);904      Value *Current = Builder.CreateAdd(905          Builder.CreateMul(RuntimeVF, Builder.getInt64(Idx)), TrailingZeros);906      if (Res) {907        Value *Cmp = Builder.CreateICmpNE(TrailingZeros, RuntimeVF);908        Res = Builder.CreateSelect(Cmp, Current, Res);909      } else {910        Res = Current;911      }912    }913 914    return Res;915  }916  case VPInstruction::ResumeForEpilogue:917    return State.get(getOperand(0), true);918  default:919    llvm_unreachable("Unsupported opcode for instruction");920  }921}922 923InstructionCost VPRecipeWithIRFlags::getCostForRecipeWithOpcode(924    unsigned Opcode, ElementCount VF, VPCostContext &Ctx) const {925  Type *ScalarTy = Ctx.Types.inferScalarType(this);926  Type *ResultTy = VF.isVector() ? toVectorTy(ScalarTy, VF) : ScalarTy;927  switch (Opcode) {928  case Instruction::FNeg:929    return Ctx.TTI.getArithmeticInstrCost(Opcode, ResultTy, Ctx.CostKind);930  case Instruction::UDiv:931  case Instruction::SDiv:932  case Instruction::SRem:933  case Instruction::URem:934  case Instruction::Add:935  case Instruction::FAdd:936  case Instruction::Sub:937  case Instruction::FSub:938  case Instruction::Mul:939  case Instruction::FMul:940  case Instruction::FDiv:941  case Instruction::FRem:942  case Instruction::Shl:943  case Instruction::LShr:944  case Instruction::AShr:945  case Instruction::And:946  case Instruction::Or:947  case Instruction::Xor: {948    TargetTransformInfo::OperandValueInfo RHSInfo = {949        TargetTransformInfo::OK_AnyValue, TargetTransformInfo::OP_None};950 951    if (VF.isVector()) {952      // Certain instructions can be cheaper to vectorize if they have a953      // constant second vector operand. One example of this are shifts on x86.954      VPValue *RHS = getOperand(1);955      RHSInfo = Ctx.getOperandInfo(RHS);956 957      if (RHSInfo.Kind == TargetTransformInfo::OK_AnyValue &&958          getOperand(1)->isDefinedOutsideLoopRegions())959        RHSInfo.Kind = TargetTransformInfo::OK_UniformValue;960    }961 962    Instruction *CtxI = dyn_cast_or_null<Instruction>(getUnderlyingValue());963    SmallVector<const Value *, 4> Operands;964    if (CtxI)965      Operands.append(CtxI->value_op_begin(), CtxI->value_op_end());966    return Ctx.TTI.getArithmeticInstrCost(967        Opcode, ResultTy, Ctx.CostKind,968        {TargetTransformInfo::OK_AnyValue, TargetTransformInfo::OP_None},969        RHSInfo, Operands, CtxI, &Ctx.TLI);970  }971  case Instruction::Freeze:972    // This opcode is unknown. Assume that it is the same as 'mul'.973    return Ctx.TTI.getArithmeticInstrCost(Instruction::Mul, ResultTy,974                                          Ctx.CostKind);975  case Instruction::ExtractValue:976    return Ctx.TTI.getInsertExtractValueCost(Instruction::ExtractValue,977                                             Ctx.CostKind);978  case Instruction::ICmp:979  case Instruction::FCmp: {980    Type *ScalarOpTy = Ctx.Types.inferScalarType(getOperand(0));981    Type *OpTy = VF.isVector() ? toVectorTy(ScalarOpTy, VF) : ScalarOpTy;982    Instruction *CtxI = dyn_cast_or_null<Instruction>(getUnderlyingValue());983    return Ctx.TTI.getCmpSelInstrCost(984        Opcode, OpTy, CmpInst::makeCmpResultType(OpTy), getPredicate(),985        Ctx.CostKind, {TTI::OK_AnyValue, TTI::OP_None},986        {TTI::OK_AnyValue, TTI::OP_None}, CtxI);987  }988  }989  llvm_unreachable("called for unsupported opcode");990}991 992InstructionCost VPInstruction::computeCost(ElementCount VF,993                                           VPCostContext &Ctx) const {994  if (Instruction::isBinaryOp(getOpcode())) {995    if (!getUnderlyingValue() && getOpcode() != Instruction::FMul) {996      // TODO: Compute cost for VPInstructions without underlying values once997      // the legacy cost model has been retired.998      return 0;999    }1000 1001    assert(!doesGeneratePerAllLanes() &&1002           "Should only generate a vector value or single scalar, not scalars "1003           "for all lanes.");1004    return getCostForRecipeWithOpcode(1005        getOpcode(),1006        vputils::onlyFirstLaneUsed(this) ? ElementCount::getFixed(1) : VF, Ctx);1007  }1008 1009  switch (getOpcode()) {1010  case Instruction::Select: {1011    // TODO: It may be possible to improve this by analyzing where the1012    // condition operand comes from.1013    CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;1014    auto *CondTy = Ctx.Types.inferScalarType(getOperand(0));1015    auto *VecTy = Ctx.Types.inferScalarType(getOperand(1));1016    if (!vputils::onlyFirstLaneUsed(this)) {1017      CondTy = toVectorTy(CondTy, VF);1018      VecTy = toVectorTy(VecTy, VF);1019    }1020    return Ctx.TTI.getCmpSelInstrCost(Instruction::Select, VecTy, CondTy, Pred,1021                                      Ctx.CostKind);1022  }1023  case Instruction::ExtractElement:1024  case VPInstruction::ExtractLane: {1025    if (VF.isScalar()) {1026      // ExtractLane with VF=1 takes care of handling extracting across multiple1027      // parts.1028      return 0;1029    }1030 1031    // Add on the cost of extracting the element.1032    auto *VecTy = toVectorTy(Ctx.Types.inferScalarType(getOperand(0)), VF);1033    return Ctx.TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy,1034                                      Ctx.CostKind);1035  }1036  case VPInstruction::AnyOf: {1037    auto *VecTy = toVectorTy(Ctx.Types.inferScalarType(this), VF);1038    return Ctx.TTI.getArithmeticReductionCost(1039        Instruction::Or, cast<VectorType>(VecTy), std::nullopt, Ctx.CostKind);1040  }1041  case VPInstruction::FirstActiveLane: {1042    Type *ScalarTy = Ctx.Types.inferScalarType(getOperand(0));1043    if (VF.isScalar())1044      return Ctx.TTI.getCmpSelInstrCost(Instruction::ICmp, ScalarTy,1045                                        CmpInst::makeCmpResultType(ScalarTy),1046                                        CmpInst::ICMP_EQ, Ctx.CostKind);1047    // Calculate the cost of determining the lane index.1048    auto *PredTy = toVectorTy(ScalarTy, VF);1049    IntrinsicCostAttributes Attrs(Intrinsic::experimental_cttz_elts,1050                                  Type::getInt64Ty(Ctx.LLVMCtx),1051                                  {PredTy, Type::getInt1Ty(Ctx.LLVMCtx)});1052    return Ctx.TTI.getIntrinsicInstrCost(Attrs, Ctx.CostKind);1053  }1054  case VPInstruction::LastActiveLane: {1055    Type *ScalarTy = Ctx.Types.inferScalarType(getOperand(0));1056    if (VF.isScalar())1057      return Ctx.TTI.getCmpSelInstrCost(Instruction::ICmp, ScalarTy,1058                                        CmpInst::makeCmpResultType(ScalarTy),1059                                        CmpInst::ICMP_EQ, Ctx.CostKind);1060    // Calculate the cost of determining the lane index: NOT + cttz_elts + SUB.1061    auto *PredTy = toVectorTy(ScalarTy, VF);1062    IntrinsicCostAttributes Attrs(Intrinsic::experimental_cttz_elts,1063                                  Type::getInt64Ty(Ctx.LLVMCtx),1064                                  {PredTy, Type::getInt1Ty(Ctx.LLVMCtx)});1065    InstructionCost Cost = Ctx.TTI.getIntrinsicInstrCost(Attrs, Ctx.CostKind);1066    // Add cost of NOT operation on the predicate.1067    Cost += Ctx.TTI.getArithmeticInstrCost(1068        Instruction::Xor, PredTy, Ctx.CostKind,1069        {TargetTransformInfo::OK_AnyValue, TargetTransformInfo::OP_None},1070        {TargetTransformInfo::OK_UniformConstantValue,1071         TargetTransformInfo::OP_None});1072    // Add cost of SUB operation on the index.1073    Cost += Ctx.TTI.getArithmeticInstrCost(1074        Instruction::Sub, Type::getInt64Ty(Ctx.LLVMCtx), Ctx.CostKind);1075    return Cost;1076  }1077  case VPInstruction::FirstOrderRecurrenceSplice: {1078    assert(VF.isVector() && "Scalar FirstOrderRecurrenceSplice?");1079    SmallVector<int> Mask(VF.getKnownMinValue());1080    std::iota(Mask.begin(), Mask.end(), VF.getKnownMinValue() - 1);1081    Type *VectorTy = toVectorTy(Ctx.Types.inferScalarType(this), VF);1082 1083    return Ctx.TTI.getShuffleCost(TargetTransformInfo::SK_Splice,1084                                  cast<VectorType>(VectorTy),1085                                  cast<VectorType>(VectorTy), Mask,1086                                  Ctx.CostKind, VF.getKnownMinValue() - 1);1087  }1088  case VPInstruction::ActiveLaneMask: {1089    Type *ArgTy = Ctx.Types.inferScalarType(getOperand(0));1090    unsigned Multiplier =1091        cast<ConstantInt>(getOperand(2)->getLiveInIRValue())->getZExtValue();1092    Type *RetTy = toVectorTy(Type::getInt1Ty(Ctx.LLVMCtx), VF * Multiplier);1093    IntrinsicCostAttributes Attrs(Intrinsic::get_active_lane_mask, RetTy,1094                                  {ArgTy, ArgTy});1095    return Ctx.TTI.getIntrinsicInstrCost(Attrs, Ctx.CostKind);1096  }1097  case VPInstruction::ExplicitVectorLength: {1098    Type *Arg0Ty = Ctx.Types.inferScalarType(getOperand(0));1099    Type *I32Ty = Type::getInt32Ty(Ctx.LLVMCtx);1100    Type *I1Ty = Type::getInt1Ty(Ctx.LLVMCtx);1101    IntrinsicCostAttributes Attrs(Intrinsic::experimental_get_vector_length,1102                                  I32Ty, {Arg0Ty, I32Ty, I1Ty});1103    return Ctx.TTI.getIntrinsicInstrCost(Attrs, Ctx.CostKind);1104  }1105  case VPInstruction::ExtractLastElement: {1106    // Add on the cost of extracting the element.1107    auto *VecTy = toVectorTy(Ctx.Types.inferScalarType(getOperand(0)), VF);1108    return Ctx.TTI.getIndexedVectorInstrCostFromEnd(Instruction::ExtractElement,1109                                                    VecTy, Ctx.CostKind, 0);1110  }1111  case VPInstruction::ExtractPenultimateElement:1112    if (VF == ElementCount::getScalable(1))1113      return InstructionCost::getInvalid();1114    [[fallthrough]];1115  default:1116    // TODO: Compute cost other VPInstructions once the legacy cost model has1117    // been retired.1118    assert(!getUnderlyingValue() &&1119           "unexpected VPInstruction witht underlying value");1120    return 0;1121  }1122}1123 1124bool VPInstruction::isVectorToScalar() const {1125  return getOpcode() == VPInstruction::ExtractLastElement ||1126         getOpcode() == VPInstruction::ExtractLastLanePerPart ||1127         getOpcode() == VPInstruction::ExtractPenultimateElement ||1128         getOpcode() == Instruction::ExtractElement ||1129         getOpcode() == VPInstruction::ExtractLane ||1130         getOpcode() == VPInstruction::FirstActiveLane ||1131         getOpcode() == VPInstruction::LastActiveLane ||1132         getOpcode() == VPInstruction::ComputeAnyOfResult ||1133         getOpcode() == VPInstruction::ComputeFindIVResult ||1134         getOpcode() == VPInstruction::ComputeReductionResult ||1135         getOpcode() == VPInstruction::AnyOf;1136}1137 1138bool VPInstruction::isSingleScalar() const {1139  switch (getOpcode()) {1140  case Instruction::PHI:1141  case VPInstruction::ExplicitVectorLength:1142  case VPInstruction::ResumeForEpilogue:1143  case VPInstruction::VScale:1144    return true;1145  default:1146    return isScalarCast();1147  }1148}1149 1150void VPInstruction::execute(VPTransformState &State) {1151  assert(!State.Lane && "VPInstruction executing an Lane");1152  IRBuilderBase::FastMathFlagGuard FMFGuard(State.Builder);1153  assert(flagsValidForOpcode(getOpcode()) &&1154         "Set flags not supported for the provided opcode");1155  if (hasFastMathFlags())1156    State.Builder.setFastMathFlags(getFastMathFlags());1157  Value *GeneratedValue = generate(State);1158  if (!hasResult())1159    return;1160  assert(GeneratedValue && "generate must produce a value");1161  bool GeneratesPerFirstLaneOnly = canGenerateScalarForFirstLane() &&1162                                   (vputils::onlyFirstLaneUsed(this) ||1163                                    isVectorToScalar() || isSingleScalar());1164  assert((((GeneratedValue->getType()->isVectorTy() ||1165            GeneratedValue->getType()->isStructTy()) ==1166           !GeneratesPerFirstLaneOnly) ||1167          State.VF.isScalar()) &&1168         "scalar value but not only first lane defined");1169  State.set(this, GeneratedValue,1170            /*IsScalar*/ GeneratesPerFirstLaneOnly);1171}1172 1173bool VPInstruction::opcodeMayReadOrWriteFromMemory() const {1174  if (Instruction::isBinaryOp(getOpcode()) || Instruction::isCast(getOpcode()))1175    return false;1176  switch (getOpcode()) {1177  case Instruction::GetElementPtr:1178  case Instruction::ExtractElement:1179  case Instruction::Freeze:1180  case Instruction::FCmp:1181  case Instruction::ICmp:1182  case Instruction::Select:1183  case Instruction::PHI:1184  case VPInstruction::AnyOf:1185  case VPInstruction::BranchOnCond:1186  case VPInstruction::BranchOnCount:1187  case VPInstruction::Broadcast:1188  case VPInstruction::BuildStructVector:1189  case VPInstruction::BuildVector:1190  case VPInstruction::CalculateTripCountMinusVF:1191  case VPInstruction::CanonicalIVIncrementForPart:1192  case VPInstruction::ExtractLane:1193  case VPInstruction::ExtractLastElement:1194  case VPInstruction::ExtractLastLanePerPart:1195  case VPInstruction::ExtractPenultimateElement:1196  case VPInstruction::ActiveLaneMask:1197  case VPInstruction::ExplicitVectorLength:1198  case VPInstruction::FirstActiveLane:1199  case VPInstruction::LastActiveLane:1200  case VPInstruction::FirstOrderRecurrenceSplice:1201  case VPInstruction::LogicalAnd:1202  case VPInstruction::Not:1203  case VPInstruction::PtrAdd:1204  case VPInstruction::WideIVStep:1205  case VPInstruction::WidePtrAdd:1206  case VPInstruction::StepVector:1207  case VPInstruction::ReductionStartVector:1208  case VPInstruction::VScale:1209  case VPInstruction::Unpack:1210    return false;1211  default:1212    return true;1213  }1214}1215 1216bool VPInstruction::usesFirstLaneOnly(const VPValue *Op) const {1217  assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");1218  if (Instruction::isBinaryOp(getOpcode()) || Instruction::isCast(getOpcode()))1219    return vputils::onlyFirstLaneUsed(this);1220 1221  switch (getOpcode()) {1222  default:1223    return false;1224  case Instruction::ExtractElement:1225    return Op == getOperand(1);1226  case Instruction::PHI:1227    return true;1228  case Instruction::FCmp:1229  case Instruction::ICmp:1230  case Instruction::Select:1231  case Instruction::Or:1232  case Instruction::Freeze:1233  case VPInstruction::Not:1234    // TODO: Cover additional opcodes.1235    return vputils::onlyFirstLaneUsed(this);1236  case VPInstruction::ActiveLaneMask:1237  case VPInstruction::ExplicitVectorLength:1238  case VPInstruction::CalculateTripCountMinusVF:1239  case VPInstruction::CanonicalIVIncrementForPart:1240  case VPInstruction::BranchOnCount:1241  case VPInstruction::BranchOnCond:1242  case VPInstruction::Broadcast:1243  case VPInstruction::ReductionStartVector:1244    return true;1245  case VPInstruction::BuildStructVector:1246  case VPInstruction::BuildVector:1247    // Before replicating by VF, Build(Struct)Vector uses all lanes of the1248    // operand, after replicating its operands only the first lane is used.1249    // Before replicating, it will have only a single operand.1250    return getNumOperands() > 1;1251  case VPInstruction::PtrAdd:1252    return Op == getOperand(0) || vputils::onlyFirstLaneUsed(this);1253  case VPInstruction::WidePtrAdd:1254    // WidePtrAdd supports scalar and vector base addresses.1255    return false;1256  case VPInstruction::ComputeAnyOfResult:1257  case VPInstruction::ComputeFindIVResult:1258    return Op == getOperand(1);1259  case VPInstruction::ExtractLane:1260    return Op == getOperand(0);1261  };1262  llvm_unreachable("switch should return");1263}1264 1265bool VPInstruction::usesFirstPartOnly(const VPValue *Op) const {1266  assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");1267  if (Instruction::isBinaryOp(getOpcode()))1268    return vputils::onlyFirstPartUsed(this);1269 1270  switch (getOpcode()) {1271  default:1272    return false;1273  case Instruction::FCmp:1274  case Instruction::ICmp:1275  case Instruction::Select:1276    return vputils::onlyFirstPartUsed(this);1277  case VPInstruction::BranchOnCount:1278  case VPInstruction::BranchOnCond:1279  case VPInstruction::CanonicalIVIncrementForPart:1280    return true;1281  };1282  llvm_unreachable("switch should return");1283}1284 1285#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1286void VPInstruction::dump() const {1287  VPSlotTracker SlotTracker(getParent()->getPlan());1288  printRecipe(dbgs(), "", SlotTracker);1289}1290 1291void VPInstruction::printRecipe(raw_ostream &O, const Twine &Indent,1292                                VPSlotTracker &SlotTracker) const {1293  O << Indent << "EMIT" << (isSingleScalar() ? "-SCALAR" : "") << " ";1294 1295  if (hasResult()) {1296    printAsOperand(O, SlotTracker);1297    O << " = ";1298  }1299 1300  switch (getOpcode()) {1301  case VPInstruction::Not:1302    O << "not";1303    break;1304  case VPInstruction::SLPLoad:1305    O << "combined load";1306    break;1307  case VPInstruction::SLPStore:1308    O << "combined store";1309    break;1310  case VPInstruction::ActiveLaneMask:1311    O << "active lane mask";1312    break;1313  case VPInstruction::ExplicitVectorLength:1314    O << "EXPLICIT-VECTOR-LENGTH";1315    break;1316  case VPInstruction::FirstOrderRecurrenceSplice:1317    O << "first-order splice";1318    break;1319  case VPInstruction::BranchOnCond:1320    O << "branch-on-cond";1321    break;1322  case VPInstruction::CalculateTripCountMinusVF:1323    O << "TC > VF ? TC - VF : 0";1324    break;1325  case VPInstruction::CanonicalIVIncrementForPart:1326    O << "VF * Part +";1327    break;1328  case VPInstruction::BranchOnCount:1329    O << "branch-on-count";1330    break;1331  case VPInstruction::Broadcast:1332    O << "broadcast";1333    break;1334  case VPInstruction::BuildStructVector:1335    O << "buildstructvector";1336    break;1337  case VPInstruction::BuildVector:1338    O << "buildvector";1339    break;1340  case VPInstruction::ExtractLane:1341    O << "extract-lane";1342    break;1343  case VPInstruction::ExtractLastElement:1344    O << "extract-last-element";1345    break;1346  case VPInstruction::ExtractLastLanePerPart:1347    O << "extract-last-lane-per-part";1348    break;1349  case VPInstruction::ExtractPenultimateElement:1350    O << "extract-penultimate-element";1351    break;1352  case VPInstruction::ComputeAnyOfResult:1353    O << "compute-anyof-result";1354    break;1355  case VPInstruction::ComputeFindIVResult:1356    O << "compute-find-iv-result";1357    break;1358  case VPInstruction::ComputeReductionResult:1359    O << "compute-reduction-result";1360    break;1361  case VPInstruction::LogicalAnd:1362    O << "logical-and";1363    break;1364  case VPInstruction::PtrAdd:1365    O << "ptradd";1366    break;1367  case VPInstruction::WidePtrAdd:1368    O << "wide-ptradd";1369    break;1370  case VPInstruction::AnyOf:1371    O << "any-of";1372    break;1373  case VPInstruction::FirstActiveLane:1374    O << "first-active-lane";1375    break;1376  case VPInstruction::LastActiveLane:1377    O << "last-active-lane";1378    break;1379  case VPInstruction::ReductionStartVector:1380    O << "reduction-start-vector";1381    break;1382  case VPInstruction::ResumeForEpilogue:1383    O << "resume-for-epilogue";1384    break;1385  case VPInstruction::Unpack:1386    O << "unpack";1387    break;1388  default:1389    O << Instruction::getOpcodeName(getOpcode());1390  }1391 1392  printFlags(O);1393  printOperands(O, SlotTracker);1394}1395#endif1396 1397void VPInstructionWithType::execute(VPTransformState &State) {1398  State.setDebugLocFrom(getDebugLoc());1399  if (isScalarCast()) {1400    Value *Op = State.get(getOperand(0), VPLane(0));1401    Value *Cast = State.Builder.CreateCast(Instruction::CastOps(getOpcode()),1402                                           Op, ResultTy);1403    State.set(this, Cast, VPLane(0));1404    return;1405  }1406  switch (getOpcode()) {1407  case VPInstruction::StepVector: {1408    Value *StepVector =1409        State.Builder.CreateStepVector(VectorType::get(ResultTy, State.VF));1410    State.set(this, StepVector);1411    break;1412  }1413  case VPInstruction::VScale: {1414    Value *VScale = State.Builder.CreateVScale(ResultTy);1415    State.set(this, VScale, true);1416    break;1417  }1418 1419  default:1420    llvm_unreachable("opcode not implemented yet");1421  }1422}1423 1424#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1425void VPInstructionWithType::printRecipe(raw_ostream &O, const Twine &Indent,1426                                        VPSlotTracker &SlotTracker) const {1427  O << Indent << "EMIT" << (isSingleScalar() ? "-SCALAR" : "") << " ";1428  printAsOperand(O, SlotTracker);1429  O << " = ";1430 1431  switch (getOpcode()) {1432  case VPInstruction::WideIVStep:1433    O << "wide-iv-step ";1434    printOperands(O, SlotTracker);1435    break;1436  case VPInstruction::StepVector:1437    O << "step-vector " << *ResultTy;1438    break;1439  case VPInstruction::VScale:1440    O << "vscale " << *ResultTy;1441    break;1442  default:1443    assert(Instruction::isCast(getOpcode()) && "unhandled opcode");1444    O << Instruction::getOpcodeName(getOpcode()) << " ";1445    printOperands(O, SlotTracker);1446    O << " to " << *ResultTy;1447  }1448}1449#endif1450 1451void VPPhi::execute(VPTransformState &State) {1452  State.setDebugLocFrom(getDebugLoc());1453  PHINode *NewPhi = State.Builder.CreatePHI(1454      State.TypeAnalysis.inferScalarType(this), 2, getName());1455  unsigned NumIncoming = getNumIncoming();1456  if (getParent() != getParent()->getPlan()->getScalarPreheader()) {1457    // TODO: Fixup all incoming values of header phis once recipes defining them1458    // are introduced.1459    NumIncoming = 1;1460  }1461  for (unsigned Idx = 0; Idx != NumIncoming; ++Idx) {1462    Value *IncV = State.get(getIncomingValue(Idx), VPLane(0));1463    BasicBlock *PredBB = State.CFG.VPBB2IRBB.at(getIncomingBlock(Idx));1464    NewPhi->addIncoming(IncV, PredBB);1465  }1466  State.set(this, NewPhi, VPLane(0));1467}1468 1469#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1470void VPPhi::printRecipe(raw_ostream &O, const Twine &Indent,1471                        VPSlotTracker &SlotTracker) const {1472  O << Indent << "EMIT" << (isSingleScalar() ? "-SCALAR" : "") << " ";1473  printAsOperand(O, SlotTracker);1474  O << " = phi ";1475  printPhiOperands(O, SlotTracker);1476}1477#endif1478 1479VPIRInstruction *VPIRInstruction ::create(Instruction &I) {1480  if (auto *Phi = dyn_cast<PHINode>(&I))1481    return new VPIRPhi(*Phi);1482  return new VPIRInstruction(I);1483}1484 1485void VPIRInstruction::execute(VPTransformState &State) {1486  assert(!isa<VPIRPhi>(this) && getNumOperands() == 0 &&1487         "PHINodes must be handled by VPIRPhi");1488  // Advance the insert point after the wrapped IR instruction. This allows1489  // interleaving VPIRInstructions and other recipes.1490  State.Builder.SetInsertPoint(I.getParent(), std::next(I.getIterator()));1491}1492 1493InstructionCost VPIRInstruction::computeCost(ElementCount VF,1494                                             VPCostContext &Ctx) const {1495  // The recipe wraps an existing IR instruction on the border of VPlan's scope,1496  // hence it does not contribute to the cost-modeling for the VPlan.1497  return 0;1498}1499 1500void VPIRInstruction::extractLastLaneOfFirstOperand(VPBuilder &Builder) {1501  assert(isa<PHINode>(getInstruction()) &&1502         "can only update exiting operands to phi nodes");1503  assert(getNumOperands() > 0 && "must have at least one operand");1504  VPValue *Exiting = getOperand(0);1505  if (Exiting->isLiveIn())1506    return;1507 1508  Exiting = Builder.createNaryOp(VPInstruction::ExtractLastElement, {Exiting});1509  setOperand(0, Exiting);1510}1511 1512#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1513void VPIRInstruction::printRecipe(raw_ostream &O, const Twine &Indent,1514                                  VPSlotTracker &SlotTracker) const {1515  O << Indent << "IR " << I;1516}1517#endif1518 1519void VPIRPhi::execute(VPTransformState &State) {1520  PHINode *Phi = &getIRPhi();1521  for (const auto &[Idx, Op] : enumerate(operands())) {1522    VPValue *ExitValue = Op;1523    auto Lane = vputils::isSingleScalar(ExitValue)1524                    ? VPLane::getFirstLane()1525                    : VPLane::getLastLaneForVF(State.VF);1526    VPBlockBase *Pred = getParent()->getPredecessors()[Idx];1527    auto *PredVPBB = Pred->getExitingBasicBlock();1528    BasicBlock *PredBB = State.CFG.VPBB2IRBB[PredVPBB];1529    // Set insertion point in PredBB in case an extract needs to be generated.1530    // TODO: Model extracts explicitly.1531    State.Builder.SetInsertPoint(PredBB, PredBB->getFirstNonPHIIt());1532    Value *V = State.get(ExitValue, VPLane(Lane));1533    // If there is no existing block for PredBB in the phi, add a new incoming1534    // value. Otherwise update the existing incoming value for PredBB.1535    if (Phi->getBasicBlockIndex(PredBB) == -1)1536      Phi->addIncoming(V, PredBB);1537    else1538      Phi->setIncomingValueForBlock(PredBB, V);1539  }1540 1541  // Advance the insert point after the wrapped IR instruction. This allows1542  // interleaving VPIRInstructions and other recipes.1543  State.Builder.SetInsertPoint(Phi->getParent(), std::next(Phi->getIterator()));1544}1545 1546void VPPhiAccessors::removeIncomingValueFor(VPBlockBase *IncomingBlock) const {1547  VPRecipeBase *R = const_cast<VPRecipeBase *>(getAsRecipe());1548  assert(R->getNumOperands() == R->getParent()->getNumPredecessors() &&1549         "Number of phi operands must match number of predecessors");1550  unsigned Position = R->getParent()->getIndexForPredecessor(IncomingBlock);1551  R->removeOperand(Position);1552}1553 1554#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1555void VPPhiAccessors::printPhiOperands(raw_ostream &O,1556                                      VPSlotTracker &SlotTracker) const {1557  interleaveComma(enumerate(getAsRecipe()->operands()), O,1558                  [this, &O, &SlotTracker](auto Op) {1559                    O << "[ ";1560                    Op.value()->printAsOperand(O, SlotTracker);1561                    O << ", ";1562                    getIncomingBlock(Op.index())->printAsOperand(O);1563                    O << " ]";1564                  });1565}1566#endif1567 1568#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1569void VPIRPhi::printRecipe(raw_ostream &O, const Twine &Indent,1570                          VPSlotTracker &SlotTracker) const {1571  VPIRInstruction::printRecipe(O, Indent, SlotTracker);1572 1573  if (getNumOperands() != 0) {1574    O << " (extra operand" << (getNumOperands() > 1 ? "s" : "") << ": ";1575    interleaveComma(incoming_values_and_blocks(), O,1576                    [&O, &SlotTracker](auto Op) {1577                      std::get<0>(Op)->printAsOperand(O, SlotTracker);1578                      O << " from ";1579                      std::get<1>(Op)->printAsOperand(O);1580                    });1581    O << ")";1582  }1583}1584#endif1585 1586void VPIRMetadata::applyMetadata(Instruction &I) const {1587  for (const auto &[Kind, Node] : Metadata)1588    I.setMetadata(Kind, Node);1589}1590 1591void VPIRMetadata::intersect(const VPIRMetadata &Other) {1592  SmallVector<std::pair<unsigned, MDNode *>> MetadataIntersection;1593  for (const auto &[KindA, MDA] : Metadata) {1594    for (const auto &[KindB, MDB] : Other.Metadata) {1595      if (KindA == KindB && MDA == MDB) {1596        MetadataIntersection.emplace_back(KindA, MDA);1597        break;1598      }1599    }1600  }1601  Metadata = std::move(MetadataIntersection);1602}1603 1604void VPWidenCallRecipe::execute(VPTransformState &State) {1605  assert(State.VF.isVector() && "not widening");1606  assert(Variant != nullptr && "Can't create vector function.");1607 1608  FunctionType *VFTy = Variant->getFunctionType();1609  // Add return type if intrinsic is overloaded on it.1610  SmallVector<Value *, 4> Args;1611  for (const auto &I : enumerate(args())) {1612    Value *Arg;1613    // Some vectorized function variants may also take a scalar argument,1614    // e.g. linear parameters for pointers. This needs to be the scalar value1615    // from the start of the respective part when interleaving.1616    if (!VFTy->getParamType(I.index())->isVectorTy())1617      Arg = State.get(I.value(), VPLane(0));1618    else1619      Arg = State.get(I.value(), usesFirstLaneOnly(I.value()));1620    Args.push_back(Arg);1621  }1622 1623  auto *CI = cast_or_null<CallInst>(getUnderlyingValue());1624  SmallVector<OperandBundleDef, 1> OpBundles;1625  if (CI)1626    CI->getOperandBundlesAsDefs(OpBundles);1627 1628  CallInst *V = State.Builder.CreateCall(Variant, Args, OpBundles);1629  applyFlags(*V);1630  applyMetadata(*V);1631  V->setCallingConv(Variant->getCallingConv());1632 1633  if (!V->getType()->isVoidTy())1634    State.set(this, V);1635}1636 1637InstructionCost VPWidenCallRecipe::computeCost(ElementCount VF,1638                                               VPCostContext &Ctx) const {1639  return Ctx.TTI.getCallInstrCost(nullptr, Variant->getReturnType(),1640                                  Variant->getFunctionType()->params(),1641                                  Ctx.CostKind);1642}1643 1644#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1645void VPWidenCallRecipe::printRecipe(raw_ostream &O, const Twine &Indent,1646                                    VPSlotTracker &SlotTracker) const {1647  O << Indent << "WIDEN-CALL ";1648 1649  Function *CalledFn = getCalledScalarFunction();1650  if (CalledFn->getReturnType()->isVoidTy())1651    O << "void ";1652  else {1653    printAsOperand(O, SlotTracker);1654    O << " = ";1655  }1656 1657  O << "call";1658  printFlags(O);1659  O << " @" << CalledFn->getName() << "(";1660  interleaveComma(args(), O, [&O, &SlotTracker](VPValue *Op) {1661    Op->printAsOperand(O, SlotTracker);1662  });1663  O << ")";1664 1665  O << " (using library function";1666  if (Variant->hasName())1667    O << ": " << Variant->getName();1668  O << ")";1669}1670#endif1671 1672void VPWidenIntrinsicRecipe::execute(VPTransformState &State) {1673  assert(State.VF.isVector() && "not widening");1674 1675  SmallVector<Type *, 2> TysForDecl;1676  // Add return type if intrinsic is overloaded on it.1677  if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, -1, State.TTI))1678    TysForDecl.push_back(VectorType::get(getResultType(), State.VF));1679  SmallVector<Value *, 4> Args;1680  for (const auto &I : enumerate(operands())) {1681    // Some intrinsics have a scalar argument - don't replace it with a1682    // vector.1683    Value *Arg;1684    if (isVectorIntrinsicWithScalarOpAtArg(VectorIntrinsicID, I.index(),1685                                           State.TTI))1686      Arg = State.get(I.value(), VPLane(0));1687    else1688      Arg = State.get(I.value(), usesFirstLaneOnly(I.value()));1689    if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, I.index(),1690                                               State.TTI))1691      TysForDecl.push_back(Arg->getType());1692    Args.push_back(Arg);1693  }1694 1695  // Use vector version of the intrinsic.1696  Module *M = State.Builder.GetInsertBlock()->getModule();1697  Function *VectorF =1698      Intrinsic::getOrInsertDeclaration(M, VectorIntrinsicID, TysForDecl);1699  assert(VectorF &&1700         "Can't retrieve vector intrinsic or vector-predication intrinsics.");1701 1702  auto *CI = cast_or_null<CallInst>(getUnderlyingValue());1703  SmallVector<OperandBundleDef, 1> OpBundles;1704  if (CI)1705    CI->getOperandBundlesAsDefs(OpBundles);1706 1707  CallInst *V = State.Builder.CreateCall(VectorF, Args, OpBundles);1708 1709  applyFlags(*V);1710  applyMetadata(*V);1711 1712  if (!V->getType()->isVoidTy())1713    State.set(this, V);1714}1715 1716/// Compute the cost for the intrinsic \p ID with \p Operands, produced by \p R.1717static InstructionCost getCostForIntrinsics(Intrinsic::ID ID,1718                                            ArrayRef<const VPValue *> Operands,1719                                            const VPRecipeWithIRFlags &R,1720                                            ElementCount VF,1721                                            VPCostContext &Ctx) {1722  // Some backends analyze intrinsic arguments to determine cost. Use the1723  // underlying value for the operand if it has one. Otherwise try to use the1724  // operand of the underlying call instruction, if there is one. Otherwise1725  // clear Arguments.1726  // TODO: Rework TTI interface to be independent of concrete IR values.1727  SmallVector<const Value *> Arguments;1728  for (const auto &[Idx, Op] : enumerate(Operands)) {1729    auto *V = Op->getUnderlyingValue();1730    if (!V) {1731      if (auto *UI = dyn_cast_or_null<CallBase>(R.getUnderlyingValue())) {1732        Arguments.push_back(UI->getArgOperand(Idx));1733        continue;1734      }1735      Arguments.clear();1736      break;1737    }1738    Arguments.push_back(V);1739  }1740 1741  Type *ScalarRetTy = Ctx.Types.inferScalarType(&R);1742  Type *RetTy = VF.isVector() ? toVectorizedTy(ScalarRetTy, VF) : ScalarRetTy;1743  SmallVector<Type *> ParamTys;1744  for (const VPValue *Op : Operands) {1745    ParamTys.push_back(VF.isVector()1746                           ? toVectorTy(Ctx.Types.inferScalarType(Op), VF)1747                           : Ctx.Types.inferScalarType(Op));1748  }1749 1750  // TODO: Rework TTI interface to avoid reliance on underlying IntrinsicInst.1751  FastMathFlags FMF =1752      R.hasFastMathFlags() ? R.getFastMathFlags() : FastMathFlags();1753  IntrinsicCostAttributes CostAttrs(1754      ID, RetTy, Arguments, ParamTys, FMF,1755      dyn_cast_or_null<IntrinsicInst>(R.getUnderlyingValue()),1756      InstructionCost::getInvalid(), &Ctx.TLI);1757  return Ctx.TTI.getIntrinsicInstrCost(CostAttrs, Ctx.CostKind);1758}1759 1760InstructionCost VPWidenIntrinsicRecipe::computeCost(ElementCount VF,1761                                                    VPCostContext &Ctx) const {1762  SmallVector<const VPValue *> ArgOps(operands());1763  return getCostForIntrinsics(VectorIntrinsicID, ArgOps, *this, VF, Ctx);1764}1765 1766StringRef VPWidenIntrinsicRecipe::getIntrinsicName() const {1767  return Intrinsic::getBaseName(VectorIntrinsicID);1768}1769 1770bool VPWidenIntrinsicRecipe::usesFirstLaneOnly(const VPValue *Op) const {1771  assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");1772  return all_of(enumerate(operands()), [this, &Op](const auto &X) {1773    auto [Idx, V] = X;1774    return V != Op || isVectorIntrinsicWithScalarOpAtArg(getVectorIntrinsicID(),1775                                                         Idx, nullptr);1776  });1777}1778 1779#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1780void VPWidenIntrinsicRecipe::printRecipe(raw_ostream &O, const Twine &Indent,1781                                         VPSlotTracker &SlotTracker) const {1782  O << Indent << "WIDEN-INTRINSIC ";1783  if (ResultTy->isVoidTy()) {1784    O << "void ";1785  } else {1786    printAsOperand(O, SlotTracker);1787    O << " = ";1788  }1789 1790  O << "call";1791  printFlags(O);1792  O << getIntrinsicName() << "(";1793 1794  interleaveComma(operands(), O, [&O, &SlotTracker](VPValue *Op) {1795    Op->printAsOperand(O, SlotTracker);1796  });1797  O << ")";1798}1799#endif1800 1801void VPHistogramRecipe::execute(VPTransformState &State) {1802  IRBuilderBase &Builder = State.Builder;1803 1804  Value *Address = State.get(getOperand(0));1805  Value *IncAmt = State.get(getOperand(1), /*IsScalar=*/true);1806  VectorType *VTy = cast<VectorType>(Address->getType());1807 1808  // The histogram intrinsic requires a mask even if the recipe doesn't;1809  // if the mask operand was omitted then all lanes should be executed and1810  // we just need to synthesize an all-true mask.1811  Value *Mask = nullptr;1812  if (VPValue *VPMask = getMask())1813    Mask = State.get(VPMask);1814  else1815    Mask =1816        Builder.CreateVectorSplat(VTy->getElementCount(), Builder.getInt1(1));1817 1818  // If this is a subtract, we want to invert the increment amount. We may1819  // add a separate intrinsic in future, but for now we'll try this.1820  if (Opcode == Instruction::Sub)1821    IncAmt = Builder.CreateNeg(IncAmt);1822  else1823    assert(Opcode == Instruction::Add && "only add or sub supported for now");1824 1825  State.Builder.CreateIntrinsic(Intrinsic::experimental_vector_histogram_add,1826                                {VTy, IncAmt->getType()},1827                                {Address, IncAmt, Mask});1828}1829 1830InstructionCost VPHistogramRecipe::computeCost(ElementCount VF,1831                                               VPCostContext &Ctx) const {1832  // FIXME: Take the gather and scatter into account as well. For now we're1833  //        generating the same cost as the fallback path, but we'll likely1834  //        need to create a new TTI method for determining the cost, including1835  //        whether we can use base + vec-of-smaller-indices or just1836  //        vec-of-pointers.1837  assert(VF.isVector() && "Invalid VF for histogram cost");1838  Type *AddressTy = Ctx.Types.inferScalarType(getOperand(0));1839  VPValue *IncAmt = getOperand(1);1840  Type *IncTy = Ctx.Types.inferScalarType(IncAmt);1841  VectorType *VTy = VectorType::get(IncTy, VF);1842 1843  // Assume that a non-constant update value (or a constant != 1) requires1844  // a multiply, and add that into the cost.1845  InstructionCost MulCost =1846      Ctx.TTI.getArithmeticInstrCost(Instruction::Mul, VTy, Ctx.CostKind);1847  if (IncAmt->isLiveIn()) {1848    ConstantInt *CI = dyn_cast<ConstantInt>(IncAmt->getLiveInIRValue());1849 1850    if (CI && CI->getZExtValue() == 1)1851      MulCost = TTI::TCC_Free;1852  }1853 1854  // Find the cost of the histogram operation itself.1855  Type *PtrTy = VectorType::get(AddressTy, VF);1856  Type *MaskTy = VectorType::get(Type::getInt1Ty(Ctx.LLVMCtx), VF);1857  IntrinsicCostAttributes ICA(Intrinsic::experimental_vector_histogram_add,1858                              Type::getVoidTy(Ctx.LLVMCtx),1859                              {PtrTy, IncTy, MaskTy});1860 1861  // Add the costs together with the add/sub operation.1862  return Ctx.TTI.getIntrinsicInstrCost(ICA, Ctx.CostKind) + MulCost +1863         Ctx.TTI.getArithmeticInstrCost(Opcode, VTy, Ctx.CostKind);1864}1865 1866#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1867void VPHistogramRecipe::printRecipe(raw_ostream &O, const Twine &Indent,1868                                    VPSlotTracker &SlotTracker) const {1869  O << Indent << "WIDEN-HISTOGRAM buckets: ";1870  getOperand(0)->printAsOperand(O, SlotTracker);1871 1872  if (Opcode == Instruction::Sub)1873    O << ", dec: ";1874  else {1875    assert(Opcode == Instruction::Add);1876    O << ", inc: ";1877  }1878  getOperand(1)->printAsOperand(O, SlotTracker);1879 1880  if (VPValue *Mask = getMask()) {1881    O << ", mask: ";1882    Mask->printAsOperand(O, SlotTracker);1883  }1884}1885 1886void VPWidenSelectRecipe::printRecipe(raw_ostream &O, const Twine &Indent,1887                                      VPSlotTracker &SlotTracker) const {1888  O << Indent << "WIDEN-SELECT ";1889  printAsOperand(O, SlotTracker);1890  O << " = select ";1891  printFlags(O);1892  getOperand(0)->printAsOperand(O, SlotTracker);1893  O << ", ";1894  getOperand(1)->printAsOperand(O, SlotTracker);1895  O << ", ";1896  getOperand(2)->printAsOperand(O, SlotTracker);1897  O << (vputils::isSingleScalar(getCond()) ? " (condition is single-scalar)"1898                                           : "");1899}1900#endif1901 1902void VPWidenSelectRecipe::execute(VPTransformState &State) {1903  Value *Cond = State.get(getCond(), vputils::isSingleScalar(getCond()));1904 1905  Value *Op0 = State.get(getOperand(1));1906  Value *Op1 = State.get(getOperand(2));1907  Value *Sel = State.Builder.CreateSelect(Cond, Op0, Op1);1908  State.set(this, Sel);1909  if (auto *I = dyn_cast<Instruction>(Sel)) {1910    if (isa<FPMathOperator>(I))1911      applyFlags(*I);1912    applyMetadata(*I);1913  }1914}1915 1916InstructionCost VPWidenSelectRecipe::computeCost(ElementCount VF,1917                                                 VPCostContext &Ctx) const {1918  SelectInst *SI = cast<SelectInst>(getUnderlyingValue());1919  bool ScalarCond = getOperand(0)->isDefinedOutsideLoopRegions();1920  Type *ScalarTy = Ctx.Types.inferScalarType(this);1921  Type *VectorTy = toVectorTy(Ctx.Types.inferScalarType(this), VF);1922 1923  VPValue *Op0, *Op1;1924  if (!ScalarCond && ScalarTy->getScalarSizeInBits() == 1 &&1925      (match(this, m_LogicalAnd(m_VPValue(Op0), m_VPValue(Op1))) ||1926       match(this, m_LogicalOr(m_VPValue(Op0), m_VPValue(Op1))))) {1927    // select x, y, false --> x & y1928    // select x, true, y --> x | y1929    const auto [Op1VK, Op1VP] = Ctx.getOperandInfo(Op0);1930    const auto [Op2VK, Op2VP] = Ctx.getOperandInfo(Op1);1931 1932    SmallVector<const Value *, 2> Operands;1933    if (all_of(operands(),1934               [](VPValue *Op) { return Op->getUnderlyingValue(); }))1935      Operands.append(SI->op_begin(), SI->op_end());1936    bool IsLogicalOr = match(this, m_LogicalOr(m_VPValue(Op0), m_VPValue(Op1)));1937    return Ctx.TTI.getArithmeticInstrCost(1938        IsLogicalOr ? Instruction::Or : Instruction::And, VectorTy,1939        Ctx.CostKind, {Op1VK, Op1VP}, {Op2VK, Op2VP}, Operands, SI);1940  }1941 1942  Type *CondTy = Ctx.Types.inferScalarType(getOperand(0));1943  if (!ScalarCond)1944    CondTy = VectorType::get(CondTy, VF);1945 1946  CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;1947  if (auto *Cmp = dyn_cast<CmpInst>(SI->getCondition()))1948    Pred = Cmp->getPredicate();1949  return Ctx.TTI.getCmpSelInstrCost(1950      Instruction::Select, VectorTy, CondTy, Pred, Ctx.CostKind,1951      {TTI::OK_AnyValue, TTI::OP_None}, {TTI::OK_AnyValue, TTI::OP_None}, SI);1952}1953 1954VPIRFlags::FastMathFlagsTy::FastMathFlagsTy(const FastMathFlags &FMF) {1955  AllowReassoc = FMF.allowReassoc();1956  NoNaNs = FMF.noNaNs();1957  NoInfs = FMF.noInfs();1958  NoSignedZeros = FMF.noSignedZeros();1959  AllowReciprocal = FMF.allowReciprocal();1960  AllowContract = FMF.allowContract();1961  ApproxFunc = FMF.approxFunc();1962}1963 1964#if !defined(NDEBUG)1965bool VPIRFlags::flagsValidForOpcode(unsigned Opcode) const {1966  switch (OpType) {1967  case OperationType::OverflowingBinOp:1968    return Opcode == Instruction::Add || Opcode == Instruction::Sub ||1969           Opcode == Instruction::Mul || Opcode == Instruction::Shl ||1970           Opcode == VPInstruction::VPInstruction::CanonicalIVIncrementForPart;1971  case OperationType::Trunc:1972    return Opcode == Instruction::Trunc;1973  case OperationType::DisjointOp:1974    return Opcode == Instruction::Or;1975  case OperationType::PossiblyExactOp:1976    return Opcode == Instruction::AShr || Opcode == Instruction::LShr ||1977           Opcode == Instruction::UDiv || Opcode == Instruction::SDiv;1978  case OperationType::GEPOp:1979    return Opcode == Instruction::GetElementPtr ||1980           Opcode == VPInstruction::PtrAdd ||1981           Opcode == VPInstruction::WidePtrAdd;1982  case OperationType::FPMathOp:1983    return Opcode == Instruction::Call || Opcode == Instruction::FAdd ||1984           Opcode == Instruction::FMul || Opcode == Instruction::FSub ||1985           Opcode == Instruction::FNeg || Opcode == Instruction::FDiv ||1986           Opcode == Instruction::FRem || Opcode == Instruction::FPExt ||1987           Opcode == Instruction::FPTrunc || Opcode == Instruction::Select ||1988           Opcode == VPInstruction::WideIVStep ||1989           Opcode == VPInstruction::ReductionStartVector ||1990           Opcode == VPInstruction::ComputeReductionResult;1991  case OperationType::FCmp:1992    return Opcode == Instruction::FCmp;1993  case OperationType::NonNegOp:1994    return Opcode == Instruction::ZExt || Opcode == Instruction::UIToFP;1995  case OperationType::Cmp:1996    return Opcode == Instruction::FCmp || Opcode == Instruction::ICmp;1997  case OperationType::Other:1998    return true;1999  }2000  llvm_unreachable("Unknown OperationType enum");2001}2002#endif2003 2004#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2005void VPIRFlags::printFlags(raw_ostream &O) const {2006  switch (OpType) {2007  case OperationType::Cmp:2008    O << " " << CmpInst::getPredicateName(getPredicate());2009    break;2010  case OperationType::FCmp:2011    O << " " << CmpInst::getPredicateName(getPredicate());2012    getFastMathFlags().print(O);2013    break;2014  case OperationType::DisjointOp:2015    if (DisjointFlags.IsDisjoint)2016      O << " disjoint";2017    break;2018  case OperationType::PossiblyExactOp:2019    if (ExactFlags.IsExact)2020      O << " exact";2021    break;2022  case OperationType::OverflowingBinOp:2023    if (WrapFlags.HasNUW)2024      O << " nuw";2025    if (WrapFlags.HasNSW)2026      O << " nsw";2027    break;2028  case OperationType::Trunc:2029    if (TruncFlags.HasNUW)2030      O << " nuw";2031    if (TruncFlags.HasNSW)2032      O << " nsw";2033    break;2034  case OperationType::FPMathOp:2035    getFastMathFlags().print(O);2036    break;2037  case OperationType::GEPOp:2038    if (GEPFlags.isInBounds())2039      O << " inbounds";2040    else if (GEPFlags.hasNoUnsignedSignedWrap())2041      O << " nusw";2042    if (GEPFlags.hasNoUnsignedWrap())2043      O << " nuw";2044    break;2045  case OperationType::NonNegOp:2046    if (NonNegFlags.NonNeg)2047      O << " nneg";2048    break;2049  case OperationType::Other:2050    break;2051  }2052  O << " ";2053}2054#endif2055 2056void VPWidenRecipe::execute(VPTransformState &State) {2057  auto &Builder = State.Builder;2058  switch (Opcode) {2059  case Instruction::Call:2060  case Instruction::Br:2061  case Instruction::PHI:2062  case Instruction::GetElementPtr:2063  case Instruction::Select:2064    llvm_unreachable("This instruction is handled by a different recipe.");2065  case Instruction::UDiv:2066  case Instruction::SDiv:2067  case Instruction::SRem:2068  case Instruction::URem:2069  case Instruction::Add:2070  case Instruction::FAdd:2071  case Instruction::Sub:2072  case Instruction::FSub:2073  case Instruction::FNeg:2074  case Instruction::Mul:2075  case Instruction::FMul:2076  case Instruction::FDiv:2077  case Instruction::FRem:2078  case Instruction::Shl:2079  case Instruction::LShr:2080  case Instruction::AShr:2081  case Instruction::And:2082  case Instruction::Or:2083  case Instruction::Xor: {2084    // Just widen unops and binops.2085    SmallVector<Value *, 2> Ops;2086    for (VPValue *VPOp : operands())2087      Ops.push_back(State.get(VPOp));2088 2089    Value *V = Builder.CreateNAryOp(Opcode, Ops);2090 2091    if (auto *VecOp = dyn_cast<Instruction>(V)) {2092      applyFlags(*VecOp);2093      applyMetadata(*VecOp);2094    }2095 2096    // Use this vector value for all users of the original instruction.2097    State.set(this, V);2098    break;2099  }2100  case Instruction::ExtractValue: {2101    assert(getNumOperands() == 2 && "expected single level extractvalue");2102    Value *Op = State.get(getOperand(0));2103    auto *CI = cast<ConstantInt>(getOperand(1)->getLiveInIRValue());2104    Value *Extract = Builder.CreateExtractValue(Op, CI->getZExtValue());2105    State.set(this, Extract);2106    break;2107  }2108  case Instruction::Freeze: {2109    Value *Op = State.get(getOperand(0));2110    Value *Freeze = Builder.CreateFreeze(Op);2111    State.set(this, Freeze);2112    break;2113  }2114  case Instruction::ICmp:2115  case Instruction::FCmp: {2116    // Widen compares. Generate vector compares.2117    bool FCmp = Opcode == Instruction::FCmp;2118    Value *A = State.get(getOperand(0));2119    Value *B = State.get(getOperand(1));2120    Value *C = nullptr;2121    if (FCmp) {2122      C = Builder.CreateFCmp(getPredicate(), A, B);2123    } else {2124      C = Builder.CreateICmp(getPredicate(), A, B);2125    }2126    if (auto *I = dyn_cast<Instruction>(C)) {2127      applyFlags(*I);2128      applyMetadata(*I);2129    }2130    State.set(this, C);2131    break;2132  }2133  default:2134    // This instruction is not vectorized by simple widening.2135    LLVM_DEBUG(dbgs() << "LV: Found an unhandled opcode : "2136                      << Instruction::getOpcodeName(Opcode));2137    llvm_unreachable("Unhandled instruction!");2138  } // end of switch.2139 2140#if !defined(NDEBUG)2141  // Verify that VPlan type inference results agree with the type of the2142  // generated values.2143  assert(VectorType::get(State.TypeAnalysis.inferScalarType(this), State.VF) ==2144             State.get(this)->getType() &&2145         "inferred type and type from generated instructions do not match");2146#endif2147}2148 2149InstructionCost VPWidenRecipe::computeCost(ElementCount VF,2150                                           VPCostContext &Ctx) const {2151  switch (Opcode) {2152  case Instruction::UDiv:2153  case Instruction::SDiv:2154  case Instruction::SRem:2155  case Instruction::URem:2156    // If the div/rem operation isn't safe to speculate and requires2157    // predication, then the only way we can even create a vplan is to insert2158    // a select on the second input operand to ensure we use the value of 12159    // for the inactive lanes. The select will be costed separately.2160  case Instruction::FNeg:2161  case Instruction::Add:2162  case Instruction::FAdd:2163  case Instruction::Sub:2164  case Instruction::FSub:2165  case Instruction::Mul:2166  case Instruction::FMul:2167  case Instruction::FDiv:2168  case Instruction::FRem:2169  case Instruction::Shl:2170  case Instruction::LShr:2171  case Instruction::AShr:2172  case Instruction::And:2173  case Instruction::Or:2174  case Instruction::Xor:2175  case Instruction::Freeze:2176  case Instruction::ExtractValue:2177  case Instruction::ICmp:2178  case Instruction::FCmp:2179    return getCostForRecipeWithOpcode(getOpcode(), VF, Ctx);2180  default:2181    llvm_unreachable("Unsupported opcode for instruction");2182  }2183}2184 2185#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2186void VPWidenRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2187                                VPSlotTracker &SlotTracker) const {2188  O << Indent << "WIDEN ";2189  printAsOperand(O, SlotTracker);2190  O << " = " << Instruction::getOpcodeName(Opcode);2191  printFlags(O);2192  printOperands(O, SlotTracker);2193}2194#endif2195 2196void VPWidenCastRecipe::execute(VPTransformState &State) {2197  auto &Builder = State.Builder;2198  /// Vectorize casts.2199  assert(State.VF.isVector() && "Not vectorizing?");2200  Type *DestTy = VectorType::get(getResultType(), State.VF);2201  VPValue *Op = getOperand(0);2202  Value *A = State.get(Op);2203  Value *Cast = Builder.CreateCast(Instruction::CastOps(Opcode), A, DestTy);2204  State.set(this, Cast);2205  if (auto *CastOp = dyn_cast<Instruction>(Cast)) {2206    applyFlags(*CastOp);2207    applyMetadata(*CastOp);2208  }2209}2210 2211InstructionCost VPWidenCastRecipe::computeCost(ElementCount VF,2212                                               VPCostContext &Ctx) const {2213  // TODO: In some cases, VPWidenCastRecipes are created but not considered in2214  // the legacy cost model, including truncates/extends when evaluating a2215  // reduction in a smaller type.2216  if (!getUnderlyingValue())2217    return 0;2218  // Computes the CastContextHint from a recipes that may access memory.2219  auto ComputeCCH = [&](const VPRecipeBase *R) -> TTI::CastContextHint {2220    if (VF.isScalar())2221      return TTI::CastContextHint::Normal;2222    if (isa<VPInterleaveBase>(R))2223      return TTI::CastContextHint::Interleave;2224    if (const auto *ReplicateRecipe = dyn_cast<VPReplicateRecipe>(R))2225      return ReplicateRecipe->isPredicated() ? TTI::CastContextHint::Masked2226                                             : TTI::CastContextHint::Normal;2227    const auto *WidenMemoryRecipe = dyn_cast<VPWidenMemoryRecipe>(R);2228    if (WidenMemoryRecipe == nullptr)2229      return TTI::CastContextHint::None;2230    if (!WidenMemoryRecipe->isConsecutive())2231      return TTI::CastContextHint::GatherScatter;2232    if (WidenMemoryRecipe->isReverse())2233      return TTI::CastContextHint::Reversed;2234    if (WidenMemoryRecipe->isMasked())2235      return TTI::CastContextHint::Masked;2236    return TTI::CastContextHint::Normal;2237  };2238 2239  VPValue *Operand = getOperand(0);2240  TTI::CastContextHint CCH = TTI::CastContextHint::None;2241  // For Trunc/FPTrunc, get the context from the only user.2242  if ((Opcode == Instruction::Trunc || Opcode == Instruction::FPTrunc) &&2243      !hasMoreThanOneUniqueUser() && getNumUsers() > 0) {2244    if (auto *StoreRecipe = dyn_cast<VPRecipeBase>(*user_begin()))2245      CCH = ComputeCCH(StoreRecipe);2246  }2247  // For Z/Sext, get the context from the operand.2248  else if (Opcode == Instruction::ZExt || Opcode == Instruction::SExt ||2249           Opcode == Instruction::FPExt) {2250    if (Operand->isLiveIn())2251      CCH = TTI::CastContextHint::Normal;2252    else if (Operand->getDefiningRecipe())2253      CCH = ComputeCCH(Operand->getDefiningRecipe());2254  }2255 2256  auto *SrcTy =2257      cast<VectorType>(toVectorTy(Ctx.Types.inferScalarType(Operand), VF));2258  auto *DestTy = cast<VectorType>(toVectorTy(getResultType(), VF));2259  // Arm TTI will use the underlying instruction to determine the cost.2260  return Ctx.TTI.getCastInstrCost(2261      Opcode, DestTy, SrcTy, CCH, Ctx.CostKind,2262      dyn_cast_if_present<Instruction>(getUnderlyingValue()));2263}2264 2265#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2266void VPWidenCastRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2267                                    VPSlotTracker &SlotTracker) const {2268  O << Indent << "WIDEN-CAST ";2269  printAsOperand(O, SlotTracker);2270  O << " = " << Instruction::getOpcodeName(Opcode);2271  printFlags(O);2272  printOperands(O, SlotTracker);2273  O << " to " << *getResultType();2274}2275#endif2276 2277InstructionCost VPHeaderPHIRecipe::computeCost(ElementCount VF,2278                                               VPCostContext &Ctx) const {2279  return Ctx.TTI.getCFInstrCost(Instruction::PHI, Ctx.CostKind);2280}2281 2282/// A helper function that returns an integer or floating-point constant with2283/// value C.2284static Constant *getSignedIntOrFpConstant(Type *Ty, int64_t C) {2285  return Ty->isIntegerTy() ? ConstantInt::getSigned(Ty, C)2286                           : ConstantFP::get(Ty, C);2287}2288 2289#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2290void VPWidenIntOrFpInductionRecipe::printRecipe(2291    raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const {2292  O << Indent;2293  printAsOperand(O, SlotTracker);2294  O << " = WIDEN-INDUCTION";2295  printFlags(O);2296  O << " ";2297  printOperands(O, SlotTracker);2298 2299  if (auto *TI = getTruncInst())2300    O << " (truncated to " << *TI->getType() << ")";2301}2302#endif2303 2304bool VPWidenIntOrFpInductionRecipe::isCanonical() const {2305  // The step may be defined by a recipe in the preheader (e.g. if it requires2306  // SCEV expansion), but for the canonical induction the step is required to be2307  // 1, which is represented as live-in.2308  if (getStepValue()->getDefiningRecipe())2309    return false;2310  auto *StepC = dyn_cast<ConstantInt>(getStepValue()->getLiveInIRValue());2311  auto *StartC = dyn_cast<ConstantInt>(getStartValue()->getLiveInIRValue());2312  return StartC && StartC->isZero() && StepC && StepC->isOne() &&2313         getScalarType() == getRegion()->getCanonicalIVType();2314}2315 2316#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2317void VPDerivedIVRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2318                                    VPSlotTracker &SlotTracker) const {2319  O << Indent;2320  printAsOperand(O, SlotTracker);2321  O << " = DERIVED-IV ";2322  getStartValue()->printAsOperand(O, SlotTracker);2323  O << " + ";2324  getOperand(1)->printAsOperand(O, SlotTracker);2325  O << " * ";2326  getStepValue()->printAsOperand(O, SlotTracker);2327}2328#endif2329 2330void VPScalarIVStepsRecipe::execute(VPTransformState &State) {2331  // Fast-math-flags propagate from the original induction instruction.2332  IRBuilder<>::FastMathFlagGuard FMFG(State.Builder);2333  if (hasFastMathFlags())2334    State.Builder.setFastMathFlags(getFastMathFlags());2335 2336  /// Compute scalar induction steps. \p ScalarIV is the scalar induction2337  /// variable on which to base the steps, \p Step is the size of the step.2338 2339  Value *BaseIV = State.get(getOperand(0), VPLane(0));2340  Value *Step = State.get(getStepValue(), VPLane(0));2341  IRBuilderBase &Builder = State.Builder;2342 2343  // Ensure step has the same type as that of scalar IV.2344  Type *BaseIVTy = BaseIV->getType()->getScalarType();2345  assert(BaseIVTy == Step->getType() && "Types of BaseIV and Step must match!");2346 2347  // We build scalar steps for both integer and floating-point induction2348  // variables. Here, we determine the kind of arithmetic we will perform.2349  Instruction::BinaryOps AddOp;2350  Instruction::BinaryOps MulOp;2351  if (BaseIVTy->isIntegerTy()) {2352    AddOp = Instruction::Add;2353    MulOp = Instruction::Mul;2354  } else {2355    AddOp = InductionOpcode;2356    MulOp = Instruction::FMul;2357  }2358 2359  // Determine the number of scalars we need to generate for each unroll2360  // iteration.2361  bool FirstLaneOnly = vputils::onlyFirstLaneUsed(this);2362  // Compute the scalar steps and save the results in State.2363  Type *IntStepTy =2364      IntegerType::get(BaseIVTy->getContext(), BaseIVTy->getScalarSizeInBits());2365 2366  unsigned StartLane = 0;2367  unsigned EndLane = FirstLaneOnly ? 1 : State.VF.getKnownMinValue();2368  if (State.Lane) {2369    StartLane = State.Lane->getKnownLane();2370    EndLane = StartLane + 1;2371  }2372  Value *StartIdx0;2373  if (getUnrollPart(*this) == 0)2374    StartIdx0 = ConstantInt::get(IntStepTy, 0);2375  else {2376    StartIdx0 = State.get(getOperand(2), true);2377    if (getUnrollPart(*this) != 1) {2378      StartIdx0 =2379          Builder.CreateMul(StartIdx0, ConstantInt::get(StartIdx0->getType(),2380                                                        getUnrollPart(*this)));2381    }2382    StartIdx0 = Builder.CreateSExtOrTrunc(StartIdx0, IntStepTy);2383  }2384 2385  if (BaseIVTy->isFloatingPointTy())2386    StartIdx0 = Builder.CreateSIToFP(StartIdx0, BaseIVTy);2387 2388  for (unsigned Lane = StartLane; Lane < EndLane; ++Lane) {2389    Value *StartIdx = Builder.CreateBinOp(2390        AddOp, StartIdx0, getSignedIntOrFpConstant(BaseIVTy, Lane));2391    // The step returned by `createStepForVF` is a runtime-evaluated value2392    // when VF is scalable. Otherwise, it should be folded into a Constant.2393    assert((State.VF.isScalable() || isa<Constant>(StartIdx)) &&2394           "Expected StartIdx to be folded to a constant when VF is not "2395           "scalable");2396    auto *Mul = Builder.CreateBinOp(MulOp, StartIdx, Step);2397    auto *Add = Builder.CreateBinOp(AddOp, BaseIV, Mul);2398    State.set(this, Add, VPLane(Lane));2399  }2400}2401 2402#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2403void VPScalarIVStepsRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2404                                        VPSlotTracker &SlotTracker) const {2405  O << Indent;2406  printAsOperand(O, SlotTracker);2407  O << " = SCALAR-STEPS ";2408  printOperands(O, SlotTracker);2409}2410#endif2411 2412bool VPWidenGEPRecipe::usesFirstLaneOnly(const VPValue *Op) const {2413  assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");2414  return vputils::isSingleScalar(Op);2415}2416 2417void VPWidenGEPRecipe::execute(VPTransformState &State) {2418  assert(State.VF.isVector() && "not widening");2419  // Construct a vector GEP by widening the operands of the scalar GEP as2420  // necessary. We mark the vector GEP 'inbounds' if appropriate. A GEP2421  // results in a vector of pointers when at least one operand of the GEP2422  // is vector-typed. Thus, to keep the representation compact, we only use2423  // vector-typed operands for loop-varying values.2424 2425  assert(2426      any_of(operands(),2427             [](VPValue *Op) { return !Op->isDefinedOutsideLoopRegions(); }) &&2428      "Expected at least one loop-variant operand");2429 2430  // If the GEP has at least one loop-varying operand, we are sure to2431  // produce a vector of pointers unless VF is scalar.2432  // The pointer operand of the new GEP. If it's loop-invariant, we2433  // won't broadcast it.2434  auto *Ptr = State.get(getOperand(0), isPointerLoopInvariant());2435 2436  // Collect all the indices for the new GEP. If any index is2437  // loop-invariant, we won't broadcast it.2438  SmallVector<Value *, 4> Indices;2439  for (unsigned I = 1, E = getNumOperands(); I < E; I++) {2440    VPValue *Operand = getOperand(I);2441    Indices.push_back(State.get(Operand, isIndexLoopInvariant(I - 1)));2442  }2443 2444  // Create the new GEP. Note that this GEP may be a scalar if VF == 1,2445  // but it should be a vector, otherwise.2446  auto *NewGEP = State.Builder.CreateGEP(getSourceElementType(), Ptr, Indices,2447                                         "", getGEPNoWrapFlags());2448  assert((State.VF.isScalar() || NewGEP->getType()->isVectorTy()) &&2449         "NewGEP is not a pointer vector");2450  State.set(this, NewGEP);2451}2452 2453#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2454void VPWidenGEPRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2455                                   VPSlotTracker &SlotTracker) const {2456  O << Indent << "WIDEN-GEP ";2457  O << (isPointerLoopInvariant() ? "Inv" : "Var");2458  for (size_t I = 0; I < getNumOperands() - 1; ++I)2459    O << "[" << (isIndexLoopInvariant(I) ? "Inv" : "Var") << "]";2460 2461  O << " ";2462  printAsOperand(O, SlotTracker);2463  O << " = getelementptr";2464  printFlags(O);2465  printOperands(O, SlotTracker);2466}2467#endif2468 2469void VPVectorEndPointerRecipe::execute(VPTransformState &State) {2470  auto &Builder = State.Builder;2471  unsigned CurrentPart = getUnrollPart(*this);2472  const DataLayout &DL = Builder.GetInsertBlock()->getDataLayout();2473  Type *IndexTy = DL.getIndexType(State.TypeAnalysis.inferScalarType(this));2474 2475  // The wide store needs to start at the last vector element.2476  Value *RunTimeVF = State.get(getVFValue(), VPLane(0));2477  if (IndexTy != RunTimeVF->getType())2478    RunTimeVF = Builder.CreateZExtOrTrunc(RunTimeVF, IndexTy);2479  // NumElt = Stride * CurrentPart * RunTimeVF2480  Value *NumElt = Builder.CreateMul(2481      ConstantInt::get(IndexTy, Stride * (int64_t)CurrentPart), RunTimeVF);2482  // LastLane = Stride * (RunTimeVF - 1)2483  Value *LastLane = Builder.CreateSub(RunTimeVF, ConstantInt::get(IndexTy, 1));2484  if (Stride != 1)2485    LastLane = Builder.CreateMul(ConstantInt::get(IndexTy, Stride), LastLane);2486  Value *Ptr = State.get(getOperand(0), VPLane(0));2487  Value *ResultPtr =2488      Builder.CreateGEP(IndexedTy, Ptr, NumElt, "", getGEPNoWrapFlags());2489  ResultPtr = Builder.CreateGEP(IndexedTy, ResultPtr, LastLane, "",2490                                getGEPNoWrapFlags());2491 2492  State.set(this, ResultPtr, /*IsScalar*/ true);2493}2494 2495#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2496void VPVectorEndPointerRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2497                                           VPSlotTracker &SlotTracker) const {2498  O << Indent;2499  printAsOperand(O, SlotTracker);2500  O << " = vector-end-pointer";2501  printFlags(O);2502  printOperands(O, SlotTracker);2503}2504#endif2505 2506void VPVectorPointerRecipe::execute(VPTransformState &State) {2507  auto &Builder = State.Builder;2508  unsigned CurrentPart = getUnrollPart(*this);2509  const DataLayout &DL = Builder.GetInsertBlock()->getDataLayout();2510  Type *IndexTy = DL.getIndexType(State.TypeAnalysis.inferScalarType(this));2511  Value *Ptr = State.get(getOperand(0), VPLane(0));2512 2513  Value *Increment = createStepForVF(Builder, IndexTy, State.VF, CurrentPart);2514  Value *ResultPtr = Builder.CreateGEP(getSourceElementType(), Ptr, Increment,2515                                       "", getGEPNoWrapFlags());2516 2517  State.set(this, ResultPtr, /*IsScalar*/ true);2518}2519 2520#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2521void VPVectorPointerRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2522                                        VPSlotTracker &SlotTracker) const {2523  O << Indent;2524  printAsOperand(O, SlotTracker);2525  O << " = vector-pointer ";2526  printFlags(O);2527  printOperands(O, SlotTracker);2528}2529#endif2530 2531InstructionCost VPBlendRecipe::computeCost(ElementCount VF,2532                                           VPCostContext &Ctx) const {2533  // Handle cases where only the first lane is used the same way as the legacy2534  // cost model.2535  if (vputils::onlyFirstLaneUsed(this))2536    return Ctx.TTI.getCFInstrCost(Instruction::PHI, Ctx.CostKind);2537 2538  Type *ResultTy = toVectorTy(Ctx.Types.inferScalarType(this), VF);2539  Type *CmpTy = toVectorTy(Type::getInt1Ty(Ctx.Types.getContext()), VF);2540  return (getNumIncomingValues() - 1) *2541         Ctx.TTI.getCmpSelInstrCost(Instruction::Select, ResultTy, CmpTy,2542                                    CmpInst::BAD_ICMP_PREDICATE, Ctx.CostKind);2543}2544 2545#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2546void VPBlendRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2547                                VPSlotTracker &SlotTracker) const {2548  O << Indent << "BLEND ";2549  printAsOperand(O, SlotTracker);2550  O << " =";2551  if (getNumIncomingValues() == 1) {2552    // Not a User of any mask: not really blending, this is a2553    // single-predecessor phi.2554    O << " ";2555    getIncomingValue(0)->printAsOperand(O, SlotTracker);2556  } else {2557    for (unsigned I = 0, E = getNumIncomingValues(); I < E; ++I) {2558      O << " ";2559      getIncomingValue(I)->printAsOperand(O, SlotTracker);2560      if (I == 0)2561        continue;2562      O << "/";2563      getMask(I)->printAsOperand(O, SlotTracker);2564    }2565  }2566}2567#endif2568 2569void VPReductionRecipe::execute(VPTransformState &State) {2570  assert(!State.Lane && "Reduction being replicated.");2571  RecurKind Kind = getRecurrenceKind();2572  assert(!RecurrenceDescriptor::isAnyOfRecurrenceKind(Kind) &&2573         "In-loop AnyOf reductions aren't currently supported");2574  // Propagate the fast-math flags carried by the underlying instruction.2575  IRBuilderBase::FastMathFlagGuard FMFGuard(State.Builder);2576  State.Builder.setFastMathFlags(getFastMathFlags());2577  Value *NewVecOp = State.get(getVecOp());2578  if (VPValue *Cond = getCondOp()) {2579    Value *NewCond = State.get(Cond, State.VF.isScalar());2580    VectorType *VecTy = dyn_cast<VectorType>(NewVecOp->getType());2581    Type *ElementTy = VecTy ? VecTy->getElementType() : NewVecOp->getType();2582 2583    Value *Start = getRecurrenceIdentity(Kind, ElementTy, getFastMathFlags());2584    if (State.VF.isVector())2585      Start = State.Builder.CreateVectorSplat(VecTy->getElementCount(), Start);2586 2587    Value *Select = State.Builder.CreateSelect(NewCond, NewVecOp, Start);2588    NewVecOp = Select;2589  }2590  Value *NewRed;2591  Value *NextInChain;2592  if (isOrdered()) {2593    Value *PrevInChain = State.get(getChainOp(), /*IsScalar*/ true);2594    if (State.VF.isVector())2595      NewRed =2596          createOrderedReduction(State.Builder, Kind, NewVecOp, PrevInChain);2597    else2598      NewRed = State.Builder.CreateBinOp(2599          (Instruction::BinaryOps)RecurrenceDescriptor::getOpcode(Kind),2600          PrevInChain, NewVecOp);2601    PrevInChain = NewRed;2602    NextInChain = NewRed;2603  } else if (isPartialReduction()) {2604    assert(Kind == RecurKind::Add && "Unexpected partial reduction kind");2605    Value *PrevInChain = State.get(getChainOp(), /*IsScalar*/ false);2606    NewRed = State.Builder.CreateIntrinsic(2607        PrevInChain->getType(), Intrinsic::vector_partial_reduce_add,2608        {PrevInChain, NewVecOp}, nullptr, "partial.reduce");2609    PrevInChain = NewRed;2610    NextInChain = NewRed;2611  } else {2612    assert(isInLoop() &&2613           "The reduction must either be ordered, partial or in-loop");2614    Value *PrevInChain = State.get(getChainOp(), /*IsScalar*/ true);2615    NewRed = createSimpleReduction(State.Builder, NewVecOp, Kind);2616    if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind))2617      NextInChain = createMinMaxOp(State.Builder, Kind, NewRed, PrevInChain);2618    else2619      NextInChain = State.Builder.CreateBinOp(2620          (Instruction::BinaryOps)RecurrenceDescriptor::getOpcode(Kind),2621          PrevInChain, NewRed);2622  }2623  State.set(this, NextInChain, /*IsScalar*/ !isPartialReduction());2624}2625 2626void VPReductionEVLRecipe::execute(VPTransformState &State) {2627  assert(!State.Lane && "Reduction being replicated.");2628 2629  auto &Builder = State.Builder;2630  // Propagate the fast-math flags carried by the underlying instruction.2631  IRBuilderBase::FastMathFlagGuard FMFGuard(Builder);2632  Builder.setFastMathFlags(getFastMathFlags());2633 2634  RecurKind Kind = getRecurrenceKind();2635  Value *Prev = State.get(getChainOp(), /*IsScalar*/ true);2636  Value *VecOp = State.get(getVecOp());2637  Value *EVL = State.get(getEVL(), VPLane(0));2638 2639  Value *Mask;2640  if (VPValue *CondOp = getCondOp())2641    Mask = State.get(CondOp);2642  else2643    Mask = Builder.CreateVectorSplat(State.VF, Builder.getTrue());2644 2645  Value *NewRed;2646  if (isOrdered()) {2647    NewRed = createOrderedReduction(Builder, Kind, VecOp, Prev, Mask, EVL);2648  } else {2649    NewRed = createSimpleReduction(Builder, VecOp, Kind, Mask, EVL);2650    if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind))2651      NewRed = createMinMaxOp(Builder, Kind, NewRed, Prev);2652    else2653      NewRed = Builder.CreateBinOp(2654          (Instruction::BinaryOps)RecurrenceDescriptor::getOpcode(Kind), NewRed,2655          Prev);2656  }2657  State.set(this, NewRed, /*IsScalar*/ true);2658}2659 2660InstructionCost VPReductionRecipe::computeCost(ElementCount VF,2661                                               VPCostContext &Ctx) const {2662  RecurKind RdxKind = getRecurrenceKind();2663  Type *ElementTy = Ctx.Types.inferScalarType(this);2664  auto *VectorTy = cast<VectorType>(toVectorTy(ElementTy, VF));2665  unsigned Opcode = RecurrenceDescriptor::getOpcode(RdxKind);2666  FastMathFlags FMFs = getFastMathFlags();2667  std::optional<FastMathFlags> OptionalFMF =2668      ElementTy->isFloatingPointTy() ? std::make_optional(FMFs) : std::nullopt;2669 2670  if (isPartialReduction()) {2671    InstructionCost CondCost = 0;2672    if (isConditional()) {2673      CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;2674      auto *CondTy = cast<VectorType>(2675          toVectorTy(Ctx.Types.inferScalarType(getCondOp()), VF));2676      CondCost = Ctx.TTI.getCmpSelInstrCost(Instruction::Select, VectorTy,2677                                            CondTy, Pred, Ctx.CostKind);2678    }2679    return CondCost + Ctx.TTI.getPartialReductionCost(2680                          Opcode, ElementTy, ElementTy, ElementTy, VF,2681                          TargetTransformInfo::PR_None,2682                          TargetTransformInfo::PR_None, std::nullopt,2683                          Ctx.CostKind);2684  }2685 2686  // TODO: Support any-of reductions.2687  assert(2688      (!RecurrenceDescriptor::isAnyOfRecurrenceKind(RdxKind) ||2689       ForceTargetInstructionCost.getNumOccurrences() > 0) &&2690      "Any-of reduction not implemented in VPlan-based cost model currently.");2691 2692  // Note that TTI should model the cost of moving result to the scalar register2693  // and the BinOp cost in the getMinMaxReductionCost().2694  if (RecurrenceDescriptor::isMinMaxRecurrenceKind(RdxKind)) {2695    Intrinsic::ID Id = getMinMaxReductionIntrinsicOp(RdxKind);2696    return Ctx.TTI.getMinMaxReductionCost(Id, VectorTy, FMFs, Ctx.CostKind);2697  }2698 2699  // Note that TTI should model the cost of moving result to the scalar register2700  // and the BinOp cost in the getArithmeticReductionCost().2701  return Ctx.TTI.getArithmeticReductionCost(Opcode, VectorTy, OptionalFMF,2702                                            Ctx.CostKind);2703}2704 2705VPExpressionRecipe::VPExpressionRecipe(2706    ExpressionTypes ExpressionType,2707    ArrayRef<VPSingleDefRecipe *> ExpressionRecipes)2708    : VPSingleDefRecipe(VPDef::VPExpressionSC, {}, {}),2709      ExpressionRecipes(ExpressionRecipes), ExpressionType(ExpressionType) {2710  assert(!ExpressionRecipes.empty() && "Nothing to combine?");2711  assert(2712      none_of(ExpressionRecipes,2713              [](VPSingleDefRecipe *R) { return R->mayHaveSideEffects(); }) &&2714      "expression cannot contain recipes with side-effects");2715 2716  // Maintain a copy of the expression recipes as a set of users.2717  SmallPtrSet<VPUser *, 4> ExpressionRecipesAsSetOfUsers;2718  for (auto *R : ExpressionRecipes)2719    ExpressionRecipesAsSetOfUsers.insert(R);2720 2721  // Recipes in the expression, except the last one, must only be used by2722  // (other) recipes inside the expression. If there are other users, external2723  // to the expression, use a clone of the recipe for external users.2724  for (VPSingleDefRecipe *R : reverse(ExpressionRecipes)) {2725    if (R != ExpressionRecipes.back() &&2726        any_of(R->users(), [&ExpressionRecipesAsSetOfUsers](VPUser *U) {2727          return !ExpressionRecipesAsSetOfUsers.contains(U);2728        })) {2729      // There are users outside of the expression. Clone the recipe and use the2730      // clone those external users.2731      VPSingleDefRecipe *CopyForExtUsers = R->clone();2732      R->replaceUsesWithIf(CopyForExtUsers, [&ExpressionRecipesAsSetOfUsers](2733                                                VPUser &U, unsigned) {2734        return !ExpressionRecipesAsSetOfUsers.contains(&U);2735      });2736      CopyForExtUsers->insertBefore(R);2737    }2738    if (R->getParent())2739      R->removeFromParent();2740  }2741 2742  // Internalize all external operands to the expression recipes. To do so,2743  // create new temporary VPValues for all operands defined by a recipe outside2744  // the expression. The original operands are added as operands of the2745  // VPExpressionRecipe itself.2746  for (auto *R : ExpressionRecipes) {2747    for (const auto &[Idx, Op] : enumerate(R->operands())) {2748      auto *Def = Op->getDefiningRecipe();2749      if (Def && ExpressionRecipesAsSetOfUsers.contains(Def))2750        continue;2751      addOperand(Op);2752      LiveInPlaceholders.push_back(new VPValue());2753    }2754  }2755 2756  // Replace each external operand with the first one created for it in2757  // LiveInPlaceholders.2758  for (auto *R : ExpressionRecipes)2759    for (auto const &[LiveIn, Tmp] : zip(operands(), LiveInPlaceholders))2760      R->replaceUsesOfWith(LiveIn, Tmp);2761}2762 2763void VPExpressionRecipe::decompose() {2764  for (auto *R : ExpressionRecipes)2765    // Since the list could contain duplicates, make sure the recipe hasn't2766    // already been inserted.2767    if (!R->getParent())2768      R->insertBefore(this);2769 2770  for (const auto &[Idx, Op] : enumerate(operands()))2771    LiveInPlaceholders[Idx]->replaceAllUsesWith(Op);2772 2773  replaceAllUsesWith(ExpressionRecipes.back());2774  ExpressionRecipes.clear();2775}2776 2777InstructionCost VPExpressionRecipe::computeCost(ElementCount VF,2778                                                VPCostContext &Ctx) const {2779  Type *RedTy = Ctx.Types.inferScalarType(this);2780  auto *SrcVecTy = cast<VectorType>(2781      toVectorTy(Ctx.Types.inferScalarType(getOperand(0)), VF));2782  assert(RedTy->isIntegerTy() &&2783         "VPExpressionRecipe only supports integer types currently.");2784  unsigned Opcode = RecurrenceDescriptor::getOpcode(2785      cast<VPReductionRecipe>(ExpressionRecipes.back())->getRecurrenceKind());2786  switch (ExpressionType) {2787  case ExpressionTypes::ExtendedReduction: {2788    unsigned Opcode = RecurrenceDescriptor::getOpcode(2789        cast<VPReductionRecipe>(ExpressionRecipes[1])->getRecurrenceKind());2790    auto *ExtR = cast<VPWidenCastRecipe>(ExpressionRecipes[0]);2791 2792    return cast<VPReductionRecipe>(ExpressionRecipes.back())2793                   ->isPartialReduction()2794               ? Ctx.TTI.getPartialReductionCost(2795                     Opcode, Ctx.Types.inferScalarType(getOperand(0)), nullptr,2796                     RedTy, VF,2797                     TargetTransformInfo::getPartialReductionExtendKind(2798                         ExtR->getOpcode()),2799                     TargetTransformInfo::PR_None, std::nullopt, Ctx.CostKind)2800               : Ctx.TTI.getExtendedReductionCost(2801                     Opcode, ExtR->getOpcode() == Instruction::ZExt, RedTy,2802                     SrcVecTy, std::nullopt, Ctx.CostKind);2803  }2804  case ExpressionTypes::MulAccReduction:2805    return Ctx.TTI.getMulAccReductionCost(false, Opcode, RedTy, SrcVecTy,2806                                          Ctx.CostKind);2807 2808  case ExpressionTypes::ExtNegatedMulAccReduction:2809    assert(Opcode == Instruction::Add && "Unexpected opcode");2810    Opcode = Instruction::Sub;2811    [[fallthrough]];2812  case ExpressionTypes::ExtMulAccReduction: {2813    auto *RedR = cast<VPReductionRecipe>(ExpressionRecipes.back());2814    if (RedR->isPartialReduction()) {2815      auto *Ext0R = cast<VPWidenCastRecipe>(ExpressionRecipes[0]);2816      auto *Ext1R = cast<VPWidenCastRecipe>(ExpressionRecipes[1]);2817      auto *Mul = cast<VPWidenRecipe>(ExpressionRecipes[2]);2818      return Ctx.TTI.getPartialReductionCost(2819          Opcode, Ctx.Types.inferScalarType(getOperand(0)),2820          Ctx.Types.inferScalarType(getOperand(1)), RedTy, VF,2821          TargetTransformInfo::getPartialReductionExtendKind(2822              Ext0R->getOpcode()),2823          TargetTransformInfo::getPartialReductionExtendKind(2824              Ext1R->getOpcode()),2825          Mul->getOpcode(), Ctx.CostKind);2826    }2827    return Ctx.TTI.getMulAccReductionCost(2828        cast<VPWidenCastRecipe>(ExpressionRecipes.front())->getOpcode() ==2829            Instruction::ZExt,2830        Opcode, RedTy, SrcVecTy, Ctx.CostKind);2831  }2832  }2833  llvm_unreachable("Unknown VPExpressionRecipe::ExpressionTypes enum");2834}2835 2836bool VPExpressionRecipe::mayReadOrWriteMemory() const {2837  return any_of(ExpressionRecipes, [](VPSingleDefRecipe *R) {2838    return R->mayReadFromMemory() || R->mayWriteToMemory();2839  });2840}2841 2842bool VPExpressionRecipe::mayHaveSideEffects() const {2843  assert(2844      none_of(ExpressionRecipes,2845              [](VPSingleDefRecipe *R) { return R->mayHaveSideEffects(); }) &&2846      "expression cannot contain recipes with side-effects");2847  return false;2848}2849 2850bool VPExpressionRecipe::isSingleScalar() const {2851  // Cannot use vputils::isSingleScalar(), because all external operands2852  // of the expression will be live-ins while bundled.2853  auto *RR = dyn_cast<VPReductionRecipe>(ExpressionRecipes.back());2854  return RR && !RR->isPartialReduction();2855}2856 2857#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)2858 2859void VPExpressionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2860                                     VPSlotTracker &SlotTracker) const {2861  O << Indent << "EXPRESSION ";2862  printAsOperand(O, SlotTracker);2863  O << " = ";2864  auto *Red = cast<VPReductionRecipe>(ExpressionRecipes.back());2865  unsigned Opcode = RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind());2866 2867  switch (ExpressionType) {2868  case ExpressionTypes::ExtendedReduction: {2869    getOperand(1)->printAsOperand(O, SlotTracker);2870    O << " + " << (Red->isPartialReduction() ? "partial." : "") << "reduce.";2871    O << Instruction::getOpcodeName(Opcode) << " (";2872    getOperand(0)->printAsOperand(O, SlotTracker);2873    Red->printFlags(O);2874 2875    auto *Ext0 = cast<VPWidenCastRecipe>(ExpressionRecipes[0]);2876    O << Instruction::getOpcodeName(Ext0->getOpcode()) << " to "2877      << *Ext0->getResultType();2878    if (Red->isConditional()) {2879      O << ", ";2880      Red->getCondOp()->printAsOperand(O, SlotTracker);2881    }2882    O << ")";2883    break;2884  }2885  case ExpressionTypes::ExtNegatedMulAccReduction: {2886    getOperand(getNumOperands() - 1)->printAsOperand(O, SlotTracker);2887    O << " + " << (Red->isPartialReduction() ? "partial." : "") << "reduce.";2888    O << Instruction::getOpcodeName(2889             RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()))2890      << " (sub (0, mul";2891    auto *Mul = cast<VPWidenRecipe>(ExpressionRecipes[2]);2892    Mul->printFlags(O);2893    O << "(";2894    getOperand(0)->printAsOperand(O, SlotTracker);2895    auto *Ext0 = cast<VPWidenCastRecipe>(ExpressionRecipes[0]);2896    O << " " << Instruction::getOpcodeName(Ext0->getOpcode()) << " to "2897      << *Ext0->getResultType() << "), (";2898    getOperand(1)->printAsOperand(O, SlotTracker);2899    auto *Ext1 = cast<VPWidenCastRecipe>(ExpressionRecipes[1]);2900    O << " " << Instruction::getOpcodeName(Ext1->getOpcode()) << " to "2901      << *Ext1->getResultType() << ")";2902    if (Red->isConditional()) {2903      O << ", ";2904      Red->getCondOp()->printAsOperand(O, SlotTracker);2905    }2906    O << "))";2907    break;2908  }2909  case ExpressionTypes::MulAccReduction:2910  case ExpressionTypes::ExtMulAccReduction: {2911    getOperand(getNumOperands() - 1)->printAsOperand(O, SlotTracker);2912    O << " + " << (Red->isPartialReduction() ? "partial." : "") << "reduce.";2913    O << Instruction::getOpcodeName(2914             RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()))2915      << " (";2916    O << "mul";2917    bool IsExtended = ExpressionType == ExpressionTypes::ExtMulAccReduction;2918    auto *Mul = cast<VPWidenRecipe>(IsExtended ? ExpressionRecipes[2]2919                                               : ExpressionRecipes[0]);2920    Mul->printFlags(O);2921    if (IsExtended)2922      O << "(";2923    getOperand(0)->printAsOperand(O, SlotTracker);2924    if (IsExtended) {2925      auto *Ext0 = cast<VPWidenCastRecipe>(ExpressionRecipes[0]);2926      O << " " << Instruction::getOpcodeName(Ext0->getOpcode()) << " to "2927        << *Ext0->getResultType() << "), (";2928    } else {2929      O << ", ";2930    }2931    getOperand(1)->printAsOperand(O, SlotTracker);2932    if (IsExtended) {2933      auto *Ext1 = cast<VPWidenCastRecipe>(ExpressionRecipes[1]);2934      O << " " << Instruction::getOpcodeName(Ext1->getOpcode()) << " to "2935        << *Ext1->getResultType() << ")";2936    }2937    if (Red->isConditional()) {2938      O << ", ";2939      Red->getCondOp()->printAsOperand(O, SlotTracker);2940    }2941    O << ")";2942    break;2943  }2944  }2945}2946 2947void VPReductionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2948                                    VPSlotTracker &SlotTracker) const {2949  if (isPartialReduction())2950    O << Indent << "PARTIAL-REDUCE ";2951  else2952    O << Indent << "REDUCE ";2953  printAsOperand(O, SlotTracker);2954  O << " = ";2955  getChainOp()->printAsOperand(O, SlotTracker);2956  O << " +";2957  printFlags(O);2958  O << " reduce."2959    << Instruction::getOpcodeName(2960           RecurrenceDescriptor::getOpcode(getRecurrenceKind()))2961    << " (";2962  getVecOp()->printAsOperand(O, SlotTracker);2963  if (isConditional()) {2964    O << ", ";2965    getCondOp()->printAsOperand(O, SlotTracker);2966  }2967  O << ")";2968}2969 2970void VPReductionEVLRecipe::printRecipe(raw_ostream &O, const Twine &Indent,2971                                       VPSlotTracker &SlotTracker) const {2972  O << Indent << "REDUCE ";2973  printAsOperand(O, SlotTracker);2974  O << " = ";2975  getChainOp()->printAsOperand(O, SlotTracker);2976  O << " +";2977  printFlags(O);2978  O << " vp.reduce."2979    << Instruction::getOpcodeName(2980           RecurrenceDescriptor::getOpcode(getRecurrenceKind()))2981    << " (";2982  getVecOp()->printAsOperand(O, SlotTracker);2983  O << ", ";2984  getEVL()->printAsOperand(O, SlotTracker);2985  if (isConditional()) {2986    O << ", ";2987    getCondOp()->printAsOperand(O, SlotTracker);2988  }2989  O << ")";2990}2991 2992#endif2993 2994/// A helper function to scalarize a single Instruction in the innermost loop.2995/// Generates a sequence of scalar instances for lane \p Lane. Uses the VPValue2996/// operands from \p RepRecipe instead of \p Instr's operands.2997static void scalarizeInstruction(const Instruction *Instr,2998                                 VPReplicateRecipe *RepRecipe,2999                                 const VPLane &Lane, VPTransformState &State) {3000  assert((!Instr->getType()->isAggregateType() ||3001          canVectorizeTy(Instr->getType())) &&3002         "Expected vectorizable or non-aggregate type.");3003 3004  // Does this instruction return a value ?3005  bool IsVoidRetTy = Instr->getType()->isVoidTy();3006 3007  Instruction *Cloned = Instr->clone();3008  if (!IsVoidRetTy) {3009    Cloned->setName(Instr->getName() + ".cloned");3010    Type *ResultTy = State.TypeAnalysis.inferScalarType(RepRecipe);3011    // The operands of the replicate recipe may have been narrowed, resulting in3012    // a narrower result type. Update the type of the cloned instruction to the3013    // correct type.3014    if (ResultTy != Cloned->getType())3015      Cloned->mutateType(ResultTy);3016  }3017 3018  RepRecipe->applyFlags(*Cloned);3019  RepRecipe->applyMetadata(*Cloned);3020 3021  if (RepRecipe->hasPredicate())3022    cast<CmpInst>(Cloned)->setPredicate(RepRecipe->getPredicate());3023 3024  if (auto DL = RepRecipe->getDebugLoc())3025    State.setDebugLocFrom(DL);3026 3027  // Replace the operands of the cloned instructions with their scalar3028  // equivalents in the new loop.3029  for (const auto &I : enumerate(RepRecipe->operands())) {3030    auto InputLane = Lane;3031    VPValue *Operand = I.value();3032    if (vputils::isSingleScalar(Operand))3033      InputLane = VPLane::getFirstLane();3034    Cloned->setOperand(I.index(), State.get(Operand, InputLane));3035  }3036 3037  // Place the cloned scalar in the new loop.3038  State.Builder.Insert(Cloned);3039 3040  State.set(RepRecipe, Cloned, Lane);3041 3042  // If we just cloned a new assumption, add it the assumption cache.3043  if (auto *II = dyn_cast<AssumeInst>(Cloned))3044    State.AC->registerAssumption(II);3045 3046  assert(3047      (RepRecipe->getRegion() ||3048       !RepRecipe->getParent()->getPlan()->getVectorLoopRegion() ||3049       all_of(RepRecipe->operands(),3050              [](VPValue *Op) { return Op->isDefinedOutsideLoopRegions(); })) &&3051      "Expected a recipe is either within a region or all of its operands "3052      "are defined outside the vectorized region.");3053}3054 3055void VPReplicateRecipe::execute(VPTransformState &State) {3056  Instruction *UI = getUnderlyingInstr();3057 3058  if (!State.Lane) {3059    assert(IsSingleScalar && "VPReplicateRecipes outside replicate regions "3060                             "must have already been unrolled");3061    scalarizeInstruction(UI, this, VPLane(0), State);3062    return;3063  }3064 3065  assert((State.VF.isScalar() || !isSingleScalar()) &&3066         "uniform recipe shouldn't be predicated");3067  assert(!State.VF.isScalable() && "Can't scalarize a scalable vector");3068  scalarizeInstruction(UI, this, *State.Lane, State);3069  // Insert scalar instance packing it into a vector.3070  if (State.VF.isVector() && shouldPack()) {3071    Value *WideValue =3072        State.Lane->isFirstLane()3073            ? PoisonValue::get(toVectorizedTy(UI->getType(), State.VF))3074            : State.get(this);3075    State.set(this, State.packScalarIntoVectorizedValue(this, WideValue,3076                                                        *State.Lane));3077  }3078}3079 3080bool VPReplicateRecipe::shouldPack() const {3081  // Find if the recipe is used by a widened recipe via an intervening3082  // VPPredInstPHIRecipe. In this case, also pack the scalar values in a vector.3083  return any_of(users(), [](const VPUser *U) {3084    if (auto *PredR = dyn_cast<VPPredInstPHIRecipe>(U))3085      return !vputils::onlyScalarValuesUsed(PredR);3086    return false;3087  });3088}3089 3090/// Returns a SCEV expression for \p Ptr if it is a pointer computation for3091/// which the legacy cost model computes a SCEV expression when computing the3092/// address cost. Computing SCEVs for VPValues is incomplete and returns3093/// SCEVCouldNotCompute in cases the legacy cost model can compute SCEVs. In3094/// those cases we fall back to the legacy cost model. Otherwise return nullptr.3095static const SCEV *getAddressAccessSCEV(const VPValue *Ptr, ScalarEvolution &SE,3096                                        const Loop *L) {3097  auto *PtrR = Ptr->getDefiningRecipe();3098  if (!PtrR || !((isa<VPReplicateRecipe>(Ptr) &&3099                  cast<VPReplicateRecipe>(Ptr)->getOpcode() ==3100                      Instruction::GetElementPtr) ||3101                 isa<VPWidenGEPRecipe>(Ptr) ||3102                 match(Ptr, m_GetElementPtr(m_VPValue(), m_VPValue()))))3103    return nullptr;3104 3105  // We are looking for a GEP where all indices are either loop invariant or3106  // inductions.3107  for (VPValue *Opd : drop_begin(PtrR->operands())) {3108    if (!Opd->isDefinedOutsideLoopRegions() &&3109        !isa<VPScalarIVStepsRecipe, VPWidenIntOrFpInductionRecipe>(Opd))3110      return nullptr;3111  }3112 3113  return vputils::getSCEVExprForVPValue(Ptr, SE, L);3114}3115 3116/// Returns true if \p V is used as part of the address of another load or3117/// store.3118static bool isUsedByLoadStoreAddress(const VPUser *V) {3119  SmallPtrSet<const VPUser *, 4> Seen;3120  SmallVector<const VPUser *> WorkList = {V};3121 3122  while (!WorkList.empty()) {3123    auto *Cur = dyn_cast<VPSingleDefRecipe>(WorkList.pop_back_val());3124    if (!Cur || !Seen.insert(Cur).second)3125      continue;3126 3127    auto *Blend = dyn_cast<VPBlendRecipe>(Cur);3128    // Skip blends that use V only through a compare by checking if any incoming3129    // value was already visited.3130    if (Blend && none_of(seq<unsigned>(0, Blend->getNumIncomingValues()),3131                         [&](unsigned I) {3132                           return Seen.contains(3133                               Blend->getIncomingValue(I)->getDefiningRecipe());3134                         }))3135      continue;3136 3137    for (VPUser *U : Cur->users()) {3138      if (auto *InterleaveR = dyn_cast<VPInterleaveBase>(U))3139        if (InterleaveR->getAddr() == Cur)3140          return true;3141      if (auto *RepR = dyn_cast<VPReplicateRecipe>(U)) {3142        if (RepR->getOpcode() == Instruction::Load &&3143            RepR->getOperand(0) == Cur)3144          return true;3145        if (RepR->getOpcode() == Instruction::Store &&3146            RepR->getOperand(1) == Cur)3147          return true;3148      }3149      if (auto *MemR = dyn_cast<VPWidenMemoryRecipe>(U)) {3150        if (MemR->getAddr() == Cur && MemR->isConsecutive())3151          return true;3152      }3153    }3154 3155    // The legacy cost model only supports scalarization loads/stores with phi3156    // addresses, if the phi is directly used as load/store address. Don't3157    // traverse further for Blends.3158    if (Blend)3159      continue;3160 3161    append_range(WorkList, Cur->users());3162  }3163  return false;3164}3165 3166InstructionCost VPReplicateRecipe::computeCost(ElementCount VF,3167                                               VPCostContext &Ctx) const {3168  Instruction *UI = cast<Instruction>(getUnderlyingValue());3169  // VPReplicateRecipe may be cloned as part of an existing VPlan-to-VPlan3170  // transform, avoid computing their cost multiple times for now.3171  Ctx.SkipCostComputation.insert(UI);3172 3173  if (VF.isScalable() && !isSingleScalar())3174    return InstructionCost::getInvalid();3175 3176  switch (UI->getOpcode()) {3177  case Instruction::GetElementPtr:3178    // We mark this instruction as zero-cost because the cost of GEPs in3179    // vectorized code depends on whether the corresponding memory instruction3180    // is scalarized or not. Therefore, we handle GEPs with the memory3181    // instruction cost.3182    return 0;3183  case Instruction::Call: {3184    auto *CalledFn =3185        cast<Function>(getOperand(getNumOperands() - 1)->getLiveInIRValue());3186 3187    SmallVector<const VPValue *> ArgOps(drop_end(operands()));3188    SmallVector<Type *, 4> Tys;3189    for (const VPValue *ArgOp : ArgOps)3190      Tys.push_back(Ctx.Types.inferScalarType(ArgOp));3191 3192    if (CalledFn->isIntrinsic())3193      // Various pseudo-intrinsics with costs of 0 are scalarized instead of3194      // vectorized via VPWidenIntrinsicRecipe. Return 0 for them early.3195      switch (CalledFn->getIntrinsicID()) {3196      case Intrinsic::assume:3197      case Intrinsic::lifetime_end:3198      case Intrinsic::lifetime_start:3199      case Intrinsic::sideeffect:3200      case Intrinsic::pseudoprobe:3201      case Intrinsic::experimental_noalias_scope_decl: {3202        assert(getCostForIntrinsics(CalledFn->getIntrinsicID(), ArgOps, *this,3203                                    ElementCount::getFixed(1), Ctx) == 0 &&3204               "scalarizing intrinsic should be free");3205        return InstructionCost(0);3206      }3207      default:3208        break;3209      }3210 3211    Type *ResultTy = Ctx.Types.inferScalarType(this);3212    InstructionCost ScalarCallCost =3213        Ctx.TTI.getCallInstrCost(CalledFn, ResultTy, Tys, Ctx.CostKind);3214    if (isSingleScalar()) {3215      if (CalledFn->isIntrinsic())3216        ScalarCallCost = std::min(3217            ScalarCallCost,3218            getCostForIntrinsics(CalledFn->getIntrinsicID(), ArgOps, *this,3219                                 ElementCount::getFixed(1), Ctx));3220      return ScalarCallCost;3221    }3222 3223    return ScalarCallCost * VF.getFixedValue() +3224           Ctx.getScalarizationOverhead(ResultTy, ArgOps, VF);3225  }3226  case Instruction::Add:3227  case Instruction::Sub:3228  case Instruction::FAdd:3229  case Instruction::FSub:3230  case Instruction::Mul:3231  case Instruction::FMul:3232  case Instruction::FDiv:3233  case Instruction::FRem:3234  case Instruction::Shl:3235  case Instruction::LShr:3236  case Instruction::AShr:3237  case Instruction::And:3238  case Instruction::Or:3239  case Instruction::Xor:3240  case Instruction::ICmp:3241  case Instruction::FCmp:3242    return getCostForRecipeWithOpcode(getOpcode(), ElementCount::getFixed(1),3243                                      Ctx) *3244           (isSingleScalar() ? 1 : VF.getFixedValue());3245  case Instruction::SDiv:3246  case Instruction::UDiv:3247  case Instruction::SRem:3248  case Instruction::URem: {3249    InstructionCost ScalarCost =3250        getCostForRecipeWithOpcode(getOpcode(), ElementCount::getFixed(1), Ctx);3251    if (isSingleScalar())3252      return ScalarCost;3253 3254    ScalarCost = ScalarCost * VF.getFixedValue() +3255                 Ctx.getScalarizationOverhead(Ctx.Types.inferScalarType(this),3256                                              to_vector(operands()), VF);3257    // If the recipe is not predicated (i.e. not in a replicate region), return3258    // the scalar cost. Otherwise handle predicated cost.3259    if (!getRegion()->isReplicator())3260      return ScalarCost;3261 3262    // Account for the phi nodes that we will create.3263    ScalarCost += VF.getFixedValue() *3264                  Ctx.TTI.getCFInstrCost(Instruction::PHI, Ctx.CostKind);3265    // Scale the cost by the probability of executing the predicated blocks.3266    // This assumes the predicated block for each vector lane is equally3267    // likely.3268    ScalarCost /= Ctx.getPredBlockCostDivisor(UI->getParent());3269    return ScalarCost;3270  }3271  case Instruction::Load:3272  case Instruction::Store: {3273    // TODO: See getMemInstScalarizationCost for how to handle replicating and3274    // predicated cases.3275    const VPRegionBlock *ParentRegion = getRegion();3276    if (ParentRegion && ParentRegion->isReplicator())3277      break;3278 3279    bool IsLoad = UI->getOpcode() == Instruction::Load;3280    const VPValue *PtrOp = getOperand(!IsLoad);3281    const SCEV *PtrSCEV = getAddressAccessSCEV(PtrOp, Ctx.SE, Ctx.L);3282    if (isa_and_nonnull<SCEVCouldNotCompute>(PtrSCEV))3283      break;3284 3285    Type *ValTy = Ctx.Types.inferScalarType(IsLoad ? this : getOperand(0));3286    Type *ScalarPtrTy = Ctx.Types.inferScalarType(PtrOp);3287    const Align Alignment = getLoadStoreAlignment(UI);3288    unsigned AS = cast<PointerType>(ScalarPtrTy)->getAddressSpace();3289    TTI::OperandValueInfo OpInfo = TTI::getOperandInfo(UI->getOperand(0));3290    InstructionCost ScalarMemOpCost = Ctx.TTI.getMemoryOpCost(3291        UI->getOpcode(), ValTy, Alignment, AS, Ctx.CostKind, OpInfo);3292 3293    Type *PtrTy = isSingleScalar() ? ScalarPtrTy : toVectorTy(ScalarPtrTy, VF);3294    bool PreferVectorizedAddressing = Ctx.TTI.prefersVectorizedAddressing();3295    bool UsedByLoadStoreAddress =3296        !PreferVectorizedAddressing && isUsedByLoadStoreAddress(this);3297    InstructionCost ScalarCost =3298        ScalarMemOpCost + Ctx.TTI.getAddressComputationCost(3299                              PtrTy, UsedByLoadStoreAddress ? nullptr : &Ctx.SE,3300                              PtrSCEV, Ctx.CostKind);3301    if (isSingleScalar())3302      return ScalarCost;3303 3304    SmallVector<const VPValue *> OpsToScalarize;3305    Type *ResultTy = Type::getVoidTy(PtrTy->getContext());3306    // Set ResultTy and OpsToScalarize, if scalarization is needed. Currently we3307    // don't assign scalarization overhead in general, if the target prefers3308    // vectorized addressing or the loaded value is used as part of an address3309    // of another load or store.3310    if (!UsedByLoadStoreAddress) {3311      bool EfficientVectorLoadStore =3312          Ctx.TTI.supportsEfficientVectorElementLoadStore();3313      if (!(IsLoad && !PreferVectorizedAddressing) &&3314          !(!IsLoad && EfficientVectorLoadStore))3315        append_range(OpsToScalarize, operands());3316 3317      if (!EfficientVectorLoadStore)3318        ResultTy = Ctx.Types.inferScalarType(this);3319    }3320 3321    return (ScalarCost * VF.getFixedValue()) +3322           Ctx.getScalarizationOverhead(ResultTy, OpsToScalarize, VF, true);3323  }3324  }3325 3326  return Ctx.getLegacyCost(UI, VF);3327}3328 3329#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)3330void VPReplicateRecipe::printRecipe(raw_ostream &O, const Twine &Indent,3331                                    VPSlotTracker &SlotTracker) const {3332  O << Indent << (IsSingleScalar ? "CLONE " : "REPLICATE ");3333 3334  if (!getUnderlyingInstr()->getType()->isVoidTy()) {3335    printAsOperand(O, SlotTracker);3336    O << " = ";3337  }3338  if (auto *CB = dyn_cast<CallBase>(getUnderlyingInstr())) {3339    O << "call";3340    printFlags(O);3341    O << "@" << CB->getCalledFunction()->getName() << "(";3342    interleaveComma(make_range(op_begin(), op_begin() + (getNumOperands() - 1)),3343                    O, [&O, &SlotTracker](VPValue *Op) {3344                      Op->printAsOperand(O, SlotTracker);3345                    });3346    O << ")";3347  } else {3348    O << Instruction::getOpcodeName(getUnderlyingInstr()->getOpcode());3349    printFlags(O);3350    printOperands(O, SlotTracker);3351  }3352 3353  if (shouldPack())3354    O << " (S->V)";3355}3356#endif3357 3358void VPBranchOnMaskRecipe::execute(VPTransformState &State) {3359  assert(State.Lane && "Branch on Mask works only on single instance.");3360 3361  VPValue *BlockInMask = getOperand(0);3362  Value *ConditionBit = State.get(BlockInMask, *State.Lane);3363 3364  // Replace the temporary unreachable terminator with a new conditional branch,3365  // whose two destinations will be set later when they are created.3366  auto *CurrentTerminator = State.CFG.PrevBB->getTerminator();3367  assert(isa<UnreachableInst>(CurrentTerminator) &&3368         "Expected to replace unreachable terminator with conditional branch.");3369  auto CondBr =3370      State.Builder.CreateCondBr(ConditionBit, State.CFG.PrevBB, nullptr);3371  CondBr->setSuccessor(0, nullptr);3372  CurrentTerminator->eraseFromParent();3373}3374 3375InstructionCost VPBranchOnMaskRecipe::computeCost(ElementCount VF,3376                                                  VPCostContext &Ctx) const {3377  // The legacy cost model doesn't assign costs to branches for individual3378  // replicate regions. Match the current behavior in the VPlan cost model for3379  // now.3380  return 0;3381}3382 3383void VPPredInstPHIRecipe::execute(VPTransformState &State) {3384  assert(State.Lane && "Predicated instruction PHI works per instance.");3385  Instruction *ScalarPredInst =3386      cast<Instruction>(State.get(getOperand(0), *State.Lane));3387  BasicBlock *PredicatedBB = ScalarPredInst->getParent();3388  BasicBlock *PredicatingBB = PredicatedBB->getSinglePredecessor();3389  assert(PredicatingBB && "Predicated block has no single predecessor.");3390  assert(isa<VPReplicateRecipe>(getOperand(0)) &&3391         "operand must be VPReplicateRecipe");3392 3393  // By current pack/unpack logic we need to generate only a single phi node: if3394  // a vector value for the predicated instruction exists at this point it means3395  // the instruction has vector users only, and a phi for the vector value is3396  // needed. In this case the recipe of the predicated instruction is marked to3397  // also do that packing, thereby "hoisting" the insert-element sequence.3398  // Otherwise, a phi node for the scalar value is needed.3399  if (State.hasVectorValue(getOperand(0))) {3400    auto *VecI = cast<Instruction>(State.get(getOperand(0)));3401    assert((isa<InsertElementInst, InsertValueInst>(VecI)) &&3402           "Packed operands must generate an insertelement or insertvalue");3403 3404    // If VectorI is a struct, it will be a sequence like:3405    // %1       = insertvalue %unmodified, %x, 03406    // %2       = insertvalue %1, %y, 13407    // %VectorI = insertvalue %2, %z, 23408    // To get the unmodified vector we need to look through the chain.3409    if (auto *StructTy = dyn_cast<StructType>(VecI->getType()))3410      for (unsigned I = 0; I < StructTy->getNumContainedTypes() - 1; I++)3411        VecI = cast<InsertValueInst>(VecI->getOperand(0));3412 3413    PHINode *VPhi = State.Builder.CreatePHI(VecI->getType(), 2);3414    VPhi->addIncoming(VecI->getOperand(0), PredicatingBB); // Unmodified vector.3415    VPhi->addIncoming(VecI, PredicatedBB); // New vector with inserted element.3416    if (State.hasVectorValue(this))3417      State.reset(this, VPhi);3418    else3419      State.set(this, VPhi);3420    // NOTE: Currently we need to update the value of the operand, so the next3421    // predicated iteration inserts its generated value in the correct vector.3422    State.reset(getOperand(0), VPhi);3423  } else {3424    if (vputils::onlyFirstLaneUsed(this) && !State.Lane->isFirstLane())3425      return;3426 3427    Type *PredInstType = State.TypeAnalysis.inferScalarType(getOperand(0));3428    PHINode *Phi = State.Builder.CreatePHI(PredInstType, 2);3429    Phi->addIncoming(PoisonValue::get(ScalarPredInst->getType()),3430                     PredicatingBB);3431    Phi->addIncoming(ScalarPredInst, PredicatedBB);3432    if (State.hasScalarValue(this, *State.Lane))3433      State.reset(this, Phi, *State.Lane);3434    else3435      State.set(this, Phi, *State.Lane);3436    // NOTE: Currently we need to update the value of the operand, so the next3437    // predicated iteration inserts its generated value in the correct vector.3438    State.reset(getOperand(0), Phi, *State.Lane);3439  }3440}3441 3442#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)3443void VPPredInstPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,3444                                      VPSlotTracker &SlotTracker) const {3445  O << Indent << "PHI-PREDICATED-INSTRUCTION ";3446  printAsOperand(O, SlotTracker);3447  O << " = ";3448  printOperands(O, SlotTracker);3449}3450#endif3451 3452InstructionCost VPWidenMemoryRecipe::computeCost(ElementCount VF,3453                                                 VPCostContext &Ctx) const {3454  Type *Ty = toVectorTy(getLoadStoreType(&Ingredient), VF);3455  unsigned AS = cast<PointerType>(Ctx.Types.inferScalarType(getAddr()))3456                    ->getAddressSpace();3457  unsigned Opcode = isa<VPWidenLoadRecipe, VPWidenLoadEVLRecipe>(this)3458                        ? Instruction::Load3459                        : Instruction::Store;3460 3461  if (!Consecutive) {3462    // TODO: Using the original IR may not be accurate.3463    // Currently, ARM will use the underlying IR to calculate gather/scatter3464    // instruction cost.3465    assert(!Reverse &&3466           "Inconsecutive memory access should not have the order.");3467 3468    const Value *Ptr = getLoadStorePointerOperand(&Ingredient);3469    Type *PtrTy = Ptr->getType();3470 3471    // If the address value is uniform across all lanes, then the address can be3472    // calculated with scalar type and broadcast.3473    if (!vputils::isSingleScalar(getAddr()))3474      PtrTy = toVectorTy(PtrTy, VF);3475 3476    unsigned IID = isa<VPWidenLoadRecipe>(this)      ? Intrinsic::masked_gather3477                   : isa<VPWidenStoreRecipe>(this)   ? Intrinsic::masked_scatter3478                   : isa<VPWidenLoadEVLRecipe>(this) ? Intrinsic::vp_gather3479                                                     : Intrinsic::vp_scatter;3480    return Ctx.TTI.getAddressComputationCost(PtrTy, nullptr, nullptr,3481                                             Ctx.CostKind) +3482           Ctx.TTI.getMemIntrinsicInstrCost(3483               MemIntrinsicCostAttributes(IID, Ty, Ptr, IsMasked, Alignment,3484                                          &Ingredient),3485               Ctx.CostKind);3486  }3487 3488  InstructionCost Cost = 0;3489  if (IsMasked) {3490    unsigned IID = isa<VPWidenLoadRecipe>(this) ? Intrinsic::masked_load3491                                                : Intrinsic::masked_store;3492    Cost += Ctx.TTI.getMemIntrinsicInstrCost(3493        MemIntrinsicCostAttributes(IID, Ty, Alignment, AS), Ctx.CostKind);3494  } else {3495    TTI::OperandValueInfo OpInfo = Ctx.getOperandInfo(3496        isa<VPWidenLoadRecipe, VPWidenLoadEVLRecipe>(this) ? getOperand(0)3497                                                           : getOperand(1));3498    Cost += Ctx.TTI.getMemoryOpCost(Opcode, Ty, Alignment, AS, Ctx.CostKind,3499                                    OpInfo, &Ingredient);3500  }3501  if (!Reverse)3502    return Cost;3503 3504  return Cost += Ctx.TTI.getShuffleCost(3505             TargetTransformInfo::SK_Reverse, cast<VectorType>(Ty),3506             cast<VectorType>(Ty), {}, Ctx.CostKind, 0);3507}3508 3509void VPWidenLoadRecipe::execute(VPTransformState &State) {3510  Type *ScalarDataTy = getLoadStoreType(&Ingredient);3511  auto *DataTy = VectorType::get(ScalarDataTy, State.VF);3512  bool CreateGather = !isConsecutive();3513 3514  auto &Builder = State.Builder;3515  Value *Mask = nullptr;3516  if (auto *VPMask = getMask()) {3517    // Mask reversal is only needed for non-all-one (null) masks, as reverse3518    // of a null all-one mask is a null mask.3519    Mask = State.get(VPMask);3520    if (isReverse())3521      Mask = Builder.CreateVectorReverse(Mask, "reverse");3522  }3523 3524  Value *Addr = State.get(getAddr(), /*IsScalar*/ !CreateGather);3525  Value *NewLI;3526  if (CreateGather) {3527    NewLI = Builder.CreateMaskedGather(DataTy, Addr, Alignment, Mask, nullptr,3528                                       "wide.masked.gather");3529  } else if (Mask) {3530    NewLI =3531        Builder.CreateMaskedLoad(DataTy, Addr, Alignment, Mask,3532                                 PoisonValue::get(DataTy), "wide.masked.load");3533  } else {3534    NewLI = Builder.CreateAlignedLoad(DataTy, Addr, Alignment, "wide.load");3535  }3536  applyMetadata(*cast<Instruction>(NewLI));3537  if (Reverse)3538    NewLI = Builder.CreateVectorReverse(NewLI, "reverse");3539  State.set(this, NewLI);3540}3541 3542#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)3543void VPWidenLoadRecipe::printRecipe(raw_ostream &O, const Twine &Indent,3544                                    VPSlotTracker &SlotTracker) const {3545  O << Indent << "WIDEN ";3546  printAsOperand(O, SlotTracker);3547  O << " = load ";3548  printOperands(O, SlotTracker);3549}3550#endif3551 3552/// Use all-true mask for reverse rather than actual mask, as it avoids a3553/// dependence w/o affecting the result.3554static Instruction *createReverseEVL(IRBuilderBase &Builder, Value *Operand,3555                                     Value *EVL, const Twine &Name) {3556  VectorType *ValTy = cast<VectorType>(Operand->getType());3557  Value *AllTrueMask =3558      Builder.CreateVectorSplat(ValTy->getElementCount(), Builder.getTrue());3559  return Builder.CreateIntrinsic(ValTy, Intrinsic::experimental_vp_reverse,3560                                 {Operand, AllTrueMask, EVL}, nullptr, Name);3561}3562 3563void VPWidenLoadEVLRecipe::execute(VPTransformState &State) {3564  Type *ScalarDataTy = getLoadStoreType(&Ingredient);3565  auto *DataTy = VectorType::get(ScalarDataTy, State.VF);3566  bool CreateGather = !isConsecutive();3567 3568  auto &Builder = State.Builder;3569  CallInst *NewLI;3570  Value *EVL = State.get(getEVL(), VPLane(0));3571  Value *Addr = State.get(getAddr(), !CreateGather);3572  Value *Mask = nullptr;3573  if (VPValue *VPMask = getMask()) {3574    Mask = State.get(VPMask);3575    if (isReverse())3576      Mask = createReverseEVL(Builder, Mask, EVL, "vp.reverse.mask");3577  } else {3578    Mask = Builder.CreateVectorSplat(State.VF, Builder.getTrue());3579  }3580 3581  if (CreateGather) {3582    NewLI =3583        Builder.CreateIntrinsic(DataTy, Intrinsic::vp_gather, {Addr, Mask, EVL},3584                                nullptr, "wide.masked.gather");3585  } else {3586    NewLI = Builder.CreateIntrinsic(DataTy, Intrinsic::vp_load,3587                                    {Addr, Mask, EVL}, nullptr, "vp.op.load");3588  }3589  NewLI->addParamAttr(3590      0, Attribute::getWithAlignment(NewLI->getContext(), Alignment));3591  applyMetadata(*NewLI);3592  Instruction *Res = NewLI;3593  if (isReverse())3594    Res = createReverseEVL(Builder, Res, EVL, "vp.reverse");3595  State.set(this, Res);3596}3597 3598InstructionCost VPWidenLoadEVLRecipe::computeCost(ElementCount VF,3599                                                  VPCostContext &Ctx) const {3600  if (!Consecutive || IsMasked)3601    return VPWidenMemoryRecipe::computeCost(VF, Ctx);3602 3603  // We need to use the getMemIntrinsicInstrCost() instead of getMemoryOpCost()3604  // here because the EVL recipes using EVL to replace the tail mask. But in the3605  // legacy model, it will always calculate the cost of mask.3606  // TODO: Using getMemoryOpCost() instead of getMemIntrinsicInstrCost  when we3607  // don't need to compare to the legacy cost model.3608  Type *Ty = toVectorTy(getLoadStoreType(&Ingredient), VF);3609  unsigned AS = cast<PointerType>(Ctx.Types.inferScalarType(getAddr()))3610                    ->getAddressSpace();3611  // FIXME: getMaskedMemoryOpCost assumes masked_* intrinsics.3612  // After migrating to getMemIntrinsicInstrCost, switch this to vp_load.3613  InstructionCost Cost = Ctx.TTI.getMemIntrinsicInstrCost(3614      MemIntrinsicCostAttributes(Intrinsic::masked_load, Ty, Alignment, AS),3615      Ctx.CostKind);3616  if (!Reverse)3617    return Cost;3618 3619  return Cost + Ctx.TTI.getShuffleCost(3620                    TargetTransformInfo::SK_Reverse, cast<VectorType>(Ty),3621                    cast<VectorType>(Ty), {}, Ctx.CostKind, 0);3622}3623 3624#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)3625void VPWidenLoadEVLRecipe::printRecipe(raw_ostream &O, const Twine &Indent,3626                                       VPSlotTracker &SlotTracker) const {3627  O << Indent << "WIDEN ";3628  printAsOperand(O, SlotTracker);3629  O << " = vp.load ";3630  printOperands(O, SlotTracker);3631}3632#endif3633 3634void VPWidenStoreRecipe::execute(VPTransformState &State) {3635  VPValue *StoredVPValue = getStoredValue();3636  bool CreateScatter = !isConsecutive();3637 3638  auto &Builder = State.Builder;3639 3640  Value *Mask = nullptr;3641  if (auto *VPMask = getMask()) {3642    // Mask reversal is only needed for non-all-one (null) masks, as reverse3643    // of a null all-one mask is a null mask.3644    Mask = State.get(VPMask);3645    if (isReverse())3646      Mask = Builder.CreateVectorReverse(Mask, "reverse");3647  }3648 3649  Value *StoredVal = State.get(StoredVPValue);3650  if (isReverse()) {3651    // If we store to reverse consecutive memory locations, then we need3652    // to reverse the order of elements in the stored value.3653    StoredVal = Builder.CreateVectorReverse(StoredVal, "reverse");3654    // We don't want to update the value in the map as it might be used in3655    // another expression. So don't call resetVectorValue(StoredVal).3656  }3657  Value *Addr = State.get(getAddr(), /*IsScalar*/ !CreateScatter);3658  Instruction *NewSI = nullptr;3659  if (CreateScatter)3660    NewSI = Builder.CreateMaskedScatter(StoredVal, Addr, Alignment, Mask);3661  else if (Mask)3662    NewSI = Builder.CreateMaskedStore(StoredVal, Addr, Alignment, Mask);3663  else3664    NewSI = Builder.CreateAlignedStore(StoredVal, Addr, Alignment);3665  applyMetadata(*NewSI);3666}3667 3668#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)3669void VPWidenStoreRecipe::printRecipe(raw_ostream &O, const Twine &Indent,3670                                     VPSlotTracker &SlotTracker) const {3671  O << Indent << "WIDEN store ";3672  printOperands(O, SlotTracker);3673}3674#endif3675 3676void VPWidenStoreEVLRecipe::execute(VPTransformState &State) {3677  VPValue *StoredValue = getStoredValue();3678  bool CreateScatter = !isConsecutive();3679 3680  auto &Builder = State.Builder;3681 3682  CallInst *NewSI = nullptr;3683  Value *StoredVal = State.get(StoredValue);3684  Value *EVL = State.get(getEVL(), VPLane(0));3685  if (isReverse())3686    StoredVal = createReverseEVL(Builder, StoredVal, EVL, "vp.reverse");3687  Value *Mask = nullptr;3688  if (VPValue *VPMask = getMask()) {3689    Mask = State.get(VPMask);3690    if (isReverse())3691      Mask = createReverseEVL(Builder, Mask, EVL, "vp.reverse.mask");3692  } else {3693    Mask = Builder.CreateVectorSplat(State.VF, Builder.getTrue());3694  }3695  Value *Addr = State.get(getAddr(), !CreateScatter);3696  if (CreateScatter) {3697    NewSI = Builder.CreateIntrinsic(Type::getVoidTy(EVL->getContext()),3698                                    Intrinsic::vp_scatter,3699                                    {StoredVal, Addr, Mask, EVL});3700  } else {3701    NewSI = Builder.CreateIntrinsic(Type::getVoidTy(EVL->getContext()),3702                                    Intrinsic::vp_store,3703                                    {StoredVal, Addr, Mask, EVL});3704  }3705  NewSI->addParamAttr(3706      1, Attribute::getWithAlignment(NewSI->getContext(), Alignment));3707  applyMetadata(*NewSI);3708}3709 3710InstructionCost VPWidenStoreEVLRecipe::computeCost(ElementCount VF,3711                                                   VPCostContext &Ctx) const {3712  if (!Consecutive || IsMasked)3713    return VPWidenMemoryRecipe::computeCost(VF, Ctx);3714 3715  // We need to use the getMemIntrinsicInstrCost() instead of getMemoryOpCost()3716  // here because the EVL recipes using EVL to replace the tail mask. But in the3717  // legacy model, it will always calculate the cost of mask.3718  // TODO: Using getMemoryOpCost() instead of getMemIntrinsicInstrCost when we3719  // don't need to compare to the legacy cost model.3720  Type *Ty = toVectorTy(getLoadStoreType(&Ingredient), VF);3721  unsigned AS = cast<PointerType>(Ctx.Types.inferScalarType(getAddr()))3722                    ->getAddressSpace();3723  // FIXME: getMaskedMemoryOpCost assumes masked_* intrinsics.3724  // After migrating to getMemIntrinsicInstrCost, switch this to vp_store.3725  InstructionCost Cost = Ctx.TTI.getMemIntrinsicInstrCost(3726      MemIntrinsicCostAttributes(Intrinsic::masked_store, Ty, Alignment, AS),3727      Ctx.CostKind);3728  if (!Reverse)3729    return Cost;3730 3731  return Cost + Ctx.TTI.getShuffleCost(3732                    TargetTransformInfo::SK_Reverse, cast<VectorType>(Ty),3733                    cast<VectorType>(Ty), {}, Ctx.CostKind, 0);3734}3735 3736#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)3737void VPWidenStoreEVLRecipe::printRecipe(raw_ostream &O, const Twine &Indent,3738                                        VPSlotTracker &SlotTracker) const {3739  O << Indent << "WIDEN vp.store ";3740  printOperands(O, SlotTracker);3741}3742#endif3743 3744static Value *createBitOrPointerCast(IRBuilderBase &Builder, Value *V,3745                                     VectorType *DstVTy, const DataLayout &DL) {3746  // Verify that V is a vector type with same number of elements as DstVTy.3747  auto VF = DstVTy->getElementCount();3748  auto *SrcVecTy = cast<VectorType>(V->getType());3749  assert(VF == SrcVecTy->getElementCount() && "Vector dimensions do not match");3750  Type *SrcElemTy = SrcVecTy->getElementType();3751  Type *DstElemTy = DstVTy->getElementType();3752  assert((DL.getTypeSizeInBits(SrcElemTy) == DL.getTypeSizeInBits(DstElemTy)) &&3753         "Vector elements must have same size");3754 3755  // Do a direct cast if element types are castable.3756  if (CastInst::isBitOrNoopPointerCastable(SrcElemTy, DstElemTy, DL)) {3757    return Builder.CreateBitOrPointerCast(V, DstVTy);3758  }3759  // V cannot be directly casted to desired vector type.3760  // May happen when V is a floating point vector but DstVTy is a vector of3761  // pointers or vice-versa. Handle this using a two-step bitcast using an3762  // intermediate Integer type for the bitcast i.e. Ptr <-> Int <-> Float.3763  assert((DstElemTy->isPointerTy() != SrcElemTy->isPointerTy()) &&3764         "Only one type should be a pointer type");3765  assert((DstElemTy->isFloatingPointTy() != SrcElemTy->isFloatingPointTy()) &&3766         "Only one type should be a floating point type");3767  Type *IntTy =3768      IntegerType::getIntNTy(V->getContext(), DL.getTypeSizeInBits(SrcElemTy));3769  auto *VecIntTy = VectorType::get(IntTy, VF);3770  Value *CastVal = Builder.CreateBitOrPointerCast(V, VecIntTy);3771  return Builder.CreateBitOrPointerCast(CastVal, DstVTy);3772}3773 3774/// Return a vector containing interleaved elements from multiple3775/// smaller input vectors.3776static Value *interleaveVectors(IRBuilderBase &Builder, ArrayRef<Value *> Vals,3777                                const Twine &Name) {3778  unsigned Factor = Vals.size();3779  assert(Factor > 1 && "Tried to interleave invalid number of vectors");3780 3781  VectorType *VecTy = cast<VectorType>(Vals[0]->getType());3782#ifndef NDEBUG3783  for (Value *Val : Vals)3784    assert(Val->getType() == VecTy && "Tried to interleave mismatched types");3785#endif3786 3787  // Scalable vectors cannot use arbitrary shufflevectors (only splats), so3788  // must use intrinsics to interleave.3789  if (VecTy->isScalableTy()) {3790    assert(Factor <= 8 && "Unsupported interleave factor for scalable vectors");3791    return Builder.CreateVectorInterleave(Vals, Name);3792  }3793 3794  // Fixed length. Start by concatenating all vectors into a wide vector.3795  Value *WideVec = concatenateVectors(Builder, Vals);3796 3797  // Interleave the elements into the wide vector.3798  const unsigned NumElts = VecTy->getElementCount().getFixedValue();3799  return Builder.CreateShuffleVector(3800      WideVec, createInterleaveMask(NumElts, Factor), Name);3801}3802 3803// Try to vectorize the interleave group that \p Instr belongs to.3804//3805// E.g. Translate following interleaved load group (factor = 3):3806//   for (i = 0; i < N; i+=3) {3807//     R = Pic[i];             // Member of index 03808//     G = Pic[i+1];           // Member of index 13809//     B = Pic[i+2];           // Member of index 23810//     ... // do something to R, G, B3811//   }3812// To:3813//   %wide.vec = load <12 x i32>                       ; Read 4 tuples of R,G,B3814//   %R.vec = shuffle %wide.vec, poison, <0, 3, 6, 9>   ; R elements3815//   %G.vec = shuffle %wide.vec, poison, <1, 4, 7, 10>  ; G elements3816//   %B.vec = shuffle %wide.vec, poison, <2, 5, 8, 11>  ; B elements3817//3818// Or translate following interleaved store group (factor = 3):3819//   for (i = 0; i < N; i+=3) {3820//     ... do something to R, G, B3821//     Pic[i]   = R;           // Member of index 03822//     Pic[i+1] = G;           // Member of index 13823//     Pic[i+2] = B;           // Member of index 23824//   }3825// To:3826//   %R_G.vec = shuffle %R.vec, %G.vec, <0, 1, 2, ..., 7>3827//   %B_U.vec = shuffle %B.vec, poison, <0, 1, 2, 3, u, u, u, u>3828//   %interleaved.vec = shuffle %R_G.vec, %B_U.vec,3829//        <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11>    ; Interleave R,G,B elements3830//   store <12 x i32> %interleaved.vec              ; Write 4 tuples of R,G,B3831void VPInterleaveRecipe::execute(VPTransformState &State) {3832  assert(!State.Lane && "Interleave group being replicated.");3833  assert((!needsMaskForGaps() || !State.VF.isScalable()) &&3834         "Masking gaps for scalable vectors is not yet supported.");3835  const InterleaveGroup<Instruction> *Group = getInterleaveGroup();3836  Instruction *Instr = Group->getInsertPos();3837 3838  // Prepare for the vector type of the interleaved load/store.3839  Type *ScalarTy = getLoadStoreType(Instr);3840  unsigned InterleaveFactor = Group->getFactor();3841  auto *VecTy = VectorType::get(ScalarTy, State.VF * InterleaveFactor);3842 3843  VPValue *BlockInMask = getMask();3844  VPValue *Addr = getAddr();3845  Value *ResAddr = State.get(Addr, VPLane(0));3846 3847  auto CreateGroupMask = [&BlockInMask, &State,3848                          &InterleaveFactor](Value *MaskForGaps) -> Value * {3849    if (State.VF.isScalable()) {3850      assert(!MaskForGaps && "Interleaved groups with gaps are not supported.");3851      assert(InterleaveFactor <= 8 &&3852             "Unsupported deinterleave factor for scalable vectors");3853      auto *ResBlockInMask = State.get(BlockInMask);3854      SmallVector<Value *> Ops(InterleaveFactor, ResBlockInMask);3855      return interleaveVectors(State.Builder, Ops, "interleaved.mask");3856    }3857 3858    if (!BlockInMask)3859      return MaskForGaps;3860 3861    Value *ResBlockInMask = State.get(BlockInMask);3862    Value *ShuffledMask = State.Builder.CreateShuffleVector(3863        ResBlockInMask,3864        createReplicatedMask(InterleaveFactor, State.VF.getFixedValue()),3865        "interleaved.mask");3866    return MaskForGaps ? State.Builder.CreateBinOp(Instruction::And,3867                                                   ShuffledMask, MaskForGaps)3868                       : ShuffledMask;3869  };3870 3871  const DataLayout &DL = Instr->getDataLayout();3872  // Vectorize the interleaved load group.3873  if (isa<LoadInst>(Instr)) {3874    Value *MaskForGaps = nullptr;3875    if (needsMaskForGaps()) {3876      MaskForGaps =3877          createBitMaskForGaps(State.Builder, State.VF.getFixedValue(), *Group);3878      assert(MaskForGaps && "Mask for Gaps is required but it is null");3879    }3880 3881    Instruction *NewLoad;3882    if (BlockInMask || MaskForGaps) {3883      Value *GroupMask = CreateGroupMask(MaskForGaps);3884      Value *PoisonVec = PoisonValue::get(VecTy);3885      NewLoad = State.Builder.CreateMaskedLoad(VecTy, ResAddr,3886                                               Group->getAlign(), GroupMask,3887                                               PoisonVec, "wide.masked.vec");3888    } else3889      NewLoad = State.Builder.CreateAlignedLoad(VecTy, ResAddr,3890                                                Group->getAlign(), "wide.vec");3891    applyMetadata(*NewLoad);3892    // TODO: Also manage existing metadata using VPIRMetadata.3893    Group->addMetadata(NewLoad);3894 3895    ArrayRef<VPValue *> VPDefs = definedValues();3896    if (VecTy->isScalableTy()) {3897      // Scalable vectors cannot use arbitrary shufflevectors (only splats),3898      // so must use intrinsics to deinterleave.3899      assert(InterleaveFactor <= 8 &&3900             "Unsupported deinterleave factor for scalable vectors");3901      NewLoad = State.Builder.CreateIntrinsic(3902          Intrinsic::getDeinterleaveIntrinsicID(InterleaveFactor),3903          NewLoad->getType(), NewLoad,3904          /*FMFSource=*/nullptr, "strided.vec");3905    }3906 3907    auto CreateStridedVector = [&InterleaveFactor, &State,3908                                &NewLoad](unsigned Index) -> Value * {3909      assert(Index < InterleaveFactor && "Illegal group index");3910      if (State.VF.isScalable())3911        return State.Builder.CreateExtractValue(NewLoad, Index);3912 3913      // For fixed length VF, use shuffle to extract the sub-vectors from the3914      // wide load.3915      auto StrideMask =3916          createStrideMask(Index, InterleaveFactor, State.VF.getFixedValue());3917      return State.Builder.CreateShuffleVector(NewLoad, StrideMask,3918                                               "strided.vec");3919    };3920 3921    for (unsigned I = 0, J = 0; I < InterleaveFactor; ++I) {3922      Instruction *Member = Group->getMember(I);3923 3924      // Skip the gaps in the group.3925      if (!Member)3926        continue;3927 3928      Value *StridedVec = CreateStridedVector(I);3929 3930      // If this member has different type, cast the result type.3931      if (Member->getType() != ScalarTy) {3932        VectorType *OtherVTy = VectorType::get(Member->getType(), State.VF);3933        StridedVec =3934            createBitOrPointerCast(State.Builder, StridedVec, OtherVTy, DL);3935      }3936 3937      if (Group->isReverse())3938        StridedVec = State.Builder.CreateVectorReverse(StridedVec, "reverse");3939 3940      State.set(VPDefs[J], StridedVec);3941      ++J;3942    }3943    return;3944  }3945 3946  // The sub vector type for current instruction.3947  auto *SubVT = VectorType::get(ScalarTy, State.VF);3948 3949  // Vectorize the interleaved store group.3950  Value *MaskForGaps =3951      createBitMaskForGaps(State.Builder, State.VF.getKnownMinValue(), *Group);3952  assert(((MaskForGaps != nullptr) == needsMaskForGaps()) &&3953         "Mismatch between NeedsMaskForGaps and MaskForGaps");3954  ArrayRef<VPValue *> StoredValues = getStoredValues();3955  // Collect the stored vector from each member.3956  SmallVector<Value *, 4> StoredVecs;3957  unsigned StoredIdx = 0;3958  for (unsigned i = 0; i < InterleaveFactor; i++) {3959    assert((Group->getMember(i) || MaskForGaps) &&3960           "Fail to get a member from an interleaved store group");3961    Instruction *Member = Group->getMember(i);3962 3963    // Skip the gaps in the group.3964    if (!Member) {3965      Value *Undef = PoisonValue::get(SubVT);3966      StoredVecs.push_back(Undef);3967      continue;3968    }3969 3970    Value *StoredVec = State.get(StoredValues[StoredIdx]);3971    ++StoredIdx;3972 3973    if (Group->isReverse())3974      StoredVec = State.Builder.CreateVectorReverse(StoredVec, "reverse");3975 3976    // If this member has different type, cast it to a unified type.3977 3978    if (StoredVec->getType() != SubVT)3979      StoredVec = createBitOrPointerCast(State.Builder, StoredVec, SubVT, DL);3980 3981    StoredVecs.push_back(StoredVec);3982  }3983 3984  // Interleave all the smaller vectors into one wider vector.3985  Value *IVec = interleaveVectors(State.Builder, StoredVecs, "interleaved.vec");3986  Instruction *NewStoreInstr;3987  if (BlockInMask || MaskForGaps) {3988    Value *GroupMask = CreateGroupMask(MaskForGaps);3989    NewStoreInstr = State.Builder.CreateMaskedStore(3990        IVec, ResAddr, Group->getAlign(), GroupMask);3991  } else3992    NewStoreInstr =3993        State.Builder.CreateAlignedStore(IVec, ResAddr, Group->getAlign());3994 3995  applyMetadata(*NewStoreInstr);3996  // TODO: Also manage existing metadata using VPIRMetadata.3997  Group->addMetadata(NewStoreInstr);3998}3999 4000#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4001void VPInterleaveRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4002                                     VPSlotTracker &SlotTracker) const {4003  const InterleaveGroup<Instruction> *IG = getInterleaveGroup();4004  O << Indent << "INTERLEAVE-GROUP with factor " << IG->getFactor() << " at ";4005  IG->getInsertPos()->printAsOperand(O, false);4006  O << ", ";4007  getAddr()->printAsOperand(O, SlotTracker);4008  VPValue *Mask = getMask();4009  if (Mask) {4010    O << ", ";4011    Mask->printAsOperand(O, SlotTracker);4012  }4013 4014  unsigned OpIdx = 0;4015  for (unsigned i = 0; i < IG->getFactor(); ++i) {4016    if (!IG->getMember(i))4017      continue;4018    if (getNumStoreOperands() > 0) {4019      O << "\n" << Indent << "  store ";4020      getOperand(1 + OpIdx)->printAsOperand(O, SlotTracker);4021      O << " to index " << i;4022    } else {4023      O << "\n" << Indent << "  ";4024      getVPValue(OpIdx)->printAsOperand(O, SlotTracker);4025      O << " = load from index " << i;4026    }4027    ++OpIdx;4028  }4029}4030#endif4031 4032void VPInterleaveEVLRecipe::execute(VPTransformState &State) {4033  assert(!State.Lane && "Interleave group being replicated.");4034  assert(State.VF.isScalable() &&4035         "Only support scalable VF for EVL tail-folding.");4036  assert(!needsMaskForGaps() &&4037         "Masking gaps for scalable vectors is not yet supported.");4038  const InterleaveGroup<Instruction> *Group = getInterleaveGroup();4039  Instruction *Instr = Group->getInsertPos();4040 4041  // Prepare for the vector type of the interleaved load/store.4042  Type *ScalarTy = getLoadStoreType(Instr);4043  unsigned InterleaveFactor = Group->getFactor();4044  assert(InterleaveFactor <= 8 &&4045         "Unsupported deinterleave/interleave factor for scalable vectors");4046  ElementCount WideVF = State.VF * InterleaveFactor;4047  auto *VecTy = VectorType::get(ScalarTy, WideVF);4048 4049  VPValue *Addr = getAddr();4050  Value *ResAddr = State.get(Addr, VPLane(0));4051  Value *EVL = State.get(getEVL(), VPLane(0));4052  Value *InterleaveEVL = State.Builder.CreateMul(4053      EVL, ConstantInt::get(EVL->getType(), InterleaveFactor), "interleave.evl",4054      /* NUW= */ true, /* NSW= */ true);4055  LLVMContext &Ctx = State.Builder.getContext();4056 4057  Value *GroupMask = nullptr;4058  if (VPValue *BlockInMask = getMask()) {4059    SmallVector<Value *> Ops(InterleaveFactor, State.get(BlockInMask));4060    GroupMask = interleaveVectors(State.Builder, Ops, "interleaved.mask");4061  } else {4062    GroupMask =4063        State.Builder.CreateVectorSplat(WideVF, State.Builder.getTrue());4064  }4065 4066  // Vectorize the interleaved load group.4067  if (isa<LoadInst>(Instr)) {4068    CallInst *NewLoad = State.Builder.CreateIntrinsic(4069        VecTy, Intrinsic::vp_load, {ResAddr, GroupMask, InterleaveEVL}, nullptr,4070        "wide.vp.load");4071    NewLoad->addParamAttr(0,4072                          Attribute::getWithAlignment(Ctx, Group->getAlign()));4073 4074    applyMetadata(*NewLoad);4075    // TODO: Also manage existing metadata using VPIRMetadata.4076    Group->addMetadata(NewLoad);4077 4078    // Scalable vectors cannot use arbitrary shufflevectors (only splats),4079    // so must use intrinsics to deinterleave.4080    NewLoad = State.Builder.CreateIntrinsic(4081        Intrinsic::getDeinterleaveIntrinsicID(InterleaveFactor),4082        NewLoad->getType(), NewLoad,4083        /*FMFSource=*/nullptr, "strided.vec");4084 4085    const DataLayout &DL = Instr->getDataLayout();4086    for (unsigned I = 0, J = 0; I < InterleaveFactor; ++I) {4087      Instruction *Member = Group->getMember(I);4088      // Skip the gaps in the group.4089      if (!Member)4090        continue;4091 4092      Value *StridedVec = State.Builder.CreateExtractValue(NewLoad, I);4093      // If this member has different type, cast the result type.4094      if (Member->getType() != ScalarTy) {4095        VectorType *OtherVTy = VectorType::get(Member->getType(), State.VF);4096        StridedVec =4097            createBitOrPointerCast(State.Builder, StridedVec, OtherVTy, DL);4098      }4099 4100      State.set(getVPValue(J), StridedVec);4101      ++J;4102    }4103    return;4104  } // End for interleaved load.4105 4106  // The sub vector type for current instruction.4107  auto *SubVT = VectorType::get(ScalarTy, State.VF);4108  // Vectorize the interleaved store group.4109  ArrayRef<VPValue *> StoredValues = getStoredValues();4110  // Collect the stored vector from each member.4111  SmallVector<Value *, 4> StoredVecs;4112  const DataLayout &DL = Instr->getDataLayout();4113  for (unsigned I = 0, StoredIdx = 0; I < InterleaveFactor; I++) {4114    Instruction *Member = Group->getMember(I);4115    // Skip the gaps in the group.4116    if (!Member) {4117      StoredVecs.push_back(PoisonValue::get(SubVT));4118      continue;4119    }4120 4121    Value *StoredVec = State.get(StoredValues[StoredIdx]);4122    // If this member has different type, cast it to a unified type.4123    if (StoredVec->getType() != SubVT)4124      StoredVec = createBitOrPointerCast(State.Builder, StoredVec, SubVT, DL);4125 4126    StoredVecs.push_back(StoredVec);4127    ++StoredIdx;4128  }4129 4130  // Interleave all the smaller vectors into one wider vector.4131  Value *IVec = interleaveVectors(State.Builder, StoredVecs, "interleaved.vec");4132  CallInst *NewStore =4133      State.Builder.CreateIntrinsic(Type::getVoidTy(Ctx), Intrinsic::vp_store,4134                                    {IVec, ResAddr, GroupMask, InterleaveEVL});4135  NewStore->addParamAttr(1,4136                         Attribute::getWithAlignment(Ctx, Group->getAlign()));4137 4138  applyMetadata(*NewStore);4139  // TODO: Also manage existing metadata using VPIRMetadata.4140  Group->addMetadata(NewStore);4141}4142 4143#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4144void VPInterleaveEVLRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4145                                        VPSlotTracker &SlotTracker) const {4146  const InterleaveGroup<Instruction> *IG = getInterleaveGroup();4147  O << Indent << "INTERLEAVE-GROUP with factor " << IG->getFactor() << " at ";4148  IG->getInsertPos()->printAsOperand(O, false);4149  O << ", ";4150  getAddr()->printAsOperand(O, SlotTracker);4151  O << ", ";4152  getEVL()->printAsOperand(O, SlotTracker);4153  if (VPValue *Mask = getMask()) {4154    O << ", ";4155    Mask->printAsOperand(O, SlotTracker);4156  }4157 4158  unsigned OpIdx = 0;4159  for (unsigned i = 0; i < IG->getFactor(); ++i) {4160    if (!IG->getMember(i))4161      continue;4162    if (getNumStoreOperands() > 0) {4163      O << "\n" << Indent << "  vp.store ";4164      getOperand(2 + OpIdx)->printAsOperand(O, SlotTracker);4165      O << " to index " << i;4166    } else {4167      O << "\n" << Indent << "  ";4168      getVPValue(OpIdx)->printAsOperand(O, SlotTracker);4169      O << " = vp.load from index " << i;4170    }4171    ++OpIdx;4172  }4173}4174#endif4175 4176InstructionCost VPInterleaveBase::computeCost(ElementCount VF,4177                                              VPCostContext &Ctx) const {4178  Instruction *InsertPos = getInsertPos();4179  // Find the VPValue index of the interleave group. We need to skip gaps.4180  unsigned InsertPosIdx = 0;4181  for (unsigned Idx = 0; IG->getFactor(); ++Idx)4182    if (auto *Member = IG->getMember(Idx)) {4183      if (Member == InsertPos)4184        break;4185      InsertPosIdx++;4186    }4187  Type *ValTy = Ctx.Types.inferScalarType(4188      getNumDefinedValues() > 0 ? getVPValue(InsertPosIdx)4189                                : getStoredValues()[InsertPosIdx]);4190  auto *VectorTy = cast<VectorType>(toVectorTy(ValTy, VF));4191  unsigned AS = cast<PointerType>(Ctx.Types.inferScalarType(getAddr()))4192                    ->getAddressSpace();4193 4194  unsigned InterleaveFactor = IG->getFactor();4195  auto *WideVecTy = VectorType::get(ValTy, VF * InterleaveFactor);4196 4197  // Holds the indices of existing members in the interleaved group.4198  SmallVector<unsigned, 4> Indices;4199  for (unsigned IF = 0; IF < InterleaveFactor; IF++)4200    if (IG->getMember(IF))4201      Indices.push_back(IF);4202 4203  // Calculate the cost of the whole interleaved group.4204  InstructionCost Cost = Ctx.TTI.getInterleavedMemoryOpCost(4205      InsertPos->getOpcode(), WideVecTy, IG->getFactor(), Indices,4206      IG->getAlign(), AS, Ctx.CostKind, getMask(), NeedsMaskForGaps);4207 4208  if (!IG->isReverse())4209    return Cost;4210 4211  return Cost + IG->getNumMembers() *4212                    Ctx.TTI.getShuffleCost(TargetTransformInfo::SK_Reverse,4213                                           VectorTy, VectorTy, {}, Ctx.CostKind,4214                                           0);4215}4216 4217#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4218void VPCanonicalIVPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4219                                         VPSlotTracker &SlotTracker) const {4220  O << Indent << "EMIT ";4221  printAsOperand(O, SlotTracker);4222  O << " = CANONICAL-INDUCTION ";4223  printOperands(O, SlotTracker);4224}4225#endif4226 4227bool VPWidenPointerInductionRecipe::onlyScalarsGenerated(bool IsScalable) {4228  return vputils::onlyScalarValuesUsed(this) &&4229         (!IsScalable || vputils::onlyFirstLaneUsed(this));4230}4231 4232#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4233void VPWidenPointerInductionRecipe::printRecipe(4234    raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const {4235  assert((getNumOperands() == 3 || getNumOperands() == 5) &&4236         "unexpected number of operands");4237  O << Indent << "EMIT ";4238  printAsOperand(O, SlotTracker);4239  O << " = WIDEN-POINTER-INDUCTION ";4240  getStartValue()->printAsOperand(O, SlotTracker);4241  O << ", ";4242  getStepValue()->printAsOperand(O, SlotTracker);4243  O << ", ";4244  getOperand(2)->printAsOperand(O, SlotTracker);4245  if (getNumOperands() == 5) {4246    O << ", ";4247    getOperand(3)->printAsOperand(O, SlotTracker);4248    O << ", ";4249    getOperand(4)->printAsOperand(O, SlotTracker);4250  }4251}4252 4253void VPExpandSCEVRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4254                                     VPSlotTracker &SlotTracker) const {4255  O << Indent << "EMIT ";4256  printAsOperand(O, SlotTracker);4257  O << " = EXPAND SCEV " << *Expr;4258}4259#endif4260 4261void VPWidenCanonicalIVRecipe::execute(VPTransformState &State) {4262  Value *CanonicalIV = State.get(getOperand(0), /*IsScalar*/ true);4263  Type *STy = CanonicalIV->getType();4264  IRBuilder<> Builder(State.CFG.PrevBB->getTerminator());4265  ElementCount VF = State.VF;4266  Value *VStart = VF.isScalar()4267                      ? CanonicalIV4268                      : Builder.CreateVectorSplat(VF, CanonicalIV, "broadcast");4269  Value *VStep = createStepForVF(Builder, STy, VF, getUnrollPart(*this));4270  if (VF.isVector()) {4271    VStep = Builder.CreateVectorSplat(VF, VStep);4272    VStep =4273        Builder.CreateAdd(VStep, Builder.CreateStepVector(VStep->getType()));4274  }4275  Value *CanonicalVectorIV = Builder.CreateAdd(VStart, VStep, "vec.iv");4276  State.set(this, CanonicalVectorIV);4277}4278 4279#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4280void VPWidenCanonicalIVRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4281                                           VPSlotTracker &SlotTracker) const {4282  O << Indent << "EMIT ";4283  printAsOperand(O, SlotTracker);4284  O << " = WIDEN-CANONICAL-INDUCTION ";4285  printOperands(O, SlotTracker);4286}4287#endif4288 4289void VPFirstOrderRecurrencePHIRecipe::execute(VPTransformState &State) {4290  auto &Builder = State.Builder;4291  // Create a vector from the initial value.4292  auto *VectorInit = getStartValue()->getLiveInIRValue();4293 4294  Type *VecTy = State.VF.isScalar()4295                    ? VectorInit->getType()4296                    : VectorType::get(VectorInit->getType(), State.VF);4297 4298  BasicBlock *VectorPH =4299      State.CFG.VPBB2IRBB.at(getParent()->getCFGPredecessor(0));4300  if (State.VF.isVector()) {4301    auto *IdxTy = Builder.getInt32Ty();4302    auto *One = ConstantInt::get(IdxTy, 1);4303    IRBuilder<>::InsertPointGuard Guard(Builder);4304    Builder.SetInsertPoint(VectorPH->getTerminator());4305    auto *RuntimeVF = getRuntimeVF(Builder, IdxTy, State.VF);4306    auto *LastIdx = Builder.CreateSub(RuntimeVF, One);4307    VectorInit = Builder.CreateInsertElement(4308        PoisonValue::get(VecTy), VectorInit, LastIdx, "vector.recur.init");4309  }4310 4311  // Create a phi node for the new recurrence.4312  PHINode *Phi = PHINode::Create(VecTy, 2, "vector.recur");4313  Phi->insertBefore(State.CFG.PrevBB->getFirstInsertionPt());4314  Phi->addIncoming(VectorInit, VectorPH);4315  State.set(this, Phi);4316}4317 4318InstructionCost4319VPFirstOrderRecurrencePHIRecipe::computeCost(ElementCount VF,4320                                             VPCostContext &Ctx) const {4321  if (VF.isScalar())4322    return Ctx.TTI.getCFInstrCost(Instruction::PHI, Ctx.CostKind);4323 4324  return 0;4325}4326 4327#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4328void VPFirstOrderRecurrencePHIRecipe::printRecipe(4329    raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const {4330  O << Indent << "FIRST-ORDER-RECURRENCE-PHI ";4331  printAsOperand(O, SlotTracker);4332  O << " = phi ";4333  printOperands(O, SlotTracker);4334}4335#endif4336 4337void VPReductionPHIRecipe::execute(VPTransformState &State) {4338  // Reductions do not have to start at zero. They can start with4339  // any loop invariant values.4340  VPValue *StartVPV = getStartValue();4341 4342  // In order to support recurrences we need to be able to vectorize Phi nodes.4343  // Phi nodes have cycles, so we need to vectorize them in two stages. This is4344  // stage #1: We create a new vector PHI node with no incoming edges. We'll use4345  // this value when we vectorize all of the instructions that use the PHI.4346  BasicBlock *VectorPH =4347      State.CFG.VPBB2IRBB.at(getParent()->getCFGPredecessor(0));4348  bool ScalarPHI = State.VF.isScalar() || isInLoop();4349  Value *StartV = State.get(StartVPV, ScalarPHI);4350  Type *VecTy = StartV->getType();4351 4352  BasicBlock *HeaderBB = State.CFG.PrevBB;4353  assert(State.CurrentParentLoop->getHeader() == HeaderBB &&4354         "recipe must be in the vector loop header");4355  auto *Phi = PHINode::Create(VecTy, 2, "vec.phi");4356  Phi->insertBefore(HeaderBB->getFirstInsertionPt());4357  State.set(this, Phi, isInLoop());4358 4359  Phi->addIncoming(StartV, VectorPH);4360}4361 4362#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4363void VPReductionPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4364                                       VPSlotTracker &SlotTracker) const {4365  O << Indent << "WIDEN-REDUCTION-PHI ";4366 4367  printAsOperand(O, SlotTracker);4368  O << " = phi ";4369  printOperands(O, SlotTracker);4370  if (getVFScaleFactor() > 1)4371    O << " (VF scaled by 1/" << getVFScaleFactor() << ")";4372}4373#endif4374 4375void VPWidenPHIRecipe::execute(VPTransformState &State) {4376  Value *Op0 = State.get(getOperand(0));4377  Type *VecTy = Op0->getType();4378  Instruction *VecPhi = State.Builder.CreatePHI(VecTy, 2, Name);4379  State.set(this, VecPhi);4380}4381 4382#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4383void VPWidenPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4384                                   VPSlotTracker &SlotTracker) const {4385  O << Indent << "WIDEN-PHI ";4386 4387  printAsOperand(O, SlotTracker);4388  O << " = phi ";4389  printPhiOperands(O, SlotTracker);4390}4391#endif4392 4393// TODO: It would be good to use the existing VPWidenPHIRecipe instead and4394// remove VPActiveLaneMaskPHIRecipe.4395void VPActiveLaneMaskPHIRecipe::execute(VPTransformState &State) {4396  BasicBlock *VectorPH =4397      State.CFG.VPBB2IRBB.at(getParent()->getCFGPredecessor(0));4398  Value *StartMask = State.get(getOperand(0));4399  PHINode *Phi =4400      State.Builder.CreatePHI(StartMask->getType(), 2, "active.lane.mask");4401  Phi->addIncoming(StartMask, VectorPH);4402  State.set(this, Phi);4403}4404 4405#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4406void VPActiveLaneMaskPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4407                                            VPSlotTracker &SlotTracker) const {4408  O << Indent << "ACTIVE-LANE-MASK-PHI ";4409 4410  printAsOperand(O, SlotTracker);4411  O << " = phi ";4412  printOperands(O, SlotTracker);4413}4414#endif4415 4416#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)4417void VPEVLBasedIVPHIRecipe::printRecipe(raw_ostream &O, const Twine &Indent,4418                                        VPSlotTracker &SlotTracker) const {4419  O << Indent << "EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI ";4420 4421  printAsOperand(O, SlotTracker);4422  O << " = phi ";4423  printOperands(O, SlotTracker);4424}4425#endif4426