Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/glslang/SPIRV/disassemble.cpp
21453 views
1
//
2
// Copyright (C) 2014-2015 LunarG, Inc.
3
//
4
// All rights reserved.
5
//
6
// Redistribution and use in source and binary forms, with or without
7
// modification, are permitted provided that the following conditions
8
// are met:
9
//
10
// Redistributions of source code must retain the above copyright
11
// notice, this list of conditions and the following disclaimer.
12
//
13
// Redistributions in binary form must reproduce the above
14
// copyright notice, this list of conditions and the following
15
// disclaimer in the documentation and/or other materials provided
16
// with the distribution.
17
//
18
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19
// contributors may be used to endorse or promote products derived
20
// from this software without specific prior written permission.
21
//
22
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
// POSSIBILITY OF SUCH DAMAGE.
34
35
//
36
// Disassembler for SPIR-V.
37
//
38
39
#include <cstdint>
40
#include <cstdlib>
41
#include <cstring>
42
#include <cassert>
43
#include <iomanip>
44
#include <stack>
45
#include <sstream>
46
#include <cstring>
47
#include <utility>
48
49
#include "disassemble.h"
50
#include "doc.h"
51
#include "spvUtil.h"
52
53
namespace spv {
54
extern "C" {
55
// Include C-based headers that don't have a namespace
56
#include "GLSL.std.450.h"
57
#include "GLSL.ext.AMD.h"
58
#include "GLSL.ext.NV.h"
59
#include "GLSL.ext.ARM.h"
60
#include "NonSemanticShaderDebugInfo100.h"
61
#include "GLSL.ext.QCOM.h"
62
}
63
}
64
static const char* GlslStd450DebugNames[spv::GLSLstd450Count];
65
66
namespace spv {
67
68
static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
69
static const char* GLSLextNVGetDebugNames(const char*, unsigned);
70
static const char* NonSemanticShaderDebugInfo100GetDebugNames(unsigned);
71
72
static void Kill(std::ostream& out, const char* message)
73
{
74
out << std::endl << "Disassembly failed: " << message << std::endl;
75
exit(1);
76
}
77
78
// used to identify the extended instruction library imported when printing
79
enum ExtInstSet {
80
GLSL450Inst,
81
GLSLextAMDInst,
82
GLSLextNVInst,
83
OpenCLExtInst,
84
NonSemanticDebugPrintfExtInst,
85
NonSemanticDebugBreakExtInst,
86
NonSemanticShaderDebugInfo100
87
};
88
89
// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
90
class SpirvStream {
91
public:
92
SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
93
virtual ~SpirvStream() { }
94
95
void validate();
96
void processInstructions();
97
98
protected:
99
SpirvStream(const SpirvStream&);
100
SpirvStream& operator=(const SpirvStream&);
101
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : Op::OpNop; }
102
103
// Output methods
104
void outputIndent();
105
void formatId(Id id, std::stringstream&);
106
void outputResultId(Id id);
107
void outputTypeId(Id id);
108
void outputId(Id id);
109
void outputMask(OperandClass operandClass, unsigned mask);
110
void disassembleImmediates(int numOperands);
111
void disassembleIds(int numOperands);
112
std::pair<int, std::string> decodeString();
113
int disassembleString();
114
void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
115
116
// Data
117
std::ostream& out; // where to write the disassembly
118
const std::vector<unsigned int>& stream; // the actual word stream
119
int size; // the size of the word stream
120
int word; // the next word of the stream to read
121
122
// map each <id> to the instruction that created it
123
Id bound;
124
std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
125
126
std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
127
128
// schema
129
unsigned int schema;
130
131
// stack of structured-merge points
132
std::stack<Id> nestedControl;
133
Id nextNestedControl; // need a slight delay for when we are nested
134
};
135
136
void SpirvStream::validate()
137
{
138
size = (int)stream.size();
139
if (size < 4)
140
Kill(out, "stream is too short");
141
142
// Magic number
143
if (stream[word++] != MagicNumber) {
144
out << "Bad magic number";
145
return;
146
}
147
148
// Version
149
out << "// Module Version " << std::hex << stream[word++] << std::endl;
150
151
// Generator's magic number
152
out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
153
154
// Result <id> bound
155
bound = stream[word++];
156
idInstruction.resize(bound);
157
idDescriptor.resize(bound);
158
out << "// Id's are bound by " << bound << std::endl;
159
out << std::endl;
160
161
// Reserved schema, must be 0 for now
162
schema = stream[word++];
163
if (schema != 0)
164
Kill(out, "bad schema, must be 0");
165
}
166
167
// Loop over all the instructions, in order, processing each.
168
// Boiler plate for each is handled here directly, the rest is dispatched.
169
void SpirvStream::processInstructions()
170
{
171
// Instructions
172
while (word < size) {
173
int instructionStart = word;
174
175
// Instruction wordCount and opcode
176
unsigned int firstWord = stream[word];
177
unsigned wordCount = firstWord >> WordCountShift;
178
Op opCode = (Op)(firstWord & OpCodeMask);
179
int nextInst = word + wordCount;
180
++word;
181
182
// Presence of full instruction
183
if (nextInst > size)
184
Kill(out, "stream instruction terminated too early");
185
186
// Base for computing number of operands; will be updated as more is learned
187
unsigned numOperands = wordCount - 1;
188
189
// Type <id>
190
Id typeId = 0;
191
if (InstructionDesc[enumCast(opCode)].hasType()) {
192
typeId = stream[word++];
193
--numOperands;
194
}
195
196
// Result <id>
197
Id resultId = 0;
198
if (InstructionDesc[enumCast(opCode)].hasResult()) {
199
resultId = stream[word++];
200
--numOperands;
201
202
// save instruction for future reference
203
idInstruction[resultId] = instructionStart;
204
}
205
206
outputResultId(resultId);
207
outputTypeId(typeId);
208
outputIndent();
209
210
// Hand off the Op and all its operands
211
disassembleInstruction(resultId, typeId, opCode, numOperands);
212
if (word != nextInst) {
213
out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
214
word = nextInst;
215
}
216
out << std::endl;
217
}
218
}
219
220
void SpirvStream::outputIndent()
221
{
222
for (int i = 0; i < (int)nestedControl.size(); ++i)
223
out << " ";
224
}
225
226
void SpirvStream::formatId(Id id, std::stringstream& idStream)
227
{
228
if (id != 0) {
229
// On instructions with no IDs, this is called with "0", which does not
230
// have to be within ID bounds on null shaders.
231
if (id >= bound)
232
Kill(out, "Bad <id>");
233
234
idStream << id;
235
if (idDescriptor[id].size() > 0)
236
idStream << "(" << idDescriptor[id] << ")";
237
}
238
}
239
240
void SpirvStream::outputResultId(Id id)
241
{
242
const int width = 16;
243
std::stringstream idStream;
244
formatId(id, idStream);
245
out << std::setw(width) << std::right << idStream.str();
246
if (id != 0)
247
out << ":";
248
else
249
out << " ";
250
251
if (nestedControl.size() && id == nestedControl.top())
252
nestedControl.pop();
253
}
254
255
void SpirvStream::outputTypeId(Id id)
256
{
257
const int width = 12;
258
std::stringstream idStream;
259
formatId(id, idStream);
260
out << std::setw(width) << std::right << idStream.str() << " ";
261
}
262
263
void SpirvStream::outputId(Id id)
264
{
265
if (id >= bound)
266
Kill(out, "Bad <id>");
267
268
out << id;
269
if (idDescriptor[id].size() > 0)
270
out << "(" << idDescriptor[id] << ")";
271
}
272
273
void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
274
{
275
if (mask == 0)
276
out << "None";
277
else {
278
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
279
if (mask & (1 << m))
280
out << OperandClassParams[operandClass].getName(m) << " ";
281
}
282
}
283
}
284
285
void SpirvStream::disassembleImmediates(int numOperands)
286
{
287
for (int i = 0; i < numOperands; ++i) {
288
out << stream[word++];
289
if (i < numOperands - 1)
290
out << " ";
291
}
292
}
293
294
void SpirvStream::disassembleIds(int numOperands)
295
{
296
for (int i = 0; i < numOperands; ++i) {
297
outputId(stream[word++]);
298
if (i < numOperands - 1)
299
out << " ";
300
}
301
}
302
303
// decode string from words at current position (non-consuming)
304
std::pair<int, std::string> SpirvStream::decodeString()
305
{
306
std::string res;
307
int wordPos = word;
308
char c;
309
bool done = false;
310
311
do {
312
unsigned int content = stream[wordPos];
313
for (int charCount = 0; charCount < 4; ++charCount) {
314
c = content & 0xff;
315
content >>= 8;
316
if (c == '\0') {
317
done = true;
318
break;
319
}
320
res += c;
321
}
322
++wordPos;
323
} while(! done);
324
325
return std::make_pair(wordPos - word, res);
326
}
327
328
// return the number of operands consumed by the string
329
int SpirvStream::disassembleString()
330
{
331
out << " \"";
332
333
std::pair<int, std::string> decoderes = decodeString();
334
335
out << decoderes.second;
336
out << "\"";
337
338
word += decoderes.first;
339
340
return decoderes.first;
341
}
342
343
static uint32_t popcount(uint32_t mask)
344
{
345
uint32_t count = 0;
346
while (mask) {
347
if (mask & 1) {
348
count++;
349
}
350
mask >>= 1;
351
}
352
return count;
353
}
354
355
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
356
{
357
// Process the opcode
358
359
out << (OpcodeString((int)opCode) + 2); // leave out the "Op"
360
361
if (opCode == Op::OpLoopMerge || opCode == Op::OpSelectionMerge)
362
nextNestedControl = stream[word];
363
else if (opCode == Op::OpBranchConditional || opCode == Op::OpSwitch) {
364
if (nextNestedControl) {
365
nestedControl.push(nextNestedControl);
366
nextNestedControl = 0;
367
}
368
} else if (opCode == Op::OpExtInstImport) {
369
idDescriptor[resultId] = decodeString().second;
370
}
371
else {
372
if (resultId != 0 && idDescriptor[resultId].size() == 0) {
373
switch (opCode) {
374
case Op::OpTypeInt:
375
switch (stream[word]) {
376
case 8: idDescriptor[resultId] = "int8_t"; break;
377
case 16: idDescriptor[resultId] = "int16_t"; break;
378
default: assert(0); [[fallthrough]];
379
case 32: idDescriptor[resultId] = "int"; break;
380
case 64: idDescriptor[resultId] = "int64_t"; break;
381
}
382
break;
383
case Op::OpTypeFloat:
384
switch (stream[word]) {
385
case 8:
386
case 16:
387
if (numOperands > 1) {
388
switch (stream[word+1]) {
389
default:
390
assert(0); [[fallthrough]];
391
case (int)spv::FPEncoding::BFloat16KHR:
392
idDescriptor[resultId] = "bfloat16_t";
393
break;
394
case (int)spv::FPEncoding::Float8E4M3EXT:
395
idDescriptor[resultId] = "floate4m3_t";
396
break;
397
case (int)spv::FPEncoding::Float8E5M2EXT:
398
idDescriptor[resultId] = "floate5m2_t";
399
break;
400
}
401
} else {
402
idDescriptor[resultId] = "float16_t";
403
}
404
break;
405
default: assert(0); [[fallthrough]];
406
case 32: idDescriptor[resultId] = "float"; break;
407
case 64: idDescriptor[resultId] = "float64_t"; break;
408
}
409
break;
410
case Op::OpTypeBool:
411
idDescriptor[resultId] = "bool";
412
break;
413
case Op::OpTypeStruct:
414
idDescriptor[resultId] = "struct";
415
break;
416
case Op::OpTypePointer:
417
idDescriptor[resultId] = "ptr";
418
break;
419
case Op::OpTypeVector:
420
if (idDescriptor[stream[word]].size() > 0) {
421
if (idDescriptor[stream[word]].substr(0,2) == "bf") {
422
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 2);
423
} else {
424
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
425
}
426
if (strstr(idDescriptor[stream[word]].c_str(), "8")) {
427
idDescriptor[resultId].append("8");
428
}
429
if (strstr(idDescriptor[stream[word]].c_str(), "16")) {
430
idDescriptor[resultId].append("16");
431
}
432
if (strstr(idDescriptor[stream[word]].c_str(), "64")) {
433
idDescriptor[resultId].append("64");
434
}
435
}
436
idDescriptor[resultId].append("vec");
437
switch (stream[word + 1]) {
438
case 2: idDescriptor[resultId].append("2"); break;
439
case 3: idDescriptor[resultId].append("3"); break;
440
case 4: idDescriptor[resultId].append("4"); break;
441
case 8: idDescriptor[resultId].append("8"); break;
442
case 16: idDescriptor[resultId].append("16"); break;
443
case 32: idDescriptor[resultId].append("32"); break;
444
default: break;
445
}
446
break;
447
default:
448
break;
449
}
450
}
451
}
452
453
// Process the operands. Note, a new context-dependent set could be
454
// swapped in mid-traversal.
455
456
// Handle images specially, so can put out helpful strings.
457
if (opCode == Op::OpTypeImage) {
458
out << " ";
459
disassembleIds(1);
460
out << " " << DimensionString((int)(Dim)stream[word++]);
461
out << (stream[word++] != 0 ? " depth" : "");
462
out << (stream[word++] != 0 ? " array" : "");
463
out << (stream[word++] != 0 ? " multi-sampled" : "");
464
switch (stream[word++]) {
465
case 0: out << " runtime"; break;
466
case 1: out << " sampled"; break;
467
case 2: out << " nonsampled"; break;
468
}
469
out << " format:" << ImageFormatString((int)(ImageFormat)stream[word++]);
470
471
if (numOperands == 8) {
472
out << " " << AccessQualifierString(stream[word++]);
473
}
474
return;
475
}
476
477
// Handle all the parameterized operands
478
for (int op = 0; op < InstructionDesc[enumCast(opCode)].operands.getNum() && numOperands > 0; ++op) {
479
out << " ";
480
OperandClass operandClass = InstructionDesc[enumCast(opCode)].operands.getClass(op);
481
switch (operandClass) {
482
case OperandId:
483
case OperandScope:
484
case OperandMemorySemantics:
485
disassembleIds(1);
486
--numOperands;
487
// Get names for printing "(XXX)" for readability, *after* this id
488
if (opCode == Op::OpName)
489
idDescriptor[stream[word - 1]] = decodeString().second;
490
break;
491
case OperandVariableIds:
492
disassembleIds(numOperands);
493
return;
494
case OperandImageOperands:
495
outputMask(OperandImageOperands, stream[word++]);
496
--numOperands;
497
disassembleIds(numOperands);
498
return;
499
case OperandOptionalLiteral:
500
case OperandVariableLiterals:
501
if ((opCode == Op::OpDecorate && stream[word - 1] == Decoration::BuiltIn) ||
502
(opCode == Op::OpMemberDecorate && stream[word - 1] == Decoration::BuiltIn)) {
503
out << BuiltInString(stream[word++]);
504
--numOperands;
505
++op;
506
}
507
disassembleImmediates(numOperands);
508
return;
509
case OperandVariableIdLiteral:
510
while (numOperands > 0) {
511
out << std::endl;
512
outputResultId(0);
513
outputTypeId(0);
514
outputIndent();
515
out << " Type ";
516
disassembleIds(1);
517
out << ", member ";
518
disassembleImmediates(1);
519
numOperands -= 2;
520
}
521
return;
522
case OperandVariableLiteralId:
523
while (numOperands > 0) {
524
out << std::endl;
525
outputResultId(0);
526
outputTypeId(0);
527
outputIndent();
528
out << " case ";
529
disassembleImmediates(1);
530
out << ": ";
531
disassembleIds(1);
532
numOperands -= 2;
533
}
534
return;
535
case OperandLiteralNumber:
536
disassembleImmediates(1);
537
--numOperands;
538
if (opCode == Op::OpExtInst) {
539
ExtInstSet extInstSet = GLSL450Inst;
540
const char* name = idDescriptor[stream[word - 2]].c_str();
541
if (strcmp("OpenCL.std", name) == 0) {
542
extInstSet = OpenCLExtInst;
543
} else if (strcmp("OpenCL.DebugInfo.100", name) == 0) {
544
extInstSet = OpenCLExtInst;
545
} else if (strcmp("NonSemantic.DebugPrintf", name) == 0) {
546
extInstSet = NonSemanticDebugPrintfExtInst;
547
} else if (strcmp("NonSemantic.DebugBreak", name) == 0) {
548
extInstSet = NonSemanticDebugBreakExtInst;
549
} else if (strcmp("NonSemantic.Shader.DebugInfo.100", name) == 0) {
550
extInstSet = NonSemanticShaderDebugInfo100;
551
} else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
552
strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
553
strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
554
strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
555
extInstSet = GLSLextAMDInst;
556
} else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
557
strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
558
strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
559
strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0 ||
560
strcmp(spv::E_SPV_NV_fragment_shader_barycentric, name) == 0 ||
561
strcmp(spv::E_SPV_NV_mesh_shader, name) == 0) {
562
extInstSet = GLSLextNVInst;
563
}
564
unsigned entrypoint = stream[word - 1];
565
if (extInstSet == GLSL450Inst) {
566
if (entrypoint < GLSLstd450Count) {
567
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
568
}
569
} else if (extInstSet == GLSLextAMDInst) {
570
out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
571
}
572
else if (extInstSet == GLSLextNVInst) {
573
out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
574
} else if (extInstSet == NonSemanticDebugPrintfExtInst) {
575
out << "(DebugPrintf)";
576
} else if (extInstSet == NonSemanticDebugBreakExtInst) {
577
out << "(DebugBreak)";
578
} else if (extInstSet == NonSemanticShaderDebugInfo100) {
579
out << "(" << NonSemanticShaderDebugInfo100GetDebugNames(entrypoint) << ")";
580
}
581
}
582
break;
583
case OperandOptionalLiteralString:
584
case OperandLiteralString:
585
numOperands -= disassembleString();
586
break;
587
case OperandVariableLiteralStrings:
588
while (numOperands > 0)
589
numOperands -= disassembleString();
590
return;
591
case OperandMemoryAccess:
592
{
593
outputMask(OperandMemoryAccess, stream[word++]);
594
--numOperands;
595
// Put a space after "None" if there are any remaining operands
596
if (numOperands && stream[word-1] == 0) {
597
out << " ";
598
}
599
uint32_t mask = stream[word-1];
600
// Aligned is the only memory access operand that uses an immediate
601
// value, and it is also the first operand that uses a value at all.
602
if (mask & (uint32_t)MemoryAccessMask::Aligned) {
603
disassembleImmediates(1);
604
numOperands--;
605
if (numOperands)
606
out << " ";
607
}
608
609
uint32_t bitCount = popcount(mask & (uint32_t)(MemoryAccessMask::MakePointerAvailable | MemoryAccessMask::MakePointerVisible));
610
disassembleIds(bitCount);
611
numOperands -= bitCount;
612
}
613
break;
614
case OperandTensorAddressingOperands:
615
{
616
outputMask(OperandTensorAddressingOperands, stream[word++]);
617
--numOperands;
618
// Put a space after "None" if there are any remaining operands
619
if (numOperands && stream[word-1] == 0) {
620
out << " ";
621
}
622
uint32_t bitCount = popcount(stream[word-1]);
623
disassembleIds(bitCount);
624
numOperands -= bitCount;
625
}
626
break;
627
default:
628
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
629
630
if (OperandClassParams[operandClass].bitmask)
631
outputMask(operandClass, stream[word++]);
632
else
633
out << OperandClassParams[operandClass].getName(stream[word++]);
634
--numOperands;
635
636
break;
637
}
638
}
639
640
return;
641
}
642
643
static void GLSLstd450GetDebugNames(const char** names)
644
{
645
for (int i = 0; i < GLSLstd450Count; ++i)
646
names[i] = "Unknown";
647
648
names[GLSLstd450Round] = "Round";
649
names[GLSLstd450RoundEven] = "RoundEven";
650
names[GLSLstd450Trunc] = "Trunc";
651
names[GLSLstd450FAbs] = "FAbs";
652
names[GLSLstd450SAbs] = "SAbs";
653
names[GLSLstd450FSign] = "FSign";
654
names[GLSLstd450SSign] = "SSign";
655
names[GLSLstd450Floor] = "Floor";
656
names[GLSLstd450Ceil] = "Ceil";
657
names[GLSLstd450Fract] = "Fract";
658
names[GLSLstd450Radians] = "Radians";
659
names[GLSLstd450Degrees] = "Degrees";
660
names[GLSLstd450Sin] = "Sin";
661
names[GLSLstd450Cos] = "Cos";
662
names[GLSLstd450Tan] = "Tan";
663
names[GLSLstd450Asin] = "Asin";
664
names[GLSLstd450Acos] = "Acos";
665
names[GLSLstd450Atan] = "Atan";
666
names[GLSLstd450Sinh] = "Sinh";
667
names[GLSLstd450Cosh] = "Cosh";
668
names[GLSLstd450Tanh] = "Tanh";
669
names[GLSLstd450Asinh] = "Asinh";
670
names[GLSLstd450Acosh] = "Acosh";
671
names[GLSLstd450Atanh] = "Atanh";
672
names[GLSLstd450Atan2] = "Atan2";
673
names[GLSLstd450Pow] = "Pow";
674
names[GLSLstd450Exp] = "Exp";
675
names[GLSLstd450Log] = "Log";
676
names[GLSLstd450Exp2] = "Exp2";
677
names[GLSLstd450Log2] = "Log2";
678
names[GLSLstd450Sqrt] = "Sqrt";
679
names[GLSLstd450InverseSqrt] = "InverseSqrt";
680
names[GLSLstd450Determinant] = "Determinant";
681
names[GLSLstd450MatrixInverse] = "MatrixInverse";
682
names[GLSLstd450Modf] = "Modf";
683
names[GLSLstd450ModfStruct] = "ModfStruct";
684
names[GLSLstd450FMin] = "FMin";
685
names[GLSLstd450SMin] = "SMin";
686
names[GLSLstd450UMin] = "UMin";
687
names[GLSLstd450FMax] = "FMax";
688
names[GLSLstd450SMax] = "SMax";
689
names[GLSLstd450UMax] = "UMax";
690
names[GLSLstd450FClamp] = "FClamp";
691
names[GLSLstd450SClamp] = "SClamp";
692
names[GLSLstd450UClamp] = "UClamp";
693
names[GLSLstd450FMix] = "FMix";
694
names[GLSLstd450Step] = "Step";
695
names[GLSLstd450SmoothStep] = "SmoothStep";
696
names[GLSLstd450Fma] = "Fma";
697
names[GLSLstd450Frexp] = "Frexp";
698
names[GLSLstd450FrexpStruct] = "FrexpStruct";
699
names[GLSLstd450Ldexp] = "Ldexp";
700
names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
701
names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
702
names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
703
names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
704
names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
705
names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
706
names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
707
names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
708
names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
709
names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
710
names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
711
names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
712
names[GLSLstd450Length] = "Length";
713
names[GLSLstd450Distance] = "Distance";
714
names[GLSLstd450Cross] = "Cross";
715
names[GLSLstd450Normalize] = "Normalize";
716
names[GLSLstd450FaceForward] = "FaceForward";
717
names[GLSLstd450Reflect] = "Reflect";
718
names[GLSLstd450Refract] = "Refract";
719
names[GLSLstd450FindILsb] = "FindILsb";
720
names[GLSLstd450FindSMsb] = "FindSMsb";
721
names[GLSLstd450FindUMsb] = "FindUMsb";
722
names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
723
names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
724
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
725
names[GLSLstd450NMin] = "NMin";
726
names[GLSLstd450NMax] = "NMax";
727
names[GLSLstd450NClamp] = "NClamp";
728
}
729
730
static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
731
{
732
if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
733
switch (entrypoint) {
734
case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
735
case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
736
case WriteInvocationAMD: return "WriteInvocationAMD";
737
case MbcntAMD: return "MbcntAMD";
738
default: return "Bad";
739
}
740
} else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
741
switch (entrypoint) {
742
case FMin3AMD: return "FMin3AMD";
743
case UMin3AMD: return "UMin3AMD";
744
case SMin3AMD: return "SMin3AMD";
745
case FMax3AMD: return "FMax3AMD";
746
case UMax3AMD: return "UMax3AMD";
747
case SMax3AMD: return "SMax3AMD";
748
case FMid3AMD: return "FMid3AMD";
749
case UMid3AMD: return "UMid3AMD";
750
case SMid3AMD: return "SMid3AMD";
751
default: return "Bad";
752
}
753
} else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
754
switch (entrypoint) {
755
case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
756
default: return "Bad";
757
}
758
}
759
else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
760
switch (entrypoint) {
761
case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
762
case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
763
case TimeAMD: return "TimeAMD";
764
default:
765
break;
766
}
767
}
768
769
return "Bad";
770
}
771
772
static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
773
{
774
if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
775
strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
776
strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
777
strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
778
strcmp(name, spv::E_SPV_NVX_multiview_per_view_attributes) == 0 ||
779
strcmp(name, spv::E_SPV_NV_fragment_shader_barycentric) == 0 ||
780
strcmp(name, spv::E_SPV_NV_mesh_shader) == 0 ||
781
strcmp(name, spv::E_SPV_NV_shader_image_footprint) == 0) {
782
switch (entrypoint) {
783
// NV builtins
784
case (unsigned)BuiltIn::ViewportMaskNV: return "ViewportMaskNV";
785
case (unsigned)BuiltIn::SecondaryPositionNV: return "SecondaryPositionNV";
786
case (unsigned)BuiltIn::SecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
787
case (unsigned)BuiltIn::PositionPerViewNV: return "PositionPerViewNV";
788
case (unsigned)BuiltIn::ViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
789
case (unsigned)BuiltIn::BaryCoordNV: return "BaryCoordNV";
790
case (unsigned)BuiltIn::BaryCoordNoPerspNV: return "BaryCoordNoPerspNV";
791
case (unsigned)BuiltIn::TaskCountNV: return "TaskCountNV";
792
case (unsigned)BuiltIn::PrimitiveCountNV: return "PrimitiveCountNV";
793
case (unsigned)BuiltIn::PrimitiveIndicesNV: return "PrimitiveIndicesNV";
794
case (unsigned)BuiltIn::ClipDistancePerViewNV: return "ClipDistancePerViewNV";
795
case (unsigned)BuiltIn::CullDistancePerViewNV: return "CullDistancePerViewNV";
796
case (unsigned)BuiltIn::LayerPerViewNV: return "LayerPerViewNV";
797
case (unsigned)BuiltIn::MeshViewCountNV: return "MeshViewCountNV";
798
case (unsigned)BuiltIn::MeshViewIndicesNV: return "MeshViewIndicesNV";
799
800
// NV Capabilities
801
case (unsigned)Capability::GeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
802
case (unsigned)Capability::ShaderViewportMaskNV: return "ShaderViewportMaskNV";
803
case (unsigned)Capability::ShaderStereoViewNV: return "ShaderStereoViewNV";
804
case (unsigned)Capability::PerViewAttributesNV: return "PerViewAttributesNV";
805
case (unsigned)Capability::FragmentBarycentricNV: return "FragmentBarycentricNV";
806
case (unsigned)Capability::MeshShadingNV: return "MeshShadingNV";
807
case (unsigned)Capability::ImageFootprintNV: return "ImageFootprintNV";
808
case (unsigned)Capability::SampleMaskOverrideCoverageNV:return "SampleMaskOverrideCoverageNV";
809
810
// NV Decorations
811
case (unsigned)Decoration::OverrideCoverageNV: return "OverrideCoverageNV";
812
case (unsigned)Decoration::PassthroughNV: return "PassthroughNV";
813
case (unsigned)Decoration::ViewportRelativeNV: return "ViewportRelativeNV";
814
case (unsigned)Decoration::SecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
815
case (unsigned)Decoration::PerVertexNV: return "PerVertexNV";
816
case (unsigned)Decoration::PerPrimitiveNV: return "PerPrimitiveNV";
817
case (unsigned)Decoration::PerViewNV: return "PerViewNV";
818
case (unsigned)Decoration::PerTaskNV: return "PerTaskNV";
819
820
default: return "Bad";
821
}
822
}
823
return "Bad";
824
}
825
826
static const char* NonSemanticShaderDebugInfo100GetDebugNames(unsigned entrypoint)
827
{
828
switch (entrypoint) {
829
case NonSemanticShaderDebugInfo100DebugInfoNone: return "DebugInfoNone";
830
case NonSemanticShaderDebugInfo100DebugCompilationUnit: return "DebugCompilationUnit";
831
case NonSemanticShaderDebugInfo100DebugTypeBasic: return "DebugTypeBasic";
832
case NonSemanticShaderDebugInfo100DebugTypePointer: return "DebugTypePointer";
833
case NonSemanticShaderDebugInfo100DebugTypeQualifier: return "DebugTypeQualifier";
834
case NonSemanticShaderDebugInfo100DebugTypeArray: return "DebugTypeArray";
835
case NonSemanticShaderDebugInfo100DebugTypeVector: return "DebugTypeVector";
836
case NonSemanticShaderDebugInfo100DebugTypedef: return "DebugTypedef";
837
case NonSemanticShaderDebugInfo100DebugTypeFunction: return "DebugTypeFunction";
838
case NonSemanticShaderDebugInfo100DebugTypeEnum: return "DebugTypeEnum";
839
case NonSemanticShaderDebugInfo100DebugTypeComposite: return "DebugTypeComposite";
840
case NonSemanticShaderDebugInfo100DebugTypeMember: return "DebugTypeMember";
841
case NonSemanticShaderDebugInfo100DebugTypeInheritance: return "DebugTypeInheritance";
842
case NonSemanticShaderDebugInfo100DebugTypePtrToMember: return "DebugTypePtrToMember";
843
case NonSemanticShaderDebugInfo100DebugTypeTemplate: return "DebugTypeTemplate";
844
case NonSemanticShaderDebugInfo100DebugTypeTemplateParameter: return "DebugTypeTemplateParameter";
845
case NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter: return "DebugTypeTemplateTemplateParameter";
846
case NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack: return "DebugTypeTemplateParameterPack";
847
case NonSemanticShaderDebugInfo100DebugGlobalVariable: return "DebugGlobalVariable";
848
case NonSemanticShaderDebugInfo100DebugFunctionDeclaration: return "DebugFunctionDeclaration";
849
case NonSemanticShaderDebugInfo100DebugFunction: return "DebugFunction";
850
case NonSemanticShaderDebugInfo100DebugLexicalBlock: return "DebugLexicalBlock";
851
case NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator: return "DebugLexicalBlockDiscriminator";
852
case NonSemanticShaderDebugInfo100DebugScope: return "DebugScope";
853
case NonSemanticShaderDebugInfo100DebugNoScope: return "DebugNoScope";
854
case NonSemanticShaderDebugInfo100DebugInlinedAt: return "DebugInlinedAt";
855
case NonSemanticShaderDebugInfo100DebugLocalVariable: return "DebugLocalVariable";
856
case NonSemanticShaderDebugInfo100DebugInlinedVariable: return "DebugInlinedVariable";
857
case NonSemanticShaderDebugInfo100DebugDeclare: return "DebugDeclare";
858
case NonSemanticShaderDebugInfo100DebugValue: return "DebugValue";
859
case NonSemanticShaderDebugInfo100DebugOperation: return "DebugOperation";
860
case NonSemanticShaderDebugInfo100DebugExpression: return "DebugExpression";
861
case NonSemanticShaderDebugInfo100DebugMacroDef: return "DebugMacroDef";
862
case NonSemanticShaderDebugInfo100DebugMacroUndef: return "DebugMacroUndef";
863
case NonSemanticShaderDebugInfo100DebugImportedEntity: return "DebugImportedEntity";
864
case NonSemanticShaderDebugInfo100DebugSource: return "DebugSource";
865
case NonSemanticShaderDebugInfo100DebugFunctionDefinition: return "DebugFunctionDefinition";
866
case NonSemanticShaderDebugInfo100DebugSourceContinued: return "DebugSourceContinued";
867
case NonSemanticShaderDebugInfo100DebugLine: return "DebugLine";
868
case NonSemanticShaderDebugInfo100DebugNoLine: return "DebugNoLine";
869
case NonSemanticShaderDebugInfo100DebugBuildIdentifier: return "DebugBuildIdentifier";
870
case NonSemanticShaderDebugInfo100DebugStoragePath: return "DebugStoragePath";
871
case NonSemanticShaderDebugInfo100DebugEntryPoint: return "DebugEntryPoint";
872
case NonSemanticShaderDebugInfo100DebugTypeMatrix: return "DebugTypeMatrix";
873
default: return "Bad";
874
}
875
876
return "Bad";
877
}
878
879
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
880
{
881
SpirvStream SpirvStream(out, stream);
882
spv::Parameterize();
883
GLSLstd450GetDebugNames(GlslStd450DebugNames);
884
SpirvStream.validate();
885
SpirvStream.processInstructions();
886
}
887
888
} // end namespace spv
889
890