我正在尝试编写一个简单的“现代”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)