Index: CODE_OWNERS.TXT =================================================================== --- CODE_OWNERS.TXT +++ CODE_OWNERS.TXT @@ -146,6 +146,10 @@ 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 Index: include/llvm/ADT/Triple.h =================================================================== --- include/llvm/ADT/Triple.h +++ include/llvm/ADT/Triple.h @@ -50,6 +50,7 @@ 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 Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -597,3 +597,4 @@ include "llvm/IR/IntrinsicsNVVM.td" include "llvm/IR/IntrinsicsMips.td" include "llvm/IR/IntrinsicsR600.td" +include "llvm/IR/IntrinsicsBPF.td" Index: include/llvm/IR/IntrinsicsBPF.td =================================================================== --- /dev/null +++ include/llvm/IR/IntrinsicsBPF.td @@ -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]>; +} Index: lib/Support/Triple.cpp =================================================================== --- lib/Support/Triple.cpp +++ lib/Support/Triple.cpp @@ -23,6 +23,7 @@ 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 @@ case amdgcn: case r600: return "amdgpu"; + case bpf: return "bpf"; + case sparcv9: case sparc: return "sparc"; @@ -191,6 +194,7 @@ .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 @@ .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 @@ 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 @@ 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 @@ case Triple::aarch64: case Triple::aarch64_be: + case Triple::bpf: case Triple::le64: case Triple::amdil64: case Triple::amdgcn: Index: lib/Target/BPF/BPF.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPF.h @@ -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 Index: lib/Target/BPF/BPF.td =================================================================== --- /dev/null +++ lib/Target/BPF/BPF.td @@ -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 Features> + : Processor; + +def : Proc<"generic", []>; + +def BPFInstPrinter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + +def BPF : Target { + let InstructionSet = BPFInstrInfo; + let AssemblyWriters = [BPFInstPrinter]; +} Index: lib/Target/BPF/BPFAsmPrinter.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFAsmPrinter.cpp @@ -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 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(""); + } +} + +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 X(TheBPFTarget); +} Index: lib/Target/BPF/BPFCallingConv.td =================================================================== --- /dev/null +++ lib/Target/BPF/BPFCallingConv.td @@ -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>, + + // 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)>; Index: lib/Target/BPF/BPFFrameLowering.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFFrameLowering.h @@ -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 Index: lib/Target/BPF/BPFFrameLowering.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFFrameLowering.cpp @@ -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); +} Index: lib/Target/BPF/BPFISelDAGToDAG.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFISelDAGToDAG.cpp @@ -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(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(Addr.getOperand(1)); + if (isInt<32>(CN->getSExtValue())) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = + dyn_cast(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(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(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); +} Index: lib/Target/BPF/BPFISelLowering.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFISelLowering.h @@ -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 &Ins, SDLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + // Lower a call into CALLSEQ_START - BPFISD:CALL - CALLSEQ_END chain + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + + // Lower incoming arguments, copy physregs into vregs + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &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 Index: lib/Target/BPF/BPFISelLowering.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFISelLowering.cpp @@ -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 &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &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 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 &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 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, 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(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, getPointerTy(), + G->getOffset(), 0); + else if (ExternalSymbolSDNode *E = dyn_cast(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 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 &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + + // CCValAssign - represent the assignment of the return value to a location + SmallVector 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 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 &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + + MachineFunction &MF = DAG.getMachineFunction(); + // Assign locations to each value returned by this call. + SmallVector 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(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(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(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; +} Index: lib/Target/BPF/BPFInstrFormats.td =================================================================== --- /dev/null +++ lib/Target/BPF/BPFInstrFormats.td @@ -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 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 pattern> + : InstBPF { + let Inst{63-0} = 0; + let isPseudo = 1; +} Index: lib/Target/BPF/BPFInstrInfo.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFInstrInfo.h @@ -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 &Cond, + bool AllowModify) const override; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const override; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl &Cond, + DebugLoc DL) const override; +}; +} + +#endif Index: lib/Target/BPF/BPFInstrInfo.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFInstrInfo.cpp @@ -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 &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 &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; +} Index: lib/Target/BPF/BPFInstrInfo.td =================================================================== --- /dev/null +++ lib/Target/BPF/BPFInstrInfo.td @@ -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; +def calltarget : Operand; + +def u64imm : Operand { + let PrintMethod = "printImm64Operand"; +} + +def i64immSExt32 : PatLeaf<(imm), + [{return isInt<32>(N->getSExtValue()); }]>; + +// Addressing modes. +def ADDRri : ComplexPattern; + +// Address operands +def MEMri : Operand { + 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 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 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 Opc, string OpcodeStr, PatLeaf Cond> { + def _rr : JMP_RR; + def _ri : JMP_RI; +} + +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 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 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 Opc, string OpcodeStr, SDNode OpNode> { + def _rr : ALU_RR; + def _ri : ALU_RI; +} + +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 + : 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 + : 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 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 SizeOp, string OpcodeStr, list 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 Opc, string OpcodeStr, PatFrag OpNode> + : STORE; + +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 SizeOp, string OpcodeStr, list 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 SizeOp, string OpcodeStr, PatFrag OpNode> + : LOAD; + +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 Opc, string OpcodeStr, list 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 + : 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 + : 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 + : 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 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 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 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>; Index: lib/Target/BPF/BPFMCInstLower.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFMCInstLower.h @@ -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 Index: lib/Target/BPF/BPFMCInstLower.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFMCInstLower.cpp @@ -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); + } +} Index: lib/Target/BPF/BPFRegisterInfo.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFRegisterInfo.h @@ -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 Index: lib/Target/BPF/BPFRegisterInfo.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFRegisterInfo.cpp @@ -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; +} Index: lib/Target/BPF/BPFRegisterInfo.td =================================================================== --- /dev/null +++ lib/Target/BPF/BPFRegisterInfo.td @@ -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 Enc, string n> : Register { + 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 + )>; Index: lib/Target/BPF/BPFSubtarget.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFSubtarget.h @@ -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 Index: lib/Target/BPF/BPFSubtarget.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFSubtarget.cpp @@ -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) {} Index: lib/Target/BPF/BPFTargetMachine.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPFTargetMachine.h @@ -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 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 Index: lib/Target/BPF/BPFTargetMachine.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFTargetMachine.cpp @@ -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 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()), + 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(); + } + + 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; +} Index: lib/Target/BPF/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/BPF/CMakeLists.txt @@ -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) Index: lib/Target/BPF/InstPrinter/BPFInstPrinter.h =================================================================== --- /dev/null +++ lib/Target/BPF/InstPrinter/BPFInstPrinter.h @@ -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 Index: lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp @@ -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(Expr)) + SRE = dyn_cast(BE->getLHS()); + else + SRE = dyn_cast(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; +} Index: lib/Target/BPF/InstPrinter/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/BPF/InstPrinter/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMBPFAsmPrinter + BPFInstPrinter.cpp + ) Index: lib/Target/BPF/InstPrinter/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/BPF/InstPrinter/LLVMBuild.txt @@ -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 Index: lib/Target/BPF/InstPrinter/Makefile =================================================================== --- /dev/null +++ lib/Target/BPF/InstPrinter/Makefile @@ -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 Index: lib/Target/BPF/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/BPF/LLVMBuild.txt @@ -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 Index: lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -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(); +} Index: lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp @@ -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); +} Index: lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h @@ -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 Index: lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp @@ -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 &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 &Fixups, + const MCSubtargetInfo &STI) const; + + uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &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 &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) + return MRI.getEncodingValue(MO.getReg()); + if (MO.isImm()) + return static_cast(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 &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 &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" Index: lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h @@ -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 Index: lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp @@ -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 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); +} Index: lib/Target/BPF/MCTargetDesc/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,6 @@ +add_llvm_library(LLVMBPFDesc + BPFMCTargetDesc.cpp + BPFAsmBackend.cpp + BPFMCCodeEmitter.cpp + BPFELFObjectWriter.cpp + ) Index: lib/Target/BPF/MCTargetDesc/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/LLVMBuild.txt @@ -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 Index: lib/Target/BPF/MCTargetDesc/Makefile =================================================================== --- /dev/null +++ lib/Target/BPF/MCTargetDesc/Makefile @@ -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 Index: lib/Target/BPF/Makefile =================================================================== --- /dev/null +++ lib/Target/BPF/Makefile @@ -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 Index: lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp @@ -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 X(TheBPFTarget, "bpf", "BPF"); +} Index: lib/Target/BPF/TargetInfo/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/BPF/TargetInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMBPFInfo + BPFTargetInfo.cpp + ) Index: lib/Target/BPF/TargetInfo/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/BPF/TargetInfo/LLVMBuild.txt @@ -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 Index: lib/Target/BPF/TargetInfo/Makefile =================================================================== --- /dev/null +++ lib/Target/BPF/TargetInfo/Makefile @@ -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 Index: lib/Target/LLVMBuild.txt =================================================================== --- lib/Target/LLVMBuild.txt +++ lib/Target/LLVMBuild.txt @@ -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 Index: test/CodeGen/BPF/alu8.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/alu8.ll @@ -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 +} Index: test/CodeGen/BPF/atomics.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/atomics.ll @@ -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 +} Index: test/CodeGen/BPF/basictest.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/basictest.ll @@ -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) +} Index: test/CodeGen/BPF/byval.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/byval.ll @@ -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 Index: test/CodeGen/BPF/cc_args.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/cc_args.ll @@ -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 +} Index: test/CodeGen/BPF/cc_ret.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/cc_ret.ll @@ -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 +} Index: test/CodeGen/BPF/cmp.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/cmp.ll @@ -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 + +;