Pass统计

Statistic类被设计成从道次暴露各种成功指标的简单方法。在-stats 命令行上启用命令行选项时,将在运行结束时打印这些统计信息。有关详细信息,请参阅“程序员手册”中的“统计”部分。

PassManager做了什么

PassManager类带着一张pass的列表,确保他们的先决条件 设置是否正确,然后通过调度高效运行。所有运行传递的LLVM工具都使用PassManager来执行这些传递。

PassManager做了两件主要的事情来尝试减少一系列传递的执行时间:

  1. 分享分析结果。PassManager尽可能避免重新计算分析的尝试。这意味着要跟踪哪些分析已经可用,哪些分析失效,以及需要为通过运行哪些分析。工作的一个重要部分是PassManager跟踪所有分析结果的确切生命周期,允许它在不再需要时释放分配给保存分析结果的内存。

  2. 管道程序执行传递。 该PassManager 尝试,以流水线的通行证在一起以获得更好的高速缓存和内存的使用行为进行了一系列的通行证的。这意味着,给定一系列连续的FunctionPass,它将执行所有的FunctionPass中的第一功能,那么所有的 FunctionPasses第二功能,等等……直到整个程序已经通过传递中运行。

    这改进了编译器的缓存行为,因为它一次只触及单个函数的LLVM程序表示,而不是遍历整个程序。它减少了编译器的内存消耗,因为,例如,一次只需要计算一个DominatorSet。这也使得将来可以实现一些 有趣的增强功能。

它的有效性PassManager直接受到它所调度的通行证的信息量的影响。例如,面对未实现的getAnalysisUsage 方法,“保留”集合是故意保守的。如果没有实施,将会产生不允许任何分析结果贯穿执行传递的效果。

PassManager类暴露了一个–debug-pass命令行选项,可用于调试通执行,看到的东西是如何工作的,当你应该保持更多的分析比你目前的诊断是有用的。(要获取有关该–debug-pass选项的所有变体的信息,只需键入“ ”)。opt -help-hidden

例如,通过使用-debug-pass = Structure选项,我们可以看到Hello World传递如何 与其他传递交互。让我们尝试使用gvn和licm传递:

$ opt -load lib/LLVMHello.so -gvn -licm --debug-pass=Structure < hello.bc > /dev/null
ModulePass Manager
FunctionPass Manager
Dominator Tree Construction
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Memory Dependence Analysis
Global Value Numbering
Natural Loop Information
Canonicalize natural loops
Loop-Closed SSA Form Pass
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Scalar Evolution Analysis
Loop Pass Manager
Loop Invariant Code Motion
Module Verifier
Bitcode Writer

此输出显示构建通道的时间。在这里,我们看到GVN使用支配树信息来完成它的工作。LICM传递使用自然循环信息,它也使用支配树。

在LICM传递之后,模块验证程序运行(由opt工具自动添加),它使用支配树来检查生成的LLVM代码是否格式正确。注意,支配树计算一次,并由三遍共享。

让我们看看当我们在两次传递之间运行Hello World传递时这会如何变化:

$ opt -load lib/LLVMHello.so -gvn -hello -licm --debug-pass=Structure < hello.bc > /dev/null
ModulePass Manager
FunctionPass Manager
Dominator Tree Construction
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Memory Dependence Analysis
Global Value Numbering
Hello World Pass
Dominator Tree Construction
Natural Loop Information
Canonicalize natural loops
Loop-Closed SSA Form Pass
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Scalar Evolution Analysis
Loop Pass Manager
Loop Invariant Code Motion
Module Verifier
Bitcode Writer
Hello: __main
Hello: puts
Hello: main

在这里,我们看到Hello World传递已经杀死了Dominator Tree传递,即使它根本不修改代码!要解决这个问题,我们需要在pass中添加以下getAnalysisUsage方法:

// We don't modify the program, so we preserve all analyses
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}

现在当我们运行传递时,我们得到这个输出:

$ opt -load lib/LLVMHello.so -gvn -hello -licm --debug-pass=Structure < hello.bc > /dev/null
Pass Arguments: -gvn -hello -licm
ModulePass Manager
FunctionPass Manager
Dominator Tree Construction
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Memory Dependence Analysis
Global Value Numbering
Hello World Pass
Natural Loop Information
Canonicalize natural loops
Loop-Closed SSA Form Pass
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Scalar Evolution Analysis
Loop Pass Manager
Loop Invariant Code Motion
Module Verifier
Bitcode Writer
Hello: __main
Hello: puts
Hello: main

这表明我们不会意外地使支配者信息无效,因此不必计算两次。

releaseMemory方法

virtual void releaseMemory();

该PassManager自动确定何时计算分析结果,以及如何长时间保持周围他们。因为传递对象本身的生命周期实际上是编译过程的整个持续时间,所以当它们不再有用时,我们需要一些方法来释放分析结果。该 releaseMemory虚拟方法是做到这一点的方式。

如果您正在编写分析或任何其他保留大量状态的传递(供另一个“需要”传递并使用getAnalysis方法的传递),您应该实现releaseMemory,以及释放分配的内存来维护此内部州。在您的传递中run的下一次调用之前,在类的方法之后调用此方法run