编辑:
我找到了处理这个问题的TwoAddressInstructionPass
pass。现在我正在研究实现。
LLVM IR的add
是一个三地址指令:
%x = add i32 %y %z
但是X86 add
是两个地址:
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
与翻译有关:
- 如果是这种情况,
约束
如何发挥作用? - 如果不是,LLVM 如何以及在何处处理翻译(
lea
情况除外)?它插入mov
吗?如果是这种情况,LLVM 如何处理冗余的mov
?
最佳答案
有一个 TwoAddressInstructionPass
,如果 MachineInstr
中的某些 MachineOperand
是,它会将三地址模式指令转换为双地址模式。绑定(bind)(TwoAddressInstructionPass.cpp):
static bool isTwoAddrUse(MachineInstr &MI, unsigned Reg, unsigned &DstReg) {
for (unsigned i = 0, NumOps = MI.getNumOperands(); i != NumOps; ++i) {
const MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg() || !MO.isUse() || MO.getReg() != Reg)
continue;
unsigned ti;
if (MI.isRegTiedToDefOperand(i, &ti)) {
DstReg = MI.getOperand(ti).getReg();
return true;
}
}
return false;
}
“Tied”表示两个操作数映射到同一个寄存器。当我们在 tablegen 中编写 Constraints = "$src1 = $dst"
时,生成的代码会将 $src1
和 $dst
设置为“tied”( GlobalISel/Utils.cpp):
bool llvm::constrainSelectedInstRegOperands(MachineInstr &I,
const TargetInstrInfo &TII,
const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI) {
assert(!isPreISelGenericOpcode(I.getOpcode()) &&
"A selected instruction is expected");
MachineBasicBlock &MBB = *I.getParent();
MachineFunction &MF = *MBB.getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();
for (unsigned OpI = 0, OpE = I.getNumExplicitOperands(); OpI != OpE; ++OpI) {
MachineOperand &MO = I.getOperand(OpI);
// There's nothing to be done on non-register operands.
if (!MO.isReg())
continue;
LLVM_DEBUG(dbgs() << "Converting operand: " << MO << '\n');
assert(MO.isReg() && "Unsupported non-reg operand");
Register Reg = MO.getReg();
// Physical registers don't need to be constrained.
if (Register::isPhysicalRegister(Reg))
continue;
// Register operands with a value of 0 (e.g. predicate operands) don't need
// to be constrained.
if (Reg == 0)
continue;
// If the operand is a vreg, we should constrain its regclass, and only
// insert COPYs if that's impossible.
// constrainOperandRegClass does that for us.
MO.setReg(constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(),
MO, OpI));
// Tie uses to defs as indicated in MCInstrDesc if this hasn't already been
// done.
if (MO.isUse()) {
int DefIdx = I.getDesc().getOperandConstraint(OpI, MCOI::TIED_TO);
if (DefIdx != -1 && !I.isRegTiedToUseOperand(DefIdx))
I.tieOperands(DefIdx, OpI);
}
}
return true;
}
关于compiler-construction - LLVM如何将三个地址LLVM IR `add`转换为X86两个地址 `add`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57551135/