blob: c950a66a0e28f973efcc4ef39e71c0518e0f9902 [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
chaoc0ad6a4e2016-12-19 16:29:34 -080057#ifdef NV_EXTENSIONS
58 #include "GLSL.ext.NV.h"
59#endif
Rex Xu9d93a232016-05-05 12:30:44 +080060 }
61}
62const char* GlslStd450DebugNames[spv::GLSLstd450Count];
63
64namespace spv {
65
66#ifdef AMD_EXTENSIONS
67static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
68#endif
John Kessenich140f3df2015-06-26 16:58:36 -060069
chaoc0ad6a4e2016-12-19 16:29:34 -080070#ifdef NV_EXTENSIONS
71static const char* GLSLextNVGetDebugNames(const char*, unsigned);
72#endif
73
Mark Adams18b637f2016-02-23 12:17:11 -050074static void Kill(std::ostream& out, const char* message)
John Kessenich140f3df2015-06-26 16:58:36 -060075{
76 out << std::endl << "Disassembly failed: " << message << std::endl;
77 exit(1);
78}
79
John Kessenich5e4b1242015-08-06 22:53:06 -060080// used to identify the extended instruction library imported when printing
81enum ExtInstSet {
82 GLSL450Inst,
Rex Xu9d93a232016-05-05 12:30:44 +080083#ifdef AMD_EXTENSIONS
84 GLSLextAMDInst,
85#endif
chaoc0ad6a4e2016-12-19 16:29:34 -080086#ifdef NV_EXTENSIONS
87 GLSLextNVInst,
88#endif
John Kessenich5e4b1242015-08-06 22:53:06 -060089 OpenCLExtInst,
90};
91
John Kessenich140f3df2015-06-26 16:58:36 -060092// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
93class SpirvStream {
94public:
95 SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
96 virtual ~SpirvStream() { }
97
98 void validate();
99 void processInstructions();
100
101protected:
John Kessenich5e4b1242015-08-06 22:53:06 -0600102 SpirvStream(const SpirvStream&);
103 SpirvStream& operator=(const SpirvStream&);
John Kessenich140f3df2015-06-26 16:58:36 -0600104 Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
105
106 // Output methods
107 void outputIndent();
108 void formatId(Id id, std::stringstream&);
109 void outputResultId(Id id);
110 void outputTypeId(Id id);
111 void outputId(Id id);
John Kessenich5e4b1242015-08-06 22:53:06 -0600112 void outputMask(OperandClass operandClass, unsigned mask);
John Kessenich140f3df2015-06-26 16:58:36 -0600113 void disassembleImmediates(int numOperands);
114 void disassembleIds(int numOperands);
John Kessenich55e7d112015-11-15 21:33:39 -0700115 int disassembleString();
John Kessenich140f3df2015-06-26 16:58:36 -0600116 void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
117
118 // Data
119 std::ostream& out; // where to write the disassembly
120 const std::vector<unsigned int>& stream; // the actual word stream
121 int size; // the size of the word stream
122 int word; // the next word of the stream to read
123
124 // map each <id> to the instruction that created it
125 Id bound;
126 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)
127
128 std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
129
130 // schema
131 unsigned int schema;
132
133 // stack of structured-merge points
134 std::stack<Id> nestedControl;
135 Id nextNestedControl; // need a slight delay for when we are nested
136};
137
138void SpirvStream::validate()
139{
140 size = (int)stream.size();
141 if (size < 4)
142 Kill(out, "stream is too short");
143
144 // Magic number
145 if (stream[word++] != MagicNumber) {
146 out << "Bad magic number";
147 return;
148 }
149
150 // Version
John Kessenich55e7d112015-11-15 21:33:39 -0700151 out << "// Module Version " << std::hex << stream[word++] << std::endl;
John Kessenich140f3df2015-06-26 16:58:36 -0600152
153 // Generator's magic number
John Kessenich55e7d112015-11-15 21:33:39 -0700154 out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
John Kessenich140f3df2015-06-26 16:58:36 -0600155
156 // Result <id> bound
157 bound = stream[word++];
158 idInstruction.resize(bound);
159 idDescriptor.resize(bound);
160 out << "// Id's are bound by " << bound << std::endl;
161 out << std::endl;
162
163 // Reserved schema, must be 0 for now
164 schema = stream[word++];
165 if (schema != 0)
166 Kill(out, "bad schema, must be 0");
167}
168
169// Loop over all the instructions, in order, processing each.
170// Boiler plate for each is handled here directly, the rest is dispatched.
171void SpirvStream::processInstructions()
172{
173 // Instructions
174 while (word < size) {
175 int instructionStart = word;
176
177 // Instruction wordCount and opcode
178 unsigned int firstWord = stream[word];
179 unsigned wordCount = firstWord >> WordCountShift;
180 Op opCode = (Op)(firstWord & OpCodeMask);
181 int nextInst = word + wordCount;
182 ++word;
183
184 // Presence of full instruction
185 if (nextInst > size)
186 Kill(out, "stream instruction terminated too early");
187
188 // Base for computing number of operands; will be updated as more is learned
189 unsigned numOperands = wordCount - 1;
190
191 // Type <id>
192 Id typeId = 0;
193 if (InstructionDesc[opCode].hasType()) {
194 typeId = stream[word++];
195 --numOperands;
196 }
197
198 // Result <id>
199 Id resultId = 0;
200 if (InstructionDesc[opCode].hasResult()) {
201 resultId = stream[word++];
202 --numOperands;
203
204 // save instruction for future reference
205 idInstruction[resultId] = instructionStart;
206 }
207
208 outputResultId(resultId);
209 outputTypeId(typeId);
210 outputIndent();
211
212 // Hand off the Op and all its operands
213 disassembleInstruction(resultId, typeId, opCode, numOperands);
214 if (word != nextInst) {
215 out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
216 word = nextInst;
217 }
218 out << std::endl;
219 }
220}
221
222void SpirvStream::outputIndent()
223{
224 for (int i = 0; i < (int)nestedControl.size(); ++i)
225 out << " ";
226}
227
228void SpirvStream::formatId(Id id, std::stringstream& idStream)
229{
John Kessenich140f3df2015-06-26 16:58:36 -0600230 if (id != 0) {
steve-lunarga8456412016-08-17 16:18:06 -0600231 // On instructions with no IDs, this is called with "0", which does not
232 // have to be within ID bounds on null shaders.
233 if (id >= bound)
234 Kill(out, "Bad <id>");
235
John Kessenich140f3df2015-06-26 16:58:36 -0600236 idStream << id;
237 if (idDescriptor[id].size() > 0)
238 idStream << "(" << idDescriptor[id] << ")";
239 }
240}
241
242void SpirvStream::outputResultId(Id id)
243{
244 const int width = 16;
245 std::stringstream idStream;
246 formatId(id, idStream);
247 out << std::setw(width) << std::right << idStream.str();
248 if (id != 0)
249 out << ":";
250 else
251 out << " ";
252
253 if (nestedControl.size() && id == nestedControl.top())
254 nestedControl.pop();
255}
256
257void SpirvStream::outputTypeId(Id id)
258{
259 const int width = 12;
260 std::stringstream idStream;
261 formatId(id, idStream);
262 out << std::setw(width) << std::right << idStream.str() << " ";
263}
264
265void SpirvStream::outputId(Id id)
266{
267 if (id >= bound)
268 Kill(out, "Bad <id>");
269
270 out << id;
271 if (idDescriptor[id].size() > 0)
272 out << "(" << idDescriptor[id] << ")";
273}
274
John Kessenich5e4b1242015-08-06 22:53:06 -0600275void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
276{
277 if (mask == 0)
278 out << "None";
279 else {
280 for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
281 if (mask & (1 << m))
282 out << OperandClassParams[operandClass].getName(m) << " ";
283 }
284 }
285}
286
John Kessenich140f3df2015-06-26 16:58:36 -0600287void SpirvStream::disassembleImmediates(int numOperands)
288{
289 for (int i = 0; i < numOperands; ++i) {
290 out << stream[word++];
291 if (i < numOperands - 1)
292 out << " ";
293 }
294}
295
296void SpirvStream::disassembleIds(int numOperands)
297{
298 for (int i = 0; i < numOperands; ++i) {
299 outputId(stream[word++]);
300 if (i < numOperands - 1)
301 out << " ";
302 }
303}
304
John Kessenich55e7d112015-11-15 21:33:39 -0700305// return the number of operands consumed by the string
306int SpirvStream::disassembleString()
John Kessenich140f3df2015-06-26 16:58:36 -0600307{
John Kessenich55e7d112015-11-15 21:33:39 -0700308 int startWord = word;
309
John Kessenich140f3df2015-06-26 16:58:36 -0600310 out << " \"";
311
John Kessenich55e7d112015-11-15 21:33:39 -0700312 const char* wordString;
John Kessenich140f3df2015-06-26 16:58:36 -0600313 bool done = false;
314 do {
315 unsigned int content = stream[word];
John Kessenich55e7d112015-11-15 21:33:39 -0700316 wordString = (const char*)&content;
John Kessenich140f3df2015-06-26 16:58:36 -0600317 for (int charCount = 0; charCount < 4; ++charCount) {
318 if (*wordString == 0) {
319 done = true;
320 break;
321 }
322 out << *(wordString++);
323 }
324 ++word;
325 } while (! done);
326
327 out << "\"";
John Kessenich55e7d112015-11-15 21:33:39 -0700328
329 return word - startWord;
John Kessenich140f3df2015-06-26 16:58:36 -0600330}
331
332void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
333{
334 // Process the opcode
335
336 out << (OpcodeString(opCode) + 2); // leave out the "Op"
337
338 if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
339 nextNestedControl = stream[word];
340 else if (opCode == OpBranchConditional || opCode == OpSwitch) {
341 if (nextNestedControl) {
342 nestedControl.push(nextNestedControl);
343 nextNestedControl = 0;
344 }
John Kessenich5e4b1242015-08-06 22:53:06 -0600345 } else if (opCode == OpExtInstImport) {
Mark Adamsc11e95f2015-10-26 12:38:46 -0400346 idDescriptor[resultId] = (const char*)(&stream[word]);
John Kessenich5e4b1242015-08-06 22:53:06 -0600347 }
John Kessenich140f3df2015-06-26 16:58:36 -0600348 else {
steve-lunarga8456412016-08-17 16:18:06 -0600349 if (resultId != 0 && idDescriptor[resultId].size() == 0) {
John Kessenich140f3df2015-06-26 16:58:36 -0600350 switch (opCode) {
351 case OpTypeInt:
352 idDescriptor[resultId] = "int";
353 break;
354 case OpTypeFloat:
355 idDescriptor[resultId] = "float";
356 break;
357 case OpTypeBool:
358 idDescriptor[resultId] = "bool";
359 break;
360 case OpTypeStruct:
361 idDescriptor[resultId] = "struct";
362 break;
363 case OpTypePointer:
364 idDescriptor[resultId] = "ptr";
365 break;
366 case OpTypeVector:
367 if (idDescriptor[stream[word]].size() > 0)
368 idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
369 idDescriptor[resultId].append("vec");
370 switch (stream[word + 1]) {
371 case 2: idDescriptor[resultId].append("2"); break;
372 case 3: idDescriptor[resultId].append("3"); break;
373 case 4: idDescriptor[resultId].append("4"); break;
374 case 8: idDescriptor[resultId].append("8"); break;
375 case 16: idDescriptor[resultId].append("16"); break;
376 case 32: idDescriptor[resultId].append("32"); break;
377 default: break;
378 }
379 break;
380 default:
381 break;
382 }
383 }
384 }
385
386 // Process the operands. Note, a new context-dependent set could be
387 // swapped in mid-traversal.
388
John Kessenich5e4b1242015-08-06 22:53:06 -0600389 // Handle images specially, so can put out helpful strings.
390 if (opCode == OpTypeImage) {
391 out << " ";
John Kessenich140f3df2015-06-26 16:58:36 -0600392 disassembleIds(1);
393 out << " " << DimensionString((Dim)stream[word++]);
John Kessenich140f3df2015-06-26 16:58:36 -0600394 out << (stream[word++] != 0 ? " depth" : "");
John Kessenich5e4b1242015-08-06 22:53:06 -0600395 out << (stream[word++] != 0 ? " array" : "");
John Kessenich140f3df2015-06-26 16:58:36 -0600396 out << (stream[word++] != 0 ? " multi-sampled" : "");
John Kessenich5e4b1242015-08-06 22:53:06 -0600397 switch (stream[word++]) {
398 case 0: out << " runtime"; break;
399 case 1: out << " sampled"; break;
400 case 2: out << " nonsampled"; break;
401 }
402 out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
403
404 if (numOperands == 8) {
405 out << " " << AccessQualifierString(stream[word++]);
406 }
John Kessenich140f3df2015-06-26 16:58:36 -0600407 return;
408 }
409
410 // Handle all the parameterized operands
John Kessenich5e4b1242015-08-06 22:53:06 -0600411 for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
John Kessenich140f3df2015-06-26 16:58:36 -0600412 out << " ";
413 OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
414 switch (operandClass) {
415 case OperandId:
John Kessenich5e4b1242015-08-06 22:53:06 -0600416 case OperandScope:
417 case OperandMemorySemantics:
John Kessenich140f3df2015-06-26 16:58:36 -0600418 disassembleIds(1);
John Kessenich55e7d112015-11-15 21:33:39 -0700419 --numOperands;
John Kessenich140f3df2015-06-26 16:58:36 -0600420 // Get names for printing "(XXX)" for readability, *after* this id
421 if (opCode == OpName)
Mark Adamsc11e95f2015-10-26 12:38:46 -0400422 idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
John Kessenich140f3df2015-06-26 16:58:36 -0600423 break;
John Kessenich140f3df2015-06-26 16:58:36 -0600424 case OperandVariableIds:
425 disassembleIds(numOperands);
426 return;
John Kessenich55e7d112015-11-15 21:33:39 -0700427 case OperandImageOperands:
John Kessenich71631272015-10-13 10:39:19 -0600428 outputMask(OperandImageOperands, stream[word++]);
John Kessenich5e4b1242015-08-06 22:53:06 -0600429 --numOperands;
430 disassembleIds(numOperands);
431 return;
432 case OperandOptionalLiteral:
John Kessenich140f3df2015-06-26 16:58:36 -0600433 case OperandVariableLiterals:
Mark Adamsc11e95f2015-10-26 12:38:46 -0400434 if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
435 (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
John Kessenich140f3df2015-06-26 16:58:36 -0600436 out << BuiltInString(stream[word++]);
437 --numOperands;
438 ++op;
439 }
440 disassembleImmediates(numOperands);
441 return;
John Kessenich5e4b1242015-08-06 22:53:06 -0600442 case OperandVariableIdLiteral:
443 while (numOperands > 0) {
444 out << std::endl;
445 outputResultId(0);
446 outputTypeId(0);
447 outputIndent();
448 out << " Type ";
449 disassembleIds(1);
450 out << ", member ";
451 disassembleImmediates(1);
452 numOperands -= 2;
453 }
454 return;
John Kessenich140f3df2015-06-26 16:58:36 -0600455 case OperandVariableLiteralId:
456 while (numOperands > 0) {
457 out << std::endl;
458 outputResultId(0);
459 outputTypeId(0);
460 outputIndent();
461 out << " case ";
462 disassembleImmediates(1);
463 out << ": ";
464 disassembleIds(1);
465 numOperands -= 2;
466 }
467 return;
468 case OperandLiteralNumber:
469 disassembleImmediates(1);
John Kessenich55e7d112015-11-15 21:33:39 -0700470 --numOperands;
John Kessenich140f3df2015-06-26 16:58:36 -0600471 if (opCode == OpExtInst) {
John Kessenich5e4b1242015-08-06 22:53:06 -0600472 ExtInstSet extInstSet = GLSL450Inst;
Rex Xu9d93a232016-05-05 12:30:44 +0800473 const char* name = idDescriptor[stream[word - 2]].c_str();
474 if (0 == memcmp("OpenCL", name, 6)) {
John Kessenich5e4b1242015-08-06 22:53:06 -0600475 extInstSet = OpenCLExtInst;
Rex Xu9d93a232016-05-05 12:30:44 +0800476#ifdef AMD_EXTENSIONS
477 } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
478 strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
479 strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
480 strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
481 extInstSet = GLSLextAMDInst;
482#endif
chaoc0ad6a4e2016-12-19 16:29:34 -0800483#ifdef NV_EXTENSIONS
chaoc6e5acae2016-12-20 13:28:52 -0800484 }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
chaoc771d89f2017-01-13 01:10:53 -0800485 strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
chaocdf3956c2017-02-14 14:52:34 -0800486 strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
487 strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) {
chaoc0ad6a4e2016-12-19 16:29:34 -0800488 extInstSet = GLSLextNVInst;
489#endif
John Kessenich5e4b1242015-08-06 22:53:06 -0600490 }
John Kessenich140f3df2015-06-26 16:58:36 -0600491 unsigned entrypoint = stream[word - 1];
John Kessenich5e4b1242015-08-06 22:53:06 -0600492 if (extInstSet == GLSL450Inst) {
John Kessenich55e7d112015-11-15 21:33:39 -0700493 if (entrypoint < GLSLstd450Count) {
John Kessenich5e4b1242015-08-06 22:53:06 -0600494 out << "(" << GlslStd450DebugNames[entrypoint] << ")";
495 }
Rex Xu9d93a232016-05-05 12:30:44 +0800496#ifdef AMD_EXTENSIONS
497 } else if (extInstSet == GLSLextAMDInst) {
498 out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
499#endif
chaoc0ad6a4e2016-12-19 16:29:34 -0800500#ifdef NV_EXTENSIONS
501 }
502 else if (extInstSet == GLSLextNVInst) {
503 out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
504#endif
John Kessenich5e4b1242015-08-06 22:53:06 -0600505 }
John Kessenich140f3df2015-06-26 16:58:36 -0600506 }
507 break;
John Kessenich55e7d112015-11-15 21:33:39 -0700508 case OperandOptionalLiteralString:
John Kessenich140f3df2015-06-26 16:58:36 -0600509 case OperandLiteralString:
John Kessenich55e7d112015-11-15 21:33:39 -0700510 numOperands -= disassembleString();
511 break;
John Kessenich140f3df2015-06-26 16:58:36 -0600512 default:
513 assert(operandClass >= OperandSource && operandClass < OperandOpcode);
514
John Kessenich5e4b1242015-08-06 22:53:06 -0600515 if (OperandClassParams[operandClass].bitmask)
516 outputMask(operandClass, stream[word++]);
517 else
John Kessenich140f3df2015-06-26 16:58:36 -0600518 out << OperandClassParams[operandClass].getName(stream[word++]);
John Kessenich55e7d112015-11-15 21:33:39 -0700519 --numOperands;
John Kessenich6c292d32016-02-15 20:58:50 -0700520
John Kessenich140f3df2015-06-26 16:58:36 -0600521 break;
522 }
John Kessenich140f3df2015-06-26 16:58:36 -0600523 }
524
525 return;
526}
527
Mark Adams18b637f2016-02-23 12:17:11 -0500528static void GLSLstd450GetDebugNames(const char** names)
John Kessenich5e4b1242015-08-06 22:53:06 -0600529{
530 for (int i = 0; i < GLSLstd450Count; ++i)
531 names[i] = "Unknown";
532
533 names[GLSLstd450Round] = "Round";
534 names[GLSLstd450RoundEven] = "RoundEven";
535 names[GLSLstd450Trunc] = "Trunc";
536 names[GLSLstd450FAbs] = "FAbs";
537 names[GLSLstd450SAbs] = "SAbs";
538 names[GLSLstd450FSign] = "FSign";
539 names[GLSLstd450SSign] = "SSign";
540 names[GLSLstd450Floor] = "Floor";
541 names[GLSLstd450Ceil] = "Ceil";
542 names[GLSLstd450Fract] = "Fract";
543 names[GLSLstd450Radians] = "Radians";
544 names[GLSLstd450Degrees] = "Degrees";
545 names[GLSLstd450Sin] = "Sin";
546 names[GLSLstd450Cos] = "Cos";
547 names[GLSLstd450Tan] = "Tan";
548 names[GLSLstd450Asin] = "Asin";
549 names[GLSLstd450Acos] = "Acos";
550 names[GLSLstd450Atan] = "Atan";
551 names[GLSLstd450Sinh] = "Sinh";
552 names[GLSLstd450Cosh] = "Cosh";
553 names[GLSLstd450Tanh] = "Tanh";
554 names[GLSLstd450Asinh] = "Asinh";
555 names[GLSLstd450Acosh] = "Acosh";
556 names[GLSLstd450Atanh] = "Atanh";
557 names[GLSLstd450Atan2] = "Atan2";
558 names[GLSLstd450Pow] = "Pow";
559 names[GLSLstd450Exp] = "Exp";
560 names[GLSLstd450Log] = "Log";
561 names[GLSLstd450Exp2] = "Exp2";
562 names[GLSLstd450Log2] = "Log2";
563 names[GLSLstd450Sqrt] = "Sqrt";
John Kessenich55e7d112015-11-15 21:33:39 -0700564 names[GLSLstd450InverseSqrt] = "InverseSqrt";
John Kessenich5e4b1242015-08-06 22:53:06 -0600565 names[GLSLstd450Determinant] = "Determinant";
John Kessenich55e7d112015-11-15 21:33:39 -0700566 names[GLSLstd450MatrixInverse] = "MatrixInverse";
John Kessenich5e4b1242015-08-06 22:53:06 -0600567 names[GLSLstd450Modf] = "Modf";
568 names[GLSLstd450ModfStruct] = "ModfStruct";
569 names[GLSLstd450FMin] = "FMin";
570 names[GLSLstd450SMin] = "SMin";
571 names[GLSLstd450UMin] = "UMin";
572 names[GLSLstd450FMax] = "FMax";
573 names[GLSLstd450SMax] = "SMax";
574 names[GLSLstd450UMax] = "UMax";
575 names[GLSLstd450FClamp] = "FClamp";
576 names[GLSLstd450SClamp] = "SClamp";
577 names[GLSLstd450UClamp] = "UClamp";
John Kessenich55e7d112015-11-15 21:33:39 -0700578 names[GLSLstd450FMix] = "FMix";
John Kessenich5e4b1242015-08-06 22:53:06 -0600579 names[GLSLstd450Step] = "Step";
John Kessenich55e7d112015-11-15 21:33:39 -0700580 names[GLSLstd450SmoothStep] = "SmoothStep";
John Kessenich5e4b1242015-08-06 22:53:06 -0600581 names[GLSLstd450Fma] = "Fma";
582 names[GLSLstd450Frexp] = "Frexp";
583 names[GLSLstd450FrexpStruct] = "FrexpStruct";
584 names[GLSLstd450Ldexp] = "Ldexp";
585 names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
586 names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
587 names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
588 names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
589 names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
590 names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
591 names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
592 names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
593 names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
594 names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
595 names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
596 names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
597 names[GLSLstd450Length] = "Length";
598 names[GLSLstd450Distance] = "Distance";
599 names[GLSLstd450Cross] = "Cross";
600 names[GLSLstd450Normalize] = "Normalize";
John Kessenich55e7d112015-11-15 21:33:39 -0700601 names[GLSLstd450FaceForward] = "FaceForward";
John Kessenich5e4b1242015-08-06 22:53:06 -0600602 names[GLSLstd450Reflect] = "Reflect";
603 names[GLSLstd450Refract] = "Refract";
John Kessenich55e7d112015-11-15 21:33:39 -0700604 names[GLSLstd450FindILsb] = "FindILsb";
605 names[GLSLstd450FindSMsb] = "FindSMsb";
606 names[GLSLstd450FindUMsb] = "FindUMsb";
John Kessenich5e4b1242015-08-06 22:53:06 -0600607 names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
608 names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
609 names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
610}
611
Rex Xu9d93a232016-05-05 12:30:44 +0800612#ifdef AMD_EXTENSIONS
613static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
614{
615 if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
616 switch (entrypoint) {
617 case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
618 case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
619 case WriteInvocationAMD: return "WriteInvocationAMD";
620 case MbcntAMD: return "MbcntAMD";
621 default: return "Bad";
622 }
623 } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
624 switch (entrypoint) {
625 case FMin3AMD: return "FMin3AMD";
626 case UMin3AMD: return "UMin3AMD";
627 case SMin3AMD: return "SMin3AMD";
628 case FMax3AMD: return "FMax3AMD";
629 case UMax3AMD: return "UMax3AMD";
630 case SMax3AMD: return "SMax3AMD";
631 case FMid3AMD: return "FMid3AMD";
632 case UMid3AMD: return "UMid3AMD";
633 case SMid3AMD: return "SMid3AMD";
634 default: return "Bad";
635 }
636 } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
637 switch (entrypoint) {
638 case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
639 default: return "Bad";
640 }
641 }
642 else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
643 switch (entrypoint) {
644 case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
645 case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
646 case TimeAMD: return "TimeAMD";
647 default:
648 break;
649 }
650 }
651
652 return "Bad";
653}
654#endif
655
chaoc0ad6a4e2016-12-19 16:29:34 -0800656
657#ifdef NV_EXTENSIONS
658static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
659{
chaoc6e5acae2016-12-20 13:28:52 -0800660 if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
chaoc771d89f2017-01-13 01:10:53 -0800661 strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
662 strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
chaocdf3956c2017-02-14 14:52:34 -0800663 strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
664 strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) {
chaoc0ad6a4e2016-12-19 16:29:34 -0800665 switch (entrypoint) {
chaoc771d89f2017-01-13 01:10:53 -0800666 case DecorationOverrideCoverageNV: return "OverrideCoverageNV";
667 case DecorationPassthroughNV: return "PassthroughNV";
668 case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
669 case DecorationViewportRelativeNV: return "ViewportRelativeNV";
670 case BuiltInViewportMaskNV: return "ViewportMaskNV";
671 case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV";
672 case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
673 case BuiltInSecondaryPositionNV: return "SecondaryPositionNV";
674 case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
675 case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV";
chaocdf3956c2017-02-14 14:52:34 -0800676 case BuiltInPositionPerViewNV: return "PositionPerViewNV";
677 case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
678 case CapabilityPerViewAttributesNV: return "PerViewAttributesNV";
chaoc771d89f2017-01-13 01:10:53 -0800679 default: return "Bad";
chaoc0ad6a4e2016-12-19 16:29:34 -0800680 }
681 }
682 return "Bad";
683}
684#endif
685
John Kessenich140f3df2015-06-26 16:58:36 -0600686void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
687{
688 SpirvStream SpirvStream(out, stream);
Jack Andersen52e61ac2016-02-23 12:03:21 -1000689 spv::Parameterize();
John Kessenich5e4b1242015-08-06 22:53:06 -0600690 GLSLstd450GetDebugNames(GlslStd450DebugNames);
John Kessenich140f3df2015-06-26 16:58:36 -0600691 SpirvStream.validate();
692 SpirvStream.processInstructions();
693}
694
695}; // end namespace spv