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