blob: ce7db0b9a0e84b67dd812045b3094ea69b7ef614 [file] [log] [blame]
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +01001// Copyright (c) 2015 The Khronos Group Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and/or associated documentation files (the
5// "Materials"), to deal in the Materials without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Materials, and to
8// permit persons to whom the Materials are furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Materials.
13//
14// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
15// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
16// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
17// https://www.khronos.org/registry/
18//
19// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
26
27#include <libspirv/libspirv.h>
28#include "binary.h"
29#include "diagnostic.h"
30#include "ext_inst.h"
31#include "opcode.h"
32#include "operand.h"
33
34#include <assert.h>
35#include <string.h>
36
37#include <sstream>
38
39// Binary API
40
41enum {
42 I32_ENDIAN_LITTLE = 0x03020100ul,
43 I32_ENDIAN_BIG = 0x00010203ul,
44};
45
46static const union {
47 unsigned char bytes[4];
48 uint32_t value;
49} o32_host_order = {{0, 1, 2, 3}};
50
51#define I32_ENDIAN_HOST (o32_host_order.value)
52
53spv_result_t spvBinaryEndianness(const spv_binary binary,
54 spv_endianness_t *pEndian) {
55 spvCheck(!binary->code || !binary->wordCount,
56 return SPV_ERROR_INVALID_BINARY);
57 spvCheck(!pEndian, return SPV_ERROR_INVALID_POINTER);
58
59 uint8_t bytes[4];
60 memcpy(bytes, binary->code, sizeof(uint32_t));
61
62 if (0x03 == bytes[0] && 0x02 == bytes[1] && 0x23 == bytes[2] &&
63 0x07 == bytes[3]) {
64 *pEndian = SPV_ENDIANNESS_LITTLE;
65 return SPV_SUCCESS;
66 }
67
68 if (0x07 == bytes[0] && 0x23 == bytes[1] && 0x02 == bytes[2] &&
69 0x03 == bytes[3]) {
70 *pEndian = SPV_ENDIANNESS_BIG;
71 return SPV_SUCCESS;
72 }
73
74 return SPV_ERROR_INVALID_BINARY;
75}
76
77uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian) {
78 if ((SPV_ENDIANNESS_LITTLE == endian && I32_ENDIAN_HOST == I32_ENDIAN_BIG) ||
79 (SPV_ENDIANNESS_BIG == endian && I32_ENDIAN_HOST == I32_ENDIAN_LITTLE)) {
80 return (word & 0x000000ff) << 24 | (word & 0x0000ff00) << 8 |
81 (word & 0x00ff0000) >> 8 | (word & 0xff000000) >> 24;
82 }
83
84 return word;
85}
86
87spv_result_t spvBinaryHeaderGet(const spv_binary binary,
88 const spv_endianness_t endian,
89 spv_header_t *pHeader) {
90 spvCheck(!binary->code || !binary->wordCount,
91 return SPV_ERROR_INVALID_BINARY);
92 spvCheck(!pHeader, return SPV_ERROR_INVALID_POINTER);
93
94 // TODO: Validation checking?
95 pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
96 pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
97 pHeader->generator =
98 spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
99 pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
100 pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
101 pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
102
103 return SPV_SUCCESS;
104}
105
106spv_result_t spvBinaryHeaderSet(spv_binary_t *binary, const uint32_t bound) {
107 spvCheck(!binary, return SPV_ERROR_INVALID_BINARY);
108 spvCheck(!binary->code || !binary->wordCount,
109 return SPV_ERROR_INVALID_BINARY);
110
111 binary->code[SPV_INDEX_MAGIC_NUMBER] = SPV_MAGIC_NUMBER;
112 binary->code[SPV_INDEX_VERSION_NUMBER] = SPV_VERSION_NUMBER;
Kenneth Benzie (Benie)81d7d492015-06-01 09:50:46 -0700113 binary->code[SPV_INDEX_GENERATOR_NUMBER] = SPV_GENERATOR_KHRONOS;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100114 binary->code[SPV_INDEX_BOUND] = bound;
115 binary->code[SPV_INDEX_SCHEMA] = 0; // NOTE: Reserved
116
117 return SPV_SUCCESS;
118}
119
120spv_result_t spvBinaryEncodeU32(const uint32_t value, spv_instruction_t *pInst,
121 const spv_position position,
122 spv_diagnostic *pDiagnostic) {
123 spvCheck(pInst->wordCount + 1 > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
124 DIAGNOSTIC << "Instruction word count '"
125 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "' exceeded.";
126 return SPV_ERROR_INVALID_TEXT);
127
128 pInst->words[pInst->wordCount++] = (uint32_t)value;
129 return SPV_SUCCESS;
130}
131
132spv_result_t spvBinaryEncodeU64(const uint64_t value, spv_instruction_t *pInst,
133 const spv_position position,
134 spv_diagnostic *pDiagnostic) {
135 spvCheck(pInst->wordCount + 2 > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
136 DIAGNOSTIC << "Instruction word count '"
137 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "' exceeded.";
138 return SPV_ERROR_INVALID_TEXT);
139
140 uint32_t low = (uint32_t)(0x00000000ffffffff & value);
141 uint32_t high = (uint32_t)((0xffffffff00000000 & value) >> 32);
142 pInst->words[pInst->wordCount++] = low;
143 pInst->words[pInst->wordCount++] = high;
144 return SPV_SUCCESS;
145}
146
147spv_result_t spvBinaryEncodeString(const char *str, spv_instruction_t *pInst,
148 const spv_position position,
149 spv_diagnostic *pDiagnostic) {
150 size_t length = strlen(str);
151 size_t wordCount = (length / 4) + 1;
152 spvCheck((sizeof(uint32_t) * pInst->wordCount) + length >
153 sizeof(uint32_t) * SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
154 DIAGNOSTIC << "Instruction word count '"
155 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "'exceeded.";
156 return SPV_ERROR_INVALID_TEXT);
157
158 char *dest = (char *)&pInst->words[pInst->wordCount];
159 strncpy(dest, str, length);
160 pInst->wordCount += (uint16_t)wordCount;
161
162 return SPV_SUCCESS;
163}
164
David Neto78c3b432015-08-27 13:03:52 -0400165// TODO(dneto): This API is not powerful enough in the case that the
166// number and type of operands are not known until partway through parsing
167// the operation. This happens when enum operands might have different number
168// of operands, or with extended instructions.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100169spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
170 const uint16_t operandIndex,
171 const spv_opcode_desc opcodeEntry,
172 const spv_operand_table operandTable,
173 spv_operand_desc *pOperandEntry) {
174 spv_operand_type_t type;
David Neto78c3b432015-08-27 13:03:52 -0400175 if (operandIndex < opcodeEntry->numTypes) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100176 // NOTE: Do operand table lookup to set operandEntry if successful
177 uint16_t index = operandIndex - 1;
178 type = opcodeEntry->operandTypes[index];
179 spv_operand_desc entry = nullptr;
180 if (!spvOperandTableValueLookup(operandTable, type, word, &entry)) {
181 if (SPV_OPERAND_TYPE_NONE != entry->operandTypes[0]) {
182 *pOperandEntry = entry;
183 }
184 }
185 } else if (*pOperandEntry) {
186 // NOTE: Use specified operand entry operand type for this word
David Neto78c3b432015-08-27 13:03:52 -0400187 uint16_t index = operandIndex - opcodeEntry->numTypes;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100188 type = (*pOperandEntry)->operandTypes[index];
189 } else if (OpSwitch == opcodeEntry->opcode) {
190 // NOTE: OpSwitch is a special case which expects a list of paired extra
191 // operands
192 assert(0 &&
193 "This case is previously untested, remove this assert and ensure it "
194 "is behaving correctly!");
David Neto78c3b432015-08-27 13:03:52 -0400195 uint16_t lastIndex = opcodeEntry->numTypes - 1;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100196 uint16_t index = lastIndex + ((operandIndex - lastIndex) % 2);
197 type = opcodeEntry->operandTypes[index];
198 } else {
199 // NOTE: Default to last operand type in opcode entry
David Neto78c3b432015-08-27 13:03:52 -0400200 uint16_t index = opcodeEntry->numTypes - 1;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100201 type = opcodeEntry->operandTypes[index];
202 }
203 return type;
204}
205
206spv_result_t spvBinaryDecodeOperand(
207 const Op opcode, const spv_operand_type_t type, const uint32_t *words,
208 const spv_endianness_t endian, const uint32_t options,
209 const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
David Neto78c3b432015-08-27 13:03:52 -0400210 spv_operand_pattern_t *pExpectedOperands, spv_ext_inst_type_t *pExtInstType,
211 out_stream &stream, spv_position position, spv_diagnostic *pDiagnostic) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100212 spvCheck(!words || !position, return SPV_ERROR_INVALID_POINTER);
213 spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
214
215 bool print = spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
216 bool color =
217 print && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options);
218
219 uint64_t index = 0;
220 switch (type) {
David Neto78c3b432015-08-27 13:03:52 -0400221 case SPV_OPERAND_TYPE_ID:
222 case SPV_OPERAND_TYPE_RESULT_ID:
223 case SPV_OPERAND_TYPE_OPTIONAL_ID:
224 case SPV_OPERAND_TYPE_ID_IN_OPTIONAL_TUPLE: {
225 if (color) {
226 stream.get() << (type == SPV_OPERAND_TYPE_RESULT_ID ? clr::blue()
227 : clr::yellow());
228 }
Lei Zhangabafd5e2015-08-21 11:52:29 -0400229 stream.get() << "%" << spvFixWord(words[index], endian);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100230 stream.get() << ((color) ? clr::reset() : "");
231 index++;
232 position->index++;
233 } break;
David Neto78c3b432015-08-27 13:03:52 -0400234 case SPV_OPERAND_TYPE_LITERAL:
235 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL:
236 case SPV_OPERAND_TYPE_LITERAL_IN_OPTIONAL_TUPLE: {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100237 // TODO: Need to support multiple word literals
238 stream.get() << (color ? clr::red() : "");
239 stream.get() << spvFixWord(words[index], endian);
240 stream.get() << (color ? clr::reset() : "");
241 index++;
242 position->index++;
243 } break;
244 case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
245 // NOTE: Special case for extended instruction use
246 if (OpExtInst == opcode) {
247 spv_ext_inst_desc extInst;
248 spvCheck(spvExtInstTableValueLookup(extInstTable, *pExtInstType,
249 words[0], &extInst),
250 DIAGNOSTIC << "Invalid extended instruction '" << words[0]
251 << "'.";
252 return SPV_ERROR_INVALID_BINARY);
David Neto78c3b432015-08-27 13:03:52 -0400253 spvPrependOperandTypes(extInst->operandTypes, pExpectedOperands);
Andrew Woloszyn0d350b52015-08-21 14:23:42 -0400254 stream.get() << (color ? clr::red() : "");
255 stream.get() << extInst->name;
256 stream.get() << (color ? clr::reset() : "");
257 } else {
258 stream.get() << (color ? clr::red() : "");
259 stream.get() << spvFixWord(words[index], endian);
260 stream.get() << (color ? clr::reset() : "");
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100261 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100262 index++;
263 position->index++;
264 } break;
David Neto78c3b432015-08-27 13:03:52 -0400265 case SPV_OPERAND_TYPE_LITERAL_STRING:
266 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100267 const char *string = (const char *)&words[index];
268 uint64_t stringOperandCount = (strlen(string) / 4) + 1;
269
270 // NOTE: Special case for extended instruction import
271 if (OpExtInstImport == opcode) {
272 *pExtInstType = spvExtInstImportTypeGet(string);
273 spvCheck(SPV_EXT_INST_TYPE_NONE == *pExtInstType,
274 DIAGNOSTIC << "Invalid extended instruction import'" << string
275 << "'.";
276 return SPV_ERROR_INVALID_BINARY);
277 }
278
279 stream.get() << "\"";
280 stream.get() << (color ? clr::green() : "");
281 stream.get() << string;
282 stream.get() << (color ? clr::reset() : "");
283 stream.get() << "\"";
284 index += stringOperandCount;
285 position->index += stringOperandCount;
286 } break;
287 case SPV_OPERAND_TYPE_CAPABILITY:
288 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
289 case SPV_OPERAND_TYPE_EXECUTION_MODEL:
290 case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
291 case SPV_OPERAND_TYPE_MEMORY_MODEL:
292 case SPV_OPERAND_TYPE_EXECUTION_MODE:
David Neto78c3b432015-08-27 13:03:52 -0400293 case SPV_OPERAND_TYPE_OPTIONAL_EXECUTION_MODE:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100294 case SPV_OPERAND_TYPE_STORAGE_CLASS:
295 case SPV_OPERAND_TYPE_DIMENSIONALITY:
296 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
297 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
298 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
299 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
300 case SPV_OPERAND_TYPE_LINKAGE_TYPE:
301 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
302 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
303 case SPV_OPERAND_TYPE_DECORATION:
304 case SPV_OPERAND_TYPE_BUILT_IN:
305 case SPV_OPERAND_TYPE_SELECTION_CONTROL:
306 case SPV_OPERAND_TYPE_LOOP_CONTROL:
307 case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
308 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
David Neto78c3b432015-08-27 13:03:52 -0400309 case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100310 case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
311 case SPV_OPERAND_TYPE_GROUP_OPERATION:
312 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
David Neto47994822015-08-27 13:11:01 -0400313 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100314 spv_operand_desc entry;
315 spvCheck(
316 spvOperandTableValueLookup(operandTable, type,
317 spvFixWord(words[index], endian), &entry),
318 DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " operand '"
319 << words[index] << "'.";
320 return SPV_ERROR_INVALID_TEXT);
321 stream.get() << entry->name;
David Neto78c3b432015-08-27 13:03:52 -0400322 // Prepare to accept operands to this operand, if needed.
323 spvPrependOperandTypes(entry->operandTypes, pExpectedOperands);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100324 index++;
325 position->index++;
326 } break;
327 default: {
328 DIAGNOSTIC << "Invalid binary operand '" << type << "'";
329 return SPV_ERROR_INVALID_BINARY;
330 }
331 }
332
333 return SPV_SUCCESS;
334}
335
336spv_result_t spvBinaryDecodeOpcode(
337 spv_instruction_t *pInst, const spv_endianness_t endian,
338 const uint32_t options, const spv_opcode_table opcodeTable,
339 const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
340 out_stream &stream, spv_position position, spv_diagnostic *pDiagnostic) {
341 spvCheck(!pInst || !position, return SPV_ERROR_INVALID_POINTER);
342 spvCheck(!opcodeTable || !operandTable || !extInstTable,
343 return SPV_ERROR_INVALID_TABLE);
344 spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
345
David Neto78c3b432015-08-27 13:03:52 -0400346 spv_position_t instructionStart = *position;
347
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100348 uint16_t wordCount;
349 Op opcode;
350 spvOpcodeSplit(spvFixWord(pInst->words[0], endian), &wordCount, &opcode);
351
352 spv_opcode_desc opcodeEntry;
353 spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
354 DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
355 return SPV_ERROR_INVALID_BINARY);
356
David Neto78c3b432015-08-27 13:03:52 -0400357 // See if there are enough required words.
358 // Some operands in the operand types are optional or could be zero length.
359 // The optional and zero length opeands must be at the end of the list.
360 if (opcodeEntry->numTypes > wordCount &&
361 !spvOperandIsOptional(opcodeEntry->operandTypes[wordCount])) {
362 uint16_t numRequired;
363 for (numRequired = 0; numRequired < opcodeEntry->numTypes &&
364 !spvOperandIsOptional(opcodeEntry->operandTypes[numRequired]) ; numRequired++ )
365 ;
366 DIAGNOSTIC << "Invalid instruction Op" << opcodeEntry->name
367 << " word count '" << wordCount
368 << "', expected at least '" << numRequired
369 << "'.";
370 return SPV_ERROR_INVALID_BINARY;
371 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100372
Lei Zhang8a375202015-08-24 15:52:26 -0400373 std::stringstream no_result_id_strstream;
374 out_stream no_result_id_stream(no_result_id_strstream);
375 const int16_t result_id_index = spvOpcodeResultIdIndex(opcodeEntry);
376 no_result_id_stream.get() << "Op" << opcodeEntry->name;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100377
378 position->index++;
379
David Neto78c3b432015-08-27 13:03:52 -0400380 // Maintains the ordered list of expected operand types.
381 // For many instructions we only need the {numTypes, operandTypes}
382 // entries in opcodeEntry. However, sometimes we need to modify
383 // the list as we parse the operands. This occurs when an operand
384 // has its own logical operands (such as the LocalSize operand for
385 // ExecutionMode), or for extended instructions that may have their
386 // own operands depending on the selected extended instruction.
387 spv_operand_pattern_t expectedOperands(
388 opcodeEntry->operandTypes,
389 opcodeEntry->operandTypes + opcodeEntry->numTypes);
390
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100391 for (uint16_t index = 1; index < wordCount; ++index) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100392 const uint64_t currentPosIndex = position->index;
393
David Neto78c3b432015-08-27 13:03:52 -0400394 spvCheck(expectedOperands.empty(),
395 DIAGNOSTIC << "Invalid instruction Op" << opcodeEntry->name
396 << " starting at word " << instructionStart.index
397 << ": "
398 << " expected no more operands after " << index
399 << " words, but word count is " << wordCount << ".";
400 return SPV_ERROR_INVALID_BINARY;);
401
402 spv_operand_type_t type = spvTakeFirstMatchableOperand(&expectedOperands);
403
Lei Zhang8a375202015-08-24 15:52:26 -0400404 if (result_id_index != index - 1) no_result_id_strstream << " ";
David Neto78c3b432015-08-27 13:03:52 -0400405 spvCheck(
406 spvBinaryDecodeOperand(
407 opcodeEntry->opcode, type, pInst->words + index, endian, options,
408 operandTable, extInstTable, &expectedOperands, &pInst->extInstType,
409 (result_id_index == index - 1 ? stream : no_result_id_stream),
410 position, pDiagnostic),
411 DIAGNOSTIC << "UNEXPLAINED ERROR";
412 return SPV_ERROR_INVALID_BINARY);
Lei Zhang8a375202015-08-24 15:52:26 -0400413 if (result_id_index == index - 1) stream.get() << " = ";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100414 index += (uint16_t)(position->index - currentPosIndex - 1);
415 }
David Neto78c3b432015-08-27 13:03:52 -0400416 // TODO(dneto): There's an opportunity for a more informative message.
417 spvCheck(!expectedOperands.empty() &&
418 !spvOperandIsOptional(expectedOperands.front()),
419 DIAGNOSTIC << "Invalid instruction Op" << opcodeEntry->name
420 << " starting at word " << instructionStart.index << ": "
421 << " expected more operands after " << wordCount
422 << " words.";
423 return SPV_ERROR_INVALID_BINARY;);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100424
Lei Zhang8a375202015-08-24 15:52:26 -0400425 stream.get() << no_result_id_strstream.str();
426
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100427 return SPV_SUCCESS;
428}
429
430spv_result_t spvBinaryToText(const spv_binary binary, const uint32_t options,
431 const spv_opcode_table opcodeTable,
432 const spv_operand_table operandTable,
433 const spv_ext_inst_table extInstTable,
434 spv_text *pText, spv_diagnostic *pDiagnostic) {
435 spvCheck(!binary->code || !binary->wordCount,
436 return SPV_ERROR_INVALID_BINARY);
437 spvCheck(!opcodeTable || !operandTable || !extInstTable,
438 return SPV_ERROR_INVALID_TABLE);
439 spvCheck(pText && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options),
440 return SPV_ERROR_INVALID_POINTER);
441 spvCheck(!pText && !spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options),
442 return SPV_ERROR_INVALID_POINTER);
443 spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
444
445 spv_endianness_t endian;
446 spv_position_t position = {};
447 spvCheck(spvBinaryEndianness(binary, &endian),
448 DIAGNOSTIC << "Invalid SPIR-V magic number '" << std::hex
449 << binary->code[0] << "'.";
450 return SPV_ERROR_INVALID_BINARY);
451
452 spv_header_t header;
453 spvCheck(spvBinaryHeaderGet(binary, endian, &header),
454 DIAGNOSTIC << "Invalid SPIR-V header.";
455 return SPV_ERROR_INVALID_BINARY);
456
457 bool print = spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
458 bool color =
459 print && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options);
460
461 std::stringstream sstream;
462 out_stream stream(sstream);
463 if (print) {
464 stream = out_stream();
465 }
466
467 if (color) {
468 stream.get() << clr::grey();
469 }
470 stream.get() << "; SPIR-V\n"
471 << "; Version: " << header.version << "\n"
472 << "; Generator: " << spvGeneratorStr(header.generator) << "\n"
473 << "; Bound: " << header.bound << "\n"
474 << "; Schema: " << header.schema << "\n";
475 if (color) {
476 stream.get() << clr::reset();
477 }
478
479 const uint32_t *words = binary->code;
480 position.index = SPV_INDEX_INSTRUCTION;
481 spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
482 while (position.index < binary->wordCount) {
483 uint64_t index = position.index;
484 uint16_t wordCount;
485 Op opcode;
486 spvOpcodeSplit(spvFixWord(words[position.index], endian), &wordCount,
487 &opcode);
488
489 spv_instruction_t inst = {};
490 inst.extInstType = extInstType;
491 spvInstructionCopy(&words[position.index], opcode, wordCount, endian,
492 &inst);
493
494 spvCheck(
495 spvBinaryDecodeOpcode(&inst, endian, options, opcodeTable, operandTable,
496 extInstTable, stream, &position, pDiagnostic),
497 return SPV_ERROR_INVALID_BINARY);
498 extInstType = inst.extInstType;
499
500 spvCheck((index + wordCount) != position.index,
501 DIAGNOSTIC << "Invalid word count.";
502 return SPV_ERROR_INVALID_BINARY);
503
504 stream.get() << "\n";
505 }
506
507 if (!print) {
508 size_t length = sstream.str().size();
509 char *str = new char[length + 1];
510 spvCheck(!str, return SPV_ERROR_OUT_OF_MEMORY);
511 strncpy(str, sstream.str().c_str(), length + 1);
512 spv_text text = new spv_text_t();
513 spvCheck(!text, return SPV_ERROR_OUT_OF_MEMORY);
514 text->str = str;
515 text->length = length;
516 *pText = text;
517 }
518
519 return SPV_SUCCESS;
520}
521
522void spvBinaryDestroy(spv_binary binary) {
523 spvCheck(!binary, return );
524 if (binary->code) {
525 delete[] binary->code;
526 }
527 delete binary;
528}