brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.7 KiB · 314f580 Raw
147 lines · cpp
1//===-- SPIRVMCCodeEmitter.cpp - Emit SPIR-V machine code -------*- C++ -*-===//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 SPIRVMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "MCTargetDesc/SPIRVMCTargetDesc.h"14#include "llvm/MC/MCCodeEmitter.h"15#include "llvm/MC/MCFixup.h"16#include "llvm/MC/MCInst.h"17#include "llvm/MC/MCInstrInfo.h"18#include "llvm/MC/MCSubtargetInfo.h"19#include "llvm/Support/EndianStream.h"20 21using namespace llvm;22 23#define DEBUG_TYPE "spirv-mccodeemitter"24 25namespace {26 27class SPIRVMCCodeEmitter : public MCCodeEmitter {28  const MCInstrInfo &MCII;29 30public:31  SPIRVMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}32  SPIRVMCCodeEmitter(const SPIRVMCCodeEmitter &) = delete;33  void operator=(const SPIRVMCCodeEmitter &) = delete;34  ~SPIRVMCCodeEmitter() override = default;35 36  // getBinaryCodeForInstr - TableGen'erated function for getting the37  // binary encoding for an instruction.38  uint64_t getBinaryCodeForInstr(const MCInst &MI,39                                 SmallVectorImpl<MCFixup> &Fixups,40                                 const MCSubtargetInfo &STI) const;41 42  void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,43                         SmallVectorImpl<MCFixup> &Fixups,44                         const MCSubtargetInfo &STI) const override;45  void encodeUnknownType(const MCInst &MI, SmallVectorImpl<char> &CB,46                         SmallVectorImpl<MCFixup> &Fixups,47                         const MCSubtargetInfo &STI) const;48};49 50} // end anonymous namespace51 52MCCodeEmitter *llvm::createSPIRVMCCodeEmitter(const MCInstrInfo &MCII,53                                              MCContext &Ctx) {54  return new SPIRVMCCodeEmitter(MCII);55}56 57using EndianWriter = support::endian::Writer;58 59// Check if the instruction has a type argument for operand 1, and defines an ID60// output register in operand 0. If so, we need to swap operands 0 and 1 so the61// type comes first in the output, despide coming second in the MCInst.62static bool hasType(const MCInst &MI, const MCInstrInfo &MII) {63  const MCInstrDesc &MCDesc = MII.get(MI.getOpcode());64  // If we define an output, and have at least one other argument.65  if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) {66    // Check if we define an ID, and take a type as operand 1.67    return MCDesc.operands()[0].RegClass >= 0 &&68           MCDesc.operands()[1].RegClass >= 0 &&69           MCDesc.operands()[0].RegClass != SPIRV::TYPERegClassID &&70           MCDesc.operands()[1].RegClass == SPIRV::TYPERegClassID;71  }72  return false;73}74 75static void emitOperand(const MCOperand &Op, SmallVectorImpl<char> &CB) {76  if (Op.isReg()) {77    // Emit the id index starting at 1 (0 is an invalid index).78    support::endian::write<uint32_t>(79        CB, SPIRV::getIDFromRegister(Op.getReg().id()) + 1,80        llvm::endianness::little);81  } else if (Op.isImm()) {82    support::endian::write(CB, static_cast<uint32_t>(Op.getImm()),83                           llvm::endianness::little);84  } else {85    llvm_unreachable("Unexpected operand type in VReg");86  }87}88 89// Emit the type in operand 1 before the ID in operand 0 it defines, and all90// remaining operands in the order they come naturally.91static void emitTypedInstrOperands(const MCInst &MI,92                                   SmallVectorImpl<char> &CB) {93  unsigned NumOps = MI.getNumOperands();94  emitOperand(MI.getOperand(1), CB);95  emitOperand(MI.getOperand(0), CB);96  for (unsigned i = 2; i < NumOps; ++i)97    emitOperand(MI.getOperand(i), CB);98}99 100// Emit operands in the order they come naturally.101static void emitUntypedInstrOperands(const MCInst &MI,102                                     SmallVectorImpl<char> &CB) {103  for (const auto &Op : MI)104    emitOperand(Op, CB);105}106 107void SPIRVMCCodeEmitter::encodeUnknownType(const MCInst &MI,108                                           SmallVectorImpl<char> &CB,109                                           SmallVectorImpl<MCFixup> &Fixups,110                                           const MCSubtargetInfo &STI) const {111  // Encode the first 32 SPIR-V bits with the number of args and the opcode.112  const uint64_t OpCode = MI.getOperand(1).getImm();113  const uint32_t NumWords = MI.getNumOperands();114  const uint32_t FirstWord = (0xFFFF & NumWords) << 16 | (0xFFFF & OpCode);115 116  // encoding: <opcode+len> <result type> [<operand0> <operand1> ...]117  support::endian::write(CB, FirstWord, llvm::endianness::little);118 119  emitOperand(MI.getOperand(0), CB);120  for (unsigned i = 2; i < NumWords; ++i)121    emitOperand(MI.getOperand(i), CB);122}123 124void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI,125                                           SmallVectorImpl<char> &CB,126                                           SmallVectorImpl<MCFixup> &Fixups,127                                           const MCSubtargetInfo &STI) const {128  if (MI.getOpcode() == SPIRV::UNKNOWN_type) {129    encodeUnknownType(MI, CB, Fixups, STI);130    return;131  }132 133  // Encode the first 32 SPIR-V bytes with the number of args and the opcode.134  const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI);135  const uint32_t NumWords = MI.getNumOperands() + 1;136  const uint32_t FirstWord = (NumWords << 16) | OpCode;137  support::endian::write(CB, FirstWord, llvm::endianness::little);138 139  // Emit the instruction arguments (emitting the output type first if present).140  if (hasType(MI, MCII))141    emitTypedInstrOperands(MI, CB);142  else143    emitUntypedInstrOperands(MI, CB);144}145 146#include "SPIRVGenMCCodeEmitter.inc"147