SuperAPI AI 工具集

llvm-passes

编程与开发

查看项目

更新于 10-15 18:15

技能介绍

用途

LLVM Passes 技能用于指导代理编写 LLVM 优化 Pass,基于新 Pass Manager(New Pass Manager)。它覆盖 FunctionPass 与 ModulePass 的结构、PassPluginLibraryInfo 注册、通过 opt -load-pass-plugin 运行、常用分析工具(DominatorTree、LoopInfo、AliasAnalysis)、IR 修改模式、llvm-lit 测试,以及使用 opt -print-after-all 进行调试。

适用场景

  • 为基于 LLVM 的编译器添加自定义优化
  • 编写 IR 变换 Pass(内联、死代码消除、自定义 lowering)
  • 使用支配树或循环信息分析控制流
  • 使用 FileCheck 和 llvm-lit 测试 Pass
  • 调试 Pass 顺序与 IR 损坏
  • 通过插件将 Pass 集成到 Clang

工作流程

1. 新 Pass Manager 架构

opt / clang
├── ModulePassManager
│   └── FunctionPassManager (per function)
│       └── FunctionPass instances
└── AnalysisManager (cached analyses)

Pass 声明其分析使用;IR 变更时分析会失效。

2. 最小 FunctionPass(C++ 插件)

// MyPass.cpp
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {

struct MyPass : PassInfoMixin<MyPass> {
    PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
        bool changed = false;
        for (BasicBlock &BB : F) {
            for (Instruction &I : BB) {
                if (auto *Call = dyn_cast<CallInst>(&I)) {
                    if (Call->getCalledFunction() &&
                        Call->getCalledFunction()->getName() == "dead_func") {
                        Call->eraseFromParent();
                        changed = true;
                    }
                }
            }
        }
        return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
    }
};

} // namespace

extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
    return {
        LLVM_PLUGIN_API_VERSION, "MyPass", "v0.1",
        [](PassBuilder &PB) {
            PB.registerPipelineParsingCallback(
                [](StringRef Name, FunctionPassManager &FPM,
                   ArrayRef<PassBuilder::PipelineElement>) {
                    if (Name == "my-pass") {
                        FPM.addPass(MyPass());
                        return true;
                    }
                    return false;
                });
        }
    };
}
# CMakeLists.txt
find_package(LLVM REQUIRED CONFIG)
add_library(MyPass MODULE MyPass.cpp)
target_include_directories(MyPass SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS})
target_compile_definitions(MyPass PRIVATE ${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs core passes support)
target_link_libraries(MyPass PRIVATE ${llvm_libs})
cmake -B build -DLLVM_DIR=$(llvm-config --cmakedir)
cmake --build build

3. 使用 opt 运行

# Run pass on IR file
opt -load-pass-plugin ./build/MyPass.so -passes=my-pass -S input.ll -o output.ll

# Print IR after each pass
opt -load-pass-plugin ./build/MyPass.so -passes=my-pass -print-after-all input.ll -o /dev/null

# Pass pipeline string
opt -passes="function(instcombine),my-pass,function(dce)" input.ll -S -o out.ll

4. ModulePass 示例

struct MyModulePass : PassInfoMixin<MyModulePass> {
    PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
        for (Function &F : M) {
            if (F.isDeclaration()) continue;
            // module-level transformation
        }
        return PreservedAnalyses::none();
    }
};

在插件回调中注册到 ModulePassManager。

5. 分析工具

#include "llvm/Analysis/DominatorTree.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/AliasAnalysis.h"

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
    auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
    auto &LI = AM.getResult<LoopAnalysis>(F);
    auto &AA = AM.getResult<AAManager>(F);

    for (Loop *L : LI) {
        BasicBlock *Header = L->getHeader();
        // Loop invariant code motion, etc.
    }

    DominatorTreeNode *IDom = DT.getNode(&F.getEntryBlock());
    (void)IDom;
    return PreservedAnalyses::all();
}

声明使用的分析:

AnalysisUsage MyLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<DominatorTreeWrapperPass>();
    AU.addRequired<LoopInfoWrapperPass>();
    return AU;
}

(新 PM:通过 AM.getResult<> 请求分析——依赖自动跟踪。)

6. IR 修改模式

// Insert instruction before iterator
IRBuilder<> Builder(&*I.getIterator());
Value *NewVal = Builder.CreateAdd(I.getOperand(0), ConstantInt::get(I.getType(), 1));
I.replaceAllUsesWith(NewVal);
I.eraseFromParent();

// Clone basic block
BasicBlock *Clone = CloneBasicBlock(OrigBB, VMap, ".clone", &F);

// Create function
FunctionCallee Fn = M.getOrInsertFunction("my_fn",
    FunctionType::get(Builder.getVoidTy(), false));

结构变更后始终更新 SSA 并使分析失效。

7. llvm-lit 测试

test/
├── lit.cfg.py
└── my-pass.test
# my-pass.test
# RUN: opt -load-pass-plugin %shlibdir/MyPass.so -passes=my-pass -S %s | FileCheck %s

define void @test() {
  call void @dead_func()
  ret void
}

; CHECK-NOT: dead_func
llvm-lit test/my-pass.test -v

8. 调试 Pass

# Verify IR after pass
opt -load-pass-plugin ./MyPass.so -passes=my-pass input.ll -o out.ll
opt -verify-each out.ll

# Time passes
opt -passes=my-pass -time-passes input.ll -o /dev/null

# Debug pass manager
OPT_DEBUG=1 opt -passes=my-pass input.ll -o /dev/null

常见问题

症状 原因 修复
Pass not found: my-pass 插件未加载或名称不匹配 检查 registerPipelineParsingCallback 名称
Verify module failed 变换后 SSA 损坏 运行 -verify-each;检查 use-def 链
Analysis stale 修改 IR 但未失效分析 返回 PreservedAnalyses::none()
Plugin load error LLVM 版本不匹配 使用与 opt 相同的 LLVM 构建
Empty opt output 忘记 -S 添加 -S 输出文本 IR
lit test FAIL CHECK 行不匹配 用 opt -S 手动对比

相关技能

  • skills/compilers/llvm — 以用户身份检查 LLVM IR 与 opt 流水线
  • skills/compiler-internals/compiler-frontend — 为 Pass 提供输入的 IR 生成
  • skills/compiler-internals/jit-compilation — 运行优化后 IR 的 ORC JIT
  • skills/compiler-internals/mlir — MLIR Pass(概念类似)
  • skills/compilers/clang — Clang 优化标志
  • skills/build-systems/cmake — 构建 Pass 插件