LLVM 22.0.0git
SPIRVMCCodeEmitter.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the SPIRVMCCodeEmitter class.
10//
11//===----------------------------------------------------------------------===//
12
15#include "llvm/MC/MCFixup.h"
16#include "llvm/MC/MCInst.h"
17#include "llvm/MC/MCInstrInfo.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 the
37 // binary encoding for an instruction.
38 uint64_t getBinaryCodeForInstr(const MCInst &MI,
40 const MCSubtargetInfo &STI) const;
41
44 const MCSubtargetInfo &STI) const override;
45 void encodeUnknownType(const MCInst &MI, SmallVectorImpl<char> &CB,
47 const MCSubtargetInfo &STI) const;
48};
49
50} // end anonymous namespace
51
53 MCContext &Ctx) {
54 return new SPIRVMCCodeEmitter(MCII);
55}
56
58
59// Check if the instruction has a type argument for operand 1, and defines an ID
60// output register in operand 0. If so, we need to swap operands 0 and 1 so the
61// 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
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,
81 } else if (Op.isImm()) {
82 support::endian::write(CB, static_cast<uint32_t>(Op.getImm()),
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 all
90// remaining operands in the order they come naturally.
91static void emitTypedInstrOperands(const MCInst &MI,
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.
103 for (const auto &Op : MI)
104 emitOperand(Op, CB);
105}
106
107void SPIRVMCCodeEmitter::encodeUnknownType(const MCInst &MI,
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> ...]
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,
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;
138
139 // Emit the instruction arguments (emitting the output type first if present).
140 if (hasType(MI, MCII))
142 else
144}
145
146#include "SPIRVGenMCCodeEmitter.inc"
IRTranslator LLVM IR MI
static void emitUntypedInstrOperands(const MCInst &MI, SmallVectorImpl< char > &CB)
static void emitOperand(const MCOperand &Op, SmallVectorImpl< char > &CB)
static void emitTypedInstrOperands(const MCInst &MI, SmallVectorImpl< char > &CB)
static bool hasType(const MCInst &MI, const MCInstrInfo &MII)
This class represents an Operation in the Expression.
MCCodeEmitter - Generic instruction encoding interface.
Definition: MCCodeEmitter.h:23
virtual void encodeInstruction(const MCInst &Inst, SmallVectorImpl< char > &CB, SmallVectorImpl< MCFixup > &Fixups, const MCSubtargetInfo &STI) const =0
Encode the given Inst to bytes and append to CB.
MCCodeEmitter & operator=(const MCCodeEmitter &)=delete
Context object for machine code objects.
Definition: MCContext.h:83
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:188
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:199
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
Definition: MCInstrDesc.h:238
ArrayRef< MCOperandInfo > operands() const
Definition: MCInstrDesc.h:240
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
Definition: MCInstrDesc.h:249
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:27
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition: MCInstrInfo.h:64
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:40
Generic base class for all target subtargets.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned getIDFromRegister(unsigned Reg)
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition: Endian.h:92
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MCCodeEmitter * createSPIRVMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:67