mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
04317cc618
Modified patch by Adam Preuss. This builds on the existing framework for block tracing, edge profiling and optimal edge profiling. See -help-hidden for new flags. For documentation, see the technical report "Implementation of Path Profiling..." in llvm.org/pubs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@124515 91177308-0d34-0410-b5e6-96231b3b80d8
435 lines
14 KiB
C++
435 lines
14 KiB
C++
//===- PathProfileInfo.cpp ------------------------------------*- C++ -*---===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the interface used by optimizers to load path profiles,
|
|
// and provides a loader pass which reads a path profile file.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#define DEBUG_TYPE "path-profile-info"
|
|
|
|
#include "llvm/Module.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Analysis/Passes.h"
|
|
#include "llvm/Analysis/ProfileInfoTypes.h"
|
|
#include "llvm/Analysis/PathProfileInfo.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <cstdio>
|
|
|
|
using namespace llvm;
|
|
|
|
// command line option for loading path profiles
|
|
static cl::opt<std::string>
|
|
PathProfileInfoFilename("path-profile-loader-file", cl::init("llvmprof.out"),
|
|
cl::value_desc("filename"),
|
|
cl::desc("Path profile file loaded by -path-profile-loader"), cl::Hidden);
|
|
|
|
namespace {
|
|
class PathProfileLoaderPass : public ModulePass, public PathProfileInfo {
|
|
public:
|
|
PathProfileLoaderPass() : ModulePass(ID) { }
|
|
~PathProfileLoaderPass();
|
|
|
|
// this pass doesn't change anything (only loads information)
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.setPreservesAll();
|
|
}
|
|
|
|
// the full name of the loader pass
|
|
virtual const char* getPassName() const {
|
|
return "Path Profiling Information Loader";
|
|
}
|
|
|
|
// required since this pass implements multiple inheritance
|
|
virtual void *getAdjustedAnalysisPointer(AnalysisID PI) {
|
|
if (PI == &PathProfileInfo::ID)
|
|
return (PathProfileInfo*)this;
|
|
return this;
|
|
}
|
|
|
|
// entry point to run the pass
|
|
bool runOnModule(Module &M);
|
|
|
|
// pass identification
|
|
static char ID;
|
|
|
|
private:
|
|
// make a reference table to refer to function by number
|
|
void buildFunctionRefs(Module &M);
|
|
|
|
// process argument info of a program from the input file
|
|
void handleArgumentInfo();
|
|
|
|
// process path number information from the input file
|
|
void handlePathInfo();
|
|
|
|
// array of references to the functions in the module
|
|
std::vector<Function*> _functions;
|
|
|
|
// path profile file handle
|
|
FILE* _file;
|
|
|
|
// path profile file name
|
|
std::string _filename;
|
|
};
|
|
}
|
|
|
|
// register PathLoader
|
|
char PathProfileLoaderPass::ID = 0;
|
|
|
|
INITIALIZE_ANALYSIS_GROUP(PathProfileInfo, "Path Profile Information",
|
|
NoPathProfileInfo)
|
|
INITIALIZE_AG_PASS(PathProfileLoaderPass, PathProfileInfo,
|
|
"path-profile-loader",
|
|
"Load path profile information from file",
|
|
false, true, false)
|
|
|
|
char &llvm::PathProfileLoaderPassID = PathProfileLoaderPass::ID;
|
|
|
|
// link PathLoader as a pass, and make it available as an optimisation
|
|
ModulePass *llvm::createPathProfileLoaderPass() {
|
|
return new PathProfileLoaderPass;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// PathEdge implementation
|
|
//
|
|
ProfilePathEdge::ProfilePathEdge (BasicBlock* source, BasicBlock* target,
|
|
unsigned duplicateNumber)
|
|
: _source(source), _target(target), _duplicateNumber(duplicateNumber) {}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Path implementation
|
|
//
|
|
|
|
ProfilePath::ProfilePath (unsigned int number, unsigned int count,
|
|
double countStdDev, PathProfileInfo* ppi)
|
|
: _number(number) , _count(count), _countStdDev(countStdDev), _ppi(ppi) {}
|
|
|
|
double ProfilePath::getFrequency() const {
|
|
return 100 * double(_count) /
|
|
double(_ppi->_functionPathCounts[_ppi->_currentFunction]);
|
|
}
|
|
|
|
static BallLarusEdge* getNextEdge (BallLarusNode* node,
|
|
unsigned int pathNumber) {
|
|
BallLarusEdge* best = 0;
|
|
|
|
for( BLEdgeIterator next = node->succBegin(),
|
|
end = node->succEnd(); next != end; next++ ) {
|
|
if( (*next)->getType() != BallLarusEdge::BACKEDGE && // no backedges
|
|
(*next)->getType() != BallLarusEdge::SPLITEDGE && // no split edges
|
|
(*next)->getWeight() <= pathNumber && // weight must be <= pathNumber
|
|
(!best || (best->getWeight() < (*next)->getWeight())) ) // best one?
|
|
best = *next;
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
ProfilePathEdgeVector* ProfilePath::getPathEdges() const {
|
|
BallLarusNode* currentNode = _ppi->_currentDag->getRoot ();
|
|
unsigned int increment = _number;
|
|
ProfilePathEdgeVector* pev = new ProfilePathEdgeVector;
|
|
|
|
while (currentNode != _ppi->_currentDag->getExit()) {
|
|
BallLarusEdge* next = getNextEdge(currentNode, increment);
|
|
|
|
increment -= next->getWeight();
|
|
|
|
if( next->getType() != BallLarusEdge::BACKEDGE_PHONY &&
|
|
next->getType() != BallLarusEdge::SPLITEDGE_PHONY &&
|
|
next->getTarget() != _ppi->_currentDag->getExit() )
|
|
pev->push_back(ProfilePathEdge(
|
|
next->getSource()->getBlock(),
|
|
next->getTarget()->getBlock(),
|
|
next->getDuplicateNumber()));
|
|
|
|
if( next->getType() == BallLarusEdge::BACKEDGE_PHONY &&
|
|
next->getTarget() == _ppi->_currentDag->getExit() )
|
|
pev->push_back(ProfilePathEdge(
|
|
next->getRealEdge()->getSource()->getBlock(),
|
|
next->getRealEdge()->getTarget()->getBlock(),
|
|
next->getDuplicateNumber()));
|
|
|
|
if( next->getType() == BallLarusEdge::SPLITEDGE_PHONY &&
|
|
next->getSource() == _ppi->_currentDag->getRoot() )
|
|
pev->push_back(ProfilePathEdge(
|
|
next->getRealEdge()->getSource()->getBlock(),
|
|
next->getRealEdge()->getTarget()->getBlock(),
|
|
next->getDuplicateNumber()));
|
|
|
|
// set the new node
|
|
currentNode = next->getTarget();
|
|
}
|
|
|
|
return pev;
|
|
}
|
|
|
|
ProfilePathBlockVector* ProfilePath::getPathBlocks() const {
|
|
BallLarusNode* currentNode = _ppi->_currentDag->getRoot ();
|
|
unsigned int increment = _number;
|
|
ProfilePathBlockVector* pbv = new ProfilePathBlockVector;
|
|
|
|
while (currentNode != _ppi->_currentDag->getExit()) {
|
|
BallLarusEdge* next = getNextEdge(currentNode, increment);
|
|
increment -= next->getWeight();
|
|
|
|
// add block to the block list if it is a real edge
|
|
if( next->getType() == BallLarusEdge::NORMAL)
|
|
pbv->push_back (currentNode->getBlock());
|
|
// make the back edge the last edge since we are at the end
|
|
else if( next->getTarget() == _ppi->_currentDag->getExit() ) {
|
|
pbv->push_back (currentNode->getBlock());
|
|
pbv->push_back (next->getRealEdge()->getTarget()->getBlock());
|
|
}
|
|
|
|
// set the new node
|
|
currentNode = next->getTarget();
|
|
}
|
|
|
|
return pbv;
|
|
}
|
|
|
|
BasicBlock* ProfilePath::getFirstBlockInPath() const {
|
|
BallLarusNode* root = _ppi->_currentDag->getRoot();
|
|
BallLarusEdge* edge = getNextEdge(root, _number);
|
|
|
|
if( edge && (edge->getType() == BallLarusEdge::BACKEDGE_PHONY ||
|
|
edge->getType() == BallLarusEdge::SPLITEDGE_PHONY) )
|
|
return edge->getTarget()->getBlock();
|
|
|
|
return root->getBlock();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// PathProfileInfo implementation
|
|
//
|
|
|
|
// Pass identification
|
|
char llvm::PathProfileInfo::ID = 0;
|
|
|
|
PathProfileInfo::PathProfileInfo () : _currentDag(0) , _currentFunction(0) {
|
|
}
|
|
|
|
PathProfileInfo::~PathProfileInfo() {
|
|
if (_currentDag)
|
|
delete _currentDag;
|
|
}
|
|
|
|
// set the function for which paths are currently begin processed
|
|
void PathProfileInfo::setCurrentFunction(Function* F) {
|
|
// Make sure it exists
|
|
if (!F) return;
|
|
|
|
if (_currentDag)
|
|
delete _currentDag;
|
|
|
|
_currentFunction = F;
|
|
_currentDag = new BallLarusDag(*F);
|
|
_currentDag->init();
|
|
_currentDag->calculatePathNumbers();
|
|
}
|
|
|
|
// get the function for which paths are currently being processed
|
|
Function* PathProfileInfo::getCurrentFunction() const {
|
|
return _currentFunction;
|
|
}
|
|
|
|
// get the entry block of the function
|
|
BasicBlock* PathProfileInfo::getCurrentFunctionEntry() {
|
|
return _currentDag->getRoot()->getBlock();
|
|
}
|
|
|
|
// return the path based on its number
|
|
ProfilePath* PathProfileInfo::getPath(unsigned int number) {
|
|
return _functionPaths[_currentFunction][number];
|
|
}
|
|
|
|
// return the number of paths which a function may potentially execute
|
|
unsigned int PathProfileInfo::getPotentialPathCount() {
|
|
return _currentDag ? _currentDag->getNumberOfPaths() : 0;
|
|
}
|
|
|
|
// return an iterator for the beginning of a functions executed paths
|
|
ProfilePathIterator PathProfileInfo::pathBegin() {
|
|
return _functionPaths[_currentFunction].begin();
|
|
}
|
|
|
|
// return an iterator for the end of a functions executed paths
|
|
ProfilePathIterator PathProfileInfo::pathEnd() {
|
|
return _functionPaths[_currentFunction].end();
|
|
}
|
|
|
|
// returns the total number of paths run in the function
|
|
unsigned int PathProfileInfo::pathsRun() {
|
|
return _currentFunction ? _functionPaths[_currentFunction].size() : 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// PathLoader implementation
|
|
//
|
|
|
|
// remove all generated paths
|
|
PathProfileLoaderPass::~PathProfileLoaderPass() {
|
|
for( FunctionPathIterator funcNext = _functionPaths.begin(),
|
|
funcEnd = _functionPaths.end(); funcNext != funcEnd; funcNext++)
|
|
for( ProfilePathIterator pathNext = funcNext->second.begin(),
|
|
pathEnd = funcNext->second.end(); pathNext != pathEnd; pathNext++)
|
|
delete pathNext->second;
|
|
}
|
|
|
|
// entry point of the pass; this loads and parses a file
|
|
bool PathProfileLoaderPass::runOnModule(Module &M) {
|
|
// get the filename and setup the module's function references
|
|
_filename = PathProfileInfoFilename;
|
|
buildFunctionRefs (M);
|
|
|
|
if (!(_file = fopen(_filename.c_str(), "rb"))) {
|
|
errs () << "error: input '" << _filename << "' file does not exist.\n";
|
|
return false;
|
|
}
|
|
|
|
ProfilingType profType;
|
|
|
|
while( fread(&profType, sizeof(ProfilingType), 1, _file) ) {
|
|
switch (profType) {
|
|
case ArgumentInfo:
|
|
handleArgumentInfo ();
|
|
break;
|
|
case PathInfo:
|
|
handlePathInfo ();
|
|
break;
|
|
default:
|
|
errs () << "error: bad path profiling file syntax, " << profType << "\n";
|
|
fclose (_file);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
fclose (_file);
|
|
|
|
return true;
|
|
}
|
|
|
|
// create a reference table for functions defined in the path profile file
|
|
void PathProfileLoaderPass::buildFunctionRefs (Module &M) {
|
|
_functions.push_back(0); // make the 0 index a null pointer
|
|
|
|
for (Module::iterator F = M.begin(), E = M.end(); F != E; F++) {
|
|
if (F->isDeclaration())
|
|
continue;
|
|
_functions.push_back(F);
|
|
}
|
|
}
|
|
|
|
// handle command like argument infor in the output file
|
|
void PathProfileLoaderPass::handleArgumentInfo() {
|
|
// get the argument list's length
|
|
unsigned savedArgsLength;
|
|
if( fread(&savedArgsLength, sizeof(unsigned), 1, _file) != 1 ) {
|
|
errs() << "warning: argument info header/data mismatch\n";
|
|
return;
|
|
}
|
|
|
|
// allocate a buffer, and get the arguments
|
|
char* args = new char[savedArgsLength+1];
|
|
if( fread(args, 1, savedArgsLength, _file) != savedArgsLength )
|
|
errs() << "warning: argument info header/data mismatch\n";
|
|
|
|
args[savedArgsLength] = '\0';
|
|
argList = std::string(args);
|
|
delete [] args; // cleanup dynamic string
|
|
|
|
// byte alignment
|
|
if (savedArgsLength & 3)
|
|
fseek(_file, 4-(savedArgsLength&3), SEEK_CUR);
|
|
}
|
|
|
|
// Handle path profile information in the output file
|
|
void PathProfileLoaderPass::handlePathInfo () {
|
|
// get the number of functions in this profile
|
|
unsigned functionCount;
|
|
if( fread(&functionCount, sizeof(functionCount), 1, _file) != 1 ) {
|
|
errs() << "warning: path info header/data mismatch\n";
|
|
return;
|
|
}
|
|
|
|
// gather path information for each function
|
|
for (unsigned i = 0; i < functionCount; i++) {
|
|
PathProfileHeader pathHeader;
|
|
if( fread(&pathHeader, sizeof(pathHeader), 1, _file) != 1 ) {
|
|
errs() << "warning: bad header for path function info\n";
|
|
break;
|
|
}
|
|
|
|
Function* f = _functions[pathHeader.fnNumber];
|
|
|
|
// dynamically allocate a table to store path numbers
|
|
PathProfileTableEntry* pathTable =
|
|
new PathProfileTableEntry[pathHeader.numEntries];
|
|
|
|
if( fread(pathTable, sizeof(PathProfileTableEntry),
|
|
pathHeader.numEntries, _file) != pathHeader.numEntries) {
|
|
delete [] pathTable;
|
|
errs() << "warning: path function info header/data mismatch\n";
|
|
return;
|
|
}
|
|
|
|
// Build a new path for the current function
|
|
unsigned int totalPaths = 0;
|
|
for (unsigned int j = 0; j < pathHeader.numEntries; j++) {
|
|
totalPaths += pathTable[j].pathCounter;
|
|
_functionPaths[f][pathTable[j].pathNumber]
|
|
= new ProfilePath(pathTable[j].pathNumber, pathTable[j].pathCounter,
|
|
0, this);
|
|
}
|
|
|
|
_functionPathCounts[f] = totalPaths;
|
|
|
|
delete [] pathTable;
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// NoProfile PathProfileInfo implementation
|
|
//
|
|
|
|
namespace {
|
|
struct NoPathProfileInfo : public ImmutablePass, public PathProfileInfo {
|
|
static char ID; // Class identification, replacement for typeinfo
|
|
NoPathProfileInfo() : ImmutablePass(ID) {
|
|
initializeNoPathProfileInfoPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
/// getAdjustedAnalysisPointer - This method is used when a pass implements
|
|
/// an analysis interface through multiple inheritance. If needed, it
|
|
/// should override this to adjust the this pointer as needed for the
|
|
/// specified pass info.
|
|
virtual void *getAdjustedAnalysisPointer(AnalysisID PI) {
|
|
if (PI == &PathProfileInfo::ID)
|
|
return (PathProfileInfo*)this;
|
|
return this;
|
|
}
|
|
|
|
virtual const char *getPassName() const {
|
|
return "NoPathProfileInfo";
|
|
}
|
|
};
|
|
} // End of anonymous namespace
|
|
|
|
char NoPathProfileInfo::ID = 0;
|
|
// Register this pass...
|
|
INITIALIZE_AG_PASS(NoPathProfileInfo, PathProfileInfo, "no-path-profile",
|
|
"No Path Profile Information", false, true, true)
|
|
|
|
ImmutablePass *llvm::createNoPathProfileInfoPass() { return new NoPathProfileInfo(); }
|