如何将 llvm-tablegen 中自己的寄存器操作数映射到指令的操作码?

How to map own register operands in llvm-tablegen to instruction's opcode?

我正在尝试实现 "address register with offset" 类型的操作数。它们由基址寄存器和偏移寄存器组成:[K1 + K3]。但是在指令的操作码中,我需要为那些寄存器单独保留代码。我找不到办法 1)获取操作数的代码(那是一回事吗?) 2) 将操作数的Reg:$Rm、Reg:$Rn直接映射到指令的Rm、Rn字段。我将 Rm 放入 Rn 的插槽中,而 Rn 只是被忽略了。

那么如何完成这件事呢?

当我尝试通过 BuildMI 添加它们并打印代码时,它们似乎编写正确,所以我猜这些操作数被正确解析了。

操作数说明

def MemRRAsmOperand : AsmOperandClass {
  let Name = "MemRR";
  let ParserMethod = "parseMEMOperand";
}

class MemRR<RegisterOperand Reg> : Operand<i32>
{
  let MIOperandInfo = (ops Reg:$Rm, Reg:$Rn); <--- --- ---
  let ParserMatchClass = MemRRAsmOperand;
}

let PrintMethod = "printMemOperand" in
{
  def memJJ : MemRR<RegisterOperand<JSS>>;
  def memKK : MemRR<RegisterOperand<KSS>>;
}

指令说明

class IALULoadStoreInstBase<dag outs, dag ins, string mnemonic, string operands, list<dag> pattern> :
  MyInst<outs, ins, mnemonic, operands, pattern>
{

    ...

  bits<5> Ureg; 
  bits<5> Rn; 
  bits<5> Rm; 

    ...
//IType is opcode
  let IType{25-21} = Group;  
  let IType{20-16} = Ureg;

  let IType{15} = MOD;
  let IType{14} = LQ;
  let IType{13} = ImmFlag;

  let IType{12-8} = Rm; <--- --- ---
  let IType{7-6} = 0b00;
  let IType{5-1} = Rn; <--- --- ---
  let IType{0} = Q;
   ...

}

我填写标志并传出和插入的多类

multiclass IALULoadInstDst<RegisterOperand Dst, string mnemonic, string prefix, ValueType Type>
{
  let WR = 0 in
  {
    let JK = 0 in
    {
      let MOD = 0 in
      {
        defm fromJrr : IALULoadStoreRRInstEx<(outs Dst:$Ureg), (ins memJJ:$src), <--- --- ---
                                             !strconcat(mnemonic, "fromjrr"), !strconcat("$Ureg, ", prefix, "[$src]"), <--- --- ---
                                             [(set Type:$Ureg, (load addr:$src))]>; <--- --- ---
      }
    }
    let JK = 1 in
    {
      let MOD = 0 in
      {
        defm fromKrr : IALULoadStoreRRInstEx<(outs Dst:$Ureg), (ins memKK:$src), <--- --- ---
                                             !strconcat(mnemonic, "fromkrr"), !strconcat("$Ureg, ", prefix, "[$src]"), <--- --- ---
                                             [(set Type:$Ureg, (load addr:$src))]>; <--- --- ---
      }
    }
  }
}

您需要为此类操作数编写自己的选择代码。此类模式称为 "Complex",您需要为它们编写自定义指令选择代码。参见例如X86DAGToDAGISel::SelectAddr() 或 SystemZDAGToDGAISel::selectBDAddr() 及周围。