llvm-project/clang/lib/Analysis/Dominators.cpp

161 lines
4.5 KiB
C++

//==- Dominators.cpp - Construct the Dominance Tree Given CFG ----*- C++ --*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple, fast dominance algorithm for source-level CFGs.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/Dominators.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
using namespace clang;
DominatorTree::~DominatorTree() {
IDoms.clear();
RootNode = 0;
}
CFGBlock * DominatorTree::getNode(const CFGBlock *B) const {
CFGBlockMapTy::const_iterator I = IDoms.find(B);
return I != IDoms.end() ? I->second : 0;
}
bool DominatorTree::properlyDominates(const CFGBlock *A,
const CFGBlock *B) const {
if (0 == A || 0 == B || A == B)
return false;
// The EntryBlock dominates every other block.
if (A == RootNode)
return true;
// Note: The dominator of the EntryBlock is itself.
CFGBlock *IDom = getNode(B);
while (IDom != A && IDom != RootNode)
IDom = getNode(IDom);
return IDom != RootNode;
}
bool DominatorTree::dominates(const CFGBlock *A,
const CFGBlock *B) const {
if (A == B)
return true;
return properlyDominates(A, B);
}
const CFGBlock * DominatorTree::findNearestCommonDominator
(const CFGBlock *A, const CFGBlock *B) const {
//If A dominates B, then A is the nearest common dominator
if (dominates(A, B))
return A;
//If B dominates A, then B is the nearest common dominator
if (dominates(B, A))
return B;
//Collect all A's dominators
llvm::SmallPtrSet<CFGBlock *, 16> ADoms;
ADoms.insert(RootNode);
CFGBlock *ADom = getNode(A);
while (ADom != RootNode) {
ADoms.insert(ADom);
ADom = getNode(ADom);
}
//Check all B's dominators against ADoms
CFGBlock *BDom = getNode(B);
while (BDom != RootNode){
if (ADoms.count(BDom) != 0)
return BDom;
BDom = getNode(BDom);
}
//The RootNode dominates every other node
return RootNode;
}
/// Constructs immediate dominator tree for a given CFG based on the algorithm
/// described in this paper:
///
/// A Simple, Fast Dominance Algorithm
/// Keith D. Cooper, Timothy J. Harvey and Ken Kennedy
/// Software-Practice and Expreience, 2001;4:1-10.
///
/// This implementation is simple and runs faster in practice than the classis
/// Lengauer-Tarjan algorithm. For detailed discussions, refer to the paper.
void DominatorTree::BuildDominatorTree() {
CFG *cfg = AC.getCFG();
CFGBlock *EntryBlk = &cfg->getEntry();
//Sort all CFGBlocks in reverse order
PostOrderCFGView *rpocfg = AC.getAnalysis<PostOrderCFGView>();
//Set the root of the dominance tree
RootNode = EntryBlk;
//Compute the immediate dominator for each CFGBlock
IDoms[EntryBlk] = EntryBlk;
bool changed = true;
while (changed){
changed = false;
for (PostOrderCFGView::iterator I = rpocfg->begin(),
E = rpocfg->end(); I != E; ++I){
if (EntryBlk == *I)
continue;
if (const CFGBlock *B = *I) {
//Compute immediate dominance information for CFGBlock B
CFGBlock *IDom = 0;
for (CFGBlock::const_pred_iterator J = B->pred_begin(),
K = B->pred_end(); J != K; ++J)
if( CFGBlock *P = *J) {
if (IDoms.find(P) == IDoms.end())
continue;
if (!IDom)
IDom = P;
else {
//intersect IDom and P
CFGBlock *B1 = IDom, *B2 = P;
while (B1 != B2) {
while ((rpocfg->getComparator())(B2,B1))
B1 = IDoms[B1];
while ((rpocfg->getComparator())(B1,B2))
B2 = IDoms[B2];
}
IDom = B1;
}
}
if (IDoms[B] != IDom) {
IDoms[B] = IDom;
changed = true;
}
}
}
}//while
}
void DominatorTree::dump() {
CFG *cfg = AC.getCFG();
llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n";
for (CFG::const_iterator I = cfg->begin(),
E = cfg->end(); I != E; ++I) {
assert(IDoms[(*I)] &&
"Failed to find the immediate dominator for all CFG blocks.");
llvm::errs() << "(" << (*I)->getBlockID()
<< "," << IDoms[(*I)]->getBlockID() << ")\n";
}
}