mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-17 03:30:28 +00:00
4fe85c7548
Summary: V8->V9: - cleanup tests V7->V8: - addressed feedback from David: - switched to range-based 'for' loops - fixed formatting of tests V6->V7: - rebased and adjusted AsmPrinter args - CamelCased .td, fixed formatting, cleaned up names, removed unused patterns - diffstat: 3 files changed, 203 insertions(+), 227 deletions(-) V5->V6: - addressed feedback from Chandler: - reinstated full verbose standard banner in all files - fixed variables that were not in CamelCase - fixed names of #ifdef in header files - removed redundant braces in if/else chains with single statements - fixed comments - removed trailing empty line - dropped debug annotations from tests - diffstat of these changes: 46 files changed, 456 insertions(+), 469 deletions(-) V4->V5: - fix setLoadExtAction() interface - clang-formated all where it made sense V3->V4: - added CODE_OWNERS entry for BPF backend V2->V3: - fix metadata in tests V1->V2: - addressed feedback from Tom and Matt - removed top level change to configure (now everything via 'experimental-backend') - reworked error reporting via DiagnosticInfo (similar to R600) - added few more tests - added cmake build - added Triple::bpf - tested on linux and darwin V1 cover letter: --------------------- recently linux gained "universal in-kernel virtual machine" which is called eBPF or extended BPF. The name comes from "Berkeley Packet Filter", since new instruction set is based on it. This patch adds a new backend that emits extended BPF instruction set. The concept and development are covered by the following articles: http://lwn.net/Articles/599755/ http://lwn.net/Articles/575531/ http://lwn.net/Articles/603983/ http://lwn.net/Articles/606089/ http://lwn.net/Articles/612878/ One of use cases: dtrace/systemtap alternative. bpf syscall manpage: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=b4fc1a460f3017e958e6a8ea560ea0afd91bf6fe instruction set description and differences vs classic BPF: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/filter.txt Short summary of instruction set: - 64-bit registers R0 - return value from in-kernel function, and exit value for BPF program R1 - R5 - arguments from BPF program to in-kernel function R6 - R9 - callee saved registers that in-kernel function will preserve R10 - read-only frame pointer to access stack - two-operand instructions like +, -, *, mov, load/store - implicit prologue/epilogue (invisible stack pointer) - no floating point, no simd Short history of extended BPF in kernel: interpreter in 3.15, x64 JIT in 3.16, arm64 JIT, verifier, bpf syscall in 3.18, more to come in the future. It's a very small and simple backend. There is no support for global variables, arbitrary function calls, floating point, varargs, exceptions, indirect jumps, arbitrary pointer arithmetic, alloca, etc. From C front-end point of view it's very restricted. It's done on purpose, since kernel rejects all programs that it cannot prove safe. It rejects programs with loops and with memory accesses via arbitrary pointers. When kernel accepts the program it is guaranteed that program will terminate and will not crash the kernel. This patch implements all 'must have' bits. There are several things on TODO list, so this is not the end of development. Most of the code is a boiler plate code, copy-pasted from other backends. Only odd things are lack or < and <= instructions, specialized load_byte intrinsics and 'compare and goto' as single instruction. Current instruction set is fixed, but more instructions can be added in the future. Signed-off-by: Alexei Starovoitov <alexei.starovoitov@gmail.com> Subscribers: majnemer, chandlerc, echristo, joerg, pete, rengolin, kristof.beyls, arsenm, t.p.northover, tstellarAMD, aemerson, llvm-commits Differential Revision: http://reviews.llvm.org/D6494 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@227008 91177308-0d34-0410-b5e6-96231b3b80d8
508 lines
15 KiB
TableGen
508 lines
15 KiB
TableGen
//===-- BPFInstrInfo.td - Target Description for BPF Target ---------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file describes the BPF instructions in TableGen format.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
include "BPFInstrFormats.td"
|
|
|
|
// Instruction Operands and Patterns
|
|
|
|
// These are target-independent nodes, but have target-specific formats.
|
|
def SDT_BPFCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>]>;
|
|
def SDT_BPFCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
|
|
def SDT_BPFCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;
|
|
def SDT_BPFSetFlag : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>]>;
|
|
def SDT_BPFSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>,
|
|
SDTCisSameAs<0, 4>,
|
|
SDTCisSameAs<4, 5>]>;
|
|
def SDT_BPFBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>,
|
|
SDTCisVT<3, OtherVT>]>;
|
|
def SDT_BPFWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
|
|
SDTCisPtrTy<0>]>;
|
|
|
|
def BPFcall : SDNode<"BPFISD::CALL", SDT_BPFCall,
|
|
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
|
|
SDNPVariadic]>;
|
|
def BPFretflag : SDNode<"BPFISD::RET_FLAG", SDTNone,
|
|
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
|
|
def BPFcallseq_start: SDNode<"ISD::CALLSEQ_START", SDT_BPFCallSeqStart,
|
|
[SDNPHasChain, SDNPOutGlue]>;
|
|
def BPFcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_BPFCallSeqEnd,
|
|
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
|
|
def BPFbrcc : SDNode<"BPFISD::BR_CC", SDT_BPFBrCC,
|
|
[SDNPHasChain, SDNPOutGlue, SDNPInGlue]>;
|
|
|
|
def BPFselectcc : SDNode<"BPFISD::SELECT_CC", SDT_BPFSelectCC, [SDNPInGlue]>;
|
|
def BPFWrapper : SDNode<"BPFISD::Wrapper", SDT_BPFWrapper>;
|
|
|
|
def brtarget : Operand<OtherVT>;
|
|
def calltarget : Operand<i64>;
|
|
|
|
def u64imm : Operand<i64> {
|
|
let PrintMethod = "printImm64Operand";
|
|
}
|
|
|
|
def i64immSExt32 : PatLeaf<(imm),
|
|
[{return isInt<32>(N->getSExtValue()); }]>;
|
|
|
|
// Addressing modes.
|
|
def ADDRri : ComplexPattern<i64, 2, "SelectAddr", [frameindex], []>;
|
|
|
|
// Address operands
|
|
def MEMri : Operand<i64> {
|
|
let PrintMethod = "printMemOperand";
|
|
let EncoderMethod = "getMemoryOpValue";
|
|
let MIOperandInfo = (ops GPR, i16imm);
|
|
}
|
|
|
|
// Conditional code predicates - used for pattern matching for jump instructions
|
|
def BPF_CC_EQ : PatLeaf<(imm),
|
|
[{return (N->getZExtValue() == ISD::SETEQ);}]>;
|
|
def BPF_CC_NE : PatLeaf<(imm),
|
|
[{return (N->getZExtValue() == ISD::SETNE);}]>;
|
|
def BPF_CC_GE : PatLeaf<(imm),
|
|
[{return (N->getZExtValue() == ISD::SETGE);}]>;
|
|
def BPF_CC_GT : PatLeaf<(imm),
|
|
[{return (N->getZExtValue() == ISD::SETGT);}]>;
|
|
def BPF_CC_GTU : PatLeaf<(imm),
|
|
[{return (N->getZExtValue() == ISD::SETUGT);}]>;
|
|
def BPF_CC_GEU : PatLeaf<(imm),
|
|
[{return (N->getZExtValue() == ISD::SETUGE);}]>;
|
|
|
|
// jump instructions
|
|
class JMP_RR<bits<4> Opc, string OpcodeStr, PatLeaf Cond>
|
|
: InstBPF<(outs), (ins GPR:$dst, GPR:$src, brtarget:$BrDst),
|
|
!strconcat(OpcodeStr, "\t$dst, $src goto $BrDst"),
|
|
[(BPFbrcc i64:$dst, i64:$src, Cond, bb:$BrDst)]> {
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<4> src;
|
|
bits<16> BrDst;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{55-52} = src;
|
|
let Inst{51-48} = dst;
|
|
let Inst{47-32} = BrDst;
|
|
|
|
let op = Opc;
|
|
let BPFSrc = 1;
|
|
let BPFClass = 5; // BPF_JMP
|
|
}
|
|
|
|
class JMP_RI<bits<4> Opc, string OpcodeStr, PatLeaf Cond>
|
|
: InstBPF<(outs), (ins GPR:$dst, i64imm:$imm, brtarget:$BrDst),
|
|
!strconcat(OpcodeStr, "i\t$dst, $imm goto $BrDst"),
|
|
[(BPFbrcc i64:$dst, i64immSExt32:$imm, Cond, bb:$BrDst)]> {
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<16> BrDst;
|
|
bits<32> imm;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{51-48} = dst;
|
|
let Inst{47-32} = BrDst;
|
|
let Inst{31-0} = imm;
|
|
|
|
let op = Opc;
|
|
let BPFSrc = 0;
|
|
let BPFClass = 5; // BPF_JMP
|
|
}
|
|
|
|
multiclass J<bits<4> Opc, string OpcodeStr, PatLeaf Cond> {
|
|
def _rr : JMP_RR<Opc, OpcodeStr, Cond>;
|
|
def _ri : JMP_RI<Opc, OpcodeStr, Cond>;
|
|
}
|
|
|
|
let isBranch = 1, isTerminator = 1, hasDelaySlot=0 in {
|
|
// cmp+goto instructions
|
|
defm JEQ : J<0x1, "jeq", BPF_CC_EQ>;
|
|
defm JUGT : J<0x2, "jgt", BPF_CC_GTU>;
|
|
defm JUGE : J<0x3, "jge", BPF_CC_GEU>;
|
|
defm JNE : J<0x5, "jne", BPF_CC_NE>;
|
|
defm JSGT : J<0x6, "jsgt", BPF_CC_GT>;
|
|
defm JSGE : J<0x7, "jsge", BPF_CC_GE>;
|
|
}
|
|
|
|
// ALU instructions
|
|
class ALU_RI<bits<4> Opc, string OpcodeStr, SDNode OpNode>
|
|
: InstBPF<(outs GPR:$dst), (ins GPR:$src2, i64imm:$imm),
|
|
!strconcat(OpcodeStr, "i\t$dst, $imm"),
|
|
[(set GPR:$dst, (OpNode GPR:$src2, i64immSExt32:$imm))]> {
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<32> imm;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{51-48} = dst;
|
|
let Inst{31-0} = imm;
|
|
|
|
let op = Opc;
|
|
let BPFSrc = 0;
|
|
let BPFClass = 7; // BPF_ALU64
|
|
}
|
|
|
|
class ALU_RR<bits<4> Opc, string OpcodeStr, SDNode OpNode>
|
|
: InstBPF<(outs GPR:$dst), (ins GPR:$src2, GPR:$src),
|
|
!strconcat(OpcodeStr, "\t$dst, $src"),
|
|
[(set GPR:$dst, (OpNode i64:$src2, i64:$src))]> {
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<4> src;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{55-52} = src;
|
|
let Inst{51-48} = dst;
|
|
|
|
let op = Opc;
|
|
let BPFSrc = 1;
|
|
let BPFClass = 7; // BPF_ALU64
|
|
}
|
|
|
|
multiclass ALU<bits<4> Opc, string OpcodeStr, SDNode OpNode> {
|
|
def _rr : ALU_RR<Opc, OpcodeStr, OpNode>;
|
|
def _ri : ALU_RI<Opc, OpcodeStr, OpNode>;
|
|
}
|
|
|
|
let Constraints = "$dst = $src2" in {
|
|
let isAsCheapAsAMove = 1 in {
|
|
defm ADD : ALU<0x0, "add", add>;
|
|
defm SUB : ALU<0x1, "sub", sub>;
|
|
defm OR : ALU<0x4, "or", or>;
|
|
defm AND : ALU<0x5, "and", and>;
|
|
defm SLL : ALU<0x6, "sll", shl>;
|
|
defm SRL : ALU<0x7, "srl", srl>;
|
|
defm XOR : ALU<0xa, "xor", xor>;
|
|
defm SRA : ALU<0xc, "sra", sra>;
|
|
}
|
|
defm MUL : ALU<0x2, "mul", mul>;
|
|
defm DIV : ALU<0x3, "div", udiv>;
|
|
}
|
|
|
|
class MOV_RR<string OpcodeStr>
|
|
: InstBPF<(outs GPR:$dst), (ins GPR:$src),
|
|
!strconcat(OpcodeStr, "\t$dst, $src"),
|
|
[]> {
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<4> src;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{55-52} = src;
|
|
let Inst{51-48} = dst;
|
|
|
|
let op = 0xb; // BPF_MOV
|
|
let BPFSrc = 1; // BPF_X
|
|
let BPFClass = 7; // BPF_ALU64
|
|
}
|
|
|
|
class MOV_RI<string OpcodeStr>
|
|
: InstBPF<(outs GPR:$dst), (ins i64imm:$imm),
|
|
!strconcat(OpcodeStr, "\t$dst, $imm"),
|
|
[(set GPR:$dst, (i64 i64immSExt32:$imm))]> {
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<32> imm;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{51-48} = dst;
|
|
let Inst{31-0} = imm;
|
|
|
|
let op = 0xb; // BPF_MOV
|
|
let BPFSrc = 0; // BPF_K
|
|
let BPFClass = 7; // BPF_ALU64
|
|
}
|
|
def MOV_rr : MOV_RR<"mov">;
|
|
def MOV_ri : MOV_RI<"mov">;
|
|
|
|
class LD_IMM64<bits<4> Pseudo, string OpcodeStr>
|
|
: InstBPF<(outs GPR:$dst), (ins u64imm:$imm),
|
|
!strconcat(OpcodeStr, "\t$dst, $imm"),
|
|
[(set GPR:$dst, (i64 imm:$imm))]> {
|
|
|
|
bits<3> mode;
|
|
bits<2> size;
|
|
bits<4> dst;
|
|
bits<64> imm;
|
|
|
|
let Inst{63-61} = mode;
|
|
let Inst{60-59} = size;
|
|
let Inst{51-48} = dst;
|
|
let Inst{55-52} = Pseudo;
|
|
let Inst{47-32} = 0;
|
|
let Inst{31-0} = imm{31-0};
|
|
|
|
let mode = 0; // BPF_IMM
|
|
let size = 3; // BPF_DW
|
|
let BPFClass = 0; // BPF_LD
|
|
}
|
|
def LD_imm64 : LD_IMM64<0, "ld_64">;
|
|
|
|
// STORE instructions
|
|
class STORE<bits<2> SizeOp, string OpcodeStr, list<dag> Pattern>
|
|
: InstBPF<(outs), (ins GPR:$src, MEMri:$addr),
|
|
!strconcat(OpcodeStr, "\t$addr, $src"), Pattern> {
|
|
bits<3> mode;
|
|
bits<2> size;
|
|
bits<4> src;
|
|
bits<20> addr;
|
|
|
|
let Inst{63-61} = mode;
|
|
let Inst{60-59} = size;
|
|
let Inst{51-48} = addr{19-16}; // base reg
|
|
let Inst{55-52} = src;
|
|
let Inst{47-32} = addr{15-0}; // offset
|
|
|
|
let mode = 3; // BPF_MEM
|
|
let size = SizeOp;
|
|
let BPFClass = 3; // BPF_STX
|
|
}
|
|
|
|
class STOREi64<bits<2> Opc, string OpcodeStr, PatFrag OpNode>
|
|
: STORE<Opc, OpcodeStr, [(OpNode i64:$src, ADDRri:$addr)]>;
|
|
|
|
def STW : STOREi64<0x0, "stw", truncstorei32>;
|
|
def STH : STOREi64<0x1, "sth", truncstorei16>;
|
|
def STB : STOREi64<0x2, "stb", truncstorei8>;
|
|
def STD : STOREi64<0x3, "std", store>;
|
|
|
|
// LOAD instructions
|
|
class LOAD<bits<2> SizeOp, string OpcodeStr, list<dag> Pattern>
|
|
: InstBPF<(outs GPR:$dst), (ins MEMri:$addr),
|
|
!strconcat(OpcodeStr, "\t$dst, $addr"), Pattern> {
|
|
bits<3> mode;
|
|
bits<2> size;
|
|
bits<4> dst;
|
|
bits<20> addr;
|
|
|
|
let Inst{63-61} = mode;
|
|
let Inst{60-59} = size;
|
|
let Inst{51-48} = dst;
|
|
let Inst{55-52} = addr{19-16};
|
|
let Inst{47-32} = addr{15-0};
|
|
|
|
let mode = 3; // BPF_MEM
|
|
let size = SizeOp;
|
|
let BPFClass = 1; // BPF_LDX
|
|
}
|
|
|
|
class LOADi64<bits<2> SizeOp, string OpcodeStr, PatFrag OpNode>
|
|
: LOAD<SizeOp, OpcodeStr, [(set i64:$dst, (OpNode ADDRri:$addr))]>;
|
|
|
|
def LDW : LOADi64<0x0, "ldw", zextloadi32>;
|
|
def LDH : LOADi64<0x1, "ldh", zextloadi16>;
|
|
def LDB : LOADi64<0x2, "ldb", zextloadi8>;
|
|
def LDD : LOADi64<0x3, "ldd", load>;
|
|
|
|
class BRANCH<bits<4> Opc, string OpcodeStr, list<dag> Pattern>
|
|
: InstBPF<(outs), (ins brtarget:$BrDst),
|
|
!strconcat(OpcodeStr, "\t$BrDst"), Pattern> {
|
|
bits<4> op;
|
|
bits<16> BrDst;
|
|
bits<1> BPFSrc;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{47-32} = BrDst;
|
|
|
|
let op = Opc;
|
|
let BPFSrc = 0;
|
|
let BPFClass = 5; // BPF_JMP
|
|
}
|
|
|
|
class CALL<string OpcodeStr>
|
|
: InstBPF<(outs), (ins calltarget:$BrDst),
|
|
!strconcat(OpcodeStr, "\t$BrDst"), []> {
|
|
bits<4> op;
|
|
bits<32> BrDst;
|
|
bits<1> BPFSrc;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{31-0} = BrDst;
|
|
|
|
let op = 8; // BPF_CALL
|
|
let BPFSrc = 0;
|
|
let BPFClass = 5; // BPF_JMP
|
|
}
|
|
|
|
// Jump always
|
|
let isBranch = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1 in {
|
|
def JMP : BRANCH<0x0, "jmp", [(br bb:$BrDst)]>;
|
|
}
|
|
|
|
// Jump and link
|
|
let isCall=1, hasDelaySlot=0, Uses = [R11],
|
|
// Potentially clobbered registers
|
|
Defs = [R0, R1, R2, R3, R4, R5] in {
|
|
def JAL : CALL<"call">;
|
|
}
|
|
|
|
class NOP_I<string OpcodeStr>
|
|
: InstBPF<(outs), (ins i32imm:$imm),
|
|
!strconcat(OpcodeStr, "\t$imm"), []> {
|
|
// mov r0, r0 == nop
|
|
bits<4> op;
|
|
bits<1> BPFSrc;
|
|
bits<4> dst;
|
|
bits<4> src;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = BPFSrc;
|
|
let Inst{55-52} = src;
|
|
let Inst{51-48} = dst;
|
|
|
|
let op = 0xb; // BPF_MOV
|
|
let BPFSrc = 1; // BPF_X
|
|
let BPFClass = 7; // BPF_ALU64
|
|
let src = 0; // R0
|
|
let dst = 0; // R0
|
|
}
|
|
|
|
let hasSideEffects = 0 in
|
|
def NOP : NOP_I<"nop">;
|
|
|
|
class RET<string OpcodeStr>
|
|
: InstBPF<(outs), (ins),
|
|
!strconcat(OpcodeStr, ""), [(BPFretflag)]> {
|
|
bits<4> op;
|
|
|
|
let Inst{63-60} = op;
|
|
let Inst{59} = 0;
|
|
let Inst{31-0} = 0;
|
|
|
|
let op = 9; // BPF_EXIT
|
|
let BPFClass = 5; // BPF_JMP
|
|
}
|
|
|
|
let isReturn = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1,
|
|
isNotDuplicable = 1 in {
|
|
def RET : RET<"ret">;
|
|
}
|
|
|
|
// ADJCALLSTACKDOWN/UP pseudo insns
|
|
let Defs = [R11], Uses = [R11] in {
|
|
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt),
|
|
"#ADJCALLSTACKDOWN $amt",
|
|
[(BPFcallseq_start timm:$amt)]>;
|
|
def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
|
|
"#ADJCALLSTACKUP $amt1 $amt2",
|
|
[(BPFcallseq_end timm:$amt1, timm:$amt2)]>;
|
|
}
|
|
|
|
let usesCustomInserter = 1 in {
|
|
def Select : Pseudo<(outs GPR:$dst),
|
|
(ins GPR:$lhs, GPR:$rhs, i64imm:$imm, GPR:$src, GPR:$src2),
|
|
"# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2",
|
|
[(set i64:$dst,
|
|
(BPFselectcc i64:$lhs, i64:$rhs, (i64 imm:$imm), i64:$src, i64:$src2))]>;
|
|
}
|
|
|
|
// load 64-bit global addr into register
|
|
def : Pat<(BPFWrapper tglobaladdr:$in), (LD_imm64 tglobaladdr:$in)>;
|
|
|
|
// 0xffffFFFF doesn't fit into simm32, optimize common case
|
|
def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)),
|
|
(SRL_ri (SLL_ri (i64 GPR:$src), 32), 32)>;
|
|
|
|
// Calls
|
|
def : Pat<(BPFcall tglobaladdr:$dst), (JAL tglobaladdr:$dst)>;
|
|
def : Pat<(BPFcall imm:$dst), (JAL imm:$dst)>;
|
|
|
|
// Loads
|
|
def : Pat<(extloadi8 ADDRri:$src), (i64 (LDB ADDRri:$src))>;
|
|
def : Pat<(extloadi16 ADDRri:$src), (i64 (LDH ADDRri:$src))>;
|
|
def : Pat<(extloadi32 ADDRri:$src), (i64 (LDW ADDRri:$src))>;
|
|
|
|
// Atomics
|
|
class XADD<bits<2> SizeOp, string OpcodeStr, PatFrag OpNode>
|
|
: InstBPF<(outs GPR:$dst), (ins MEMri:$addr, GPR:$val),
|
|
!strconcat(OpcodeStr, "\t$dst, $addr, $val"),
|
|
[(set GPR:$dst, (OpNode ADDRri:$addr, GPR:$val))]> {
|
|
bits<3> mode;
|
|
bits<2> size;
|
|
bits<4> src;
|
|
bits<20> addr;
|
|
|
|
let Inst{63-61} = mode;
|
|
let Inst{60-59} = size;
|
|
let Inst{51-48} = addr{19-16}; // base reg
|
|
let Inst{55-52} = src;
|
|
let Inst{47-32} = addr{15-0}; // offset
|
|
|
|
let mode = 6; // BPF_XADD
|
|
let size = SizeOp;
|
|
let BPFClass = 3; // BPF_STX
|
|
}
|
|
|
|
let Constraints = "$dst = $val" in {
|
|
def XADD32 : XADD<0, "xadd32", atomic_load_add_32>;
|
|
def XADD64 : XADD<3, "xadd64", atomic_load_add_64>;
|
|
// undefined def XADD16 : XADD<1, "xadd16", atomic_load_add_16>;
|
|
// undefined def XADD8 : XADD<2, "xadd8", atomic_load_add_8>;
|
|
}
|
|
|
|
let Defs = [R0, R1, R2, R3, R4, R5], Uses = [R6], hasSideEffects = 1,
|
|
hasExtraDefRegAllocReq = 1, hasExtraSrcRegAllocReq = 1, mayLoad = 1 in {
|
|
class LOAD_ABS<bits<2> SizeOp, string OpcodeStr, Intrinsic OpNode>
|
|
: InstBPF<(outs), (ins GPR:$skb, i64imm:$imm),
|
|
!strconcat(OpcodeStr, "\tr0, $skb.data + $imm"),
|
|
[(set R0, (OpNode GPR:$skb, i64immSExt32:$imm))]> {
|
|
bits<3> mode;
|
|
bits<2> size;
|
|
bits<32> imm;
|
|
|
|
let Inst{63-61} = mode;
|
|
let Inst{60-59} = size;
|
|
let Inst{31-0} = imm;
|
|
|
|
let mode = 1; // BPF_ABS
|
|
let size = SizeOp;
|
|
let BPFClass = 0; // BPF_LD
|
|
}
|
|
|
|
class LOAD_IND<bits<2> SizeOp, string OpcodeStr, Intrinsic OpNode>
|
|
: InstBPF<(outs), (ins GPR:$skb, GPR:$val),
|
|
!strconcat(OpcodeStr, "\tr0, $skb.data + $val"),
|
|
[(set R0, (OpNode GPR:$skb, GPR:$val))]> {
|
|
bits<3> mode;
|
|
bits<2> size;
|
|
bits<4> val;
|
|
|
|
let Inst{63-61} = mode;
|
|
let Inst{60-59} = size;
|
|
let Inst{55-52} = val;
|
|
|
|
let mode = 2; // BPF_IND
|
|
let size = SizeOp;
|
|
let BPFClass = 0; // BPF_LD
|
|
}
|
|
}
|
|
|
|
def LD_ABS_B : LOAD_ABS<2, "ldabs_b", int_bpf_load_byte>;
|
|
def LD_ABS_H : LOAD_ABS<1, "ldabs_h", int_bpf_load_half>;
|
|
def LD_ABS_W : LOAD_ABS<0, "ldabs_w", int_bpf_load_word>;
|
|
|
|
def LD_IND_B : LOAD_IND<2, "ldind_b", int_bpf_load_byte>;
|
|
def LD_IND_H : LOAD_IND<1, "ldind_h", int_bpf_load_half>;
|
|
def LD_IND_W : LOAD_IND<0, "ldind_w", int_bpf_load_word>;
|