blob: b432e65d0f031c2c3fc3b3bd7560cd7805cab52f [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2014-2015 LunarG, Inc.
John Kessenich140f3df2015-06-26 16:58:36 -06003//
John Kessenich927608b2017-01-06 12:34:14 -07004// All rights reserved.
John Kessenich140f3df2015-06-26 16:58:36 -06005//
John Kessenich927608b2017-01-06 12:34:14 -07006// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions
8// are met:
John Kessenich140f3df2015-06-26 16:58:36 -06009//
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//
John Kessenich927608b2017-01-06 12:34:14 -070022// 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.
John Kessenich140f3df2015-06-26 16:58:36 -060034
35//
John Kessenich140f3df2015-06-26 16:58:36 -060036// Disassembler for SPIR-V.
37//
38
John Kessenich66ec80e2016-08-05 14:04:23 -060039#include <cstdlib>
40#include <cstring>
41#include <cassert>
John Kessenich140f3df2015-06-26 16:58:36 -060042#include <iomanip>
43#include <stack>
44#include <sstream>
John Kessenich5e4b1242015-08-06 22:53:06 -060045#include <cstring>
John Kessenich140f3df2015-06-26 16:58:36 -060046
47#include "disassemble.h"
48#include "doc.h"
49
50namespace spv {
Rex Xu9d93a232016-05-05 12:30:44 +080051 extern "C" {
52 // Include C-based headers that don't have a namespace
53 #include "GLSL.std.450.h"
54#ifdef AMD_EXTENSIONS
55 #include "GLSL.ext.AMD.h"
56#endif
John Kessenich66011cb2018-03-06 16:12:04 -070057
chaoc0ad6a4e2016-12-19 16:29:34 -080058#ifdef NV_EXTENSIONS
59 #include "GLSL.ext.NV.h"
60#endif
Rex Xu9d93a232016-05-05 12:30:44 +080061 }
62}
63const char* GlslStd450DebugNames[spv::GLSLstd450Count];
64
65namespace spv {
66
67#ifdef AMD_EXTENSIONS
68static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
69#endif
John Kessenich140f3df2015-06-26 16:58:36 -060070
chaoc0ad6a4e2016-12-19 16:29:34 -080071#ifdef NV_EXTENSIONS
72static const char* GLSLextNVGetDebugNames(const char*, unsigned);
73#endif
74
Mark Adams18b637f2016-02-23 12:17:11 -050075static void Kill(std::ostream& out, const char* message)
John Kessenich140f3df2015-06-26 16:58:36 -060076{
77 out << std::endl << "Disassembly failed: " << message << std::endl;
78 exit(1);
79}
80
John Kessenich5e4b1242015-08-06 22:53:06 -060081// used to identify the extended instruction library imported when printing
82enum ExtInstSet {
83 GLSL450Inst,
John Kessenich66011cb2018-03-06 16:12:04 -070084
Rex Xu9d93a232016-05-05 12:30:44 +080085#ifdef AMD_EXTENSIONS
86 GLSLextAMDInst,
87#endif
John Kessenich66011cb2018-03-06 16:12:04 -070088
chaoc0ad6a4e2016-12-19 16:29:34 -080089#ifdef NV_EXTENSIONS
90 GLSLextNVInst,
91#endif
John Kessenich66011cb2018-03-06 16:12:04 -070092
John Kessenich5e4b1242015-08-06 22:53:06 -060093 OpenCLExtInst,
94};
95
John Kessenich140f3df2015-06-26 16:58:36 -060096// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
97class SpirvStream {
98public:
99 SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
100 virtual ~SpirvStream() { }
101
102 void validate();
103 void processInstructions();
104
105protected:
John Kessenich5e4b1242015-08-06 22:53:06 -0600106 SpirvStream(const SpirvStream&);
107 SpirvStream& operator=(const SpirvStream&);
John Kessenich140f3df2015-06-26 16:58:36 -0600108 Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
109
110 // Output methods
111 void outputIndent();
112 void formatId(Id id, std::stringstream&);
113 void outputResultId(Id id);
114 void outputTypeId(Id id);
115 void outputId(Id id);
John Kessenich5e4b1242015-08-06 22:53:06 -0600116 void outputMask(OperandClass operandClass, unsigned mask);
John Kessenich140f3df2015-06-26 16:58:36 -0600117 void disassembleImmediates(int numOperands);
118 void disassembleIds(int numOperands);
John Kessenich55e7d112015-11-15 21:33:39 -0700119 int disassembleString();
John Kessenich140f3df2015-06-26 16:58:36 -0600120 void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
121
122 // Data
123 std::ostream& out; // where to write the disassembly
124 const std::vector<unsigned int>& stream; // the actual word stream
125 int size; // the size of the word stream
126 int word; // the next word of the stream to read
127
128 // map each <id> to the instruction that created it
129 Id bound;
130 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)
131
132 std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
133
134 // schema
135 unsigned int schema;
136
137 // stack of structured-merge points
138 std::stack<Id> nestedControl;
139 Id nextNestedControl; // need a slight delay for when we are nested
140};
141
142void SpirvStream::validate()
143{
144 size = (int)stream.size();
145 if (size < 4)
146 Kill(out, "stream is too short");
147
148 // Magic number
149 if (stream[word++] != MagicNumber) {
150 out << "Bad magic number";
151 return;
152 }
153
154 // Version
John Kessenich55e7d112015-11-15 21:33:39 -0700155 out << "// Module Version " << std::hex << stream[word++] << std::endl;
John Kessenich140f3df2015-06-26 16:58:36 -0600156
157 // Generator's magic number
John Kessenich55e7d112015-11-15 21:33:39 -0700158 out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
John Kessenich140f3df2015-06-26 16:58:36 -0600159
160 // Result <id> bound
161 bound = stream[word++];
162 idInstruction.resize(bound);
163 idDescriptor.resize(bound);
164 out << "// Id's are bound by " << bound << std::endl;
165 out << std::endl;
166
167 // Reserved schema, must be 0 for now
168 schema = stream[word++];
169 if (schema != 0)
170 Kill(out, "bad schema, must be 0");
171}
172
173// Loop over all the instructions, in order, processing each.
174// Boiler plate for each is handled here directly, the rest is dispatched.
175void SpirvStream::processInstructions()
176{
177 // Instructions
178 while (word < size) {
179 int instructionStart = word;
180
181 // Instruction wordCount and opcode
182 unsigned int firstWord = stream[word];
183 unsigned wordCount = firstWord >> WordCountShift;
184 Op opCode = (Op)(firstWord & OpCodeMask);
185 int nextInst = word + wordCount;
186 ++word;
187
188 // Presence of full instruction
189 if (nextInst > size)
190 Kill(out, "stream instruction terminated too early");
191
192 // Base for computing number of operands; will be updated as more is learned
193 unsigned numOperands = wordCount - 1;
194
195 // Type <id>
196 Id typeId = 0;
197 if (InstructionDesc[opCode].hasType()) {
198 typeId = stream[word++];
199 --numOperands;
200 }
201
202 // Result <id>
203 Id resultId = 0;
204 if (InstructionDesc[opCode].hasResult()) {
205 resultId = stream[word++];
206 --numOperands;
207
208 // save instruction for future reference
209 idInstruction[resultId] = instructionStart;
210 }
211
212 outputResultId(resultId);
213 outputTypeId(typeId);
214 outputIndent();
215
216 // Hand off the Op and all its operands
217 disassembleInstruction(resultId, typeId, opCode, numOperands);
218 if (word != nextInst) {
219 out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
220 word = nextInst;
221 }
222 out << std::endl;
223 }
224}
225
226void SpirvStream::outputIndent()
227{
228 for (int i = 0; i < (int)nestedControl.size(); ++i)
229 out << " ";
230}
231
232void SpirvStream::formatId(Id id, std::stringstream& idStream)
233{
John Kessenich140f3df2015-06-26 16:58:36 -0600234 if (id != 0) {
steve-lunarga8456412016-08-17 16:18:06 -0600235 // On instructions with no IDs, this is called with "0", which does not
236 // have to be within ID bounds on null shaders.
237 if (id >= bound)
238 Kill(out, "Bad <id>");
239
John Kessenich140f3df2015-06-26 16:58:36 -0600240 idStream << id;
241 if (idDescriptor[id].size() > 0)
242 idStream << "(" << idDescriptor[id] << ")";
243 }
244}
245
246void SpirvStream::outputResultId(Id id)
247{
248 const int width = 16;
249 std::stringstream idStream;
250 formatId(id, idStream);
251 out << std::setw(width) << std::right << idStream.str();
252 if (id != 0)
253 out << ":";
254 else
255 out << " ";
256
257 if (nestedControl.size() && id == nestedControl.top())
258 nestedControl.pop();
259}
260
261void SpirvStream::outputTypeId(Id id)
262{
263 const int width = 12;
264 std::stringstream idStream;
265 formatId(id, idStream);
266 out << std::setw(width) << std::right << idStream.str() << " ";
267}
268
269void SpirvStream::outputId(Id id)
270{
271 if (id >= bound)
272 Kill(out, "Bad <id>");
273
274 out << id;
275 if (idDescriptor[id].size() > 0)
276 out << "(" << idDescriptor[id] << ")";
277}
278
John Kessenich5e4b1242015-08-06 22:53:06 -0600279void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
280{
281 if (mask == 0)
282 out << "None";
283 else {
284 for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
285 if (mask & (1 << m))
286 out << OperandClassParams[operandClass].getName(m) << " ";
287 }
288 }
289}
290
John Kessenich140f3df2015-06-26 16:58:36 -0600291void SpirvStream::disassembleImmediates(int numOperands)
292{
293 for (int i = 0; i < numOperands; ++i) {
294 out << stream[word++];
295 if (i < numOperands - 1)
296 out << " ";
297 }
298}
299
300void SpirvStream::disassembleIds(int numOperands)
301{
302 for (int i = 0; i < numOperands; ++i) {
303 outputId(stream[word++]);
304 if (i < numOperands - 1)
305 out << " ";
306 }
307}
308
John Kessenich55e7d112015-11-15 21:33:39 -0700309// return the number of operands consumed by the string
310int SpirvStream::disassembleString()
John Kessenich140f3df2015-06-26 16:58:36 -0600311{
John Kessenich55e7d112015-11-15 21:33:39 -0700312 int startWord = word;
313
John Kessenich140f3df2015-06-26 16:58:36 -0600314 out << " \"";
315
John Kessenich55e7d112015-11-15 21:33:39 -0700316 const char* wordString;
John Kessenich140f3df2015-06-26 16:58:36 -0600317 bool done = false;
318 do {
319 unsigned int content = stream[word];
John Kessenich55e7d112015-11-15 21:33:39 -0700320 wordString = (const char*)&content;
John Kessenich140f3df2015-06-26 16:58:36 -0600321 for (int charCount = 0; charCount < 4; ++charCount) {
322 if (*wordString == 0) {
323 done = true;
324 break;
325 }
326 out << *(wordString++);
327 }
328 ++word;
329 } while (! done);
330
331 out << "\"";
John Kessenich55e7d112015-11-15 21:33:39 -0700332
333 return word - startWord;
John Kessenich140f3df2015-06-26 16:58:36 -0600334}
335
336void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
337{
338 // Process the opcode
339
340 out << (OpcodeString(opCode) + 2); // leave out the "Op"
341
342 if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
343 nextNestedControl = stream[word];
344 else if (opCode == OpBranchConditional || opCode == OpSwitch) {
345 if (nextNestedControl) {
346 nestedControl.push(nextNestedControl);
347 nextNestedControl = 0;
348 }
John Kessenich5e4b1242015-08-06 22:53:06 -0600349 } else if (opCode == OpExtInstImport) {
Mark Adamsc11e95f2015-10-26 12:38:46 -0400350 idDescriptor[resultId] = (const char*)(&stream[word]);
John Kessenich5e4b1242015-08-06 22:53:06 -0600351 }
John Kessenich140f3df2015-06-26 16:58:36 -0600352 else {
steve-lunarga8456412016-08-17 16:18:06 -0600353 if (resultId != 0 && idDescriptor[resultId].size() == 0) {
John Kessenich140f3df2015-06-26 16:58:36 -0600354 switch (opCode) {
355 case OpTypeInt:
Jeff Bolzaf7a9482018-05-22 23:13:30 -0500356 switch (stream[word]) {
357 case 8: idDescriptor[resultId] = "int8_t"; break;
358 case 16: idDescriptor[resultId] = "int16_t"; break;
359 default: assert(0); // fallthrough
360 case 32: idDescriptor[resultId] = "int"; break;
361 case 64: idDescriptor[resultId] = "int64_t"; break;
362 }
John Kessenich140f3df2015-06-26 16:58:36 -0600363 break;
364 case OpTypeFloat:
Jeff Bolzaf7a9482018-05-22 23:13:30 -0500365 switch (stream[word]) {
366 case 16: idDescriptor[resultId] = "float16_t"; break;
367 default: assert(0); // fallthrough
368 case 32: idDescriptor[resultId] = "float"; break;
369 case 64: idDescriptor[resultId] = "float64_t"; break;
370 }
John Kessenich140f3df2015-06-26 16:58:36 -0600371 break;
372 case OpTypeBool:
373 idDescriptor[resultId] = "bool";
374 break;
375 case OpTypeStruct:
376 idDescriptor[resultId] = "struct";
377 break;
378 case OpTypePointer:
379 idDescriptor[resultId] = "ptr";
380 break;
381 case OpTypeVector:
Jeff Bolzaf7a9482018-05-22 23:13:30 -0500382 if (idDescriptor[stream[word]].size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -0600383 idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
Jeff Bolzaf7a9482018-05-22 23:13:30 -0500384 if (strstr(idDescriptor[stream[word]].c_str(), "8")) {
385 idDescriptor[resultId].append("8");
386 }
387 if (strstr(idDescriptor[stream[word]].c_str(), "16")) {
388 idDescriptor[resultId].append("16");
389 }
390 if (strstr(idDescriptor[stream[word]].c_str(), "64")) {
391 idDescriptor[resultId].append("64");
392 }
393 }
John Kessenich140f3df2015-06-26 16:58:36 -0600394 idDescriptor[resultId].append("vec");
395 switch (stream[word + 1]) {
396 case 2: idDescriptor[resultId].append("2"); break;
397 case 3: idDescriptor[resultId].append("3"); break;
398 case 4: idDescriptor[resultId].append("4"); break;
399 case 8: idDescriptor[resultId].append("8"); break;
400 case 16: idDescriptor[resultId].append("16"); break;
401 case 32: idDescriptor[resultId].append("32"); break;
402 default: break;
403 }
404 break;
405 default:
406 break;
407 }
408 }
409 }
410
411 // Process the operands. Note, a new context-dependent set could be
412 // swapped in mid-traversal.
413
John Kessenich5e4b1242015-08-06 22:53:06 -0600414 // Handle images specially, so can put out helpful strings.
415 if (opCode == OpTypeImage) {
416 out << " ";
John Kessenich140f3df2015-06-26 16:58:36 -0600417 disassembleIds(1);
418 out << " " << DimensionString((Dim)stream[word++]);
John Kessenich140f3df2015-06-26 16:58:36 -0600419 out << (stream[word++] != 0 ? " depth" : "");
John Kessenich5e4b1242015-08-06 22:53:06 -0600420 out << (stream[word++] != 0 ? " array" : "");
John Kessenich140f3df2015-06-26 16:58:36 -0600421 out << (stream[word++] != 0 ? " multi-sampled" : "");
John Kessenich5e4b1242015-08-06 22:53:06 -0600422 switch (stream[word++]) {
423 case 0: out << " runtime"; break;
424 case 1: out << " sampled"; break;
425 case 2: out << " nonsampled"; break;
426 }
427 out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
428
429 if (numOperands == 8) {
430 out << " " << AccessQualifierString(stream[word++]);
431 }
John Kessenich140f3df2015-06-26 16:58:36 -0600432 return;
433 }
434
435 // Handle all the parameterized operands
John Kessenich5e4b1242015-08-06 22:53:06 -0600436 for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
John Kessenich140f3df2015-06-26 16:58:36 -0600437 out << " ";
438 OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
439 switch (operandClass) {
440 case OperandId:
John Kessenich5e4b1242015-08-06 22:53:06 -0600441 case OperandScope:
442 case OperandMemorySemantics:
John Kessenich140f3df2015-06-26 16:58:36 -0600443 disassembleIds(1);
John Kessenich55e7d112015-11-15 21:33:39 -0700444 --numOperands;
John Kessenich140f3df2015-06-26 16:58:36 -0600445 // Get names for printing "(XXX)" for readability, *after* this id
446 if (opCode == OpName)
Mark Adamsc11e95f2015-10-26 12:38:46 -0400447 idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
John Kessenich140f3df2015-06-26 16:58:36 -0600448 break;
John Kessenich140f3df2015-06-26 16:58:36 -0600449 case OperandVariableIds:
450 disassembleIds(numOperands);
451 return;
John Kessenich55e7d112015-11-15 21:33:39 -0700452 case OperandImageOperands:
John Kessenich71631272015-10-13 10:39:19 -0600453 outputMask(OperandImageOperands, stream[word++]);
John Kessenich5e4b1242015-08-06 22:53:06 -0600454 --numOperands;
455 disassembleIds(numOperands);
456 return;
457 case OperandOptionalLiteral:
John Kessenich140f3df2015-06-26 16:58:36 -0600458 case OperandVariableLiterals:
Mark Adamsc11e95f2015-10-26 12:38:46 -0400459 if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
460 (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
John Kessenich140f3df2015-06-26 16:58:36 -0600461 out << BuiltInString(stream[word++]);
462 --numOperands;
463 ++op;
464 }
465 disassembleImmediates(numOperands);
466 return;
John Kessenich5e4b1242015-08-06 22:53:06 -0600467 case OperandVariableIdLiteral:
468 while (numOperands > 0) {
469 out << std::endl;
470 outputResultId(0);
471 outputTypeId(0);
472 outputIndent();
473 out << " Type ";
474 disassembleIds(1);
475 out << ", member ";
476 disassembleImmediates(1);
477 numOperands -= 2;
478 }
479 return;
John Kessenich140f3df2015-06-26 16:58:36 -0600480 case OperandVariableLiteralId:
481 while (numOperands > 0) {
482 out << std::endl;
483 outputResultId(0);
484 outputTypeId(0);
485 outputIndent();
486 out << " case ";
487 disassembleImmediates(1);
488 out << ": ";
489 disassembleIds(1);
490 numOperands -= 2;
491 }
492 return;
493 case OperandLiteralNumber:
494 disassembleImmediates(1);
John Kessenich55e7d112015-11-15 21:33:39 -0700495 --numOperands;
John Kessenich140f3df2015-06-26 16:58:36 -0600496 if (opCode == OpExtInst) {
John Kessenich5e4b1242015-08-06 22:53:06 -0600497 ExtInstSet extInstSet = GLSL450Inst;
Rex Xu9d93a232016-05-05 12:30:44 +0800498 const char* name = idDescriptor[stream[word - 2]].c_str();
499 if (0 == memcmp("OpenCL", name, 6)) {
John Kessenich5e4b1242015-08-06 22:53:06 -0600500 extInstSet = OpenCLExtInst;
Rex Xu9d93a232016-05-05 12:30:44 +0800501#ifdef AMD_EXTENSIONS
502 } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
503 strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
504 strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
505 strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
506 extInstSet = GLSLextAMDInst;
507#endif
chaoc0ad6a4e2016-12-19 16:29:34 -0800508#ifdef NV_EXTENSIONS
chaoc6e5acae2016-12-20 13:28:52 -0800509 }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
chaoc771d89f2017-01-13 01:10:53 -0800510 strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
chaocdf3956c2017-02-14 14:52:34 -0800511 strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
512 strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) {
chaoc0ad6a4e2016-12-19 16:29:34 -0800513 extInstSet = GLSLextNVInst;
514#endif
John Kessenich5e4b1242015-08-06 22:53:06 -0600515 }
John Kessenich140f3df2015-06-26 16:58:36 -0600516 unsigned entrypoint = stream[word - 1];
John Kessenich5e4b1242015-08-06 22:53:06 -0600517 if (extInstSet == GLSL450Inst) {
John Kessenich55e7d112015-11-15 21:33:39 -0700518 if (entrypoint < GLSLstd450Count) {
John Kessenich5e4b1242015-08-06 22:53:06 -0600519 out << "(" << GlslStd450DebugNames[entrypoint] << ")";
520 }
Rex Xu9d93a232016-05-05 12:30:44 +0800521#ifdef AMD_EXTENSIONS
522 } else if (extInstSet == GLSLextAMDInst) {
523 out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
524#endif
chaoc0ad6a4e2016-12-19 16:29:34 -0800525#ifdef NV_EXTENSIONS
526 }
527 else if (extInstSet == GLSLextNVInst) {
528 out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
529#endif
John Kessenich5e4b1242015-08-06 22:53:06 -0600530 }
John Kessenich140f3df2015-06-26 16:58:36 -0600531 }
532 break;
John Kessenich55e7d112015-11-15 21:33:39 -0700533 case OperandOptionalLiteralString:
John Kessenich140f3df2015-06-26 16:58:36 -0600534 case OperandLiteralString:
John Kessenich55e7d112015-11-15 21:33:39 -0700535 numOperands -= disassembleString();
536 break;
John Kessenich140f3df2015-06-26 16:58:36 -0600537 default:
538 assert(operandClass >= OperandSource && operandClass < OperandOpcode);
539
John Kessenich5e4b1242015-08-06 22:53:06 -0600540 if (OperandClassParams[operandClass].bitmask)
541 outputMask(operandClass, stream[word++]);
542 else
John Kessenich140f3df2015-06-26 16:58:36 -0600543 out << OperandClassParams[operandClass].getName(stream[word++]);
John Kessenich55e7d112015-11-15 21:33:39 -0700544 --numOperands;
John Kessenich6c292d32016-02-15 20:58:50 -0700545
John Kessenich140f3df2015-06-26 16:58:36 -0600546 break;
547 }
John Kessenich140f3df2015-06-26 16:58:36 -0600548 }
549
550 return;
551}
552
Mark Adams18b637f2016-02-23 12:17:11 -0500553static void GLSLstd450GetDebugNames(const char** names)
John Kessenich5e4b1242015-08-06 22:53:06 -0600554{
555 for (int i = 0; i < GLSLstd450Count; ++i)
556 names[i] = "Unknown";
557
558 names[GLSLstd450Round] = "Round";
559 names[GLSLstd450RoundEven] = "RoundEven";
560 names[GLSLstd450Trunc] = "Trunc";
561 names[GLSLstd450FAbs] = "FAbs";
562 names[GLSLstd450SAbs] = "SAbs";
563 names[GLSLstd450FSign] = "FSign";
564 names[GLSLstd450SSign] = "SSign";
565 names[GLSLstd450Floor] = "Floor";
566 names[GLSLstd450Ceil] = "Ceil";
567 names[GLSLstd450Fract] = "Fract";
568 names[GLSLstd450Radians] = "Radians";
569 names[GLSLstd450Degrees] = "Degrees";
570 names[GLSLstd450Sin] = "Sin";
571 names[GLSLstd450Cos] = "Cos";
572 names[GLSLstd450Tan] = "Tan";
573 names[GLSLstd450Asin] = "Asin";
574 names[GLSLstd450Acos] = "Acos";
575 names[GLSLstd450Atan] = "Atan";
576 names[GLSLstd450Sinh] = "Sinh";
577 names[GLSLstd450Cosh] = "Cosh";
578 names[GLSLstd450Tanh] = "Tanh";
579 names[GLSLstd450Asinh] = "Asinh";
580 names[GLSLstd450Acosh] = "Acosh";
581 names[GLSLstd450Atanh] = "Atanh";
582 names[GLSLstd450Atan2] = "Atan2";
583 names[GLSLstd450Pow] = "Pow";
584 names[GLSLstd450Exp] = "Exp";
585 names[GLSLstd450Log] = "Log";
586 names[GLSLstd450Exp2] = "Exp2";
587 names[GLSLstd450Log2] = "Log2";
588 names[GLSLstd450Sqrt] = "Sqrt";
John Kessenich55e7d112015-11-15 21:33:39 -0700589 names[GLSLstd450InverseSqrt] = "InverseSqrt";
John Kessenich5e4b1242015-08-06 22:53:06 -0600590 names[GLSLstd450Determinant] = "Determinant";
John Kessenich55e7d112015-11-15 21:33:39 -0700591 names[GLSLstd450MatrixInverse] = "MatrixInverse";
John Kessenich5e4b1242015-08-06 22:53:06 -0600592 names[GLSLstd450Modf] = "Modf";
593 names[GLSLstd450ModfStruct] = "ModfStruct";
594 names[GLSLstd450FMin] = "FMin";
595 names[GLSLstd450SMin] = "SMin";
596 names[GLSLstd450UMin] = "UMin";
597 names[GLSLstd450FMax] = "FMax";
598 names[GLSLstd450SMax] = "SMax";
599 names[GLSLstd450UMax] = "UMax";
600 names[GLSLstd450FClamp] = "FClamp";
601 names[GLSLstd450SClamp] = "SClamp";
602 names[GLSLstd450UClamp] = "UClamp";
John Kessenich55e7d112015-11-15 21:33:39 -0700603 names[GLSLstd450FMix] = "FMix";
John Kessenich5e4b1242015-08-06 22:53:06 -0600604 names[GLSLstd450Step] = "Step";
John Kessenich55e7d112015-11-15 21:33:39 -0700605 names[GLSLstd450SmoothStep] = "SmoothStep";
John Kessenich5e4b1242015-08-06 22:53:06 -0600606 names[GLSLstd450Fma] = "Fma";
607 names[GLSLstd450Frexp] = "Frexp";
608 names[GLSLstd450FrexpStruct] = "FrexpStruct";
609 names[GLSLstd450Ldexp] = "Ldexp";
610 names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
611 names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
612 names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
613 names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
614 names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
615 names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
616 names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
617 names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
618 names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
619 names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
620 names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
621 names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
622 names[GLSLstd450Length] = "Length";
623 names[GLSLstd450Distance] = "Distance";
624 names[GLSLstd450Cross] = "Cross";
625 names[GLSLstd450Normalize] = "Normalize";
John Kessenich55e7d112015-11-15 21:33:39 -0700626 names[GLSLstd450FaceForward] = "FaceForward";
John Kessenich5e4b1242015-08-06 22:53:06 -0600627 names[GLSLstd450Reflect] = "Reflect";
628 names[GLSLstd450Refract] = "Refract";
John Kessenich55e7d112015-11-15 21:33:39 -0700629 names[GLSLstd450FindILsb] = "FindILsb";
630 names[GLSLstd450FindSMsb] = "FindSMsb";
631 names[GLSLstd450FindUMsb] = "FindUMsb";
John Kessenich5e4b1242015-08-06 22:53:06 -0600632 names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
633 names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
634 names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
635}
636
Rex Xu9d93a232016-05-05 12:30:44 +0800637#ifdef AMD_EXTENSIONS
638static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
639{
640 if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
641 switch (entrypoint) {
642 case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
643 case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
644 case WriteInvocationAMD: return "WriteInvocationAMD";
645 case MbcntAMD: return "MbcntAMD";
646 default: return "Bad";
647 }
648 } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
649 switch (entrypoint) {
650 case FMin3AMD: return "FMin3AMD";
651 case UMin3AMD: return "UMin3AMD";
652 case SMin3AMD: return "SMin3AMD";
653 case FMax3AMD: return "FMax3AMD";
654 case UMax3AMD: return "UMax3AMD";
655 case SMax3AMD: return "SMax3AMD";
656 case FMid3AMD: return "FMid3AMD";
657 case UMid3AMD: return "UMid3AMD";
658 case SMid3AMD: return "SMid3AMD";
659 default: return "Bad";
660 }
661 } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
662 switch (entrypoint) {
663 case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
664 default: return "Bad";
665 }
666 }
667 else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
668 switch (entrypoint) {
669 case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
670 case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
671 case TimeAMD: return "TimeAMD";
672 default:
673 break;
674 }
675 }
676
677 return "Bad";
678}
679#endif
680
chaoc0ad6a4e2016-12-19 16:29:34 -0800681#ifdef NV_EXTENSIONS
682static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
683{
chaoc6e5acae2016-12-20 13:28:52 -0800684 if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
chaoc771d89f2017-01-13 01:10:53 -0800685 strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
686 strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
chaocdf3956c2017-02-14 14:52:34 -0800687 strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
688 strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) {
chaoc0ad6a4e2016-12-19 16:29:34 -0800689 switch (entrypoint) {
chaoc771d89f2017-01-13 01:10:53 -0800690 case DecorationOverrideCoverageNV: return "OverrideCoverageNV";
691 case DecorationPassthroughNV: return "PassthroughNV";
692 case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
693 case DecorationViewportRelativeNV: return "ViewportRelativeNV";
694 case BuiltInViewportMaskNV: return "ViewportMaskNV";
695 case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV";
696 case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
697 case BuiltInSecondaryPositionNV: return "SecondaryPositionNV";
698 case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
699 case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV";
chaocdf3956c2017-02-14 14:52:34 -0800700 case BuiltInPositionPerViewNV: return "PositionPerViewNV";
701 case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
702 case CapabilityPerViewAttributesNV: return "PerViewAttributesNV";
chaoc771d89f2017-01-13 01:10:53 -0800703 default: return "Bad";
chaoc0ad6a4e2016-12-19 16:29:34 -0800704 }
705 }
706 return "Bad";
707}
708#endif
709
John Kessenich140f3df2015-06-26 16:58:36 -0600710void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
711{
712 SpirvStream SpirvStream(out, stream);
Jack Andersen52e61ac2016-02-23 12:03:21 -1000713 spv::Parameterize();
John Kessenich5e4b1242015-08-06 22:53:06 -0600714 GLSLstd450GetDebugNames(GlslStd450DebugNames);
John Kessenich140f3df2015-06-26 16:58:36 -0600715 SpirvStream.validate();
716 SpirvStream.processInstructions();
717}
718
719}; // end namespace spv