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