//===- PathNumbering.cpp --------------------------------------*- C++ -*---===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Ball-Larus path numbers uniquely identify paths through a directed acyclic // graph (DAG) [Ball96]. For a CFG backedges are removed and replaced by phony // edges to obtain a DAG, and thus the unique path numbers [Ball96]. // // The purpose of this analysis is to enumerate the edges in a CFG in order // to obtain paths from path numbers in a convenient manner. As described in // [Ball96] edges can be enumerated such that given a path number by following // the CFG and updating the path number, the path is obtained. // // [Ball96] // T. Ball and J. R. Larus. "Efficient Path Profiling." // International Symposium on Microarchitecture, pages 46-57, 1996. // http://portal.acm.org/citation.cfm?id=243857 // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "ball-larus-numbering" #include "llvm/Analysis/PathNumbering.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/InstrTypes.h" #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/Support/CFG.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TypeBuilder.h" #include "llvm/Support/raw_ostream.h" #include <queue> #include <stack> #include <string> #include <utility> #include <sstream> using namespace llvm; // Are we enabling early termination static cl::opt<bool> ProcessEarlyTermination( "path-profile-early-termination", cl::Hidden, cl::desc("In path profiling, insert extra instrumentation to account for " "unexpected function termination.")); // Returns the basic block for the BallLarusNode BasicBlock* BallLarusNode::getBlock() { return(_basicBlock); } // Returns the number of paths to the exit starting at the node. unsigned BallLarusNode::getNumberPaths() { return(_numberPaths); } // Sets the number of paths to the exit starting at the node. void BallLarusNode::setNumberPaths(unsigned numberPaths) { _numberPaths = numberPaths; } // Gets the NodeColor used in graph algorithms. BallLarusNode::NodeColor BallLarusNode::getColor() { return(_color); } // Sets the NodeColor used in graph algorithms. void BallLarusNode::setColor(BallLarusNode::NodeColor color) { _color = color; } // Returns an iterator over predecessor edges. Includes phony and // backedges. BLEdgeIterator BallLarusNode::predBegin() { return(_predEdges.begin()); } // Returns the end sentinel for the predecessor iterator. BLEdgeIterator BallLarusNode::predEnd() { return(_predEdges.end()); } // Returns the number of predecessor edges. Includes phony and // backedges. unsigned BallLarusNode::getNumberPredEdges() { return(_predEdges.size()); } // Returns an iterator over successor edges. Includes phony and // backedges. BLEdgeIterator BallLarusNode::succBegin() { return(_succEdges.begin()); } // Returns the end sentinel for the successor iterator. BLEdgeIterator BallLarusNode::succEnd() { return(_succEdges.end()); } // Returns the number of successor edges. Includes phony and // backedges. unsigned BallLarusNode::getNumberSuccEdges() { return(_succEdges.size()); } // Add an edge to the predecessor list. void BallLarusNode::addPredEdge(BallLarusEdge* edge) { _predEdges.push_back(edge); } // Remove an edge from the predecessor list. void BallLarusNode::removePredEdge(BallLarusEdge* edge) { removeEdge(_predEdges, edge); } // Add an edge to the successor list. void BallLarusNode::addSuccEdge(BallLarusEdge* edge) { _succEdges.push_back(edge); } // Remove an edge from the successor list. void BallLarusNode::removeSuccEdge(BallLarusEdge* edge) { removeEdge(_succEdges, edge); } // Returns the name of the BasicBlock being represented. If BasicBlock // is null then returns "<null>". If BasicBlock has no name, then // "<unnamed>" is returned. Intended for use with debug output. std::string BallLarusNode::getName() { std::stringstream name; if(getBlock() != NULL) { if(getBlock()->hasName()) { std::string tempName(getBlock()->getName()); name << tempName.c_str() << " (" << _uid << ")"; } else name << "<unnamed> (" << _uid << ")"; } else name << "<null> (" << _uid << ")"; return name.str(); } // Removes an edge from an edgeVector. Used by removePredEdge and // removeSuccEdge. void BallLarusNode::removeEdge(BLEdgeVector& v, BallLarusEdge* e) { // TODO: Avoid linear scan by using a set instead for(BLEdgeIterator i = v.begin(), end = v.end(); i != end; ++i) { if((*i) == e) { v.erase(i); break; } } } // Returns the source node of this edge. BallLarusNode* BallLarusEdge::getSource() const { return(_source); } // Returns the target node of this edge. BallLarusNode* BallLarusEdge::getTarget() const { return(_target); } // Sets the type of the edge. BallLarusEdge::EdgeType BallLarusEdge::getType() const { return _edgeType; } // Gets the type of the edge. void BallLarusEdge::setType(EdgeType type) { _edgeType = type; } // Returns the weight of this edge. Used to decode path numbers to sequences // of basic blocks. unsigned BallLarusEdge::getWeight() { return(_weight); } // Sets the weight of the edge. Used during path numbering. void BallLarusEdge::setWeight(unsigned weight) { _weight = weight; } // Gets the phony edge originating at the root. BallLarusEdge* BallLarusEdge::getPhonyRoot() { return _phonyRoot; } // Sets the phony edge originating at the root. void BallLarusEdge::setPhonyRoot(BallLarusEdge* phonyRoot) { _phonyRoot = phonyRoot; } // Gets the phony edge terminating at the exit. BallLarusEdge* BallLarusEdge::getPhonyExit() { return _phonyExit; } // Sets the phony edge terminating at the exit. void BallLarusEdge::setPhonyExit(BallLarusEdge* phonyExit) { _phonyExit = phonyExit; } // Gets the associated real edge if this is a phony edge. BallLarusEdge* BallLarusEdge::getRealEdge() { return _realEdge; } // Sets the associated real edge if this is a phony edge. void BallLarusEdge::setRealEdge(BallLarusEdge* realEdge) { _realEdge = realEdge; } // Returns the duplicate number of the edge. unsigned BallLarusEdge::getDuplicateNumber() { return(_duplicateNumber); } // Initialization that requires virtual functions which are not fully // functional in the constructor. void BallLarusDag::init() { BLBlockNodeMap inDag; std::stack<BallLarusNode*> dfsStack; _root = addNode(&(_function.getEntryBlock())); _exit = addNode(NULL); // start search from root dfsStack.push(getRoot()); // dfs to add each bb into the dag while(dfsStack.size()) buildNode(inDag, dfsStack); // put in the final edge addEdge(getExit(),getRoot(),0); } // Frees all memory associated with the DAG. BallLarusDag::~BallLarusDag() { for(BLEdgeIterator edge = _edges.begin(), end = _edges.end(); edge != end; ++edge) delete (*edge); for(BLNodeIterator node = _nodes.begin(), end = _nodes.end(); node != end; ++node) delete (*node); } // Calculate the path numbers by assigning edge increments as prescribed // in Ball-Larus path profiling. void BallLarusDag::calculatePathNumbers() { BallLarusNode* node; std::queue<BallLarusNode*> bfsQueue; bfsQueue.push(getExit()); while(bfsQueue.size() > 0) { node = bfsQueue.front(); DEBUG(dbgs() << "calculatePathNumbers on " << node->getName() << "\n"); bfsQueue.pop(); unsigned prevPathNumber = node->getNumberPaths(); calculatePathNumbersFrom(node); // Check for DAG splitting if( node->getNumberPaths() > 100000000 && node != getRoot() ) { // Add new phony edge from the split-node to the DAG's exit BallLarusEdge* exitEdge = addEdge(node, getExit(), 0); exitEdge->setType(BallLarusEdge::SPLITEDGE_PHONY); // Counters to handle the possibility of a multi-graph BasicBlock* oldTarget = 0; unsigned duplicateNumber = 0; // Iterate through each successor edge, adding phony edges for( BLEdgeIterator succ = node->succBegin(), end = node->succEnd(); succ != end; oldTarget = (*succ)->getTarget()->getBlock(), succ++ ) { if( (*succ)->getType() == BallLarusEdge::NORMAL ) { // is this edge a duplicate? if( oldTarget != (*succ)->getTarget()->getBlock() ) duplicateNumber = 0; // create the new phony edge: root -> succ BallLarusEdge* rootEdge = addEdge(getRoot(), (*succ)->getTarget(), duplicateNumber++); rootEdge->setType(BallLarusEdge::SPLITEDGE_PHONY); rootEdge->setRealEdge(*succ); // split on this edge and reference it's exit/root phony edges (*succ)->setType(BallLarusEdge::SPLITEDGE); (*succ)->setPhonyRoot(rootEdge); (*succ)->setPhonyExit(exitEdge); (*succ)->setWeight(0); } } calculatePathNumbersFrom(node); } DEBUG(dbgs() << "prev, new number paths " << prevPathNumber << ", " << node->getNumberPaths() << ".\n"); if(prevPathNumber == 0 && node->getNumberPaths() != 0) { DEBUG(dbgs() << "node ready : " << node->getName() << "\n"); for(BLEdgeIterator pred = node->predBegin(), end = node->predEnd(); pred != end; pred++) { if( (*pred)->getType() == BallLarusEdge::BACKEDGE || (*pred)->getType() == BallLarusEdge::SPLITEDGE ) continue; BallLarusNode* nextNode = (*pred)->getSource(); // not yet visited? if(nextNode->getNumberPaths() == 0) bfsQueue.push(nextNode); } } } DEBUG(dbgs() << "\tNumber of paths: " << getRoot()->getNumberPaths() << "\n"); } // Returns the number of paths for the Dag. unsigned BallLarusDag::getNumberOfPaths() { return(getRoot()->getNumberPaths()); } // Returns the root (i.e. entry) node for the DAG. BallLarusNode* BallLarusDag::getRoot() { return _root; } // Returns the exit node for the DAG. BallLarusNode* BallLarusDag::getExit() { return _exit; } // Returns the function for the DAG. Function& BallLarusDag::getFunction() { return(_function); } // Clears the node colors. void BallLarusDag::clearColors(BallLarusNode::NodeColor color) { for (BLNodeIterator nodeIt = _nodes.begin(); nodeIt != _nodes.end(); nodeIt++) (*nodeIt)->setColor(color); } // Processes one node and its imediate edges for building the DAG. void BallLarusDag::buildNode(BLBlockNodeMap& inDag, BLNodeStack& dfsStack) { BallLarusNode* currentNode = dfsStack.top(); BasicBlock* currentBlock = currentNode->getBlock(); if(currentNode->getColor() != BallLarusNode::WHITE) { // we have already visited this node dfsStack.pop(); currentNode->setColor(BallLarusNode::BLACK); } else { // are there any external procedure calls? if( ProcessEarlyTermination ) { for( BasicBlock::iterator bbCurrent = currentNode->getBlock()->begin(), bbEnd = currentNode->getBlock()->end(); bbCurrent != bbEnd; bbCurrent++ ) { Instruction& instr = *bbCurrent; if( instr.getOpcode() == Instruction::Call ) { BallLarusEdge* callEdge = addEdge(currentNode, getExit(), 0); callEdge->setType(BallLarusEdge::CALLEDGE_PHONY); break; } } } TerminatorInst* terminator = currentNode->getBlock()->getTerminator(); if(isa<ReturnInst>(terminator) || isa<UnreachableInst>(terminator) || isa<ResumeInst>(terminator) || isa<UnwindInst>(terminator)) addEdge(currentNode, getExit(),0); currentNode->setColor(BallLarusNode::GRAY); inDag[currentBlock] = currentNode; BasicBlock* oldSuccessor = 0; unsigned duplicateNumber = 0; // iterate through this node's successors for(succ_iterator successor = succ_begin(currentBlock), succEnd = succ_end(currentBlock); successor != succEnd; oldSuccessor = *successor, ++successor ) { BasicBlock* succBB = *successor; // is this edge a duplicate? if (oldSuccessor == succBB) duplicateNumber++; else duplicateNumber = 0; buildEdge(inDag, dfsStack, currentNode, succBB, duplicateNumber); } } } // Process an edge in the CFG for DAG building. void BallLarusDag::buildEdge(BLBlockNodeMap& inDag, std::stack<BallLarusNode*>& dfsStack, BallLarusNode* currentNode, BasicBlock* succBB, unsigned duplicateCount) { BallLarusNode* succNode = inDag[succBB]; if(succNode && succNode->getColor() == BallLarusNode::BLACK) { // visited node and forward edge addEdge(currentNode, succNode, duplicateCount); } else if(succNode && succNode->getColor() == BallLarusNode::GRAY) { // visited node and back edge DEBUG(dbgs() << "Backedge detected.\n"); addBackedge(currentNode, succNode, duplicateCount); } else { BallLarusNode* childNode; // not visited node and forward edge if(succNode) // an unvisited node that is child of a gray node childNode = succNode; else { // an unvisited node that is a child of a an unvisted node childNode = addNode(succBB); inDag[succBB] = childNode; } addEdge(currentNode, childNode, duplicateCount); dfsStack.push(childNode); } } // The weight on each edge is the increment required along any path that // contains that edge. void BallLarusDag::calculatePathNumbersFrom(BallLarusNode* node) { if(node == getExit()) // The Exit node must be base case node->setNumberPaths(1); else { unsigned sumPaths = 0; BallLarusNode* succNode; for(BLEdgeIterator succ = node->succBegin(), end = node->succEnd(); succ != end; succ++) { if( (*succ)->getType() == BallLarusEdge::BACKEDGE || (*succ)->getType() == BallLarusEdge::SPLITEDGE ) continue; (*succ)->setWeight(sumPaths); succNode = (*succ)->getTarget(); if( !succNode->getNumberPaths() ) return; sumPaths += succNode->getNumberPaths(); } node->setNumberPaths(sumPaths); } } // Allows subclasses to determine which type of Node is created. // Override this method to produce subclasses of BallLarusNode if // necessary. The destructor of BallLarusDag will call free on each // pointer created. BallLarusNode* BallLarusDag::createNode(BasicBlock* BB) { return( new BallLarusNode(BB) ); } // Allows subclasses to determine which type of Edge is created. // Override this method to produce subclasses of BallLarusEdge if // necessary. The destructor of BallLarusDag will call free on each // pointer created. BallLarusEdge* BallLarusDag::createEdge(BallLarusNode* source, BallLarusNode* target, unsigned duplicateCount) { return( new BallLarusEdge(source, target, duplicateCount) ); } // Proxy to node's constructor. Updates the DAG state. BallLarusNode* BallLarusDag::addNode(BasicBlock* BB) { BallLarusNode* newNode = createNode(BB); _nodes.push_back(newNode); return( newNode ); } // Proxy to edge's constructor. Updates the DAG state. BallLarusEdge* BallLarusDag::addEdge(BallLarusNode* source, BallLarusNode* target, unsigned duplicateCount) { BallLarusEdge* newEdge = createEdge(source, target, duplicateCount); _edges.push_back(newEdge); source->addSuccEdge(newEdge); target->addPredEdge(newEdge); return(newEdge); } // Adds a backedge with its phony edges. Updates the DAG state. void BallLarusDag::addBackedge(BallLarusNode* source, BallLarusNode* target, unsigned duplicateCount) { BallLarusEdge* childEdge = addEdge(source, target, duplicateCount); childEdge->setType(BallLarusEdge::BACKEDGE); childEdge->setPhonyRoot(addEdge(getRoot(), target,0)); childEdge->setPhonyExit(addEdge(source, getExit(),0)); childEdge->getPhonyRoot()->setRealEdge(childEdge); childEdge->getPhonyRoot()->setType(BallLarusEdge::BACKEDGE_PHONY); childEdge->getPhonyExit()->setRealEdge(childEdge); childEdge->getPhonyExit()->setType(BallLarusEdge::BACKEDGE_PHONY); _backEdges.push_back(childEdge); }