1*06c3fb27SDimitry Andric //===- IntervalPartition.cpp - CFG Partitioning into Intervals --*- C++ -*-===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric // 9*06c3fb27SDimitry Andric // This file defines functionality for partitioning a CFG into intervals. 10*06c3fb27SDimitry Andric // 11*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 12*06c3fb27SDimitry Andric 13*06c3fb27SDimitry Andric #include "clang/Analysis/Analyses/IntervalPartition.h" 14*06c3fb27SDimitry Andric #include "clang/Analysis/CFG.h" 15*06c3fb27SDimitry Andric #include "llvm/ADT/BitVector.h" 16*06c3fb27SDimitry Andric #include <queue> 17*06c3fb27SDimitry Andric #include <set> 18*06c3fb27SDimitry Andric #include <vector> 19*06c3fb27SDimitry Andric 20*06c3fb27SDimitry Andric namespace clang { 21*06c3fb27SDimitry Andric 22*06c3fb27SDimitry Andric static CFGInterval buildInterval(llvm::BitVector &Partitioned, 23*06c3fb27SDimitry Andric const CFGBlock &Header) { 24*06c3fb27SDimitry Andric CFGInterval Interval(&Header); 25*06c3fb27SDimitry Andric Partitioned.set(Header.getBlockID()); 26*06c3fb27SDimitry Andric 27*06c3fb27SDimitry Andric // Elements must not be null. Duplicates are prevented using `Workset`, below. 28*06c3fb27SDimitry Andric std::queue<const CFGBlock *> Worklist; 29*06c3fb27SDimitry Andric llvm::BitVector Workset(Header.getParent()->getNumBlockIDs(), false); 30*06c3fb27SDimitry Andric for (const CFGBlock *S : Header.succs()) 31*06c3fb27SDimitry Andric if (S != nullptr) 32*06c3fb27SDimitry Andric if (auto SID = S->getBlockID(); !Partitioned.test(SID)) { 33*06c3fb27SDimitry Andric // Successors are unique, so we don't test against `Workset` before 34*06c3fb27SDimitry Andric // adding to `Worklist`. 35*06c3fb27SDimitry Andric Worklist.push(S); 36*06c3fb27SDimitry Andric Workset.set(SID); 37*06c3fb27SDimitry Andric } 38*06c3fb27SDimitry Andric 39*06c3fb27SDimitry Andric // Contains successors of blocks in the interval that couldn't be added to the 40*06c3fb27SDimitry Andric // interval on their first encounter. This occurs when they have a predecessor 41*06c3fb27SDimitry Andric // that is either definitively outside the interval or hasn't been considered 42*06c3fb27SDimitry Andric // yet. In the latter case, we'll revisit the block through some other path 43*06c3fb27SDimitry Andric // from the interval. At the end of processing the worklist, we filter out any 44*06c3fb27SDimitry Andric // that ended up in the interval to produce the output set of interval 45*06c3fb27SDimitry Andric // successors. It may contain duplicates -- ultimately, all relevant elements 46*06c3fb27SDimitry Andric // are added to `Interval.Successors`, which is a set. 47*06c3fb27SDimitry Andric std::vector<const CFGBlock *> MaybeSuccessors; 48*06c3fb27SDimitry Andric 49*06c3fb27SDimitry Andric while (!Worklist.empty()) { 50*06c3fb27SDimitry Andric const auto *B = Worklist.front(); 51*06c3fb27SDimitry Andric auto ID = B->getBlockID(); 52*06c3fb27SDimitry Andric Worklist.pop(); 53*06c3fb27SDimitry Andric Workset.reset(ID); 54*06c3fb27SDimitry Andric 55*06c3fb27SDimitry Andric // Check whether all predecessors are in the interval, in which case `B` 56*06c3fb27SDimitry Andric // is included as well. 57*06c3fb27SDimitry Andric bool AllInInterval = true; 58*06c3fb27SDimitry Andric for (const CFGBlock *P : B->preds()) 59*06c3fb27SDimitry Andric if (Interval.Blocks.find(P) == Interval.Blocks.end()) { 60*06c3fb27SDimitry Andric MaybeSuccessors.push_back(B); 61*06c3fb27SDimitry Andric AllInInterval = false; 62*06c3fb27SDimitry Andric break; 63*06c3fb27SDimitry Andric } 64*06c3fb27SDimitry Andric if (AllInInterval) { 65*06c3fb27SDimitry Andric Interval.Blocks.insert(B); 66*06c3fb27SDimitry Andric Partitioned.set(ID); 67*06c3fb27SDimitry Andric for (const CFGBlock *S : B->succs()) 68*06c3fb27SDimitry Andric if (S != nullptr) 69*06c3fb27SDimitry Andric if (auto SID = S->getBlockID(); 70*06c3fb27SDimitry Andric !Partitioned.test(SID) && !Workset.test(SID)) { 71*06c3fb27SDimitry Andric Worklist.push(S); 72*06c3fb27SDimitry Andric Workset.set(SID); 73*06c3fb27SDimitry Andric } 74*06c3fb27SDimitry Andric } 75*06c3fb27SDimitry Andric } 76*06c3fb27SDimitry Andric 77*06c3fb27SDimitry Andric // Any block successors not in the current interval are interval successors. 78*06c3fb27SDimitry Andric for (const CFGBlock *B : MaybeSuccessors) 79*06c3fb27SDimitry Andric if (Interval.Blocks.find(B) == Interval.Blocks.end()) 80*06c3fb27SDimitry Andric Interval.Successors.insert(B); 81*06c3fb27SDimitry Andric 82*06c3fb27SDimitry Andric return Interval; 83*06c3fb27SDimitry Andric } 84*06c3fb27SDimitry Andric 85*06c3fb27SDimitry Andric CFGInterval buildInterval(const CFG &Cfg, const CFGBlock &Header) { 86*06c3fb27SDimitry Andric llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false); 87*06c3fb27SDimitry Andric return buildInterval(Partitioned, Header); 88*06c3fb27SDimitry Andric } 89*06c3fb27SDimitry Andric 90*06c3fb27SDimitry Andric std::vector<CFGInterval> partitionIntoIntervals(const CFG &Cfg) { 91*06c3fb27SDimitry Andric std::vector<CFGInterval> Intervals; 92*06c3fb27SDimitry Andric llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false); 93*06c3fb27SDimitry Andric auto &EntryBlock = Cfg.getEntry(); 94*06c3fb27SDimitry Andric Intervals.push_back(buildInterval(Partitioned, EntryBlock)); 95*06c3fb27SDimitry Andric 96*06c3fb27SDimitry Andric std::queue<const CFGBlock *> Successors; 97*06c3fb27SDimitry Andric for (const auto *S : Intervals[0].Successors) 98*06c3fb27SDimitry Andric Successors.push(S); 99*06c3fb27SDimitry Andric 100*06c3fb27SDimitry Andric while (!Successors.empty()) { 101*06c3fb27SDimitry Andric const auto *B = Successors.front(); 102*06c3fb27SDimitry Andric Successors.pop(); 103*06c3fb27SDimitry Andric if (Partitioned.test(B->getBlockID())) 104*06c3fb27SDimitry Andric continue; 105*06c3fb27SDimitry Andric 106*06c3fb27SDimitry Andric // B has not been partitioned, but it has a predecessor that has. 107*06c3fb27SDimitry Andric CFGInterval I = buildInterval(Partitioned, *B); 108*06c3fb27SDimitry Andric for (const auto *S : I.Successors) 109*06c3fb27SDimitry Andric Successors.push(S); 110*06c3fb27SDimitry Andric Intervals.push_back(std::move(I)); 111*06c3fb27SDimitry Andric } 112*06c3fb27SDimitry Andric 113*06c3fb27SDimitry Andric return Intervals; 114*06c3fb27SDimitry Andric } 115*06c3fb27SDimitry Andric 116*06c3fb27SDimitry Andric } // namespace clang 117