Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
35294 views
//===-- SPIRVMCCodeEmitter.cpp - Emit SPIR-V machine code -------*- C++ -*-===//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 SPIRVMCCodeEmitter class.9//10//===----------------------------------------------------------------------===//1112#include "MCTargetDesc/SPIRVMCTargetDesc.h"13#include "llvm/CodeGen/Register.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/MCRegisterInfo.h"19#include "llvm/MC/MCSubtargetInfo.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/Endian.h"22#include "llvm/Support/EndianStream.h"2324using namespace llvm;2526#define DEBUG_TYPE "spirv-mccodeemitter"2728namespace {2930class SPIRVMCCodeEmitter : public MCCodeEmitter {31const MCInstrInfo &MCII;3233public:34SPIRVMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}35SPIRVMCCodeEmitter(const SPIRVMCCodeEmitter &) = delete;36void operator=(const SPIRVMCCodeEmitter &) = delete;37~SPIRVMCCodeEmitter() override = default;3839// getBinaryCodeForInstr - TableGen'erated function for getting the40// binary encoding for an instruction.41uint64_t getBinaryCodeForInstr(const MCInst &MI,42SmallVectorImpl<MCFixup> &Fixups,43const MCSubtargetInfo &STI) const;4445void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,46SmallVectorImpl<MCFixup> &Fixups,47const MCSubtargetInfo &STI) const override;48};4950} // end anonymous namespace5152MCCodeEmitter *llvm::createSPIRVMCCodeEmitter(const MCInstrInfo &MCII,53MCContext &Ctx) {54return new SPIRVMCCodeEmitter(MCII);55}5657using EndianWriter = support::endian::Writer;5859// 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) {63const MCInstrDesc &MCDesc = MII.get(MI.getOpcode());64// If we define an output, and have at least one other argument.65if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) {66// Check if we define an ID, and take a type as operand 1.67auto &DefOpInfo = MCDesc.operands()[0];68auto &FirstArgOpInfo = MCDesc.operands()[1];69return (DefOpInfo.RegClass == SPIRV::IDRegClassID ||70DefOpInfo.RegClass == SPIRV::ANYIDRegClassID) &&71FirstArgOpInfo.RegClass == SPIRV::TYPERegClassID;72}73return false;74}7576static void emitOperand(const MCOperand &Op, SmallVectorImpl<char> &CB) {77if (Op.isReg()) {78// Emit the id index starting at 1 (0 is an invalid index).79support::endian::write<uint32_t>(80CB, Register::virtReg2Index(Op.getReg()) + 1, llvm::endianness::little);81} else if (Op.isImm()) {82support::endian::write(CB, static_cast<uint32_t>(Op.getImm()),83llvm::endianness::little);84} else {85llvm_unreachable("Unexpected operand type in VReg");86}87}8889// 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,92SmallVectorImpl<char> &CB) {93unsigned NumOps = MI.getNumOperands();94emitOperand(MI.getOperand(1), CB);95emitOperand(MI.getOperand(0), CB);96for (unsigned i = 2; i < NumOps; ++i)97emitOperand(MI.getOperand(i), CB);98}99100// Emit operands in the order they come naturally.101static void emitUntypedInstrOperands(const MCInst &MI,102SmallVectorImpl<char> &CB) {103for (const auto &Op : MI)104emitOperand(Op, CB);105}106107void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI,108SmallVectorImpl<char> &CB,109SmallVectorImpl<MCFixup> &Fixups,110const MCSubtargetInfo &STI) const {111// Encode the first 32 SPIR-V bytes with the number of args and the opcode.112const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI);113const uint32_t NumWords = MI.getNumOperands() + 1;114const uint32_t FirstWord = (NumWords << 16) | OpCode;115support::endian::write(CB, FirstWord, llvm::endianness::little);116117// Emit the instruction arguments (emitting the output type first if present).118if (hasType(MI, MCII))119emitTypedInstrOperands(MI, CB);120else121emitUntypedInstrOperands(MI, CB);122}123124#include "SPIRVGenMCCodeEmitter.inc"125126127