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;
Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20200512/41742dbd/attachment.html>
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.
~Craig
On Tue, May 12, 2020 at 2:23 PM Chris Sears via llvm-dev <
llvm-dev at lists.llvm.org> wrote:
> 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;
>
> Chris
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20200512/af8ba1ad/attachment-0001.html>
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. Chris On Tue, May 12, 2020 at 2:30 PM Craig Topper <craig.topper at gmail.com> wrote:> 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. > > > ~Craig > > > On Tue, May 12, 2020 at 2:23 PM Chris Sears via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > >> 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; >> >> Chris >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >> >-- Ite Ursi -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200512/6b41b86b/attachment.html>