VLLM 中的module PASS 和FUN PASS

LLVM Module Pass 与 Function Pass 详解

一、核心区别与作用范围

特性 Module Pass Function Pass
作用粒度 作用于整个编译单元(Module),可访问模块内所有函数、全局变量、元数据等 [[4]] 作用于单个函数(Function),仅能访问当前函数的IR结构 [[2]]
执行顺序 在整个Module级别执行一次 对Module中的每个函数独立执行一次 [[2]]
依赖关系 可请求并使用Function Pass的分析结果(通过getAnalysis接口) [[35]] 不能依赖Module Pass(Legacy PM中存在此限制) [[6]]
行为特性 具有全局视角,可进行跨函数优化、内联决策、全局符号分析等 具有局部可预测性,系统可预期其行为仅影响当前函数 [[2]]

二、典型应用场景

Module Pass 适用场景:

  • 全局优化:函数内联(需分析调用图)、死函数消除
  • 链接时优化(LTO):跨编译单元的符号合并与优化
  • 全局变量初始化分析、模块级元数据处理
  • 构建和维护全局数据结构(如调用图CallGraph)

Function Pass 适用场景:

  • 函数内优化:常量传播、死代码消除、指令组合
  • 基本块级分析:支配树(DominatorTree)、循环识别
  • 局部寄存器分配前的指令调度
  • 函数内特定模式匹配与转换

三、Pass 实现与注册(New Pass Manager)

LLVM 11+ 推荐使用 New Pass Manager(优化管线默认采用),其核心改进是分离Pass与Analysis,支持更灵活的pipeline组合 [[18]]。

1. Function Pass 实现示例
cpp 复制代码
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"

namespace {

struct HelloFunctionPass : public llvm::PassInfoMixin<HelloFunctionPass> {
  llvm::PreservedAnalyses run(llvm::Function &F,
                              llvm::FunctionAnalysisManager &AM) {
    llvm::errs() << "Hello from function: " << F.getName() << "\n";
    return llvm::PreservedAnalyses::none(); // 表示未保留任何分析结果
  }
};

// 静态注册(用于opt工具)
llvm::PassPluginLibraryInfo getHelloFunctionPassPluginInfo() {
  return {
    LLVM_PLUGIN_API_VERSION, "HelloFunctionPass", LLVM_VERSION_STRING,
    [](llvm::PassBuilder &PB) {
      // 注册到默认优化管线的EarlyCSE阶段后
      PB.registerPipelineParsingCallback(
        [](llvm::StringRef Name, llvm::FunctionPassManager &FPM,
           llvm::ArrayRef<llvm::PassBuilder::PipelineElement>) {
          if (Name == "hello-function") {
            FPM.addPass(HelloFunctionPass());
            return true;
          }
          return false;
        });
    }
  };
}

} // namespace

extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
  return getHelloFunctionPassPluginInfo();
}
2. Module Pass 实现示例
cpp 复制代码
struct HelloModulePass : public llvm::PassInfoMixin<HelloModulePass> {
  llvm::PreservedAnalyses run(llvm::Module &M,
                              llvm::ModuleAnalysisManager &AM) {
    llvm::errs() << "Module: " << M.getName() << " has " 
                 << M.size() << " functions\n";
    
    // 可在Module Pass中请求Function级分析
    auto &FAM = AM.getResult<llvm::FunctionAnalysisManagerModuleProxy>(M).getManager();
    for (auto &F : M) {
      if (!F.isDeclaration()) {
        auto &DT = FAM.getResult<llvm::DominatorTreeAnalysis>(F);
        // 使用支配树分析...
      }
    }
    return llvm::PreservedAnalyses::none();
  }
};

四、Pipeline 注册机制

1. 命令行使用(opt工具)
bash 复制代码
# 运行Function Pass(自动包装在ModulePassManager中)
opt -passes='hello-function' input.ll -o output.ll

# 混合Module Pass与Function Pass
# 注意:Function Pass需用module作用域包装
opt -passes='no-op-module,function(hello-function),no-op-module' input.ll

# 显式使用module adaptor包装Function Pass
opt -passes='module(function(hello-function))' input.ll
2. Pipeline 构建层次结构

New Pass Manager 的IR层次为:Module → (CGSCC) → Function → Loop [[31]]

cpp 复制代码
// C++代码中构建pipeline
llvm::PassBuilder PB;
llvm::ModulePassManager MPM;

// 添加Module Pass
MPM.addPass(HelloModulePass());

// 添加Function Pass序列(自动创建FunctionPassManager)
MPM.addPass(llvm::createModuleToFunctionPassAdaptor(
  llvm::FunctionPassManager(
    HelloFunctionPass(),
    AnotherFunctionPass()
  )
));

// 运行pipeline
llvm::ModuleAnalysisManager MAM;
MPM.run(*M, MAM);
3. 注册到Clang默认优化管线
cpp 复制代码
PB.registerOptimizerLastEPCallback(
  [](llvm::ModulePassManager &MPM, llvm::OptimizationLevel Level) {
    if (Level.getSpeedupLevel() >= 2) {
      MPM.addPass(HelloModulePass());
    }
  });

PB.registerPeepholeEPCallback(
  [](llvm::FunctionPassManager &FPM, llvm::OptimizationLevel Level) {
    FPM.addPass(HelloFunctionPass());
  });

五、Legacy Pass Manager 对比(已逐步淘汰)

Legacy PM 使用虚函数接口,注册方式不同:

cpp 复制代码
// Legacy Function Pass
struct LegacyHelloPass : public llvm::FunctionPass {
  static char ID;
  LegacyHelloPass() : FunctionPass(ID) {}
  bool runOnFunction(llvm::Function &F) override {
    llvm::errs() << "Hello: " << F.getName() << "\n";
    return false; // 未修改IR
  }
};
char LegacyHelloPass::ID = 0;
static llvm::RegisterPass<LegacyHelloPass> X("hello", "Hello Pass");

// 使用:opt -load libHello.so -hello input.bc

重要提示:LLVM 16+ 已全面转向New Pass Manager,建议新开发直接采用New PM。代码生成后端(CodeGen)目前仍部分使用Legacy PM [[17]]。

六、关键设计原则

  1. 作用域隔离:Function Pass不应产生跨函数副作用,保证可并行执行
  2. 分析复用:通过AnalysisManager避免重复计算(如多次请求DominatorTree)
  3. Pipeline组合:Module Pass可包含嵌套的FunctionPassManager,实现层次化优化
  4. PreservedAnalyses:精确声明保留的分析结果,避免不必要的重新计算

此设计使LLVM能够灵活组合不同粒度的优化,在保证正确性的同时最大化编译性能。

在使用FUN PASS的时候,如果涉及到整个module 的更改,应将其转换为module PASS

相关推荐
末日汐2 小时前
linux线程
linux·运维
玉梅小洋2 小时前
CentOS :yum源配置及验证指南
linux·运维·centos·yum
沐芊屿2 小时前
华为交换机配置M-LAG
服务器·网络·华为
枷锁—sha2 小时前
【SRC】越权漏洞检测
运维·服务器·网络·安全·网络安全·系统安全
UP_Continue2 小时前
Linux--进程控制
linux·运维·服务器
请输入蚊子2 小时前
«操作系统真像还原» 第二章 编写MBR主引导记录
linux·汇编·操作系统·bochs·操作系统真像还原
188号安全攻城狮3 小时前
【PWN】HappyNewYearCTF_8_ret2csu
linux·汇编·安全·网络安全·系统安全
喵叔哟3 小时前
02-CSharp基础语法快速入门
服务器
Yana.nice4 小时前
openssl将证书从p7b转换为crt格式
java·linux