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"
30 #include <strstream.h>
33 //*********************** Internal Data Structures *************************/
35 const char* const PRINTF = "printf";
37 #undef DONT_EMBED_STRINGS_IN_FMT
40 //************************** Internal Functions ****************************/
44 static inline ConstPoolPointerRef*
45 GetStringRef(Module* module, const char* str)
47 static hash_map<string, ConstPoolPointerRef*> stringRefCache;
48 static Module* lastModule = NULL;
50 if (lastModule != module)
51 { // Let's make sure we create separate global references in each module
52 stringRefCache.clear();
56 ConstPoolPointerRef* result = stringRefCache[str];
59 ConstPoolArray* charArray = ConstPoolArray::get(str);
60 GlobalVariable* stringVar =
61 new GlobalVariable(charArray->getType(),/*isConst*/true,charArray,str);
62 module->getGlobalList().push_back(stringVar);
63 result = ConstPoolPointerRef::get(stringVar);
64 assert(result && "Failed to create reference to string constant");
65 stringRefCache[str] = result;
72 static inline GlobalVariable*
73 GetStringRef(Module* module, const char* str)
75 static hash_map<string, GlobalVariable*> stringRefCache;
76 static Module* lastModule = NULL;
78 if (lastModule != module)
79 { // Let's make sure we create separate global references in each module
80 stringRefCache.clear();
84 GlobalVariable* result = stringRefCache[str];
87 ConstPoolArray* charArray = ConstPoolArray::get(str);
88 GlobalVariable* stringVar =
89 new GlobalVariable(charArray->getType(),/*isConst*/true,charArray);
90 module->getGlobalList().push_back(stringVar);
92 // result = ConstPoolPointerRef::get(stringVar);
93 assert(result && "Failed to create reference to string constant");
94 stringRefCache[str] = result;
102 TraceThisOpCode(unsigned opCode)
104 // Explicitly test for opCodes *not* to trace so that any new opcodes will
105 // be traced by default (or will fail in a later assertion on VoidTy)
107 return (opCode < Instruction::FirstOtherOp &&
108 opCode != Instruction::Ret &&
109 opCode != Instruction::Br &&
110 opCode != Instruction::Switch &&
111 opCode != Instruction::Free &&
112 opCode != Instruction::Alloca &&
113 opCode != Instruction::Store &&
114 opCode != Instruction::PHINode &&
115 opCode != Instruction::Cast);
120 FindValuesToTraceInBB(BasicBlock* bb,
121 vector<Value*>& valuesToTraceInBB)
123 for (BasicBlock::iterator II = bb->begin(); II != bb->end(); ++II)
124 if ((*II)->getType()->isPrimitiveType() &&
125 TraceThisOpCode((*II)->getOpcode()))
127 valuesToTraceInBB.push_back(*II);
133 // Insert print instructions at the end of the basic block *bb
134 // for each value in valueVec[]. *bb must postdominate the block
135 // in which the value is computed; this is not checked here.
138 TraceValuesAtBBExit(const vector<Value*>& valueVec,
144 // Get an iterator to point to the insertion location
146 BasicBlock::InstListType& instList = bb->getInstList();
147 TerminatorInst* termInst = bb->getTerminator();
148 BasicBlock::InstListType::iterator here = instList.end();
149 while ((*here) != termInst && here != instList.begin())
151 assert((*here) == termInst);
153 // Insert a print instruction for each value.
155 for (unsigned i=0, N=valueVec.size(); i < N; i++)
157 Instruction* traceInstr =
158 CreatePrintInstr(valueVec[i], bb, module, indent, isMethodExit);
159 here = instList.insert(here, traceInstr);
164 InsertCodeToShowMethodEntry(BasicBlock* entryBB)
169 InsertCodeToShowMethodExit(BasicBlock* exitBB)
174 //************************** External Functions ****************************/
177 // The signatures of the print methods supported are:
178 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, int intValue)
179 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, unsigned uintValue)
180 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, float floatValue)
181 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, double doubleValue)
182 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, char* stringValue)
183 // int printf(ubyte*, ubyte*, ubyte*, ubyte*, void* ptrValue)
185 // The invocation should be:
186 // call "printf"(fmt, bbName, valueName, valueTypeName, value).
189 GetPrintMethodForType(Module* module, const Type* valueType)
191 #ifdef DONT_EMBED_STRINGS_IN_FMT
192 static const int LASTARGINDEX = 4;
194 static const int LASTARGINDEX = 1;
196 static PointerType* ubytePtrTy = NULL;
197 static vector<const Type*> argTypesVec(LASTARGINDEX + 1);
199 if (ubytePtrTy == NULL)
200 { // create these once since they are invariant
201 ubytePtrTy = PointerType::get(ArrayType::get(Type::UByteTy));
202 argTypesVec[0] = ubytePtrTy;
203 #ifdef DONT_EMBED_STRINGS_IN_FMT
204 argTypesVec[1] = ubytePtrTy;
205 argTypesVec[2] = ubytePtrTy;
206 argTypesVec[3] = ubytePtrTy;
207 #endif DONT_EMBED_STRINGS_IN_FMT
210 SymbolTable* symtab = module->getSymbolTable();
211 argTypesVec[LASTARGINDEX] = valueType;
212 MethodType* printMethodTy = MethodType::get(Type::IntTy, argTypesVec,
215 Method* printMethod =
216 cast<Method>(symtab->lookup(PointerType::get(printMethodTy), PRINTF));
217 if (printMethod == NULL)
218 { // Create a new method and add it to the module
219 printMethod = new Method(printMethodTy, PRINTF);
220 module->getMethodList().push_back(printMethod);
222 // Create the argument list for the method so that the full signature
223 // can be declared. The args can be anonymous.
224 Method::ArgumentListType &argList = printMethod->getArgumentList();
225 for (unsigned i=0; i < argTypesVec.size(); ++i)
226 argList.push_back(new MethodArgument(argTypesVec[i]));
234 CreatePrintInstr(Value* val,
235 const BasicBlock* bb,
240 strstream fmtString, scopeNameString, valNameString;
241 vector<Value*> paramList;
242 const Type* valueType = val->getType();
243 Method* printMethod = GetPrintMethodForType(module, valueType);
245 if (! valueType->isPrimitiveType() ||
246 valueType->getPrimitiveID() == Type::VoidTyID ||
247 valueType->getPrimitiveID() == Type::TypeTyID ||
248 valueType->getPrimitiveID() == Type::LabelTyID)
250 assert(0 && "Unsupported type for printing");
254 const Value* scopeToUse = (isMethodExit)? (const Value*) bb->getParent()
256 if (scopeToUse->hasName())
257 scopeNameString << scopeToUse->getName() << ends;
259 scopeNameString << scopeToUse << ends;
262 valNameString << val->getName() << ends;
264 valNameString << val << ends;
266 for (unsigned i=0; i < indent; i++)
269 #undef DONT_EMBED_STRINGS_IN_FMT
270 #ifdef DONT_EMBED_STRINGS_IN_FMT
271 fmtString << " At exit of "
272 << ((isMethodExit)? "Method " : "BB ")
273 << "%s : val %s = %s ";
275 GlobalVariable* scopeNameVal = GetStringRef(module, scopeNameString.str());
276 GlobalVariable* valNameVal = GetStringRef(module,valNameString.str());
277 GlobalVariable* typeNameVal = GetStringRef(module,
278 val->getType()->getDescription().c_str());
280 fmtString << " At exit of "
281 << ((isMethodExit)? "Method " : "BB ")
282 << scopeNameString.str() << " : "
283 << valNameString.str() << " = "
284 << val->getType()->getDescription().c_str();
285 #endif DONT_EMBED_STRINGS_IN_FMT
287 switch(valueType->getPrimitiveID())
290 case Type::UByteTyID: case Type::UShortTyID:
291 case Type::UIntTyID: case Type::ULongTyID:
292 case Type::SByteTyID: case Type::ShortTyID:
293 case Type::IntTyID: case Type::LongTyID:
294 fmtString << " %d\0A";
297 case Type::FloatTyID: case Type::DoubleTyID:
298 fmtString << " %g\0A";
301 case Type::PointerTyID:
302 fmtString << " %p\0A";
306 assert(0 && "Should not get here. Check the IF expression above");
311 GlobalVariable* fmtVal = GetStringRef(module, fmtString.str());
313 #ifdef DONT_EMBED_STRINGS_IN_FMT
314 paramList.push_back(fmtVal);
315 paramList.push_back(scopeNameVal);
316 paramList.push_back(valNameVal);
317 paramList.push_back(typeNameVal);
318 paramList.push_back(val);
320 paramList.push_back(fmtVal);
321 paramList.push_back(val);
322 #endif DONT_EMBED_STRINGS_IN_FMT
324 free(fmtString.str());
325 free(scopeNameString.str());
326 free(valNameString.str());
328 return new CallInst(printMethod, paramList);
333 InsertCodeToTraceValues(Method* method,
334 bool traceBasicBlockExits,
335 bool traceMethodExits)
337 vector<Value*> valuesToTraceInMethod;
338 Module* module = method->getParent();
339 BasicBlock* exitBB = NULL;
341 if (method->isExternal() ||
342 (! traceBasicBlockExits && ! traceMethodExits))
345 if (traceMethodExits)
347 InsertCodeToShowMethodEntry(method->getEntryNode());
349 exitBB = method->getExitNode();
353 for (Method::iterator BI = method->begin(); BI != method->end(); ++BI)
355 BasicBlock* bb = *BI;
356 vector<Value*> valuesToTraceInBB;
357 FindValuesToTraceInBB(bb, valuesToTraceInBB);
359 if (traceBasicBlockExits && bb != exitBB)
360 TraceValuesAtBBExit(valuesToTraceInBB, bb, module,
361 /*indent*/ 4, /*isMethodExit*/ false);
363 if (traceMethodExits)
364 valuesToTraceInMethod.insert(valuesToTraceInMethod.end(),
365 valuesToTraceInBB.begin(),
366 valuesToTraceInBB.end());
369 if (traceMethodExits)
371 TraceValuesAtBBExit(valuesToTraceInMethod, exitBB, module,
372 /*indent*/ 0, /*isMethodExit*/ true);
373 InsertCodeToShowMethodExit(exitBB);