You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LLVM ModulePass开发需求:逐次删除两个测试函数仅保留单个调用

实现LLVM ModulePass:保留单个测试函数调用并移除其他函数

核心目标

你需要的是一个可以选择性保留test1/test2/test3其中一个函数的调用与定义,同时移除另外两个测试函数的ModulePass。我们可以通过命令行参数控制要保留的目标函数,这样每次运行Pass时就能生成仅包含单个测试函数调用的模块。

完整代码实现

#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <vector>

using namespace llvm;

// 命令行参数:指定要保留的测试函数名(默认保留test1)
static cl::opt<std::string> KeepTestFunc("keep-test-func", cl::desc("Specify the test function to keep"), cl::init("test1"));

namespace {
struct KeepSingleTestFuncPass : public ModulePass {
  static char ID;
  KeepSingleTestFuncPass() : ModulePass(ID) {}

  bool runOnModule(Module &M) override {
    // 1. 定义目标测试函数名集合,用于后续匹配
    std::vector<std::string> targetTests = {"test1", "test2", "test3"};
    std::string keepFunc = KeepTestFunc;

    // 校验输入的函数名是否合法
    if (std::find(targetTests.begin(), targetTests.end(), keepFunc) == targetTests.end()) {
      errs() << "Error: Invalid test function name. Must be test1/test2/test3\n";
      return false;
    }

    // 2. 定位main函数
    Function *MainFunc = M.getFunction("main");
    if (!MainFunc) {
      errs() << "Error: No main function found in the module\n";
      return false;
    }

    // 3. 遍历main函数,标记需要移除的非保留测试函数调用
    std::vector<CallInst*> callsToRemove;
    for (BasicBlock &BB : *MainFunc) {
      for (Instruction &I : BB) {
        if (CallInst *CI = dyn_cast<CallInst>(&I)) {
          Function *Callee = CI->getCalledFunction();
          if (Callee && std::find(targetTests.begin(), targetTests.end(), Callee->getName()) != targetTests.end()) {
            if (Callee->getName() != keepFunc) {
              callsToRemove.push_back(CI);
            }
          }
        }
      }
    }

    // 统一移除标记的调用指令(避免遍历中删除导致迭代器失效)
    for (CallInst *CI : callsToRemove) {
      CI->eraseFromParent();
    }

    // 4. 遍历模块函数,标记需要删除的非保留测试函数定义
    std::vector<Function*> funcsToRemove;
    for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
      std::string funcName = F->getName();
      if (std::find(targetTests.begin(), targetTests.end(), funcName) != targetTests.end() && funcName != keepFunc) {
        funcsToRemove.push_back(&*F);
      }
    }

    // 统一删除标记的函数定义
    for (Function *F : funcsToRemove) {
      F->eraseFromParent();
    }

    return true; // 标记模块已被修改
  }
};
} // namespace

char KeepSingleTestFuncPass::ID = 0;
static RegisterPass<KeepSingleTestFuncPass> X("keep-single-test", "Keep only one test function call and definition", false, false);

关键步骤说明

  • 命令行参数控制:通过-keep-test-func参数指定保留的函数,比如运行opt -load ./libKeepSingleTestFuncPass.so -keep-single-test -keep-test-func=test2 input.ll -o output.ll,就能生成仅保留test2调用与定义的IR文件。
  • 避免迭代器失效:不管是处理调用指令还是函数定义,都先把要删除的对象收集到容器中,再统一删除,防止遍历过程中直接修改容器导致迭代器异常。
  • 合法性校验:先检查输入的保留函数名是否在目标集合内,避免无效操作输出错误信息。

使用提示

  • 编译Pass时要确保CMakeLists.txt正确链接LLVM相关依赖库;
  • 若测试函数存在其他依赖(比如被main之外的函数调用),需要额外处理这些依赖关系,当前代码默认只有main调用测试函数。

内容的提问来源于stack exchange,提问作者mikasa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:20:57