| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| )>; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| add_llvm_library(LLVMBPFAsmPrinter | ||
| BPFInstPrinter.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| add_llvm_library(LLVMBPFDesc | ||
| BPFMCTargetDesc.cpp | ||
| BPFAsmBackend.cpp | ||
| BPFMCCodeEmitter.cpp | ||
| BPFELFObjectWriter.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| add_llvm_library(LLVMBPFInfo | ||
| BPFTargetInfo.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |