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