blob: 5628c3a8110821bf033217a16870c98c40155a60 [file] [log] [blame]
Nick Lewycky93b68b22011-04-12 01:06:09 +00001//===- LineProfiling.cpp - Insert counters for line profiling -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass creates counters for the number of times that the original source
11// lines of code were executed.
12//
13// The lines are found from existing debug info in the LLVM IR. Iterating
14// through LLVM instructions, every time the debug location changes we insert a
15// new counter and instructions to increment the counter there. A global
16// destructor runs to dump the counters out to a file.
17//
18//===----------------------------------------------------------------------===//
19
20#define DEBUG_TYPE "insert-line-profiling"
21
22#include "ProfilingUtils.h"
23#include "llvm/Transforms/Instrumentation.h"
24#include "llvm/Analysis/DebugInfo.h"
25#include "llvm/Module.h"
26#include "llvm/Pass.h"
27#include "llvm/Instructions.h"
28#include "llvm/Support/raw_ostream.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/DebugLoc.h"
31#include "llvm/Support/InstIterator.h"
32#include "llvm/Support/IRBuilder.h"
33#include "llvm/ADT/DenseMap.h"
34#include "llvm/ADT/Statistic.h"
35#include "llvm/ADT/StringExtras.h"
36#include <set>
37#include <string>
38using namespace llvm;
39
40STATISTIC(NumUpdatesInserted, "The # of counter increments inserted.");
41
42namespace {
43 class LineProfiler : public ModulePass {
44 bool runOnModule(Module &M);
45 public:
46 static char ID;
47 LineProfiler() : ModulePass(ID) {
48 initializeLineProfilerPass(*PassRegistry::getPassRegistry());
49 }
50 virtual const char *getPassName() const {
51 return "Line Profiler";
52 }
53
54 private:
55 // Get pointers to the functions in the runtime library.
56 Constant *getStartFileFunc();
57 Constant *getCounterFunc();
58 Constant *getEndFileFunc();
59
60 // Insert an increment of the counter before instruction I.
61 void InsertCounterUpdateBefore(Instruction *I);
62
63 // Add the function to write out all our counters to the global destructor
64 // list.
65 void InsertCounterWriteout();
66
67 // Mapping from the source location to the counter tracking that location.
68 DenseMap<DebugLoc, GlobalVariable *> counters;
69
70 Module *Mod;
71 LLVMContext *Ctx;
72 };
73}
74
75char LineProfiler::ID = 0;
76INITIALIZE_PASS(LineProfiler, "insert-line-profiling",
77 "Insert instrumentation for line profiling", false, false)
78
79ModulePass *llvm::createLineProfilerPass() { return new LineProfiler(); }
80
81bool LineProfiler::runOnModule(Module &M) {
82 Mod = &M;
83 Ctx = &M.getContext();
84
85 DebugLoc last_line; // initializes to unknown
86 bool Changed = false;
87 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
88 for (inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE; ++II) {
89 const DebugLoc &loc = II->getDebugLoc();
90 if (loc.isUnknown()) continue;
91 if (loc == last_line) continue;
92 last_line = loc;
93
94 InsertCounterUpdateBefore(&*II);
95 ++NumUpdatesInserted;
96 Changed = true;
97 }
98 }
99
100 if (Changed) {
101 InsertCounterWriteout();
102 }
103
104 return Changed;
105}
106
107void LineProfiler::InsertCounterUpdateBefore(Instruction *I) {
108 const DebugLoc &loc = I->getDebugLoc();
109 GlobalVariable *&counter = counters[loc];
110 const Type *Int64Ty = Type::getInt64Ty(*Ctx);
111 if (!counter) {
112 counter = new GlobalVariable(*Mod, Int64Ty, false,
113 GlobalValue::InternalLinkage,
114 Constant::getNullValue(Int64Ty),
115 "__llvm_prof_linecov_ctr", 0, false, 0);
116 counter->setVisibility(GlobalVariable::HiddenVisibility);
117 counter->setUnnamedAddr(true);
118 }
119
120 if (isa<PHINode>(I)) {
121 // We may not error out or crash in this case, because a module could put
122 // changing line numbers on phi nodes and still pass the verifier.
123 dbgs() << "Refusing to insert code before phi: " << *I << "\n";
124 I = I->getParent()->getFirstNonPHI();
125 }
126
127 IRBuilder<> builder(I);
128 Value *ctr = builder.CreateLoad(counter);
129 ctr = builder.CreateAdd(ctr, ConstantInt::get(Int64Ty, 1));
130 builder.CreateStore(ctr, counter);
131}
132
133static DISubprogram FindSubprogram(DIScope scope) {
134 while (!scope.isSubprogram()) {
135 assert(scope.isLexicalBlock() &&
136 "Debug location not lexical block or subprogram");
137 scope = DILexicalBlock(scope).getContext();
138 }
139 return DISubprogram(scope);
140}
141
142Constant *LineProfiler::getStartFileFunc() {
143 const Type *Args[1] = { Type::getInt8PtrTy(*Ctx) };
144 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
145 Args, false);
146 return Mod->getOrInsertFunction("llvm_prof_linectr_start_file", FTy);
147}
148
149Constant *LineProfiler::getCounterFunc() {
150 const Type *Args[] = {
151 Type::getInt8PtrTy(*Ctx), // const char *dir
152 Type::getInt8PtrTy(*Ctx), // const char *file
153 Type::getInt32Ty(*Ctx), // uint32_t line
154 Type::getInt32Ty(*Ctx), // uint32_t column
155 Type::getInt64PtrTy(*Ctx), // int64_t *counter
156 };
157 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
158 Args, false);
159 return Mod->getOrInsertFunction("llvm_prof_linectr_emit_counter", FTy);
160}
161
162Constant *LineProfiler::getEndFileFunc() {
163 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
164 return Mod->getOrInsertFunction("llvm_prof_linectr_end_file", FTy);
165}
166
167void LineProfiler::InsertCounterWriteout() {
168 std::set<std::string> compile_units;
169 for (DenseMap<DebugLoc, GlobalVariable *>::iterator I = counters.begin(),
170 E = counters.end(); I != E; ++I) {
171 const DebugLoc &loc = I->first;
172 DISubprogram subprogram(FindSubprogram(DIScope(loc.getScope(*Ctx))));
173 compile_units.insert(subprogram.getCompileUnit().getFilename().str());
174 }
175
176 const FunctionType *WriteoutFTy =
177 FunctionType::get(Type::getVoidTy(*Ctx), false);
178 Function *WriteoutF = Function::Create(WriteoutFTy,
179 GlobalValue::InternalLinkage,
180 "__llvm_prof_linecov_dtor",
181 Mod);
182 WriteoutF->setUnnamedAddr(true);
183 BasicBlock *BB = BasicBlock::Create(*Ctx, "", WriteoutF);
184 IRBuilder<> builder(BB);
185
186 Constant *StartFile = getStartFileFunc();
187 Constant *EmitCounter = getCounterFunc();
188 Constant *EndFile = getEndFileFunc();
189
190 for (std::set<std::string>::const_iterator CUI = compile_units.begin(),
191 CUE = compile_units.end(); CUI != CUE; ++CUI) {
192 builder.CreateCall(StartFile,
193 builder.CreateGlobalStringPtr(*CUI));
194 for (DenseMap<DebugLoc, GlobalVariable *>::iterator I = counters.begin(),
195 E = counters.end(); I != E; ++I) {
196 const DebugLoc &loc = I->first;
197 DISubprogram subprogram(FindSubprogram(DIScope(loc.getScope(*Ctx))));
198 DICompileUnit compileunit(subprogram.getCompileUnit());
199
200 if (compileunit.getFilename() != *CUI)
201 continue;
202
203 Value *Args[] = {
204 builder.CreateGlobalStringPtr(subprogram.getDirectory()),
205 builder.CreateGlobalStringPtr(subprogram.getFilename()),
206 ConstantInt::get(Type::getInt32Ty(*Ctx), loc.getLine()),
207 ConstantInt::get(Type::getInt32Ty(*Ctx), loc.getCol()),
208 I->second
209 };
210 builder.CreateCall(EmitCounter, Args);
211 }
212 builder.CreateCall(EndFile);
213 }
214 builder.CreateRetVoid();
215
216 InsertProfilingShutdownCall(WriteoutF, Mod);
217}