指令选择¶
此 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 应分别替换为 ImmLeaf
、 IntImmLeaf
或 FPImmLeaf
。
其他 PatLeaf 没有标准答案。一些标准断言已烘焙到 TableGen 中,但通常不应这样做。
自定义 SDNode¶
自定义 SDNode 应使用 GINodeEquiv
映射到目标伪指令。这将导致指令选择器导入它们,但您还需要确保在指令选择器之前将目标伪指令引入 MIR。任何前面的 Pass 都适用,但合法化将是一个特别常见的选择。
复杂模式¶
复杂模式无法导入,因为它们的 C++ 实现是基于 SDNode
对象的。GlobalISel 版本应使用 GIComplexOperandMatcher
定义,并使用 GIComplexPatternEquiv
映射到 ComplexPattern。
以下断言对于移植 ComplexPattern 很有用
isBaseWithConstantOffset() - 检查 base+offset 结构
isOperandImmEqual() - 检查特定常量
isObviouslySafeToFold() - 检查指令无法下沉并折叠到另一个指令的原因。
C++ 实现有一些重要事项
不要在断言中修改 MIR
渲染器 lambda 应按值捕获以避免使用后释放。它们将在断言返回后使用。
仅在渲染器 lambda 中创建指令。GlobalISel 不会清理您创建但未使用的东西。