InstructionSelect¶
此Pass将通用机器指令转换为等效的目标特定指令。它自底向上遍历 MachineFunction
,在定义之前选择使用,从而实现简单的死代码消除。
API: InstructionSelector¶
目标实现了 InstructionSelector
类,其中包含目标特定的选择逻辑。
实例由子目标提供,以便它可以根据子目标特性专门化选择器(例如,向量选择器覆盖通用公共选择器的部分)。我们可能还希望通过 MachineFunction 对其进行参数化,以根据函数属性(如 optsize)启用选择器变体。
简单的 API 包括
virtual bool select(MachineInstr &MI)
此目标提供的方法负责将可能通用的 MI 转换为完全目标特定的等效指令(通过修改或替换)。它还负责将 gvregs 约束到适当的寄存器类别,以及将 COPY 指令传递给寄存器分配器。
InstructionSelector
可以通过遍历 vreg 操作数的使用-定义链,将其他指令折叠到选定的 MI 中。由于 GlobalISel 是全局的,因此这种折叠可以跨基本块发生。
SelectionDAG 规则导入¶
TableGen 将导入 SelectionDAG 规则并提供以下函数来执行它们
bool selectImpl(MachineInstr &MI)
可以使用 --stats
选项来确定成功导入的规则的比例。最简单的方法是从 ninja -v
复制 -gen-globalisel
tablegen 命令并对其进行修改。
同样,可以使用 --warn-on-skipped-patterns
选项来获取规则未导入的原因。这可以用于关注最重要的拒绝原因。
PatLeaf 谓词¶
PatLeafs 无法导入,因为它们的 C++ 是用 SDNode
对象实现的。处理立即数谓词的 PatLeafs 应根据需要替换为 ImmLeaf
、IntImmLeaf
或 FPImmLeaf
。
对于其他 PatLeafs,没有标准答案。一些标准谓词已被烘焙到 TableGen 中,但这通常不应该这样做。
自定义 SDNodes¶
自定义 SDNodes 应使用 GINodeEquiv
映射到目标伪指令。这将导致指令选择器导入它们,但您还需要确保在指令选择器之前将目标伪指令引入到 MIR 中。任何先前的 Pass 都是合适的,但 legalizer 将是一个特别常见的选择。
ComplexPatterns¶
ComplexPatterns 无法导入,因为它们的 C++ 是用 SDNode
对象实现的。GlobalISel 版本应使用 GIComplexOperandMatcher
定义,并使用 GIComplexPatternEquiv
映射到 ComplexPattern。
以下谓词对于移植 ComplexPattern 非常有用
isBaseWithConstantOffset() - 检查 base+offset 结构
isOperandImmEqual() - 检查特定常量
isObviouslySafeToFold() - 检查指令无法下沉并折叠到另一个指令的原因。
C++ 实现有一些重要的要点
不要在谓词中修改 MIR
Renderer lambda 应该按值捕获,以避免 use-after-free。它们将在谓词返回后使用。
仅在 renderer lambda 中创建指令。GlobalISel 不会清理您创建但未使用的内容。