//===- IntervalPartition.cpp - CFG Partitioning into Intervals --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines functionality for partitioning a CFG into intervals. // //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/IntervalPartition.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/BitVector.h" #include #include #include namespace clang { static CFGInterval buildInterval(llvm::BitVector &Partitioned, const CFGBlock &Header) { CFGInterval Interval(&Header); Partitioned.set(Header.getBlockID()); // Elements must not be null. Duplicates are prevented using `Workset`, below. std::queue Worklist; llvm::BitVector Workset(Header.getParent()->getNumBlockIDs(), false); for (const CFGBlock *S : Header.succs()) if (S != nullptr) if (auto SID = S->getBlockID(); !Partitioned.test(SID)) { // Successors are unique, so we don't test against `Workset` before // adding to `Worklist`. Worklist.push(S); Workset.set(SID); } // Contains successors of blocks in the interval that couldn't be added to the // interval on their first encounter. This occurs when they have a predecessor // that is either definitively outside the interval or hasn't been considered // yet. In the latter case, we'll revisit the block through some other path // from the interval. At the end of processing the worklist, we filter out any // that ended up in the interval to produce the output set of interval // successors. It may contain duplicates -- ultimately, all relevant elements // are added to `Interval.Successors`, which is a set. std::vector MaybeSuccessors; while (!Worklist.empty()) { const auto *B = Worklist.front(); auto ID = B->getBlockID(); Worklist.pop(); Workset.reset(ID); // Check whether all predecessors are in the interval, in which case `B` // is included as well. bool AllInInterval = true; for (const CFGBlock *P : B->preds()) if (Interval.Blocks.find(P) == Interval.Blocks.end()) { MaybeSuccessors.push_back(B); AllInInterval = false; break; } if (AllInInterval) { Interval.Blocks.insert(B); Partitioned.set(ID); for (const CFGBlock *S : B->succs()) if (S != nullptr) if (auto SID = S->getBlockID(); !Partitioned.test(SID) && !Workset.test(SID)) { Worklist.push(S); Workset.set(SID); } } } // Any block successors not in the current interval are interval successors. for (const CFGBlock *B : MaybeSuccessors) if (Interval.Blocks.find(B) == Interval.Blocks.end()) Interval.Successors.insert(B); return Interval; } CFGInterval buildInterval(const CFG &Cfg, const CFGBlock &Header) { llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false); return buildInterval(Partitioned, Header); } std::vector partitionIntoIntervals(const CFG &Cfg) { std::vector Intervals; llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false); auto &EntryBlock = Cfg.getEntry(); Intervals.push_back(buildInterval(Partitioned, EntryBlock)); std::queue Successors; for (const auto *S : Intervals[0].Successors) Successors.push(S); while (!Successors.empty()) { const auto *B = Successors.front(); Successors.pop(); if (Partitioned.test(B->getBlockID())) continue; // B has not been partitioned, but it has a predecessor that has. CFGInterval I = buildInterval(Partitioned, *B); for (const auto *S : I.Successors) Successors.push(S); Intervals.push_back(std::move(I)); } return Intervals; } } // namespace clang