Alberto
Alberto

Reputation: 494

How to run an LLVM pass with the new PassManager

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

Answers (1)

Igor Stoppa
Igor Stoppa

Reputation: 333

For those landing here fter the drop of he legacy pass manager, I put an example here

Upvotes: 0

Related Questions