mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
BPF backend
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 llvm-svn: 227008
This commit is contained in:
parent
5c148a073f
commit
9de5355969
@ -146,6 +146,10 @@ N: Michael Spencer
|
||||
E: bigcheesegs@gmail.com
|
||||
D: Windows parts of Support, Object, ar, nm, objdump, ranlib, size
|
||||
|
||||
N: Alexei Starovoitov
|
||||
E: alexei.starovoitov@gmail.com
|
||||
D: BPF backend
|
||||
|
||||
N: Tom Stellard
|
||||
E: thomas.stellard@amd.com
|
||||
E: mesa-dev@lists.freedesktop.org
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
armeb, // ARM (big endian): armeb
|
||||
aarch64, // AArch64 (little endian): aarch64
|
||||
aarch64_be, // AArch64 (big endian): aarch64_be
|
||||
bpf, // eBPF or extended BPF or 64-bit BPF (little endian)
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
|
@ -597,3 +597,4 @@ include "llvm/IR/IntrinsicsHexagon.td"
|
||||
include "llvm/IR/IntrinsicsNVVM.td"
|
||||
include "llvm/IR/IntrinsicsMips.td"
|
||||
include "llvm/IR/IntrinsicsR600.td"
|
||||
include "llvm/IR/IntrinsicsBPF.td"
|
||||
|
22
include/llvm/IR/IntrinsicsBPF.td
Normal file
22
include/llvm/IR/IntrinsicsBPF.td
Normal file
@ -0,0 +1,22 @@
|
||||
//===- IntrinsicsBPF.td - Defines BPF intrinsics -----------*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines all of the BPF-specific intrinsics.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Specialized loads from packet
|
||||
let TargetPrefix = "bpf" in { // All intrinsics start with "llvm.bpf."
|
||||
def int_bpf_load_byte : GCCBuiltin<"__builtin_bpf_load_byte">,
|
||||
Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>;
|
||||
def int_bpf_load_half : GCCBuiltin<"__builtin_bpf_load_half">,
|
||||
Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>;
|
||||
def int_bpf_load_word : GCCBuiltin<"__builtin_bpf_load_word">,
|
||||
Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>;
|
||||
}
|
@ -23,6 +23,7 @@ const char *Triple::getArchTypeName(ArchType Kind) {
|
||||
case aarch64_be: return "aarch64_be";
|
||||
case arm: return "arm";
|
||||
case armeb: return "armeb";
|
||||
case bpf: return "bpf";
|
||||
case hexagon: return "hexagon";
|
||||
case mips: return "mips";
|
||||
case mipsel: return "mipsel";
|
||||
@ -86,6 +87,8 @@ const char *Triple::getArchTypePrefix(ArchType Kind) {
|
||||
case amdgcn:
|
||||
case r600: return "amdgpu";
|
||||
|
||||
case bpf: return "bpf";
|
||||
|
||||
case sparcv9:
|
||||
case sparc: return "sparc";
|
||||
|
||||
@ -191,6 +194,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
|
||||
.Case("arm64", aarch64) // "arm64" is an alias for "aarch64"
|
||||
.Case("arm", arm)
|
||||
.Case("armeb", armeb)
|
||||
.Case("bpf", bpf)
|
||||
.Case("mips", mips)
|
||||
.Case("mipsel", mipsel)
|
||||
.Case("mips64", mips64)
|
||||
@ -290,6 +294,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
|
||||
.Case("mips64el", Triple::mips64el)
|
||||
.Case("r600", Triple::r600)
|
||||
.Case("amdgcn", Triple::amdgcn)
|
||||
.Case("bpf", Triple::bpf)
|
||||
.Case("hexagon", Triple::hexagon)
|
||||
.Case("s390x", Triple::systemz)
|
||||
.Case("sparc", Triple::sparc)
|
||||
@ -869,6 +874,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
|
||||
case llvm::Triple::aarch64:
|
||||
case llvm::Triple::aarch64_be:
|
||||
case llvm::Triple::amdgcn:
|
||||
case llvm::Triple::bpf:
|
||||
case llvm::Triple::le64:
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
@ -905,6 +911,7 @@ Triple Triple::get32BitArchVariant() const {
|
||||
case Triple::aarch64:
|
||||
case Triple::aarch64_be:
|
||||
case Triple::amdgcn:
|
||||
case Triple::bpf:
|
||||
case Triple::msp430:
|
||||
case Triple::systemz:
|
||||
case Triple::ppc64le:
|
||||
@ -966,6 +973,7 @@ Triple Triple::get64BitArchVariant() const {
|
||||
|
||||
case Triple::aarch64:
|
||||
case Triple::aarch64_be:
|
||||
case Triple::bpf:
|
||||
case Triple::le64:
|
||||
case Triple::amdil64:
|
||||
case Triple::amdgcn:
|
||||
|
22
lib/Target/BPF/BPF.h
Normal file
22
lib/Target/BPF/BPF.h
Normal file
@ -0,0 +1,22 @@
|
||||
//===-- BPF.h - Top-level interface for BPF representation ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPF_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPF_H
|
||||
|
||||
#include "MCTargetDesc/BPFMCTargetDesc.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
namespace llvm {
|
||||
class BPFTargetMachine;
|
||||
|
||||
FunctionPass *createBPFISelDag(BPFTargetMachine &TM);
|
||||
}
|
||||
|
||||
#endif
|
31
lib/Target/BPF/BPF.td
Normal file
31
lib/Target/BPF/BPF.td
Normal file
@ -0,0 +1,31 @@
|
||||
//===-- BPF.td - Describe the BPF Target Machine -----------*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "llvm/Target/Target.td"
|
||||
|
||||
include "BPFRegisterInfo.td"
|
||||
include "BPFCallingConv.td"
|
||||
include "BPFInstrInfo.td"
|
||||
|
||||
def BPFInstrInfo : InstrInfo;
|
||||
|
||||
class Proc<string Name, list<SubtargetFeature> Features>
|
||||
: Processor<Name, NoItineraries, Features>;
|
||||
|
||||
def : Proc<"generic", []>;
|
||||
|
||||
def BPFInstPrinter : AsmWriter {
|
||||
string AsmWriterClassName = "InstPrinter";
|
||||
bit isMCAsmWriter = 1;
|
||||
}
|
||||
|
||||
def BPF : Target {
|
||||
let InstructionSet = BPFInstrInfo;
|
||||
let AssemblyWriters = [BPFInstPrinter];
|
||||
}
|
87
lib/Target/BPF/BPFAsmPrinter.cpp
Normal file
87
lib/Target/BPF/BPFAsmPrinter.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
//===-- BPFAsmPrinter.cpp - BPF LLVM assembly writer ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to the BPF assembly language.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFInstrInfo.h"
|
||||
#include "BPFMCInstLower.h"
|
||||
#include "BPFTargetMachine.h"
|
||||
#include "InstPrinter/BPFInstPrinter.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
|
||||
namespace {
|
||||
class BPFAsmPrinter : public AsmPrinter {
|
||||
public:
|
||||
explicit BPFAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
|
||||
: AsmPrinter(TM, std::move(Streamer)) {}
|
||||
|
||||
const char *getPassName() const override { return "BPF Assembly Printer"; }
|
||||
|
||||
void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O,
|
||||
const char *Modifier = nullptr);
|
||||
void EmitInstruction(const MachineInstr *MI) override;
|
||||
};
|
||||
}
|
||||
|
||||
void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
|
||||
raw_ostream &O, const char *Modifier) {
|
||||
const MachineOperand &MO = MI->getOperand(OpNum);
|
||||
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
O << BPFInstPrinter::getRegisterName(MO.getReg());
|
||||
break;
|
||||
|
||||
case MachineOperand::MO_Immediate:
|
||||
O << MO.getImm();
|
||||
break;
|
||||
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
O << *MO.getMBB()->getSymbol();
|
||||
break;
|
||||
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
O << *getSymbol(MO.getGlobal());
|
||||
break;
|
||||
|
||||
default:
|
||||
llvm_unreachable("<unknown operand type>");
|
||||
}
|
||||
}
|
||||
|
||||
void BPFAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
|
||||
BPFMCInstLower MCInstLowering(OutContext, *this);
|
||||
|
||||
MCInst TmpInst;
|
||||
MCInstLowering.Lower(MI, TmpInst);
|
||||
EmitToStreamer(OutStreamer, TmpInst);
|
||||
}
|
||||
|
||||
// Force static initialization.
|
||||
extern "C" void LLVMInitializeBPFAsmPrinter() {
|
||||
RegisterAsmPrinter<BPFAsmPrinter> X(TheBPFTarget);
|
||||
}
|
29
lib/Target/BPF/BPFCallingConv.td
Normal file
29
lib/Target/BPF/BPFCallingConv.td
Normal file
@ -0,0 +1,29 @@
|
||||
//===-- BPFCallingConv.td - Calling Conventions BPF --------*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This describes the calling conventions for the BPF architecture.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// BPF 64-bit C return-value convention.
|
||||
def RetCC_BPF64 : CallingConv<[CCIfType<[i64], CCAssignToReg<[R0]>>]>;
|
||||
|
||||
// BPF 64-bit C Calling convention.
|
||||
def CC_BPF64 : CallingConv<[
|
||||
// Promote i8/i16/i32 args to i64
|
||||
CCIfType<[ i8, i16, i32 ], CCPromoteToType<i64>>,
|
||||
|
||||
// All arguments get passed in integer registers if there is space.
|
||||
CCIfType<[i64], CCAssignToReg<[ R1, R2, R3, R4, R5 ]>>,
|
||||
|
||||
// Could be assigned to the stack in 8-byte aligned units, but unsupported
|
||||
CCAssignToStack<8, 8>
|
||||
]>;
|
||||
|
||||
def CSR : CalleeSavedRegs<(add R6, R7, R8, R9, R10)>;
|
39
lib/Target/BPF/BPFFrameLowering.cpp
Normal file
39
lib/Target/BPF/BPFFrameLowering.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===-- BPFFrameLowering.cpp - BPF Frame Information ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the BPF implementation of TargetFrameLowering class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPFFrameLowering.h"
|
||||
#include "BPFInstrInfo.h"
|
||||
#include "BPFSubtarget.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
bool BPFFrameLowering::hasFP(const MachineFunction &MF) const { return true; }
|
||||
|
||||
void BPFFrameLowering::emitPrologue(MachineFunction &MF) const {}
|
||||
|
||||
void BPFFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {}
|
||||
|
||||
void BPFFrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
MachineFunction &MF, RegScavenger *RS) const {
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
|
||||
MRI.setPhysRegUnused(BPF::R6);
|
||||
MRI.setPhysRegUnused(BPF::R7);
|
||||
MRI.setPhysRegUnused(BPF::R8);
|
||||
MRI.setPhysRegUnused(BPF::R9);
|
||||
}
|
41
lib/Target/BPF/BPFFrameLowering.h
Normal file
41
lib/Target/BPF/BPFFrameLowering.h
Normal file
@ -0,0 +1,41 @@
|
||||
//===-- BPFFrameLowering.h - Define frame lowering for BPF -----*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements BPF-specific bits of TargetFrameLowering class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFFRAMELOWERING_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFFRAMELOWERING_H
|
||||
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
|
||||
namespace llvm {
|
||||
class BPFSubtarget;
|
||||
|
||||
class BPFFrameLowering : public TargetFrameLowering {
|
||||
public:
|
||||
explicit BPFFrameLowering(const BPFSubtarget &sti)
|
||||
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 8, 0) {}
|
||||
|
||||
void emitPrologue(MachineFunction &MF) const override;
|
||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
|
||||
bool hasFP(const MachineFunction &MF) const override;
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
RegScavenger *RS) const override;
|
||||
|
||||
void
|
||||
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI) const override {
|
||||
MBB.erase(MI);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
159
lib/Target/BPF/BPFISelDAGToDAG.cpp
Normal file
159
lib/Target/BPF/BPFISelDAGToDAG.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
//===-- BPFISelDAGToDAG.cpp - A dag to dag inst selector for BPF ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a DAG pattern matching instruction selector for BPF,
|
||||
// converting from a legalized dag to a BPF dag.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFRegisterInfo.h"
|
||||
#include "BPFSubtarget.h"
|
||||
#include "BPFTargetMachine.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "bpf-isel"
|
||||
|
||||
// Instruction Selector Implementation
|
||||
namespace {
|
||||
|
||||
class BPFDAGToDAGISel : public SelectionDAGISel {
|
||||
public:
|
||||
explicit BPFDAGToDAGISel(BPFTargetMachine &TM) : SelectionDAGISel(TM) {}
|
||||
|
||||
const char *getPassName() const override {
|
||||
return "BPF DAG->DAG Pattern Instruction Selection";
|
||||
}
|
||||
|
||||
private:
|
||||
// Include the pieces autogenerated from the target description.
|
||||
#include "BPFGenDAGISel.inc"
|
||||
|
||||
SDNode *Select(SDNode *N) override;
|
||||
|
||||
// Complex Pattern for address selection.
|
||||
bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
|
||||
};
|
||||
}
|
||||
|
||||
// ComplexPattern used on BPF Load/Store instructions
|
||||
bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
|
||||
// if Address is FI, get the TargetFrameIndex.
|
||||
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
||||
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
|
||||
Offset = CurDAG->getTargetConstant(0, MVT::i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
||||
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
||||
return false;
|
||||
|
||||
// Addresses of the form FI+const or FI|const
|
||||
if (CurDAG->isBaseWithConstantOffset(Addr)) {
|
||||
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
|
||||
if (isInt<32>(CN->getSExtValue())) {
|
||||
|
||||
// If the first operand is a FI, get the TargetFI Node
|
||||
if (FrameIndexSDNode *FIN =
|
||||
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
|
||||
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
|
||||
else
|
||||
Base = Addr.getOperand(0);
|
||||
|
||||
Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i64);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Base = Addr;
|
||||
Offset = CurDAG->getTargetConstant(0, MVT::i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
SDNode *BPFDAGToDAGISel::Select(SDNode *Node) {
|
||||
unsigned Opcode = Node->getOpcode();
|
||||
|
||||
// Dump information about the Node being selected
|
||||
DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
|
||||
|
||||
// If we have a custom node, we already have selected!
|
||||
if (Node->isMachineOpcode()) {
|
||||
DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// tablegen selection should be handled here.
|
||||
switch (Opcode) {
|
||||
default: break;
|
||||
|
||||
case ISD::UNDEF: {
|
||||
errs() << "BUG: "; Node->dump(CurDAG); errs() << '\n';
|
||||
report_fatal_error("shouldn't see UNDEF during Select");
|
||||
break;
|
||||
}
|
||||
|
||||
case ISD::INTRINSIC_W_CHAIN: {
|
||||
unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
|
||||
switch (IntNo) {
|
||||
case Intrinsic::bpf_load_byte:
|
||||
case Intrinsic::bpf_load_half:
|
||||
case Intrinsic::bpf_load_word: {
|
||||
SDLoc DL(Node);
|
||||
SDValue Chain = Node->getOperand(0);
|
||||
SDValue N1 = Node->getOperand(1);
|
||||
SDValue Skb = Node->getOperand(2);
|
||||
SDValue N3 = Node->getOperand(3);
|
||||
|
||||
SDValue R6Reg = CurDAG->getRegister(BPF::R6, MVT::i64);
|
||||
Chain = CurDAG->getCopyToReg(Chain, DL, R6Reg, Skb, SDValue());
|
||||
Node = CurDAG->UpdateNodeOperands(Node, Chain, N1, R6Reg, N3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ISD::FrameIndex: {
|
||||
int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
|
||||
EVT VT = Node->getValueType(0);
|
||||
SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
|
||||
unsigned Opc = BPF::MOV_rr;
|
||||
if (Node->hasOneUse())
|
||||
return CurDAG->SelectNodeTo(Node, Opc, VT, TFI);
|
||||
return CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI);
|
||||
}
|
||||
}
|
||||
|
||||
// Select the default instruction
|
||||
SDNode *ResNode = SelectCode(Node);
|
||||
|
||||
DEBUG(dbgs() << "=> ";
|
||||
if (ResNode == nullptr || ResNode == Node)
|
||||
Node->dump(CurDAG);
|
||||
else
|
||||
ResNode->dump(CurDAG);
|
||||
dbgs() << '\n');
|
||||
return ResNode;
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
|
||||
return new BPFDAGToDAGISel(TM);
|
||||
}
|
642
lib/Target/BPF/BPFISelLowering.cpp
Normal file
642
lib/Target/BPF/BPFISelLowering.cpp
Normal file
@ -0,0 +1,642 @@
|
||||
//===-- BPFISelLowering.cpp - BPF DAG Lowering Implementation ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interfaces that BPF uses to lower LLVM code into a
|
||||
// selection DAG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPFISelLowering.h"
|
||||
#include "BPF.h"
|
||||
#include "BPFTargetMachine.h"
|
||||
#include "BPFSubtarget.h"
|
||||
#include "llvm/CodeGen/CallingConvLower.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/IR/DiagnosticPrinter.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "bpf-lower"
|
||||
|
||||
namespace {
|
||||
|
||||
// Diagnostic information for unimplemented or unsupported feature reporting.
|
||||
class DiagnosticInfoUnsupported : public DiagnosticInfo {
|
||||
private:
|
||||
// Debug location where this diagnostic is triggered.
|
||||
DebugLoc DLoc;
|
||||
const Twine &Description;
|
||||
const Function &Fn;
|
||||
SDValue Value;
|
||||
|
||||
static int KindID;
|
||||
|
||||
static int getKindID() {
|
||||
if (KindID == 0)
|
||||
KindID = llvm::getNextAvailablePluginDiagnosticKind();
|
||||
return KindID;
|
||||
}
|
||||
|
||||
public:
|
||||
DiagnosticInfoUnsupported(SDLoc DLoc, const Function &Fn, const Twine &Desc,
|
||||
SDValue Value)
|
||||
: DiagnosticInfo(getKindID(), DS_Error), DLoc(DLoc.getDebugLoc()),
|
||||
Description(Desc), Fn(Fn), Value(Value) {}
|
||||
|
||||
void print(DiagnosticPrinter &DP) const override {
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
|
||||
if (DLoc.isUnknown() == false) {
|
||||
DILocation DIL(DLoc.getAsMDNode(Fn.getContext()));
|
||||
StringRef Filename = DIL.getFilename();
|
||||
unsigned Line = DIL.getLineNumber();
|
||||
unsigned Column = DIL.getColumnNumber();
|
||||
OS << Filename << ':' << Line << ':' << Column << ' ';
|
||||
}
|
||||
|
||||
OS << "in function " << Fn.getName() << ' ' << *Fn.getFunctionType() << '\n'
|
||||
<< Description;
|
||||
if (Value)
|
||||
Value->print(OS);
|
||||
OS << '\n';
|
||||
OS.flush();
|
||||
DP << Str;
|
||||
}
|
||||
|
||||
static bool classof(const DiagnosticInfo *DI) {
|
||||
return DI->getKind() == getKindID();
|
||||
}
|
||||
};
|
||||
|
||||
int DiagnosticInfoUnsupported::KindID = 0;
|
||||
}
|
||||
|
||||
BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM)
|
||||
: TargetLowering(TM) {
|
||||
|
||||
// Set up the register classes.
|
||||
addRegisterClass(MVT::i64, &BPF::GPRRegClass);
|
||||
|
||||
// Compute derived properties from the register classes
|
||||
computeRegisterProperties();
|
||||
|
||||
setStackPointerRegisterToSaveRestore(BPF::R11);
|
||||
|
||||
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
|
||||
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
||||
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
|
||||
setOperationAction(ISD::SETCC, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SELECT, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
|
||||
|
||||
setOperationAction(ISD::GlobalAddress, MVT::i64, Custom);
|
||||
|
||||
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
|
||||
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
||||
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
||||
|
||||
setOperationAction(ISD::SDIVREM, MVT::i64, Expand);
|
||||
setOperationAction(ISD::UDIVREM, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SREM, MVT::i64, Expand);
|
||||
setOperationAction(ISD::UREM, MVT::i64, Expand);
|
||||
|
||||
setOperationAction(ISD::MULHU, MVT::i64, Expand);
|
||||
setOperationAction(ISD::MULHS, MVT::i64, Expand);
|
||||
setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
|
||||
|
||||
setOperationAction(ISD::ADDC, MVT::i64, Expand);
|
||||
setOperationAction(ISD::ADDE, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SUBC, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SUBE, MVT::i64, Expand);
|
||||
|
||||
// no UNDEF allowed
|
||||
setOperationAction(ISD::UNDEF, MVT::i64, Expand);
|
||||
|
||||
setOperationAction(ISD::ROTR, MVT::i64, Expand);
|
||||
setOperationAction(ISD::ROTL, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand);
|
||||
setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand);
|
||||
|
||||
setOperationAction(ISD::BSWAP, MVT::i64, Expand);
|
||||
setOperationAction(ISD::CTTZ, MVT::i64, Custom);
|
||||
setOperationAction(ISD::CTLZ, MVT::i64, Custom);
|
||||
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Custom);
|
||||
setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Custom);
|
||||
setOperationAction(ISD::CTPOP, MVT::i64, Expand);
|
||||
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand);
|
||||
|
||||
// Extended load operations for i1 types must be promoted
|
||||
for (MVT VT : MVT::integer_valuetypes()) {
|
||||
setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote);
|
||||
setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);
|
||||
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
|
||||
|
||||
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand);
|
||||
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i16, Expand);
|
||||
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i32, Expand);
|
||||
}
|
||||
|
||||
setBooleanContents(ZeroOrOneBooleanContent);
|
||||
|
||||
// Function alignments (log2)
|
||||
setMinFunctionAlignment(3);
|
||||
setPrefFunctionAlignment(3);
|
||||
|
||||
// inline memcpy() for kernel to see explicit copy
|
||||
MaxStoresPerMemset = MaxStoresPerMemsetOptSize = 128;
|
||||
MaxStoresPerMemcpy = MaxStoresPerMemcpyOptSize = 128;
|
||||
MaxStoresPerMemmove = MaxStoresPerMemmoveOptSize = 128;
|
||||
}
|
||||
|
||||
SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
switch (Op.getOpcode()) {
|
||||
case ISD::BR_CC:
|
||||
return LowerBR_CC(Op, DAG);
|
||||
case ISD::GlobalAddress:
|
||||
return LowerGlobalAddress(Op, DAG);
|
||||
case ISD::SELECT_CC:
|
||||
return LowerSELECT_CC(Op, DAG);
|
||||
default:
|
||||
llvm_unreachable("unimplemented operand");
|
||||
}
|
||||
}
|
||||
|
||||
// Calling Convention Implementation
|
||||
#include "BPFGenCallingConv.inc"
|
||||
|
||||
SDValue BPFTargetLowering::LowerFormalArguments(
|
||||
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
switch (CallConv) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported calling convention");
|
||||
case CallingConv::C:
|
||||
case CallingConv::Fast:
|
||||
break;
|
||||
}
|
||||
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineRegisterInfo &RegInfo = MF.getRegInfo();
|
||||
|
||||
// Assign locations to all of the incoming arguments.
|
||||
SmallVector<CCValAssign, 16> ArgLocs;
|
||||
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
|
||||
CCInfo.AnalyzeFormalArguments(Ins, CC_BPF64);
|
||||
|
||||
for (auto &VA : ArgLocs) {
|
||||
if (VA.isRegLoc()) {
|
||||
// Arguments passed in registers
|
||||
EVT RegVT = VA.getLocVT();
|
||||
switch (RegVT.getSimpleVT().SimpleTy) {
|
||||
default: {
|
||||
errs() << "LowerFormalArguments Unhandled argument type: "
|
||||
<< RegVT.getSimpleVT().SimpleTy << '\n';
|
||||
llvm_unreachable(0);
|
||||
}
|
||||
case MVT::i64:
|
||||
unsigned VReg = RegInfo.createVirtualRegister(&BPF::GPRRegClass);
|
||||
RegInfo.addLiveIn(VA.getLocReg(), VReg);
|
||||
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT);
|
||||
|
||||
// If this is an 8/16/32-bit value, it is really passed promoted to 64
|
||||
// bits. Insert an assert[sz]ext to capture this, then truncate to the
|
||||
// right size.
|
||||
if (VA.getLocInfo() == CCValAssign::SExt)
|
||||
ArgValue = DAG.getNode(ISD::AssertSext, DL, RegVT, ArgValue,
|
||||
DAG.getValueType(VA.getValVT()));
|
||||
else if (VA.getLocInfo() == CCValAssign::ZExt)
|
||||
ArgValue = DAG.getNode(ISD::AssertZext, DL, RegVT, ArgValue,
|
||||
DAG.getValueType(VA.getValVT()));
|
||||
|
||||
if (VA.getLocInfo() != CCValAssign::Full)
|
||||
ArgValue = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), ArgValue);
|
||||
|
||||
InVals.push_back(ArgValue);
|
||||
}
|
||||
} else {
|
||||
DiagnosticInfoUnsupported Err(DL, *MF.getFunction(),
|
||||
"defined with too many args", SDValue());
|
||||
DAG.getContext()->diagnose(Err);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsVarArg || MF.getFunction()->hasStructRetAttr()) {
|
||||
DiagnosticInfoUnsupported Err(
|
||||
DL, *MF.getFunction(),
|
||||
"functions with VarArgs or StructRet are not supported", SDValue());
|
||||
DAG.getContext()->diagnose(Err);
|
||||
}
|
||||
|
||||
return Chain;
|
||||
}
|
||||
|
||||
SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
SelectionDAG &DAG = CLI.DAG;
|
||||
auto &Outs = CLI.Outs;
|
||||
auto &OutVals = CLI.OutVals;
|
||||
auto &Ins = CLI.Ins;
|
||||
SDValue Chain = CLI.Chain;
|
||||
SDValue Callee = CLI.Callee;
|
||||
bool &IsTailCall = CLI.IsTailCall;
|
||||
CallingConv::ID CallConv = CLI.CallConv;
|
||||
bool IsVarArg = CLI.IsVarArg;
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
|
||||
// BPF target does not support tail call optimization.
|
||||
IsTailCall = false;
|
||||
|
||||
switch (CallConv) {
|
||||
default:
|
||||
report_fatal_error("Unsupported calling convention");
|
||||
case CallingConv::Fast:
|
||||
case CallingConv::C:
|
||||
break;
|
||||
}
|
||||
|
||||
// Analyze operands of the call, assigning locations to each operand.
|
||||
SmallVector<CCValAssign, 16> ArgLocs;
|
||||
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
|
||||
|
||||
CCInfo.AnalyzeCallOperands(Outs, CC_BPF64);
|
||||
|
||||
unsigned NumBytes = CCInfo.getNextStackOffset();
|
||||
|
||||
if (Outs.size() >= 6) {
|
||||
DiagnosticInfoUnsupported Err(CLI.DL, *MF.getFunction(),
|
||||
"too many args to ", Callee);
|
||||
DAG.getContext()->diagnose(Err);
|
||||
}
|
||||
|
||||
for (auto &Arg : Outs) {
|
||||
ISD::ArgFlagsTy Flags = Arg.Flags;
|
||||
if (!Flags.isByVal())
|
||||
continue;
|
||||
|
||||
DiagnosticInfoUnsupported Err(CLI.DL, *MF.getFunction(),
|
||||
"pass by value not supported ", Callee);
|
||||
DAG.getContext()->diagnose(Err);
|
||||
}
|
||||
|
||||
Chain = DAG.getCALLSEQ_START(
|
||||
Chain, DAG.getConstant(NumBytes, getPointerTy(), true), CLI.DL);
|
||||
|
||||
SmallVector<std::pair<unsigned, SDValue>, 5> RegsToPass;
|
||||
|
||||
// Walk arg assignments
|
||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
SDValue Arg = OutVals[i];
|
||||
|
||||
// Promote the value if needed.
|
||||
switch (VA.getLocInfo()) {
|
||||
default:
|
||||
llvm_unreachable("Unknown loc info");
|
||||
case CCValAssign::Full:
|
||||
break;
|
||||
case CCValAssign::SExt:
|
||||
Arg = DAG.getNode(ISD::SIGN_EXTEND, CLI.DL, VA.getLocVT(), Arg);
|
||||
break;
|
||||
case CCValAssign::ZExt:
|
||||
Arg = DAG.getNode(ISD::ZERO_EXTEND, CLI.DL, VA.getLocVT(), Arg);
|
||||
break;
|
||||
case CCValAssign::AExt:
|
||||
Arg = DAG.getNode(ISD::ANY_EXTEND, CLI.DL, VA.getLocVT(), Arg);
|
||||
break;
|
||||
}
|
||||
|
||||
// Push arguments into RegsToPass vector
|
||||
if (VA.isRegLoc())
|
||||
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
||||
else
|
||||
llvm_unreachable("call arg pass bug");
|
||||
}
|
||||
|
||||
SDValue InFlag;
|
||||
|
||||
// Build a sequence of copy-to-reg nodes chained together with token chain and
|
||||
// flag operands which copy the outgoing args into registers. The InFlag in
|
||||
// necessary since all emitted instructions must be stuck together.
|
||||
for (auto &Reg : RegsToPass) {
|
||||
Chain = DAG.getCopyToReg(Chain, CLI.DL, Reg.first, Reg.second, InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
}
|
||||
|
||||
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
||||
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
||||
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, getPointerTy(),
|
||||
G->getOffset(), 0);
|
||||
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
||||
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), 0);
|
||||
|
||||
// Returns a chain & a flag for retval copy to use.
|
||||
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
Ops.push_back(Chain);
|
||||
Ops.push_back(Callee);
|
||||
|
||||
// Add argument registers to the end of the list so that they are
|
||||
// known live into the call.
|
||||
for (auto &Reg : RegsToPass)
|
||||
Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
|
||||
|
||||
if (InFlag.getNode())
|
||||
Ops.push_back(InFlag);
|
||||
|
||||
Chain = DAG.getNode(BPFISD::CALL, CLI.DL, NodeTys, Ops);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
// Create the CALLSEQ_END node.
|
||||
Chain = DAG.getCALLSEQ_END(
|
||||
Chain, DAG.getConstant(NumBytes, getPointerTy(), true),
|
||||
DAG.getConstant(0, getPointerTy(), true), InFlag, CLI.DL);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
// Handle result values, copying them out of physregs into vregs that we
|
||||
// return.
|
||||
return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, CLI.DL, DAG,
|
||||
InVals);
|
||||
}
|
||||
|
||||
SDValue
|
||||
BPFTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
|
||||
bool IsVarArg,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
SDLoc DL, SelectionDAG &DAG) const {
|
||||
|
||||
// CCValAssign - represent the assignment of the return value to a location
|
||||
SmallVector<CCValAssign, 16> RVLocs;
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
|
||||
// CCState - Info about the registers and stack slot.
|
||||
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
|
||||
|
||||
if (MF.getFunction()->getReturnType()->isAggregateType()) {
|
||||
DiagnosticInfoUnsupported Err(DL, *MF.getFunction(),
|
||||
"only integer returns supported", SDValue());
|
||||
DAG.getContext()->diagnose(Err);
|
||||
}
|
||||
|
||||
// Analize return values.
|
||||
CCInfo.AnalyzeReturn(Outs, RetCC_BPF64);
|
||||
|
||||
SDValue Flag;
|
||||
SmallVector<SDValue, 4> RetOps(1, Chain);
|
||||
|
||||
// Copy the result values into the output registers.
|
||||
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
||||
CCValAssign &VA = RVLocs[i];
|
||||
assert(VA.isRegLoc() && "Can only return in registers!");
|
||||
|
||||
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag);
|
||||
|
||||
// Guarantee that all emitted copies are stuck together,
|
||||
// avoiding something bad.
|
||||
Flag = Chain.getValue(1);
|
||||
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
||||
}
|
||||
|
||||
unsigned Opc = BPFISD::RET_FLAG;
|
||||
RetOps[0] = Chain; // Update chain.
|
||||
|
||||
// Add the flag if we have it.
|
||||
if (Flag.getNode())
|
||||
RetOps.push_back(Flag);
|
||||
|
||||
return DAG.getNode(Opc, DL, MVT::Other, RetOps);
|
||||
}
|
||||
|
||||
SDValue BPFTargetLowering::LowerCallResult(
|
||||
SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool IsVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
// Assign locations to each value returned by this call.
|
||||
SmallVector<CCValAssign, 16> RVLocs;
|
||||
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
|
||||
|
||||
if (Ins.size() >= 2) {
|
||||
DiagnosticInfoUnsupported Err(DL, *MF.getFunction(),
|
||||
"only small returns supported", SDValue());
|
||||
DAG.getContext()->diagnose(Err);
|
||||
}
|
||||
|
||||
CCInfo.AnalyzeCallResult(Ins, RetCC_BPF64);
|
||||
|
||||
// Copy all of the result registers out of their specified physreg.
|
||||
for (auto &Val : RVLocs) {
|
||||
Chain = DAG.getCopyFromReg(Chain, DL, Val.getLocReg(),
|
||||
Val.getValVT(), InFlag).getValue(1);
|
||||
InFlag = Chain.getValue(2);
|
||||
InVals.push_back(Chain.getValue(0));
|
||||
}
|
||||
|
||||
return Chain;
|
||||
}
|
||||
|
||||
static void NegateCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) {
|
||||
switch (CC) {
|
||||
default:
|
||||
break;
|
||||
case ISD::SETULT:
|
||||
case ISD::SETULE:
|
||||
case ISD::SETLT:
|
||||
case ISD::SETLE:
|
||||
CC = ISD::getSetCCSwappedOperands(CC);
|
||||
std::swap(LHS, RHS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDValue BPFTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
||||
SDValue Chain = Op.getOperand(0);
|
||||
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
|
||||
SDValue LHS = Op.getOperand(2);
|
||||
SDValue RHS = Op.getOperand(3);
|
||||
SDValue Dest = Op.getOperand(4);
|
||||
SDLoc DL(Op);
|
||||
|
||||
NegateCC(LHS, RHS, CC);
|
||||
|
||||
return DAG.getNode(BPFISD::BR_CC, DL, Op.getValueType(), Chain, LHS, RHS,
|
||||
DAG.getConstant(CC, MVT::i64), Dest);
|
||||
}
|
||||
|
||||
SDValue BPFTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
|
||||
SDValue LHS = Op.getOperand(0);
|
||||
SDValue RHS = Op.getOperand(1);
|
||||
SDValue TrueV = Op.getOperand(2);
|
||||
SDValue FalseV = Op.getOperand(3);
|
||||
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
||||
SDLoc DL(Op);
|
||||
|
||||
NegateCC(LHS, RHS, CC);
|
||||
|
||||
SDValue TargetCC = DAG.getConstant(CC, MVT::i64);
|
||||
|
||||
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
|
||||
SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
|
||||
|
||||
return DAG.getNode(BPFISD::SELECT_CC, DL, VTs, Ops);
|
||||
}
|
||||
|
||||
const char *BPFTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
return NULL;
|
||||
case BPFISD::RET_FLAG:
|
||||
return "BPFISD::RET_FLAG";
|
||||
case BPFISD::CALL:
|
||||
return "BPFISD::CALL";
|
||||
case BPFISD::SELECT_CC:
|
||||
return "BPFISD::SELECT_CC";
|
||||
case BPFISD::BR_CC:
|
||||
return "BPFISD::BR_CC";
|
||||
case BPFISD::Wrapper:
|
||||
return "BPFISD::Wrapper";
|
||||
}
|
||||
}
|
||||
|
||||
SDValue BPFTargetLowering::LowerGlobalAddress(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
SDLoc DL(Op);
|
||||
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
||||
SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i64);
|
||||
|
||||
return DAG.getNode(BPFISD::Wrapper, DL, MVT::i64, GA);
|
||||
}
|
||||
|
||||
MachineBasicBlock *
|
||||
BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const {
|
||||
unsigned Opc = MI->getOpcode();
|
||||
|
||||
const TargetInstrInfo &TII =
|
||||
*getTargetMachine().getSubtargetImpl()->getInstrInfo();
|
||||
DebugLoc DL = MI->getDebugLoc();
|
||||
|
||||
assert(Opc == BPF::Select && "Unexpected instr type to insert");
|
||||
|
||||
// To "insert" a SELECT instruction, we actually have to insert the diamond
|
||||
// control-flow pattern. The incoming instruction knows the destination vreg
|
||||
// to set, the condition code register to branch on, the true/false values to
|
||||
// select between, and a branch opcode to use.
|
||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||
MachineFunction::iterator I = BB;
|
||||
++I;
|
||||
|
||||
// ThisMBB:
|
||||
// ...
|
||||
// TrueVal = ...
|
||||
// jmp_XX r1, r2 goto Copy1MBB
|
||||
// fallthrough --> Copy0MBB
|
||||
MachineBasicBlock *ThisMBB = BB;
|
||||
MachineFunction *F = BB->getParent();
|
||||
MachineBasicBlock *Copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *Copy1MBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||
|
||||
F->insert(I, Copy0MBB);
|
||||
F->insert(I, Copy1MBB);
|
||||
// Update machine-CFG edges by transferring all successors of the current
|
||||
// block to the new block which will contain the Phi node for the select.
|
||||
Copy1MBB->splice(Copy1MBB->begin(), BB,
|
||||
std::next(MachineBasicBlock::iterator(MI)), BB->end());
|
||||
Copy1MBB->transferSuccessorsAndUpdatePHIs(BB);
|
||||
// Next, add the true and fallthrough blocks as its successors.
|
||||
BB->addSuccessor(Copy0MBB);
|
||||
BB->addSuccessor(Copy1MBB);
|
||||
|
||||
// Insert Branch if Flag
|
||||
unsigned LHS = MI->getOperand(1).getReg();
|
||||
unsigned RHS = MI->getOperand(2).getReg();
|
||||
int CC = MI->getOperand(3).getImm();
|
||||
switch (CC) {
|
||||
case ISD::SETGT:
|
||||
BuildMI(BB, DL, TII.get(BPF::JSGT_rr))
|
||||
.addReg(LHS)
|
||||
.addReg(RHS)
|
||||
.addMBB(Copy1MBB);
|
||||
break;
|
||||
case ISD::SETUGT:
|
||||
BuildMI(BB, DL, TII.get(BPF::JUGT_rr))
|
||||
.addReg(LHS)
|
||||
.addReg(RHS)
|
||||
.addMBB(Copy1MBB);
|
||||
break;
|
||||
case ISD::SETGE:
|
||||
BuildMI(BB, DL, TII.get(BPF::JSGE_rr))
|
||||
.addReg(LHS)
|
||||
.addReg(RHS)
|
||||
.addMBB(Copy1MBB);
|
||||
break;
|
||||
case ISD::SETUGE:
|
||||
BuildMI(BB, DL, TII.get(BPF::JUGE_rr))
|
||||
.addReg(LHS)
|
||||
.addReg(RHS)
|
||||
.addMBB(Copy1MBB);
|
||||
break;
|
||||
case ISD::SETEQ:
|
||||
BuildMI(BB, DL, TII.get(BPF::JEQ_rr))
|
||||
.addReg(LHS)
|
||||
.addReg(RHS)
|
||||
.addMBB(Copy1MBB);
|
||||
break;
|
||||
case ISD::SETNE:
|
||||
BuildMI(BB, DL, TII.get(BPF::JNE_rr))
|
||||
.addReg(LHS)
|
||||
.addReg(RHS)
|
||||
.addMBB(Copy1MBB);
|
||||
break;
|
||||
default:
|
||||
report_fatal_error("unimplemented select CondCode " + Twine(CC));
|
||||
}
|
||||
|
||||
// Copy0MBB:
|
||||
// %FalseValue = ...
|
||||
// # fallthrough to Copy1MBB
|
||||
BB = Copy0MBB;
|
||||
|
||||
// Update machine-CFG edges
|
||||
BB->addSuccessor(Copy1MBB);
|
||||
|
||||
// Copy1MBB:
|
||||
// %Result = phi [ %FalseValue, Copy0MBB ], [ %TrueValue, ThisMBB ]
|
||||
// ...
|
||||
BB = Copy1MBB;
|
||||
BuildMI(*BB, BB->begin(), DL, TII.get(BPF::PHI), MI->getOperand(0).getReg())
|
||||
.addReg(MI->getOperand(5).getReg())
|
||||
.addMBB(Copy0MBB)
|
||||
.addReg(MI->getOperand(4).getReg())
|
||||
.addMBB(ThisMBB);
|
||||
|
||||
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
||||
return BB;
|
||||
}
|
89
lib/Target/BPF/BPFISelLowering.h
Normal file
89
lib/Target/BPF/BPFISelLowering.h
Normal file
@ -0,0 +1,89 @@
|
||||
//===-- BPFISelLowering.h - BPF DAG Lowering Interface ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interfaces that BPF uses to lower LLVM code into a
|
||||
// selection DAG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFISELLOWERING_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFISELLOWERING_H
|
||||
|
||||
#include "BPF.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace BPFISD {
|
||||
enum {
|
||||
FIRST_NUMBER = ISD::BUILTIN_OP_END,
|
||||
RET_FLAG,
|
||||
CALL,
|
||||
SELECT_CC,
|
||||
BR_CC,
|
||||
Wrapper
|
||||
};
|
||||
}
|
||||
|
||||
class BPFTargetLowering : public TargetLowering {
|
||||
public:
|
||||
explicit BPFTargetLowering(const TargetMachine &TM);
|
||||
|
||||
// Provide custom lowering hooks for some operations.
|
||||
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
|
||||
|
||||
// This method returns the name of a target specific DAG node.
|
||||
const char *getTargetNodeName(unsigned Opcode) const override;
|
||||
|
||||
MachineBasicBlock *
|
||||
EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const override;
|
||||
|
||||
private:
|
||||
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
|
||||
// Lower the result values of a call, copying them out of physregs into vregs
|
||||
SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
|
||||
CallingConv::ID CallConv, bool IsVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL,
|
||||
SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
|
||||
// Lower a call into CALLSEQ_START - BPFISD:CALL - CALLSEQ_END chain
|
||||
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
SmallVectorImpl<SDValue> &InVals) const override;
|
||||
|
||||
// Lower incoming arguments, copy physregs into vregs
|
||||
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
|
||||
bool IsVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
SDLoc DL, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const override;
|
||||
|
||||
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
|
||||
SelectionDAG &DAG) const override;
|
||||
|
||||
EVT getOptimalMemOpType(uint64_t Size, unsigned DstAlign, unsigned SrcAlign,
|
||||
bool IsMemset, bool ZeroMemset, bool MemcpyStrSrc,
|
||||
MachineFunction &MF) const override {
|
||||
return Size >= 8 ? MVT::i64 : MVT::i32;
|
||||
}
|
||||
|
||||
bool shouldConvertConstantLoadToIntImm(const APInt &Imm,
|
||||
Type *Ty) const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
33
lib/Target/BPF/BPFInstrFormats.td
Normal file
33
lib/Target/BPF/BPFInstrFormats.td
Normal file
@ -0,0 +1,33 @@
|
||||
//===-- BPFInstrFormats.td - BPF Instruction Formats -------*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class InstBPF<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: Instruction {
|
||||
field bits<64> Inst;
|
||||
field bits<64> SoftFail = 0;
|
||||
let Size = 8;
|
||||
|
||||
let Namespace = "BPF";
|
||||
let DecoderNamespace = "BPF";
|
||||
|
||||
bits<3> BPFClass;
|
||||
let Inst{58-56} = BPFClass;
|
||||
|
||||
dag OutOperandList = outs;
|
||||
dag InOperandList = ins;
|
||||
let AsmString = asmstr;
|
||||
let Pattern = pattern;
|
||||
}
|
||||
|
||||
// Pseudo instructions
|
||||
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstBPF<outs, ins, asmstr, pattern> {
|
||||
let Inst{63-0} = 0;
|
||||
let isPseudo = 1;
|
||||
}
|
168
lib/Target/BPF/BPFInstrInfo.cpp
Normal file
168
lib/Target/BPF/BPFInstrInfo.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
//===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the BPF implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFInstrInfo.h"
|
||||
#include "BPFSubtarget.h"
|
||||
#include "BPFTargetMachine.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
#define GET_INSTRINFO_CTOR_DTOR
|
||||
#include "BPFGenInstrInfo.inc"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
BPFInstrInfo::BPFInstrInfo()
|
||||
: BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}
|
||||
|
||||
void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I, DebugLoc DL,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
bool KillSrc) const {
|
||||
if (BPF::GPRRegClass.contains(DestReg, SrcReg))
|
||||
BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg)
|
||||
.addReg(SrcReg, getKillRegState(KillSrc));
|
||||
else
|
||||
llvm_unreachable("Impossible reg-to-reg copy");
|
||||
}
|
||||
|
||||
void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
unsigned SrcReg, bool IsKill, int FI,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const {
|
||||
DebugLoc DL;
|
||||
if (I != MBB.end())
|
||||
DL = I->getDebugLoc();
|
||||
|
||||
if (RC == &BPF::GPRRegClass)
|
||||
BuildMI(MBB, I, DL, get(BPF::STD))
|
||||
.addReg(SrcReg, getKillRegState(IsKill))
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0);
|
||||
else
|
||||
llvm_unreachable("Can't store this register to stack slot");
|
||||
}
|
||||
|
||||
void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
unsigned DestReg, int FI,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const {
|
||||
DebugLoc DL;
|
||||
if (I != MBB.end())
|
||||
DL = I->getDebugLoc();
|
||||
|
||||
if (RC == &BPF::GPRRegClass)
|
||||
BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0);
|
||||
else
|
||||
llvm_unreachable("Can't load this register from stack slot");
|
||||
}
|
||||
|
||||
bool BPFInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock *&TBB,
|
||||
MachineBasicBlock *&FBB,
|
||||
SmallVectorImpl<MachineOperand> &Cond,
|
||||
bool AllowModify) const {
|
||||
// Start from the bottom of the block and work up, examining the
|
||||
// terminator instructions.
|
||||
MachineBasicBlock::iterator I = MBB.end();
|
||||
while (I != MBB.begin()) {
|
||||
--I;
|
||||
if (I->isDebugValue())
|
||||
continue;
|
||||
|
||||
// Working from the bottom, when we see a non-terminator
|
||||
// instruction, we're done.
|
||||
if (!isUnpredicatedTerminator(I))
|
||||
break;
|
||||
|
||||
// A terminator that isn't a branch can't easily be handled
|
||||
// by this analysis.
|
||||
if (!I->isBranch())
|
||||
return true;
|
||||
|
||||
// Handle unconditional branches.
|
||||
if (I->getOpcode() == BPF::JMP) {
|
||||
if (!AllowModify) {
|
||||
TBB = I->getOperand(0).getMBB();
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the block has any instructions after a J, delete them.
|
||||
while (std::next(I) != MBB.end())
|
||||
std::next(I)->eraseFromParent();
|
||||
Cond.clear();
|
||||
FBB = 0;
|
||||
|
||||
// Delete the J if it's equivalent to a fall-through.
|
||||
if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
|
||||
TBB = 0;
|
||||
I->eraseFromParent();
|
||||
I = MBB.end();
|
||||
continue;
|
||||
}
|
||||
|
||||
// TBB is used to indicate the unconditinal destination.
|
||||
TBB = I->getOperand(0).getMBB();
|
||||
continue;
|
||||
}
|
||||
// Cannot handle conditional branches
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned BPFInstrInfo::InsertBranch(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB,
|
||||
const SmallVectorImpl<MachineOperand> &Cond,
|
||||
DebugLoc DL) const {
|
||||
// Shouldn't be a fall through.
|
||||
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
|
||||
|
||||
if (Cond.empty()) {
|
||||
// Unconditional branch
|
||||
assert(!FBB && "Unconditional branch with multiple successors!");
|
||||
BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB);
|
||||
return 1;
|
||||
}
|
||||
|
||||
llvm_unreachable("Unexpected conditional branch");
|
||||
}
|
||||
|
||||
unsigned BPFInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator I = MBB.end();
|
||||
unsigned Count = 0;
|
||||
|
||||
while (I != MBB.begin()) {
|
||||
--I;
|
||||
if (I->isDebugValue())
|
||||
continue;
|
||||
if (I->getOpcode() != BPF::JMP)
|
||||
break;
|
||||
// Remove the branch.
|
||||
I->eraseFromParent();
|
||||
I = MBB.end();
|
||||
++Count;
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
60
lib/Target/BPF/BPFInstrInfo.h
Normal file
60
lib/Target/BPF/BPFInstrInfo.h
Normal file
@ -0,0 +1,60 @@
|
||||
//===-- BPFInstrInfo.h - BPF Instruction Information ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the BPF implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFINSTRINFO_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFINSTRINFO_H
|
||||
|
||||
#include "BPFRegisterInfo.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
|
||||
#define GET_INSTRINFO_HEADER
|
||||
#include "BPFGenInstrInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BPFInstrInfo : public BPFGenInstrInfo {
|
||||
const BPFRegisterInfo RI;
|
||||
|
||||
public:
|
||||
BPFInstrInfo();
|
||||
|
||||
const BPFRegisterInfo &getRegisterInfo() const { return RI; }
|
||||
|
||||
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
DebugLoc DL, unsigned DestReg, unsigned SrcReg,
|
||||
bool KillSrc) const override;
|
||||
|
||||
void storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI, unsigned SrcReg,
|
||||
bool isKill, int FrameIndex,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
|
||||
void loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI, unsigned DestReg,
|
||||
int FrameIndex, const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
|
||||
MachineBasicBlock *&FBB,
|
||||
SmallVectorImpl<MachineOperand> &Cond,
|
||||
bool AllowModify) const override;
|
||||
|
||||
unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
|
||||
unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB,
|
||||
const SmallVectorImpl<MachineOperand> &Cond,
|
||||
DebugLoc DL) const override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
507
lib/Target/BPF/BPFInstrInfo.td
Normal file
507
lib/Target/BPF/BPFInstrInfo.td
Normal file
@ -0,0 +1,507 @@
|
||||
//===-- 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>;
|
77
lib/Target/BPF/BPFMCInstLower.cpp
Normal file
77
lib/Target/BPF/BPFMCInstLower.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
//=-- BPFMCInstLower.cpp - Convert BPF MachineInstr to an MCInst ------------=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains code to lower BPF MachineInstrs to their corresponding
|
||||
// MCInst records.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPFMCInstLower.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
using namespace llvm;
|
||||
|
||||
MCSymbol *
|
||||
BPFMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
|
||||
return Printer.getSymbol(MO.getGlobal());
|
||||
}
|
||||
|
||||
MCOperand BPFMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
|
||||
MCSymbol *Sym) const {
|
||||
|
||||
const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx);
|
||||
|
||||
if (!MO.isJTI() && MO.getOffset())
|
||||
llvm_unreachable("unknown symbol op");
|
||||
|
||||
return MCOperand::CreateExpr(Expr);
|
||||
}
|
||||
|
||||
void BPFMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
|
||||
OutMI.setOpcode(MI->getOpcode());
|
||||
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
const MachineOperand &MO = MI->getOperand(i);
|
||||
|
||||
MCOperand MCOp;
|
||||
switch (MO.getType()) {
|
||||
default:
|
||||
MI->dump();
|
||||
llvm_unreachable("unknown operand type");
|
||||
case MachineOperand::MO_Register:
|
||||
// Ignore all implicit register operands.
|
||||
if (MO.isImplicit())
|
||||
continue;
|
||||
MCOp = MCOperand::CreateReg(MO.getReg());
|
||||
break;
|
||||
case MachineOperand::MO_Immediate:
|
||||
MCOp = MCOperand::CreateImm(MO.getImm());
|
||||
break;
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
MCOp = MCOperand::CreateExpr(
|
||||
MCSymbolRefExpr::Create(MO.getMBB()->getSymbol(), Ctx));
|
||||
break;
|
||||
case MachineOperand::MO_RegisterMask:
|
||||
continue;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
|
||||
break;
|
||||
}
|
||||
|
||||
OutMI.addOperand(MCOp);
|
||||
}
|
||||
}
|
43
lib/Target/BPF/BPFMCInstLower.h
Normal file
43
lib/Target/BPF/BPFMCInstLower.h
Normal file
@ -0,0 +1,43 @@
|
||||
//===-- BPFMCInstLower.h - Lower MachineInstr to MCInst ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFMCINSTLOWER_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFMCINSTLOWER_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
class AsmPrinter;
|
||||
class MCContext;
|
||||
class MCInst;
|
||||
class MCOperand;
|
||||
class MCSymbol;
|
||||
class MachineInstr;
|
||||
class MachineModuleInfoMachO;
|
||||
class MachineOperand;
|
||||
class Mangler;
|
||||
|
||||
// BPFMCInstLower - This class is used to lower an MachineInstr into an MCInst.
|
||||
class LLVM_LIBRARY_VISIBILITY BPFMCInstLower {
|
||||
MCContext &Ctx;
|
||||
|
||||
AsmPrinter &Printer;
|
||||
|
||||
public:
|
||||
BPFMCInstLower(MCContext &ctx, AsmPrinter &printer)
|
||||
: Ctx(ctx), Printer(printer) {}
|
||||
void Lower(const MachineInstr *MI, MCInst &OutMI) const;
|
||||
|
||||
MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
|
||||
|
||||
MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
88
lib/Target/BPF/BPFRegisterInfo.cpp
Normal file
88
lib/Target/BPF/BPFRegisterInfo.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
//===-- BPFRegisterInfo.cpp - BPF Register Information ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the BPF implementation of the TargetRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFRegisterInfo.h"
|
||||
#include "BPFSubtarget.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
|
||||
#define GET_REGINFO_TARGET_DESC
|
||||
#include "BPFGenRegisterInfo.inc"
|
||||
using namespace llvm;
|
||||
|
||||
BPFRegisterInfo::BPFRegisterInfo()
|
||||
: BPFGenRegisterInfo(BPF::R0) {}
|
||||
|
||||
const MCPhysReg *
|
||||
BPFRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
||||
return CSR_SaveList;
|
||||
}
|
||||
|
||||
BitVector BPFRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
|
||||
BitVector Reserved(getNumRegs());
|
||||
Reserved.set(BPF::R10); // R10 is read only frame pointer
|
||||
Reserved.set(BPF::R11); // R11 is pseudo stack pointer
|
||||
return Reserved;
|
||||
}
|
||||
|
||||
void BPFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
int SPAdj, unsigned FIOperandNum,
|
||||
RegScavenger *RS) const {
|
||||
assert(SPAdj == 0 && "Unexpected");
|
||||
|
||||
unsigned i = 0;
|
||||
MachineInstr &MI = *II;
|
||||
MachineFunction &MF = *MI.getParent()->getParent();
|
||||
DebugLoc DL = MI.getDebugLoc();
|
||||
|
||||
while (!MI.getOperand(i).isFI()) {
|
||||
++i;
|
||||
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
|
||||
}
|
||||
|
||||
unsigned FrameReg = getFrameRegister(MF);
|
||||
int FrameIndex = MI.getOperand(i).getIndex();
|
||||
|
||||
if (MI.getOpcode() == BPF::MOV_rr) {
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
|
||||
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
|
||||
MachineBasicBlock &MBB = *MI.getParent();
|
||||
unsigned reg = MI.getOperand(i - 1).getReg();
|
||||
BuildMI(MBB, ++II, DL, TII.get(BPF::ADD_ri), reg)
|
||||
.addReg(reg)
|
||||
.addImm(Offset);
|
||||
return;
|
||||
}
|
||||
|
||||
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
|
||||
MI.getOperand(i + 1).getImm();
|
||||
|
||||
if (!isInt<32>(Offset))
|
||||
llvm_unreachable("bug in frame offset");
|
||||
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i + 1).ChangeToImmediate(Offset);
|
||||
}
|
||||
|
||||
unsigned BPFRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
|
||||
return BPF::R10;
|
||||
}
|
41
lib/Target/BPF/BPFRegisterInfo.h
Normal file
41
lib/Target/BPF/BPFRegisterInfo.h
Normal file
@ -0,0 +1,41 @@
|
||||
//===-- BPFRegisterInfo.h - BPF Register Information Impl -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the BPF implementation of the TargetRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFREGISTERINFO_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFREGISTERINFO_H
|
||||
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
|
||||
#define GET_REGINFO_HEADER
|
||||
#include "BPFGenRegisterInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct BPFRegisterInfo : public BPFGenRegisterInfo {
|
||||
|
||||
BPFRegisterInfo();
|
||||
|
||||
const MCPhysReg *
|
||||
getCalleeSavedRegs(const MachineFunction *MF = nullptr) const override;
|
||||
|
||||
BitVector getReservedRegs(const MachineFunction &MF) const override;
|
||||
|
||||
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
|
||||
unsigned FIOperandNum,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
|
||||
unsigned getFrameRegister(const MachineFunction &MF) const override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
41
lib/Target/BPF/BPFRegisterInfo.td
Normal file
41
lib/Target/BPF/BPFRegisterInfo.td
Normal file
@ -0,0 +1,41 @@
|
||||
//===-- BPFRegisterInfo.td - BPF Register defs -------------*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Declarations that describe the BPF register file
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Registers are identified with 4-bit ID numbers.
|
||||
// Ri - 64-bit integer registers
|
||||
class Ri<bits<16> Enc, string n> : Register<n> {
|
||||
let Namespace = "BPF";
|
||||
let HWEncoding = Enc;
|
||||
}
|
||||
|
||||
// Integer registers
|
||||
def R0 : Ri< 0, "r0">, DwarfRegNum<[0]>;
|
||||
def R1 : Ri< 1, "r1">, DwarfRegNum<[1]>;
|
||||
def R2 : Ri< 2, "r2">, DwarfRegNum<[2]>;
|
||||
def R3 : Ri< 3, "r3">, DwarfRegNum<[3]>;
|
||||
def R4 : Ri< 4, "r4">, DwarfRegNum<[4]>;
|
||||
def R5 : Ri< 5, "r5">, DwarfRegNum<[5]>;
|
||||
def R6 : Ri< 6, "r6">, DwarfRegNum<[6]>;
|
||||
def R7 : Ri< 7, "r7">, DwarfRegNum<[7]>;
|
||||
def R8 : Ri< 8, "r8">, DwarfRegNum<[8]>;
|
||||
def R9 : Ri< 9, "r9">, DwarfRegNum<[9]>;
|
||||
def R10 : Ri<10, "r10">, DwarfRegNum<[10]>;
|
||||
def R11 : Ri<11, "r11">, DwarfRegNum<[11]>;
|
||||
|
||||
// Register classes.
|
||||
def GPR : RegisterClass<"BPF", [i64], 64, (add R1, R2, R3, R4, R5,
|
||||
R6, R7, R8, R9, // callee saved
|
||||
R0, // return value
|
||||
R11, // stack ptr
|
||||
R10 // frame ptr
|
||||
)>;
|
31
lib/Target/BPF/BPFSubtarget.cpp
Normal file
31
lib/Target/BPF/BPFSubtarget.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
//===-- BPFSubtarget.cpp - BPF Subtarget Information ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the BPF specific subclass of TargetSubtargetInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPFSubtarget.h"
|
||||
#include "BPF.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "bpf-subtarget"
|
||||
|
||||
#define GET_SUBTARGETINFO_TARGET_DESC
|
||||
#define GET_SUBTARGETINFO_CTOR
|
||||
#include "BPFGenSubtargetInfo.inc"
|
||||
|
||||
void BPFSubtarget::anchor() {}
|
||||
|
||||
BPFSubtarget::BPFSubtarget(const std::string &TT, const std::string &CPU,
|
||||
const std::string &FS, const TargetMachine &TM)
|
||||
: BPFGenSubtargetInfo(TT, CPU, FS), DL("e-m:e-p:64:64-i64:64-n32:64-S128"),
|
||||
InstrInfo(), FrameLowering(*this), TLInfo(TM), TSInfo(&DL) {}
|
66
lib/Target/BPF/BPFSubtarget.h
Normal file
66
lib/Target/BPF/BPFSubtarget.h
Normal file
@ -0,0 +1,66 @@
|
||||
//===-- BPFSubtarget.h - Define Subtarget for the BPF -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the BPF specific subclass of TargetSubtargetInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFSUBTARGET_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFSUBTARGET_H
|
||||
|
||||
#include "BPFFrameLowering.h"
|
||||
#include "BPFISelLowering.h"
|
||||
#include "BPFInstrInfo.h"
|
||||
#include "llvm/Target/TargetSelectionDAGInfo.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
|
||||
#define GET_SUBTARGETINFO_HEADER
|
||||
#include "BPFGenSubtargetInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
|
||||
class BPFSubtarget : public BPFGenSubtargetInfo {
|
||||
virtual void anchor();
|
||||
const DataLayout DL; // Calculates type size & alignment
|
||||
BPFInstrInfo InstrInfo;
|
||||
BPFFrameLowering FrameLowering;
|
||||
BPFTargetLowering TLInfo;
|
||||
TargetSelectionDAGInfo TSInfo;
|
||||
|
||||
public:
|
||||
// This constructor initializes the data members to match that
|
||||
// of the specified triple.
|
||||
BPFSubtarget(const std::string &TT, const std::string &CPU,
|
||||
const std::string &FS, const TargetMachine &TM);
|
||||
|
||||
// ParseSubtargetFeatures - Parses features string setting specified
|
||||
// subtarget options. Definition of function is auto generated by tblgen.
|
||||
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
|
||||
|
||||
const BPFInstrInfo *getInstrInfo() const override { return &InstrInfo; }
|
||||
const BPFFrameLowering *getFrameLowering() const override {
|
||||
return &FrameLowering;
|
||||
}
|
||||
const BPFTargetLowering *getTargetLowering() const override {
|
||||
return &TLInfo;
|
||||
}
|
||||
const TargetSelectionDAGInfo *getSelectionDAGInfo() const override {
|
||||
return &TSInfo;
|
||||
}
|
||||
const TargetRegisterInfo *getRegisterInfo() const override {
|
||||
return &InstrInfo.getRegisterInfo();
|
||||
}
|
||||
const DataLayout *getDataLayout() const override { return &DL; }
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
68
lib/Target/BPF/BPFTargetMachine.cpp
Normal file
68
lib/Target/BPF/BPFTargetMachine.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
//===-- BPFTargetMachine.cpp - Define TargetMachine for BPF ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements the info about BPF target spec.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFTargetMachine.h"
|
||||
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
using namespace llvm;
|
||||
|
||||
extern "C" void LLVMInitializeBPFTarget() {
|
||||
// Register the target.
|
||||
RegisterTargetMachine<BPFTargetMachine> X(TheBPFTarget);
|
||||
}
|
||||
|
||||
// DataLayout --> Little-endian, 64-bit pointer/ABI/alignment
|
||||
// The stack is always 8 byte aligned
|
||||
// On function prologue, the stack is created by decrementing
|
||||
// its pointer. Once decremented, all references are done with positive
|
||||
// offset from the stack/frame pointer.
|
||||
BPFTargetMachine::BPFTargetMachine(const Target &T, StringRef TT, StringRef CPU,
|
||||
StringRef FS, const TargetOptions &Options,
|
||||
Reloc::Model RM, CodeModel::Model CM,
|
||||
CodeGenOpt::Level OL)
|
||||
: LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
|
||||
TLOF(make_unique<TargetLoweringObjectFileELF>()),
|
||||
Subtarget(TT, CPU, FS, *this) {
|
||||
initAsmInfo();
|
||||
}
|
||||
namespace {
|
||||
// BPF Code Generator Pass Configuration Options.
|
||||
class BPFPassConfig : public TargetPassConfig {
|
||||
public:
|
||||
BPFPassConfig(BPFTargetMachine *TM, PassManagerBase &PM)
|
||||
: TargetPassConfig(TM, PM) {}
|
||||
|
||||
BPFTargetMachine &getBPFTargetMachine() const {
|
||||
return getTM<BPFTargetMachine>();
|
||||
}
|
||||
|
||||
bool addInstSelector() override;
|
||||
};
|
||||
}
|
||||
|
||||
TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) {
|
||||
return new BPFPassConfig(this, PM);
|
||||
}
|
||||
|
||||
// Install an instruction selector pass using
|
||||
// the ISelDag to gen BPF code.
|
||||
bool BPFPassConfig::addInstSelector() {
|
||||
addPass(createBPFISelDag(getBPFTargetMachine()));
|
||||
|
||||
return false;
|
||||
}
|
40
lib/Target/BPF/BPFTargetMachine.h
Normal file
40
lib/Target/BPF/BPFTargetMachine.h
Normal file
@ -0,0 +1,40 @@
|
||||
//===-- BPFTargetMachine.h - Define TargetMachine for BPF --- C++ ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the BPF specific subclass of TargetMachine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_BPFTARGETMACHINE_H
|
||||
#define LLVM_LIB_TARGET_BPF_BPFTARGETMACHINE_H
|
||||
|
||||
#include "BPFSubtarget.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
namespace llvm {
|
||||
class BPFTargetMachine : public LLVMTargetMachine {
|
||||
std::unique_ptr<TargetLoweringObjectFile> TLOF;
|
||||
BPFSubtarget Subtarget;
|
||||
|
||||
public:
|
||||
BPFTargetMachine(const Target &T, StringRef TT, StringRef CPU, StringRef FS,
|
||||
const TargetOptions &Options, Reloc::Model RM,
|
||||
CodeModel::Model CM, CodeGenOpt::Level OL);
|
||||
|
||||
const BPFSubtarget *getSubtargetImpl() const override { return &Subtarget; }
|
||||
|
||||
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
|
||||
|
||||
TargetLoweringObjectFile *getObjFileLowering() const override {
|
||||
return TLOF.get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
27
lib/Target/BPF/CMakeLists.txt
Normal file
27
lib/Target/BPF/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
set(LLVM_TARGET_DEFINITIONS BPF.td)
|
||||
|
||||
tablegen(LLVM BPFGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM BPFGenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM BPFGenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM X86GenAsmMatcher.inc -gen-asm-matcher)
|
||||
tablegen(LLVM BPFGenDAGISel.inc -gen-dag-isel)
|
||||
tablegen(LLVM BPFGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM BPFGenCallingConv.inc -gen-callingconv)
|
||||
tablegen(LLVM BPFGenSubtargetInfo.inc -gen-subtarget)
|
||||
add_public_tablegen_target(BPFCommonTableGen)
|
||||
|
||||
add_llvm_target(BPFCodeGen
|
||||
BPFAsmPrinter.cpp
|
||||
BPFFrameLowering.cpp
|
||||
BPFInstrInfo.cpp
|
||||
BPFISelDAGToDAG.cpp
|
||||
BPFISelLowering.cpp
|
||||
BPFMCInstLower.cpp
|
||||
BPFRegisterInfo.cpp
|
||||
BPFSubtarget.cpp
|
||||
BPFTargetMachine.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(InstPrinter)
|
||||
add_subdirectory(TargetInfo)
|
||||
add_subdirectory(MCTargetDesc)
|
86
lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
Normal file
86
lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
//===-- BPFInstPrinter.cpp - Convert BPF MCInst to asm syntax -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class prints an BPF MCInst to a .s file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFInstPrinter.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
|
||||
// Include the auto-generated portion of the assembly writer.
|
||||
#include "BPFGenAsmWriter.inc"
|
||||
|
||||
void BPFInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
|
||||
StringRef Annot) {
|
||||
printInstruction(MI, O);
|
||||
printAnnotation(O, Annot);
|
||||
}
|
||||
|
||||
static void printExpr(const MCExpr *Expr, raw_ostream &O) {
|
||||
const MCSymbolRefExpr *SRE;
|
||||
|
||||
if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
|
||||
SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());
|
||||
else
|
||||
SRE = dyn_cast<MCSymbolRefExpr>(Expr);
|
||||
assert(SRE && "Unexpected MCExpr type.");
|
||||
|
||||
MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
|
||||
|
||||
assert(Kind == MCSymbolRefExpr::VK_None);
|
||||
O << *Expr;
|
||||
}
|
||||
|
||||
void BPFInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
||||
raw_ostream &O, const char *Modifier) {
|
||||
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
|
||||
const MCOperand &Op = MI->getOperand(OpNo);
|
||||
if (Op.isReg()) {
|
||||
O << getRegisterName(Op.getReg());
|
||||
} else if (Op.isImm()) {
|
||||
O << (int32_t)Op.getImm();
|
||||
} else {
|
||||
assert(Op.isExpr() && "Expected an expression");
|
||||
printExpr(Op.getExpr(), O);
|
||||
}
|
||||
}
|
||||
|
||||
void BPFInstPrinter::printMemOperand(const MCInst *MI, int OpNo, raw_ostream &O,
|
||||
const char *Modifier) {
|
||||
const MCOperand &RegOp = MI->getOperand(OpNo);
|
||||
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
|
||||
// offset
|
||||
if (OffsetOp.isImm())
|
||||
O << formatDec(OffsetOp.getImm());
|
||||
else
|
||||
assert(0 && "Expected an immediate");
|
||||
|
||||
// register
|
||||
assert(RegOp.isReg() && "Register operand not a register");
|
||||
O << '(' << getRegisterName(RegOp.getReg()) << ')';
|
||||
}
|
||||
|
||||
void BPFInstPrinter::printImm64Operand(const MCInst *MI, unsigned OpNo,
|
||||
raw_ostream &O) {
|
||||
const MCOperand &Op = MI->getOperand(OpNo);
|
||||
if (Op.isImm())
|
||||
O << (uint64_t)Op.getImm();
|
||||
else
|
||||
O << Op;
|
||||
}
|
41
lib/Target/BPF/InstPrinter/BPFInstPrinter.h
Normal file
41
lib/Target/BPF/InstPrinter/BPFInstPrinter.h
Normal file
@ -0,0 +1,41 @@
|
||||
//===-- BPFInstPrinter.h - Convert BPF MCInst to asm syntax -------*- C++ -*--//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class prints a BPF MCInst to a .s file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_INSTPRINTER_BPFINSTPRINTER_H
|
||||
#define LLVM_LIB_TARGET_BPF_INSTPRINTER_BPFINSTPRINTER_H
|
||||
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
|
||||
namespace llvm {
|
||||
class MCOperand;
|
||||
|
||||
class BPFInstPrinter : public MCInstPrinter {
|
||||
public:
|
||||
BPFInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
|
||||
const MCRegisterInfo &MRI)
|
||||
: MCInstPrinter(MAI, MII, MRI) {}
|
||||
|
||||
void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot) override;
|
||||
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
|
||||
const char *Modifier = nullptr);
|
||||
void printMemOperand(const MCInst *MI, int OpNo, raw_ostream &O,
|
||||
const char *Modifier = nullptr);
|
||||
void printImm64Operand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
||||
|
||||
// Autogenerated by tblgen.
|
||||
void printInstruction(const MCInst *MI, raw_ostream &O);
|
||||
static const char *getRegisterName(unsigned RegNo);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
3
lib/Target/BPF/InstPrinter/CMakeLists.txt
Normal file
3
lib/Target/BPF/InstPrinter/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMBPFAsmPrinter
|
||||
BPFInstPrinter.cpp
|
||||
)
|
23
lib/Target/BPF/InstPrinter/LLVMBuild.txt
Normal file
23
lib/Target/BPF/InstPrinter/LLVMBuild.txt
Normal file
@ -0,0 +1,23 @@
|
||||
;===- ./lib/Target/BPF/InstPrinter/LLVMBuild.txt ---------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = BPFAsmPrinter
|
||||
parent = BPF
|
||||
required_libraries = MC Support
|
||||
add_to_library_groups = BPF
|
16
lib/Target/BPF/InstPrinter/Makefile
Normal file
16
lib/Target/BPF/InstPrinter/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
##===- lib/Target/BPF/InstPrinter/Makefile -----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../../..
|
||||
LIBRARYNAME = LLVMBPFAsmPrinter
|
||||
|
||||
# Hack: we need to include 'main' BPF target directory to grab private headers
|
||||
CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
32
lib/Target/BPF/LLVMBuild.txt
Normal file
32
lib/Target/BPF/LLVMBuild.txt
Normal file
@ -0,0 +1,32 @@
|
||||
;===- ./lib/Target/BPF/LLVMBuild.txt ---------------------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = InstPrinter MCTargetDesc TargetInfo
|
||||
|
||||
[component_0]
|
||||
type = TargetGroup
|
||||
name = BPF
|
||||
parent = Target
|
||||
has_asmprinter = 1
|
||||
|
||||
[component_1]
|
||||
type = Library
|
||||
name = BPFCodeGen
|
||||
parent = BPF
|
||||
required_libraries = AsmPrinter CodeGen Core MC BPFAsmPrinter BPFDesc BPFInfo SelectionDAG Support Target
|
||||
add_to_library_groups = BPF
|
83
lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
Normal file
83
lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
//===-- BPFAsmBackend.cpp - BPF Assembler Backend -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCTargetDesc/BPFMCTargetDesc.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAssembler.h"
|
||||
#include "llvm/MC/MCDirectives.h"
|
||||
#include "llvm/MC/MCELFObjectWriter.h"
|
||||
#include "llvm/MC/MCFixupKindInfo.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class BPFAsmBackend : public MCAsmBackend {
|
||||
public:
|
||||
BPFAsmBackend() : MCAsmBackend() {}
|
||||
~BPFAsmBackend() override {}
|
||||
|
||||
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
|
||||
uint64_t Value, bool IsPCRel) const override;
|
||||
|
||||
MCObjectWriter *createObjectWriter(raw_ostream &OS) const override;
|
||||
|
||||
// No instruction requires relaxation
|
||||
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||
const MCRelaxableFragment *DF,
|
||||
const MCAsmLayout &Layout) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned getNumFixupKinds() const override { return 1; }
|
||||
|
||||
bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
|
||||
|
||||
void relaxInstruction(const MCInst &Inst, MCInst &Res) const override {}
|
||||
|
||||
bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
|
||||
};
|
||||
|
||||
bool BPFAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
|
||||
if ((Count % 8) != 0)
|
||||
return false;
|
||||
|
||||
for (uint64_t i = 0; i < Count; i += 8)
|
||||
OW->Write64(0x15000000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BPFAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
|
||||
unsigned DataSize, uint64_t Value,
|
||||
bool IsPCRel) const {
|
||||
|
||||
if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) {
|
||||
assert(Value == 0);
|
||||
return;
|
||||
}
|
||||
assert(Fixup.getKind() == FK_PCRel_2);
|
||||
*(uint16_t *)&Data[Fixup.getOffset() + 2] = (uint16_t)((Value - 8) / 8);
|
||||
}
|
||||
|
||||
MCObjectWriter *BPFAsmBackend::createObjectWriter(raw_ostream &OS) const {
|
||||
return createBPFELFObjectWriter(OS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
MCAsmBackend *llvm::createBPFAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI, StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new BPFAsmBackend();
|
||||
}
|
53
lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
Normal file
53
lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
//===-- BPFELFObjectWriter.cpp - BPF ELF Writer ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCTargetDesc/BPFMCTargetDesc.h"
|
||||
#include "llvm/MC/MCELFObjectWriter.h"
|
||||
#include "llvm/MC/MCFixup.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class BPFELFObjectWriter : public MCELFObjectTargetWriter {
|
||||
public:
|
||||
BPFELFObjectWriter(uint8_t OSABI);
|
||||
|
||||
~BPFELFObjectWriter() override;
|
||||
|
||||
protected:
|
||||
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
|
||||
bool IsPCRel) const override;
|
||||
};
|
||||
}
|
||||
|
||||
BPFELFObjectWriter::BPFELFObjectWriter(uint8_t OSABI)
|
||||
: MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_NONE,
|
||||
/*HasRelocationAddend*/ false) {}
|
||||
|
||||
BPFELFObjectWriter::~BPFELFObjectWriter() {}
|
||||
|
||||
unsigned BPFELFObjectWriter::GetRelocType(const MCValue &Target,
|
||||
const MCFixup &Fixup,
|
||||
bool IsPCRel) const {
|
||||
// determine the type of the relocation
|
||||
switch ((unsigned)Fixup.getKind()) {
|
||||
default:
|
||||
llvm_unreachable("invalid fixup kind!");
|
||||
case FK_SecRel_8:
|
||||
return ELF::R_X86_64_64;
|
||||
case FK_SecRel_4:
|
||||
return ELF::R_X86_64_PC32;
|
||||
}
|
||||
}
|
||||
|
||||
MCObjectWriter *llvm::createBPFELFObjectWriter(raw_ostream &OS, uint8_t OSABI) {
|
||||
MCELFObjectTargetWriter *MOTW = new BPFELFObjectWriter(OSABI);
|
||||
return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true);
|
||||
}
|
36
lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
Normal file
36
lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
Normal file
@ -0,0 +1,36 @@
|
||||
//===-- BPFMCAsmInfo.h - BPF asm properties -------------------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the BPFMCAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_MCTARGETDESC_BPFMCASMINFO_H
|
||||
#define LLVM_LIB_TARGET_BPF_MCTARGETDESC_BPFMCASMINFO_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class Target;
|
||||
|
||||
class BPFMCAsmInfo : public MCAsmInfo {
|
||||
public:
|
||||
explicit BPFMCAsmInfo(StringRef TT) {
|
||||
PrivateGlobalPrefix = ".L";
|
||||
WeakRefDirective = "\t.weak\t";
|
||||
|
||||
UsesELFSectionDirectiveForBSS = true;
|
||||
HasSingleParameterDotFile = false;
|
||||
HasDotTypeDotSizeDirective = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
167
lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
Normal file
167
lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
//===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the BPFMCCodeEmitter class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCTargetDesc/BPFMCTargetDesc.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCFixup.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "mccodeemitter"
|
||||
|
||||
namespace {
|
||||
class BPFMCCodeEmitter : public MCCodeEmitter {
|
||||
BPFMCCodeEmitter(const BPFMCCodeEmitter &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const BPFMCCodeEmitter &) LLVM_DELETED_FUNCTION;
|
||||
const MCRegisterInfo &MRI;
|
||||
|
||||
public:
|
||||
BPFMCCodeEmitter(const MCRegisterInfo &mri) : MRI(mri) {}
|
||||
|
||||
~BPFMCCodeEmitter() {}
|
||||
|
||||
// getBinaryCodeForInstr - TableGen'erated function for getting the
|
||||
// binary encoding for an instruction.
|
||||
uint64_t getBinaryCodeForInstr(const MCInst &MI,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
// getMachineOpValue - Return binary encoding of operand. If the machin
|
||||
// operand requires relocation, record the relocation and return zero.
|
||||
unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const override;
|
||||
};
|
||||
}
|
||||
|
||||
MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCRegisterInfo &MRI,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx) {
|
||||
return new BPFMCCodeEmitter(MRI);
|
||||
}
|
||||
|
||||
unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
|
||||
const MCOperand &MO,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
if (MO.isReg())
|
||||
return MRI.getEncodingValue(MO.getReg());
|
||||
if (MO.isImm())
|
||||
return static_cast<unsigned>(MO.getImm());
|
||||
|
||||
assert(MO.isExpr());
|
||||
|
||||
const MCExpr *Expr = MO.getExpr();
|
||||
MCExpr::ExprKind Kind = Expr->getKind();
|
||||
|
||||
assert(Kind == MCExpr::SymbolRef);
|
||||
|
||||
if (MI.getOpcode() == BPF::JAL)
|
||||
// func call name
|
||||
Fixups.push_back(MCFixup::Create(0, Expr, FK_SecRel_4));
|
||||
else if (MI.getOpcode() == BPF::LD_imm64)
|
||||
Fixups.push_back(MCFixup::Create(0, Expr, FK_SecRel_8));
|
||||
else
|
||||
// bb label
|
||||
Fixups.push_back(MCFixup::Create(0, Expr, FK_PCRel_2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Emit one byte through output stream
|
||||
void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) {
|
||||
OS << (char)C;
|
||||
++CurByte;
|
||||
}
|
||||
|
||||
// Emit a series of bytes (little endian)
|
||||
void EmitLEConstant(uint64_t Val, unsigned Size, unsigned &CurByte,
|
||||
raw_ostream &OS) {
|
||||
assert(Size <= 8 && "size too big in emit constant");
|
||||
|
||||
for (unsigned i = 0; i != Size; ++i) {
|
||||
EmitByte(Val & 255, CurByte, OS);
|
||||
Val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit a series of bytes (big endian)
|
||||
void EmitBEConstant(uint64_t Val, unsigned Size, unsigned &CurByte,
|
||||
raw_ostream &OS) {
|
||||
assert(Size <= 8 && "size too big in emit constant");
|
||||
|
||||
for (int i = (Size - 1) * 8; i >= 0; i -= 8)
|
||||
EmitByte((Val >> i) & 255, CurByte, OS);
|
||||
}
|
||||
|
||||
void BPFMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
unsigned Opcode = MI.getOpcode();
|
||||
// Keep track of the current byte being emitted
|
||||
unsigned CurByte = 0;
|
||||
|
||||
if (Opcode == BPF::LD_imm64) {
|
||||
uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);
|
||||
EmitByte(Value >> 56, CurByte, OS);
|
||||
EmitByte(((Value >> 48) & 0xff), CurByte, OS);
|
||||
EmitLEConstant(0, 2, CurByte, OS);
|
||||
EmitLEConstant(Value & 0xffffFFFF, 4, CurByte, OS);
|
||||
|
||||
const MCOperand &MO = MI.getOperand(1);
|
||||
uint64_t Imm = MO.isImm() ? MO.getImm() : 0;
|
||||
EmitByte(0, CurByte, OS);
|
||||
EmitByte(0, CurByte, OS);
|
||||
EmitLEConstant(0, 2, CurByte, OS);
|
||||
EmitLEConstant(Imm >> 32, 4, CurByte, OS);
|
||||
} else {
|
||||
// Get instruction encoding and emit it
|
||||
uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);
|
||||
EmitByte(Value >> 56, CurByte, OS);
|
||||
EmitByte((Value >> 48) & 0xff, CurByte, OS);
|
||||
EmitLEConstant((Value >> 32) & 0xffff, 2, CurByte, OS);
|
||||
EmitLEConstant(Value & 0xffffFFFF, 4, CurByte, OS);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode BPF Memory Operand
|
||||
uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
uint64_t Encoding;
|
||||
const MCOperand Op1 = MI.getOperand(1);
|
||||
assert(Op1.isReg() && "First operand is not register.");
|
||||
Encoding = MRI.getEncodingValue(Op1.getReg());
|
||||
Encoding <<= 16;
|
||||
MCOperand Op2 = MI.getOperand(2);
|
||||
assert(Op2.isImm() && "Second operand is not immediate.");
|
||||
Encoding |= Op2.getImm() & 0xffff;
|
||||
return Encoding;
|
||||
}
|
||||
|
||||
#include "BPFGenMCCodeEmitter.inc"
|
111
lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
Normal file
111
lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
//===-- BPFMCTargetDesc.cpp - BPF Target Descriptions ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides BPF specific target descriptions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "BPFMCTargetDesc.h"
|
||||
#include "BPFMCAsmInfo.h"
|
||||
#include "InstPrinter/BPFInstPrinter.h"
|
||||
#include "llvm/MC/MCCodeGenInfo.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
#define GET_INSTRINFO_MC_DESC
|
||||
#include "BPFGenInstrInfo.inc"
|
||||
|
||||
#define GET_SUBTARGETINFO_MC_DESC
|
||||
#include "BPFGenSubtargetInfo.inc"
|
||||
|
||||
#define GET_REGINFO_MC_DESC
|
||||
#include "BPFGenRegisterInfo.inc"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static MCInstrInfo *createBPFMCInstrInfo() {
|
||||
MCInstrInfo *X = new MCInstrInfo();
|
||||
InitBPFMCInstrInfo(X);
|
||||
return X;
|
||||
}
|
||||
|
||||
static MCRegisterInfo *createBPFMCRegisterInfo(StringRef TT) {
|
||||
MCRegisterInfo *X = new MCRegisterInfo();
|
||||
InitBPFMCRegisterInfo(X, BPF::R11 /* RAReg doesn't exist */);
|
||||
return X;
|
||||
}
|
||||
|
||||
static MCSubtargetInfo *createBPFMCSubtargetInfo(StringRef TT, StringRef CPU,
|
||||
StringRef FS) {
|
||||
MCSubtargetInfo *X = new MCSubtargetInfo();
|
||||
InitBPFMCSubtargetInfo(X, TT, CPU, FS);
|
||||
return X;
|
||||
}
|
||||
|
||||
static MCCodeGenInfo *createBPFMCCodeGenInfo(StringRef TT, Reloc::Model RM,
|
||||
CodeModel::Model CM,
|
||||
CodeGenOpt::Level OL) {
|
||||
MCCodeGenInfo *X = new MCCodeGenInfo();
|
||||
X->InitMCCodeGenInfo(RM, CM, OL);
|
||||
return X;
|
||||
}
|
||||
|
||||
static MCStreamer *createBPFMCStreamer(const Target &T, StringRef TT,
|
||||
MCContext &Ctx, MCAsmBackend &MAB,
|
||||
raw_ostream &_OS,
|
||||
MCCodeEmitter *_Emitter,
|
||||
const MCSubtargetInfo &STI,
|
||||
bool RelaxAll) {
|
||||
return createELFStreamer(Ctx, MAB, _OS, _Emitter, RelaxAll);
|
||||
}
|
||||
|
||||
static MCInstPrinter *
|
||||
createBPFMCInstPrinter(const Target &T, unsigned SyntaxVariant,
|
||||
const MCAsmInfo &MAI, const MCInstrInfo &MII,
|
||||
const MCRegisterInfo &MRI, const MCSubtargetInfo &STI) {
|
||||
if (SyntaxVariant == 0)
|
||||
return new BPFInstPrinter(MAI, MII, MRI);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void LLVMInitializeBPFTargetMC() {
|
||||
// Register the MC asm info.
|
||||
RegisterMCAsmInfo<BPFMCAsmInfo> X(TheBPFTarget);
|
||||
|
||||
// Register the MC codegen info.
|
||||
TargetRegistry::RegisterMCCodeGenInfo(TheBPFTarget, createBPFMCCodeGenInfo);
|
||||
|
||||
// Register the MC instruction info.
|
||||
TargetRegistry::RegisterMCInstrInfo(TheBPFTarget, createBPFMCInstrInfo);
|
||||
|
||||
// Register the MC register info.
|
||||
TargetRegistry::RegisterMCRegInfo(TheBPFTarget, createBPFMCRegisterInfo);
|
||||
|
||||
// Register the MC subtarget info.
|
||||
TargetRegistry::RegisterMCSubtargetInfo(TheBPFTarget,
|
||||
createBPFMCSubtargetInfo);
|
||||
|
||||
// Register the MC code emitter
|
||||
TargetRegistry::RegisterMCCodeEmitter(TheBPFTarget,
|
||||
llvm::createBPFMCCodeEmitter);
|
||||
|
||||
// Register the ASM Backend
|
||||
TargetRegistry::RegisterMCAsmBackend(TheBPFTarget, createBPFAsmBackend);
|
||||
|
||||
// Register the object streamer
|
||||
TargetRegistry::RegisterMCObjectStreamer(TheBPFTarget, createBPFMCStreamer);
|
||||
|
||||
// Register the MCInstPrinter.
|
||||
TargetRegistry::RegisterMCInstPrinter(TheBPFTarget, createBPFMCInstPrinter);
|
||||
}
|
59
lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
Normal file
59
lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
Normal file
@ -0,0 +1,59 @@
|
||||
//===-- BPFMCTargetDesc.h - BPF Target Descriptions -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides BPF specific target descriptions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_BPF_MCTARGETDESC_BPFMCTARGETDESC_H
|
||||
#define LLVM_LIB_TARGET_BPF_MCTARGETDESC_BPFMCTARGETDESC_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Config/config.h"
|
||||
|
||||
namespace llvm {
|
||||
class MCAsmBackend;
|
||||
class MCCodeEmitter;
|
||||
class MCContext;
|
||||
class MCInstrInfo;
|
||||
class MCObjectWriter;
|
||||
class MCRegisterInfo;
|
||||
class MCSubtargetInfo;
|
||||
class Target;
|
||||
class StringRef;
|
||||
class raw_ostream;
|
||||
|
||||
extern Target TheBPFTarget;
|
||||
|
||||
MCCodeEmitter *createBPFMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCRegisterInfo &MRI,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
|
||||
MCAsmBackend *createBPFAsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
StringRef TT, StringRef CPU);
|
||||
|
||||
MCObjectWriter *createBPFELFObjectWriter(raw_ostream &OS, uint8_t OSABI);
|
||||
}
|
||||
|
||||
// Defines symbolic names for BPF registers. This defines a mapping from
|
||||
// register name to register number.
|
||||
//
|
||||
#define GET_REGINFO_ENUM
|
||||
#include "BPFGenRegisterInfo.inc"
|
||||
|
||||
// Defines symbolic names for the BPF instructions.
|
||||
//
|
||||
#define GET_INSTRINFO_ENUM
|
||||
#include "BPFGenInstrInfo.inc"
|
||||
|
||||
#define GET_SUBTARGETINFO_ENUM
|
||||
#include "BPFGenSubtargetInfo.inc"
|
||||
|
||||
#endif
|
6
lib/Target/BPF/MCTargetDesc/CMakeLists.txt
Normal file
6
lib/Target/BPF/MCTargetDesc/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
add_llvm_library(LLVMBPFDesc
|
||||
BPFMCTargetDesc.cpp
|
||||
BPFAsmBackend.cpp
|
||||
BPFMCCodeEmitter.cpp
|
||||
BPFELFObjectWriter.cpp
|
||||
)
|
23
lib/Target/BPF/MCTargetDesc/LLVMBuild.txt
Normal file
23
lib/Target/BPF/MCTargetDesc/LLVMBuild.txt
Normal file
@ -0,0 +1,23 @@
|
||||
;===- ./lib/Target/BPF/MCTargetDesc/LLVMBuild.txt --------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = BPFDesc
|
||||
parent = BPF
|
||||
required_libraries = MC BPFAsmPrinter BPFInfo
|
||||
add_to_library_groups = BPF
|
16
lib/Target/BPF/MCTargetDesc/Makefile
Normal file
16
lib/Target/BPF/MCTargetDesc/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
##===- lib/Target/BPF/MCTargetDesc/Makefile ----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../../..
|
||||
LIBRARYNAME = LLVMBPFDesc
|
||||
|
||||
# Hack: we need to include 'main' target directory to grab private headers
|
||||
CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
21
lib/Target/BPF/Makefile
Normal file
21
lib/Target/BPF/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
##===- lib/Target/BPF/Makefile -----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = LLVMBPFCodeGen
|
||||
TARGET = BPF
|
||||
|
||||
# Make sure that tblgen is run, first thing.
|
||||
BUILT_SOURCES = BPFGenRegisterInfo.inc BPFGenInstrInfo.inc \
|
||||
BPFGenAsmWriter.inc BPFGenAsmMatcher.inc BPFGenDAGISel.inc \
|
||||
BPFGenMCCodeEmitter.inc BPFGenSubtargetInfo.inc BPFGenCallingConv.inc
|
||||
|
||||
DIRS = InstPrinter TargetInfo MCTargetDesc
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
18
lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
Normal file
18
lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
//===-- BPFTargetInfo.cpp - BPF Target Implementation ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BPF.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
using namespace llvm;
|
||||
|
||||
Target llvm::TheBPFTarget;
|
||||
|
||||
extern "C" void LLVMInitializeBPFTargetInfo() {
|
||||
RegisterTarget<Triple::bpf> X(TheBPFTarget, "bpf", "BPF");
|
||||
}
|
3
lib/Target/BPF/TargetInfo/CMakeLists.txt
Normal file
3
lib/Target/BPF/TargetInfo/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMBPFInfo
|
||||
BPFTargetInfo.cpp
|
||||
)
|
23
lib/Target/BPF/TargetInfo/LLVMBuild.txt
Normal file
23
lib/Target/BPF/TargetInfo/LLVMBuild.txt
Normal file
@ -0,0 +1,23 @@
|
||||
;===- ./lib/Target/BPF/TargetInfo/LLVMBuild.txt ----------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = BPFInfo
|
||||
parent = BPF
|
||||
required_libraries = Support
|
||||
add_to_library_groups = BPF
|
16
lib/Target/BPF/TargetInfo/Makefile
Normal file
16
lib/Target/BPF/TargetInfo/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
##===- lib/Target/BPF/TargetInfo/Makefile ------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../../..
|
||||
LIBRARYNAME = LLVMBPFInfo
|
||||
|
||||
# Hack: we need to include 'main' target directory to grab private headers
|
||||
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
@ -16,7 +16,7 @@
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = ARM AArch64 CppBackend Hexagon MSP430 NVPTX Mips PowerPC R600 Sparc SystemZ X86 XCore
|
||||
subdirectories = ARM AArch64 BPF CppBackend Hexagon MSP430 NVPTX Mips PowerPC R600 Sparc SystemZ X86 XCore
|
||||
|
||||
; This is a special group whose required libraries are extended (by llvm-build)
|
||||
; with the best execution engine (the native JIT, if available, or the
|
||||
|
46
test/CodeGen/BPF/alu8.ll
Normal file
46
test/CodeGen/BPF/alu8.ll
Normal file
@ -0,0 +1,46 @@
|
||||
; RUN: llc -march=bpf -show-mc-encoding < %s | FileCheck %s
|
||||
; test little endian only for now
|
||||
|
||||
define i8 @mov(i8 %a, i8 %b) nounwind {
|
||||
; CHECK-LABEL: mov:
|
||||
; CHECK: mov r0, r2 # encoding: [0xbf,0x20,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
; CHECK: ret # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
ret i8 %b
|
||||
}
|
||||
|
||||
define i8 @add(i8 %a, i8 %b) nounwind {
|
||||
; CHECK-LABEL: add:
|
||||
; CHECK: add r1, r2 # encoding: [0x0f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
; CHECK: mov r0, r1 # encoding: [0xbf,0x10,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%1 = add i8 %a, %b
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
define i8 @and(i8 %a, i8 %b) nounwind {
|
||||
; CHECK-LABEL: and:
|
||||
; CHECK: and r1, r2 # encoding: [0x5f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%1 = and i8 %a, %b
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
define i8 @bis(i8 %a, i8 %b) nounwind {
|
||||
; CHECK-LABEL: bis:
|
||||
; CHECK: or r1, r2 # encoding: [0x4f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%1 = or i8 %a, %b
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
define i8 @xorand(i8 %a, i8 %b) nounwind {
|
||||
; CHECK-LABEL: xorand:
|
||||
; CHECK: xori r2, -1 # encoding: [0xa7,0x02,0x00,0x00,0xff,0xff,0xff,0xff]
|
||||
%1 = xor i8 %b, -1
|
||||
%2 = and i8 %a, %1
|
||||
ret i8 %2
|
||||
}
|
||||
|
||||
define i8 @xor(i8 %a, i8 %b) nounwind {
|
||||
; CHECK-LABEL: xor:
|
||||
; CHECK: xor r1, r2 # encoding: [0xaf,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%1 = xor i8 %a, %b
|
||||
ret i8 %1
|
||||
}
|
20
test/CodeGen/BPF/atomics.ll
Normal file
20
test/CodeGen/BPF/atomics.ll
Normal file
@ -0,0 +1,20 @@
|
||||
; RUN: llc < %s -march=bpf -verify-machineinstrs -show-mc-encoding | FileCheck %s
|
||||
; test little endian only for now
|
||||
|
||||
; CHECK-LABEL: test_load_add_32
|
||||
; CHECK: xadd32
|
||||
; CHECK: encoding: [0xc3
|
||||
define void @test_load_add_32(i32* %p, i32 zeroext %v) {
|
||||
entry:
|
||||
atomicrmw add i32* %p, i32 %v seq_cst
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: test_load_add_64
|
||||
; CHECK: xadd64
|
||||
; CHECK: encoding: [0xdb
|
||||
define void @test_load_add_64(i64* %p, i64 zeroext %v) {
|
||||
entry:
|
||||
atomicrmw add i64* %p, i64 %v seq_cst
|
||||
ret void
|
||||
}
|
28
test/CodeGen/BPF/basictest.ll
Normal file
28
test/CodeGen/BPF/basictest.ll
Normal file
@ -0,0 +1,28 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
define i32 @test0(i32 %X) {
|
||||
%tmp.1 = add i32 %X, 1
|
||||
ret i32 %tmp.1
|
||||
; CHECK-LABEL: test0:
|
||||
; CHECK: addi r1, 1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: store_imm:
|
||||
; CHECK: stw 0(r1), r0
|
||||
; CHECK: stw 4(r2), r0
|
||||
define i32 @store_imm(i32* %a, i32* %b) {
|
||||
entry:
|
||||
store i32 0, i32* %a, align 4
|
||||
%0 = getelementptr inbounds i32* %b, i32 1
|
||||
store i32 0, i32* %0, align 4
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
@G = external global i8
|
||||
define zeroext i8 @loadG() {
|
||||
%tmp = load i8* @G
|
||||
ret i8 %tmp
|
||||
; CHECK-LABEL: loadG:
|
||||
; CHECK: ld_64 r1
|
||||
; CHECK: ldb r0, 0(r1)
|
||||
}
|
27
test/CodeGen/BPF/byval.ll
Normal file
27
test/CodeGen/BPF/byval.ll
Normal file
@ -0,0 +1,27 @@
|
||||
; RUN: not llc -march=bpf < %s 2> %t1
|
||||
; RUN: FileCheck %s < %t1
|
||||
; CHECK: by value not supported
|
||||
|
||||
%struct.S = type { [10 x i32] }
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @bar(i32 %a) #0 {
|
||||
entry:
|
||||
%.compoundliteral = alloca %struct.S, align 8
|
||||
%arrayinit.begin = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 0
|
||||
store i32 1, i32* %arrayinit.begin, align 8
|
||||
%arrayinit.element = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 1
|
||||
store i32 2, i32* %arrayinit.element, align 4
|
||||
%arrayinit.element2 = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 2
|
||||
store i32 3, i32* %arrayinit.element2, align 8
|
||||
%arrayinit.start = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 3
|
||||
%scevgep4 = bitcast i32* %arrayinit.start to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* %scevgep4, i8 0, i64 28, i32 4, i1 false)
|
||||
call void @foo(i32 %a, %struct.S* byval align 8 %.compoundliteral) #3
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @foo(i32, %struct.S* byval align 8) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #3
|
96
test/CodeGen/BPF/cc_args.ll
Normal file
96
test/CodeGen/BPF/cc_args.ll
Normal file
@ -0,0 +1,96 @@
|
||||
; RUN: llc < %s -march=bpf -show-mc-encoding | FileCheck %s
|
||||
; test little endian only for now
|
||||
|
||||
define void @test() #0 {
|
||||
entry:
|
||||
; CHECK: test:
|
||||
|
||||
; CHECK: mov r1, 123 # encoding: [0xb7,0x01,0x00,0x00,0x7b,0x00,0x00,0x00]
|
||||
; CHECK: call f_i16
|
||||
call void @f_i16(i16 123)
|
||||
|
||||
; CHECK: mov r1, 12345678 # encoding: [0xb7,0x01,0x00,0x00,0x4e,0x61,0xbc,0x00]
|
||||
; CHECK: call f_i32
|
||||
call void @f_i32(i32 12345678)
|
||||
|
||||
; CHECK: ld_64 r1, 72623859790382856 # encoding: [0x18,0x01,0x00,0x00,0x08,0x07,0x06,0x05,0x00,0x00,0x00,0x00,0x04,0x03,0x02,0x01]
|
||||
; CHECK: call f_i64
|
||||
call void @f_i64(i64 72623859790382856)
|
||||
|
||||
; CHECK: mov r1, 1234
|
||||
; CHECK: mov r2, 5678
|
||||
; CHECK: call f_i32_i32
|
||||
call void @f_i32_i32(i32 1234, i32 5678)
|
||||
|
||||
; CHECK: mov r1, 2
|
||||
; CHECK: mov r2, 3
|
||||
; CHECK: mov r3, 4
|
||||
; CHECK: call f_i16_i32_i16
|
||||
call void @f_i16_i32_i16(i16 2, i32 3, i16 4)
|
||||
|
||||
; CHECK: mov r1, 5
|
||||
; CHECK: ld_64 r2, 7262385979038285
|
||||
; CHECK: mov r3, 6
|
||||
; CHECK: call f_i16_i64_i16
|
||||
call void @f_i16_i64_i16(i16 5, i64 7262385979038285, i16 6)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
@g_i16 = common global i16 0, align 2
|
||||
@g_i32 = common global i32 0, align 2
|
||||
@g_i64 = common global i64 0, align 4
|
||||
|
||||
define void @f_i16(i16 %a) #0 {
|
||||
; CHECK: f_i16:
|
||||
; CHECK: sth 0(r2), r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
store volatile i16 %a, i16* @g_i16, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_i32(i32 %a) #0 {
|
||||
; CHECK: f_i32:
|
||||
; CHECK: sth 0(r2), r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
; CHECK: sth 2(r2), r1 # encoding: [0x6b,0x12,0x02,0x00,0x00,0x00,0x00,0x00]
|
||||
store volatile i32 %a, i32* @g_i32, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_i64(i64 %a) #0 {
|
||||
; CHECK: f_i64:
|
||||
; CHECK: stw 0(r2), r1
|
||||
; CHECK: stw 4(r2), r1 # encoding: [0x63,0x12,0x04,0x00,0x00,0x00,0x00,0x00]
|
||||
store volatile i64 %a, i64* @g_i64, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_i32_i32(i32 %a, i32 %b) #0 {
|
||||
; CHECK: f_i32_i32:
|
||||
; CHECK: stw 0(r3), r1
|
||||
store volatile i32 %a, i32* @g_i32, align 4
|
||||
; CHECK: stw 0(r3), r2
|
||||
store volatile i32 %b, i32* @g_i32, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_i16_i32_i16(i16 %a, i32 %b, i16 %c) #0 {
|
||||
; CHECK: f_i16_i32_i16:
|
||||
; CHECK: sth 0(r4), r1
|
||||
store volatile i16 %a, i16* @g_i16, align 2
|
||||
; CHECK: stw 0(r1), r2
|
||||
store volatile i32 %b, i32* @g_i32, align 4
|
||||
; CHECK: sth 0(r4), r3
|
||||
store volatile i16 %c, i16* @g_i16, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_i16_i64_i16(i16 %a, i64 %b, i16 %c) #0 {
|
||||
; CHECK: f_i16_i64_i16:
|
||||
; CHECK: sth 0(r4), r1
|
||||
store volatile i16 %a, i16* @g_i16, align 2
|
||||
; CHECK: std 0(r1), r2 # encoding: [0x7b,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
store volatile i64 %b, i64* @g_i64, align 8
|
||||
; CHECK: sth 0(r4), r3
|
||||
store volatile i16 %c, i16* @g_i16, align 2
|
||||
ret void
|
||||
}
|
48
test/CodeGen/BPF/cc_ret.ll
Normal file
48
test/CodeGen/BPF/cc_ret.ll
Normal file
@ -0,0 +1,48 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
define void @test() #0 {
|
||||
entry:
|
||||
; CHECK: test:
|
||||
|
||||
; CHECK: call f_i16
|
||||
; CHECK: sth 0(r1), r0
|
||||
%0 = call i16 @f_i16()
|
||||
store volatile i16 %0, i16* @g_i16
|
||||
|
||||
; CHECK: call f_i32
|
||||
; CHECK: stw 0(r1), r0
|
||||
%1 = call i32 @f_i32()
|
||||
store volatile i32 %1, i32* @g_i32
|
||||
|
||||
; CHECK: call f_i64
|
||||
; CHECK: std 0(r1), r0
|
||||
%2 = call i64 @f_i64()
|
||||
store volatile i64 %2, i64* @g_i64
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
@g_i16 = common global i16 0, align 2
|
||||
@g_i32 = common global i32 0, align 2
|
||||
@g_i64 = common global i64 0, align 2
|
||||
|
||||
define i16 @f_i16() #0 {
|
||||
; CHECK: f_i16:
|
||||
; CHECK: mov r0, 1
|
||||
; CHECK: ret
|
||||
ret i16 1
|
||||
}
|
||||
|
||||
define i32 @f_i32() #0 {
|
||||
; CHECK: f_i32:
|
||||
; CHECK: mov r0, 16909060
|
||||
; CHECK: ret
|
||||
ret i32 16909060
|
||||
}
|
||||
|
||||
define i64 @f_i64() #0 {
|
||||
; CHECK: f_i64:
|
||||
; CHECK: ld_64 r0, 72623859790382856
|
||||
; CHECK: ret
|
||||
ret i64 72623859790382856
|
||||
}
|
119
test/CodeGen/BPF/cmp.ll
Normal file
119
test/CodeGen/BPF/cmp.ll
Normal file
@ -0,0 +1,119 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @foo_cmp1(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp sgt i8 %a, %b
|
||||
br i1 %1, label %2, label %4
|
||||
|
||||
; <label>:2 ; preds = %0
|
||||
%3 = mul i8 %b, %a
|
||||
br label %6
|
||||
|
||||
; <label>:4 ; preds = %0
|
||||
%5 = shl i8 %b, 3
|
||||
br label %6
|
||||
|
||||
; <label>:6 ; preds = %4, %2
|
||||
%.0 = phi i8 [ %3, %2 ], [ %5, %4 ]
|
||||
ret i8 %.0
|
||||
; CHECK-LABEL:foo_cmp1:
|
||||
; CHECK: jsge r2, r1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @foo_cmp2(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp slt i8 %a, %b
|
||||
br i1 %1, label %4, label %2
|
||||
|
||||
; <label>:2 ; preds = %0
|
||||
%3 = mul i8 %b, %a
|
||||
br label %6
|
||||
|
||||
; <label>:4 ; preds = %0
|
||||
%5 = shl i8 %b, 3
|
||||
br label %6
|
||||
|
||||
; <label>:6 ; preds = %4, %2
|
||||
%.0 = phi i8 [ %3, %2 ], [ %5, %4 ]
|
||||
ret i8 %.0
|
||||
; CHECK-LABEL:foo_cmp2:
|
||||
; CHECK: jsgt r2, r1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @foo_cmp3(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp slt i8 %a, %b
|
||||
br i1 %1, label %2, label %4
|
||||
|
||||
; <label>:2 ; preds = %0
|
||||
%3 = mul i8 %b, %a
|
||||
br label %6
|
||||
|
||||
; <label>:4 ; preds = %0
|
||||
%5 = shl i8 %b, 3
|
||||
br label %6
|
||||
|
||||
; <label>:6 ; preds = %4, %2
|
||||
%.0 = phi i8 [ %3, %2 ], [ %5, %4 ]
|
||||
ret i8 %.0
|
||||
; CHECK-LABEL:foo_cmp3:
|
||||
; CHECK: jsge r1, r2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @foo_cmp4(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp sgt i8 %a, %b
|
||||
br i1 %1, label %4, label %2
|
||||
|
||||
; <label>:2 ; preds = %0
|
||||
%3 = mul i8 %b, %a
|
||||
br label %6
|
||||
|
||||
; <label>:4 ; preds = %0
|
||||
%5 = shl i8 %b, 3
|
||||
br label %6
|
||||
|
||||
; <label>:6 ; preds = %4, %2
|
||||
%.0 = phi i8 [ %3, %2 ], [ %5, %4 ]
|
||||
ret i8 %.0
|
||||
; CHECK-LABEL:foo_cmp4:
|
||||
; CHECK: jsgt r1, r2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @min(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp slt i8 %a, %b
|
||||
%a.b = select i1 %1, i8 %a, i8 %b
|
||||
ret i8 %a.b
|
||||
; CHECK-LABEL:min:
|
||||
; CHECK: jsgt r2, r1
|
||||
; CHECK: mov r1, r2
|
||||
; CHECK: mov r0, r1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define zeroext i8 @minu(i8 zeroext %a, i8 zeroext %b) #0 {
|
||||
%1 = icmp ult i8 %a, 100
|
||||
%a.b = select i1 %1, i8 %a, i8 %b
|
||||
ret i8 %a.b
|
||||
; CHECK-LABEL:minu:
|
||||
; CHECK: jgt r3, r1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @max(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp sgt i8 %a, %b
|
||||
%a.b = select i1 %1, i8 %a, i8 %b
|
||||
ret i8 %a.b
|
||||
; CHECK-LABEL:max:
|
||||
; CHECK: jsgt r1, r2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @meq(i8 signext %a, i8 signext %b, i8 signext %c) #0 {
|
||||
%1 = icmp eq i8 %a, %b
|
||||
%c.a = select i1 %1, i8 %c, i8 %a
|
||||
ret i8 %c.a
|
||||
; CHECK-LABEL:meq:
|
||||
; CHECK: jeq r1, r2
|
||||
}
|
46
test/CodeGen/BPF/ex1.ll
Normal file
46
test/CodeGen/BPF/ex1.ll
Normal file
@ -0,0 +1,46 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
%struct.bpf_context = type { i64, i64, i64, i64, i64, i64, i64 }
|
||||
%struct.sk_buff = type { i64, i64, i64, i64, i64, i64, i64 }
|
||||
%struct.net_device = type { i64, i64, i64, i64, i64, i64, i64 }
|
||||
|
||||
@bpf_prog1.devname = private unnamed_addr constant [3 x i8] c"lo\00", align 1
|
||||
@bpf_prog1.fmt = private unnamed_addr constant [15 x i8] c"skb %x dev %x\0A\00", align 1
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @bpf_prog1(%struct.bpf_context* nocapture %ctx) #0 section "events/net/netif_receive_skb" {
|
||||
%devname = alloca [3 x i8], align 1
|
||||
%fmt = alloca [15 x i8], align 1
|
||||
%1 = getelementptr inbounds [3 x i8]* %devname, i64 0, i64 0
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds ([3 x i8]* @bpf_prog1.devname, i64 0, i64 0), i64 3, i32 1, i1 false)
|
||||
%2 = getelementptr inbounds %struct.bpf_context* %ctx, i64 0, i32 0
|
||||
%3 = load i64* %2, align 8
|
||||
%4 = inttoptr i64 %3 to %struct.sk_buff*
|
||||
%5 = getelementptr inbounds %struct.sk_buff* %4, i64 0, i32 2
|
||||
%6 = bitcast i64* %5 to i8*
|
||||
%7 = call i8* inttoptr (i64 4 to i8* (i8*)*)(i8* %6) #1
|
||||
%8 = call i32 inttoptr (i64 9 to i32 (i8*, i8*, i32)*)(i8* %7, i8* %1, i32 2) #1
|
||||
%9 = icmp eq i32 %8, 0
|
||||
br i1 %9, label %10, label %13
|
||||
|
||||
; <label>:10 ; preds = %0
|
||||
%11 = getelementptr inbounds [15 x i8]* %fmt, i64 0, i64 0
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %11, i8* getelementptr inbounds ([15 x i8]* @bpf_prog1.fmt, i64 0, i64 0), i64 15, i32 1, i1 false)
|
||||
%12 = call i32 (i8*, i32, ...)* inttoptr (i64 11 to i32 (i8*, i32, ...)*)(i8* %11, i32 15, %struct.sk_buff* %4, i8* %7) #1
|
||||
; CHECK-LABEL: bpf_prog1:
|
||||
; CHECK: call 4
|
||||
; CHECK: call 9
|
||||
; CHECK: jnei r0, 0
|
||||
; CHECK: mov r1, 622884453
|
||||
; CHECK: ld_64 r1, 7214898703899978611
|
||||
; CHECK: call 11
|
||||
; CHECK: mov r0, 0
|
||||
; CHECK: ret
|
||||
br label %13
|
||||
|
||||
; <label>:13 ; preds = %10, %0
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) #1
|
50
test/CodeGen/BPF/intrinsics.ll
Normal file
50
test/CodeGen/BPF/intrinsics.ll
Normal file
@ -0,0 +1,50 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @ld_b(i64 %foo, i64* nocapture %bar, i8* %ctx, i8* %ctx2) #0 {
|
||||
%1 = tail call i64 @llvm.bpf.load.byte(i8* %ctx, i64 123) #2
|
||||
%2 = add i64 %1, %foo
|
||||
%3 = load volatile i64* %bar, align 8
|
||||
%4 = add i64 %2, %3
|
||||
%5 = tail call i64 @llvm.bpf.load.byte(i8* %ctx2, i64 %foo) #2
|
||||
%6 = add i64 %4, %5
|
||||
%7 = load volatile i64* %bar, align 8
|
||||
%8 = add i64 %6, %7
|
||||
%9 = trunc i64 %8 to i32
|
||||
ret i32 %9
|
||||
; CHECK-LABEL: ld_b:
|
||||
; CHECK: ldabs_b r0, r6.data + 123
|
||||
; CHECK: ldind_b r0, r6.data
|
||||
}
|
||||
|
||||
declare i64 @llvm.bpf.load.byte(i8*, i64) #1
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @ld_h(i8* %ctx, i8* %ctx2, i32 %foo) #0 {
|
||||
%1 = tail call i64 @llvm.bpf.load.half(i8* %ctx, i64 123) #2
|
||||
%2 = sext i32 %foo to i64
|
||||
%3 = tail call i64 @llvm.bpf.load.half(i8* %ctx2, i64 %2) #2
|
||||
%4 = add i64 %3, %1
|
||||
%5 = trunc i64 %4 to i32
|
||||
ret i32 %5
|
||||
; CHECK-LABEL: ld_h:
|
||||
; CHECK: ldind_h r0, r6.data
|
||||
; CHECK: ldabs_h r0, r6.data + 123
|
||||
}
|
||||
|
||||
declare i64 @llvm.bpf.load.half(i8*, i64) #1
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @ld_w(i8* %ctx, i8* %ctx2, i32 %foo) #0 {
|
||||
%1 = tail call i64 @llvm.bpf.load.word(i8* %ctx, i64 123) #2
|
||||
%2 = sext i32 %foo to i64
|
||||
%3 = tail call i64 @llvm.bpf.load.word(i8* %ctx2, i64 %2) #2
|
||||
%4 = add i64 %3, %1
|
||||
%5 = trunc i64 %4 to i32
|
||||
ret i32 %5
|
||||
; CHECK-LABEL: ld_w:
|
||||
; CHECK: ldind_w r0, r6.data
|
||||
; CHECK: ldabs_w r0, r6.data + 123
|
||||
}
|
||||
|
||||
declare i64 @llvm.bpf.load.word(i8*, i64) #1
|
43
test/CodeGen/BPF/load.ll
Normal file
43
test/CodeGen/BPF/load.ll
Normal file
@ -0,0 +1,43 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
define i16 @am1(i16* %a) nounwind {
|
||||
%1 = load i16* %a
|
||||
ret i16 %1
|
||||
}
|
||||
; CHECK-LABEL: am1:
|
||||
; CHECK: ldh r0, 0(r1)
|
||||
|
||||
@foo = external global i16
|
||||
|
||||
define i16 @am2() nounwind {
|
||||
%1 = load i16* @foo
|
||||
ret i16 %1
|
||||
}
|
||||
; CHECK-LABEL: am2:
|
||||
; CHECK: ldh r0, 0(r1)
|
||||
|
||||
define i16 @am4() nounwind {
|
||||
%1 = load volatile i16* inttoptr(i16 32 to i16*)
|
||||
ret i16 %1
|
||||
}
|
||||
; CHECK-LABEL: am4:
|
||||
; CHECK: mov r1, 32
|
||||
; CHECK: ldh r0, 0(r1)
|
||||
|
||||
define i16 @am5(i16* %a) nounwind {
|
||||
%1 = getelementptr i16* %a, i16 2
|
||||
%2 = load i16* %1
|
||||
ret i16 %2
|
||||
}
|
||||
; CHECK-LABEL: am5:
|
||||
; CHECK: ldh r0, 4(r1)
|
||||
|
||||
%S = type { i16, i16 }
|
||||
@baz = common global %S zeroinitializer, align 1
|
||||
|
||||
define i16 @am6() nounwind {
|
||||
%1 = load i16* getelementptr (%S* @baz, i32 0, i32 1)
|
||||
ret i16 %1
|
||||
}
|
||||
; CHECK-LABEL: am6:
|
||||
; CHECK: ldh r0, 2(r1)
|
111
test/CodeGen/BPF/loops.ll
Normal file
111
test/CodeGen/BPF/loops.ll
Normal file
@ -0,0 +1,111 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
define zeroext i16 @add(i16* nocapture %a, i16 zeroext %n) nounwind readonly {
|
||||
entry:
|
||||
%cmp8 = icmp eq i16 %n, 0 ; <i1> [#uses=1]
|
||||
br i1 %cmp8, label %for.end, label %for.body
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%i.010 = phi i16 [ 0, %entry ], [ %inc, %for.body ] ; <i16> [#uses=2]
|
||||
%sum.09 = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
%arrayidx = getelementptr i16* %a, i16 %i.010 ; <i16*> [#uses=1]
|
||||
; CHECK-LABEL: add:
|
||||
; CHECK: add r{{[0-9]+}}, r{{[0-9]+}}
|
||||
%tmp4 = load i16* %arrayidx ; <i16> [#uses=1]
|
||||
%add = add i16 %tmp4, %sum.09 ; <i16> [#uses=2]
|
||||
%inc = add i16 %i.010, 1 ; <i16> [#uses=2]
|
||||
%exitcond = icmp eq i16 %inc, %n ; <i1> [#uses=1]
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.body, %entry
|
||||
%sum.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
ret i16 %sum.0.lcssa
|
||||
}
|
||||
|
||||
define zeroext i16 @sub(i16* nocapture %a, i16 zeroext %n) nounwind readonly {
|
||||
entry:
|
||||
%cmp8 = icmp eq i16 %n, 0 ; <i1> [#uses=1]
|
||||
br i1 %cmp8, label %for.end, label %for.body
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%i.010 = phi i16 [ 0, %entry ], [ %inc, %for.body ] ; <i16> [#uses=2]
|
||||
%sum.09 = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
%arrayidx = getelementptr i16* %a, i16 %i.010 ; <i16*> [#uses=1]
|
||||
; CHECK-LABEL: sub:
|
||||
; CHECK: sub r{{[0-9]+}}, r{{[0-9]+}}
|
||||
%tmp4 = load i16* %arrayidx ; <i16> [#uses=1]
|
||||
%add = sub i16 %tmp4, %sum.09 ; <i16> [#uses=2]
|
||||
%inc = add i16 %i.010, 1 ; <i16> [#uses=2]
|
||||
%exitcond = icmp eq i16 %inc, %n ; <i1> [#uses=1]
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.body, %entry
|
||||
%sum.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
ret i16 %sum.0.lcssa
|
||||
}
|
||||
|
||||
define zeroext i16 @or(i16* nocapture %a, i16 zeroext %n) nounwind readonly {
|
||||
entry:
|
||||
%cmp8 = icmp eq i16 %n, 0 ; <i1> [#uses=1]
|
||||
br i1 %cmp8, label %for.end, label %for.body
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%i.010 = phi i16 [ 0, %entry ], [ %inc, %for.body ] ; <i16> [#uses=2]
|
||||
%sum.09 = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
%arrayidx = getelementptr i16* %a, i16 %i.010 ; <i16*> [#uses=1]
|
||||
; CHECK-LABEL: or:
|
||||
; CHECK: or r{{[0-9]+}}, r{{[0-9]+}}
|
||||
%tmp4 = load i16* %arrayidx ; <i16> [#uses=1]
|
||||
%add = or i16 %tmp4, %sum.09 ; <i16> [#uses=2]
|
||||
%inc = add i16 %i.010, 1 ; <i16> [#uses=2]
|
||||
%exitcond = icmp eq i16 %inc, %n ; <i1> [#uses=1]
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.body, %entry
|
||||
%sum.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
ret i16 %sum.0.lcssa
|
||||
}
|
||||
|
||||
define zeroext i16 @xor(i16* nocapture %a, i16 zeroext %n) nounwind readonly {
|
||||
entry:
|
||||
%cmp8 = icmp eq i16 %n, 0 ; <i1> [#uses=1]
|
||||
br i1 %cmp8, label %for.end, label %for.body
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%i.010 = phi i16 [ 0, %entry ], [ %inc, %for.body ] ; <i16> [#uses=2]
|
||||
%sum.09 = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
%arrayidx = getelementptr i16* %a, i16 %i.010 ; <i16*> [#uses=1]
|
||||
; CHECK-LABEL: xor:
|
||||
; CHECK: xor r{{[0-9]+}}, r{{[0-9]+}}
|
||||
%tmp4 = load i16* %arrayidx ; <i16> [#uses=1]
|
||||
%add = xor i16 %tmp4, %sum.09 ; <i16> [#uses=2]
|
||||
%inc = add i16 %i.010, 1 ; <i16> [#uses=2]
|
||||
%exitcond = icmp eq i16 %inc, %n ; <i1> [#uses=1]
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.body, %entry
|
||||
%sum.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
ret i16 %sum.0.lcssa
|
||||
}
|
||||
|
||||
define zeroext i16 @and(i16* nocapture %a, i16 zeroext %n) nounwind readonly {
|
||||
entry:
|
||||
%cmp8 = icmp eq i16 %n, 0 ; <i1> [#uses=1]
|
||||
br i1 %cmp8, label %for.end, label %for.body
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%i.010 = phi i16 [ 0, %entry ], [ %inc, %for.body ] ; <i16> [#uses=2]
|
||||
%sum.09 = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
%arrayidx = getelementptr i16* %a, i16 %i.010 ; <i16*> [#uses=1]
|
||||
; CHECK-LABEL: and:
|
||||
; CHECK: and r{{[0-9]+}}, r{{[0-9]+}}
|
||||
%tmp4 = load i16* %arrayidx ; <i16> [#uses=1]
|
||||
%add = and i16 %tmp4, %sum.09 ; <i16> [#uses=2]
|
||||
%inc = add i16 %i.010, 1 ; <i16> [#uses=2]
|
||||
%exitcond = icmp eq i16 %inc, %n ; <i1> [#uses=1]
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.body, %entry
|
||||
%sum.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ] ; <i16> [#uses=1]
|
||||
ret i16 %sum.0.lcssa
|
||||
}
|
12
test/CodeGen/BPF/many_args1.ll
Normal file
12
test/CodeGen/BPF/many_args1.ll
Normal file
@ -0,0 +1,12 @@
|
||||
; RUN: not llc -march=bpf < %s 2> %t1
|
||||
; RUN: FileCheck %s < %t1
|
||||
; CHECK: too many args
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @foo(i32 %a, i32 %b, i32 %c) #0 {
|
||||
entry:
|
||||
%call = tail call i32 @bar(i32 %a, i32 %b, i32 %c, i32 1, i32 2, i32 3) #3
|
||||
ret i32 %call
|
||||
}
|
||||
|
||||
declare i32 @bar(i32, i32, i32, i32, i32, i32) #1
|
15
test/CodeGen/BPF/many_args2.ll
Normal file
15
test/CodeGen/BPF/many_args2.ll
Normal file
@ -0,0 +1,15 @@
|
||||
; RUN: not llc -march=bpf < %s 2> %t1
|
||||
; RUN: FileCheck %s < %t1
|
||||
; CHECK: too many args
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define i32 @bar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) #0 {
|
||||
entry:
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define i32 @foo(i32 %a, i32 %b, i32 %c) #0 {
|
||||
entry:
|
||||
ret i32 1
|
||||
}
|
117
test/CodeGen/BPF/sanity.ll
Normal file
117
test/CodeGen/BPF/sanity.ll
Normal file
@ -0,0 +1,117 @@
|
||||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
@foo_printf.fmt = private unnamed_addr constant [9 x i8] c"hello \0A\00", align 1
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define i32 @foo_int(i32 %a, i32 %b) #0 {
|
||||
%1 = add nsw i32 %b, %a
|
||||
ret i32 %1
|
||||
; CHECK-LABEL: foo_int:
|
||||
; CHECK: add r2, r1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @foo_char(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = add i8 %b, %a
|
||||
ret i8 %1
|
||||
; CHECK-LABEL: foo_char:
|
||||
; CHECK: add r2, r1
|
||||
; CHECK: slli r2, 56
|
||||
; CHECK: srai r2, 56
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define i64 @foo_ll(i64 %a, i64 %b, i64 %c) #0 {
|
||||
%1 = add nsw i64 %b, %a
|
||||
%2 = sub i64 %1, %c
|
||||
ret i64 %2
|
||||
; CHECK-LABEL: foo_ll:
|
||||
; CHECK: add r2, r1
|
||||
; CHECK: sub r2, r3
|
||||
; CHECK: mov r0, r2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @foo_call2(i32 %a, i32 %b) #1 {
|
||||
%1 = trunc i32 %b to i8
|
||||
tail call void @foo_2arg(i8 signext %1, i32 %a) #3
|
||||
ret void
|
||||
; CHECK-LABEL: foo_call2:
|
||||
; CHECK: slli r2, 56
|
||||
; CHECK: srai r2, 56
|
||||
; CHECK: mov r1, r2
|
||||
}
|
||||
|
||||
declare void @foo_2arg(i8 signext, i32) #2
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @foo_call5(i8 signext %a, i16 signext %b, i32 %c, i64 %d) #1 {
|
||||
%1 = tail call i32 @bar(i8 signext %a, i16 signext %b, i32 %c, i64 %d) #3
|
||||
ret i32 0
|
||||
; CHECK-LABEL: foo_call5:
|
||||
; CHECK: call bar
|
||||
}
|
||||
|
||||
declare i32 @bar(i8 signext, i16 signext, i32, i64) #2
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define signext i8 @foo_cmp(i8 signext %a, i8 signext %b) #0 {
|
||||
%1 = icmp slt i8 %a, %b
|
||||
%a.b = select i1 %1, i8 %a, i8 %b
|
||||
ret i8 %a.b
|
||||
; CHECK-LABEL: foo_cmp:
|
||||
; CHECK: jsgt r2, r1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define i32 @foo_muldiv(i8 signext %a, i16 signext %b, i32 %c, i64 %d) #0 {
|
||||
%1 = icmp eq i8 %a, 0
|
||||
br i1 %1, label %5, label %2
|
||||
|
||||
; <label>:2 ; preds = %0
|
||||
%3 = sext i16 %b to i32
|
||||
%4 = mul nsw i32 %3, %c
|
||||
br label %8
|
||||
|
||||
; <label>:5 ; preds = %0
|
||||
%6 = trunc i64 %d to i32
|
||||
%7 = udiv i32 %6, %c
|
||||
br label %8
|
||||
|
||||
; <label>:8 ; preds = %5, %2
|
||||
%.0 = phi i32 [ %4, %2 ], [ %7, %5 ]
|
||||
ret i32 %.0
|
||||
; CHECK-LABEL: foo_muldiv:
|
||||
; CHECK: mul r2, r3
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @foo_optimized() #1 {
|
||||
%1 = tail call i32 @manyarg(i32 1, i32 2, i32 3, i32 4, i32 5) #3
|
||||
ret i32 %1
|
||||
; CHECK-LABEL: foo_optimized:
|
||||
; CHECK: mov r1, 1
|
||||
; CHECK: mov r2, 2
|
||||
; CHECK: mov r3, 3
|
||||
; CHECK: mov r4, 4
|
||||
; CHECK: mov r5, 5
|
||||
}
|
||||
|
||||
declare i32 @manyarg(i32, i32, i32, i32, i32) #2
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @foo_printf() #1 {
|
||||
%fmt = alloca [9 x i8], align 1
|
||||
%1 = getelementptr inbounds [9 x i8]* %fmt, i64 0, i64 0
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds ([9 x i8]* @foo_printf.fmt, i64 0, i64 0), i64 9, i32 1, i1 false)
|
||||
; CHECK-LABEL: foo_printf:
|
||||
; CHECK: ld_64 r1, 729618802566522216
|
||||
%2 = call i32 (i8*, ...)* @printf(i8* %1) #3
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare i32 @printf(i8* nocapture, ...) #4
|
99
test/CodeGen/BPF/setcc.ll
Normal file
99
test/CodeGen/BPF/setcc.ll
Normal file
@ -0,0 +1,99 @@
|
||||
; RUN: llc -march=bpf < %s | FileCheck %s
|
||||
|
||||
define i16 @sccweqand(i16 %a, i16 %b) nounwind {
|
||||
%t1 = and i16 %a, %b
|
||||
%t2 = icmp eq i16 %t1, 0
|
||||
%t3 = zext i1 %t2 to i16
|
||||
ret i16 %t3
|
||||
}
|
||||
; CHECK-LABEL: sccweqand:
|
||||
; CHECK: jeq r1, r2
|
||||
|
||||
define i16 @sccwneand(i16 %a, i16 %b) nounwind {
|
||||
%t1 = and i16 %a, %b
|
||||
%t2 = icmp ne i16 %t1, 0
|
||||
%t3 = zext i1 %t2 to i16
|
||||
ret i16 %t3
|
||||
}
|
||||
; CHECK-LABEL: sccwneand:
|
||||
; CHECK: jne r1, r2
|
||||
|
||||
define i16 @sccwne(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp ne i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwne:
|
||||
; CHECK: jne r1, r2
|
||||
|
||||
define i16 @sccweq(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp eq i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccweq:
|
||||
; CHECK: jeq r1, r2
|
||||
|
||||
define i16 @sccwugt(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp ugt i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwugt:
|
||||
; CHECK: jgt r1, r2
|
||||
|
||||
define i16 @sccwuge(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp uge i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwuge:
|
||||
; CHECK: jge r1, r2
|
||||
|
||||
define i16 @sccwult(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp ult i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwult:
|
||||
; CHECK: jgt r2, r1
|
||||
|
||||
define i16 @sccwule(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp ule i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwule:
|
||||
; CHECK: jge r2, r1
|
||||
|
||||
define i16 @sccwsgt(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp sgt i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwsgt:
|
||||
; CHECK: jsgt r1, r2
|
||||
|
||||
define i16 @sccwsge(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp sge i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwsge:
|
||||
; CHECK: jsge r1, r2
|
||||
|
||||
define i16 @sccwslt(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp slt i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwslt:
|
||||
; CHECK: jsgt r2, r1
|
||||
|
||||
define i16 @sccwsle(i16 %a, i16 %b) nounwind {
|
||||
%t1 = icmp sle i16 %a, %b
|
||||
%t2 = zext i1 %t1 to i16
|
||||
ret i16 %t2
|
||||
}
|
||||
; CHECK-LABEL:sccwsle:
|
||||
; CHECK: jsge r2, r1
|
101
test/CodeGen/BPF/shifts.ll
Normal file
101
test/CodeGen/BPF/shifts.ll
Normal file
@ -0,0 +1,101 @@
|
||||
; RUN: llc < %s -march=bpf -show-mc-encoding | FileCheck %s
|
||||
; test little endian only for now
|
||||
|
||||
define zeroext i8 @lshr8(i8 zeroext %a, i8 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: lshr8:
|
||||
; CHECK: srl r1, r2 # encoding: [0x7f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = lshr i8 %a, %cnt
|
||||
ret i8 %shr
|
||||
}
|
||||
|
||||
define signext i8 @ashr8(i8 signext %a, i8 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: ashr8:
|
||||
; CHECK: sra r1, r2 # encoding: [0xcf,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = ashr i8 %a, %cnt
|
||||
ret i8 %shr
|
||||
}
|
||||
|
||||
define zeroext i8 @shl8(i8 zeroext %a, i8 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK: shl8
|
||||
; CHECK: sll r1, r2 # encoding: [0x6f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shl = shl i8 %a, %cnt
|
||||
ret i8 %shl
|
||||
}
|
||||
|
||||
define zeroext i16 @lshr16(i16 zeroext %a, i16 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: lshr16:
|
||||
; CHECK: srl r1, r2 # encoding: [0x7f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = lshr i16 %a, %cnt
|
||||
ret i16 %shr
|
||||
}
|
||||
|
||||
define signext i16 @ashr16(i16 signext %a, i16 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: ashr16:
|
||||
; CHECK: sra r1, r2 # encoding: [0xcf,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = ashr i16 %a, %cnt
|
||||
ret i16 %shr
|
||||
}
|
||||
|
||||
define zeroext i16 @shl16(i16 zeroext %a, i16 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: shl16:
|
||||
; CHECK: sll r1, r2 # encoding: [0x6f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shl = shl i16 %a, %cnt
|
||||
ret i16 %shl
|
||||
}
|
||||
|
||||
define zeroext i32 @lshr32(i32 zeroext %a, i32 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: lshr32:
|
||||
; CHECK: srl r1, r2 # encoding: [0x7f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
; CHECK: slli r1, 32 # encoding: [0x67,0x01,0x00,0x00,0x20,0x00,0x00,0x00]
|
||||
%shr = lshr i32 %a, %cnt
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @ashr32(i32 signext %a, i32 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: ashr32:
|
||||
; CHECK: sra r1, r2 # encoding: [0xcf,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = ashr i32 %a, %cnt
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define zeroext i32 @shl32(i32 zeroext %a, i32 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: shl32:
|
||||
; CHECK: sll r1, r2 # encoding: [0x6f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shl = shl i32 %a, %cnt
|
||||
ret i32 %shl
|
||||
}
|
||||
|
||||
define zeroext i64 @lshr64(i64 zeroext %a, i64 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: lshr64:
|
||||
; CHECK: srl r1, r2 # encoding: [0x7f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = lshr i64 %a, %cnt
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @ashr64(i64 signext %a, i64 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: ashr64:
|
||||
; CHECK: sra r1, r2 # encoding: [0xcf,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shr = ashr i64 %a, %cnt
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define zeroext i64 @shl64(i64 zeroext %a, i64 zeroext %cnt) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: shl64:
|
||||
; CHECK: sll r1, r2 # encoding: [0x6f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
; CHECK: mov r0, r1 # encoding: [0xbf,0x10,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
; CHECK: ret # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
%shl = shl i64 %a, %cnt
|
||||
ret i64 %shl
|
||||
}
|
326
test/CodeGen/BPF/sockex2.ll
Normal file
326
test/CodeGen/BPF/sockex2.ll
Normal file
@ -0,0 +1,326 @@
|
||||
; RUN: llc < %s -march=bpf -show-mc-encoding | FileCheck %s
|
||||
; test little endian only for now
|
||||
|
||||
%struct.bpf_map_def = type { i32, i32, i32, i32 }
|
||||
%struct.sk_buff = type opaque
|
||||
|
||||
@hash_map = global %struct.bpf_map_def { i32 1, i32 4, i32 8, i32 1024 }, section "maps", align 4
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @bpf_prog2(%struct.sk_buff* %skb) #0 section "socket2" {
|
||||
%key = alloca i32, align 4
|
||||
%val = alloca i64, align 8
|
||||
%1 = bitcast %struct.sk_buff* %skb to i8*
|
||||
%2 = call i64 @llvm.bpf.load.half(i8* %1, i64 12) #2
|
||||
%3 = icmp eq i64 %2, 34984
|
||||
br i1 %3, label %4, label %6
|
||||
|
||||
; <label>:4 ; preds = %0
|
||||
%5 = call i64 @llvm.bpf.load.half(i8* %1, i64 16) #2
|
||||
br label %6
|
||||
|
||||
; <label>:6 ; preds = %4, %0
|
||||
%proto.0.i = phi i64 [ %5, %4 ], [ %2, %0 ]
|
||||
%nhoff.0.i = phi i64 [ 18, %4 ], [ 14, %0 ]
|
||||
%7 = icmp eq i64 %proto.0.i, 33024
|
||||
br i1 %7, label %8, label %12
|
||||
|
||||
; <label>:8 ; preds = %6
|
||||
%9 = add i64 %nhoff.0.i, 2
|
||||
%10 = call i64 @llvm.bpf.load.half(i8* %1, i64 %9) #2
|
||||
%11 = add i64 %nhoff.0.i, 4
|
||||
br label %12
|
||||
|
||||
; <label>:12 ; preds = %8, %6
|
||||
%proto.1.i = phi i64 [ %10, %8 ], [ %proto.0.i, %6 ]
|
||||
%nhoff.1.i = phi i64 [ %11, %8 ], [ %nhoff.0.i, %6 ]
|
||||
switch i64 %proto.1.i, label %flow_dissector.exit.thread [
|
||||
i64 2048, label %13
|
||||
i64 34525, label %39
|
||||
]
|
||||
|
||||
; <label>:13 ; preds = %12
|
||||
%14 = add i64 %nhoff.1.i, 6
|
||||
%15 = call i64 @llvm.bpf.load.half(i8* %1, i64 %14) #2
|
||||
%16 = and i64 %15, 16383
|
||||
%17 = icmp eq i64 %16, 0
|
||||
br i1 %17, label %18, label %.thread.i.i
|
||||
|
||||
; <label>:18 ; preds = %13
|
||||
%19 = add i64 %nhoff.1.i, 9
|
||||
%20 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %19) #2
|
||||
%21 = icmp eq i64 %20, 47
|
||||
br i1 %21, label %28, label %.thread.i.i
|
||||
|
||||
.thread.i.i: ; preds = %18, %13
|
||||
%22 = phi i64 [ %20, %18 ], [ 0, %13 ]
|
||||
%23 = add i64 %nhoff.1.i, 12
|
||||
%24 = call i64 @llvm.bpf.load.word(i8* %1, i64 %23) #2
|
||||
%25 = add i64 %nhoff.1.i, 16
|
||||
%26 = call i64 @llvm.bpf.load.word(i8* %1, i64 %25) #2
|
||||
%27 = trunc i64 %26 to i32
|
||||
br label %28
|
||||
|
||||
; <label>:28 ; preds = %.thread.i.i, %18
|
||||
%29 = phi i32 [ %27, %.thread.i.i ], [ undef, %18 ]
|
||||
%30 = phi i64 [ %22, %.thread.i.i ], [ 47, %18 ]
|
||||
%31 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %nhoff.1.i) #2
|
||||
%32 = icmp eq i64 %31, 69
|
||||
br i1 %32, label %33, label %35
|
||||
|
||||
; <label>:33 ; preds = %28
|
||||
%34 = add i64 %nhoff.1.i, 20
|
||||
br label %parse_ip.exit.i
|
||||
|
||||
; <label>:35 ; preds = %28
|
||||
%36 = shl i64 %31, 2
|
||||
%37 = and i64 %36, 60
|
||||
%38 = add i64 %37, %nhoff.1.i
|
||||
br label %parse_ip.exit.i
|
||||
|
||||
; <label>:39 ; preds = %12
|
||||
%40 = add i64 %nhoff.1.i, 6
|
||||
%41 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %40) #2
|
||||
%42 = add i64 %nhoff.1.i, 8
|
||||
%43 = call i64 @llvm.bpf.load.word(i8* %1, i64 %42) #2
|
||||
%44 = add i64 %nhoff.1.i, 12
|
||||
%45 = call i64 @llvm.bpf.load.word(i8* %1, i64 %44) #2
|
||||
%46 = add i64 %nhoff.1.i, 16
|
||||
%47 = call i64 @llvm.bpf.load.word(i8* %1, i64 %46) #2
|
||||
%48 = add i64 %nhoff.1.i, 20
|
||||
%49 = call i64 @llvm.bpf.load.word(i8* %1, i64 %48) #2
|
||||
%50 = add i64 %nhoff.1.i, 24
|
||||
%51 = call i64 @llvm.bpf.load.word(i8* %1, i64 %50) #2
|
||||
%52 = add i64 %nhoff.1.i, 28
|
||||
%53 = call i64 @llvm.bpf.load.word(i8* %1, i64 %52) #2
|
||||
%54 = add i64 %nhoff.1.i, 32
|
||||
%55 = call i64 @llvm.bpf.load.word(i8* %1, i64 %54) #2
|
||||
%56 = add i64 %nhoff.1.i, 36
|
||||
%57 = call i64 @llvm.bpf.load.word(i8* %1, i64 %56) #2
|
||||
%58 = xor i64 %53, %51
|
||||
%59 = xor i64 %58, %55
|
||||
%60 = xor i64 %59, %57
|
||||
%61 = trunc i64 %60 to i32
|
||||
%62 = add i64 %nhoff.1.i, 40
|
||||
br label %parse_ip.exit.i
|
||||
|
||||
parse_ip.exit.i: ; preds = %39, %35, %33
|
||||
%63 = phi i32 [ %61, %39 ], [ %29, %33 ], [ %29, %35 ]
|
||||
%64 = phi i64 [ %41, %39 ], [ %30, %33 ], [ %30, %35 ]
|
||||
%nhoff.2.i = phi i64 [ %62, %39 ], [ %34, %33 ], [ %38, %35 ]
|
||||
switch i64 %64, label %187 [
|
||||
i64 47, label %65
|
||||
i64 4, label %137
|
||||
i64 41, label %163
|
||||
]
|
||||
|
||||
; <label>:65 ; preds = %parse_ip.exit.i
|
||||
%66 = call i64 @llvm.bpf.load.half(i8* %1, i64 %nhoff.2.i) #2
|
||||
%67 = add i64 %nhoff.2.i, 2
|
||||
%68 = call i64 @llvm.bpf.load.half(i8* %1, i64 %67) #2
|
||||
%69 = and i64 %66, 1856
|
||||
%70 = icmp eq i64 %69, 0
|
||||
br i1 %70, label %71, label %187
|
||||
|
||||
; <label>:71 ; preds = %65
|
||||
%72 = lshr i64 %66, 5
|
||||
%73 = and i64 %72, 4
|
||||
%74 = add i64 %nhoff.2.i, 4
|
||||
%..i = add i64 %74, %73
|
||||
%75 = and i64 %66, 32
|
||||
%76 = icmp eq i64 %75, 0
|
||||
%77 = add i64 %..i, 4
|
||||
%nhoff.4.i = select i1 %76, i64 %..i, i64 %77
|
||||
%78 = and i64 %66, 16
|
||||
%79 = icmp eq i64 %78, 0
|
||||
%80 = add i64 %nhoff.4.i, 4
|
||||
%nhoff.4..i = select i1 %79, i64 %nhoff.4.i, i64 %80
|
||||
%81 = icmp eq i64 %68, 33024
|
||||
br i1 %81, label %82, label %86
|
||||
|
||||
; <label>:82 ; preds = %71
|
||||
%83 = add i64 %nhoff.4..i, 2
|
||||
%84 = call i64 @llvm.bpf.load.half(i8* %1, i64 %83) #2
|
||||
%85 = add i64 %nhoff.4..i, 4
|
||||
br label %86
|
||||
|
||||
; <label>:86 ; preds = %82, %71
|
||||
%proto.2.i = phi i64 [ %84, %82 ], [ %68, %71 ]
|
||||
%nhoff.6.i = phi i64 [ %85, %82 ], [ %nhoff.4..i, %71 ]
|
||||
switch i64 %proto.2.i, label %flow_dissector.exit.thread [
|
||||
i64 2048, label %87
|
||||
i64 34525, label %113
|
||||
]
|
||||
|
||||
; <label>:87 ; preds = %86
|
||||
%88 = add i64 %nhoff.6.i, 6
|
||||
%89 = call i64 @llvm.bpf.load.half(i8* %1, i64 %88) #2
|
||||
%90 = and i64 %89, 16383
|
||||
%91 = icmp eq i64 %90, 0
|
||||
br i1 %91, label %92, label %.thread.i4.i
|
||||
|
||||
; <label>:92 ; preds = %87
|
||||
%93 = add i64 %nhoff.6.i, 9
|
||||
%94 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %93) #2
|
||||
%95 = icmp eq i64 %94, 47
|
||||
br i1 %95, label %102, label %.thread.i4.i
|
||||
|
||||
.thread.i4.i: ; preds = %92, %87
|
||||
%96 = phi i64 [ %94, %92 ], [ 0, %87 ]
|
||||
%97 = add i64 %nhoff.6.i, 12
|
||||
%98 = call i64 @llvm.bpf.load.word(i8* %1, i64 %97) #2
|
||||
%99 = add i64 %nhoff.6.i, 16
|
||||
%100 = call i64 @llvm.bpf.load.word(i8* %1, i64 %99) #2
|
||||
%101 = trunc i64 %100 to i32
|
||||
br label %102
|
||||
|
||||
; <label>:102 ; preds = %.thread.i4.i, %92
|
||||
%103 = phi i32 [ %101, %.thread.i4.i ], [ %63, %92 ]
|
||||
%104 = phi i64 [ %96, %.thread.i4.i ], [ 47, %92 ]
|
||||
%105 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %nhoff.6.i) #2
|
||||
%106 = icmp eq i64 %105, 69
|
||||
br i1 %106, label %107, label %109
|
||||
|
||||
; <label>:107 ; preds = %102
|
||||
%108 = add i64 %nhoff.6.i, 20
|
||||
br label %187
|
||||
|
||||
; <label>:109 ; preds = %102
|
||||
%110 = shl i64 %105, 2
|
||||
%111 = and i64 %110, 60
|
||||
%112 = add i64 %111, %nhoff.6.i
|
||||
br label %187
|
||||
|
||||
; <label>:113 ; preds = %86
|
||||
%114 = add i64 %nhoff.6.i, 6
|
||||
%115 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %114) #2
|
||||
%116 = add i64 %nhoff.6.i, 8
|
||||
%117 = call i64 @llvm.bpf.load.word(i8* %1, i64 %116) #2
|
||||
%118 = add i64 %nhoff.6.i, 12
|
||||
%119 = call i64 @llvm.bpf.load.word(i8* %1, i64 %118) #2
|
||||
%120 = add i64 %nhoff.6.i, 16
|
||||
%121 = call i64 @llvm.bpf.load.word(i8* %1, i64 %120) #2
|
||||
%122 = add i64 %nhoff.6.i, 20
|
||||
%123 = call i64 @llvm.bpf.load.word(i8* %1, i64 %122) #2
|
||||
%124 = add i64 %nhoff.6.i, 24
|
||||
%125 = call i64 @llvm.bpf.load.word(i8* %1, i64 %124) #2
|
||||
%126 = add i64 %nhoff.6.i, 28
|
||||
%127 = call i64 @llvm.bpf.load.word(i8* %1, i64 %126) #2
|
||||
%128 = add i64 %nhoff.6.i, 32
|
||||
%129 = call i64 @llvm.bpf.load.word(i8* %1, i64 %128) #2
|
||||
%130 = add i64 %nhoff.6.i, 36
|
||||
%131 = call i64 @llvm.bpf.load.word(i8* %1, i64 %130) #2
|
||||
%132 = xor i64 %127, %125
|
||||
%133 = xor i64 %132, %129
|
||||
%134 = xor i64 %133, %131
|
||||
%135 = trunc i64 %134 to i32
|
||||
%136 = add i64 %nhoff.6.i, 40
|
||||
br label %187
|
||||
|
||||
; <label>:137 ; preds = %parse_ip.exit.i
|
||||
%138 = add i64 %nhoff.2.i, 6
|
||||
%139 = call i64 @llvm.bpf.load.half(i8* %1, i64 %138) #2
|
||||
%140 = and i64 %139, 16383
|
||||
%141 = icmp eq i64 %140, 0
|
||||
br i1 %141, label %142, label %.thread.i1.i
|
||||
|
||||
; <label>:142 ; preds = %137
|
||||
%143 = add i64 %nhoff.2.i, 9
|
||||
%144 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %143) #2
|
||||
%145 = icmp eq i64 %144, 47
|
||||
br i1 %145, label %152, label %.thread.i1.i
|
||||
|
||||
.thread.i1.i: ; preds = %142, %137
|
||||
%146 = phi i64 [ %144, %142 ], [ 0, %137 ]
|
||||
%147 = add i64 %nhoff.2.i, 12
|
||||
%148 = call i64 @llvm.bpf.load.word(i8* %1, i64 %147) #2
|
||||
%149 = add i64 %nhoff.2.i, 16
|
||||
%150 = call i64 @llvm.bpf.load.word(i8* %1, i64 %149) #2
|
||||
%151 = trunc i64 %150 to i32
|
||||
br label %152
|
||||
|
||||
; <label>:152 ; preds = %.thread.i1.i, %142
|
||||
%153 = phi i32 [ %151, %.thread.i1.i ], [ %63, %142 ]
|
||||
%154 = phi i64 [ %146, %.thread.i1.i ], [ 47, %142 ]
|
||||
%155 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %nhoff.2.i) #2
|
||||
%156 = icmp eq i64 %155, 69
|
||||
br i1 %156, label %157, label %159
|
||||
|
||||
; <label>:157 ; preds = %152
|
||||
%158 = add i64 %nhoff.2.i, 20
|
||||
br label %187
|
||||
|
||||
; <label>:159 ; preds = %152
|
||||
%160 = shl i64 %155, 2
|
||||
%161 = and i64 %160, 60
|
||||
%162 = add i64 %161, %nhoff.2.i
|
||||
br label %187
|
||||
|
||||
; <label>:163 ; preds = %parse_ip.exit.i
|
||||
%164 = add i64 %nhoff.2.i, 6
|
||||
%165 = call i64 @llvm.bpf.load.byte(i8* %1, i64 %164) #2
|
||||
%166 = add i64 %nhoff.2.i, 8
|
||||
%167 = call i64 @llvm.bpf.load.word(i8* %1, i64 %166) #2
|
||||
%168 = add i64 %nhoff.2.i, 12
|
||||
%169 = call i64 @llvm.bpf.load.word(i8* %1, i64 %168) #2
|
||||
%170 = add i64 %nhoff.2.i, 16
|
||||
%171 = call i64 @llvm.bpf.load.word(i8* %1, i64 %170) #2
|
||||
%172 = add i64 %nhoff.2.i, 20
|
||||
%173 = call i64 @llvm.bpf.load.word(i8* %1, i64 %172) #2
|
||||
%174 = add i64 %nhoff.2.i, 24
|
||||
%175 = call i64 @llvm.bpf.load.word(i8* %1, i64 %174) #2
|
||||
%176 = add i64 %nhoff.2.i, 28
|
||||
%177 = call i64 @llvm.bpf.load.word(i8* %1, i64 %176) #2
|
||||
%178 = add i64 %nhoff.2.i, 32
|
||||
%179 = call i64 @llvm.bpf.load.word(i8* %1, i64 %178) #2
|
||||
%180 = add i64 %nhoff.2.i, 36
|
||||
%181 = call i64 @llvm.bpf.load.word(i8* %1, i64 %180) #2
|
||||
%182 = xor i64 %177, %175
|
||||
%183 = xor i64 %182, %179
|
||||
%184 = xor i64 %183, %181
|
||||
%185 = trunc i64 %184 to i32
|
||||
%186 = add i64 %nhoff.2.i, 40
|
||||
br label %187
|
||||
|
||||
; <label>:187 ; preds = %163, %159, %157, %113, %109, %107, %65, %parse_ip.exit.i
|
||||
%188 = phi i32 [ %63, %parse_ip.exit.i ], [ %185, %163 ], [ %63, %65 ], [ %135, %113 ], [ %103, %107 ], [ %103, %109 ], [ %153, %157 ], [ %153, %159 ]
|
||||
%189 = phi i64 [ %64, %parse_ip.exit.i ], [ %165, %163 ], [ 47, %65 ], [ %115, %113 ], [ %104, %107 ], [ %104, %109 ], [ %154, %157 ], [ %154, %159 ]
|
||||
%nhoff.7.i = phi i64 [ %nhoff.2.i, %parse_ip.exit.i ], [ %186, %163 ], [ %nhoff.2.i, %65 ], [ %136, %113 ], [ %108, %107 ], [ %112, %109 ], [ %158, %157 ], [ %162, %159 ]
|
||||
%cond.i.i = icmp eq i64 %189, 51
|
||||
%190 = select i1 %cond.i.i, i64 4, i64 0
|
||||
%191 = add i64 %190, %nhoff.7.i
|
||||
%192 = call i64 @llvm.bpf.load.word(i8* %1, i64 %191) #2
|
||||
store i32 %188, i32* %key, align 4
|
||||
%193 = bitcast i32* %key to i8*
|
||||
%194 = call i8* inttoptr (i64 1 to i8* (i8*, i8*)*)(i8* bitcast (%struct.bpf_map_def* @hash_map to i8*), i8* %193) #2
|
||||
%195 = icmp eq i8* %194, null
|
||||
br i1 %195, label %199, label %196
|
||||
|
||||
; <label>:196 ; preds = %187
|
||||
%197 = bitcast i8* %194 to i64*
|
||||
%198 = atomicrmw add i64* %197, i64 1 seq_cst
|
||||
br label %flow_dissector.exit.thread
|
||||
|
||||
; <label>:199 ; preds = %187
|
||||
store i64 1, i64* %val, align 8
|
||||
%200 = bitcast i64* %val to i8*
|
||||
%201 = call i32 inttoptr (i64 2 to i32 (i8*, i8*, i8*, i64)*)(i8* bitcast (%struct.bpf_map_def* @hash_map to i8*), i8* %193, i8* %200, i64 0) #2
|
||||
br label %flow_dissector.exit.thread
|
||||
|
||||
flow_dissector.exit.thread: ; preds = %86, %12, %196, %199
|
||||
ret i32 0
|
||||
; CHECK-LABEL: bpf_prog2:
|
||||
; CHECK: ldabs_h r0, r6.data + 12 # encoding: [0x28,0x00,0x00,0x00,0x0c,0x00,0x00,0x00]
|
||||
; CHECK: ldabs_h r0, r6.data + 16 # encoding: [0x28,0x00,0x00,0x00,0x10,0x00,0x00,0x00]
|
||||
; CHECK-NOT: implicit
|
||||
; CHECK: ld_64 r1
|
||||
; CHECK-NOT: ori
|
||||
; CHECK: call 1 # encoding: [0x85,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
|
||||
; CHECK: call 2 # encoding: [0x85,0x00,0x00,0x00,0x02,0x00,0x00,0x00]
|
||||
}
|
||||
|
||||
declare i64 @llvm.bpf.load.half(i8*, i64) #1
|
||||
|
||||
declare i64 @llvm.bpf.load.word(i8*, i64) #1
|
||||
|
||||
declare i64 @llvm.bpf.load.byte(i8*, i64) #1
|
17
test/CodeGen/BPF/struct_ret1.ll
Normal file
17
test/CodeGen/BPF/struct_ret1.ll
Normal file
@ -0,0 +1,17 @@
|
||||
; RUN: not llc -march=bpf < %s 2> %t1
|
||||
; RUN: FileCheck %s < %t1
|
||||
; CHECK: only integer returns
|
||||
|
||||
%struct.S = type { i32, i32, i32 }
|
||||
|
||||
@s = common global %struct.S zeroinitializer, align 4
|
||||
|
||||
; Function Attrs: nounwind readonly uwtable
|
||||
define { i64, i32 } @bar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #0 {
|
||||
entry:
|
||||
%retval.sroa.0.0.copyload = load i64* bitcast (%struct.S* @s to i64*), align 4
|
||||
%retval.sroa.2.0.copyload = load i32* getelementptr inbounds (%struct.S* @s, i64 0, i32 2), align 4
|
||||
%.fca.0.insert = insertvalue { i64, i32 } undef, i64 %retval.sroa.0.0.copyload, 0
|
||||
%.fca.1.insert = insertvalue { i64, i32 } %.fca.0.insert, i32 %retval.sroa.2.0.copyload, 1
|
||||
ret { i64, i32 } %.fca.1.insert
|
||||
}
|
12
test/CodeGen/BPF/struct_ret2.ll
Normal file
12
test/CodeGen/BPF/struct_ret2.ll
Normal file
@ -0,0 +1,12 @@
|
||||
; RUN: not llc -march=bpf < %s 2> %t1
|
||||
; RUN: FileCheck %s < %t1
|
||||
; CHECK: only small returns
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define { i64, i32 } @foo(i32 %a, i32 %b, i32 %c) #0 {
|
||||
entry:
|
||||
%call = tail call { i64, i32 } @bar(i32 %a, i32 %b, i32 %c, i32 1, i32 2) #3
|
||||
ret { i64, i32 } %call
|
||||
}
|
||||
|
||||
declare { i64, i32 } @bar(i32, i32, i32, i32, i32) #1
|
9
test/CodeGen/BPF/vararg1.ll
Normal file
9
test/CodeGen/BPF/vararg1.ll
Normal file
@ -0,0 +1,9 @@
|
||||
; RUN: not llc -march=bpf < %s 2> %t1
|
||||
; RUN: FileCheck %s < %t1
|
||||
; CHECK: with VarArgs
|
||||
|
||||
; Function Attrs: nounwind readnone uwtable
|
||||
define void @foo(i32 %a, ...) #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user