mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 19:26:05 +00:00

Adds support for the classic dataflow algorithm that partitions a flow graph into distinct intervals. C.f. Dragon book, pp. 664-666. A version of this algorithm exists in LLVM (see llvm/Analysis/Interval.h and related files), but it is specific to LLVM, is a recursive (vs iterative) algorithm, and uses many layers of abstraction that seem unnecessary for CFG purposes. This patch is part 1 of 2. The next patch will generalize the code to work on intervals, to support computation of the limit flow graph. Differential Revision: https://reviews.llvm.org/D152263
117 lines
4.0 KiB
C++
117 lines
4.0 KiB
C++
//===- 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 <queue>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
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<const CFGBlock *> 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<const CFGBlock *> 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<CFGInterval> partitionIntoIntervals(const CFG &Cfg) {
|
|
std::vector<CFGInterval> Intervals;
|
|
llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false);
|
|
auto &EntryBlock = Cfg.getEntry();
|
|
Intervals.push_back(buildInterval(Partitioned, EntryBlock));
|
|
|
|
std::queue<const CFGBlock *> 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
|