llvm-6502/lib/Transforms/Instrumentation/TraceValues.cpp
Vikram S. Adve bedb00d6dc Handle multiple exit blocks correctly.
Restore string variable cache.
Resurrect code to use formatted printing instead of PrintVal
but leave it turned off for now.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@888 91177308-0d34-0410-b5e6-96231b3b80d8
2001-10-18 13:49:22 +00:00

393 lines
12 KiB
C++

// $Id$
//***************************************************************************
// File:
// TraceValues.cpp
//
// Purpose:
// Support for inserting LLVM code to print values at basic block
// and method exits. Also exports functions to create a call
// "printf" instruction with one of the signatures listed below.
//
// History:
// 10/11/01 - Vikram Adve - Created
//**************************************************************************/
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/GlobalVariable.h"
#include "llvm/ConstPoolVals.h"
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instruction.h"
#include "llvm/iTerminators.h"
#include "llvm/iOther.h"
#include "llvm/BasicBlock.h"
#include "llvm/Method.h"
#include "llvm/Module.h"
#include "llvm/SymbolTable.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/HashExtras.h"
#include <strstream>
#include <hash_map>
//*********************** Internal Data Structures *************************/
const char* const PRINTF = "printf";
//************************** Internal Functions ****************************/
static inline GlobalVariable *
GetStringRef(Module *M, const string &str)
{
static hash_map<string, GlobalVariable*> stringRefCache;
static Module* lastModule = NULL;
if (lastModule != M)
{ // Let's make sure we create separate global references in each module
stringRefCache.clear();
lastModule = M;
}
GlobalVariable* result = stringRefCache[str];
if (result == NULL)
{
ConstPoolArray *Init = ConstPoolArray::get(str);
result = new GlobalVariable(Init->getType(), /*Const*/true, Init);
M->getGlobalList().push_back(result);
stringRefCache[str] = result;
}
return result;
}
static inline bool
TraceThisOpCode(unsigned opCode)
{
// Explicitly test for opCodes *not* to trace so that any new opcodes will
// be traced by default (VoidTy's are already excluded)
//
return (opCode < Instruction::FirstOtherOp &&
opCode != Instruction::Alloca &&
opCode != Instruction::PHINode &&
opCode != Instruction::Cast);
}
static void
FindValuesToTraceInBB(BasicBlock* bb, vector<Value*>& valuesToTraceInBB)
{
for (BasicBlock::iterator II = bb->begin(); II != bb->end(); ++II)
if ((*II)->getType()->isPrimitiveType() &&
(*II)->getType() != Type::VoidTy &&
TraceThisOpCode((*II)->getOpcode()))
{
valuesToTraceInBB.push_back(*II);
}
}
//
// Let's save this code for future use; it has been tested and works:
//
// The signatures of the printf methods supported are:
// int printf(ubyte*, ubyte*, ubyte*, ubyte*, int intValue)
// int printf(ubyte*, ubyte*, ubyte*, ubyte*, unsigned uintValue)
// int printf(ubyte*, ubyte*, ubyte*, ubyte*, float floatValue)
// int printf(ubyte*, ubyte*, ubyte*, ubyte*, double doubleValue)
// int printf(ubyte*, ubyte*, ubyte*, ubyte*, char* stringValue)
// int printf(ubyte*, ubyte*, ubyte*, ubyte*, void* ptrValue)
//
// The invocation should be:
// call "printf"(fmt, bbName, valueName, valueTypeName, value).
//
Method*
GetPrintfMethodForType(Module* module, const Type* valueType)
{
static const int LASTARGINDEX = 4;
static PointerType* ubytePtrTy = NULL;
static vector<const Type*> argTypesVec(LASTARGINDEX + 1);
if (ubytePtrTy == NULL)
{ // create these once since they are invariant
ubytePtrTy = PointerType::get(ArrayType::get(Type::UByteTy));
argTypesVec[0] = ubytePtrTy;
argTypesVec[1] = ubytePtrTy;
argTypesVec[2] = ubytePtrTy;
argTypesVec[3] = ubytePtrTy;
}
SymbolTable* symtab = module->getSymbolTable();
argTypesVec[LASTARGINDEX] = valueType;
MethodType* printMethodTy = MethodType::get(Type::IntTy, argTypesVec,
/*isVarArg*/ false);
Method* printMethod =
cast<Method>(symtab->lookup(PointerType::get(printMethodTy), PRINTF));
if (printMethod == NULL)
{ // Create a new method and add it to the module
printMethod = new Method(printMethodTy, PRINTF);
module->getMethodList().push_back(printMethod);
// Create the argument list for the method so that the full signature
// can be declared. The args can be anonymous.
Method::ArgumentListType &argList = printMethod->getArgumentList();
for (unsigned i=0; i < argTypesVec.size(); ++i)
argList.push_back(new MethodArgument(argTypesVec[i]));
}
return printMethod;
}
Instruction*
CreatePrintfInstr(Value* val,
const BasicBlock* bb,
Module* module,
unsigned int indent,
bool isMethodExit)
{
strstream fmtString, scopeNameString, valNameString;
vector<Value*> paramList;
const Type* valueType = val->getType();
Method* printMethod = GetPrintfMethodForType(module, valueType);
if (! valueType->isPrimitiveType() ||
valueType->getPrimitiveID() == Type::VoidTyID ||
valueType->getPrimitiveID() == Type::TypeTyID ||
valueType->getPrimitiveID() == Type::LabelTyID)
{
assert(0 && "Unsupported type for printing");
return NULL;
}
const Value* scopeToUse = (isMethodExit)? (const Value*) bb->getParent()
: (const Value*) bb;
if (scopeToUse->hasName())
scopeNameString << scopeToUse->getName() << ends;
else
scopeNameString << scopeToUse << ends;
if (val->hasName())
valNameString << val->getName() << ends;
else
valNameString << val << ends;
for (unsigned i=0; i < indent; i++)
fmtString << " ";
fmtString << " At exit of "
<< ((isMethodExit)? "Method " : "BB ")
<< "%s : val %s = %s ";
GlobalVariable* scopeNameVal = GetStringRef(module, scopeNameString.str());
GlobalVariable* valNameVal = GetStringRef(module,valNameString.str());
GlobalVariable* typeNameVal = GetStringRef(module,
val->getType()->getDescription().c_str());
switch(valueType->getPrimitiveID())
{
case Type::BoolTyID:
case Type::UByteTyID: case Type::UShortTyID:
case Type::UIntTyID: case Type::ULongTyID:
case Type::SByteTyID: case Type::ShortTyID:
case Type::IntTyID: case Type::LongTyID:
fmtString << " %d\0A";
break;
case Type::FloatTyID: case Type::DoubleTyID:
fmtString << " %g\0A";
break;
case Type::PointerTyID:
fmtString << " %p\0A";
break;
default:
assert(0 && "Should not get here. Check the IF expression above");
return NULL;
}
fmtString << ends;
GlobalVariable* fmtVal = GetStringRef(module, fmtString.str());
paramList.push_back(fmtVal);
paramList.push_back(scopeNameVal);
paramList.push_back(valNameVal);
paramList.push_back(typeNameVal);
paramList.push_back(val);
free(fmtString.str());
free(scopeNameString.str());
free(valNameString.str());
return new CallInst(printMethod, paramList);
}
// The invocation should be:
// call "printVal"(value).
//
static Value *GetPrintMethodForType(Module *Mod, const Type *VTy) {
MethodType *MTy = MethodType::get(Type::VoidTy, vector<const Type*>(1, VTy),
/*isVarArg*/ false);
SymbolTable *ST = Mod->getSymbolTableSure();
if (Value *V = ST->lookup(PointerType::get(MTy), "printVal"))
return V;
// Create a new method and add it to the module
Method *M = new Method(MTy, "printVal");
Mod->getMethodList().push_back(M);
return M;
}
static void InsertPrintInsts(Value *Val,
BasicBlock::iterator &BBI,
Module *Mod,
unsigned int indent,
bool isMethodExit) {
const Type* ValTy = Val->getType();
BasicBlock *BB = (*BBI)->getParent();
assert(ValTy->isPrimitiveType() &&
ValTy->getPrimitiveID() != Type::VoidTyID &&
ValTy->getPrimitiveID() != Type::TypeTyID &&
ValTy->getPrimitiveID() != Type::LabelTyID &&
"Unsupported type for printing");
const Value* scopeToUse =
isMethodExit ? (const Value*)BB->getParent() : (const Value*)BB;
// Create the marker string...
strstream scopeNameString;
WriteAsOperand(scopeNameString, scopeToUse) << " : ";
WriteAsOperand(scopeNameString, Val) << " = " << ends;
string fmtString(indent, ' ');
fmtString += string(" At exit of") + scopeNameString.str();
free(scopeNameString.str());
// Turn the marker string into a global variable...
GlobalVariable *fmtVal = GetStringRef(Mod, fmtString);
// Insert the first print instruction to print the string flag:
Instruction *I = new CallInst(GetPrintMethodForType(Mod, fmtVal->getType()),
vector<Value*>(1, fmtVal));
BBI = BB->getInstList().insert(BBI, I)+1;
// Insert the next print instruction to print the value:
I = new CallInst(GetPrintMethodForType(Mod, ValTy),
vector<Value*>(1, Val));
BBI = BB->getInstList().insert(BBI, I)+1;
// Print out a newline
fmtVal = GetStringRef(Mod, "\n");
I = new CallInst(GetPrintMethodForType(Mod, fmtVal->getType()),
vector<Value*>(1, fmtVal));
BBI = BB->getInstList().insert(BBI, I)+1;
}
//
// Insert print instructions at the end of the basic block *bb
// for each value in valueVec[]. *bb must postdominate the block
// in which the value is computed; this is not checked here.
//
static void
TraceValuesAtBBExit(const vector<Value*>& valueVec,
BasicBlock* bb,
Module* module,
unsigned int indent,
bool isMethodExit)
{
// Get an iterator to point to the insertion location
//
BasicBlock::InstListType& instList = bb->getInstList();
TerminatorInst* termInst = bb->getTerminator();
BasicBlock::iterator here = instList.end()-1;
assert((*here)->isTerminator());
// Insert a print instruction for each value.
//
for (unsigned i=0, N=valueVec.size(); i < N; i++)
InsertPrintInsts(valueVec[i], here, module, indent, isMethodExit);
}
static void
InsertCodeToShowMethodEntry(BasicBlock* entryBB)
{
}
static void
InsertCodeToShowMethodExit(BasicBlock* exitBB)
{
}
//************************** External Functions ****************************/
bool
InsertTraceCode::doInsertTraceCode(Method *M,
bool traceBasicBlockExits,
bool traceMethodExits)
{
vector<Value*> valuesToTraceInMethod;
Module* module = M->getParent();
BasicBlock* exitBB = NULL;
vector<BasicBlock*> exitBlocks;
if (M->isExternal() ||
(! traceBasicBlockExits && ! traceMethodExits))
return false;
if (traceMethodExits)
{
InsertCodeToShowMethodEntry(M->getEntryNode());
}
for (Method::iterator BI = M->begin(); BI != M->end(); ++BI)
{
BasicBlock* bb = *BI;
bool isExitBlock = false;
vector<Value*> valuesToTraceInBB;
FindValuesToTraceInBB(bb, valuesToTraceInBB);
if (bb->succ_begin() == bb->succ_end())
{ // record this as an exit block
exitBlocks.push_back(bb);
isExitBlock = true;
}
if (traceBasicBlockExits && (!isExitBlock || !traceMethodExits))
TraceValuesAtBBExit(valuesToTraceInBB, bb, module,
/*indent*/ 4, /*isMethodExit*/ false);
if (traceMethodExits) {
valuesToTraceInMethod.insert(valuesToTraceInMethod.end(),
valuesToTraceInBB.begin(),
valuesToTraceInBB.end());
}
}
if (traceMethodExits)
for (unsigned i=0; i < exitBlocks.size(); ++i)
{
TraceValuesAtBBExit(valuesToTraceInMethod, exitBlocks[i], module,
/*indent*/ 0, /*isMethodExit*/ true);
InsertCodeToShowMethodExit(exitBB);
}
return true;
}