Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement -finstrument-functions. #1845

Merged
merged 1 commit into from
Nov 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}