LLVM 24.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
42 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
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
57// Check if the instruction has a type argument for operand 1, and defines an ID
58// output register in operand 0. If so, we need to swap operands 0 and 1 so the
59// type comes first in the output, despide coming second in the MCInst.
60static bool hasType(const MCInst &MI, const MCInstrInfo &MII) {
61 const MCInstrDesc &MCDesc = MII.get(MI.getOpcode());
62 // If we define an output, and have at least one other argument.
63 if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) {
64 // Check if we define an ID, and take a type as operand 1.
65 return MCDesc.operands()[0].RegClass >= 0 &&
66 MCDesc.operands()[1].RegClass >= 0 &&
67 MCDesc.operands()[0].RegClass != SPIRV::TYPERegClassID &&
68 MCDesc.operands()[1].RegClass == SPIRV::TYPERegClassID;
69 }
70 return false;
71}
72
74 if (Op.isReg()) {
75 // Emit the id index starting at 1 (0 is an invalid index).
77 CB, SPIRV::getIDFromRegister(Op.getReg().id()) + 1,
79 } else if (Op.isImm()) {
80 support::endian::write(CB, static_cast<uint32_t>(Op.getImm()),
82 } else {
83 llvm_unreachable("Unexpected operand type in VReg");
84 }
85}
86
87// Emit the type in operand 1 before the ID in operand 0 it defines, and all
88// remaining operands in the order they come naturally.
89static void emitTypedInstrOperands(const MCInst &MI,
91 unsigned NumOps = MI.getNumOperands();
92 emitOperand(MI.getOperand(1), CB);
93 emitOperand(MI.getOperand(0), CB);
94 for (unsigned i = 2; i < NumOps; ++i)
95 emitOperand(MI.getOperand(i), CB);
96}
97
98// Emit operands in the order they come naturally.
101 for (const auto &Op : MI)
102 emitOperand(Op, CB);
103}
104
105void SPIRVMCCodeEmitter::encodeUnknownType(const MCInst &MI,
108 const MCSubtargetInfo &STI) const {
109 // Encode the first 32 SPIR-V bits with the number of args and the opcode.
110 const uint64_t OpCode = MI.getOperand(1).getImm();
111 const uint32_t NumWords = MI.getNumOperands();
112 const uint32_t FirstWord = (0xFFFF & NumWords) << 16 | (0xFFFF & OpCode);
113
114 // encoding: <opcode+len> <result type> [<operand0> <operand1> ...]
116
117 emitOperand(MI.getOperand(0), CB);
118 for (unsigned i = 2; i < NumWords; ++i)
119 emitOperand(MI.getOperand(i), CB);
120}
121
122void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI,
123 SmallVectorImpl<char> &CB,
124 SmallVectorImpl<MCFixup> &Fixups,
125 const MCSubtargetInfo &STI) const {
126 if (MI.getOpcode() == SPIRV::UNKNOWN_type) {
127 encodeUnknownType(MI, CB, Fixups, STI);
128 return;
129 }
130
131 // Encode the first 32 SPIR-V bytes with the number of args and the opcode.
132 const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI);
133 const uint32_t NumWords = MI.getNumOperands() + 1;
134 const uint32_t FirstWord = (NumWords << 16) | OpCode;
136
137 // Emit the instruction arguments (emitting the output type first if present).
138 if (hasType(MI, MCII))
140 else
142}
143
144#include "SPIRVGenMCCodeEmitter.inc"
uint64_t uint64_t
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
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)
MCCodeEmitter - Generic instruction encoding interface.
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.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
ArrayRef< MCOperandInfo > operands() const
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
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:89
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...
#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:82
This is an optimization pass for GlobalISel generic memory operations.
MCCodeEmitter * createSPIRVMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
DWARFExpression::Operation Op