brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.7 KiB · cd32e7d Raw
187 lines · cpp
1//===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the BPFMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "MCTargetDesc/BPFMCFixups.h"14#include "MCTargetDesc/BPFMCTargetDesc.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/MC/MCCodeEmitter.h"17#include "llvm/MC/MCContext.h"18#include "llvm/MC/MCExpr.h"19#include "llvm/MC/MCFixup.h"20#include "llvm/MC/MCInst.h"21#include "llvm/MC/MCInstrInfo.h"22#include "llvm/MC/MCRegisterInfo.h"23#include "llvm/MC/MCSubtargetInfo.h"24#include "llvm/Support/EndianStream.h"25#include <cassert>26#include <cstdint>27 28using namespace llvm;29 30#define DEBUG_TYPE "mccodeemitter"31 32namespace {33 34class BPFMCCodeEmitter : public MCCodeEmitter {35  const MCRegisterInfo &MRI;36  bool IsLittleEndian;37  MCContext &Ctx;38 39public:40  BPFMCCodeEmitter(const MCInstrInfo &, const MCRegisterInfo &mri,41                   bool IsLittleEndian, MCContext &ctx)42      : MRI(mri), IsLittleEndian(IsLittleEndian), Ctx(ctx) {}43  BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;44  void operator=(const BPFMCCodeEmitter &) = delete;45  ~BPFMCCodeEmitter() override = default;46 47  // getBinaryCodeForInstr - TableGen'erated function for getting the48  // binary encoding for an instruction.49  uint64_t getBinaryCodeForInstr(const MCInst &MI,50                                 SmallVectorImpl<MCFixup> &Fixups,51                                 const MCSubtargetInfo &STI) const;52 53  // getMachineOpValue - Return binary encoding of operand. If the machin54  // operand requires relocation, record the relocation and return zero.55  unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,56                             SmallVectorImpl<MCFixup> &Fixups,57                             const MCSubtargetInfo &STI) const;58 59  uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op,60                            SmallVectorImpl<MCFixup> &Fixups,61                            const MCSubtargetInfo &STI) const;62 63  void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,64                         SmallVectorImpl<MCFixup> &Fixups,65                         const MCSubtargetInfo &STI) const override;66};67 68} // end anonymous namespace69 70MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,71                                            MCContext &Ctx) {72  return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true, Ctx);73}74 75MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,76                                              MCContext &Ctx) {77  return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false, Ctx);78}79 80static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,81                     const MCExpr *Value, uint16_t Kind, bool PCRel = false) {82  Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));83}84 85unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,86                                             const MCOperand &MO,87                                             SmallVectorImpl<MCFixup> &Fixups,88                                             const MCSubtargetInfo &STI) const {89  if (MO.isReg())90    return MRI.getEncodingValue(MO.getReg());91  if (MO.isImm()) {92    uint64_t Imm = MO.getImm();93    uint64_t High32Bits = Imm >> 32, High33Bits = Imm >> 31;94    if (MI.getOpcode() != BPF::LD_imm64 && High32Bits != 0 &&95        High33Bits != 0x1FFFFFFFFULL) {96      Ctx.reportWarning(MI.getLoc(),97                        "immediate out of range, shall fit in 32 bits");98    }99    return static_cast<unsigned>(Imm);100  }101 102  assert(MO.isExpr());103 104  const MCExpr *Expr = MO.getExpr();105 106  assert(Expr->getKind() == MCExpr::SymbolRef);107 108  if (MI.getOpcode() == BPF::JAL)109    // func call name110    addFixup(Fixups, 0, Expr, FK_Data_4, true);111  else if (MI.getOpcode() == BPF::LD_imm64)112    addFixup(Fixups, 0, Expr, FK_SecRel_8);113  else if (MI.getOpcode() == BPF::JMPL)114    addFixup(Fixups, 0, Expr, BPF::FK_BPF_PCRel_4, true);115  else116    // bb label117    addFixup(Fixups, 0, Expr, FK_Data_2, true);118 119  return 0;120}121 122static uint8_t SwapBits(uint8_t Val)123{124  return (Val & 0x0F) << 4 | (Val & 0xF0) >> 4;125}126 127void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI,128                                         SmallVectorImpl<char> &CB,129                                         SmallVectorImpl<MCFixup> &Fixups,130                                         const MCSubtargetInfo &STI) const {131  unsigned Opcode = MI.getOpcode();132  raw_svector_ostream OS(CB);133  support::endian::Writer OSE(OS, IsLittleEndian ? llvm::endianness::little134                                                 : llvm::endianness::big);135 136  if (Opcode == BPF::LD_imm64 || Opcode == BPF::LD_pseudo) {137    uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);138    CB.push_back(Value >> 56);139    if (IsLittleEndian)140      CB.push_back((Value >> 48) & 0xff);141    else142      CB.push_back(SwapBits((Value >> 48) & 0xff));143    OSE.write<uint16_t>(0);144    OSE.write<uint32_t>(Value & 0xffffFFFF);145 146    const MCOperand &MO = MI.getOperand(1);147    uint64_t Imm = MO.isImm() ? MO.getImm() : 0;148    OSE.write<uint8_t>(0);149    OSE.write<uint8_t>(0);150    OSE.write<uint16_t>(0);151    OSE.write<uint32_t>(Imm >> 32);152  } else {153    // Get instruction encoding and emit it154    uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);155    CB.push_back(Value >> 56);156    if (IsLittleEndian)157      CB.push_back(char((Value >> 48) & 0xff));158    else159      CB.push_back(SwapBits((Value >> 48) & 0xff));160    OSE.write<uint16_t>((Value >> 32) & 0xffff);161    OSE.write<uint32_t>(Value & 0xffffFFFF);162  }163}164 165// Encode BPF Memory Operand166uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,167                                            SmallVectorImpl<MCFixup> &Fixups,168                                            const MCSubtargetInfo &STI) const {169  // For CMPXCHG instructions, output is implicitly in R0/W0,170  // so memory operand starts from operand 0.171  int MemOpStartIndex = 1, Opcode = MI.getOpcode();172  if (Opcode == BPF::CMPXCHGW32 || Opcode == BPF::CMPXCHGD)173    MemOpStartIndex = 0;174 175  uint64_t Encoding;176  const MCOperand Op1 = MI.getOperand(MemOpStartIndex);177  assert(Op1.isReg() && "First operand is not register.");178  Encoding = MRI.getEncodingValue(Op1.getReg());179  Encoding <<= 16;180  MCOperand Op2 = MI.getOperand(MemOpStartIndex + 1);181  assert(Op2.isImm() && "Second operand is not immediate.");182  Encoding |= Op2.getImm() & 0xffff;183  return Encoding;184}185 186#include "BPFGenMCCodeEmitter.inc"187