| //===-- 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/ADT/SmallVector.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/Support/Endian.h" | |
| #include "llvm/Support/EndianStream.h" | |
| #include <cassert> | |
| #include <cstdint> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "mccodeemitter" | |
| namespace { | |
| class BPFMCCodeEmitter : public MCCodeEmitter { | |
| const MCInstrInfo &MCII; | |
| const MCRegisterInfo &MRI; | |
| bool IsLittleEndian; | |
| public: | |
| BPFMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, | |
| bool IsLittleEndian) | |
| : MCII(mcii), MRI(mri), IsLittleEndian(IsLittleEndian) {} | |
| BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete; | |
| void operator=(const BPFMCCodeEmitter &) = delete; | |
| ~BPFMCCodeEmitter() override = default; | |
| // 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; | |
| private: | |
| uint64_t computeAvailableFeatures(const FeatureBitset &FB) const; | |
| void verifyInstructionPredicates(const MCInst &MI, | |
| uint64_t AvailableFeatures) const; | |
| }; | |
| } // end anonymous namespace | |
| MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII, | |
| const MCRegisterInfo &MRI, | |
| MCContext &Ctx) { | |
| return new BPFMCCodeEmitter(MCII, MRI, true); | |
| } | |
| MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII, | |
| const MCRegisterInfo &MRI, | |
| MCContext &Ctx) { | |
| return new BPFMCCodeEmitter(MCII, MRI, false); | |
| } | |
| 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(); | |
| assert(Expr->getKind() == MCExpr::SymbolRef); | |
| if (MI.getOpcode() == BPF::JAL) | |
| // func call name | |
| Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_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; | |
| } | |
| static uint8_t SwapBits(uint8_t Val) | |
| { | |
| return (Val & 0x0F) << 4 | (Val & 0xF0) >> 4; | |
| } | |
| void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| verifyInstructionPredicates(MI, | |
| computeAvailableFeatures(STI.getFeatureBits())); | |
| unsigned Opcode = MI.getOpcode(); | |
| support::endian::Writer OSE(OS, | |
| IsLittleEndian ? support::little : support::big); | |
| if (Opcode == BPF::LD_imm64 || Opcode == BPF::LD_pseudo) { | |
| uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI); | |
| OS << char(Value >> 56); | |
| if (IsLittleEndian) | |
| OS << char((Value >> 48) & 0xff); | |
| else | |
| OS << char(SwapBits((Value >> 48) & 0xff)); | |
| OSE.write<uint16_t>(0); | |
| OSE.write<uint32_t>(Value & 0xffffFFFF); | |
| const MCOperand &MO = MI.getOperand(1); | |
| uint64_t Imm = MO.isImm() ? MO.getImm() : 0; | |
| OSE.write<uint8_t>(0); | |
| OSE.write<uint8_t>(0); | |
| OSE.write<uint16_t>(0); | |
| OSE.write<uint32_t>(Imm >> 32); | |
| } else { | |
| // Get instruction encoding and emit it | |
| uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI); | |
| OS << char(Value >> 56); | |
| if (IsLittleEndian) | |
| OS << char((Value >> 48) & 0xff); | |
| else | |
| OS << char(SwapBits((Value >> 48) & 0xff)); | |
| OSE.write<uint16_t>((Value >> 32) & 0xffff); | |
| OSE.write<uint32_t>(Value & 0xffffFFFF); | |
| } | |
| } | |
| // 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; | |
| } | |
| #define ENABLE_INSTR_PREDICATE_VERIFIER | |
| #include "BPFGenMCCodeEmitter.inc" |