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