PassManager系统是LLVM中最重要的基础架构之一。
经过大约10多年的努力,开发人员决定给她一个新的面目。
新的PassManager Pass背后的基本概念仍然与旧版本相同:通过LLVM IR单元运行Pass,例如,功能来检查内部的IR或甚至修改它,然后将结果IR传递给下一个Pass管道。最大的区别是我们写Pass的方式。
新Pass和新PassManager背后有几种设计理念。我强烈建议读者查看过去LLVM开发者大会的相关讲座。但我不打算详细介绍。本文仅通过简单的HelloNewPM Pass 作为新PassManager系统的预告。让我们亲自动手吧!
通常,编写(遗留)LLVM Pass的教程将首先告诉您编写一个继承其中一个llvm::Pass族的类, 例如llvm::FunctionPass , 然后实现一些必要的方法,比如bool FunctionPass::runOnFunction(Function &F)
在这里你第一步将要做的也是类似的事情:
struct HelloNewPMPass : public PassInfoMixin<HelloNewPMPass> { |
我们任然需要继承父类,但是这次PassInfoMixin类中不包含任何供我们覆盖的虚函数。提供默认实现HelloNewPMPass::name()是它在这里的唯一原因。我们只使用参数类型的run方法,即Function和FunctionAnalysisManager,告诉我们应用的是哪个IR单元。
Run方法,正如它的名字表现的,担任在过去的的FunctionPass::runOnFunction,ModulePass::runOnModule等方法相同的功能,但它不再是虚拟方法,所以这里没有关键字 override。此外,返回类型不同,还有一个额外的FunctionAnalysisManager参数。事实证明,它们都与分析框架相关,前一个用于分析数据失效,后一个用于检索分析结果,这与getAnalysis<…>()传统通过中的方法类似。我们将分析主题留给第二部分。目前,由于我们不打算修改任何IR,我们只需返回PreservedAnalyses::all()告诉框架,运行此Pass后所有分析结果都是一致的。
然后我们添加一些丢失的片段并将一些代码填充到run函数体中….
#include "llvm/IR/PassManager.h" |
你猜怎么着?这就是构建新Pass所需要做的一切!我们只需要注册它。这是骨架代码:
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK |
这与传统Passes中的Pass注册有很大不同的是,我们只是从 llvmGetPassPluginInfo函数返回Pass实体,而不是使用 RegisterPass<...>实例和一些静态Pass注册魔术,这里是return语句之后的花括号将构造一个llvm::PassPluginInfo对象,携带一些传递信息。像HelloNewPMPass是Pass名称,v0.1是Pass版本。最后一个字段是lambda函数,它提供了一个PassBuilder实例。PassBuilder正如其名称所示,用于构建PassManager管道。因此我们将使用它将我们的Pass“插入”管道内的适当位置。
在我们继续之前,让我们看看如何使用该opt工具运行新的PassManager Passes。新的PassManager使用普通字符串来描述Pass管道的外观,而不是使用命令行选项来判断您将要运行哪些传递。例如:
opt -passes =“sroa,instcombine”foo.ll |
它将首先运行SROA,然后运行指令组合器。当然还有一堆其他复杂的语法,但在这里我们只需要知道Pass管道可以通过削减这种文本描述来构造。
所以现在我们的想法是,如果我们可以“拦截”上面的解析过程,那么我们可以在出现某个Pass名称时插入我们的Pass。我们是这样做的:
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK |
(上面省略了一些不相关的代码)
在registerPipelineParsingCallback那里,您可以注册从文本描述中解析通行证名称时调用的回调。在这里,当管道字符串中遇到的传递名称是hello-new-pm-pass时,我们将传递添加到管道。因此,我们可以使用opt类似于下面的命令运行我们的传递:
opt -passes ="hello-new-pm-pass"...... |
最后,这是我们的完整代码:
#include "llvm/IR/PassManager.h" |
要构建此Pass,请使用与构建可加载旧Pass的完全相同的方式。如果您不确定,请参阅官方教程。然后使用以下命令运行pass:
opt -disable-output \ |
在我看来,PassBuilder在新的PassManager系统扮演者核心角色,还有很多我没有涉及的主题。例如,分析管道,管道扩展点和文本管道表示的有趣语法。与往常一样,在进一步发布文档之前,深入了解源代码树始终是了解有关新PassManager的更多信息的最佳方式。