BPF tablegen+codegen question

In BPF, an ADD instruction is defined as a 2 register instruction:

0x0f. add dst, src. dst += src

In BPFInstrInfo.td this kind of ALU instruction is defined with:

def _rr : ALU_RR<BPF_ALU64, Opc,
(outs GPR:$dst),
(ins GPR:$src2, GPR:$src),
“$dst “#OpcodeStr#” $src”,
[(set GPR:$dst, (OpNode i64:$src2, i64:$src))]>;

How does tablegen+codegen ensure that dst and src2 are the same register? I see that the assembly/disassembly string assumes this is the case.

Also, it uses i64:$src which is an i64 and not a GPR. What is the distinction there? X86 does this differently. src1 and src2 are GR64 registers.

def IMUL64rr : RI<0xAF, MRMSrcReg, (outs GR64:$dst),
(ins GR64:$src1, GR64:$src2),
“imul{q}\t{$src2, $dst|$dst, $src2}”,
[(set GR64:$dst, EFLAGS,
(X86smul_flag GR64:$src1, GR64:$src2))]>,
Sched<[WriteIMul64Reg]>, TB;


I believe that’s done by the " let Constraints = “$dst = $src2” " here

let Constraints = “$dst = $src2” in {
let isAsCheapAsAMove = 1 in {
defm ADD : ALU<BPF_ADD, “+=”, add>;
defm SUB : ALU<BPF_SUB, “-=”, sub>;
defm OR : ALU<BPF_OR, “|=”, or>;
defm AND : ALU<BPF_AND, “&=”, and>;
defm SLL : ALU<BPF_LSH, “<<=”, shl>;
defm SRL : ALU<BPF_RSH, “>>=”, srl>;
defm XOR : ALU<BPF_XOR, “^=”, xor>;
defm SRA : ALU<BPF_ARSH, “s>>=”, sra>;
defm MUL : ALU<BPF_MUL, “*=”, mul>;
defm DIV : ALU<BPF_DIV, “/=”, udiv>;

As to your second question. I think the register class is only consulted by tablegen to find the type. It’s not used to constrain the register class. That’s done by the ins/outs of the instruction. So there’s probably not difference between GR64 or i64 in this case.

Thanks, Craig. I didn’t see Constraints but I get that now. I’ve found some explanations and examples of it in the Building An LLVM Backend. I get the typing as well.


Also, the constraint language is pretty general (if not very well documented). Looking at examples,

grep Constraints /.td

gives (among about 1200):

Hexagon/HexagonDepInstrInfo.td:let Constraints = “$Ryy32 = $Ryy32in, $Rx32 = $Rx32in”;