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 @@ -589,3 +589,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,17 @@ +//===- 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. + +// 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"; @@ -84,6 +85,8 @@ case r600: return "r600"; + case bpf: return "bpf"; + case sparcv9: case sparc: return "sparc"; @@ -189,6 +192,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) @@ -286,6 +290,7 @@ .Cases("mips64", "mips64eb", Triple::mips64) .Case("mips64el", Triple::mips64el) .Case("r600", Triple::r600) + .Case("bpf", Triple::bpf) .Case("hexagon", Triple::hexagon) .Case("s390x", Triple::systemz) .Case("sparc", Triple::sparc) @@ -864,6 +869,7 @@ case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: + case llvm::Triple::bpf: case llvm::Triple::le64: case llvm::Triple::mips64: case llvm::Triple::mips64el: @@ -899,6 +905,7 @@ case Triple::UnknownArch: case Triple::aarch64: case Triple::aarch64_be: + case Triple::bpf: case Triple::msp430: case Triple::systemz: case Triple::ppc64le: @@ -960,6 +967,7 @@ case Triple::aarch64: case Triple::aarch64_be: + case Triple::bpf: case Triple::le64: case Triple::amdil64: case Triple::hsail64: Index: lib/Target/BPF/BPF.h =================================================================== --- /dev/null +++ lib/Target/BPF/BPF.h @@ -0,0 +1,21 @@ +//===-- BPF.h - Top-level interface for BPF representation ----*- C++ -*-===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#ifndef TARGET_BPF_H +#define TARGET_BPF_H + +#include "MCTargetDesc/BPFMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class BPFTargetMachine; + +/// createBPFISelDag - This pass converts a legalized DAG into a +/// BPF-specific DAG, ready for instruction scheduling. +FunctionPass *createBPFISelDag(BPFTargetMachine &TM); + +extern Target TheBPFTarget; +} + +#endif Index: lib/Target/BPF/BPF.td =================================================================== --- /dev/null +++ lib/Target/BPF/BPF.td @@ -0,0 +1,29 @@ +//===- BPF.td - Describe the BPF Target Machine --------*- tablegen -*-===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Target-independent interfaces which we are implementing +include "llvm/Target/Target.td" + +// BPF Subtarget features. +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; +} + +// Declare the target which we are implementing +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,82 @@ +//===-- BPFAsmPrinter.cpp - BPF LLVM assembly writer --------------------===// +// 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, MCStreamer &Streamer) + : AsmPrinter(TM, 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,24 @@ +//===- BPFCallingConv.td - Calling Conventions BPF -------*- tablegen -*-===// +// 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 architectures. + +// 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,32 @@ +//===-- BPFFrameLowering.h - Define frame lowering for BPF ---*- C++ -*--===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#ifndef BPF_FRAMEINFO_H +#define BPF_FRAMEINFO_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,37 @@ +//===-- BPFFrameLowering.cpp - BPF Frame Information --------------------===// +// 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 --------===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// This file defines an instruction selector for the BPF target. + +#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 BPFInstrInfo +/// 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; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +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; +} + +/// createBPFISelDag - This pass converts a legalized DAG into a +/// BPF-specific DAG, ready for instruction scheduling. +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,82 @@ +//===-- BPFISelLowering.h - BPF DAG Lowering Interface -......-*- C++ -*-===// +// 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_TARGET_BPF_ISELLOWERING_H +#define LLVM_TARGET_BPF_ISELLOWERING_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); + + /// LowerOperation - Provide custom lowering hooks for some operations. + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + /// getTargetNodeName - 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; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + + 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 // LLVM_TARGET_BPF_ISELLOWERING_H Index: lib/Target/BPF/BPFISelLowering.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFISelLowering.cpp @@ -0,0 +1,644 @@ +//===-- BPFISelLowering.cpp - BPF DAG Lowering Implementation ----------===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// This file implements the BPFTargetLowering class. + +#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); + /* TODO: fail them gently + setOperationAction(ISD::BlockAddress, MVT::i64, Custom); + setOperationAction(ISD::JumpTable, MVT::i64, Custom); + setOperationAction(ISD::ConstantPool, 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 + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + + setLoadExtAction(ISD::SEXTLOAD, MVT::i8, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i16, Expand); + setLoadExtAction(ISD::SEXTLOAD, 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; + } + +/// LowerCCCArguments - transform physical registers into virtual registers and +/// generate load operations for arguments places on the stack. + 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 (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + 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; + SmallVector &Outs = CLI.Outs; + SmallVector &OutVals = CLI.OutVals; + SmallVector &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; + } + +/// LowerCCCCallTo - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. + + // 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); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + if (Outs.size() >= 6) { + DiagnosticInfoUnsupported Err(CLI.DL, *MF.getFunction(), + "too many args to ", Callee); + DAG.getContext()->diagnose(Err); + } + + for (unsigned i = 0, e = Outs.size(); i != e; ++i) { + ISD::ArgFlagsTy Flags = Outs[i].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, 4> RegsToPass; + + // Walk the register/memloc assignments, inserting copies/loads. + 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; + } + + // Arguments that can be passed on register must be kept at 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 (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, CLI.DL, RegsToPass[i].first, + RegsToPass[i].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 (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].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); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +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 (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), + RVLocs[i].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,29 @@ +//===- BPFInstrFormats.td - BPF Instruction Formats ----*- tablegen -*-===// +// 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,52 @@ +//===- BPFInstrInfo.h - BPF Instruction Information ---------*- C++ -*-===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#ifndef BPFINSTRUCTIONINFO_H +#define BPFINSTRUCTIONINFO_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,161 @@ +//===-- BPFInstrInfo.cpp - BPF Instruction Information --------*- C++ -*-===// +// 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), + RI(*this) { +} + +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,524 @@ +//===-- BPFInstrInfo.td - Target Description for BPF Target -------------===// +// 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 call : SDNode<"BPFISD::CALL", SDT_BPFCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def retflag : SDNode<"BPFISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_BPFCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def callseq_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>; + +// helper macros to produce 64-bit constant +// 0x11223344 55667788 -> +// reg = 0x11223344 +// reg <<= 32 +// reg += 0x55667788 +// +// 0x11223344 FF667788 -> +// reg = 0x11223345 +// reg <<= 32 +// reg += (long long)(int)0xFF667788 +def LO32 : SDNodeXFormgetTargetConstant((int64_t)(int32_t)(uint64_t)N->getZExtValue(), + MVT::i64); +}]>; +def HI32 : SDNodeXFormgetTargetConstant(((int64_t)N->getZExtValue() - + (int64_t)(int32_t)(uint64_t)N->getZExtValue()) >> 32, MVT::i64); +}]>; + + +def brtarget : Operand; +def calltarget : Operand; + +def s32imm : Operand { +} + +def u64imm : Operand { + let PrintMethod = "printImm64Operand"; +} + +def immSExt32 : 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 SF 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 br_op, string asmstr, PatLeaf Cond> + : InstBPF<(outs), (ins GPR:$rA, GPR:$rX, brtarget:$dst), + !strconcat(asmstr, "\t$rA, $rX goto $dst"), + [(BPFbrcc i64:$rA, i64:$rX, Cond, bb:$dst)]> { + bits<4> op; + bits<1> src; + bits<4> rA; + bits<4> rX; + bits<16> dst; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{55-52} = rX; + let Inst{51-48} = rA; + let Inst{47-32} = dst; + + let op = br_op; + let src = 1; + let bpfClass = 5; // BPF_JMP +} + +class JMP_RI br_op, string asmstr, PatLeaf Cond> + : InstBPF<(outs), (ins GPR:$rA, s32imm:$imm, brtarget:$dst), + !strconcat(asmstr, "i\t$rA, $imm goto $dst"), + [(BPFbrcc i64:$rA, immSExt32:$imm, Cond, bb:$dst)]> { + bits<4> op; + bits<1> src; + bits<4> rA; + bits<16> dst; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{51-48} = rA; + let Inst{47-32} = dst; + let Inst{31-0} = imm; + + let op = br_op; + let src = 0; + let bpfClass = 5; // BPF_JMP +} + +multiclass J op2Val, string asmstr, 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 aluOp, string asmstr, SDNode OpNode> + : InstBPF<(outs GPR:$rA), (ins GPR:$rS, s32imm:$imm), + !strconcat(asmstr, "i\t$rA, $imm"), + [(set GPR:$rA, (OpNode GPR:$rS, immSExt32:$imm))]> { + bits<4> op; + bits<1> src; + bits<4> rA; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{51-48} = rA; + let Inst{31-0} = imm; + + let op = aluOp; + let src = 0; + let bpfClass = 7; // BPF_ALU64 +} + +class ALU_RR aluOp, string asmstr, SDNode OpNode> + : InstBPF<(outs GPR:$rA), (ins GPR:$rS, GPR:$rX), + !strconcat(asmstr, "\t$rA, $rX"), + [(set GPR:$rA, (OpNode i64:$rS, i64:$rX))]> { + bits<4> op; + bits<1> src; + bits<4> rA; + bits<4> rX; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{55-52} = rX; + let Inst{51-48} = rA; + + let op = aluOp; + let src = 1; + let bpfClass = 7; // BPF_ALU64 +} + +multiclass ALU opVal, string asmstr, SDNode OpNode> { + def _rr : ALU_RR; + def _ri : ALU_RI; +} + +let Constraints = "$rA = $rS" 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:$rA), (ins GPR:$rX), + !strconcat(asmstr, "\t$rA, $rX"), + []> { + bits<4> op; + bits<1> src; + bits<4> rA; + bits<4> rX; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{55-52} = rX; + let Inst{51-48} = rA; + + let op = 0xb; // BPF_MOV + let src = 1; // BPF_X + let bpfClass = 7; // BPF_ALU64 +} + +class MOV_RI + : InstBPF<(outs GPR:$rA), (ins s32imm:$imm), + !strconcat(asmstr, "\t$rA, $imm"), + [(set GPR:$rA, (i64 immSExt32:$imm))]> { + bits<4> op; + bits<1> src; + bits<4> rA; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{51-48} = rA; + let Inst{31-0} = imm; + + let op = 0xb; // BPF_MOV + let src = 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 asmstr> + : InstBPF<(outs GPR:$rA), (ins u64imm:$imm), + !strconcat(asmstr, "\t$rA, $imm"), + [(set GPR:$rA, (i64 imm:$imm))]> { + + bits<3> mode; + bits<2> size; + bits<4> rA; + bits<64> imm; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = rA; + 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 asmstring, list pattern> + : InstBPF<(outs), (ins GPR:$rX, MEMri:$addr), + !strconcat(asmstring, "\t$addr, $rX"), pattern> { + bits<3> mode; + bits<2> size; + bits<4> rX; + 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} = rX; + let Inst{47-32} = addr{15-0}; // offset + + let mode = 3; // BPF_MEM + let size = sizeOp; + let bpfClass = 3; // BPF_STX +} + +class STOREi64 subOp, string asmstring, 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 asmstring, list pattern> + : InstBPF<(outs GPR:$rA), (ins MEMri:$addr), + !strconcat(asmstring, "\t$rA, $addr"), pattern> { + bits<3> mode; + bits<2> size; + bits<4> rA; + bits<20> addr; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = rA; + 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 asmstring, 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 subOp, string asmstring, list pattern> + : InstBPF<(outs), (ins brtarget:$dst), + !strconcat(asmstring, "\t$dst"), pattern> { + bits<4> op; + bits<16> dst; + bits<1> src; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{47-32} = dst; + + let op = subOp; + let src = 0; + let bpfClass = 5; // BPF_JMP +} + +class CALL + : InstBPF<(outs), (ins calltarget:$dst), + !strconcat(asmstring, "\t$dst"), []> { + bits<4> op; + bits<32> dst; + bits<1> src; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{31-0} = dst; + + let op = 8; // BPF_CALL + let src = 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:$dst)]>; +} + +// 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(asmstr, "\t$imm"), []> { + // mov r0, r0 == nop + bits<4> op; + bits<1> src; + bits<4> rA; + bits<4> rX; + + let Inst{63-60} = op; + let Inst{59} = src; + let Inst{55-52} = rX; + let Inst{51-48} = rA; + + let op = 0xb; // BPF_MOV + let src = 1; // BPF_X + let bpfClass = 7; // BPF_ALU64 + let rX = 0; // R0 + let rA = 0; // R0 +} + +let hasSideEffects = 0 in + def NOP : NOP_I<"nop">; + +class RET + : InstBPF<(outs), (ins), + !strconcat(asmstring, ""), [(retflag)]> { + 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", + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + "#ADJCALLSTACKUP $amt1 $amt2", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +let usesCustomInserter = 1 in { + def Select : Pseudo<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs, s32imm:$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)>; + +// arbitrary immediate +//def : Pat<(i64 imm:$imm), (ADD_ri (SLL_ri (MOV_ri (HI32 imm:$imm)), 32), (LO32 imm:$imm))>; + +// 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<(call tglobaladdr:$dst), (JAL tglobaladdr:$dst)>; +//def : Pat<(call texternalsym:$dst), (JAL texternalsym:$dst)>; +//def : Pat<(call (i32 imm:$dst)), (JAL (i32 imm:$dst))>; +def : Pat<(call 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 asmstr, PatFrag opNode> + : InstBPF<(outs GPR:$dst), (ins MEMri:$addr, GPR:$val), + !strconcat(asmstr, "\t$dst, $addr, $val"), + [(set GPR:$dst, (opNode ADDRri:$addr, GPR:$val))]> { + bits<3> mode; + bits<2> size; + bits<4> rX; + 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} = rX; + 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 asmstr, Intrinsic opNode> + : InstBPF<(outs), (ins GPR:$skb, s32imm:$imm), + !strconcat(asmstr, "\tr0, $skb.data + $imm"), + [(set R0, (opNode GPR:$skb, immSExt32:$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 asmstr, Intrinsic opNode> + : InstBPF<(outs), (ins GPR:$skb, GPR:$val), + !strconcat(asmstr, "\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,39 @@ +//===-- BPFMCInstLower.h - Lower MachineInstr to MCInst --------*- C++ -*-===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#ifndef BPF_MCINSTLOWER_H +#define BPF_MCINSTLOWER_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,72 @@ +//=-- BPFMCInstLower.cpp - Convert BPF MachineInstr to an MCInst ----------=// +// 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"); +// TODO support offsets +// Expr = MCBinaryExpr::CreateAdd(Expr, +// MCConstantExpr::Create(MO.getOffset(), Ctx), +// Ctx); + 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,37 @@ +//===- BPFRegisterInfo.h - BPF Register Information Impl ------*- C++ -*-===// +// 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 BPFREGISTERINFO_H +#define BPFREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "BPFGenRegisterInfo.inc" + +namespace llvm { + +class TargetInstrInfo; +class Type; + +struct BPFRegisterInfo : public BPFGenRegisterInfo { + const TargetInstrInfo &TII; + + BPFRegisterInfo(const TargetInstrInfo &tii); + + 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,82 @@ +//===-- BPFRegisterInfo.cpp - BPF Register Information --------*- C++ -*-===// +// 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(const TargetInstrInfo &tii) + : BPFGenRegisterInfo(BPF::R0), TII(tii) { +} + +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 that doesn't exist in VM + 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) { + 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,35 @@ +//===- BPFRegisterInfo.td - BPF Register defs ------------*- tablegen -*-===// +// 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,67 @@ +//===-- 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,29 @@ +//===-- 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,34 @@ +//===-- BPFTargetMachine.h - Define TargetMachine for BPF --- C++ ---===// +// 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 BPF_TARGETMACHINE_H +#define BPF_TARGETMACHINE_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,62 @@ +//===-- BPFTargetMachine.cpp - Define TargetMachine for BPF ---------===// +// 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,34 @@ +//= BPFInstPrinter.h - Convert BPF MCInst to asm syntax ---------*- C++ -*--// +// 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 BPFINSTPRINTER_H +#define 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,79 @@ +//===-- BPFInstPrinter.cpp - Convert BPF MCInst to asm syntax -----------===// +// 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,10 @@ +##===- lib/Target/BPF/InstPrinter/Makefile ----------------*- Makefile -*-===## +# 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,77 @@ +//===-- BPFAsmBackend.cpp - BPF Assembler Backend -----------------------===// +// 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,48 @@ +//===-- BPFELFObjectWriter.cpp - BPF Writer -------------------------===// +// 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,28 @@ +//=====-- BPFMCAsmInfo.h - BPF asm properties -----------*- C++ -*--====// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#ifndef BPF_MCASM_INFO_H +#define BPF_MCASM_INFO_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,160 @@ +//===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code ---------===// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#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); +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +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,52 @@ +//===-- BPFMCTargetDesc.h - BPF Target Descriptions -----------*- C++ -*-===// +// 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 BPFMCTARGETDESC_H +#define 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; + +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 -----------------===// +// 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,11 @@ +##===- lib/Target/BPF/TargetDesc/Makefile ----------------*- Makefile -*-===## +# 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,17 @@ +##===- lib/Target/BPF/Makefile ---------------------------*- Makefile -*-===## +# 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,13 @@ +//===-- BPFTargetInfo.cpp - BPF Target Implementation -----------------===// +// 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,10 @@ +##===- lib/Target/BPF/TargetInfo/Makefile ----------------*- Makefile -*-===## +# 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,47 @@ +; 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,21 @@ +; 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,29 @@ +; 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,59 @@ +; RUN: not llc -march=bpf < %s 2> %t1 +; RUN: FileCheck %s < %t1 +; CHECK: error: a.c:9:10 +; 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 + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !10, metadata !14), !dbg !15 + %arrayinit.begin = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 0, !dbg !16 + store i32 1, i32* %arrayinit.begin, align 8, !dbg !16, !tbaa !17 + %arrayinit.element = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 1, !dbg !16 + store i32 2, i32* %arrayinit.element, align 4, !dbg !16, !tbaa !17 + %arrayinit.element2 = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 2, !dbg !16 + store i32 3, i32* %arrayinit.element2, align 8, !dbg !16, !tbaa !17 + %arrayinit.start = getelementptr inbounds %struct.S* %.compoundliteral, i64 0, i32 0, i64 3, !dbg !16 + %scevgep4 = bitcast i32* %arrayinit.start to i8* + call void @llvm.memset.p0i8.i64(i8* %scevgep4, i8 0, i64 28, i32 4, i1 false), !dbg !21 + call void @foo(i32 %a, %struct.S* byval align 8 %.compoundliteral) #3, !dbg !24 + ret void, !dbg !24 +} + +declare void @foo(i32, %struct.S* byval align 8) #1 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2 + +; Function Attrs: nounwind +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #3 + +!llvm.module.flags = !{!11, !12} + +!1 = !{!"a.c", !"/w/llvm/bld"} +!2 = !{} +!3 = !{!4} +!4 = !{!"0x2e\00bar\00bar\00\007\000\001\000\000\00256\001\008", !1, !5, !6, null, void (i32)* @bar, null, null, !9} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [bar] +!5 = !{!"0x29", !1} ; [ DW_TAG_file_type ] [/w/llvm/bld/a.c] +!6 = !{!"0x15\00\000\000\000\000\000\000", null, null, null, !7, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!7 = !{null, !8} +!8 = !{!"0x24\00int\000\0032\0032\000\000\005", null, null} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] +!9 = !{!10} +!10 = !{!"0x101\00a\0016777223\000", !4, !5, !8} ; [ DW_TAG_arg_variable ] [a] [line 7] +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 2} +!14 = !{!"0x102"} ; [ DW_TAG_expression ] +!15 = !{i32 7, i32 14, !4, null} +!16 = !{i32 9, i32 10, !4, null} +!17 = !{!18, !18, i64 0} +!18 = !{!"int", !19, i64 0} +!19 = !{!"omnipotent char", !20, i64 0} +!20 = !{!"Simple C/C++ TBAA"} +!21 = !{i32 9, i32 10, !22, null} +!22 = !{!"0xb\003", !1, !23} ; [ DW_TAG_lexical_block ] [/w/llvm/bld/a.c] +!23 = !{!"0xb\001", !1, !4} ; [ DW_TAG_lexical_block ] [/w/llvm/bld/a.c] +!24 = !{i32 9, i32 10, !25, null} +!25 = !{!"0xb\002", !1, !4} ; [ DW_TAG_lexical_block ] [/w/llvm/bld/a.c] 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 + +;