summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/InitializePasses.h1
-rw-r--r--include/llvm/LinkAllPasses.h1
-rw-r--r--include/llvm/Transforms/Instrumentation.h4
-rw-r--r--lib/Transforms/Instrumentation/Instrumentation.cpp1
-rw-r--r--lib/Transforms/Instrumentation/LineProfiling.cpp217
-rw-r--r--runtime/libprofile/LineProfiling.c37
-rw-r--r--runtime/libprofile/libprofile.exports3
7 files changed, 263 insertions, 1 deletions
diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
index 74687e1ad4..be71898af4 100644
--- a/include/llvm/InitializePasses.h
+++ b/include/llvm/InitializePasses.h
@@ -94,6 +94,7 @@ void initializeDominatorTreePass(PassRegistry&);
void initializeEdgeBundlesPass(PassRegistry&);
void initializeEdgeProfilerPass(PassRegistry&);
void initializePathProfilerPass(PassRegistry&);
+void initializeLineProfilerPass(PassRegistry&);
void initializeEarlyCSEPass(PassRegistry&);
void initializeExpandISelPseudosPass(PassRegistry&);
void initializeFindUsedTypesPass(PassRegistry&);
diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h
index c09c67788d..9c486b0181 100644
--- a/include/llvm/LinkAllPasses.h
+++ b/include/llvm/LinkAllPasses.h
@@ -70,6 +70,7 @@ namespace {
(void) llvm::createEdgeProfilerPass();
(void) llvm::createOptimalEdgeProfilerPass();
(void) llvm::createPathProfilerPass();
+ (void) llvm::createLineProfilerPass();
(void) llvm::createFunctionInliningPass();
(void) llvm::createAlwaysInlinerPass();
(void) llvm::createGlobalDCEPass();
diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h
index aa9873fb8a..d47216dec7 100644
--- a/include/llvm/Transforms/Instrumentation.h
+++ b/include/llvm/Transforms/Instrumentation.h
@@ -17,7 +17,6 @@
namespace llvm {
class ModulePass;
-class FunctionPass;
// Insert edge profiling instrumentation
ModulePass *createEdgeProfilerPass();
@@ -28,6 +27,9 @@ ModulePass *createOptimalEdgeProfilerPass();
// Insert path profiling instrumentation
ModulePass *createPathProfilerPass();
+// Insert line profiling instrumentation
+ModulePass *createLineProfilerPass();
+
} // End llvm namespace
#endif
diff --git a/lib/Transforms/Instrumentation/Instrumentation.cpp b/lib/Transforms/Instrumentation/Instrumentation.cpp
index 96ed4fa5c0..b299bb71a4 100644
--- a/lib/Transforms/Instrumentation/Instrumentation.cpp
+++ b/lib/Transforms/Instrumentation/Instrumentation.cpp
@@ -23,6 +23,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) {
initializeEdgeProfilerPass(Registry);
initializeOptimalEdgeProfilerPass(Registry);
initializePathProfilerPass(Registry);
+ initializeLineProfilerPass(Registry);
}
/// LLVMInitializeInstrumentation - C binding for
diff --git a/lib/Transforms/Instrumentation/LineProfiling.cpp b/lib/Transforms/Instrumentation/LineProfiling.cpp
new file mode 100644
index 0000000000..5628c3a811
--- /dev/null
+++ b/lib/Transforms/Instrumentation/LineProfiling.cpp
@@ -0,0 +1,217 @@
+//===- LineProfiling.cpp - Insert counters for line profiling -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass creates counters for the number of times that the original source
+// lines of code were executed.
+//
+// The lines are found from existing debug info in the LLVM IR. Iterating
+// through LLVM instructions, every time the debug location changes we insert a
+// new counter and instructions to increment the counter there. A global
+// destructor runs to dump the counters out to a file.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "insert-line-profiling"
+
+#include "ProfilingUtils.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Analysis/DebugInfo.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Instructions.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DebugLoc.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include <set>
+#include <string>
+using namespace llvm;
+
+STATISTIC(NumUpdatesInserted, "The # of counter increments inserted.");
+
+namespace {
+ class LineProfiler : public ModulePass {
+ bool runOnModule(Module &M);
+ public:
+ static char ID;
+ LineProfiler() : ModulePass(ID) {
+ initializeLineProfilerPass(*PassRegistry::getPassRegistry());
+ }
+ virtual const char *getPassName() const {
+ return "Line Profiler";
+ }
+
+ private:
+ // Get pointers to the functions in the runtime library.
+ Constant *getStartFileFunc();
+ Constant *getCounterFunc();
+ Constant *getEndFileFunc();
+
+ // Insert an increment of the counter before instruction I.
+ void InsertCounterUpdateBefore(Instruction *I);
+
+ // Add the function to write out all our counters to the global destructor
+ // list.
+ void InsertCounterWriteout();
+
+ // Mapping from the source location to the counter tracking that location.
+ DenseMap<DebugLoc, GlobalVariable *> counters;
+
+ Module *Mod;
+ LLVMContext *Ctx;
+ };
+}
+
+char LineProfiler::ID = 0;
+INITIALIZE_PASS(LineProfiler, "insert-line-profiling",
+ "Insert instrumentation for line profiling", false, false)
+
+ModulePass *llvm::createLineProfilerPass() { return new LineProfiler(); }
+
+bool LineProfiler::runOnModule(Module &M) {
+ Mod = &M;
+ Ctx = &M.getContext();
+
+ DebugLoc last_line; // initializes to unknown
+ bool Changed = false;
+ for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
+ for (inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE; ++II) {
+ const DebugLoc &loc = II->getDebugLoc();
+ if (loc.isUnknown()) continue;
+ if (loc == last_line) continue;
+ last_line = loc;
+
+ InsertCounterUpdateBefore(&*II);
+ ++NumUpdatesInserted;
+ Changed = true;
+ }
+ }
+
+ if (Changed) {
+ InsertCounterWriteout();
+ }
+
+ return Changed;
+}
+
+void LineProfiler::InsertCounterUpdateBefore(Instruction *I) {
+ const DebugLoc &loc = I->getDebugLoc();
+ GlobalVariable *&counter = counters[loc];
+ const Type *Int64Ty = Type::getInt64Ty(*Ctx);
+ if (!counter) {
+ counter = new GlobalVariable(*Mod, Int64Ty, false,
+ GlobalValue::InternalLinkage,
+ Constant::getNullValue(Int64Ty),
+ "__llvm_prof_linecov_ctr", 0, false, 0);
+ counter->setVisibility(GlobalVariable::HiddenVisibility);
+ counter->setUnnamedAddr(true);
+ }
+
+ if (isa<PHINode>(I)) {
+ // We may not error out or crash in this case, because a module could put
+ // changing line numbers on phi nodes and still pass the verifier.
+ dbgs() << "Refusing to insert code before phi: " << *I << "\n";
+ I = I->getParent()->getFirstNonPHI();
+ }
+
+ IRBuilder<> builder(I);
+ Value *ctr = builder.CreateLoad(counter);
+ ctr = builder.CreateAdd(ctr, ConstantInt::get(Int64Ty, 1));
+ builder.CreateStore(ctr, counter);
+}
+
+static DISubprogram FindSubprogram(DIScope scope) {
+ while (!scope.isSubprogram()) {
+ assert(scope.isLexicalBlock() &&
+ "Debug location not lexical block or subprogram");
+ scope = DILexicalBlock(scope).getContext();
+ }
+ return DISubprogram(scope);
+}
+
+Constant *LineProfiler::getStartFileFunc() {
+ const Type *Args[1] = { Type::getInt8PtrTy(*Ctx) };
+ const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
+ Args, false);
+ return Mod->getOrInsertFunction("llvm_prof_linectr_start_file", FTy);
+}
+
+Constant *LineProfiler::getCounterFunc() {
+ const Type *Args[] = {
+ Type::getInt8PtrTy(*Ctx), // const char *dir
+ Type::getInt8PtrTy(*Ctx), // const char *file
+ Type::getInt32Ty(*Ctx), // uint32_t line
+ Type::getInt32Ty(*Ctx), // uint32_t column
+ Type::getInt64PtrTy(*Ctx), // int64_t *counter
+ };
+ const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
+ Args, false);
+ return Mod->getOrInsertFunction("llvm_prof_linectr_emit_counter", FTy);
+}
+
+Constant *LineProfiler::getEndFileFunc() {
+ const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
+ return Mod->getOrInsertFunction("llvm_prof_linectr_end_file", FTy);
+}
+
+void LineProfiler::InsertCounterWriteout() {
+ std::set<std::string> compile_units;
+ for (DenseMap<DebugLoc, GlobalVariable *>::iterator I = counters.begin(),
+ E = counters.end(); I != E; ++I) {
+ const DebugLoc &loc = I->first;
+ DISubprogram subprogram(FindSubprogram(DIScope(loc.getScope(*Ctx))));
+ compile_units.insert(subprogram.getCompileUnit().getFilename().str());
+ }
+
+ const FunctionType *WriteoutFTy =
+ FunctionType::get(Type::getVoidTy(*Ctx), false);
+ Function *WriteoutF = Function::Create(WriteoutFTy,
+ GlobalValue::InternalLinkage,
+ "__llvm_prof_linecov_dtor",
+ Mod);
+ WriteoutF->setUnnamedAddr(true);
+ BasicBlock *BB = BasicBlock::Create(*Ctx, "", WriteoutF);
+ IRBuilder<> builder(BB);
+
+ Constant *StartFile = getStartFileFunc();
+ Constant *EmitCounter = getCounterFunc();
+ Constant *EndFile = getEndFileFunc();
+
+ for (std::set<std::string>::const_iterator CUI = compile_units.begin(),
+ CUE = compile_units.end(); CUI != CUE; ++CUI) {
+ builder.CreateCall(StartFile,
+ builder.CreateGlobalStringPtr(*CUI));
+ for (DenseMap<DebugLoc, GlobalVariable *>::iterator I = counters.begin(),
+ E = counters.end(); I != E; ++I) {
+ const DebugLoc &loc = I->first;
+ DISubprogram subprogram(FindSubprogram(DIScope(loc.getScope(*Ctx))));
+ DICompileUnit compileunit(subprogram.getCompileUnit());
+
+ if (compileunit.getFilename() != *CUI)
+ continue;
+
+ Value *Args[] = {
+ builder.CreateGlobalStringPtr(subprogram.getDirectory()),
+ builder.CreateGlobalStringPtr(subprogram.getFilename()),
+ ConstantInt::get(Type::getInt32Ty(*Ctx), loc.getLine()),
+ ConstantInt::get(Type::getInt32Ty(*Ctx), loc.getCol()),
+ I->second
+ };
+ builder.CreateCall(EmitCounter, Args);
+ }
+ builder.CreateCall(EndFile);
+ }
+ builder.CreateRetVoid();
+
+ InsertProfilingShutdownCall(WriteoutF, Mod);
+}
diff --git a/runtime/libprofile/LineProfiling.c b/runtime/libprofile/LineProfiling.c
new file mode 100644
index 0000000000..6e6fa196be
--- /dev/null
+++ b/runtime/libprofile/LineProfiling.c
@@ -0,0 +1,37 @@
+/*===- LineProfiling.c - Support library for line profiling ---------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the line profiling
+|* instrumentation pass. Link against this library when running code through
+|* the -insert-line-profiling LLVM pass.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+/* A file in this case is a translation unit. Each .o file built with line
+ * profiling enabled will emit to a different file. Only one file may be
+ * started at a time.
+ */
+void llvm_prof_linectr_start_file(const char *orig_filename) {
+ printf("[%s]\n", orig_filename);
+}
+
+/* Emit data about a counter to the data file. */
+void llvm_prof_linectr_emit_counter(const char *dir, const char *file,
+ uint32_t line, uint32_t column,
+ int64_t *counter) {
+ printf("%s/%s:%u:%u %lu\n", dir, file, line, column, *counter);
+}
+
+void llvm_prof_linectr_end_file() {
+ printf("-----\n");
+}
diff --git a/runtime/libprofile/libprofile.exports b/runtime/libprofile/libprofile.exports
index b8057c7aac..fb04ea3480 100644
--- a/runtime/libprofile/libprofile.exports
+++ b/runtime/libprofile/libprofile.exports
@@ -5,3 +5,6 @@ llvm_start_basic_block_tracing
llvm_trace_basic_block
llvm_increment_path_count
llvm_decrement_path_count
+llvm_prof_linectr_start_file
+llvm_prof_linectr_emit_counter
+llvm_prof_linectr_end_file