10b57cec5SDimitry Andric //===-- VPlanPredicator.cpp -------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements the VPlanPredicator class which contains the public
110b57cec5SDimitry Andric /// interfaces to predicate and linearize the VPlan region.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "VPlanPredicator.h"
160b57cec5SDimitry Andric #include "VPlan.h"
170b57cec5SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h"
180b57cec5SDimitry Andric #include "llvm/ADT/GraphTraits.h"
190b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
200b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #define DEBUG_TYPE "VPlanPredicator"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric // Generate VPInstructions at the beginning of CurrBB that calculate the
280b57cec5SDimitry Andric // predicate being propagated from PredBB to CurrBB depending on the edge type
290b57cec5SDimitry Andric // between them. For example if:
300b57cec5SDimitry Andric //  i.  PredBB is controlled by predicate %BP, and
310b57cec5SDimitry Andric //  ii. The edge PredBB->CurrBB is the false edge, controlled by the condition
320b57cec5SDimitry Andric //  bit value %CBV then this function will generate the following two
330b57cec5SDimitry Andric //  VPInstructions at the start of CurrBB:
340b57cec5SDimitry Andric //   %IntermediateVal = not %CBV
350b57cec5SDimitry Andric //   %FinalVal        = and %BP %IntermediateVal
360b57cec5SDimitry Andric // It returns %FinalVal.
getOrCreateNotPredicate(VPBasicBlock * PredBB,VPBasicBlock * CurrBB)370b57cec5SDimitry Andric VPValue *VPlanPredicator::getOrCreateNotPredicate(VPBasicBlock *PredBB,
380b57cec5SDimitry Andric                                                   VPBasicBlock *CurrBB) {
390b57cec5SDimitry Andric   VPValue *CBV = PredBB->getCondBit();
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   // Set the intermediate value - this is either 'CBV', or 'not CBV'
420b57cec5SDimitry Andric   // depending on the edge type.
430b57cec5SDimitry Andric   EdgeType ET = getEdgeTypeBetween(PredBB, CurrBB);
440b57cec5SDimitry Andric   VPValue *IntermediateVal = nullptr;
450b57cec5SDimitry Andric   switch (ET) {
460b57cec5SDimitry Andric   case EdgeType::TRUE_EDGE:
470b57cec5SDimitry Andric     // CurrBB is the true successor of PredBB - nothing to do here.
480b57cec5SDimitry Andric     IntermediateVal = CBV;
490b57cec5SDimitry Andric     break;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   case EdgeType::FALSE_EDGE:
520b57cec5SDimitry Andric     // CurrBB is the False successor of PredBB - compute not of CBV.
530b57cec5SDimitry Andric     IntermediateVal = Builder.createNot(CBV);
540b57cec5SDimitry Andric     break;
550b57cec5SDimitry Andric   }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   // Now AND intermediate value with PredBB's block predicate if it has one.
580b57cec5SDimitry Andric   VPValue *BP = PredBB->getPredicate();
590b57cec5SDimitry Andric   if (BP)
600b57cec5SDimitry Andric     return Builder.createAnd(BP, IntermediateVal);
610b57cec5SDimitry Andric   else
620b57cec5SDimitry Andric     return IntermediateVal;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric // Generate a tree of ORs for all IncomingPredicates in  WorkList.
660b57cec5SDimitry Andric // Note: This function destroys the original Worklist.
670b57cec5SDimitry Andric //
680b57cec5SDimitry Andric // P1 P2 P3 P4 P5
690b57cec5SDimitry Andric //  \ /   \ /  /
700b57cec5SDimitry Andric //  OR1   OR2 /
710b57cec5SDimitry Andric //    \    | /
720b57cec5SDimitry Andric //     \   +/-+
730b57cec5SDimitry Andric //      \  /  |
740b57cec5SDimitry Andric //       OR3  |
750b57cec5SDimitry Andric //         \  |
760b57cec5SDimitry Andric //          OR4 <- Returns this
770b57cec5SDimitry Andric //           |
780b57cec5SDimitry Andric //
790b57cec5SDimitry Andric // The algorithm uses a worklist of predicates as its main data structure.
800b57cec5SDimitry Andric // We pop a pair of values from the front (e.g. P1 and P2), generate an OR
810b57cec5SDimitry Andric // (in this example OR1), and push it back. In this example the worklist
820b57cec5SDimitry Andric // contains {P3, P4, P5, OR1}.
830b57cec5SDimitry Andric // The process iterates until we have only one element in the Worklist (OR4).
840b57cec5SDimitry Andric // The last element is the root predicate which is returned.
genPredicateTree(std::list<VPValue * > & Worklist)850b57cec5SDimitry Andric VPValue *VPlanPredicator::genPredicateTree(std::list<VPValue *> &Worklist) {
860b57cec5SDimitry Andric   if (Worklist.empty())
870b57cec5SDimitry Andric     return nullptr;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   // The worklist initially contains all the leaf nodes. Initialize the tree
900b57cec5SDimitry Andric   // using them.
910b57cec5SDimitry Andric   while (Worklist.size() >= 2) {
920b57cec5SDimitry Andric     // Pop a pair of values from the front.
930b57cec5SDimitry Andric     VPValue *LHS = Worklist.front();
940b57cec5SDimitry Andric     Worklist.pop_front();
950b57cec5SDimitry Andric     VPValue *RHS = Worklist.front();
960b57cec5SDimitry Andric     Worklist.pop_front();
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric     // Create an OR of these values.
990b57cec5SDimitry Andric     VPValue *Or = Builder.createOr(LHS, RHS);
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     // Push OR to the back of the worklist.
1020b57cec5SDimitry Andric     Worklist.push_back(Or);
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   assert(Worklist.size() == 1 && "Expected 1 item in worklist");
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   // The root is the last node in the worklist.
1080b57cec5SDimitry Andric   VPValue *Root = Worklist.front();
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // This root needs to replace the existing block predicate. This is done in
1110b57cec5SDimitry Andric   // the caller function.
1120b57cec5SDimitry Andric   return Root;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric // Return whether the edge FromBlock -> ToBlock is a TRUE_EDGE or FALSE_EDGE
1160b57cec5SDimitry Andric VPlanPredicator::EdgeType
getEdgeTypeBetween(VPBlockBase * FromBlock,VPBlockBase * ToBlock)1170b57cec5SDimitry Andric VPlanPredicator::getEdgeTypeBetween(VPBlockBase *FromBlock,
1180b57cec5SDimitry Andric                                     VPBlockBase *ToBlock) {
1190b57cec5SDimitry Andric   unsigned Count = 0;
1200b57cec5SDimitry Andric   for (VPBlockBase *SuccBlock : FromBlock->getSuccessors()) {
1210b57cec5SDimitry Andric     if (SuccBlock == ToBlock) {
1220b57cec5SDimitry Andric       assert(Count < 2 && "Switch not supported currently");
1230b57cec5SDimitry Andric       return (Count == 0) ? EdgeType::TRUE_EDGE : EdgeType::FALSE_EDGE;
1240b57cec5SDimitry Andric     }
1250b57cec5SDimitry Andric     Count++;
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   llvm_unreachable("Broken getEdgeTypeBetween");
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric // Generate all predicates needed for CurrBlock by going through its immediate
1320b57cec5SDimitry Andric // predecessor blocks.
createOrPropagatePredicates(VPBlockBase * CurrBlock,VPRegionBlock * Region)1330b57cec5SDimitry Andric void VPlanPredicator::createOrPropagatePredicates(VPBlockBase *CurrBlock,
1340b57cec5SDimitry Andric                                                   VPRegionBlock *Region) {
1350b57cec5SDimitry Andric   // Blocks that dominate region exit inherit the predicate from the region.
1360b57cec5SDimitry Andric   // Return after setting the predicate.
1370b57cec5SDimitry Andric   if (VPDomTree.dominates(CurrBlock, Region->getExit())) {
1380b57cec5SDimitry Andric     VPValue *RegionBP = Region->getPredicate();
1390b57cec5SDimitry Andric     CurrBlock->setPredicate(RegionBP);
1400b57cec5SDimitry Andric     return;
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   // Collect all incoming predicates in a worklist.
1440b57cec5SDimitry Andric   std::list<VPValue *> IncomingPredicates;
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   // Set the builder's insertion point to the top of the current BB
1470b57cec5SDimitry Andric   VPBasicBlock *CurrBB = cast<VPBasicBlock>(CurrBlock->getEntryBasicBlock());
1480b57cec5SDimitry Andric   Builder.setInsertPoint(CurrBB, CurrBB->begin());
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   // For each predecessor, generate the VPInstructions required for
1510b57cec5SDimitry Andric   // computing 'BP AND (not) CBV" at the top of CurrBB.
1520b57cec5SDimitry Andric   // Collect the outcome of this calculation for all predecessors
1530b57cec5SDimitry Andric   // into IncomingPredicates.
1540b57cec5SDimitry Andric   for (VPBlockBase *PredBlock : CurrBlock->getPredecessors()) {
1550b57cec5SDimitry Andric     // Skip back-edges
1560b57cec5SDimitry Andric     if (VPBlockUtils::isBackEdge(PredBlock, CurrBlock, VPLI))
1570b57cec5SDimitry Andric       continue;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric     VPValue *IncomingPredicate = nullptr;
1600b57cec5SDimitry Andric     unsigned NumPredSuccsNoBE =
1610b57cec5SDimitry Andric         VPBlockUtils::countSuccessorsNoBE(PredBlock, VPLI);
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric     // If there is an unconditional branch to the currBB, then we don't create
1640b57cec5SDimitry Andric     // edge predicates. We use the predecessor's block predicate instead.
1650b57cec5SDimitry Andric     if (NumPredSuccsNoBE == 1)
1660b57cec5SDimitry Andric       IncomingPredicate = PredBlock->getPredicate();
1670b57cec5SDimitry Andric     else if (NumPredSuccsNoBE == 2) {
1680b57cec5SDimitry Andric       // Emit recipes into CurrBlock if required
1690b57cec5SDimitry Andric       assert(isa<VPBasicBlock>(PredBlock) && "Only BBs have multiple exits");
1700b57cec5SDimitry Andric       IncomingPredicate =
1710b57cec5SDimitry Andric           getOrCreateNotPredicate(cast<VPBasicBlock>(PredBlock), CurrBB);
1720b57cec5SDimitry Andric     } else
1730b57cec5SDimitry Andric       llvm_unreachable("FIXME: switch statement ?");
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric     if (IncomingPredicate)
1760b57cec5SDimitry Andric       IncomingPredicates.push_back(IncomingPredicate);
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   // Logically OR all incoming predicates by building the Predicate Tree.
1800b57cec5SDimitry Andric   VPValue *Predicate = genPredicateTree(IncomingPredicates);
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   // Now update the block's predicate with the new one.
1830b57cec5SDimitry Andric   CurrBlock->setPredicate(Predicate);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric // Generate all predicates needed for Region.
predicateRegionRec(VPRegionBlock * Region)1870b57cec5SDimitry Andric void VPlanPredicator::predicateRegionRec(VPRegionBlock *Region) {
1880b57cec5SDimitry Andric   VPBasicBlock *EntryBlock = cast<VPBasicBlock>(Region->getEntry());
1890b57cec5SDimitry Andric   ReversePostOrderTraversal<VPBlockBase *> RPOT(EntryBlock);
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   // Generate edge predicates and append them to the block predicate. RPO is
1920b57cec5SDimitry Andric   // necessary since the predecessor blocks' block predicate needs to be set
1930b57cec5SDimitry Andric   // before the current block's block predicate can be computed.
194*af732203SDimitry Andric   for (VPBlockBase *Block : RPOT) {
1950b57cec5SDimitry Andric     // TODO: Handle nested regions once we start generating the same.
1960b57cec5SDimitry Andric     assert(!isa<VPRegionBlock>(Block) && "Nested region not expected");
1970b57cec5SDimitry Andric     createOrPropagatePredicates(Block, Region);
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric // Linearize the CFG within Region.
2020b57cec5SDimitry Andric // TODO: Predication and linearization need RPOT for every region.
2030b57cec5SDimitry Andric // This traversal is expensive. Since predication is not adding new
2040b57cec5SDimitry Andric // blocks, we should be able to compute RPOT once in predication and
2050b57cec5SDimitry Andric // reuse it here. This becomes even more important once we have nested
2060b57cec5SDimitry Andric // regions.
linearizeRegionRec(VPRegionBlock * Region)2070b57cec5SDimitry Andric void VPlanPredicator::linearizeRegionRec(VPRegionBlock *Region) {
2080b57cec5SDimitry Andric   ReversePostOrderTraversal<VPBlockBase *> RPOT(Region->getEntry());
2090b57cec5SDimitry Andric   VPBlockBase *PrevBlock = nullptr;
2100b57cec5SDimitry Andric 
211*af732203SDimitry Andric   for (VPBlockBase *CurrBlock : RPOT) {
2120b57cec5SDimitry Andric     // TODO: Handle nested regions once we start generating the same.
2130b57cec5SDimitry Andric     assert(!isa<VPRegionBlock>(CurrBlock) && "Nested region not expected");
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     // Linearize control flow by adding an unconditional edge between PrevBlock
2160b57cec5SDimitry Andric     // and CurrBlock skipping loop headers and latches to keep intact loop
2170b57cec5SDimitry Andric     // header predecessors and loop latch successors.
2180b57cec5SDimitry Andric     if (PrevBlock && !VPLI->isLoopHeader(CurrBlock) &&
2190b57cec5SDimitry Andric         !VPBlockUtils::blockIsLoopLatch(PrevBlock, VPLI)) {
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Linearizing: " << PrevBlock->getName() << "->"
2220b57cec5SDimitry Andric                         << CurrBlock->getName() << "\n");
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric       PrevBlock->clearSuccessors();
2250b57cec5SDimitry Andric       CurrBlock->clearPredecessors();
2260b57cec5SDimitry Andric       VPBlockUtils::connectBlocks(PrevBlock, CurrBlock);
2270b57cec5SDimitry Andric     }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric     PrevBlock = CurrBlock;
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric // Entry point. The driver function for the predicator.
predicate(void)2340b57cec5SDimitry Andric void VPlanPredicator::predicate(void) {
2350b57cec5SDimitry Andric   // Predicate the blocks within Region.
2360b57cec5SDimitry Andric   predicateRegionRec(cast<VPRegionBlock>(Plan.getEntry()));
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   // Linearlize the blocks with Region.
2390b57cec5SDimitry Andric   linearizeRegionRec(cast<VPRegionBlock>(Plan.getEntry()));
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
VPlanPredicator(VPlan & Plan)2420b57cec5SDimitry Andric VPlanPredicator::VPlanPredicator(VPlan &Plan)
2430b57cec5SDimitry Andric     : Plan(Plan), VPLI(&(Plan.getVPLoopInfo())) {
2440b57cec5SDimitry Andric   // FIXME: Predicator is currently computing the dominator information for the
2450b57cec5SDimitry Andric   // top region. Once we start storing dominator information in a VPRegionBlock,
2460b57cec5SDimitry Andric   // we can avoid this recalculation.
2470b57cec5SDimitry Andric   VPDomTree.recalculate(*(cast<VPRegionBlock>(Plan.getEntry())));
2480b57cec5SDimitry Andric }
249