在使用LLVM构建生产质量工具时,大小很重要,既用于分发,也用于在目标系统上运行时调整驻留代码大小。因此,期望选择性地使用一些通道,同时省略其他通道并保持稍后改变配置的灵活性。您希望能够完成所有这些,并向用户提供反馈。这是Pass注册发挥作用的地方。
传递注册的基本机制是MachinePassRegistry类和MachinePassRegistryNode类的子类。
MachinePassRegistry的实例用于维护MachinePassRegistryNode对象列表 。此实例维护列表并向命令行界面传达添加和删除。
MachinePassRegistryNode子类的实例用于维护有关特定传递的信息。此信息包括命令行名称,命令帮助字符串以及用于创建传递实例的函数的地址。这些实例之一的全球静态构造函数注册了相应的MachinePassRegistry,静态的析构函数注销。因此,在工具中静态链接的传递将在启动时注册。动态加载的传递将在加载时注册,并在卸载时注销。
使用现有的注册表
有预定义的注册表来跟踪指令调度(RegisterScheduler)和寄存器分配(RegisterRegAlloc)机器传递。这里我们将描述如何注册寄存器分配器机器Pass。
实现你的寄存器分配器机器通行证。在您的register allocator .cpp文件中添加以下内容:
#include "llvm/CodeGen/RegAllocRegistry.h" |
同样在您的注册器分配器.cpp文件中,以下列形式定义创建者函数:
FunctionPass *createMyRegisterAllocator() { |
请注意,此函数的签名应与RegisterRegAlloc::FunctionPassCtor类型匹配。在同一个文件中添加“安装”声明,格式如下:
static RegisterRegAlloc myRegAlloc("myregalloc", |
请注意,帮助字符串之前的两个空格会在-help查询上产生整洁的结果 。
$ llc -help |
就是这样。用户现在可以自由选择使用-regalloc=myregalloc。除了使用RegisterScheduler类之外,注册指令调度程序是类似的 。请注意,与… RegisterScheduler::FunctionPassCtor有显着差异 RegisterRegAlloc::FunctionPassCtor。
要强制将寄存器分配器加载/链接到 llc / lli工具中,请将创建者函数的全局声明Passes.h添加到并添加“伪”调用行 llvm/Codegen/LinkAllCodegenComponents.h。
创建新的注册表
最简单的入门方法是克隆一个现有的注册表; 我们建议llvm/CodeGen/RegAllocRegistry.h。要修改的关键是类名和FunctionPassCtor类型。
然后你需要声明注册表。示例:如果您的pass注册表是 RegisterMyPasses定义的:
MachinePassRegistry RegisterMyPasses::Registry; |
最后,为你的传递声明命令行选项。例:
cl::opt<RegisterMyPasses::FunctionPassCtor, false, |
这里的命令选项是“ mypass”,createDefaultMyPass默认创建者
在GDB中使用动态加载的Pass
不幸的是,使用GDB和动态加载的传递并不像应该的那样容易。首先,您不能在尚未加载的共享对象中设置断点,其次在共享对象中存在内联函数的问题。以下是使用GDB调试传递的一些建议。
为了便于讨论,我将假设您正在调试由opt调用的转换,尽管此处描述的内容不依赖于此。
在Pass中设置断点
你要做的第一件事是在opt过程中启动gdb:
$ gdb opt |
请注意,opt中包含大量调试信息,因此加载需要时间。耐心点。由于我们尚未在传递中设置断点(共享对象直到运行时才加载),我们必须执行该过程,并在它调用我们的传递之前停止它,但是在它加载了共享对象之后。最简单的方法是设置断点 PassManager::run,然后使用您想要的参数运行该过程:
$ (gdb) break llvm::PassManager::run |
一旦opt停止在PassManager::run方法中,您现在可以在通道中自由设置断点,以便您可以跟踪执行或执行其他标准调试。
杂项问题
一旦掌握了基础知识,GDB就会遇到一些问题,一些有解决方案,一些没有解决方案。
- 内联函数具有伪造的堆栈信息。通常,GDB在获取堆栈跟踪和单步执行内联函数方面做得非常好。但是,当动态加载传递时,它会以某种方式完全失去此功能。我所知道的唯一解决方案是对函数进行去内联(将其从类的主体移动到.cpp文件中)。
- 重新启动程序会破坏断点。按照上述信息后,您已成功获得通行证中的一些断点。接下来你知道,你重新启动程序(即你run再次输入“ ”),然后开始得到关于断点无法设置的错误。我发现“修复”此问题的唯一方法是删除已在传递中设置的断点,运行程序,并在执行停止后重新设置断点PassManager::run。