【发布时间】:2019-12-24 08:13:16
【问题描述】:
编辑:
我找到了处理这个问题的TwoAddressInstructionPass 通行证。现在我正在研究实现。
LLVM IR 的add 是一个三地址指令:
%x = add i32 %y %z
但是X86add是两个地址:
add eax 2
似乎翻译需要某种:
mov dst src1
add dst src2
所以我很好奇 LLVM 是如何做到的。我查看了X86InstrArithmetic.td,找到了ArithBinOp_RF的定义:
multiclass ArithBinOp_RF<bits<8> BaseOpc, bits<8> BaseOpc2, bits<8> BaseOpc4,
string mnemonic, Format RegMRM, Format MemMRM,
SDNode opnodeflag, SDNode opnode,
bit CommutableRR, bit ConvertibleToThreeAddress,
bit ConvertibleToThreeAddressRR> {
let Defs = [EFLAGS] in {
let Constraints = "$src1 = $dst" in {
let isCommutable = CommutableRR in {
let isConvertibleToThreeAddress = ConvertibleToThreeAddressRR in {
def NAME#8rr : BinOpRR_RF<BaseOpc, mnemonic, Xi8 , opnodeflag>;
def NAME#16rr : BinOpRR_RF<BaseOpc, mnemonic, Xi16, opnodeflag>;
def NAME#32rr : BinOpRR_RF<BaseOpc, mnemonic, Xi32, opnodeflag>;
def NAME#64rr : BinOpRR_RF<BaseOpc, mnemonic, Xi64, opnodeflag>;
} // isConvertibleToThreeAddress
} // isCommutable
我怀疑Constraints与翻译有关:
- 如果是这样,
Constraints是如何工作的? - 如果不是,LLVM 如何以及在哪里处理翻译(
lea情况除外)?它是否插入mov?如果是这样,LLVM 如何处理冗余的movs?
【问题讨论】:
-
为什么 LLVM 想要或需要首先插入那些
movs?记住LLVM用的是SSA,没办法说%x = add i32 %x %y。 -
@arnt 这就是我想到的问题。 LLVM 无法表达
%x = add i32 %x %y,但这是在x86 中add的方式。所以我的问题是 LLVM 如何将%z = add i32 %x %y转换为 x86add dst src。 -
一个寄存器在添加之前包含
%y,在添加之后包含%z。添加后可能没有任何寄存器包含%y。%y不是一个寄存器,你看,它是一个值,有它自己的活性概念。寄存器分配器(有几个)可能决定一直将它保存在一个寄存器中,将它保存在不同位置的两个不同的寄存器中,从内存中读取它,等等。 -
@arnt 感谢您的解释。 IIUC,您在谈论寄存器分配短语。但是 IMO 指令选择是第一位的,不是吗?在选择短语(在寄存器分配(?)之前),LLVM 将 LLVM IR 选择为 x86 机器指令,我的问题是 LLVM 如何选择 LLVM IR
add?如果寄存器分配器决定一直将其保存在寄存器中,如您所说,它必须发出mov指令...?
标签: compiler-construction llvm