disassemble.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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. // Disassembler for SPIR-V.
  36. //
  37. #include <cstdlib>
  38. #include <cstring>
  39. #include <cassert>
  40. #include <iomanip>
  41. #include <stack>
  42. #include <sstream>
  43. #include <cstring>
  44. #include "disassemble.h"
  45. #include "doc.h"
  46. namespace spv {
  47. extern "C" {
  48. // Include C-based headers that don't have a namespace
  49. #include "GLSL.std.450.h"
  50. #ifdef AMD_EXTENSIONS
  51. #include "GLSL.ext.AMD.h"
  52. #endif
  53. #ifdef NV_EXTENSIONS
  54. #include "GLSL.ext.NV.h"
  55. #endif
  56. }
  57. }
  58. const char* GlslStd450DebugNames[spv::GLSLstd450Count];
  59. namespace spv {
  60. #ifdef AMD_EXTENSIONS
  61. static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
  62. #endif
  63. #ifdef NV_EXTENSIONS
  64. static const char* GLSLextNVGetDebugNames(const char*, unsigned);
  65. #endif
  66. static void Kill(std::ostream& out, const char* message)
  67. {
  68. out << std::endl << "Disassembly failed: " << message << std::endl;
  69. exit(1);
  70. }
  71. // used to identify the extended instruction library imported when printing
  72. enum ExtInstSet {
  73. GLSL450Inst,
  74. #ifdef AMD_EXTENSIONS
  75. GLSLextAMDInst,
  76. #endif
  77. #ifdef NV_EXTENSIONS
  78. GLSLextNVInst,
  79. #endif
  80. OpenCLExtInst,
  81. };
  82. // Container class for a single instance of a SPIR-V stream, with methods for disassembly.
  83. class SpirvStream {
  84. public:
  85. SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
  86. virtual ~SpirvStream() { }
  87. void validate();
  88. void processInstructions();
  89. protected:
  90. SpirvStream(const SpirvStream&);
  91. SpirvStream& operator=(const SpirvStream&);
  92. Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
  93. // Output methods
  94. void outputIndent();
  95. void formatId(Id id, std::stringstream&);
  96. void outputResultId(Id id);
  97. void outputTypeId(Id id);
  98. void outputId(Id id);
  99. void outputMask(OperandClass operandClass, unsigned mask);
  100. void disassembleImmediates(int numOperands);
  101. void disassembleIds(int numOperands);
  102. int disassembleString();
  103. void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
  104. // Data
  105. std::ostream& out; // where to write the disassembly
  106. const std::vector<unsigned int>& stream; // the actual word stream
  107. int size; // the size of the word stream
  108. int word; // the next word of the stream to read
  109. // map each <id> to the instruction that created it
  110. Id bound;
  111. 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)
  112. std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
  113. // schema
  114. unsigned int schema;
  115. // stack of structured-merge points
  116. std::stack<Id> nestedControl;
  117. Id nextNestedControl; // need a slight delay for when we are nested
  118. };
  119. void SpirvStream::validate()
  120. {
  121. size = (int)stream.size();
  122. if (size < 4)
  123. Kill(out, "stream is too short");
  124. // Magic number
  125. if (stream[word++] != MagicNumber) {
  126. out << "Bad magic number";
  127. return;
  128. }
  129. // Version
  130. out << "// Module Version " << std::hex << stream[word++] << std::endl;
  131. // Generator's magic number
  132. out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
  133. // Result <id> bound
  134. bound = stream[word++];
  135. idInstruction.resize(bound);
  136. idDescriptor.resize(bound);
  137. out << "// Id's are bound by " << bound << std::endl;
  138. out << std::endl;
  139. // Reserved schema, must be 0 for now
  140. schema = stream[word++];
  141. if (schema != 0)
  142. Kill(out, "bad schema, must be 0");
  143. }
  144. // Loop over all the instructions, in order, processing each.
  145. // Boiler plate for each is handled here directly, the rest is dispatched.
  146. void SpirvStream::processInstructions()
  147. {
  148. // Instructions
  149. while (word < size) {
  150. int instructionStart = word;
  151. // Instruction wordCount and opcode
  152. unsigned int firstWord = stream[word];
  153. unsigned wordCount = firstWord >> WordCountShift;
  154. Op opCode = (Op)(firstWord & OpCodeMask);
  155. int nextInst = word + wordCount;
  156. ++word;
  157. // Presence of full instruction
  158. if (nextInst > size)
  159. Kill(out, "stream instruction terminated too early");
  160. // Base for computing number of operands; will be updated as more is learned
  161. unsigned numOperands = wordCount - 1;
  162. // Type <id>
  163. Id typeId = 0;
  164. if (InstructionDesc[opCode].hasType()) {
  165. typeId = stream[word++];
  166. --numOperands;
  167. }
  168. // Result <id>
  169. Id resultId = 0;
  170. if (InstructionDesc[opCode].hasResult()) {
  171. resultId = stream[word++];
  172. --numOperands;
  173. // save instruction for future reference
  174. idInstruction[resultId] = instructionStart;
  175. }
  176. outputResultId(resultId);
  177. outputTypeId(typeId);
  178. outputIndent();
  179. // Hand off the Op and all its operands
  180. disassembleInstruction(resultId, typeId, opCode, numOperands);
  181. if (word != nextInst) {
  182. out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
  183. word = nextInst;
  184. }
  185. out << std::endl;
  186. }
  187. }
  188. void SpirvStream::outputIndent()
  189. {
  190. for (int i = 0; i < (int)nestedControl.size(); ++i)
  191. out << " ";
  192. }
  193. void SpirvStream::formatId(Id id, std::stringstream& idStream)
  194. {
  195. if (id != 0) {
  196. // On instructions with no IDs, this is called with "0", which does not
  197. // have to be within ID bounds on null shaders.
  198. if (id >= bound)
  199. Kill(out, "Bad <id>");
  200. idStream << id;
  201. if (idDescriptor[id].size() > 0)
  202. idStream << "(" << idDescriptor[id] << ")";
  203. }
  204. }
  205. void SpirvStream::outputResultId(Id id)
  206. {
  207. const int width = 16;
  208. std::stringstream idStream;
  209. formatId(id, idStream);
  210. out << std::setw(width) << std::right << idStream.str();
  211. if (id != 0)
  212. out << ":";
  213. else
  214. out << " ";
  215. if (nestedControl.size() && id == nestedControl.top())
  216. nestedControl.pop();
  217. }
  218. void SpirvStream::outputTypeId(Id id)
  219. {
  220. const int width = 12;
  221. std::stringstream idStream;
  222. formatId(id, idStream);
  223. out << std::setw(width) << std::right << idStream.str() << " ";
  224. }
  225. void SpirvStream::outputId(Id id)
  226. {
  227. if (id >= bound)
  228. Kill(out, "Bad <id>");
  229. out << id;
  230. if (idDescriptor[id].size() > 0)
  231. out << "(" << idDescriptor[id] << ")";
  232. }
  233. void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
  234. {
  235. if (mask == 0)
  236. out << "None";
  237. else {
  238. for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
  239. if (mask & (1 << m))
  240. out << OperandClassParams[operandClass].getName(m) << " ";
  241. }
  242. }
  243. }
  244. void SpirvStream::disassembleImmediates(int numOperands)
  245. {
  246. for (int i = 0; i < numOperands; ++i) {
  247. out << stream[word++];
  248. if (i < numOperands - 1)
  249. out << " ";
  250. }
  251. }
  252. void SpirvStream::disassembleIds(int numOperands)
  253. {
  254. for (int i = 0; i < numOperands; ++i) {
  255. outputId(stream[word++]);
  256. if (i < numOperands - 1)
  257. out << " ";
  258. }
  259. }
  260. // return the number of operands consumed by the string
  261. int SpirvStream::disassembleString()
  262. {
  263. int startWord = word;
  264. out << " \"";
  265. const char* wordString;
  266. bool done = false;
  267. do {
  268. unsigned int content = stream[word];
  269. wordString = (const char*)&content;
  270. for (int charCount = 0; charCount < 4; ++charCount) {
  271. if (*wordString == 0) {
  272. done = true;
  273. break;
  274. }
  275. out << *(wordString++);
  276. }
  277. ++word;
  278. } while (! done);
  279. out << "\"";
  280. return word - startWord;
  281. }
  282. void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
  283. {
  284. // Process the opcode
  285. out << (OpcodeString(opCode) + 2); // leave out the "Op"
  286. if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
  287. nextNestedControl = stream[word];
  288. else if (opCode == OpBranchConditional || opCode == OpSwitch) {
  289. if (nextNestedControl) {
  290. nestedControl.push(nextNestedControl);
  291. nextNestedControl = 0;
  292. }
  293. } else if (opCode == OpExtInstImport) {
  294. idDescriptor[resultId] = (const char*)(&stream[word]);
  295. }
  296. else {
  297. if (resultId != 0 && idDescriptor[resultId].size() == 0) {
  298. switch (opCode) {
  299. case OpTypeInt:
  300. idDescriptor[resultId] = "int";
  301. break;
  302. case OpTypeFloat:
  303. idDescriptor[resultId] = "float";
  304. break;
  305. case OpTypeBool:
  306. idDescriptor[resultId] = "bool";
  307. break;
  308. case OpTypeStruct:
  309. idDescriptor[resultId] = "struct";
  310. break;
  311. case OpTypePointer:
  312. idDescriptor[resultId] = "ptr";
  313. break;
  314. case OpTypeVector:
  315. if (idDescriptor[stream[word]].size() > 0)
  316. idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
  317. idDescriptor[resultId].append("vec");
  318. switch (stream[word + 1]) {
  319. case 2: idDescriptor[resultId].append("2"); break;
  320. case 3: idDescriptor[resultId].append("3"); break;
  321. case 4: idDescriptor[resultId].append("4"); break;
  322. case 8: idDescriptor[resultId].append("8"); break;
  323. case 16: idDescriptor[resultId].append("16"); break;
  324. case 32: idDescriptor[resultId].append("32"); break;
  325. default: break;
  326. }
  327. break;
  328. default:
  329. break;
  330. }
  331. }
  332. }
  333. // Process the operands. Note, a new context-dependent set could be
  334. // swapped in mid-traversal.
  335. // Handle images specially, so can put out helpful strings.
  336. if (opCode == OpTypeImage) {
  337. out << " ";
  338. disassembleIds(1);
  339. out << " " << DimensionString((Dim)stream[word++]);
  340. out << (stream[word++] != 0 ? " depth" : "");
  341. out << (stream[word++] != 0 ? " array" : "");
  342. out << (stream[word++] != 0 ? " multi-sampled" : "");
  343. switch (stream[word++]) {
  344. case 0: out << " runtime"; break;
  345. case 1: out << " sampled"; break;
  346. case 2: out << " nonsampled"; break;
  347. }
  348. out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
  349. if (numOperands == 8) {
  350. out << " " << AccessQualifierString(stream[word++]);
  351. }
  352. return;
  353. }
  354. // Handle all the parameterized operands
  355. for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
  356. out << " ";
  357. OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
  358. switch (operandClass) {
  359. case OperandId:
  360. case OperandScope:
  361. case OperandMemorySemantics:
  362. disassembleIds(1);
  363. --numOperands;
  364. // Get names for printing "(XXX)" for readability, *after* this id
  365. if (opCode == OpName)
  366. idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
  367. break;
  368. case OperandVariableIds:
  369. disassembleIds(numOperands);
  370. return;
  371. case OperandImageOperands:
  372. outputMask(OperandImageOperands, stream[word++]);
  373. --numOperands;
  374. disassembleIds(numOperands);
  375. return;
  376. case OperandOptionalLiteral:
  377. case OperandVariableLiterals:
  378. if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
  379. (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
  380. out << BuiltInString(stream[word++]);
  381. --numOperands;
  382. ++op;
  383. }
  384. disassembleImmediates(numOperands);
  385. return;
  386. case OperandVariableIdLiteral:
  387. while (numOperands > 0) {
  388. out << std::endl;
  389. outputResultId(0);
  390. outputTypeId(0);
  391. outputIndent();
  392. out << " Type ";
  393. disassembleIds(1);
  394. out << ", member ";
  395. disassembleImmediates(1);
  396. numOperands -= 2;
  397. }
  398. return;
  399. case OperandVariableLiteralId:
  400. while (numOperands > 0) {
  401. out << std::endl;
  402. outputResultId(0);
  403. outputTypeId(0);
  404. outputIndent();
  405. out << " case ";
  406. disassembleImmediates(1);
  407. out << ": ";
  408. disassembleIds(1);
  409. numOperands -= 2;
  410. }
  411. return;
  412. case OperandLiteralNumber:
  413. disassembleImmediates(1);
  414. --numOperands;
  415. if (opCode == OpExtInst) {
  416. ExtInstSet extInstSet = GLSL450Inst;
  417. const char* name = idDescriptor[stream[word - 2]].c_str();
  418. if (0 == memcmp("OpenCL", name, 6)) {
  419. extInstSet = OpenCLExtInst;
  420. #ifdef AMD_EXTENSIONS
  421. } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
  422. strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
  423. strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
  424. strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
  425. extInstSet = GLSLextAMDInst;
  426. #endif
  427. #ifdef NV_EXTENSIONS
  428. }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
  429. strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
  430. strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
  431. strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) {
  432. extInstSet = GLSLextNVInst;
  433. #endif
  434. }
  435. unsigned entrypoint = stream[word - 1];
  436. if (extInstSet == GLSL450Inst) {
  437. if (entrypoint < GLSLstd450Count) {
  438. out << "(" << GlslStd450DebugNames[entrypoint] << ")";
  439. }
  440. #ifdef AMD_EXTENSIONS
  441. } else if (extInstSet == GLSLextAMDInst) {
  442. out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
  443. #endif
  444. #ifdef NV_EXTENSIONS
  445. }
  446. else if (extInstSet == GLSLextNVInst) {
  447. out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
  448. #endif
  449. }
  450. }
  451. break;
  452. case OperandOptionalLiteralString:
  453. case OperandLiteralString:
  454. numOperands -= disassembleString();
  455. break;
  456. default:
  457. assert(operandClass >= OperandSource && operandClass < OperandOpcode);
  458. if (OperandClassParams[operandClass].bitmask)
  459. outputMask(operandClass, stream[word++]);
  460. else
  461. out << OperandClassParams[operandClass].getName(stream[word++]);
  462. --numOperands;
  463. break;
  464. }
  465. }
  466. return;
  467. }
  468. static void GLSLstd450GetDebugNames(const char** names)
  469. {
  470. for (int i = 0; i < GLSLstd450Count; ++i)
  471. names[i] = "Unknown";
  472. names[GLSLstd450Round] = "Round";
  473. names[GLSLstd450RoundEven] = "RoundEven";
  474. names[GLSLstd450Trunc] = "Trunc";
  475. names[GLSLstd450FAbs] = "FAbs";
  476. names[GLSLstd450SAbs] = "SAbs";
  477. names[GLSLstd450FSign] = "FSign";
  478. names[GLSLstd450SSign] = "SSign";
  479. names[GLSLstd450Floor] = "Floor";
  480. names[GLSLstd450Ceil] = "Ceil";
  481. names[GLSLstd450Fract] = "Fract";
  482. names[GLSLstd450Radians] = "Radians";
  483. names[GLSLstd450Degrees] = "Degrees";
  484. names[GLSLstd450Sin] = "Sin";
  485. names[GLSLstd450Cos] = "Cos";
  486. names[GLSLstd450Tan] = "Tan";
  487. names[GLSLstd450Asin] = "Asin";
  488. names[GLSLstd450Acos] = "Acos";
  489. names[GLSLstd450Atan] = "Atan";
  490. names[GLSLstd450Sinh] = "Sinh";
  491. names[GLSLstd450Cosh] = "Cosh";
  492. names[GLSLstd450Tanh] = "Tanh";
  493. names[GLSLstd450Asinh] = "Asinh";
  494. names[GLSLstd450Acosh] = "Acosh";
  495. names[GLSLstd450Atanh] = "Atanh";
  496. names[GLSLstd450Atan2] = "Atan2";
  497. names[GLSLstd450Pow] = "Pow";
  498. names[GLSLstd450Exp] = "Exp";
  499. names[GLSLstd450Log] = "Log";
  500. names[GLSLstd450Exp2] = "Exp2";
  501. names[GLSLstd450Log2] = "Log2";
  502. names[GLSLstd450Sqrt] = "Sqrt";
  503. names[GLSLstd450InverseSqrt] = "InverseSqrt";
  504. names[GLSLstd450Determinant] = "Determinant";
  505. names[GLSLstd450MatrixInverse] = "MatrixInverse";
  506. names[GLSLstd450Modf] = "Modf";
  507. names[GLSLstd450ModfStruct] = "ModfStruct";
  508. names[GLSLstd450FMin] = "FMin";
  509. names[GLSLstd450SMin] = "SMin";
  510. names[GLSLstd450UMin] = "UMin";
  511. names[GLSLstd450FMax] = "FMax";
  512. names[GLSLstd450SMax] = "SMax";
  513. names[GLSLstd450UMax] = "UMax";
  514. names[GLSLstd450FClamp] = "FClamp";
  515. names[GLSLstd450SClamp] = "SClamp";
  516. names[GLSLstd450UClamp] = "UClamp";
  517. names[GLSLstd450FMix] = "FMix";
  518. names[GLSLstd450Step] = "Step";
  519. names[GLSLstd450SmoothStep] = "SmoothStep";
  520. names[GLSLstd450Fma] = "Fma";
  521. names[GLSLstd450Frexp] = "Frexp";
  522. names[GLSLstd450FrexpStruct] = "FrexpStruct";
  523. names[GLSLstd450Ldexp] = "Ldexp";
  524. names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
  525. names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
  526. names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
  527. names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
  528. names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
  529. names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
  530. names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
  531. names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
  532. names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
  533. names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
  534. names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
  535. names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
  536. names[GLSLstd450Length] = "Length";
  537. names[GLSLstd450Distance] = "Distance";
  538. names[GLSLstd450Cross] = "Cross";
  539. names[GLSLstd450Normalize] = "Normalize";
  540. names[GLSLstd450FaceForward] = "FaceForward";
  541. names[GLSLstd450Reflect] = "Reflect";
  542. names[GLSLstd450Refract] = "Refract";
  543. names[GLSLstd450FindILsb] = "FindILsb";
  544. names[GLSLstd450FindSMsb] = "FindSMsb";
  545. names[GLSLstd450FindUMsb] = "FindUMsb";
  546. names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
  547. names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
  548. names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
  549. }
  550. #ifdef AMD_EXTENSIONS
  551. static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
  552. {
  553. if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
  554. switch (entrypoint) {
  555. case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
  556. case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
  557. case WriteInvocationAMD: return "WriteInvocationAMD";
  558. case MbcntAMD: return "MbcntAMD";
  559. default: return "Bad";
  560. }
  561. } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
  562. switch (entrypoint) {
  563. case FMin3AMD: return "FMin3AMD";
  564. case UMin3AMD: return "UMin3AMD";
  565. case SMin3AMD: return "SMin3AMD";
  566. case FMax3AMD: return "FMax3AMD";
  567. case UMax3AMD: return "UMax3AMD";
  568. case SMax3AMD: return "SMax3AMD";
  569. case FMid3AMD: return "FMid3AMD";
  570. case UMid3AMD: return "UMid3AMD";
  571. case SMid3AMD: return "SMid3AMD";
  572. default: return "Bad";
  573. }
  574. } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
  575. switch (entrypoint) {
  576. case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
  577. default: return "Bad";
  578. }
  579. }
  580. else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
  581. switch (entrypoint) {
  582. case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
  583. case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
  584. case TimeAMD: return "TimeAMD";
  585. default:
  586. break;
  587. }
  588. }
  589. return "Bad";
  590. }
  591. #endif
  592. #ifdef NV_EXTENSIONS
  593. static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
  594. {
  595. if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
  596. strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
  597. strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
  598. strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
  599. strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) {
  600. switch (entrypoint) {
  601. case DecorationOverrideCoverageNV: return "OverrideCoverageNV";
  602. case DecorationPassthroughNV: return "PassthroughNV";
  603. case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
  604. case DecorationViewportRelativeNV: return "ViewportRelativeNV";
  605. case BuiltInViewportMaskNV: return "ViewportMaskNV";
  606. case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV";
  607. case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
  608. case BuiltInSecondaryPositionNV: return "SecondaryPositionNV";
  609. case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
  610. case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV";
  611. case BuiltInPositionPerViewNV: return "PositionPerViewNV";
  612. case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
  613. case CapabilityPerViewAttributesNV: return "PerViewAttributesNV";
  614. default: return "Bad";
  615. }
  616. }
  617. return "Bad";
  618. }
  619. #endif
  620. void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
  621. {
  622. SpirvStream SpirvStream(out, stream);
  623. spv::Parameterize();
  624. GLSLstd450GetDebugNames(GlslStd450DebugNames);
  625. SpirvStream.validate();
  626. SpirvStream.processInstructions();
  627. }
  628. }; // end namespace spv