指令选择

此 Pass 将通用机器指令转换为等效的目标特定指令。它自下而上遍历 MachineFunction,在定义之前选择使用,从而实现简单的死代码消除。

API:InstructionSelector

目标实现 InstructionSelector 类,其中包含目标特定的选择逻辑本身。

该实例由子目标提供,以便它可以通过子目标特性(例如,使用向量选择器覆盖通用选择器的一部分)来专门化选择器。我们可能也希望通过 MachineFunction 对其进行参数化,以根据函数属性(如 optsize)启用选择器变体。

简单的 API 包括

virtual bool select(MachineInstr &MI)

此目标提供的方法负责将可能通用的 MI 更改(或替换)为完全目标特定的等效项。它还负责将 gvregs 约束到适当的寄存器类以及将 COPY 指令传递给寄存器分配器。

InstructionSelector 可以通过遍历 vreg 操作数的 use-def 链,将其他指令折叠到选定的 MI 中。由于 GlobalISel 是全局的,因此这种折叠可以跨越基本块发生。

SelectionDAG 规则导入

TableGen 将导入 SelectionDAG 规则并提供以下函数来执行它们

bool selectImpl(MachineInstr &MI)

--stats 选项可用于确定成功导入的规则的比例。最简单的方法是从 ninja -v 中复制 -gen-globalisel tablegen 命令并对其进行修改。

类似地, --warn-on-skipped-patterns 选项可用于获取规则未导入的原因。这可以用于关注最重要的拒绝原因。

PatLeaf 断言

PatLeaf 无法导入,因为它们的 C++ 实现是基于 SDNode 对象的。处理立即数断言的 PatLeaf 应分别替换为 ImmLeafIntImmLeafFPImmLeaf

其他 PatLeaf 没有标准答案。一些标准断言已烘焙到 TableGen 中,但通常不应这样做。

自定义 SDNode

自定义 SDNode 应使用 GINodeEquiv 映射到目标伪指令。这将导致指令选择器导入它们,但您还需要确保在指令选择器之前将目标伪指令引入 MIR。任何前面的 Pass 都适用,但合法化将是一个特别常见的选择。

复杂模式

复杂模式无法导入,因为它们的 C++ 实现是基于 SDNode 对象的。GlobalISel 版本应使用 GIComplexOperandMatcher 定义,并使用 GIComplexPatternEquiv 映射到 ComplexPattern。

以下断言对于移植 ComplexPattern 很有用

  • isBaseWithConstantOffset() - 检查 base+offset 结构

  • isOperandImmEqual() - 检查特定常量

  • isObviouslySafeToFold() - 检查指令无法下沉并折叠到另一个指令的原因。

C++ 实现有一些重要事项

  • 不要在断言中修改 MIR

  • 渲染器 lambda 应按值捕获以避免使用后释放。它们将在断言返回后使用。

  • 仅在渲染器 lambda 中创建指令。GlobalISel 不会清理您创建但未使用的东西。