Reputation: 494
I'm trying to create an LLVM
pass that would add a call to printf
at the beginning of each function. It works OK with opt
but I cannot manage to have it to run while I'm compiling the target C
which I want to have modified. I think it doesn't work because I did not register my pass
properly. I tried using RegisterStandardPasses
but I cannot make to compile. Please note that I want to use the new PassManager
.
I tried the pass
in this way clang-13 -v -Xclang -load -Xclang ./build/lib/Test.so bc/a.c
So far the code is the following:
#include "Test.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/Debug.h"
#include <sstream>
#include <string>
using namespace llvm;
#define DEBUG_TYPE "test"
char TestPass::ID = 0;
static std::unique_ptr<IRBuilder<>> Builder;
PreservedAnalyses TestPass::run(Module& M, ModuleAnalysisManager& AM)
{
errs() << M.getName() << "\n";
for(Function& F : M) {
runOnFunction(F);
}
return PreservedAnalyses::all();
}
PreservedAnalyses TestPass::runOnFunction(Function& F)
{
if(F.getBasicBlockList().size() > 0) {
IRBuilder<> IRB(&*F.getBasicBlockList().front().getFirstInsertionPt());
std::string var_name = "100";
Function* func_printf = F.getParent()->getFunction("printf");
if(func_printf == nullptr) {
FunctionType* functionType = FunctionType::get(IntegerType::get(F.getParent()->getContext(), 64), true);
func_printf = Function::Create(functionType, GlobalValue::ExternalLinkage, "printf", F.getParent());
func_printf->setCallingConv(CallingConv::C);
}
std::stringstream ss;
ss << "Calling function: " << F.getName().str() << "\n";
Value* str = IRB.CreateGlobalStringPtr(ss.str());
std::vector<Value*> int32_call_params;
int32_call_params.push_back(str);
IRB.CreateCall(func_printf, int32_call_params);
}
return PreservedAnalyses::none();
}
PreservedAnalyses TestPass::runOnGVariable(GlobalVariable& G)
{
outs() << G << "\n";
return PreservedAnalyses::all();
}
bool PipelineParsingCB(StringRef Name, ModulePassManager& MPM, ArrayRef<PassBuilder::PipelineElement>)
{
if(Name == "test") {
MPM.addPass(TestPass());
return true;
}
return false;
}
void RegisterCB(PassBuilder& PB)
{
PB.registerPipelineParsingCallback(PipelineParsingCB);
}
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo()
{
return { LLVM_PLUGIN_API_VERSION, "TEST", "v0.1", RegisterCB };
}
// this causes a compile error
static RegisterStandardPasses Y(
PassManagerBuilder::EP_EarlyAsPossible,
[](const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) { PM.add(new TestPass()); });
The error that I have is the following:
‘RegisterStandardPasses’ does not name a type
88 | static RegisterStandardPasses Y(
expected unqualified-id before ‘)’ token
91 | legacy::PassManagerBase &PM) { PM.add(new SepPass()); });
| ^
Any idea on how to fix it?
Thanks a lot
PS: I saw the question Adding a simple printf in a LLVM pass but it is not exactly what I need.
Upvotes: 1
Views: 1667
Reputation: 333
For those landing here fter the drop of he legacy pass manager, I put an example here
Upvotes: 0