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/SPIRVInstPrinter.cpp
35294 views
1
//===-- SPIRVInstPrinter.cpp - Output SPIR-V MCInsts as ASM -----*- 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 class prints a SPIR-V MCInst to a .s file.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "SPIRVInstPrinter.h"
14
#include "SPIRV.h"
15
#include "SPIRVBaseInfo.h"
16
#include "SPIRVInstrInfo.h"
17
#include "llvm/ADT/APFloat.h"
18
#include "llvm/CodeGen/Register.h"
19
#include "llvm/MC/MCAsmInfo.h"
20
#include "llvm/MC/MCExpr.h"
21
#include "llvm/MC/MCInst.h"
22
#include "llvm/MC/MCInstrInfo.h"
23
#include "llvm/MC/MCSymbol.h"
24
#include "llvm/Support/Casting.h"
25
#include "llvm/Support/ErrorHandling.h"
26
#include "llvm/Support/FormattedStream.h"
27
28
using namespace llvm;
29
using namespace llvm::SPIRV;
30
31
#define DEBUG_TYPE "asm-printer"
32
33
// Include the auto-generated portion of the assembly writer.
34
#include "SPIRVGenAsmWriter.inc"
35
36
void SPIRVInstPrinter::printRemainingVariableOps(const MCInst *MI,
37
unsigned StartIndex,
38
raw_ostream &O,
39
bool SkipFirstSpace,
40
bool SkipImmediates) {
41
const unsigned NumOps = MI->getNumOperands();
42
for (unsigned i = StartIndex; i < NumOps; ++i) {
43
if (!SkipImmediates || !MI->getOperand(i).isImm()) {
44
if (!SkipFirstSpace || i != StartIndex)
45
O << ' ';
46
printOperand(MI, i, O);
47
}
48
}
49
}
50
51
void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
52
unsigned StartIndex,
53
raw_ostream &O) {
54
unsigned IsBitwidth16 = MI->getFlags() & SPIRV::ASM_PRINTER_WIDTH16;
55
const unsigned NumVarOps = MI->getNumOperands() - StartIndex;
56
57
assert((NumVarOps == 1 || NumVarOps == 2) &&
58
"Unsupported number of bits for literal variable");
59
60
O << ' ';
61
62
uint64_t Imm = MI->getOperand(StartIndex).getImm();
63
64
// Handle 64 bit literals.
65
if (NumVarOps == 2) {
66
Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
67
}
68
69
// Format and print float values.
70
if (MI->getOpcode() == SPIRV::OpConstantF && IsBitwidth16 == 0) {
71
APFloat FP = NumVarOps == 1 ? APFloat(APInt(32, Imm).bitsToFloat())
72
: APFloat(APInt(64, Imm).bitsToDouble());
73
74
// Print infinity and NaN as hex floats.
75
// TODO: Make sure subnormal numbers are handled correctly as they may also
76
// require hex float notation.
77
if (FP.isInfinity()) {
78
if (FP.isNegative())
79
O << '-';
80
O << "0x1p+128";
81
return;
82
}
83
if (FP.isNaN()) {
84
O << "0x1.8p+128";
85
return;
86
}
87
88
// Format val as a decimal floating point or scientific notation (whichever
89
// is shorter), with enough digits of precision to produce the exact value.
90
O << format("%.*g", std::numeric_limits<double>::max_digits10,
91
FP.convertToDouble());
92
93
return;
94
}
95
96
// Print integer values directly.
97
O << Imm;
98
}
99
100
void SPIRVInstPrinter::recordOpExtInstImport(const MCInst *MI) {
101
Register Reg = MI->getOperand(0).getReg();
102
auto Name = getSPIRVStringOperand(*MI, 1);
103
auto Set = getExtInstSetFromString(Name);
104
ExtInstSetIDs.insert({Reg, Set});
105
}
106
107
void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
108
StringRef Annot, const MCSubtargetInfo &STI,
109
raw_ostream &OS) {
110
const unsigned OpCode = MI->getOpcode();
111
printInstruction(MI, Address, OS);
112
113
if (OpCode == SPIRV::OpDecorate) {
114
printOpDecorate(MI, OS);
115
} else if (OpCode == SPIRV::OpExtInstImport) {
116
recordOpExtInstImport(MI);
117
} else if (OpCode == SPIRV::OpExtInst) {
118
printOpExtInst(MI, OS);
119
} else {
120
// Print any extra operands for variadic instructions.
121
const MCInstrDesc &MCDesc = MII.get(OpCode);
122
if (MCDesc.isVariadic()) {
123
const unsigned NumFixedOps = MCDesc.getNumOperands();
124
const unsigned LastFixedIndex = NumFixedOps - 1;
125
const int FirstVariableIndex = NumFixedOps;
126
if (NumFixedOps > 0 && MCDesc.operands()[LastFixedIndex].OperandType ==
127
MCOI::OPERAND_UNKNOWN) {
128
// For instructions where a custom type (not reg or immediate) comes as
129
// the last operand before the variable_ops. This is usually a StringImm
130
// operand, but there are a few other cases.
131
switch (OpCode) {
132
case SPIRV::OpTypeImage:
133
OS << ' ';
134
printSymbolicOperand<OperandCategory::AccessQualifierOperand>(
135
MI, FirstVariableIndex, OS);
136
break;
137
case SPIRV::OpVariable:
138
OS << ' ';
139
printOperand(MI, FirstVariableIndex, OS);
140
break;
141
case SPIRV::OpEntryPoint: {
142
// Print the interface ID operands, skipping the name's string
143
// literal.
144
printRemainingVariableOps(MI, NumFixedOps, OS, false, true);
145
break;
146
}
147
case SPIRV::OpExecutionMode:
148
case SPIRV::OpExecutionModeId:
149
case SPIRV::OpLoopMerge: {
150
// Print any literals after the OPERAND_UNKNOWN argument normally.
151
printRemainingVariableOps(MI, NumFixedOps, OS);
152
break;
153
}
154
default:
155
break; // printStringImm has already been handled.
156
}
157
} else {
158
// For instructions with no fixed ops or a reg/immediate as the final
159
// fixed operand, we can usually print the rest with "printOperand", but
160
// check for a few cases with custom types first.
161
switch (OpCode) {
162
case SPIRV::OpLoad:
163
case SPIRV::OpStore:
164
OS << ' ';
165
printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
166
MI, FirstVariableIndex, OS);
167
printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
168
break;
169
case SPIRV::OpImageSampleImplicitLod:
170
case SPIRV::OpImageSampleDrefImplicitLod:
171
case SPIRV::OpImageSampleProjImplicitLod:
172
case SPIRV::OpImageSampleProjDrefImplicitLod:
173
case SPIRV::OpImageFetch:
174
case SPIRV::OpImageGather:
175
case SPIRV::OpImageDrefGather:
176
case SPIRV::OpImageRead:
177
case SPIRV::OpImageWrite:
178
case SPIRV::OpImageSparseSampleImplicitLod:
179
case SPIRV::OpImageSparseSampleDrefImplicitLod:
180
case SPIRV::OpImageSparseSampleProjImplicitLod:
181
case SPIRV::OpImageSparseSampleProjDrefImplicitLod:
182
case SPIRV::OpImageSparseFetch:
183
case SPIRV::OpImageSparseGather:
184
case SPIRV::OpImageSparseDrefGather:
185
case SPIRV::OpImageSparseRead:
186
case SPIRV::OpImageSampleFootprintNV:
187
OS << ' ';
188
printSymbolicOperand<OperandCategory::ImageOperandOperand>(
189
MI, FirstVariableIndex, OS);
190
printRemainingVariableOps(MI, NumFixedOps + 1, OS);
191
break;
192
case SPIRV::OpCopyMemory:
193
case SPIRV::OpCopyMemorySized: {
194
const unsigned NumOps = MI->getNumOperands();
195
for (unsigned i = NumFixedOps; i < NumOps; ++i) {
196
OS << ' ';
197
printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, i,
198
OS);
199
if (MI->getOperand(i).getImm() & MemoryOperand::Aligned) {
200
assert(i + 1 < NumOps && "Missing alignment operand");
201
OS << ' ';
202
printOperand(MI, i + 1, OS);
203
i += 1;
204
}
205
}
206
break;
207
}
208
case SPIRV::OpConstantI:
209
case SPIRV::OpConstantF:
210
// The last fixed operand along with any variadic operands that follow
211
// are part of the variable value.
212
printOpConstantVarOps(MI, NumFixedOps - 1, OS);
213
break;
214
default:
215
printRemainingVariableOps(MI, NumFixedOps, OS);
216
break;
217
}
218
}
219
}
220
}
221
222
printAnnotation(OS, Annot);
223
}
224
225
void SPIRVInstPrinter::printOpExtInst(const MCInst *MI, raw_ostream &O) {
226
// The fixed operands have already been printed, so just need to decide what
227
// type of ExtInst operands to print based on the instruction set and number.
228
const MCInstrDesc &MCDesc = MII.get(MI->getOpcode());
229
unsigned NumFixedOps = MCDesc.getNumOperands();
230
const auto NumOps = MI->getNumOperands();
231
if (NumOps == NumFixedOps)
232
return;
233
234
O << ' ';
235
236
// TODO: implement special printing for OpenCLExtInst::vstor*.
237
printRemainingVariableOps(MI, NumFixedOps, O, true);
238
}
239
240
void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) {
241
// The fixed operands have already been printed, so just need to decide what
242
// type of decoration operands to print based on the Decoration type.
243
const MCInstrDesc &MCDesc = MII.get(MI->getOpcode());
244
unsigned NumFixedOps = MCDesc.getNumOperands();
245
246
if (NumFixedOps != MI->getNumOperands()) {
247
auto DecOp = MI->getOperand(NumFixedOps - 1);
248
auto Dec = static_cast<Decoration::Decoration>(DecOp.getImm());
249
250
O << ' ';
251
252
switch (Dec) {
253
case Decoration::BuiltIn:
254
printSymbolicOperand<OperandCategory::BuiltInOperand>(MI, NumFixedOps, O);
255
break;
256
case Decoration::UniformId:
257
printSymbolicOperand<OperandCategory::ScopeOperand>(MI, NumFixedOps, O);
258
break;
259
case Decoration::FuncParamAttr:
260
printSymbolicOperand<OperandCategory::FunctionParameterAttributeOperand>(
261
MI, NumFixedOps, O);
262
break;
263
case Decoration::FPRoundingMode:
264
printSymbolicOperand<OperandCategory::FPRoundingModeOperand>(
265
MI, NumFixedOps, O);
266
break;
267
case Decoration::FPFastMathMode:
268
printSymbolicOperand<OperandCategory::FPFastMathModeOperand>(
269
MI, NumFixedOps, O);
270
break;
271
case Decoration::LinkageAttributes:
272
case Decoration::UserSemantic:
273
printStringImm(MI, NumFixedOps, O);
274
break;
275
case Decoration::HostAccessINTEL:
276
printOperand(MI, NumFixedOps, O);
277
if (NumFixedOps + 1 < MI->getNumOperands()) {
278
O << ' ';
279
printStringImm(MI, NumFixedOps + 1, O);
280
}
281
break;
282
default:
283
printRemainingVariableOps(MI, NumFixedOps, O, true);
284
break;
285
}
286
}
287
}
288
289
static void printExpr(const MCExpr *Expr, raw_ostream &O) {
290
#ifndef NDEBUG
291
const MCSymbolRefExpr *SRE;
292
293
if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
294
SRE = cast<MCSymbolRefExpr>(BE->getLHS());
295
else
296
SRE = cast<MCSymbolRefExpr>(Expr);
297
298
MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
299
300
assert(Kind == MCSymbolRefExpr::VK_None);
301
#endif
302
O << *Expr;
303
}
304
305
void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
306
raw_ostream &O, const char *Modifier) {
307
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
308
if (OpNo < MI->getNumOperands()) {
309
const MCOperand &Op = MI->getOperand(OpNo);
310
if (Op.isReg())
311
O << '%' << (Register::virtReg2Index(Op.getReg()) + 1);
312
else if (Op.isImm())
313
O << formatImm((int64_t)Op.getImm());
314
else if (Op.isDFPImm())
315
O << formatImm((double)Op.getDFPImm());
316
else if (Op.isExpr())
317
printExpr(Op.getExpr(), O);
318
else
319
llvm_unreachable("Unexpected operand type");
320
}
321
}
322
323
void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo,
324
raw_ostream &O) {
325
const unsigned NumOps = MI->getNumOperands();
326
unsigned StrStartIndex = OpNo;
327
while (StrStartIndex < NumOps) {
328
if (MI->getOperand(StrStartIndex).isReg())
329
break;
330
331
std::string Str = getSPIRVStringOperand(*MI, StrStartIndex);
332
if (StrStartIndex != OpNo)
333
O << ' '; // Add a space if we're starting a new string/argument.
334
O << '"';
335
for (char c : Str) {
336
// Escape ", \n characters (might break for complex UTF-8).
337
if (c == '\n') {
338
O.write("\\n", 2);
339
} else {
340
if (c == '"')
341
O.write('\\');
342
O.write(c);
343
}
344
}
345
O << '"';
346
347
unsigned numOpsInString = (Str.size() / 4) + 1;
348
StrStartIndex += numOpsInString;
349
350
// Check for final Op of "OpDecorate %x %stringImm %linkageAttribute".
351
if (MI->getOpcode() == SPIRV::OpDecorate &&
352
MI->getOperand(1).getImm() ==
353
static_cast<unsigned>(Decoration::LinkageAttributes)) {
354
O << ' ';
355
printSymbolicOperand<OperandCategory::LinkageTypeOperand>(
356
MI, StrStartIndex, O);
357
break;
358
}
359
}
360
}
361
362
void SPIRVInstPrinter::printExtension(const MCInst *MI, unsigned OpNo,
363
raw_ostream &O) {
364
auto SetReg = MI->getOperand(2).getReg();
365
auto Set = ExtInstSetIDs[SetReg];
366
auto Op = MI->getOperand(OpNo).getImm();
367
O << getExtInstName(Set, Op);
368
}
369
370
template <OperandCategory::OperandCategory category>
371
void SPIRVInstPrinter::printSymbolicOperand(const MCInst *MI, unsigned OpNo,
372
raw_ostream &O) {
373
if (OpNo < MI->getNumOperands()) {
374
O << getSymbolicOperandMnemonic(category, MI->getOperand(OpNo).getImm());
375
}
376
}
377
378