llvm pass 编译失败的根本原因有三类:头文件依赖缺失、cmake链接配置错误、ir类型使用不匹配;需优先检查cmakelists.txt中llvm_map_components_to_libnames调用、target_link_libraries顺序及ir合法性。

直接上结论:LLVM Pass 编译失败时,clang++ 报错本身不指向 Pass 逻辑错误,而是暴露了头文件依赖、CMake 链接配置或 IR 类型使用不匹配这三类根本问题。别急着改 Pass 代码,先砍掉干扰项。
检查 CMakeLists.txt 是否漏掉关键依赖项
Pass 编译失败最常见原因是链接时找不到 LLVM 核心库符号,比如报 undefined reference to 'llvm::FunctionPass::createPrinterPass' 或 llvm::errs() 找不到。这不是你写错了,是 CMake 没告诉链接器该连哪些库。
- 必须显式调用
llvm_map_components_to_libnames获取库名,不能硬写LLVMCore这种旧名字;新版本(15+)组件名已重命名,比如LLVMAnalysis→LLVMScalarOpts -
add_library后必须跟target_link_libraries,且顺序不能颠倒:先链LLVMCore,再链LLVMAnalysis、LLVMTransformUtils等你实际用到的模块 - 如果用了
ModulePass或访问DataLayout,还得加LLVMTarget;用了LoopInfo就必须含LLVMScalarOpts
用 opt -load 加载失败时,先验证 IR 输入是否合法
很多“编译通过但 opt -load ./MyPass.so -mypass 段错误或崩溃”,其实是因为传给 Pass 的 .ll 文件本身 IR 格式不合规——比如用了未声明的 intrinsic、类型不匹配的 getelementptr,或者 undef 被误当实值用。LLVM 不会在加载时校验,而是在 Pass 第一次访问某个 Instruction 时才触发断言。
- 先用
llvm-as 验证语法;再用 <code>opt -verify -disable-output test.ll强制做 IR 合法性检查 - 临时在 Pass 构造函数里加
llvm::errs() ,确认 so 文件能被加载;再在 <code>runOnFunction开头打日志,看是卡在加载阶段还是执行阶段 - 用
llc -march=x86-64 test.ll -o /dev/null测试后端兼容性——如果 llc 都报错,说明 IR 本身有问题,Pass 只是第一个撞上的
复现最小化:从 FunctionPass 开始,禁用所有 IR 修改操作
别一上来就写 ModulePass 或尝试重写 Instruction。LLVM Pass 的崩溃往往来自对 IR 的非法修改(比如删掉还在被引用的 Value),而不是编译错误本身。
- 新建一个空
FunctionPass,只保留runOnFunction和getAnalysisUsage,里面什么都不做,只返回false;确保它能编译 +opt -load成功运行 - 逐步加入单行逻辑:先加
for (auto &BB : F),再加for (auto &I : BB),每加一行就重新编译测试;一旦失败,问题就定位在这行对 IR 的访问方式上 - 避免直接调用
I.eraseFromParent()或Builder.CreateCall(...);先用llvm::errs() 打印,确认类型和上下文再动手
真正难缠的不是编译报错,而是 Pass 在某些特定 IR 结构下静默崩溃——比如遇到 invoke 指令却没处理异常路径,或遍历 PHINode 时没调用 getIncomingValue。这类问题只能靠最小化输入 + 分步注入逻辑来暴露,指望编译器报错是徒劳的。











