如何将 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() 及周围。
我正在尝试实现 "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() 及周围。