Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
35294 views
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
13
#include "MCTargetDesc/SPIRVMCTargetDesc.h"
14
#include "llvm/CodeGen/Register.h"
15
#include "llvm/MC/MCCodeEmitter.h"
16
#include "llvm/MC/MCFixup.h"
17
#include "llvm/MC/MCInst.h"
18
#include "llvm/MC/MCInstrInfo.h"
19
#include "llvm/MC/MCRegisterInfo.h"
20
#include "llvm/MC/MCSubtargetInfo.h"
21
#include "llvm/Support/Debug.h"
22
#include "llvm/Support/Endian.h"
23
#include "llvm/Support/EndianStream.h"
24
25
using namespace llvm;
26
27
#define DEBUG_TYPE "spirv-mccodeemitter"
28
29
namespace {
30
31
class SPIRVMCCodeEmitter : public MCCodeEmitter {
32
const MCInstrInfo &MCII;
33
34
public:
35
SPIRVMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
36
SPIRVMCCodeEmitter(const SPIRVMCCodeEmitter &) = delete;
37
void operator=(const SPIRVMCCodeEmitter &) = delete;
38
~SPIRVMCCodeEmitter() override = default;
39
40
// getBinaryCodeForInstr - TableGen'erated function for getting the
41
// binary encoding for an instruction.
42
uint64_t getBinaryCodeForInstr(const MCInst &MI,
43
SmallVectorImpl<MCFixup> &Fixups,
44
const MCSubtargetInfo &STI) const;
45
46
void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
47
SmallVectorImpl<MCFixup> &Fixups,
48
const MCSubtargetInfo &STI) const override;
49
};
50
51
} // end anonymous namespace
52
53
MCCodeEmitter *llvm::createSPIRVMCCodeEmitter(const MCInstrInfo &MCII,
54
MCContext &Ctx) {
55
return new SPIRVMCCodeEmitter(MCII);
56
}
57
58
using EndianWriter = support::endian::Writer;
59
60
// Check if the instruction has a type argument for operand 1, and defines an ID
61
// output register in operand 0. If so, we need to swap operands 0 and 1 so the
62
// type comes first in the output, despide coming second in the MCInst.
63
static bool hasType(const MCInst &MI, const MCInstrInfo &MII) {
64
const MCInstrDesc &MCDesc = MII.get(MI.getOpcode());
65
// If we define an output, and have at least one other argument.
66
if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) {
67
// Check if we define an ID, and take a type as operand 1.
68
auto &DefOpInfo = MCDesc.operands()[0];
69
auto &FirstArgOpInfo = MCDesc.operands()[1];
70
return (DefOpInfo.RegClass == SPIRV::IDRegClassID ||
71
DefOpInfo.RegClass == SPIRV::ANYIDRegClassID) &&
72
FirstArgOpInfo.RegClass == SPIRV::TYPERegClassID;
73
}
74
return false;
75
}
76
77
static void emitOperand(const MCOperand &Op, SmallVectorImpl<char> &CB) {
78
if (Op.isReg()) {
79
// Emit the id index starting at 1 (0 is an invalid index).
80
support::endian::write<uint32_t>(
81
CB, Register::virtReg2Index(Op.getReg()) + 1, llvm::endianness::little);
82
} else if (Op.isImm()) {
83
support::endian::write(CB, static_cast<uint32_t>(Op.getImm()),
84
llvm::endianness::little);
85
} else {
86
llvm_unreachable("Unexpected operand type in VReg");
87
}
88
}
89
90
// Emit the type in operand 1 before the ID in operand 0 it defines, and all
91
// remaining operands in the order they come naturally.
92
static void emitTypedInstrOperands(const MCInst &MI,
93
SmallVectorImpl<char> &CB) {
94
unsigned NumOps = MI.getNumOperands();
95
emitOperand(MI.getOperand(1), CB);
96
emitOperand(MI.getOperand(0), CB);
97
for (unsigned i = 2; i < NumOps; ++i)
98
emitOperand(MI.getOperand(i), CB);
99
}
100
101
// Emit operands in the order they come naturally.
102
static void emitUntypedInstrOperands(const MCInst &MI,
103
SmallVectorImpl<char> &CB) {
104
for (const auto &Op : MI)
105
emitOperand(Op, CB);
106
}
107
108
void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI,
109
SmallVectorImpl<char> &CB,
110
SmallVectorImpl<MCFixup> &Fixups,
111
const MCSubtargetInfo &STI) const {
112
// Encode the first 32 SPIR-V bytes with the number of args and the opcode.
113
const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI);
114
const uint32_t NumWords = MI.getNumOperands() + 1;
115
const uint32_t FirstWord = (NumWords << 16) | OpCode;
116
support::endian::write(CB, FirstWord, llvm::endianness::little);
117
118
// Emit the instruction arguments (emitting the output type first if present).
119
if (hasType(MI, MCII))
120
emitTypedInstrOperands(MI, CB);
121
else
122
emitUntypedInstrOperands(MI, CB);
123
}
124
125
#include "SPIRVGenMCCodeEmitter.inc"
126
127