Path: blob/main/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
35294 views
//===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the BPFMCCodeEmitter class.9//10//===----------------------------------------------------------------------===//1112#include "MCTargetDesc/BPFMCFixups.h"13#include "MCTargetDesc/BPFMCTargetDesc.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/MC/MCCodeEmitter.h"16#include "llvm/MC/MCExpr.h"17#include "llvm/MC/MCFixup.h"18#include "llvm/MC/MCInst.h"19#include "llvm/MC/MCInstrInfo.h"20#include "llvm/MC/MCRegisterInfo.h"21#include "llvm/MC/MCSubtargetInfo.h"22#include "llvm/Support/Endian.h"23#include "llvm/Support/EndianStream.h"24#include <cassert>25#include <cstdint>2627using namespace llvm;2829#define DEBUG_TYPE "mccodeemitter"3031namespace {3233class BPFMCCodeEmitter : public MCCodeEmitter {34const MCRegisterInfo &MRI;35bool IsLittleEndian;3637public:38BPFMCCodeEmitter(const MCInstrInfo &, const MCRegisterInfo &mri,39bool IsLittleEndian)40: MRI(mri), IsLittleEndian(IsLittleEndian) { }41BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;42void operator=(const BPFMCCodeEmitter &) = delete;43~BPFMCCodeEmitter() override = default;4445// getBinaryCodeForInstr - TableGen'erated function for getting the46// binary encoding for an instruction.47uint64_t getBinaryCodeForInstr(const MCInst &MI,48SmallVectorImpl<MCFixup> &Fixups,49const MCSubtargetInfo &STI) const;5051// getMachineOpValue - Return binary encoding of operand. If the machin52// operand requires relocation, record the relocation and return zero.53unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,54SmallVectorImpl<MCFixup> &Fixups,55const MCSubtargetInfo &STI) const;5657uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op,58SmallVectorImpl<MCFixup> &Fixups,59const MCSubtargetInfo &STI) const;6061void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,62SmallVectorImpl<MCFixup> &Fixups,63const MCSubtargetInfo &STI) const override;64};6566} // end anonymous namespace6768MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,69MCContext &Ctx) {70return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true);71}7273MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,74MCContext &Ctx) {75return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false);76}7778unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,79const MCOperand &MO,80SmallVectorImpl<MCFixup> &Fixups,81const MCSubtargetInfo &STI) const {82if (MO.isReg())83return MRI.getEncodingValue(MO.getReg());84if (MO.isImm())85return static_cast<unsigned>(MO.getImm());8687assert(MO.isExpr());8889const MCExpr *Expr = MO.getExpr();9091assert(Expr->getKind() == MCExpr::SymbolRef);9293if (MI.getOpcode() == BPF::JAL)94// func call name95Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_4));96else if (MI.getOpcode() == BPF::LD_imm64)97Fixups.push_back(MCFixup::create(0, Expr, FK_SecRel_8));98else if (MI.getOpcode() == BPF::JMPL)99Fixups.push_back(MCFixup::create(0, Expr, (MCFixupKind)BPF::FK_BPF_PCRel_4));100else101// bb label102Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_2));103104return 0;105}106107static uint8_t SwapBits(uint8_t Val)108{109return (Val & 0x0F) << 4 | (Val & 0xF0) >> 4;110}111112void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI,113SmallVectorImpl<char> &CB,114SmallVectorImpl<MCFixup> &Fixups,115const MCSubtargetInfo &STI) const {116unsigned Opcode = MI.getOpcode();117raw_svector_ostream OS(CB);118support::endian::Writer OSE(OS, IsLittleEndian ? llvm::endianness::little119: llvm::endianness::big);120121if (Opcode == BPF::LD_imm64 || Opcode == BPF::LD_pseudo) {122uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);123CB.push_back(Value >> 56);124if (IsLittleEndian)125CB.push_back((Value >> 48) & 0xff);126else127CB.push_back(SwapBits((Value >> 48) & 0xff));128OSE.write<uint16_t>(0);129OSE.write<uint32_t>(Value & 0xffffFFFF);130131const MCOperand &MO = MI.getOperand(1);132uint64_t Imm = MO.isImm() ? MO.getImm() : 0;133OSE.write<uint8_t>(0);134OSE.write<uint8_t>(0);135OSE.write<uint16_t>(0);136OSE.write<uint32_t>(Imm >> 32);137} else {138// Get instruction encoding and emit it139uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);140CB.push_back(Value >> 56);141if (IsLittleEndian)142CB.push_back(char((Value >> 48) & 0xff));143else144CB.push_back(SwapBits((Value >> 48) & 0xff));145OSE.write<uint16_t>((Value >> 32) & 0xffff);146OSE.write<uint32_t>(Value & 0xffffFFFF);147}148}149150// Encode BPF Memory Operand151uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,152SmallVectorImpl<MCFixup> &Fixups,153const MCSubtargetInfo &STI) const {154// For CMPXCHG instructions, output is implicitly in R0/W0,155// so memory operand starts from operand 0.156int MemOpStartIndex = 1, Opcode = MI.getOpcode();157if (Opcode == BPF::CMPXCHGW32 || Opcode == BPF::CMPXCHGD)158MemOpStartIndex = 0;159160uint64_t Encoding;161const MCOperand Op1 = MI.getOperand(MemOpStartIndex);162assert(Op1.isReg() && "First operand is not register.");163Encoding = MRI.getEncodingValue(Op1.getReg());164Encoding <<= 16;165MCOperand Op2 = MI.getOperand(MemOpStartIndex + 1);166assert(Op2.isImm() && "Second operand is not immediate.");167Encoding |= Op2.getImm() & 0xffff;168return Encoding;169}170171#include "BPFGenMCCodeEmitter.inc"172173174