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

source code of qtshadertools/src/3rdparty/glslang/SPIRV/disassemble.cpp