LLVM Pass官方教程会教您如何编译一个相当简单的(Legacy)LLVM Pass,她能够被opt动态加载。但现在你是一个懒惰的家伙,你想自动的在opt
甚至clang
中运行您的Pass。本文提供了将Pass集成到旧版PassManager管道的几种方法之一。然后,我的下一篇文章将讨论如何添加自定义clang
命令行选项以启用自定义功能。
默认情况下,要在Pass管道中运行Pass,我们需要先弄清楚管道是如何构建的。有一个构建器类,PassManagerBuilder
用于构建旧版PassManager以及默认的Pass管道。其中生成器类所在的路径,但是,它有点陌生-它放在include/llvm/Transforms/IPO/PassManagerBuilder.h
和lib/Transform/IPO/PassManagerBuilder.cpp
,而不是我们所熟悉的IR
或PassManager
文件夹。
在PassManagerBuilder
类中,我们可以发现,有许多可以通过名称自我解释的方法,例如,addInstructionCombiningPass
和addFunctionSimplificationPasses
。这些方法可用于向管道添加某些类别的Passes。除了调用他们明确地更新condidate Passes的列表,有在代码中使用了许多地方OptLevel
的地方,即我们熟悉-O1
,-O2
命令行选项,通过他们的优化级别来添加Pass。
让我们先看一下一般的切入点:populateFunctionPassManager
void PassManagerBuilder::populateFunctionPassManager( |
在此之前,我们只知道运行通行证的一种方式:注册它
static RegisterPass <MyPass> X("my-pass", ...); |
并使用 opt命令行选项运行-load=MyPass.so -my-pass
。但是,如果它已经放入源树中,那么每次动态加载和运行Pass 都是很奇怪和没有必要的。
因此,从上面的代码中,我们看到如果Pass已经在LLVM源代码树中,我们需要做的就是创建一个带有一些工厂函数的Pass(例如:createSROAPass)
,并且调用legacy::FunctionPassManager::add(…)
以显式将所需的Pass添加到管道中。
不幸的是,这并没有结束。事实证明,在让你的in-tree Passes全部设置之前,有几个微不足道设置:
- 实现
createXXXPass
函数. - 实现
initializeXXXPassPass
函数/InitializedPasses.h
文件. INITIALIZE_PASS_BEGIN
/END
/DEPENDENCY
code.- 将
initializeXXXPassPass
放到正确的位置. - 实现
LinkAllPasses.h
文件. - 将
createXXXPass
放到正确的位置.
以上列表是我完成这些任务的通常命令,但当然其中没有具体的优先级。让我们自上而下依次来看。
前面提到的第一个项目,它非常简单,通常只需要三行代码来实现:
FunctionPass * llvm :: createMyAwesomePass(){ |
这个过程中,仅仅是创建一个自己的Pass的实例并返回它。请注意,它是llvm
命名空间中的全局静态函数,因此不要忘记前缀llvm::
或只是用它包围它namespace llvm {…}
。
接下来的两项,第二和第三,实际上是相同的 initializeXXXPassPass
功能。此函数将为Pass创建一个内部Pass信息条目,并将其注册到PassManager,单独注册其所需的依赖项。它与RegisterPass<MyPass> X(…)
动态加载的Passes 类似。要实现此功能,首先我们将函数声明放在include/llvm/InitializePasses.h文件中
:
// ...Previous lines...<br>void initializeModuleSummaryIndexWrapperPassPass(PassRegistry&); |
在我们自己的Pass的源代码文件中,添加以下行:
INITIALIZE_PASS_BEGIN(MyAwesomePass, "my-awesome-pass", |
这实际上构建了initializeXXXPassPass
函数的函数体。
现在我们有leinitializeXXXPassPass
和createXXXPass
两个函数。我们接下来需要做的就是将它们放在正确的位置。
我们需要两个地方来调用initializeXXXPassPass
函数。第一个是在Pass类构造函数中:
MyAwesomePass():FunctionPass(ID){ |
第二地方是上层初始化函数。例如,如果您的Pass是分析Pass放在lib/Analysis
文件夹下,那么添加以下行lib/Analysis/Analysis.cpp
:
void llvm::initializeAnalysis(PassRegistry &Registry) { |
如果你是一个放在lib/Transforms/Scalar下的
转换Pass,你要找的文件就是lib/Transforms/Scalar/Scalar.cpp
。
现在让我们关注createXXXPass
。为了防止对这些createXXXPass
符号进行一些积极的链接时间优化,我们需要添加一个假函数调用include/llvm/LinkAllPasses.h
:
struct ForcePassLinking { |
最后,我们将添加一个真正的在PassManagerBuilder中被createXXXPass
调用的函数。您可以添加更复杂的逻辑,以便在某些优化级别或条件下将Pass插入管道,但通常我只是将函数调用放入某处populateXXXPassManager
,这也在前面提到过:
void PassManagerBuilder::populateFunctionPassManager( |
构建Pass管道在PassManager中始终是一个有趣的主题,包括旧版和新版。还有许多其他因素会影响Pass管道的形成。上一节仅提供了在传统PassManager中默认运行Pass的最简单方法。