llvm-6502/lib/Transforms/Instrumentation/BlockProfiling.cpp
Chris Lattner 81d1a2207d initialization calls now return argc. If the program uses the argc value
passed into main, make sure they use the return value of the init call
instead of the one passed in.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11262 91177308-0d34-0410-b5e6-96231b3b80d8
2004-02-10 17:41:01 +00:00

193 lines
7.0 KiB
C++

//===- BlockProfiling.cpp - Insert counters for block profiling -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass instruments the specified program with counters for basic block or
// function profiling. This is the most basic form of profiling, which can tell
// which blocks are hot, but cannot reliably detect hot paths through the CFG.
// Block profiling counts the number of times each basic block executes, and
// function profiling counts the number of times each function is called.
//
// Note that this implementation is very naive. Control equivalent regions of
// the CFG should not require duplicate counters, but we do put duplicate
// counters in.
//
//===----------------------------------------------------------------------===//
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
using namespace llvm;
static void insertInitializationCall(Function *MainFn, const char *FnName,
GlobalValue *Array) {
const Type *ArgVTy = PointerType::get(PointerType::get(Type::SByteTy));
const Type *UIntPtr = PointerType::get(Type::UIntTy);
Module &M = *MainFn->getParent();
Function *InitFn = M.getOrInsertFunction(FnName, Type::IntTy, Type::IntTy,
ArgVTy, UIntPtr, Type::UIntTy, 0);
// This could force argc and argv into programs that wouldn't otherwise have
// them, but instead we just pass null values in.
std::vector<Value*> Args(4);
Args[0] = Constant::getNullValue(Type::IntTy);
Args[1] = Constant::getNullValue(ArgVTy);
// Skip over any allocas in the entry block.
BasicBlock *Entry = MainFn->begin();
BasicBlock::iterator InsertPos = Entry->begin();
while (isa<AllocaInst>(InsertPos)) ++InsertPos;
ConstantPointerRef *ArrayCPR = ConstantPointerRef::get(Array);
std::vector<Constant*> GEPIndices(2, Constant::getNullValue(Type::LongTy));
Args[2] = ConstantExpr::getGetElementPtr(ArrayCPR, GEPIndices);
unsigned NumElements =
cast<ArrayType>(Array->getType()->getElementType())->getNumElements();
Args[3] = ConstantUInt::get(Type::UIntTy, NumElements);
Instruction *InitCall = new CallInst(InitFn, Args, "newargc", InsertPos);
// If argc or argv are not available in main, just pass null values in.
Function::aiterator AI;
switch (MainFn->asize()) {
default:
case 2:
AI = MainFn->abegin(); ++AI;
if (AI->getType() != ArgVTy) {
InitCall->setOperand(2, new CastInst(AI, ArgVTy, "argv.cast", InitCall));
} else {
InitCall->setOperand(2, AI);
}
case 1:
AI = MainFn->abegin();
// If the program looked at argc, have it look at the return value of the
// init call instead.
if (AI->getType() != Type::IntTy) {
if (!AI->use_empty())
AI->replaceAllUsesWith(new CastInst(InitCall, AI->getType(), "",
InsertPos));
InitCall->setOperand(1, new CastInst(AI, Type::IntTy, "argc.cast",
InitCall));
} else {
AI->replaceAllUsesWith(InitCall);
InitCall->setOperand(1, AI);
}
case 0: break;
}
}
static void IncrementCounterInBlock(BasicBlock *BB, unsigned CounterNum,
ConstantPointerRef *CounterArray) {
// Insert the increment after any alloca or PHI instructions...
BasicBlock::iterator InsertPos = BB->begin();
while (isa<AllocaInst>(InsertPos) || isa<PHINode>(InsertPos))
++InsertPos;
// Create the getelementptr constant expression
std::vector<Constant*> Indices(2);
Indices[0] = Constant::getNullValue(Type::LongTy);
Indices[1] = ConstantSInt::get(Type::LongTy, CounterNum);
Constant *ElementPtr = ConstantExpr::getGetElementPtr(CounterArray, Indices);
// Load, increment and store the value back.
Value *OldVal = new LoadInst(ElementPtr, "OldFuncCounter", InsertPos);
Value *NewVal = BinaryOperator::create(Instruction::Add, OldVal,
ConstantInt::get(Type::UIntTy, 1),
"NewFuncCounter", InsertPos);
new StoreInst(NewVal, ElementPtr, InsertPos);
}
namespace {
class FunctionProfiler : public Pass {
bool run(Module &M);
};
RegisterOpt<FunctionProfiler> X("insert-function-profiling",
"Insert instrumentation for function profiling");
}
bool FunctionProfiler::run(Module &M) {
Function *Main = M.getMainFunction();
if (Main == 0) {
std::cerr << "WARNING: cannot insert function profiling into a module"
<< " with no main function!\n";
return false; // No main, no instrumentation!
}
unsigned NumFunctions = 0;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
if (!I->isExternal())
++NumFunctions;
const Type *ATy = ArrayType::get(Type::UIntTy, NumFunctions);
GlobalVariable *Counters =
new GlobalVariable(ATy, false, GlobalValue::InternalLinkage,
Constant::getNullValue(ATy), "FuncProfCounters", &M);
ConstantPointerRef *CounterCPR = ConstantPointerRef::get(Counters);
// Instrument all of the functions...
unsigned i = 0;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
if (!I->isExternal())
// Insert counter at the start of the function
IncrementCounterInBlock(I->begin(), i++, CounterCPR);
// Add the initialization call to main.
insertInitializationCall(Main, "llvm_start_func_profiling", Counters);
return true;
}
namespace {
class BlockProfiler : public Pass {
bool run(Module &M);
};
RegisterOpt<BlockProfiler> Y("insert-block-profiling",
"Insert instrumentation for block profiling");
}
bool BlockProfiler::run(Module &M) {
Function *Main = M.getMainFunction();
if (Main == 0) {
std::cerr << "WARNING: cannot insert block profiling into a module"
<< " with no main function!\n";
return false; // No main, no instrumentation!
}
unsigned NumBlocks = 0;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
NumBlocks += I->size();
const Type *ATy = ArrayType::get(Type::UIntTy, NumBlocks);
GlobalVariable *Counters =
new GlobalVariable(ATy, false, GlobalValue::InternalLinkage,
Constant::getNullValue(ATy), "BlockProfCounters", &M);
ConstantPointerRef *CounterCPR = ConstantPointerRef::get(Counters);
// Instrument all of the blocks...
unsigned i = 0;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
for (Function::iterator BB = I->begin(), E = I->end(); BB != E; ++BB)
// Insert counter at the start of the block
IncrementCounterInBlock(BB, i++, CounterCPR);
// Add the initialization call to main.
insertInitializationCall(Main, "llvm_start_block_profiling", Counters);
return true;
}