#include
#include
#include
#include "llvm/Support/raw_ostream.h"
#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
namespace
{
const char* HOOK_FUNC_PREFIX = "_ly_fun";
const char* HOOK_BEGIN_FUNC = "_ly_fun_b";
const char* HOOK_END_FUNC = "_ly_fun_e";
struct MyPlacementPass : public FunctionPass
{
static char ID;
MyPlacementPass() : FunctionPass(ID){}
bool runOnFunction(Function &F) override{
printf("------------- runOnFunction --------------\n");
// 1.
if (F.getName().startswith(HOOK_FUNC_PREFIX))
return false;
// 2.
Value* beginTime = nullptr;
if (!insert_begin_inst(F, beginTime))
return false;
// 3.
insert_return_inst(F, beginTime);
return false;
}
bool insert_begin_inst(Function &F, Value*& beginTime){
LLVMContext &context = F.getParent()->getContext();
BasicBlock &bb = F.getEntryBlock();
/**
* 1. create begin function
*
* https://bugs.freebsd.org/bugzilla/attachment.cgi?bugid=239175&action=viewall&hide_obsolete=1
* https://bugs.freebsd.org/bugzilla/attachment.cgi?id=206326&action=diff#b/lang/beignet/files/patch-llvm9_sec1
* https://bugs.freebsd.org/bugzilla/attachment.cgi?bugid=239175&action=viewall
*/
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 90
FunctionCallee beginFun = F.getParent()->getOrInsertFunction(
#else
Constant *beginFun = F.getParent()->getOrInsertFunction(
#endif
HOOK_BEGIN_FUNC,
FunctionType::get(Type::getInt64Ty(context), {}, false)
);
// 2. create CallInst(struction)
// Value *beginTime = nullptr;
CallInst *inst = nullptr;
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 90
IRBuilder<> builder(context);
inst = builder.CreateCall(beginFun);
#else
if (Function *fun = dyn_cast(beginFun))
inst = CallInst::Create(fun);
#endif
if (!inst) {
llvm::errs() << "Create First CallInst Failed\n";
return false;
}
// 3. 获取 main() 开始的第一条指令
Instruction *beginInst = dyn_cast(bb.begin());
// 4. insert before inst
inst->insertBefore(beginInst);
beginTime = inst;
return true;
}
void insert_return_inst(Function &F, Value* beginTime)
{
LLVMContext &context = F.getParent()->getContext();
for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
{
BasicBlock &BB = *I;
for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
{
ReturnInst *IST = dyn_cast(I);
if (!IST)
continue;
// end func type
FunctionType *endFuncType = FunctionType::get(
Type::getVoidTy(context),
{Type::getInt8PtrTy(context),Type::getInt64Ty(context)},
false
);
// end func
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 90
FunctionCallee endFunc = BB.getModule()->getOrInsertFunction(
#else
Constant *endFunc = BB.getModule()->getOrInsertFunction(
#endif
HOOK_END_FUNC, endFuncType
);
// end func inst(struction)
IRBuilder<> builder(&BB);
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 90
CallInst* endCI = builder.CreateCall(
#else
CallInst* endCI = CallInst::Create(
#endif
endFunc,
{
builder.CreateGlobalStringPtr(BB.getParent()->getName()),
beginTime
}
);
// insert end func(struction)
endCI->insertBefore(IST);
}
}
}
};
}
char MyPlacementPass::ID = 0;
// Automatically enable the pass.
// http://adriansampson.net/blog/clangpass.html
static void registerSkeletonPass(const PassManagerBuilder &, legacy::PassManagerBase &PM)
{
PM.add(new MyPlacementPass());
}
static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, registerSkeletonPass);
复制代码