yum-mirror/glslang

git clone https://git.yummers.dev/yum-mirror/glslang

Saddambounds-check <id> before indexing idInstruction and idDescriptor8d6dd0e4

main
38.9 KiB914 linesraw
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
53namespace 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 "NonSemanticShaderDebugInfo.h"
61        #include "GLSL.ext.QCOM.h"
62    }
63}
64static const char* GlslStd450DebugNames[spv::GLSLstd450Count];
65
66namespace spv {
67
68static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
69static const char* GLSLextNVGetDebugNames(const char*, unsigned);
70static const char* NonSemanticShaderDebugInfoGetDebugNames(unsigned);
71
72static 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
79enum ExtInstSet {
80    GLSL450Inst,
81    GLSLextAMDInst,
82    GLSLextNVInst,
83    OpenCLExtInst,
84    NonSemanticDebugPrintfExtInst,
85    NonSemanticDebugBreakExtInst,
86    NonSemanticShaderDebugInfo
87};
88
89// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
90class SpirvStream {
91public:
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
98protected:
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
136void 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.
169void 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            if (resultId >= bound)
203                Kill(out, "Bad <id>");
204
205            // save instruction for future reference
206            idInstruction[resultId] = instructionStart;
207        }
208
209        outputResultId(resultId);
210        outputTypeId(typeId);
211        outputIndent();
212
213        // Hand off the Op and all its operands
214        disassembleInstruction(resultId, typeId, opCode, numOperands);
215        if (word != nextInst) {
216            out << " ERROR, incorrect number of operands consumed.  At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
217            word = nextInst;
218        }
219        out << std::endl;
220    }
221}
222
223void SpirvStream::outputIndent()
224{
225    for (int i = 0; i < (int)nestedControl.size(); ++i)
226        out << "  ";
227}
228
229void SpirvStream::formatId(Id id, std::stringstream& idStream)
230{
231    if (id != 0) {
232        // On instructions with no IDs, this is called with "0", which does not
233        // have to be within ID bounds on null shaders.
234        if (id >= bound)
235            Kill(out, "Bad <id>");
236
237        idStream << id;
238        if (idDescriptor[id].size() > 0)
239            idStream << "(" << idDescriptor[id] << ")";
240    }
241}
242
243void SpirvStream::outputResultId(Id id)
244{
245    const int width = 16;
246    std::stringstream idStream;
247    formatId(id, idStream);
248    out << std::setw(width) << std::right << idStream.str();
249    if (id != 0)
250        out << ":";
251    else
252        out << " ";
253
254    if (nestedControl.size() && id == nestedControl.top())
255        nestedControl.pop();
256}
257
258void SpirvStream::outputTypeId(Id id)
259{
260    const int width = 12;
261    std::stringstream idStream;
262    formatId(id, idStream);
263    out << std::setw(width) << std::right << idStream.str() << " ";
264}
265
266void SpirvStream::outputId(Id id)
267{
268    if (id >= bound)
269        Kill(out, "Bad <id>");
270
271    out << id;
272    if (idDescriptor[id].size() > 0)
273        out << "(" << idDescriptor[id] << ")";
274}
275
276void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
277{
278    if (mask == 0)
279        out << "None";
280    else {
281        for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
282            if (mask & (1 << m))
283                out << OperandClassParams[operandClass].getName(m) << " ";
284        }
285    }
286}
287
288void SpirvStream::disassembleImmediates(int numOperands)
289{
290    for (int i = 0; i < numOperands; ++i) {
291        out << stream[word++];
292        if (i < numOperands - 1)
293            out << " ";
294    }
295}
296
297void SpirvStream::disassembleIds(int numOperands)
298{
299    for (int i = 0; i < numOperands; ++i) {
300        outputId(stream[word++]);
301        if (i < numOperands - 1)
302            out << " ";
303    }
304}
305
306// decode string from words at current position (non-consuming)
307std::pair<int, std::string> SpirvStream::decodeString()
308{
309    std::string res;
310    int wordPos = word;
311    char c;
312    bool done = false;
313
314    do {
315        unsigned int content = stream[wordPos];
316        for (int charCount = 0; charCount < 4; ++charCount) {
317            c = content & 0xff;
318            content >>= 8;
319            if (c == '\0') {
320                done = true;
321                break;
322            }
323            res += c;
324        }
325        ++wordPos;
326    } while(! done);
327
328    return std::make_pair(wordPos - word, res);
329}
330
331// return the number of operands consumed by the string
332int SpirvStream::disassembleString()
333{
334    out << " \"";
335
336    std::pair<int, std::string> decoderes = decodeString();
337
338    out << decoderes.second;
339    out << "\"";
340
341    word += decoderes.first;
342
343    return decoderes.first;
344}
345
346static uint32_t popcount(uint32_t mask)
347{
348    uint32_t count = 0;
349    while (mask) {
350        if (mask & 1) {
351            count++;
352        }
353        mask >>= 1;
354    }
355    return count;
356}
357
358void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
359{
360    // Process the opcode
361
362    out << (OpcodeString((int)opCode) + 2);  // leave out the "Op"
363
364    if (opCode == Op::OpLoopMerge || opCode == Op::OpSelectionMerge)
365        nextNestedControl = stream[word];
366    else if (opCode == Op::OpBranchConditional || opCode == Op::OpSwitch) {
367        if (nextNestedControl) {
368            nestedControl.push(nextNestedControl);
369            nextNestedControl = 0;
370        }
371    } else if (opCode == Op::OpExtInstImport) {
372        idDescriptor[resultId] = decodeString().second;
373    }
374    else {
375        if (resultId != 0 && idDescriptor[resultId].size() == 0) {
376            switch (opCode) {
377            case Op::OpTypeInt:
378                switch (stream[word]) {
379                case 8:  idDescriptor[resultId] = "int8_t"; break;
380                case 16: idDescriptor[resultId] = "int16_t"; break;
381                default: assert(0); [[fallthrough]];
382                case 32: idDescriptor[resultId] = "int"; break;
383                case 64: idDescriptor[resultId] = "int64_t"; break;
384                }
385                break;
386            case Op::OpTypeFloat:
387                switch (stream[word]) {
388                case 4:
389                case 6:
390                case 8:
391                case 16:
392                    if (numOperands > 1) {
393                        switch (stream[word+1]) {
394                        default:
395                            assert(0); [[fallthrough]];
396                        case (int)spv::FPEncoding::BFloat16KHR:
397                            idDescriptor[resultId] = "bfloat16_t";
398                            break;
399                        case (int)spv::FPEncoding::Float8E4M3EXT:
400                            idDescriptor[resultId] = "floate4m3_t";
401                            break;
402                        case (int)spv::FPEncoding::Float8E5M2EXT:
403                            idDescriptor[resultId] = "floate5m2_t";
404                            break;
405                        case (int)spv::FPEncoding::Float4E2M1EXT:
406                            idDescriptor[resultId] = "floate2m1_t";
407                            break;
408                        case (int)spv::FPEncoding::Float6E3M2EXT:
409                            idDescriptor[resultId] = "floate3m2_t";
410                            break;
411                        case (int)spv::FPEncoding::Float6E2M3EXT:
412                            idDescriptor[resultId] = "floate2m3_t";
413                            break;
414                        case (int)spv::FPEncoding::Float8UnsignedE8M0EXT:
415                            idDescriptor[resultId] = "floatue8m0_t";
416                            break;
417                        case (int)spv::FPEncoding::MXInt8EXT:
418                            idDescriptor[resultId] = "floatmxint8_t";
419                            break;
420                        }
421                    } else {
422                        idDescriptor[resultId] = "float16_t";
423                    }
424                    break;
425                default: assert(0); [[fallthrough]];
426                case 32: idDescriptor[resultId] = "float"; break;
427                case 64: idDescriptor[resultId] = "float64_t"; break;
428                }
429                break;
430            case Op::OpTypeBool:
431                idDescriptor[resultId] = "bool";
432                break;
433            case Op::OpTypeStruct:
434                idDescriptor[resultId] = "struct";
435                break;
436            case Op::OpTypePointer:
437            case Op::OpTypeUntypedPointerKHR:
438                idDescriptor[resultId] = "ptr";
439                break;
440            case Op::OpTypeVector:
441                if (stream[word] >= bound)
442                    Kill(out, "Bad <id>");
443                if (idDescriptor[stream[word]].size() > 0) {
444                    if (idDescriptor[stream[word]].substr(0,2) == "bf") {
445                        idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 2);
446                    } else {
447                        idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
448                    }
449                    if (strstr(idDescriptor[stream[word]].c_str(), "8")) {
450                        idDescriptor[resultId].append("8");
451                    }
452                    if (strstr(idDescriptor[stream[word]].c_str(), "16")) {
453                        idDescriptor[resultId].append("16");
454                    }
455                    if (strstr(idDescriptor[stream[word]].c_str(), "64")) {
456                        idDescriptor[resultId].append("64");
457                    }
458                }
459                idDescriptor[resultId].append("vec");
460                switch (stream[word + 1]) {
461                case 2:   idDescriptor[resultId].append("2");   break;
462                case 3:   idDescriptor[resultId].append("3");   break;
463                case 4:   idDescriptor[resultId].append("4");   break;
464                case 8:   idDescriptor[resultId].append("8");   break;
465                case 16:  idDescriptor[resultId].append("16");  break;
466                case 32:  idDescriptor[resultId].append("32");  break;
467                default: break;
468                }
469                break;
470            default:
471                break;
472            }
473        }
474    }
475
476    // Process the operands.  Note, a new context-dependent set could be
477    // swapped in mid-traversal.
478
479    // Handle images specially, so can put out helpful strings.
480    if (opCode == Op::OpTypeImage) {
481        out << " ";
482        disassembleIds(1);
483        out << " " << DimensionString((int)(Dim)stream[word++]);
484        out << (stream[word++] != 0 ? " depth" : "");
485        out << (stream[word++] != 0 ? " array" : "");
486        out << (stream[word++] != 0 ? " multi-sampled" : "");
487        switch (stream[word++]) {
488        case 0: out << " runtime";    break;
489        case 1: out << " sampled";    break;
490        case 2: out << " nonsampled"; break;
491        }
492        out << " format:" << ImageFormatString((int)(ImageFormat)stream[word++]);
493
494        if (numOperands == 8) {
495            out << " " << AccessQualifierString(stream[word++]);
496        }
497        return;
498    }
499
500    // Handle all the parameterized operands
501    for (int op = 0; op < InstructionDesc[enumCast(opCode)].operands.getNum() && numOperands > 0; ++op) {
502        out << " ";
503        OperandClass operandClass = InstructionDesc[enumCast(opCode)].operands.getClass(op);
504        switch (operandClass) {
505        case OperandId:
506        case OperandScope:
507        case OperandMemorySemantics:
508            disassembleIds(1);
509            --numOperands;
510            // Get names for printing "(XXX)" for readability, *after* this id
511            if (opCode == Op::OpName)
512                idDescriptor[stream[word - 1]] = decodeString().second;
513            break;
514        case OperandVariableIds:
515            disassembleIds(numOperands);
516            return;
517        case OperandImageOperands:
518            outputMask(OperandImageOperands, stream[word++]);
519            --numOperands;
520            disassembleIds(numOperands);
521            return;
522        case OperandOptionalLiteral:
523        case OperandVariableLiterals:
524            if ((opCode == Op::OpDecorate && stream[word - 1] == Decoration::BuiltIn) ||
525                (opCode == Op::OpMemberDecorate && stream[word - 1] == Decoration::BuiltIn)) {
526                out << BuiltInString(stream[word++]);
527                --numOperands;
528                ++op;
529            }
530            disassembleImmediates(numOperands);
531            return;
532        case OperandVariableIdLiteral:
533            while (numOperands > 0) {
534                out << std::endl;
535                outputResultId(0);
536                outputTypeId(0);
537                outputIndent();
538                out << "     Type ";
539                disassembleIds(1);
540                out << ", member ";
541                disassembleImmediates(1);
542                numOperands -= 2;
543            }
544            return;
545        case OperandVariableLiteralId:
546            while (numOperands > 0) {
547                out << std::endl;
548                outputResultId(0);
549                outputTypeId(0);
550                outputIndent();
551                out << "     case ";
552                disassembleImmediates(1);
553                out << ": ";
554                disassembleIds(1);
555                numOperands -= 2;
556            }
557            return;
558        case OperandLiteralNumber:
559            disassembleImmediates(1);
560            --numOperands;
561            if (opCode == Op::OpExtInst) {
562                ExtInstSet extInstSet = GLSL450Inst;
563                const char* name = idDescriptor[stream[word - 2]].c_str();
564                if (strcmp("OpenCL.std", name) == 0) {
565                    extInstSet = OpenCLExtInst;
566                } else if (strcmp("OpenCL.DebugInfo.100", name) == 0) {
567                    extInstSet = OpenCLExtInst;
568                } else if (strcmp("NonSemantic.DebugPrintf", name) == 0) {
569                    extInstSet = NonSemanticDebugPrintfExtInst;
570                } else if (strcmp("NonSemantic.DebugBreak", name) == 0) {
571                    extInstSet = NonSemanticDebugBreakExtInst;
572                } else if (strncmp("NonSemantic.Shader.DebugInfo.", name, strlen("NonSemantic.Shader.DebugInfo.")) ==
573                           0) {
574                    extInstSet = NonSemanticShaderDebugInfo;
575                } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
576                           strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
577                           strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
578                           strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
579                    extInstSet = GLSLextAMDInst;
580                } else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
581                          strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
582                          strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
583                          strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0 ||
584                          strcmp(spv::E_SPV_NV_fragment_shader_barycentric, name) == 0 ||
585                          strcmp(spv::E_SPV_NV_mesh_shader, name) == 0) {
586                    extInstSet = GLSLextNVInst;
587                }
588                unsigned entrypoint = stream[word - 1];
589                if (extInstSet == GLSL450Inst) {
590                    if (entrypoint < GLSLstd450Count) {
591                        out << "(" << GlslStd450DebugNames[entrypoint] << ")";
592                    }
593                } else if (extInstSet == GLSLextAMDInst) {
594                    out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
595                }
596                else if (extInstSet == GLSLextNVInst) {
597                    out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
598                } else if (extInstSet == NonSemanticDebugPrintfExtInst) {
599                    out << "(DebugPrintf)";
600                } else if (extInstSet == NonSemanticDebugBreakExtInst) {
601                    out << "(DebugBreak)";
602                } else if (extInstSet == NonSemanticShaderDebugInfo) {
603                    out << "(" << NonSemanticShaderDebugInfoGetDebugNames(entrypoint) << ")";
604                }
605            }
606            break;
607        case OperandOptionalLiteralString:
608        case OperandLiteralString:
609            numOperands -= disassembleString();
610            break;
611        case OperandVariableLiteralStrings:
612            while (numOperands > 0)
613                numOperands -= disassembleString();
614            return;
615        case OperandMemoryAccess:
616            {
617                outputMask(OperandMemoryAccess, stream[word++]);
618                --numOperands;
619                // Put a space after "None" if there are any remaining operands
620                if (numOperands && stream[word-1] == 0) {
621                    out << " ";
622                }
623                uint32_t mask = stream[word-1];
624                // Aligned is the only memory access operand that uses an immediate
625                // value, and it is also the first operand that uses a value at all.
626                if (mask & (uint32_t)MemoryAccessMask::Aligned) {
627                    disassembleImmediates(1);
628                    numOperands--;
629                    if (numOperands)
630                        out << " ";
631                }
632
633                uint32_t bitCount = popcount(mask & (uint32_t)(MemoryAccessMask::MakePointerAvailable | MemoryAccessMask::MakePointerVisible));
634                disassembleIds(bitCount);
635                numOperands -= bitCount;
636            }
637            break;
638        case OperandTensorAddressingOperands:
639            {
640                outputMask(OperandTensorAddressingOperands, stream[word++]);
641                --numOperands;
642                // Put a space after "None" if there are any remaining operands
643                if (numOperands && stream[word-1] == 0) {
644                    out << " ";
645                }
646                uint32_t bitCount = popcount(stream[word-1]);
647                disassembleIds(bitCount);
648                numOperands -= bitCount;
649            }
650            break;
651        default:
652            assert(operandClass >= OperandSource && operandClass < OperandOpcode);
653
654            if (OperandClassParams[operandClass].bitmask)
655                outputMask(operandClass, stream[word++]);
656            else
657                out << OperandClassParams[operandClass].getName(stream[word++]);
658            --numOperands;
659
660            break;
661        }
662    }
663
664    return;
665}
666
667static void GLSLstd450GetDebugNames(const char** names)
668{
669    for (int i = 0; i < GLSLstd450Count; ++i)
670        names[i] = "Unknown";
671
672    names[GLSLstd450Round]                   = "Round";
673    names[GLSLstd450RoundEven]               = "RoundEven";
674    names[GLSLstd450Trunc]                   = "Trunc";
675    names[GLSLstd450FAbs]                    = "FAbs";
676    names[GLSLstd450SAbs]                    = "SAbs";
677    names[GLSLstd450FSign]                   = "FSign";
678    names[GLSLstd450SSign]                   = "SSign";
679    names[GLSLstd450Floor]                   = "Floor";
680    names[GLSLstd450Ceil]                    = "Ceil";
681    names[GLSLstd450Fract]                   = "Fract";
682    names[GLSLstd450Radians]                 = "Radians";
683    names[GLSLstd450Degrees]                 = "Degrees";
684    names[GLSLstd450Sin]                     = "Sin";
685    names[GLSLstd450Cos]                     = "Cos";
686    names[GLSLstd450Tan]                     = "Tan";
687    names[GLSLstd450Asin]                    = "Asin";
688    names[GLSLstd450Acos]                    = "Acos";
689    names[GLSLstd450Atan]                    = "Atan";
690    names[GLSLstd450Sinh]                    = "Sinh";
691    names[GLSLstd450Cosh]                    = "Cosh";
692    names[GLSLstd450Tanh]                    = "Tanh";
693    names[GLSLstd450Asinh]                   = "Asinh";
694    names[GLSLstd450Acosh]                   = "Acosh";
695    names[GLSLstd450Atanh]                   = "Atanh";
696    names[GLSLstd450Atan2]                   = "Atan2";
697    names[GLSLstd450Pow]                     = "Pow";
698    names[GLSLstd450Exp]                     = "Exp";
699    names[GLSLstd450Log]                     = "Log";
700    names[GLSLstd450Exp2]                    = "Exp2";
701    names[GLSLstd450Log2]                    = "Log2";
702    names[GLSLstd450Sqrt]                    = "Sqrt";
703    names[GLSLstd450InverseSqrt]             = "InverseSqrt";
704    names[GLSLstd450Determinant]             = "Determinant";
705    names[GLSLstd450MatrixInverse]           = "MatrixInverse";
706    names[GLSLstd450Modf]                    = "Modf";
707    names[GLSLstd450ModfStruct]              = "ModfStruct";
708    names[GLSLstd450FMin]                    = "FMin";
709    names[GLSLstd450SMin]                    = "SMin";
710    names[GLSLstd450UMin]                    = "UMin";
711    names[GLSLstd450FMax]                    = "FMax";
712    names[GLSLstd450SMax]                    = "SMax";
713    names[GLSLstd450UMax]                    = "UMax";
714    names[GLSLstd450FClamp]                  = "FClamp";
715    names[GLSLstd450SClamp]                  = "SClamp";
716    names[GLSLstd450UClamp]                  = "UClamp";
717    names[GLSLstd450FMix]                    = "FMix";
718    names[GLSLstd450Step]                    = "Step";
719    names[GLSLstd450SmoothStep]              = "SmoothStep";
720    names[GLSLstd450Fma]                     = "Fma";
721    names[GLSLstd450Frexp]                   = "Frexp";
722    names[GLSLstd450FrexpStruct]             = "FrexpStruct";
723    names[GLSLstd450Ldexp]                   = "Ldexp";
724    names[GLSLstd450PackSnorm4x8]            = "PackSnorm4x8";
725    names[GLSLstd450PackUnorm4x8]            = "PackUnorm4x8";
726    names[GLSLstd450PackSnorm2x16]           = "PackSnorm2x16";
727    names[GLSLstd450PackUnorm2x16]           = "PackUnorm2x16";
728    names[GLSLstd450PackHalf2x16]            = "PackHalf2x16";
729    names[GLSLstd450PackDouble2x32]          = "PackDouble2x32";
730    names[GLSLstd450UnpackSnorm2x16]         = "UnpackSnorm2x16";
731    names[GLSLstd450UnpackUnorm2x16]         = "UnpackUnorm2x16";
732    names[GLSLstd450UnpackHalf2x16]          = "UnpackHalf2x16";
733    names[GLSLstd450UnpackSnorm4x8]          = "UnpackSnorm4x8";
734    names[GLSLstd450UnpackUnorm4x8]          = "UnpackUnorm4x8";
735    names[GLSLstd450UnpackDouble2x32]        = "UnpackDouble2x32";
736    names[GLSLstd450Length]                  = "Length";
737    names[GLSLstd450Distance]                = "Distance";
738    names[GLSLstd450Cross]                   = "Cross";
739    names[GLSLstd450Normalize]               = "Normalize";
740    names[GLSLstd450FaceForward]             = "FaceForward";
741    names[GLSLstd450Reflect]                 = "Reflect";
742    names[GLSLstd450Refract]                 = "Refract";
743    names[GLSLstd450FindILsb]                = "FindILsb";
744    names[GLSLstd450FindSMsb]                = "FindSMsb";
745    names[GLSLstd450FindUMsb]                = "FindUMsb";
746    names[GLSLstd450InterpolateAtCentroid]   = "InterpolateAtCentroid";
747    names[GLSLstd450InterpolateAtSample]     = "InterpolateAtSample";
748    names[GLSLstd450InterpolateAtOffset]     = "InterpolateAtOffset";
749    names[GLSLstd450NMin]                    = "NMin";
750    names[GLSLstd450NMax]                    = "NMax";
751    names[GLSLstd450NClamp]                  = "NClamp";
752}
753
754static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
755{
756    if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
757        switch (entrypoint) {
758        case SwizzleInvocationsAMD:         return "SwizzleInvocationsAMD";
759        case SwizzleInvocationsMaskedAMD:   return "SwizzleInvocationsMaskedAMD";
760        case WriteInvocationAMD:            return "WriteInvocationAMD";
761        case MbcntAMD:                      return "MbcntAMD";
762        default:                            return "Bad";
763        }
764    } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
765        switch (entrypoint) {
766        case FMin3AMD:      return "FMin3AMD";
767        case UMin3AMD:      return "UMin3AMD";
768        case SMin3AMD:      return "SMin3AMD";
769        case FMax3AMD:      return "FMax3AMD";
770        case UMax3AMD:      return "UMax3AMD";
771        case SMax3AMD:      return "SMax3AMD";
772        case FMid3AMD:      return "FMid3AMD";
773        case UMid3AMD:      return "UMid3AMD";
774        case SMid3AMD:      return "SMid3AMD";
775        default:            return "Bad";
776        }
777    } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
778        switch (entrypoint) {
779        case InterpolateAtVertexAMD:    return "InterpolateAtVertexAMD";
780        default:                        return "Bad";
781        }
782    }
783    else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
784        switch (entrypoint) {
785        case CubeFaceIndexAMD:      return "CubeFaceIndexAMD";
786        case CubeFaceCoordAMD:      return "CubeFaceCoordAMD";
787        case TimeAMD:               return "TimeAMD";
788        default:
789            break;
790        }
791    }
792
793    return "Bad";
794}
795
796static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
797{
798    if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
799        strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
800        strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
801        strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
802        strcmp(name, spv::E_SPV_NVX_multiview_per_view_attributes) == 0 ||
803        strcmp(name, spv::E_SPV_NV_fragment_shader_barycentric) == 0 ||
804        strcmp(name, spv::E_SPV_NV_mesh_shader) == 0 ||
805        strcmp(name, spv::E_SPV_NV_shader_image_footprint) == 0) {
806        switch (entrypoint) {
807        // NV builtins
808        case (unsigned)BuiltIn::ViewportMaskNV:                 return "ViewportMaskNV";
809        case (unsigned)BuiltIn::SecondaryPositionNV:            return "SecondaryPositionNV";
810        case (unsigned)BuiltIn::SecondaryViewportMaskNV:        return "SecondaryViewportMaskNV";
811        case (unsigned)BuiltIn::PositionPerViewNV:              return "PositionPerViewNV";
812        case (unsigned)BuiltIn::ViewportMaskPerViewNV:          return "ViewportMaskPerViewNV";
813        case (unsigned)BuiltIn::BaryCoordNV:                    return "BaryCoordNV";
814        case (unsigned)BuiltIn::BaryCoordNoPerspNV:             return "BaryCoordNoPerspNV";
815        case (unsigned)BuiltIn::TaskCountNV:                    return "TaskCountNV";
816        case (unsigned)BuiltIn::PrimitiveCountNV:               return "PrimitiveCountNV";
817        case (unsigned)BuiltIn::PrimitiveIndicesNV:             return "PrimitiveIndicesNV";
818        case (unsigned)BuiltIn::ClipDistancePerViewNV:          return "ClipDistancePerViewNV";
819        case (unsigned)BuiltIn::CullDistancePerViewNV:          return "CullDistancePerViewNV";
820        case (unsigned)BuiltIn::LayerPerViewNV:                 return "LayerPerViewNV";
821        case (unsigned)BuiltIn::MeshViewCountNV:                return "MeshViewCountNV";
822        case (unsigned)BuiltIn::MeshViewIndicesNV:              return "MeshViewIndicesNV";
823
824        // NV Capabilities
825        case (unsigned)Capability::GeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
826        case (unsigned)Capability::ShaderViewportMaskNV:        return "ShaderViewportMaskNV";
827        case (unsigned)Capability::ShaderStereoViewNV:          return "ShaderStereoViewNV";
828        case (unsigned)Capability::PerViewAttributesNV:         return "PerViewAttributesNV";
829        case (unsigned)Capability::FragmentBarycentricNV:       return "FragmentBarycentricNV";
830        case (unsigned)Capability::MeshShadingNV:               return "MeshShadingNV";
831        case (unsigned)Capability::ImageFootprintNV:            return "ImageFootprintNV";
832        case (unsigned)Capability::SampleMaskOverrideCoverageNV:return "SampleMaskOverrideCoverageNV";
833
834        // NV Decorations
835        case (unsigned)Decoration::OverrideCoverageNV:          return "OverrideCoverageNV";
836        case (unsigned)Decoration::PassthroughNV:               return "PassthroughNV";
837        case (unsigned)Decoration::ViewportRelativeNV:          return "ViewportRelativeNV";
838        case (unsigned)Decoration::SecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
839        case (unsigned)Decoration::PerVertexNV:                 return "PerVertexNV";
840        case (unsigned)Decoration::PerPrimitiveNV:              return "PerPrimitiveNV";
841        case (unsigned)Decoration::PerViewNV:                   return "PerViewNV";
842        case (unsigned)Decoration::PerTaskNV:                   return "PerTaskNV";
843
844        default:                                    return "Bad";
845        }
846    }
847    return "Bad";
848}
849
850static const char* NonSemanticShaderDebugInfoGetDebugNames(unsigned entrypoint)
851{
852    switch (entrypoint) {
853        case NonSemanticShaderDebugInfoDebugInfoNone:                        return "DebugInfoNone";
854        case NonSemanticShaderDebugInfoDebugCompilationUnit:                 return "DebugCompilationUnit";
855        case NonSemanticShaderDebugInfoDebugTypeBasic:                       return "DebugTypeBasic";
856        case NonSemanticShaderDebugInfoDebugTypePointer:                     return "DebugTypePointer";
857        case NonSemanticShaderDebugInfoDebugTypeQualifier:                   return "DebugTypeQualifier";
858        case NonSemanticShaderDebugInfoDebugTypeArray:                       return "DebugTypeArray";
859        case NonSemanticShaderDebugInfoDebugTypeVector:                      return "DebugTypeVector";
860        case NonSemanticShaderDebugInfoDebugTypedef:                         return "DebugTypedef";
861        case NonSemanticShaderDebugInfoDebugTypeFunction:                    return "DebugTypeFunction";
862        case NonSemanticShaderDebugInfoDebugTypeEnum:                        return "DebugTypeEnum";
863        case NonSemanticShaderDebugInfoDebugTypeComposite:                   return "DebugTypeComposite";
864        case NonSemanticShaderDebugInfoDebugTypeMember:                      return "DebugTypeMember";
865        case NonSemanticShaderDebugInfoDebugTypeInheritance:                 return "DebugTypeInheritance";
866        case NonSemanticShaderDebugInfoDebugTypePtrToMember:                 return "DebugTypePtrToMember";
867        case NonSemanticShaderDebugInfoDebugTypeTemplate:                    return "DebugTypeTemplate";
868        case NonSemanticShaderDebugInfoDebugTypeTemplateParameter:           return "DebugTypeTemplateParameter";
869        case NonSemanticShaderDebugInfoDebugTypeTemplateTemplateParameter:   return "DebugTypeTemplateTemplateParameter";
870        case NonSemanticShaderDebugInfoDebugTypeTemplateParameterPack:       return "DebugTypeTemplateParameterPack";
871        case NonSemanticShaderDebugInfoDebugGlobalVariable:                  return "DebugGlobalVariable";
872        case NonSemanticShaderDebugInfoDebugFunctionDeclaration:             return "DebugFunctionDeclaration";
873        case NonSemanticShaderDebugInfoDebugFunction:                        return "DebugFunction";
874        case NonSemanticShaderDebugInfoDebugLexicalBlock:                    return "DebugLexicalBlock";
875        case NonSemanticShaderDebugInfoDebugLexicalBlockDiscriminator:       return "DebugLexicalBlockDiscriminator";
876        case NonSemanticShaderDebugInfoDebugScope:                           return "DebugScope";
877        case NonSemanticShaderDebugInfoDebugNoScope:                         return "DebugNoScope";
878        case NonSemanticShaderDebugInfoDebugInlinedAt:                       return "DebugInlinedAt";
879        case NonSemanticShaderDebugInfoDebugLocalVariable:                   return "DebugLocalVariable";
880        case NonSemanticShaderDebugInfoDebugInlinedVariable:                 return "DebugInlinedVariable";
881        case NonSemanticShaderDebugInfoDebugDeclare:                         return "DebugDeclare";
882        case NonSemanticShaderDebugInfoDebugValue:                           return "DebugValue";
883        case NonSemanticShaderDebugInfoDebugOperation:                       return "DebugOperation";
884        case NonSemanticShaderDebugInfoDebugExpression:                      return "DebugExpression";
885        case NonSemanticShaderDebugInfoDebugMacroDef:                        return "DebugMacroDef";
886        case NonSemanticShaderDebugInfoDebugMacroUndef:                      return "DebugMacroUndef";
887        case NonSemanticShaderDebugInfoDebugImportedEntity:                  return "DebugImportedEntity";
888        case NonSemanticShaderDebugInfoDebugSource:                          return "DebugSource";
889        case NonSemanticShaderDebugInfoDebugFunctionDefinition:              return "DebugFunctionDefinition";
890        case NonSemanticShaderDebugInfoDebugSourceContinued:                 return "DebugSourceContinued";
891        case NonSemanticShaderDebugInfoDebugLine:                            return "DebugLine";
892        case NonSemanticShaderDebugInfoDebugNoLine:                          return "DebugNoLine";
893        case NonSemanticShaderDebugInfoDebugBuildIdentifier:                 return "DebugBuildIdentifier";
894        case NonSemanticShaderDebugInfoDebugStoragePath:                     return "DebugStoragePath";
895        case NonSemanticShaderDebugInfoDebugEntryPoint:                      return "DebugEntryPoint";
896        case NonSemanticShaderDebugInfoDebugTypeMatrix:                      return "DebugTypeMatrix";
897        case NonSemanticShaderDebugInfoDebugTypeVectorIdEXT:                 return "DebugTypeVectorIdEXT";
898        case NonSemanticShaderDebugInfoDebugTypeCooperativeMatrixKHR:        return "DebugTypeCooperativeMatrixKHR";
899        default:                                                                return "Bad";
900    }
901
902    return "Bad";
903}
904
905void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
906{
907    SpirvStream SpirvStream(out, stream);
908    spv::Parameterize();
909    GLSLstd450GetDebugNames(GlslStd450DebugNames);
910    SpirvStream.validate();
911    SpirvStream.processInstructions();
912}
913
914} // end namespace spv