From df1892fee24fe1f051c77df196ae14d3e24afaf3 Mon Sep 17 00:00:00 2001 From: "Vikram S. Adve" Date: Sun, 14 Oct 2001 23:18:45 +0000 Subject: [PATCH] Insert code to trace values at basic block and method exits. Current version does not check for liveness. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@800 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Instrumentation/Makefile | 6 + .../Instrumentation/TraceValues.cpp | 374 ++++++++++++++++++ 2 files changed, 380 insertions(+) create mode 100644 lib/Transforms/Instrumentation/Makefile create mode 100644 lib/Transforms/Instrumentation/TraceValues.cpp diff --git a/lib/Transforms/Instrumentation/Makefile b/lib/Transforms/Instrumentation/Makefile new file mode 100644 index 00000000000..0fb7198858a --- /dev/null +++ b/lib/Transforms/Instrumentation/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../.. + +LIBRARYNAME = instrument + +include $(LEVEL)/Makefile.common + diff --git a/lib/Transforms/Instrumentation/TraceValues.cpp b/lib/Transforms/Instrumentation/TraceValues.cpp new file mode 100644 index 00000000000..0c14e60ce3b --- /dev/null +++ b/lib/Transforms/Instrumentation/TraceValues.cpp @@ -0,0 +1,374 @@ +// $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/Support/HashExtras.h" +#include +#include +#include + + +//*********************** Internal Data Structures *************************/ + +const char* const PRINTF = "printf"; + +#undef DONT_EMBED_STRINGS_IN_FMT + + +//************************** Internal Functions ****************************/ + +#undef USE_PTRREF +#ifdef USE_PTRREF +inline ConstPoolPointerReference* +GetStringRef(Module* module, const char* str) +{ + static hash_map stringRefCache; + static Module* lastModule = NULL; + + if (lastModule != module) + { // Let's make sure we create separate global references in each module + stringRefCache.clear(); + lastModule = module; + } + + ConstPoolPointerReference* result = stringRefCache[str]; + if (result == NULL) + { + ConstPoolArray* charArray = ConstPoolArray::get(str); + GlobalVariable* stringVar = + new GlobalVariable(charArray->getType(),/*isConst*/true,charArray,str); + module->getGlobalList().push_back(stringVar); + result = ConstPoolPointerReference::get(stringVar); + assert(result && "Failed to create reference to string constant"); + stringRefCache[str] = result; + } + + return result; +} +#endif USE_PTRREF + +inline GlobalVariable* +GetStringRef(Module* module, const char* str) +{ + static hash_map stringRefCache; + static Module* lastModule = NULL; + + if (lastModule != module) + { // Let's make sure we create separate global references in each module + stringRefCache.clear(); + lastModule = module; + } + + GlobalVariable* result = stringRefCache[str]; + if (result == NULL) + { + ConstPoolArray* charArray = ConstPoolArray::get(str); + GlobalVariable* stringVar = + new GlobalVariable(charArray->getType(),/*isConst*/true,charArray); + module->getGlobalList().push_back(stringVar); + result = stringVar; + // result = ConstPoolPointerReference::get(stringVar); + assert(result && "Failed to create reference to string constant"); + stringRefCache[str] = result; + } + + return result; +} + + +inline bool +TraceThisOpCode(unsigned opCode) +{ + // Explicitly test for opCodes *not* to trace so that any new opcodes will + // be traced by default (or will fail in a later assertion on VoidTy) + // + return (opCode < Instruction::FirstOtherOp && + opCode != Instruction::Ret && + opCode != Instruction::Br && + opCode != Instruction::Switch && + opCode != Instruction::Free && + opCode != Instruction::Alloca && + opCode != Instruction::Store && + opCode != Instruction::PHINode && + opCode != Instruction::Cast); +} + + +static void +FindValuesToTraceInBB(BasicBlock* bb, + vector& valuesToTraceInBB) +{ + for (BasicBlock::iterator II = bb->begin(); II != bb->end(); ++II) + if ((*II)->getType()->isPrimitiveType() && + TraceThisOpCode((*II)->getOpcode())) + { + valuesToTraceInBB.push_back(*II); + } +} + + +// +// 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& 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::InstListType::iterator here = instList.end(); + while ((*here) != termInst && here != instList.begin()) + --here; + assert((*here) == termInst); + + // Insert a print instruction for each value. + // + for (unsigned i=0, N=valueVec.size(); i < N; i++) + { + Instruction* traceInstr = + CreatePrintInstr(valueVec[i], bb, module, indent, isMethodExit); + here = instList.insert(here, traceInstr); + } +} + +void +InsertCodeToShowMethodEntry(BasicBlock* entryBB) +{ +} + +void +InsertCodeToShowMethodExit(BasicBlock* exitBB) +{ +} + + +//************************** External Functions ****************************/ + +// +// The signatures of the print 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* +GetPrintMethodForType(Module* module, const Type* valueType) +{ +#ifdef DONT_EMBED_STRINGS_IN_FMT + static const int LASTARGINDEX = 4; +#else + static const int LASTARGINDEX = 1; +#endif + static PointerType* ubytePtrTy = NULL; + static vector argTypesVec(LASTARGINDEX + 1); + + if (ubytePtrTy == NULL) + { // create these once since they are invariant + ubytePtrTy = PointerType::get(ArrayType::get(Type::UByteTy)); + argTypesVec[0] = ubytePtrTy; +#ifdef DONT_EMBED_STRINGS_IN_FMT + argTypesVec[1] = ubytePtrTy; + argTypesVec[2] = ubytePtrTy; + argTypesVec[3] = ubytePtrTy; +#endif DONT_EMBED_STRINGS_IN_FMT + } + + SymbolTable* symtab = module->getSymbolTable(); + argTypesVec[LASTARGINDEX] = valueType; + MethodType* printMethodTy = MethodType::get(Type::IntTy, argTypesVec, + /*isVarArg*/ false); + + Method* printMethod = + cast(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* +CreatePrintInstr(Value* val, + const BasicBlock* bb, + Module* module, + unsigned int indent, + bool isMethodExit) +{ + strstream fmtString, scopeNameString, valNameString; + vector paramList; + const Type* valueType = val->getType(); + Method* printMethod = GetPrintMethodForType(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 << " "; + +#undef DONT_EMBED_STRINGS_IN_FMT +#ifdef DONT_EMBED_STRINGS_IN_FMT + 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()); +#else + fmtString << " At exit of " + << ((isMethodExit)? "Method " : "BB ") + << scopeNameString.str() << " : " + << valNameString.str() << " = " + << val->getType()->getDescription().c_str(); +#endif DONT_EMBED_STRINGS_IN_FMT + + 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()); + +#ifdef DONT_EMBED_STRINGS_IN_FMT + paramList.push_back(fmtVal); + paramList.push_back(scopeNameVal); + paramList.push_back(valNameVal); + paramList.push_back(typeNameVal); + paramList.push_back(val); +#else + paramList.push_back(fmtVal); + paramList.push_back(val); +#endif DONT_EMBED_STRINGS_IN_FMT + + free(fmtString.str()); + free(scopeNameString.str()); + free(valNameString.str()); + + return new CallInst(printMethod, paramList); +} + + +void +InsertCodeToTraceValues(Method* method, + bool traceBasicBlockExits, + bool traceMethodExits) +{ + vector valuesToTraceInMethod; + Module* module = method->getParent(); + BasicBlock* exitBB = NULL; + + if (method->isExternal() || + (! traceBasicBlockExits && ! traceMethodExits)) + return; + + if (traceMethodExits) + { + InsertCodeToShowMethodEntry(method->getEntryNode()); + exitBB = method->getExitNode(); + } + + for (Method::iterator BI = method->begin(); BI != method->end(); ++BI) + { + BasicBlock* bb = *BI; + vector valuesToTraceInBB; + FindValuesToTraceInBB(bb, valuesToTraceInBB); + + if (traceBasicBlockExits && bb != exitBB) + TraceValuesAtBBExit(valuesToTraceInBB, bb, module, + /*indent*/ 4, /*isMethodExit*/ false); + + if (traceMethodExits) + valuesToTraceInMethod.insert(valuesToTraceInMethod.end(), + valuesToTraceInBB.begin(), + valuesToTraceInBB.end()); + } + + if (traceMethodExits) + { + TraceValuesAtBBExit(valuesToTraceInMethod, exitBB, module, + /*indent*/ 0, /*isMethodExit*/ true); + InsertCodeToShowMethodExit(exitBB); + } +}