Skip to content

Commit

Permalink
Merge pull request #1845 from LemonBoy/instr
Browse files Browse the repository at this point in the history
Implement -finstrument-functions.
  • Loading branch information
kinke authored Nov 7, 2016
2 parents 0833c9b + 596fc82 commit e154826
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 0 deletions.
5 changes: 5 additions & 0 deletions driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,11 @@ cl::opt<std::string> usefileInstrProf(
cl::ValueRequired);
#endif

cl::opt<bool>
instrumentFunctions("finstrument-functions",
cl::desc("Instrument function entry and exit with "
"GCC-compatible profiling calls"));

static cl::extrahelp footer(
"\n"
"-d-debug can also be specified without options, in which case it enables "
Expand Down
1 change: 1 addition & 0 deletions driver/cl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ extern cl::opt<unsigned, true> nestedTemplateDepth;
extern cl::opt<std::string> genfileInstrProf;
extern cl::opt<std::string> usefileInstrProf;
#endif
extern cl::opt<bool> instrumentFunctions;

// Arguments to -d-debug
extern std::vector<std::string> debugArgs;
Expand Down
4 changes: 4 additions & 0 deletions gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,8 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
// debug info - after all allocas, but before any llvm.dbg.declare etc
gIR->DBuilder.EmitFuncStart(fd);

emitInstrumentationFnEnter(fd);

// this hack makes sure the frame pointer elimination optimization is
// disabled.
// this this eliminates a bunch of inline asm related issues.
Expand Down Expand Up @@ -1077,6 +1079,8 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
// llvm requires all basic blocks to end with a TerminatorInst but DMD does
// not put a return statement in automatically, so we do it here.

emitInstrumentationFnLeave(fd);

// pass the previous block into this block
gIR->DBuilder.EmitStopPoint(fd->endloc);
if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
Expand Down
36 changes: 36 additions & 0 deletions gen/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "ir/irfunction.h"
#include "ir/irtype.h"
#include "ir/irtypefunction.h"
#include "driver/cl_options.h"
#include "ldcbindings.h"
#include "mars.h"
#include "module.h"
Expand Down Expand Up @@ -329,6 +330,16 @@ static void buildRuntimeModule() {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

// void __cyg_profile_func_enter(void *callee, void *caller)
// void __cyg_profile_func_exit(void *callee, void *caller)
createFwdDecl(LINKc, voidTy,
{"__cyg_profile_func_exit", "__cyg_profile_func_enter"},
{voidPtrTy, voidPtrTy}, {}, Attr_NoUnwind);

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

// void _d_assert(string file, uint line)
// void _d_arraybounds(string file, uint line)
createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"},
Expand Down Expand Up @@ -739,3 +750,28 @@ static void buildRuntimeModule() {
}
}
}

static void emitInstrumentationFn(const char *name) {
LLFunction *fn = getRuntimeFunction(Loc(), gIR->module, name);

// Grab the address of the calling function
auto *caller =
gIR->ir->CreateCall(GET_INTRINSIC_DECL(returnaddress), DtoConstInt(1));
auto callee = DtoBitCast(gIR->topfunc(), getVoidPtrType());

#if LDC_LLVM_VER >= 307
gIR->ir->CreateCall(fn, {callee, caller});
#else
gIR->ir->CreateCall2(fn, callee, caller);
#endif
}

void emitInstrumentationFnEnter(FuncDeclaration *decl) {
if (opts::instrumentFunctions && decl->emitInstrumentation)
emitInstrumentationFn("__cyg_profile_func_enter");
}

void emitInstrumentationFnLeave(FuncDeclaration *decl) {
if (opts::instrumentFunctions && decl->emitInstrumentation)
emitInstrumentationFn("__cyg_profile_func_exit");
}
4 changes: 4 additions & 0 deletions gen/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Module;
}

struct Loc;
struct FuncDeclaration;

// D runtime support helpers
bool initRuntime();
Expand All @@ -32,4 +33,7 @@ llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
llvm::GlobalVariable *
getRuntimeGlobal(const Loc &loc, llvm::Module &target, const char *name);

void emitInstrumentationFnEnter(FuncDeclaration *decl);
void emitInstrumentationFnLeave(FuncDeclaration *decl);

#endif // LDC_GEN_RUNTIME_H
2 changes: 2 additions & 0 deletions gen/statements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ class ToIRVisitor : public Visitor {
FuncDeclaration *const fd = f->decl;
LLFunction *const llFunc = f->func;

emitInstrumentationFnLeave(fd);

// is there a return value expression?
if (stmt->exp || (!stmt->exp && (llFunc == irs->mainFunc))) {
// if the function's return type is void, it uses sret
Expand Down
29 changes: 29 additions & 0 deletions tests/codegen/instrumentation.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %ldc -c -output-ll -finstrument-functions -of=%t.ll %s && FileCheck %s < %t.ll

void fun0 () {
// CHECK-LABEL: define{{.*}} @{{.*}}4fun0FZv
// CHECK: call void @__cyg_profile_func_enter
// CHECK: call void @__cyg_profile_func_exit
// CHECK-NEXT: ret
return;
}

pragma(LDC_profile_instr, false)
int fun1 (int x) {
// CHECK-LABEL: define{{.*}} @{{.*}}4fun1FiZi
// CHECK-NOT: call void @__cyg_profile_func_enter
// CHECK-NOT: call void @__cyg_profile_func_exit
return 42;
}

bool fun2 (int x) {
// CHECK-LABEL: define{{.*}} @{{.*}}4fun2FiZb
if (x < 10)
// CHECK: call void @__cyg_profile_func_exit
// CHECK-NEXT: ret
return true;

// CHECK: call void @__cyg_profile_func_exit
// CHECK-NEXT: ret
return false;
}

0 comments on commit e154826

Please sign in to comment.