mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	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(); }
 |