2 //***************************************************************************
7 // Support for inserting LLVM code to print values at basic block
8 // and method exits. Also exports functions to create a call
9 // "printf" instruction with one of the signatures listed below.
12 // 10/11/01 - Vikram Adve - Created
13 //**************************************************************************/
16 #include "llvm/Transforms/Instrumentation/TraceValues.h"
17 #include "llvm/GlobalVariable.h"
18 #include "llvm/ConstPoolVals.h"
19 #include "llvm/Type.h"
20 #include "llvm/DerivedTypes.h"
21 #include "llvm/Instruction.h"
22 #include "llvm/iTerminators.h"
23 #include "llvm/iOther.h"
24 #include "llvm/BasicBlock.h"
25 #include "llvm/Method.h"
26 #include "llvm/Module.h"
27 #include "llvm/SymbolTable.h"
28 #include "llvm/Support/HashExtras.h"
31 #include <strstream.h>
34 //*********************** Internal Data Structures *************************/
36 const char* const PRINTF = "printf";
38 #undef DONT_EMBED_STRINGS_IN_FMT
41 //************************** Internal Functions ****************************/
45 inline ConstPoolPointerReference*
46 GetStringRef(Module* module, const char* str)
48 static hash_map<string, ConstPoolPointerReference*> stringRefCache;
49 static Module* lastModule = NULL;
51 if (lastModule != module)
52 { // Let's make sure we create separate global references in each module
53 stringRefCache.clear();
57 ConstPoolPointerReference* result = stringRefCache[str];
60 ConstPoolArray* charArray = ConstPoolArray::get(str);
61 GlobalVariable* stringVar =
62 new GlobalVariable(charArray->getType(),/*isConst*/true,charArray,str);
63 module->getGlobalList().push_back(stringVar);
64 result = ConstPoolPointerReference::get(stringVar);
65 assert(result && "Failed to create reference to string constant");
66 stringRefCache[str] = result;
73 inline GlobalVariable*
74 GetStringRef(Module* module, const char* str)
76 static hash_map<string, GlobalVariable*> stringRefCache;
77 static Module* lastModule = NULL;
79 if (lastModule != module)
80 { // Let's make sure we create separate global references in each module
81 stringRefCache.clear();
85 GlobalVariable* result = stringRefCache[str];
88 ConstPoolArray* charArray = ConstPoolArray::get(str);
89 GlobalVariable* stringVar =
90 new GlobalVariable(charArray->getType(),/*isConst*/true,charArray);
91 module->getGlobalList().push_back(stringVar);
93 // result = ConstPoolPointerReference::get(stringVar);
94 assert(result && "Failed to create reference to string constant");
95 stringRefCache[str] = result;
103 TraceThisOpCode(unsigned opCode)
105 // Explicitly test for opCodes *not* to trace so that any new opcodes will
106 // be traced by default (or will fail in a later assertion on VoidTy)
108 return (opCode < Instruction::FirstOtherOp &&
109 opCode != Instruction::Ret &&
110 opCode != Instruction::Br &&
111 opCode != Instruction::Switch &&
112 opCode != Instruction::Free &&
113 opCode != Instruction::Alloca &&
114 opCode != Instruction::Store &&
115 opCode != Instruction::PHINode &&
116 opCode != Instruction::Cast);
121 FindValuesToTraceInBB(BasicBlock* bb,
122 vector<Value*>& valuesToTraceInBB)
124 for (BasicBlock::iterator II = bb->begin(); II != bb->end(); ++II)
125 if ((*II)->getType()->isPrimitiveType() &&
126 TraceThisOpCode((*II)->getOpcode()))
128 valuesToTraceInBB.push_back(*II);
134 // Insert print instructions at the end of the basic block *bb
135 // for each value in valueVec[]. *bb must postdominate the block
136 // in which the value is computed; this is not checked here.
139 TraceValuesAtBBExit(const vector<Value*>& valueVec,
145 // Get an iterator to point to the insertion location
147 BasicBlock::InstListType& instList = bb->getInstList();
148 TerminatorInst* termInst = bb->getTerminator();
149 BasicBlock::InstListType::iterator here = instList.end();
150 while ((*here) != termInst && here != instList.begin())
152 assert((*here) == termInst);
154 // Insert a print instruction for each value.
156 for (unsigned i=0, N=valueVec.size(); i < N; i++)
158 Instruction* traceInstr =
159 CreatePrintInstr(valueVec[i], bb, module, indent, isMethodExit);
160 here = instList.insert(here, traceInstr);
165 InsertCodeToShowMethodEntry(BasicBlock* entryBB)
170 InsertCodeToShowMethodExit(BasicBlock* exitBB)
175 //************************** External Functions ****************************/
178 // The signatures of the print methods supported are:
179 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, int intValue)
180 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, unsigned uintValue)
181 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, float floatValue)
182 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, double doubleValue)
183 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, char* stringValue)
184 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, void* ptrValue)
186 // The invocation should be:
187 // call "printf"(fmt, bbName, valueName, valueTypeName, value).
190 GetPrintMethodForType(Module* module, const Type* valueType)
192 #ifdef DONT_EMBED_STRINGS_IN_FMT
193 static const int LASTARGINDEX = 4;
195 static const int LASTARGINDEX = 1;
197 static PointerType* ubytePtrTy = NULL;
198 static vector<const Type*> argTypesVec(LASTARGINDEX + 1);
200 if (ubytePtrTy == NULL)
201 { // create these once since they are invariant
202 ubytePtrTy = PointerType::get(ArrayType::get(Type::UByteTy));
203 argTypesVec[0] = ubytePtrTy;
204 #ifdef DONT_EMBED_STRINGS_IN_FMT
205 argTypesVec[1] = ubytePtrTy;
206 argTypesVec[2] = ubytePtrTy;
207 argTypesVec[3] = ubytePtrTy;
208 #endif DONT_EMBED_STRINGS_IN_FMT
211 SymbolTable* symtab = module->getSymbolTable();
212 argTypesVec[LASTARGINDEX] = valueType;
213 MethodType* printMethodTy = MethodType::get(Type::IntTy, argTypesVec,
216 Method* printMethod =
217 cast<Method>(symtab->lookup(PointerType::get(printMethodTy), PRINTF));
218 if (printMethod == NULL)
219 { // Create a new method and add it to the module
220 printMethod = new Method(printMethodTy, PRINTF);
221 module->getMethodList().push_back(printMethod);
223 // Create the argument list for the method so that the full signature
224 // can be declared. The args can be anonymous.
225 Method::ArgumentListType &argList = printMethod->getArgumentList();
226 for (unsigned i=0; i < argTypesVec.size(); ++i)
227 argList.push_back(new MethodArgument(argTypesVec[i]));
235 CreatePrintInstr(Value* val,
236 const BasicBlock* bb,
241 strstream fmtString, scopeNameString, valNameString;
242 vector<Value*> paramList;
243 const Type* valueType = val->getType();
244 Method* printMethod = GetPrintMethodForType(module, valueType);
246 if (! valueType->isPrimitiveType() ||
247 valueType->getPrimitiveID() == Type::VoidTyID ||
248 valueType->getPrimitiveID() == Type::TypeTyID ||
249 valueType->getPrimitiveID() == Type::LabelTyID)
251 assert(0 && "Unsupported type for printing");
255 const Value* scopeToUse = (isMethodExit)? (const Value*) bb->getParent()
257 if (scopeToUse->hasName())
258 scopeNameString << scopeToUse->getName() << ends;
260 scopeNameString << scopeToUse << ends;
263 valNameString << val->getName() << ends;
265 valNameString << val << ends;
267 for (unsigned i=0; i < indent; i++)
270 #undef DONT_EMBED_STRINGS_IN_FMT
271 #ifdef DONT_EMBED_STRINGS_IN_FMT
272 fmtString << " At exit of "
273 << ((isMethodExit)? "Method " : "BB ")
274 << "%s : val %s = %s ";
276 GlobalVariable* scopeNameVal = GetStringRef(module, scopeNameString.str());
277 GlobalVariable* valNameVal = GetStringRef(module,valNameString.str());
278 GlobalVariable* typeNameVal = GetStringRef(module,
279 val->getType()->getDescription().c_str());
281 fmtString << " At exit of "
282 << ((isMethodExit)? "Method " : "BB ")
283 << scopeNameString.str() << " : "
284 << valNameString.str() << " = "
285 << val->getType()->getDescription().c_str();
286 #endif DONT_EMBED_STRINGS_IN_FMT
288 switch(valueType->getPrimitiveID())
291 case Type::UByteTyID: case Type::UShortTyID:
292 case Type::UIntTyID: case Type::ULongTyID:
293 case Type::SByteTyID: case Type::ShortTyID:
294 case Type::IntTyID: case Type::LongTyID:
295 fmtString << " %d\0A";
298 case Type::FloatTyID: case Type::DoubleTyID:
299 fmtString << " %g\0A";
302 case Type::PointerTyID:
303 fmtString << " %p\0A";
307 assert(0 && "Should not get here. Check the IF expression above");
312 GlobalVariable* fmtVal = GetStringRef(module, fmtString.str());
314 #ifdef DONT_EMBED_STRINGS_IN_FMT
315 paramList.push_back(fmtVal);
316 paramList.push_back(scopeNameVal);
317 paramList.push_back(valNameVal);
318 paramList.push_back(typeNameVal);
319 paramList.push_back(val);
321 paramList.push_back(fmtVal);
322 paramList.push_back(val);
323 #endif DONT_EMBED_STRINGS_IN_FMT
325 free(fmtString.str());
326 free(scopeNameString.str());
327 free(valNameString.str());
329 return new CallInst(printMethod, paramList);
334 InsertCodeToTraceValues(Method* method,
335 bool traceBasicBlockExits,
336 bool traceMethodExits)
338 vector<Value*> valuesToTraceInMethod;
339 Module* module = method->getParent();
340 BasicBlock* exitBB = NULL;
342 if (method->isExternal() ||
343 (! traceBasicBlockExits && ! traceMethodExits))
346 if (traceMethodExits)
348 InsertCodeToShowMethodEntry(method->getEntryNode());
349 exitBB = method->getExitNode();
352 for (Method::iterator BI = method->begin(); BI != method->end(); ++BI)
354 BasicBlock* bb = *BI;
355 vector<Value*> valuesToTraceInBB;
356 FindValuesToTraceInBB(bb, valuesToTraceInBB);
358 if (traceBasicBlockExits && bb != exitBB)
359 TraceValuesAtBBExit(valuesToTraceInBB, bb, module,
360 /*indent*/ 4, /*isMethodExit*/ false);
362 if (traceMethodExits)
363 valuesToTraceInMethod.insert(valuesToTraceInMethod.end(),
364 valuesToTraceInBB.begin(),
365 valuesToTraceInBB.end());
368 if (traceMethodExits)
370 TraceValuesAtBBExit(valuesToTraceInMethod, exitBB, module,
371 /*indent*/ 0, /*isMethodExit*/ true);
372 InsertCodeToShowMethodExit(exitBB);