1480093f4SDimitry Andric //===-- VPlanTransforms.cpp - Utility VPlan to VPlan transforms -----------===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric ///
9480093f4SDimitry Andric /// \file
10480093f4SDimitry Andric /// This file implements a set of utility VPlan to VPlan transformations.
11480093f4SDimitry Andric ///
12480093f4SDimitry Andric //===----------------------------------------------------------------------===//
13480093f4SDimitry Andric 
14480093f4SDimitry Andric #include "VPlanTransforms.h"
15480093f4SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
16480093f4SDimitry Andric 
17480093f4SDimitry Andric using namespace llvm;
18480093f4SDimitry Andric 
VPInstructionsToVPRecipes(Loop * OrigLoop,VPlanPtr & Plan,LoopVectorizationLegality::InductionList & Inductions,SmallPtrSetImpl<Instruction * > & DeadInstructions,ScalarEvolution & SE)19480093f4SDimitry Andric void VPlanTransforms::VPInstructionsToVPRecipes(
20480093f4SDimitry Andric     Loop *OrigLoop, VPlanPtr &Plan,
215ffd83dbSDimitry Andric     LoopVectorizationLegality::InductionList &Inductions,
225f7ddb14SDimitry Andric     SmallPtrSetImpl<Instruction *> &DeadInstructions, ScalarEvolution &SE) {
23480093f4SDimitry Andric 
24480093f4SDimitry Andric   auto *TopRegion = cast<VPRegionBlock>(Plan->getEntry());
25480093f4SDimitry Andric   ReversePostOrderTraversal<VPBlockBase *> RPOT(TopRegion->getEntry());
26480093f4SDimitry Andric 
27480093f4SDimitry Andric   for (VPBlockBase *Base : RPOT) {
28480093f4SDimitry Andric     // Do not widen instructions in pre-header and exit blocks.
29480093f4SDimitry Andric     if (Base->getNumPredecessors() == 0 || Base->getNumSuccessors() == 0)
30480093f4SDimitry Andric       continue;
31480093f4SDimitry Andric 
32480093f4SDimitry Andric     VPBasicBlock *VPBB = Base->getEntryBasicBlock();
33480093f4SDimitry Andric     // Introduce each ingredient into VPlan.
34480093f4SDimitry Andric     for (auto I = VPBB->begin(), E = VPBB->end(); I != E;) {
35480093f4SDimitry Andric       VPRecipeBase *Ingredient = &*I++;
365f7ddb14SDimitry Andric       VPValue *VPV = Ingredient->getVPSingleValue();
375f7ddb14SDimitry Andric       Instruction *Inst = cast<Instruction>(VPV->getUnderlyingValue());
38480093f4SDimitry Andric       if (DeadInstructions.count(Inst)) {
39af732203SDimitry Andric         VPValue DummyValue;
405f7ddb14SDimitry Andric         VPV->replaceAllUsesWith(&DummyValue);
41480093f4SDimitry Andric         Ingredient->eraseFromParent();
42480093f4SDimitry Andric         continue;
43480093f4SDimitry Andric       }
44480093f4SDimitry Andric 
45480093f4SDimitry Andric       VPRecipeBase *NewRecipe = nullptr;
465f7ddb14SDimitry Andric       if (auto *VPPhi = dyn_cast<VPWidenPHIRecipe>(Ingredient)) {
475f7ddb14SDimitry Andric         auto *Phi = cast<PHINode>(VPPhi->getUnderlyingValue());
485ffd83dbSDimitry Andric         InductionDescriptor II = Inductions.lookup(Phi);
49480093f4SDimitry Andric         if (II.getKind() == InductionDescriptor::IK_IntInduction ||
50480093f4SDimitry Andric             II.getKind() == InductionDescriptor::IK_FpInduction) {
51af732203SDimitry Andric           VPValue *Start = Plan->getOrAddVPValue(II.getStartValue());
525f7ddb14SDimitry Andric           NewRecipe = new VPWidenIntOrFpInductionRecipe(Phi, Start, nullptr);
535f7ddb14SDimitry Andric         } else {
545f7ddb14SDimitry Andric           Plan->addVPValue(Phi, VPPhi);
555f7ddb14SDimitry Andric           continue;
565f7ddb14SDimitry Andric         }
575f7ddb14SDimitry Andric       } else {
585f7ddb14SDimitry Andric         assert(isa<VPInstruction>(Ingredient) &&
595f7ddb14SDimitry Andric                "only VPInstructions expected here");
605f7ddb14SDimitry Andric         assert(!isa<PHINode>(Inst) && "phis should be handled above");
615f7ddb14SDimitry Andric         // Create VPWidenMemoryInstructionRecipe for loads and stores.
625f7ddb14SDimitry Andric         if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
635f7ddb14SDimitry Andric           NewRecipe = new VPWidenMemoryInstructionRecipe(
645f7ddb14SDimitry Andric               *Load, Plan->getOrAddVPValue(getLoadStorePointerOperand(Inst)),
655f7ddb14SDimitry Andric               nullptr /*Mask*/);
665f7ddb14SDimitry Andric         } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
675f7ddb14SDimitry Andric           NewRecipe = new VPWidenMemoryInstructionRecipe(
685f7ddb14SDimitry Andric               *Store, Plan->getOrAddVPValue(getLoadStorePointerOperand(Inst)),
695f7ddb14SDimitry Andric               Plan->getOrAddVPValue(Store->getValueOperand()),
705f7ddb14SDimitry Andric               nullptr /*Mask*/);
71480093f4SDimitry Andric         } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
725ffd83dbSDimitry Andric           NewRecipe = new VPWidenGEPRecipe(
735ffd83dbSDimitry Andric               GEP, Plan->mapToVPValues(GEP->operands()), OrigLoop);
745f7ddb14SDimitry Andric         } else if (CallInst *CI = dyn_cast<CallInst>(Inst)) {
755f7ddb14SDimitry Andric           NewRecipe = new VPWidenCallRecipe(
765f7ddb14SDimitry Andric               *CI, Plan->mapToVPValues(CI->arg_operands()));
775f7ddb14SDimitry Andric         } else if (SelectInst *SI = dyn_cast<SelectInst>(Inst)) {
785f7ddb14SDimitry Andric           bool InvariantCond =
795f7ddb14SDimitry Andric               SE.isLoopInvariant(SE.getSCEV(SI->getOperand(0)), OrigLoop);
805f7ddb14SDimitry Andric           NewRecipe = new VPWidenSelectRecipe(
815f7ddb14SDimitry Andric               *SI, Plan->mapToVPValues(SI->operands()), InvariantCond);
825f7ddb14SDimitry Andric         } else {
835ffd83dbSDimitry Andric           NewRecipe =
845ffd83dbSDimitry Andric               new VPWidenRecipe(*Inst, Plan->mapToVPValues(Inst->operands()));
855f7ddb14SDimitry Andric         }
865f7ddb14SDimitry Andric       }
87480093f4SDimitry Andric 
88480093f4SDimitry Andric       NewRecipe->insertBefore(Ingredient);
89af732203SDimitry Andric       if (NewRecipe->getNumDefinedValues() == 1)
905f7ddb14SDimitry Andric         VPV->replaceAllUsesWith(NewRecipe->getVPSingleValue());
91af732203SDimitry Andric       else
92af732203SDimitry Andric         assert(NewRecipe->getNumDefinedValues() == 0 &&
93af732203SDimitry Andric                "Only recpies with zero or one defined values expected");
94480093f4SDimitry Andric       Ingredient->eraseFromParent();
955f7ddb14SDimitry Andric       Plan->removeVPValueFor(Inst);
965f7ddb14SDimitry Andric       for (auto *Def : NewRecipe->definedValues()) {
975f7ddb14SDimitry Andric         Plan->addVPValue(Inst, Def);
98480093f4SDimitry Andric       }
99480093f4SDimitry Andric     }
100480093f4SDimitry Andric   }
1015f7ddb14SDimitry Andric }
1025f7ddb14SDimitry Andric 
sinkScalarOperands(VPlan & Plan)1035f7ddb14SDimitry Andric bool VPlanTransforms::sinkScalarOperands(VPlan &Plan) {
1045f7ddb14SDimitry Andric   auto Iter = depth_first(
1055f7ddb14SDimitry Andric       VPBlockRecursiveTraversalWrapper<VPBlockBase *>(Plan.getEntry()));
1065f7ddb14SDimitry Andric   bool Changed = false;
1075f7ddb14SDimitry Andric   // First, collect the operands of all predicated replicate recipes as seeds
1085f7ddb14SDimitry Andric   // for sinking.
1095f7ddb14SDimitry Andric   SetVector<VPValue *> WorkList;
1105f7ddb14SDimitry Andric   for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(Iter)) {
1115f7ddb14SDimitry Andric     for (auto &Recipe : *VPBB) {
1125f7ddb14SDimitry Andric       auto *RepR = dyn_cast<VPReplicateRecipe>(&Recipe);
1135f7ddb14SDimitry Andric       if (!RepR || !RepR->isPredicated())
1145f7ddb14SDimitry Andric         continue;
1155f7ddb14SDimitry Andric       WorkList.insert(RepR->op_begin(), RepR->op_end());
1165f7ddb14SDimitry Andric     }
1175f7ddb14SDimitry Andric   }
1185f7ddb14SDimitry Andric 
1195f7ddb14SDimitry Andric   // Try to sink each replicate recipe in the worklist.
1205f7ddb14SDimitry Andric   while (!WorkList.empty()) {
1215f7ddb14SDimitry Andric     auto *C = WorkList.pop_back_val();
1225f7ddb14SDimitry Andric     auto *SinkCandidate = dyn_cast_or_null<VPReplicateRecipe>(C->Def);
1235f7ddb14SDimitry Andric     if (!SinkCandidate || SinkCandidate->isUniform())
1245f7ddb14SDimitry Andric       continue;
1255f7ddb14SDimitry Andric 
1265f7ddb14SDimitry Andric     // All users of SinkCandidate must be in the same block in order to perform
1275f7ddb14SDimitry Andric     // sinking. Therefore the destination block for sinking must match the block
1285f7ddb14SDimitry Andric     // containing the first user.
1295f7ddb14SDimitry Andric     auto *FirstUser = dyn_cast<VPRecipeBase>(*SinkCandidate->user_begin());
1305f7ddb14SDimitry Andric     if (!FirstUser)
1315f7ddb14SDimitry Andric       continue;
1325f7ddb14SDimitry Andric     VPBasicBlock *SinkTo = FirstUser->getParent();
1335f7ddb14SDimitry Andric     if (SinkCandidate->getParent() == SinkTo ||
1345f7ddb14SDimitry Andric         SinkCandidate->mayHaveSideEffects() ||
1355f7ddb14SDimitry Andric         SinkCandidate->mayReadOrWriteMemory())
1365f7ddb14SDimitry Andric       continue;
1375f7ddb14SDimitry Andric 
1385f7ddb14SDimitry Andric     // All recipe users of the sink candidate must be in the same block SinkTo.
1395f7ddb14SDimitry Andric     if (any_of(SinkCandidate->users(), [SinkTo](VPUser *U) {
1405f7ddb14SDimitry Andric           auto *UI = dyn_cast<VPRecipeBase>(U);
1415f7ddb14SDimitry Andric           return !UI || UI->getParent() != SinkTo;
1425f7ddb14SDimitry Andric         }))
1435f7ddb14SDimitry Andric       continue;
1445f7ddb14SDimitry Andric 
1455f7ddb14SDimitry Andric     SinkCandidate->moveBefore(*SinkTo, SinkTo->getFirstNonPhi());
1465f7ddb14SDimitry Andric     WorkList.insert(SinkCandidate->op_begin(), SinkCandidate->op_end());
1475f7ddb14SDimitry Andric     Changed = true;
1485f7ddb14SDimitry Andric   }
1495f7ddb14SDimitry Andric   return Changed;
1505f7ddb14SDimitry Andric }
1515f7ddb14SDimitry Andric 
1525f7ddb14SDimitry Andric /// If \p R is a region with a VPBranchOnMaskRecipe in the entry block, return
1535f7ddb14SDimitry Andric /// the mask.
getPredicatedMask(VPRegionBlock * R)1545f7ddb14SDimitry Andric VPValue *getPredicatedMask(VPRegionBlock *R) {
1555f7ddb14SDimitry Andric   auto *EntryBB = dyn_cast<VPBasicBlock>(R->getEntry());
1565f7ddb14SDimitry Andric   if (!EntryBB || EntryBB->size() != 1 ||
1575f7ddb14SDimitry Andric       !isa<VPBranchOnMaskRecipe>(EntryBB->begin()))
1585f7ddb14SDimitry Andric     return nullptr;
1595f7ddb14SDimitry Andric 
1605f7ddb14SDimitry Andric   return cast<VPBranchOnMaskRecipe>(&*EntryBB->begin())->getOperand(0);
1615f7ddb14SDimitry Andric }
1625f7ddb14SDimitry Andric 
1635f7ddb14SDimitry Andric /// If \p R is a triangle region, return the 'then' block of the triangle.
getPredicatedThenBlock(VPRegionBlock * R)1645f7ddb14SDimitry Andric static VPBasicBlock *getPredicatedThenBlock(VPRegionBlock *R) {
1655f7ddb14SDimitry Andric   auto *EntryBB = cast<VPBasicBlock>(R->getEntry());
1665f7ddb14SDimitry Andric   if (EntryBB->getNumSuccessors() != 2)
1675f7ddb14SDimitry Andric     return nullptr;
1685f7ddb14SDimitry Andric 
1695f7ddb14SDimitry Andric   auto *Succ0 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[0]);
1705f7ddb14SDimitry Andric   auto *Succ1 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[1]);
1715f7ddb14SDimitry Andric   if (!Succ0 || !Succ1)
1725f7ddb14SDimitry Andric     return nullptr;
1735f7ddb14SDimitry Andric 
1745f7ddb14SDimitry Andric   if (Succ0->getNumSuccessors() + Succ1->getNumSuccessors() != 1)
1755f7ddb14SDimitry Andric     return nullptr;
1765f7ddb14SDimitry Andric   if (Succ0->getSingleSuccessor() == Succ1)
1775f7ddb14SDimitry Andric     return Succ0;
1785f7ddb14SDimitry Andric   if (Succ1->getSingleSuccessor() == Succ0)
1795f7ddb14SDimitry Andric     return Succ1;
1805f7ddb14SDimitry Andric   return nullptr;
1815f7ddb14SDimitry Andric }
1825f7ddb14SDimitry Andric 
mergeReplicateRegions(VPlan & Plan)1835f7ddb14SDimitry Andric bool VPlanTransforms::mergeReplicateRegions(VPlan &Plan) {
1845f7ddb14SDimitry Andric   SetVector<VPRegionBlock *> DeletedRegions;
1855f7ddb14SDimitry Andric   bool Changed = false;
1865f7ddb14SDimitry Andric 
1875f7ddb14SDimitry Andric   // Collect region blocks to process up-front, to avoid iterator invalidation
1885f7ddb14SDimitry Andric   // issues while merging regions.
1895f7ddb14SDimitry Andric   SmallVector<VPRegionBlock *, 8> CandidateRegions(
1905f7ddb14SDimitry Andric       VPBlockUtils::blocksOnly<VPRegionBlock>(depth_first(
1915f7ddb14SDimitry Andric           VPBlockRecursiveTraversalWrapper<VPBlockBase *>(Plan.getEntry()))));
1925f7ddb14SDimitry Andric 
1935f7ddb14SDimitry Andric   // Check if Base is a predicated triangle, followed by an empty block,
1945f7ddb14SDimitry Andric   // followed by another predicate triangle. If that's the case, move the
1955f7ddb14SDimitry Andric   // recipes from the first to the second triangle.
1965f7ddb14SDimitry Andric   for (VPRegionBlock *Region1 : CandidateRegions) {
1975f7ddb14SDimitry Andric     if (DeletedRegions.contains(Region1))
1985f7ddb14SDimitry Andric       continue;
1995f7ddb14SDimitry Andric     auto *MiddleBasicBlock =
2005f7ddb14SDimitry Andric         dyn_cast_or_null<VPBasicBlock>(Region1->getSingleSuccessor());
2015f7ddb14SDimitry Andric     if (!MiddleBasicBlock || !MiddleBasicBlock->empty())
2025f7ddb14SDimitry Andric       continue;
2035f7ddb14SDimitry Andric 
2045f7ddb14SDimitry Andric     auto *Region2 =
2055f7ddb14SDimitry Andric         dyn_cast_or_null<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
2065f7ddb14SDimitry Andric     if (!Region2)
2075f7ddb14SDimitry Andric       continue;
2085f7ddb14SDimitry Andric 
2095f7ddb14SDimitry Andric     VPValue *Mask1 = getPredicatedMask(Region1);
2105f7ddb14SDimitry Andric     VPValue *Mask2 = getPredicatedMask(Region2);
2115f7ddb14SDimitry Andric     if (!Mask1 || Mask1 != Mask2)
2125f7ddb14SDimitry Andric       continue;
2135f7ddb14SDimitry Andric     VPBasicBlock *Then1 = getPredicatedThenBlock(Region1);
2145f7ddb14SDimitry Andric     VPBasicBlock *Then2 = getPredicatedThenBlock(Region2);
2155f7ddb14SDimitry Andric     if (!Then1 || !Then2)
2165f7ddb14SDimitry Andric       continue;
2175f7ddb14SDimitry Andric 
2185f7ddb14SDimitry Andric     assert(Mask1 && Mask2 && "both region must have conditions");
2195f7ddb14SDimitry Andric 
2205f7ddb14SDimitry Andric     // Note: No fusion-preventing memory dependencies are expected in either
2215f7ddb14SDimitry Andric     // region. Such dependencies should be rejected during earlier dependence
2225f7ddb14SDimitry Andric     // checks, which guarantee accesses can be re-ordered for vectorization.
2235f7ddb14SDimitry Andric     //
2245f7ddb14SDimitry Andric     // Move recipes to the successor region.
2255f7ddb14SDimitry Andric     for (VPRecipeBase &ToMove : make_early_inc_range(reverse(*Then1)))
2265f7ddb14SDimitry Andric       ToMove.moveBefore(*Then2, Then2->getFirstNonPhi());
2275f7ddb14SDimitry Andric 
2285f7ddb14SDimitry Andric     auto *Merge1 = cast<VPBasicBlock>(Then1->getSingleSuccessor());
2295f7ddb14SDimitry Andric     auto *Merge2 = cast<VPBasicBlock>(Then2->getSingleSuccessor());
2305f7ddb14SDimitry Andric 
2315f7ddb14SDimitry Andric     // Move VPPredInstPHIRecipes from the merge block to the successor region's
2325f7ddb14SDimitry Andric     // merge block. Update all users inside the successor region to use the
2335f7ddb14SDimitry Andric     // original values.
2345f7ddb14SDimitry Andric     for (VPRecipeBase &Phi1ToMove : make_early_inc_range(reverse(*Merge1))) {
2355f7ddb14SDimitry Andric       VPValue *PredInst1 =
2365f7ddb14SDimitry Andric           cast<VPPredInstPHIRecipe>(&Phi1ToMove)->getOperand(0);
237*18baa991SDimitry Andric       VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue();
238*18baa991SDimitry Andric       SmallVector<VPUser *> Users(Phi1ToMoveV->user_begin(),
239*18baa991SDimitry Andric                                   Phi1ToMoveV->user_end());
240*18baa991SDimitry Andric       for (VPUser *U : Users) {
2415f7ddb14SDimitry Andric         auto *UI = dyn_cast<VPRecipeBase>(U);
2425f7ddb14SDimitry Andric         if (!UI || UI->getParent() != Then2)
2435f7ddb14SDimitry Andric           continue;
2445f7ddb14SDimitry Andric         for (unsigned I = 0, E = U->getNumOperands(); I != E; ++I) {
245*18baa991SDimitry Andric           if (Phi1ToMoveV != U->getOperand(I))
2465f7ddb14SDimitry Andric             continue;
2475f7ddb14SDimitry Andric           U->setOperand(I, PredInst1);
2485f7ddb14SDimitry Andric         }
2495f7ddb14SDimitry Andric       }
2505f7ddb14SDimitry Andric 
2515f7ddb14SDimitry Andric       Phi1ToMove.moveBefore(*Merge2, Merge2->begin());
2525f7ddb14SDimitry Andric     }
2535f7ddb14SDimitry Andric 
2545f7ddb14SDimitry Andric     // Finally, remove the first region.
2555f7ddb14SDimitry Andric     for (VPBlockBase *Pred : make_early_inc_range(Region1->getPredecessors())) {
2565f7ddb14SDimitry Andric       VPBlockUtils::disconnectBlocks(Pred, Region1);
2575f7ddb14SDimitry Andric       VPBlockUtils::connectBlocks(Pred, MiddleBasicBlock);
2585f7ddb14SDimitry Andric     }
2595f7ddb14SDimitry Andric     VPBlockUtils::disconnectBlocks(Region1, MiddleBasicBlock);
2605f7ddb14SDimitry Andric     DeletedRegions.insert(Region1);
2615f7ddb14SDimitry Andric   }
2625f7ddb14SDimitry Andric 
2635f7ddb14SDimitry Andric   for (VPRegionBlock *ToDelete : DeletedRegions)
2645f7ddb14SDimitry Andric     delete ToDelete;
2655f7ddb14SDimitry Andric   return Changed;
2665f7ddb14SDimitry Andric }
267