如何在 Clang 中自动注册并加载现代 Pass?

Ale*_*hev 14 llvm clang

我正在尝试编写一个简单的“现代”LLVM pass 并将其与 Clang 一起使用。我希望它能够使用如下命令运行: clang -Xclang -load -Xclang libMyPass.so file.cpp

有很多关于如何将遗留通行证集成到 Clang 中的手册。然而,关于新通行证管理器的信息并不多。我看到了一系列名为“2018 年编写 LLVM Pass”的文章。但它只提到了您的密码放置在 LLVM 代码树内的情况。我需要在树外构建模块。

class MyPass : public llvm::PassInfoMixin<MyPass> {
public:
    llvm::PreservedAnalyses run(
        llvm::Function &F,
        llvm::FunctionAnalysisManager &FAM
    ) {
    // Pass code here
    }
};

extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
    return {
        LLVM_PLUGIN_API_VERSION, "MyPass", "v0.1",
        [](llvm::PassBuilder &PB) {
            PB.registerPipelineParsingCallback(
                [](
                    llvm::StringRef Name, llvm::FunctionPassManager &FPM,
                    llvm::ArrayRef <llvm::PassBuilder::PipelineElement>
                ) {
                    if (Name == "my-pass") {
                        FPM.addPass(MyPass());
                        return true;
                    }
                    return false;
                }
            );
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

目前,该通行证尚未执行。我尝试查看 -print-after-all 选项输出并使用std::cout它来检测它是否已运行。我在日志中看不到我的通行证。我也无法在控制台窗口中看到调试输出。

Mag*_*nus 10

两年后,关于这样做的信息仍然很少。我花了一段时间才弄清楚我自己的通行证。

首先,让 clang 使用你的 pass 库:

clang -O1 -fexperimental-new-pass-manager -fpass-plugin=libMyPass.so file.cpp
Run Code Online (Sandbox Code Playgroud)

请注意,-O1标志很重要(我稍后会谈到)。

至于你的通行证,我无法找到强制 clang 使用“解析管道”的方法,因此我们必须使用其他优化器扩展点之一llvm::PassBuilder(几乎所有这些都需要 1 或更高的优化级别,因此-O1)。由于您的 passrun方法采用Function,我们需要一个采用 的扩展点回调FunctionPassManger。我们将使用registerVectorizerStartEPCallback.

class MyPass : public llvm::PassInfoMixin<MyPass> {
public:
    llvm::PreservedAnalyses run(
        llvm::Function &F,
        llvm::FunctionAnalysisManager &FAM
    ) {
    // Pass code here
    }
};

extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
    return {
        LLVM_PLUGIN_API_VERSION, "MyPass", "v0.1",
        [](llvm::PassBuilder &PB) {
            PB.registerVectorizerStartEPCallback(
                [](
                    llvm::FunctionPassManager &FPM,
                    llvm::OptimizationLevel &O
                ) {
                    FPM.addPass(MyPass());
                  }
            );
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

此代码仅在 LLVM 11 中正确。更高版本具有新的PassBuilder扩展点,并删除或重命名了一些旧的扩展点。registerVectorizerStartEPCallback但在 LLVM 13 中仍然存在。

我花了很长时间试图弄清楚是否可以通过构建新的FunctionPassMangager等来强制 clang 使用自定义通道,但似乎没有办法让 clang 使用它。如果您想坚持使用树外传递,优化器扩展点似乎是您唯一的选择。

提示 - 在执行此类操作时,阅读 LLVM 头文件或 grep 查询 clang 源代码树非常有帮助。


小智 5

现在有可能了。

示例插件注册代码:

PassPluginLibraryInfo getPassPluginInfo() {
    const auto callback = [](PassBuilder &PB) {
        PB.registerPipelineEarlySimplificationEPCallback([&](ModulePassManager &MPM, auto) {
            MPM.addPass(MyPass());
            return true;
        });
    };

    return {LLVM_PLUGIN_API_VERSION, "name", "0.0.1", callback};
};

extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
    return getPassPluginInfo();
}
Run Code Online (Sandbox Code Playgroud)

示例 clang 调用代码(假设您将插件构建为共享库):

clang++ -O0 -g -fpass-plugin=pass.so ...
Run Code Online (Sandbox Code Playgroud)