1283625Sdim//===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code -----------===// 2283625Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6283625Sdim// 7283625Sdim//===----------------------------------------------------------------------===// 8283625Sdim// 9283625Sdim// This file implements the BPFMCCodeEmitter class. 10283625Sdim// 11283625Sdim//===----------------------------------------------------------------------===// 12283625Sdim 13283625Sdim#include "MCTargetDesc/BPFMCTargetDesc.h" 14314564Sdim#include "llvm/ADT/SmallVector.h" 15283625Sdim#include "llvm/MC/MCCodeEmitter.h" 16283625Sdim#include "llvm/MC/MCFixup.h" 17283625Sdim#include "llvm/MC/MCInst.h" 18283625Sdim#include "llvm/MC/MCInstrInfo.h" 19283625Sdim#include "llvm/MC/MCRegisterInfo.h" 20283625Sdim#include "llvm/MC/MCSubtargetInfo.h" 21314564Sdim#include "llvm/Support/Endian.h" 22309124Sdim#include "llvm/Support/EndianStream.h" 23314564Sdim#include <cassert> 24314564Sdim#include <cstdint> 25314564Sdim 26283625Sdimusing namespace llvm; 27283625Sdim 28283625Sdim#define DEBUG_TYPE "mccodeemitter" 29283625Sdim 30283625Sdimnamespace { 31314564Sdim 32283625Sdimclass BPFMCCodeEmitter : public MCCodeEmitter { 33314564Sdim const MCInstrInfo &MCII; 34283625Sdim const MCRegisterInfo &MRI; 35284236Sdim bool IsLittleEndian; 36283625Sdim 37283625Sdimpublic: 38314564Sdim BPFMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, 39314564Sdim bool IsLittleEndian) 40314564Sdim : MCII(mcii), MRI(mri), IsLittleEndian(IsLittleEndian) {} 41314564Sdim BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete; 42314564Sdim void operator=(const BPFMCCodeEmitter &) = delete; 43314564Sdim ~BPFMCCodeEmitter() override = default; 44283625Sdim 45283625Sdim // getBinaryCodeForInstr - TableGen'erated function for getting the 46283625Sdim // binary encoding for an instruction. 47283625Sdim uint64_t getBinaryCodeForInstr(const MCInst &MI, 48283625Sdim SmallVectorImpl<MCFixup> &Fixups, 49283625Sdim const MCSubtargetInfo &STI) const; 50283625Sdim 51283625Sdim // getMachineOpValue - Return binary encoding of operand. If the machin 52283625Sdim // operand requires relocation, record the relocation and return zero. 53283625Sdim unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, 54283625Sdim SmallVectorImpl<MCFixup> &Fixups, 55283625Sdim const MCSubtargetInfo &STI) const; 56283625Sdim 57283625Sdim uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op, 58283625Sdim SmallVectorImpl<MCFixup> &Fixups, 59283625Sdim const MCSubtargetInfo &STI) const; 60283625Sdim 61283625Sdim void encodeInstruction(const MCInst &MI, raw_ostream &OS, 62283625Sdim SmallVectorImpl<MCFixup> &Fixups, 63283625Sdim const MCSubtargetInfo &STI) const override; 64314564Sdim 65314564Sdimprivate: 66353358Sdim FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const; 67353358Sdim void 68353358Sdim verifyInstructionPredicates(const MCInst &MI, 69353358Sdim const FeatureBitset &AvailableFeatures) const; 70283625Sdim}; 71283625Sdim 72314564Sdim} // end anonymous namespace 73314564Sdim 74283625SdimMCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII, 75283625Sdim const MCRegisterInfo &MRI, 76283625Sdim MCContext &Ctx) { 77314564Sdim return new BPFMCCodeEmitter(MCII, MRI, true); 78283625Sdim} 79283625Sdim 80284236SdimMCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII, 81284236Sdim const MCRegisterInfo &MRI, 82284236Sdim MCContext &Ctx) { 83314564Sdim return new BPFMCCodeEmitter(MCII, MRI, false); 84284236Sdim} 85284236Sdim 86283625Sdimunsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI, 87283625Sdim const MCOperand &MO, 88283625Sdim SmallVectorImpl<MCFixup> &Fixups, 89283625Sdim const MCSubtargetInfo &STI) const { 90283625Sdim if (MO.isReg()) 91283625Sdim return MRI.getEncodingValue(MO.getReg()); 92283625Sdim if (MO.isImm()) 93283625Sdim return static_cast<unsigned>(MO.getImm()); 94283625Sdim 95283625Sdim assert(MO.isExpr()); 96283625Sdim 97283625Sdim const MCExpr *Expr = MO.getExpr(); 98283625Sdim 99283625Sdim assert(Expr->getKind() == MCExpr::SymbolRef); 100283625Sdim 101283625Sdim if (MI.getOpcode() == BPF::JAL) 102283625Sdim // func call name 103327952Sdim Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_4)); 104283625Sdim else if (MI.getOpcode() == BPF::LD_imm64) 105283625Sdim Fixups.push_back(MCFixup::create(0, Expr, FK_SecRel_8)); 106283625Sdim else 107283625Sdim // bb label 108283625Sdim Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_2)); 109283625Sdim 110283625Sdim return 0; 111283625Sdim} 112283625Sdim 113284236Sdimstatic uint8_t SwapBits(uint8_t Val) 114284236Sdim{ 115284236Sdim return (Val & 0x0F) << 4 | (Val & 0xF0) >> 4; 116283625Sdim} 117283625Sdim 118283625Sdimvoid BPFMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, 119283625Sdim SmallVectorImpl<MCFixup> &Fixups, 120283625Sdim const MCSubtargetInfo &STI) const { 121314564Sdim verifyInstructionPredicates(MI, 122314564Sdim computeAvailableFeatures(STI.getFeatureBits())); 123314564Sdim 124283625Sdim unsigned Opcode = MI.getOpcode(); 125341825Sdim support::endian::Writer OSE(OS, 126341825Sdim IsLittleEndian ? support::little : support::big); 127283625Sdim 128283625Sdim if (Opcode == BPF::LD_imm64 || Opcode == BPF::LD_pseudo) { 129283625Sdim uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI); 130341825Sdim OS << char(Value >> 56); 131284236Sdim if (IsLittleEndian) 132341825Sdim OS << char((Value >> 48) & 0xff); 133284236Sdim else 134341825Sdim OS << char(SwapBits((Value >> 48) & 0xff)); 135341825Sdim OSE.write<uint16_t>(0); 136341825Sdim OSE.write<uint32_t>(Value & 0xffffFFFF); 137283625Sdim 138283625Sdim const MCOperand &MO = MI.getOperand(1); 139283625Sdim uint64_t Imm = MO.isImm() ? MO.getImm() : 0; 140341825Sdim OSE.write<uint8_t>(0); 141341825Sdim OSE.write<uint8_t>(0); 142341825Sdim OSE.write<uint16_t>(0); 143341825Sdim OSE.write<uint32_t>(Imm >> 32); 144283625Sdim } else { 145283625Sdim // Get instruction encoding and emit it 146283625Sdim uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI); 147341825Sdim OS << char(Value >> 56); 148341825Sdim if (IsLittleEndian) 149341825Sdim OS << char((Value >> 48) & 0xff); 150341825Sdim else 151341825Sdim OS << char(SwapBits((Value >> 48) & 0xff)); 152341825Sdim OSE.write<uint16_t>((Value >> 32) & 0xffff); 153341825Sdim OSE.write<uint32_t>(Value & 0xffffFFFF); 154283625Sdim } 155283625Sdim} 156283625Sdim 157283625Sdim// Encode BPF Memory Operand 158283625Sdimuint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op, 159283625Sdim SmallVectorImpl<MCFixup> &Fixups, 160283625Sdim const MCSubtargetInfo &STI) const { 161283625Sdim uint64_t Encoding; 162283625Sdim const MCOperand Op1 = MI.getOperand(1); 163283625Sdim assert(Op1.isReg() && "First operand is not register."); 164283625Sdim Encoding = MRI.getEncodingValue(Op1.getReg()); 165283625Sdim Encoding <<= 16; 166283625Sdim MCOperand Op2 = MI.getOperand(2); 167283625Sdim assert(Op2.isImm() && "Second operand is not immediate."); 168283625Sdim Encoding |= Op2.getImm() & 0xffff; 169283625Sdim return Encoding; 170283625Sdim} 171283625Sdim 172314564Sdim#define ENABLE_INSTR_PREDICATE_VERIFIER 173283625Sdim#include "BPFGenMCCodeEmitter.inc" 174