159 changes: 159 additions & 0 deletions llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
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);
}
642 changes: 642 additions & 0 deletions llvm/lib/Target/BPF/BPFISelLowering.cpp

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions llvm/lib/Target/BPF/BPFISelLowering.h
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
33 changes: 33 additions & 0 deletions llvm/lib/Target/BPF/BPFInstrFormats.td
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;
}
168 changes: 168 additions & 0 deletions llvm/lib/Target/BPF/BPFInstrInfo.cpp
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;
}
60 changes: 60 additions & 0 deletions llvm/lib/Target/BPF/BPFInstrInfo.h
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
507 changes: 507 additions & 0 deletions llvm/lib/Target/BPF/BPFInstrInfo.td

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions llvm/lib/Target/BPF/BPFMCInstLower.cpp
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);
}
}
43 changes: 43 additions & 0 deletions llvm/lib/Target/BPF/BPFMCInstLower.h
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
88 changes: 88 additions & 0 deletions llvm/lib/Target/BPF/BPFRegisterInfo.cpp
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;
}
41 changes: 41 additions & 0 deletions llvm/lib/Target/BPF/BPFRegisterInfo.h
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
41 changes: 41 additions & 0 deletions llvm/lib/Target/BPF/BPFRegisterInfo.td
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
)>;
31 changes: 31 additions & 0 deletions llvm/lib/Target/BPF/BPFSubtarget.cpp
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) {}
66 changes: 66 additions & 0 deletions llvm/lib/Target/BPF/BPFSubtarget.h
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
68 changes: 68 additions & 0 deletions llvm/lib/Target/BPF/BPFTargetMachine.cpp
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;
}
40 changes: 40 additions & 0 deletions llvm/lib/Target/BPF/BPFTargetMachine.h
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
27 changes: 27 additions & 0 deletions llvm/lib/Target/BPF/CMakeLists.txt
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)
86 changes: 86 additions & 0 deletions llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
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;
}
41 changes: 41 additions & 0 deletions llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.h
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
3 changes: 3 additions & 0 deletions llvm/lib/Target/BPF/InstPrinter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_llvm_library(LLVMBPFAsmPrinter
BPFInstPrinter.cpp
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/BPF/InstPrinter/LLVMBuild.txt
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
16 changes: 16 additions & 0 deletions llvm/lib/Target/BPF/InstPrinter/Makefile
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
32 changes: 32 additions & 0 deletions llvm/lib/Target/BPF/LLVMBuild.txt
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
83 changes: 83 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
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();
}
53 changes: 53 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
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);
}
36 changes: 36 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
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
167 changes: 167 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
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"
111 changes: 111 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
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);
}
59 changes: 59 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
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
6 changes: 6 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/CMakeLists.txt
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
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/LLVMBuild.txt
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
16 changes: 16 additions & 0 deletions llvm/lib/Target/BPF/MCTargetDesc/Makefile
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
21 changes: 21 additions & 0 deletions llvm/lib/Target/BPF/Makefile
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
18 changes: 18 additions & 0 deletions llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
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");
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/BPF/TargetInfo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_llvm_library(LLVMBPFInfo
BPFTargetInfo.cpp
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/BPF/TargetInfo/LLVMBuild.txt
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
16 changes: 16 additions & 0 deletions llvm/lib/Target/BPF/TargetInfo/Makefile
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
2 changes: 1 addition & 1 deletion llvm/lib/Target/LLVMBuild.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;

[common]
subdirectories = ARM AArch64 CppBackend Hexagon MSP430 NVPTX Mips PowerPC R600 Sparc SystemZ X86 XCore
subdirectories = ARM AArch64 BPF CppBackend Hexagon MSP430 NVPTX Mips PowerPC R600 Sparc SystemZ X86 XCore

; This is a special group whose required libraries are extended (by llvm-build)
; with the best execution engine (the native JIT, if available, or the
Expand Down
46 changes: 46 additions & 0 deletions llvm/test/CodeGen/BPF/alu8.ll
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
}
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/BPF/atomics.ll
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
}
28 changes: 28 additions & 0 deletions llvm/test/CodeGen/BPF/basictest.ll
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)
}
27 changes: 27 additions & 0 deletions llvm/test/CodeGen/BPF/byval.ll
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
96 changes: 96 additions & 0 deletions llvm/test/CodeGen/BPF/cc_args.ll
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
}
48 changes: 48 additions & 0 deletions llvm/test/CodeGen/BPF/cc_ret.ll
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
}
119 changes: 119 additions & 0 deletions llvm/test/CodeGen/BPF/cmp.ll
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
}
46 changes: 46 additions & 0 deletions llvm/test/CodeGen/BPF/ex1.ll
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
50 changes: 50 additions & 0 deletions llvm/test/CodeGen/BPF/intrinsics.ll
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
43 changes: 43 additions & 0 deletions llvm/test/CodeGen/BPF/load.ll
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)
111 changes: 111 additions & 0 deletions llvm/test/CodeGen/BPF/loops.ll
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
}
12 changes: 12 additions & 0 deletions llvm/test/CodeGen/BPF/many_args1.ll
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
15 changes: 15 additions & 0 deletions llvm/test/CodeGen/BPF/many_args2.ll
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
}
117 changes: 117 additions & 0 deletions llvm/test/CodeGen/BPF/sanity.ll
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
99 changes: 99 additions & 0 deletions llvm/test/CodeGen/BPF/setcc.ll
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
101 changes: 101 additions & 0 deletions llvm/test/CodeGen/BPF/shifts.ll
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
}
Loading