Skip to content

Commit

Permalink
Implement -finstrument-functions.
Browse files Browse the repository at this point in the history
Closes #1839.
  • Loading branch information
LemonBoy committed Oct 20, 2016
1 parent 86d11c8 commit e0124bf
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 2 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
6 changes: 6 additions & 0 deletions gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
// debug info - after all allocas, but before any llvm.dbg.declare etc
gIR->DBuilder.EmitFuncStart(fd);

if (opts::instrumentFunctions && fd->emitInstrumentation)
emitInstrumentationFn(false);

// 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 @@ -1088,6 +1091,9 @@ 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.

if (opts::instrumentFunctions && fd->emitInstrumentation)
emitInstrumentationFn(true);

// pass the previous block into this block
gIR->DBuilder.EmitStopPoint(fd->endloc);
if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
Expand Down
32 changes: 30 additions & 2 deletions gen/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ static void createFwdDecl(LINK linkage, Type *returntype,
ArrayParam<llvm::StringRef> fnames,
ArrayParam<Type *> paramtypes,
ArrayParam<StorageClass> paramsSTC = {},
AttrSet attribset = AttrSet()) {
AttrSet attribset = AttrSet(),
llvm::Module *module = M) {

Parameters *params = nullptr;
if (!paramtypes.empty()) {
Expand All @@ -244,7 +245,7 @@ static void createFwdDecl(LINK linkage, Type *returntype,

for (auto fname : fnames) {
llvm::Function *fn = llvm::Function::Create(
llfunctype, llvm::GlobalValue::ExternalLinkage, fname, M);
llfunctype, llvm::GlobalValue::ExternalLinkage, fname, module);

fn->setAttributes(attrs);

Expand Down Expand Up @@ -327,6 +328,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});

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

// 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 @@ -736,3 +747,20 @@ static void buildRuntimeModule() {
}
}
}

void emitInstrumentationFn(bool atExit) {
const char *name =
atExit ? "__cyg_profile_func_exit" : "__cyg_profile_func_enter";
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
}
2 changes: 2 additions & 0 deletions gen/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
llvm::GlobalVariable *
getRuntimeGlobal(const Loc &loc, llvm::Module &target, const char *name);

void emitInstrumentationFn(bool atExit);

#endif // LDC_GEN_RUNTIME_H
4 changes: 4 additions & 0 deletions gen/statements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "module.h"
#include "mtype.h"
#include "port.h"
#include "driver/cl_options.h"
#include "gen/abi.h"
#include "gen/arrays.h"
#include "gen/classes.h"
Expand Down Expand Up @@ -134,6 +135,9 @@ class ToIRVisitor : public Visitor {
FuncDeclaration *const fd = f->decl;
LLFunction *const llFunc = f->func;

if (opts::instrumentFunctions && fd->emitInstrumentation)
emitInstrumentationFn(true);

// 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 e0124bf

Please sign in to comment.