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

LLVM新Pass管理器自定义分析供Pass调用的问题排查

问题:LLVM新Pass管理器中自定义Function Analysis的崩溃与断言错误

我正在LLVM新Pass管理器中编写一个Function Analysis,希望让分析结果能被自定义Function Pass和Loop Pass获取。但因为新Pass管理器文档不足,遇到了问题。下面是最简示例代码,目标是让Function Analysis返回整数,供两个Pass打印。

#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/PassManager.h>
#include <llvm/IR/ValueMap.h>
#include <llvm/Pass.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Passes/PassPlugin.h>
#include <llvm/Support/raw_ostream.h>

using namespace llvm;
using namespace std;

class FunctionAnalysis : public AnalysisInfoMixin<FunctionAnalysis> {
public:
    static AnalysisKey Key;

    struct Result {
        bool invalidate(Function& F, const PreservedAnalyses& PA, FunctionAnalysisManager::Invalidator& Inv) {
            outs() << "Invalidating...\n";
            llvm_unreachable("idk what to do here tbh");
            return false;
        }

        int dummy_data;
    };

    Result run(Function& F, FunctionAnalysisManager& AM) {
        outs() << "Function analysis has been run...\n";
        return {.dummy_data = 5};
    }
};
AnalysisKey FunctionAnalysis::Key;

class TestFunctionPass : public PassInfoMixin<TestFunctionPass> {
public:
    PreservedAnalyses run(Function& func, FunctionAnalysisManager& AM) {
        FunctionAnalysis::Result& func_analysis = AM.getResult<FunctionAnalysis>(func);

        outs() << "Result: " << func_analysis.dummy_data << '\n';
        return PreservedAnalyses::all();
    }
};

class TestLoopPass : public PassInfoMixin<TestLoopPass> {
public:
    PreservedAnalyses run(Loop& loop, LoopAnalysisManager& AM, LoopStandardAnalysisResults& res, LPMUpdater& updater) {
        const auto& FAMProxy = AM.getResult<FunctionAnalysisManagerLoopProxy>(loop, res);
        FunctionAnalysis::Result* func_analysis =
            FAMProxy.getCachedResult<FunctionAnalysis>(*loop.getLoopPreheader()->getParent());

        outs() << "Result: " << func_analysis->dummy_data << '\n';
        return PreservedAnalyses::all();
    }
};

//-------------------- Plugin Entry Point --------------------
extern "C" LLVM_ATTRIBUTE_WEAK __attribute__((visibility("default"))) PassPluginLibraryInfo llvmGetPassPluginInfo() {
    return {LLVM_PLUGIN_API_VERSION, "Test", "v0.1", [](PassBuilder& PB) {
                PB.registerPipelineParsingCallback(
                    [](StringRef Name, FunctionPassManager& FPM, ArrayRef<PassBuilder::PipelineElement>) -> bool {
                        if (Name == "test-function-pass") {
                            FPM.addPass(TestFunctionPass());
                            return true;
                        }
                        return false;
                    });

                PB.registerPipelineParsingCallback(
                    [](StringRef Name, LoopPassManager& LPM, ArrayRef<PassBuilder::PipelineElement>) -> bool {
                        if (Name == "test-loop-pass") {
                            LPM.addPass(TestLoopPass());
                            return true;
                        }
                        return false;
                    });

                PB.registerAnalysisRegistrationCallback([](FunctionAnalysisManager& FAM) {
                    FAM.registerPass([]() {
                        outs() << "\nDefinitely registered...\n\n";
                        return FunctionAnalysis();
                    });
                });
            }};
}

执行函数Pass时的崩溃信息

Stack dump:
0.      Program arguments: opt -bugpoint-enable-legacy-pm=1 -load-pass-plugin=build/test.so -passes=test-function-pass,loop(test-loop-pass) build/tests/LICM/provided-pre.bc -o build/tests/BLAH.bc
1.      Running pass "function(TestFunctionPass,loop(TestLoopPass))" on module "build/tests/LICM/provided-pre.bc"
2.      Running pass "TestFunctionPass" on function "test"
 #0 0x00005575d2862c50 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/local/bin/opt+0x2d3ec50)
 #1 0x00005575d286022e SignalHandler(int) Signals.cpp:0:0
 #2 0x00007fe28e3c8520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007fe28dfdf75d llvm::AnalysisManager<llvm::Function>::getResultImpl(llvm::AnalysisKey*, llvm::Function&) (build/test.so+0x42975d)
 #4 0x00007fe28dfdf658 llvm::AnalysisManager<llvm::Function>::getResultImpl(llvm::AnalysisKey*, llvm::Function&) (build/test.so+0x429658)
 #5 0x00007fe28dc7cd84 FunctionAnalysis::Result& llvm::AnalysisManager<llvm::Function>::getResult<FunctionAnalysis>(llvm::Function&) /usr/local/include/llvm/IR/PassManager.h:409:22
 #6 0x00007fe28dc7c09e TestFunctionPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /workspaces/hw3/test.cpp:40:75
...
Segmentation fault (core dumped)

执行循环Pass时的断言错误

opt: /usr/local/include/llvm/IR/PassManager.h:406: ...: Assertion `AnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being queried"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: opt -bugpoint-enable-legacy-pm=1 -load-pass-plugin=build/test.so -passes=test-loop-pass build/tests/LICM/provided-pre.bc -o build/tests/BLAH.bc
1.      Running pass "function(loop(TestLoopPass))" on module "build/tests/LICM/provided-pre.bc"
2.      Running pass "loop(TestLoopPass)" on function "test"
 #0 0x000055e009bfbc50 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/local/bin/opt+0x2d3ec50)
 #1 0x000055e009bf922e SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f2b38df7520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007f2b38e4b9fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #4 0x00007f2b38e4b9fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #5 0x00007f2b38e4b9fc pthread_kill ./nptl/pthread_kill.c:89:10
 #6 0x00007f2b38df7476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #7 0x00007f2b38ddd7f3 abort ./stdlib/abort.c:81:7
 #8 0x00007f2b38ddd71b _nl_load_domain ./intl/loadmsgcat.c:1177:9
 #9 0x00007f2b38deee96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#10 0x00007f2b386abdef llvm::OuterAnalysisManagerProxy<llvm::AnalysisManager<llvm::Function>, llvm::Loop, llvm::LoopStandardAnalysisResults&>::Result& llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>::getResult<llvm::OuterAnalysisManagerProxy<llvm::AnalysisManager<llvm::Function>, llvm::Loop, llvm::LoopStandardAnalysisResults&>>(llvm::Loop&, llvm::LoopStandardAnalysisResults&) /usr/local/include/llvm/IR/PassManager.h:409:22
#11 0x00007f2b386ab14c TestLoopPass::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) /workspaces/hw3/test.cpp:50:72
...

错误原因与修复方案

1. Analysis的invalidate方法错误

你的Result::invalidate方法中调用了llvm_unreachable,这会直接触发程序崩溃。正确的逻辑应该是判断当前分析是否被保留:如果分析的Key在PreservedAnalyses中,则不需要失效,返回false;否则返回true。修改后的方法:

bool invalidate(Function& F, const PreservedAnalyses& PA, FunctionAnalysisManager::Invalidator& Inv) {
  return !PA.preserved(FunctionAnalysis::Key);
}

2. Loop Pass中获取分析结果的方式错误

getCachedResult只会返回已经缓存的分析结果,如果分析还没运行,会返回nullptr,直接访问会导致空指针崩溃。应该通过FAM代理获取FunctionAnalysisManager,再调用getResult确保分析被执行:

PreservedAnalyses run(Loop& loop, LoopAnalysisManager& AM, LoopStandardAnalysisResults& res, LPMUpdater& updater) {
  auto& FAMProxy = AM.getResult<FunctionAnalysisManagerLoopProxy>(loop, res);
  Function& F = *loop.getLoopPreheader()->getParent();
  // 获取FAM并调用getResult确保分析运行
  FunctionAnalysis::Result& func_analysis = FAMProxy.getManager().getResult<FunctionAnalysis>(F);

  outs() << "Result: " << func_analysis.dummy_data << '\n';
  return PreservedAnalyses::all();
}

3. 命令行参数冲突

你使用了-bugpoint-enable-legacy-pm=1,这会强制启用旧Pass管理器,而你的代码是针对新Pass管理器编写的。去掉该参数,使用纯新PM的执行命令:

opt -load-pass-plugin=build/test.so -passes="test-function-pass,loop(test-loop-pass)" build/tests/LICM/provided-pre.bc -o build/tests/BLAH.bc

4. 确保分析代理的正确注册

虽然PassBuilder会自动处理大部分代理注册,但如果遇到Loop Pass无法获取FAM的情况,可以手动在PassBuilder回调中注册Loop到Function的分析代理:

PB.registerLoopAnalyses([](LoopAnalysisManager& LAM, FunctionAnalysisManager& FAM) {
  LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
});

修改后的完整代码

#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/PassManager.h>
#include <llvm/IR/ValueMap.h>
#include <llvm/Pass.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Passes/PassPlugin.h>
#include <llvm/Support/raw_ostream.h>

using namespace llvm;

class FunctionAnalysis : public AnalysisInfoMixin<FunctionAnalysis> {
public:
    static AnalysisKey Key;

    struct Result {
        bool invalidate(Function& F, const PreservedAnalyses& PA, FunctionAnalysisManager::Invalidator& Inv) {
            return !PA.preserved(FunctionAnalysis::Key);
        }

        int dummy_data;
    };

    Result run(Function& F, FunctionAnalysisManager& AM) {
        outs() << "Function analysis has been run...\n";
        return {.dummy_data = 5};
    }
};
AnalysisKey FunctionAnalysis::Key;

class TestFunctionPass : public PassInfoMixin<TestFunctionPass> {
public:
    PreservedAnalyses run(Function& func, FunctionAnalysisManager& AM) {
        FunctionAnalysis::Result& func_analysis = AM.getResult<FunctionAnalysis>(func);

        outs() << "Result from Function Pass: " << func_analysis.dummy_data << '\n';
        return PreservedAnalyses::all();
    }
};

class TestLoopPass : public PassInfoMixin<TestLoopPass> {
public:
    PreservedAnalyses run(Loop& loop, LoopAnalysisManager& AM, LoopStandardAnalysisResults& res, LPMUpdater& updater) {
        auto& FAMProxy = AM.getResult<FunctionAnalysisManagerLoopProxy>(loop, res);
        Function& F = *loop.getLoopPreheader()->getParent();
        FunctionAnalysis::Result& func_analysis = FAMProxy.getManager().getResult<FunctionAnalysis>(F);

        outs() << "Result from Loop Pass: " << func_analysis.dummy_data << '\n';
        return PreservedAnalyses::all();
    }
};

//-------------------- Plugin Entry Point --------------------
extern "C" LLVM_ATTRIBUTE_WEAK __attribute__((visibility("default"))) PassPluginLibraryInfo llvmGetPassPluginInfo() {
    return {LLVM_PLUGIN_API_VERSION, "Test", "v0.1", [](PassBuilder& PB) {
                PB.registerPipelineParsingCallback(
                    [](StringRef Name, FunctionPassManager& FPM, ArrayRef<PassBuilder::PipelineElement>) -> bool {
                        if (Name == "test-function-pass") {
                            FPM.addPass(TestFunctionPass());
                            return true;
                        }
                        return false;
                    });

                PB.registerPipelineParsingCallback(
                    [](StringRef Name, LoopPassManager& LPM, ArrayRef<PassBuilder::PipelineElement>) -> bool {
                        if (Name == "test-loop-pass") {
                            LPM.addPass(TestLoopPass());
                            return true;
                        }
                        return false;
                    });

                PB.registerAnalysisRegistrationCallback([](FunctionAnalysisManager& FAM) {
                    FAM.registerPass([]() {
                        return FunctionAnalysis();
                    });
                });

                // 手动注册Loop到Function的分析代理(可选,部分LLVM版本可能需要)
                PB.registerLoopAnalyses([](LoopAnalysisManager& LAM, FunctionAnalysisManager& FAM) {
                    LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
                });
            }};
}

内容的提问来源于stack exchange,提问作者Otto von Bisquick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:40:54