binary.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. // Copyright (c) 2015-2020 The Khronos Group Inc.
  2. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
  3. // reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #include "source/binary.h"
  17. #include <algorithm>
  18. #include <cassert>
  19. #include <cstring>
  20. #include <iterator>
  21. #include <limits>
  22. #include <string>
  23. #include <unordered_map>
  24. #include <vector>
  25. #include "source/assembly_grammar.h"
  26. #include "source/diagnostic.h"
  27. #include "source/ext_inst.h"
  28. #include "source/latest_version_spirv_header.h"
  29. #include "source/opcode.h"
  30. #include "source/operand.h"
  31. #include "source/spirv_constant.h"
  32. #include "source/spirv_endian.h"
  33. #include "source/table2.h"
  34. #include "source/util/string_utils.h"
  35. spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
  36. const spv_endianness_t endian,
  37. spv_header_t* pHeader) {
  38. if (!binary->code) return SPV_ERROR_INVALID_BINARY;
  39. if (binary->wordCount < SPV_INDEX_INSTRUCTION)
  40. return SPV_ERROR_INVALID_BINARY;
  41. if (!pHeader) return SPV_ERROR_INVALID_POINTER;
  42. // TODO: Validation checking?
  43. pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
  44. pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
  45. // Per 2.3.1 version's high and low bytes are 0
  46. if ((pHeader->version & 0x000000ff) || pHeader->version & 0xff000000)
  47. return SPV_ERROR_INVALID_BINARY;
  48. // Minimum version was 1.0 and max version is defined by SPV_VERSION.
  49. if (pHeader->version < SPV_SPIRV_VERSION_WORD(1, 0) ||
  50. pHeader->version > SPV_VERSION)
  51. return SPV_ERROR_INVALID_BINARY;
  52. pHeader->generator =
  53. spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
  54. pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
  55. pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
  56. pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
  57. return SPV_SUCCESS;
  58. }
  59. std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
  60. const uint16_t operand_index) {
  61. assert(operand_index < inst.num_operands);
  62. const spv_parsed_operand_t& operand = inst.operands[operand_index];
  63. return spvtools::utils::MakeString(inst.words + operand.offset,
  64. operand.num_words);
  65. }
  66. namespace {
  67. // A SPIR-V binary parser. A parser instance communicates detailed parse
  68. // results via callbacks.
  69. class Parser {
  70. public:
  71. // The user_data value is provided to the callbacks as context.
  72. Parser(const spv_const_context context, void* user_data,
  73. spv_parsed_header_fn_t parsed_header_fn,
  74. spv_parsed_instruction_fn_t parsed_instruction_fn)
  75. : grammar_(context),
  76. consumer_(context->consumer),
  77. user_data_(user_data),
  78. parsed_header_fn_(parsed_header_fn),
  79. parsed_instruction_fn_(parsed_instruction_fn) {}
  80. // Parses the specified binary SPIR-V module, issuing callbacks on a parsed
  81. // header and for each parsed instruction. Returns SPV_SUCCESS on success.
  82. // Otherwise returns an error code and issues a diagnostic.
  83. spv_result_t parse(const uint32_t* words, size_t num_words,
  84. spv_diagnostic* diagnostic);
  85. private:
  86. // All remaining methods work on the current module parse state.
  87. // Like the parse method, but works on the current module parse state.
  88. spv_result_t parseModule();
  89. // Parses an instruction at the current position of the binary. Assumes
  90. // the header has been parsed, the endian has been set, and the word index is
  91. // still in range. Advances the parsing position past the instruction, and
  92. // updates other parsing state for the current module.
  93. // On success, returns SPV_SUCCESS and issues the parsed-instruction callback.
  94. // On failure, returns an error code and issues a diagnostic.
  95. spv_result_t parseInstruction();
  96. // Parses an instruction operand with the given type, for an instruction
  97. // starting at inst_offset words into the SPIR-V binary.
  98. // If the SPIR-V binary is the same endianness as the host, then the
  99. // endian_converted_inst_words parameter is ignored. Otherwise, this method
  100. // appends the words for this operand, converted to host native endianness,
  101. // to the end of endian_converted_inst_words. This method also updates the
  102. // expected_operands parameter, and the scalar members of the inst parameter.
  103. // On success, returns SPV_SUCCESS, advances past the operand, and pushes a
  104. // new entry on to the operands vector. Otherwise returns an error code and
  105. // issues a diagnostic.
  106. spv_result_t parseOperand(size_t inst_offset, spv_parsed_instruction_t* inst,
  107. const spv_operand_type_t type,
  108. std::vector<uint32_t>* endian_converted_inst_words,
  109. std::vector<spv_parsed_operand_t>* operands,
  110. spv_operand_pattern_t* expected_operands);
  111. // Records the numeric type for an operand according to the type information
  112. // associated with the given non-zero type Id. This can fail if the type Id
  113. // is not a type Id, or if the type Id does not reference a scalar numeric
  114. // type. On success, return SPV_SUCCESS and populates the num_words,
  115. // number_kind, and number_bit_width fields of parsed_operand.
  116. spv_result_t setNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand,
  117. uint32_t type_id);
  118. // Records the number type for an instruction at the given offset, if that
  119. // instruction generates a type. For types that aren't scalar numbers,
  120. // record something with number kind SPV_NUMBER_NONE.
  121. void recordNumberType(size_t inst_offset,
  122. const spv_parsed_instruction_t* inst);
  123. // Returns a diagnostic stream object initialized with current position in
  124. // the input stream, and for the given error code. Any data written to the
  125. // returned object will be propagated to the current parse's diagnostic
  126. // object.
  127. spvtools::DiagnosticStream diagnostic(spv_result_t error) {
  128. return spvtools::DiagnosticStream({0, 0, _.instruction_count}, consumer_,
  129. "", error);
  130. }
  131. // Returns a diagnostic stream object with the default parse error code.
  132. spvtools::DiagnosticStream diagnostic() {
  133. // The default failure for parsing is invalid binary.
  134. return diagnostic(SPV_ERROR_INVALID_BINARY);
  135. }
  136. // Issues a diagnostic describing an exhaustion of input condition when
  137. // trying to decode an instruction operand, and returns
  138. // SPV_ERROR_INVALID_BINARY.
  139. spv_result_t exhaustedInputDiagnostic(size_t inst_offset, spv::Op opcode,
  140. spv_operand_type_t type) {
  141. return diagnostic() << "End of input reached while decoding Op"
  142. << spvOpcodeString(opcode) << " starting at word "
  143. << inst_offset
  144. << ((_.word_index < _.num_words) ? ": truncated "
  145. : ": missing ")
  146. << spvOperandTypeStr(type) << " operand at word offset "
  147. << _.word_index - inst_offset << ".";
  148. }
  149. // Returns the endian-corrected word at the current position.
  150. uint32_t peek() const { return peekAt(_.word_index); }
  151. // Returns the endian-corrected word at the given position.
  152. uint32_t peekAt(size_t index) const {
  153. assert(index < _.num_words);
  154. return spvFixWord(_.words[index], _.endian);
  155. }
  156. // Data members
  157. const spvtools::AssemblyGrammar grammar_; // SPIR-V syntax utility.
  158. const spvtools::MessageConsumer& consumer_; // Message consumer callback.
  159. void* const user_data_; // Context for the callbacks
  160. const spv_parsed_header_fn_t parsed_header_fn_; // Parsed header callback
  161. const spv_parsed_instruction_fn_t
  162. parsed_instruction_fn_; // Parsed instruction callback
  163. // Describes the format of a typed literal number.
  164. struct NumberType {
  165. spv_number_kind_t type;
  166. uint32_t bit_width;
  167. spv_fp_encoding_t encoding;
  168. };
  169. // The state used to parse a single SPIR-V binary module.
  170. struct State {
  171. State(const uint32_t* words_arg, size_t num_words_arg,
  172. spv_diagnostic* diagnostic_arg)
  173. : words(words_arg),
  174. num_words(num_words_arg),
  175. diagnostic(diagnostic_arg),
  176. word_index(0),
  177. instruction_count(0),
  178. endian(),
  179. requires_endian_conversion(false) {
  180. // Temporary storage for parser state within a single instruction.
  181. // Most instructions require fewer than 25 words or operands.
  182. operands.reserve(25);
  183. endian_converted_words.reserve(25);
  184. expected_operands.reserve(25);
  185. }
  186. State() : State(0, 0, nullptr) {}
  187. const uint32_t* words; // Words in the binary SPIR-V module.
  188. size_t num_words; // Number of words in the module.
  189. spv_diagnostic* diagnostic; // Where diagnostics go.
  190. size_t word_index; // The current position in words.
  191. size_t instruction_count; // The count of processed instructions
  192. spv_endianness_t endian; // The endianness of the binary.
  193. // Is the SPIR-V binary in a different endianness from the host native
  194. // endianness?
  195. bool requires_endian_conversion;
  196. // Maps a result ID to its type ID. By convention:
  197. // - a result ID that is a type definition maps to itself.
  198. // - a result ID without a type maps to 0. (E.g. for OpLabel)
  199. std::unordered_map<uint32_t, uint32_t> id_to_type_id;
  200. // Maps a type ID to its number type description.
  201. std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info;
  202. // Maps an ExtInstImport id to the extended instruction type.
  203. std::unordered_map<uint32_t, spv_ext_inst_type_t>
  204. import_id_to_ext_inst_type;
  205. // Used by parseOperand
  206. std::vector<spv_parsed_operand_t> operands;
  207. std::vector<uint32_t> endian_converted_words;
  208. spv_operand_pattern_t expected_operands;
  209. } _;
  210. };
  211. spv_result_t Parser::parse(const uint32_t* words, size_t num_words,
  212. spv_diagnostic* diagnostic_arg) {
  213. _ = State(words, num_words, diagnostic_arg);
  214. const spv_result_t result = parseModule();
  215. // Clear the module state. The tables might be big.
  216. _ = State();
  217. return result;
  218. }
  219. spv_result_t Parser::parseModule() {
  220. if (!_.words) return diagnostic() << "Missing module.";
  221. if (_.num_words < SPV_INDEX_INSTRUCTION)
  222. return diagnostic() << "Module has incomplete header: only " << _.num_words
  223. << " words instead of " << SPV_INDEX_INSTRUCTION;
  224. // Check the magic number and detect the module's endianness.
  225. spv_const_binary_t binary{_.words, _.num_words};
  226. if (spvBinaryEndianness(&binary, &_.endian)) {
  227. return diagnostic() << "Invalid SPIR-V magic number '" << std::hex
  228. << _.words[0] << "'.";
  229. }
  230. _.requires_endian_conversion = !spvIsHostEndian(_.endian);
  231. // Process the header.
  232. spv_header_t header;
  233. if (spvBinaryHeaderGet(&binary, _.endian, &header)) {
  234. // It turns out there is no way to trigger this error since the only
  235. // failure cases are already handled above, with better messages.
  236. return diagnostic(SPV_ERROR_INTERNAL)
  237. << "Internal error: unhandled header parse failure";
  238. }
  239. if (parsed_header_fn_) {
  240. if (auto error = parsed_header_fn_(user_data_, _.endian, header.magic,
  241. header.version, header.generator,
  242. header.bound, header.schema)) {
  243. return error;
  244. }
  245. }
  246. // Process the instructions.
  247. _.word_index = SPV_INDEX_INSTRUCTION;
  248. while (_.word_index < _.num_words)
  249. if (auto error = parseInstruction()) return error;
  250. // Running off the end should already have been reported earlier.
  251. assert(_.word_index == _.num_words);
  252. return SPV_SUCCESS;
  253. }
  254. spv_result_t Parser::parseInstruction() {
  255. _.instruction_count++;
  256. // The zero values for all members except for opcode are the
  257. // correct initial values.
  258. spv_parsed_instruction_t inst = {};
  259. const uint32_t first_word = peek();
  260. // If the module's endianness is different from the host native endianness,
  261. // then converted_words contains the endian-translated words in the
  262. // instruction.
  263. _.endian_converted_words.clear();
  264. _.endian_converted_words.push_back(first_word);
  265. // After a successful parse of the instruction, the inst.operands member
  266. // will point to this vector's storage.
  267. _.operands.clear();
  268. assert(_.word_index < _.num_words);
  269. // Decompose and check the first word.
  270. uint16_t inst_word_count = 0;
  271. spvOpcodeSplit(first_word, &inst_word_count, &inst.opcode);
  272. if (inst_word_count < 1) {
  273. return diagnostic() << "Invalid instruction word count: "
  274. << inst_word_count;
  275. }
  276. const spvtools::InstructionDesc* opcode_desc = nullptr;
  277. if (spvtools::LookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc))
  278. return diagnostic() << "Invalid opcode: " << inst.opcode;
  279. // Advance past the opcode word. But remember the of the start
  280. // of the instruction.
  281. const size_t inst_offset = _.word_index;
  282. _.word_index++;
  283. // Maintains the ordered list of expected operand types.
  284. // For many instructions we only need the {numTypes, operandTypes}
  285. // entries in opcode_desc. However, sometimes we need to modify
  286. // the list as we parse the operands. This occurs when an operand
  287. // has its own logical operands (such as the LocalSize operand for
  288. // ExecutionMode), or for extended instructions that may have their
  289. // own operands depending on the selected extended instruction.
  290. _.expected_operands.clear();
  291. spvPushOperandTypes(opcode_desc->operands(), &_.expected_operands);
  292. while (_.word_index < inst_offset + inst_word_count) {
  293. const uint16_t inst_word_index = uint16_t(_.word_index - inst_offset);
  294. if (_.expected_operands.empty()) {
  295. return diagnostic() << "Invalid instruction Op"
  296. << opcode_desc->name().data() << " starting at word "
  297. << inst_offset << ": expected no more operands after "
  298. << inst_word_index
  299. << " words, but stated word count is "
  300. << inst_word_count << ".";
  301. }
  302. spv_operand_type_t type =
  303. spvTakeFirstMatchableOperand(&_.expected_operands);
  304. if (auto error =
  305. parseOperand(inst_offset, &inst, type, &_.endian_converted_words,
  306. &_.operands, &_.expected_operands)) {
  307. return error;
  308. }
  309. }
  310. if (!_.expected_operands.empty() &&
  311. !spvOperandIsOptional(_.expected_operands.back())) {
  312. return diagnostic() << "End of input reached while decoding Op"
  313. << opcode_desc->name().data() << " starting at word "
  314. << inst_offset << ": expected more operands after "
  315. << inst_word_count << " words.";
  316. }
  317. if ((inst_offset + inst_word_count) != _.word_index) {
  318. return diagnostic() << "Invalid word count: Op"
  319. << opcode_desc->name().data() << " starting at word "
  320. << inst_offset << " says it has " << inst_word_count
  321. << " words, but found " << _.word_index - inst_offset
  322. << " words instead.";
  323. }
  324. // Check the computed length of the endian-converted words vector against
  325. // the declared number of words in the instruction. If endian conversion
  326. // is required, then they should match. If no endian conversion was
  327. // performed, then the vector only contains the initial opcode/word-count
  328. // word.
  329. assert(!_.requires_endian_conversion ||
  330. (inst_word_count == _.endian_converted_words.size()));
  331. assert(_.requires_endian_conversion ||
  332. (_.endian_converted_words.size() == 1));
  333. if (_.requires_endian_conversion) {
  334. // We must wait until here to set this pointer, because the vector might
  335. // have been be resized while we accumulated its elements.
  336. inst.words = _.endian_converted_words.data();
  337. } else {
  338. // If no conversion is required, then just point to the underlying binary.
  339. // This saves time and space.
  340. inst.words = _.words + inst_offset;
  341. }
  342. inst.num_words = inst_word_count;
  343. recordNumberType(inst_offset, &inst);
  344. // We must wait until here to set this pointer, because the vector might
  345. // have been be resized while we accumulated its elements.
  346. inst.operands = _.operands.data();
  347. inst.num_operands = uint16_t(_.operands.size());
  348. // Issue the callback. The callee should know that all the storage in inst
  349. // is transient, and will disappear immediately afterward.
  350. if (parsed_instruction_fn_) {
  351. if (auto error = parsed_instruction_fn_(user_data_, &inst)) return error;
  352. }
  353. return SPV_SUCCESS;
  354. }
  355. spv_result_t Parser::parseOperand(size_t inst_offset,
  356. spv_parsed_instruction_t* inst,
  357. const spv_operand_type_t type,
  358. std::vector<uint32_t>* words,
  359. std::vector<spv_parsed_operand_t>* operands,
  360. spv_operand_pattern_t* expected_operands) {
  361. const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
  362. // We'll fill in this result as we go along.
  363. spv_parsed_operand_t parsed_operand;
  364. parsed_operand.offset = uint16_t(_.word_index - inst_offset);
  365. // Most operands occupy one word. This might be be adjusted later.
  366. parsed_operand.num_words = 1;
  367. // The type argument is the one used by the grammar to parse the instruction.
  368. // But it can exposes internal parser details such as whether an operand is
  369. // optional or actually represents a variable-length sequence of operands.
  370. // The resulting type should be adjusted to avoid those internal details.
  371. // In most cases, the resulting operand type is the same as the grammar type.
  372. parsed_operand.type = type;
  373. // Assume non-numeric values. This will be updated for literal numbers.
  374. parsed_operand.number_kind = SPV_NUMBER_NONE;
  375. parsed_operand.number_bit_width = 0;
  376. if (_.word_index >= _.num_words)
  377. return exhaustedInputDiagnostic(inst_offset, opcode, type);
  378. const uint32_t word = peek();
  379. // Do the words in this operand have to be converted to native endianness?
  380. // True for all but literal strings.
  381. bool convert_operand_endianness = true;
  382. switch (type) {
  383. case SPV_OPERAND_TYPE_TYPE_ID:
  384. if (!word)
  385. return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Type Id is 0";
  386. inst->type_id = word;
  387. break;
  388. case SPV_OPERAND_TYPE_RESULT_ID:
  389. if (!word)
  390. return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Result Id is 0";
  391. inst->result_id = word;
  392. // Save the result ID to type ID mapping.
  393. // In the grammar, type ID always appears before result ID.
  394. if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
  395. return diagnostic(SPV_ERROR_INVALID_ID)
  396. << "Id " << inst->result_id << " is defined more than once";
  397. // Record it.
  398. // A regular value maps to its type. Some instructions (e.g. OpLabel)
  399. // have no type Id, and will map to 0. The result Id for a
  400. // type-generating instruction (e.g. OpTypeInt) maps to itself.
  401. _.id_to_type_id[inst->result_id] =
  402. spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id;
  403. break;
  404. case SPV_OPERAND_TYPE_ID:
  405. case SPV_OPERAND_TYPE_OPTIONAL_ID:
  406. if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
  407. parsed_operand.type = SPV_OPERAND_TYPE_ID;
  408. if (spvIsExtendedInstruction(opcode) && parsed_operand.offset == 3) {
  409. // The current word is the extended instruction set Id.
  410. // Set the extended instruction set type for the current instruction.
  411. auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
  412. if (ext_inst_type_iter == _.import_id_to_ext_inst_type.end()) {
  413. return diagnostic(SPV_ERROR_INVALID_ID)
  414. << "OpExtInst set Id " << word
  415. << " does not reference an OpExtInstImport result Id";
  416. }
  417. inst->ext_inst_type = ext_inst_type_iter->second;
  418. }
  419. break;
  420. case SPV_OPERAND_TYPE_SCOPE_ID:
  421. case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
  422. // Check for trivially invalid values. The operand descriptions already
  423. // have the word "ID" in them.
  424. if (!word) return diagnostic() << spvOperandTypeStr(type) << " is 0";
  425. break;
  426. case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
  427. assert(spvIsExtendedInstruction(opcode));
  428. assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
  429. const spvtools::ExtInstDesc* desc = nullptr;
  430. if (spvtools::LookupExtInst(inst->ext_inst_type, word, &desc) ==
  431. SPV_SUCCESS) {
  432. // if we know about this ext inst, push the expected operands
  433. spvPushOperandTypes(desc->operands(), expected_operands);
  434. } else {
  435. // if we don't know this extended instruction and the set isn't
  436. // non-semantic, we cannot process further
  437. if (!spvExtInstIsNonSemantic(inst->ext_inst_type)) {
  438. return diagnostic()
  439. << "Invalid extended instruction number: " << word;
  440. } else {
  441. // for non-semantic instruction sets, we know the form of all such
  442. // extended instructions contains a series of IDs as parameters
  443. expected_operands->push_back(SPV_OPERAND_TYPE_VARIABLE_ID);
  444. }
  445. }
  446. } break;
  447. case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
  448. assert(spv::Op::OpSpecConstantOp == opcode);
  449. if (word > static_cast<uint32_t>(spv::Op::Max) ||
  450. grammar_.lookupSpecConstantOpcode(spv::Op(word))) {
  451. return diagnostic()
  452. << "Invalid " << spvOperandTypeStr(type) << ": " << word;
  453. }
  454. const spvtools::InstructionDesc* opcode_entry = nullptr;
  455. if (spvtools::LookupOpcode(spv::Op(word), &opcode_entry)) {
  456. return diagnostic(SPV_ERROR_INTERNAL)
  457. << "OpSpecConstant opcode table out of sync";
  458. }
  459. // OpSpecConstant opcodes must have a type and result. We've already
  460. // processed them, so skip them when preparing to parse the other
  461. // operants for the opcode.
  462. assert(opcode_entry->hasType);
  463. assert(opcode_entry->hasResult);
  464. assert(opcode_entry->operands().size() >= 2);
  465. spvPushOperandTypes(opcode_entry->operands().subspan(2),
  466. expected_operands);
  467. } break;
  468. case SPV_OPERAND_TYPE_LITERAL_INTEGER:
  469. case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
  470. // These are regular single-word literal integer operands.
  471. // Post-parsing validation should check the range of the parsed value.
  472. parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER;
  473. // It turns out they are always unsigned integers!
  474. parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT;
  475. parsed_operand.number_bit_width = 32;
  476. break;
  477. case SPV_OPERAND_TYPE_LITERAL_FLOAT:
  478. // These are regular single-word literal float operands.
  479. parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT;
  480. parsed_operand.number_kind = SPV_NUMBER_FLOATING;
  481. parsed_operand.number_bit_width = 32;
  482. break;
  483. case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
  484. case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
  485. parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
  486. if (opcode == spv::Op::OpSwitch) {
  487. // The literal operands have the same type as the value
  488. // referenced by the selector Id.
  489. const uint32_t selector_id = peekAt(inst_offset + 1);
  490. const auto type_id_iter = _.id_to_type_id.find(selector_id);
  491. if (type_id_iter == _.id_to_type_id.end() ||
  492. type_id_iter->second == 0) {
  493. return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
  494. << " has no type";
  495. }
  496. uint32_t type_id = type_id_iter->second;
  497. if (selector_id == type_id) {
  498. // Recall that by convention, a result ID that is a type definition
  499. // maps to itself.
  500. return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
  501. << " is a type, not a value";
  502. }
  503. if (auto error = setNumericTypeInfoForType(&parsed_operand, type_id))
  504. return error;
  505. if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT &&
  506. parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) {
  507. return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
  508. << " is not a scalar integer";
  509. }
  510. } else {
  511. assert(opcode == spv::Op::OpConstant ||
  512. opcode == spv::Op::OpSpecConstant);
  513. // The literal number type is determined by the type Id for the
  514. // constant.
  515. assert(inst->type_id);
  516. if (auto error =
  517. setNumericTypeInfoForType(&parsed_operand, inst->type_id))
  518. return error;
  519. }
  520. break;
  521. case SPV_OPERAND_TYPE_LITERAL_STRING:
  522. case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
  523. const size_t max_words = _.num_words - _.word_index;
  524. std::string string =
  525. spvtools::utils::MakeString(_.words + _.word_index, max_words, false);
  526. if (string.length() == max_words * 4)
  527. return exhaustedInputDiagnostic(inst_offset, opcode, type);
  528. // Make sure we can record the word count without overflow.
  529. //
  530. // This error can't currently be triggered because of validity
  531. // checks elsewhere.
  532. const size_t string_num_words = string.length() / 4 + 1;
  533. if (string_num_words > std::numeric_limits<uint16_t>::max()) {
  534. return diagnostic() << "Literal string is longer than "
  535. << std::numeric_limits<uint16_t>::max()
  536. << " words: " << string_num_words << " words long";
  537. }
  538. parsed_operand.num_words = uint16_t(string_num_words);
  539. parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
  540. if (spv::Op::OpExtInstImport == opcode) {
  541. // Record the extended instruction type for the ID for this import.
  542. // There is only one string literal argument to OpExtInstImport,
  543. // so it's sufficient to guard this just on the opcode.
  544. const spv_ext_inst_type_t ext_inst_type =
  545. spvExtInstImportTypeGet(string.c_str());
  546. if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
  547. return diagnostic()
  548. << "Invalid extended instruction import '" << string << "'";
  549. }
  550. // We must have parsed a valid result ID. It's a condition
  551. // of the grammar, and we only accept non-zero result Ids.
  552. assert(inst->result_id);
  553. _.import_id_to_ext_inst_type[inst->result_id] = ext_inst_type;
  554. }
  555. } break;
  556. case SPV_OPERAND_TYPE_CAPABILITY:
  557. case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY:
  558. case SPV_OPERAND_TYPE_EXECUTION_MODEL:
  559. case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
  560. case SPV_OPERAND_TYPE_MEMORY_MODEL:
  561. case SPV_OPERAND_TYPE_EXECUTION_MODE:
  562. case SPV_OPERAND_TYPE_STORAGE_CLASS:
  563. case SPV_OPERAND_TYPE_DIMENSIONALITY:
  564. case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
  565. case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
  566. case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
  567. case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
  568. case SPV_OPERAND_TYPE_LINKAGE_TYPE:
  569. case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
  570. case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
  571. case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
  572. case SPV_OPERAND_TYPE_DECORATION:
  573. case SPV_OPERAND_TYPE_BUILT_IN:
  574. case SPV_OPERAND_TYPE_GROUP_OPERATION:
  575. case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
  576. case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
  577. case SPV_OPERAND_TYPE_RAY_FLAGS:
  578. case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
  579. case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
  580. case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
  581. case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
  582. case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
  583. case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
  584. case SPV_OPERAND_TYPE_DEBUG_OPERATION:
  585. case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
  586. case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
  587. case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
  588. case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
  589. case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
  590. case SPV_OPERAND_TYPE_FPDENORM_MODE:
  591. case SPV_OPERAND_TYPE_FPOPERATION_MODE:
  592. case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
  593. case SPV_OPERAND_TYPE_OVERFLOW_MODES:
  594. case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
  595. case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
  596. case SPV_OPERAND_TYPE_FPENCODING:
  597. case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING:
  598. case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
  599. case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL:
  600. case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
  601. case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: {
  602. // A single word that is a plain enum value.
  603. // Map an optional operand type to its corresponding concrete type.
  604. if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
  605. parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
  606. if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT)
  607. parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT;
  608. if (type == SPV_OPERAND_TYPE_OPTIONAL_FPENCODING)
  609. parsed_operand.type = SPV_OPERAND_TYPE_FPENCODING;
  610. if (type == SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY)
  611. parsed_operand.type = SPV_OPERAND_TYPE_CAPABILITY;
  612. const spvtools::OperandDesc* entry = nullptr;
  613. if (spvtools::LookupOperand(type, word, &entry)) {
  614. return diagnostic()
  615. << "Invalid " << spvOperandTypeStr(parsed_operand.type)
  616. << " operand: " << word;
  617. }
  618. // Prepare to accept operands to this operand, if needed.
  619. spvPushOperandTypes(entry->operands(), expected_operands);
  620. } break;
  621. case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: {
  622. const spvtools::OperandDesc* entry = nullptr;
  623. if (spvtools::LookupOperand(type, word, &entry)) {
  624. return diagnostic()
  625. << "Invalid " << spvOperandTypeStr(parsed_operand.type)
  626. << " operand: " << word
  627. << ", if you are creating a new source language please use "
  628. "value 0 "
  629. "(Unknown) and when ready, add your source language to "
  630. "SPIRV-Headers";
  631. }
  632. // Prepare to accept operands to this operand, if needed.
  633. spvPushOperandTypes(entry->operands(), expected_operands);
  634. } break;
  635. case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
  636. case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
  637. case SPV_OPERAND_TYPE_LOOP_CONTROL:
  638. case SPV_OPERAND_TYPE_IMAGE:
  639. case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
  640. case SPV_OPERAND_TYPE_MEMORY_ACCESS:
  641. case SPV_OPERAND_TYPE_TENSOR_OPERANDS:
  642. case SPV_OPERAND_TYPE_OPTIONAL_TENSOR_OPERANDS:
  643. case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
  644. case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
  645. case SPV_OPERAND_TYPE_SELECTION_CONTROL:
  646. case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
  647. case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
  648. case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
  649. case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
  650. case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
  651. case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS:
  652. case SPV_OPERAND_TYPE_MATRIX_MULTIPLY_ACCUMULATE_OPERANDS:
  653. case SPV_OPERAND_TYPE_OPTIONAL_MATRIX_MULTIPLY_ACCUMULATE_OPERANDS: {
  654. // This operand is a mask.
  655. // Map an optional operand type to its corresponding concrete type.
  656. if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
  657. parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
  658. if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
  659. parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
  660. if (type == SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS)
  661. parsed_operand.type = SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS;
  662. if (type == SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS)
  663. parsed_operand.type = SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS;
  664. if (type == SPV_OPERAND_TYPE_OPTIONAL_MATRIX_MULTIPLY_ACCUMULATE_OPERANDS)
  665. parsed_operand.type =
  666. SPV_OPERAND_TYPE_MATRIX_MULTIPLY_ACCUMULATE_OPERANDS;
  667. if (type == SPV_OPERAND_TYPE_OPTIONAL_TENSOR_OPERANDS)
  668. parsed_operand.type = SPV_OPERAND_TYPE_TENSOR_OPERANDS;
  669. // Check validity of set mask bits. Also prepare for operands for those
  670. // masks if they have any. To get operand order correct, scan from
  671. // MSB to LSB since we can only prepend operands to a pattern.
  672. // The only case in the grammar where you have more than one mask bit
  673. // having an operand is for image operands. See SPIR-V 3.14 Image
  674. // Operands.
  675. uint32_t remaining_word = word;
  676. for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) {
  677. if (remaining_word & mask) {
  678. const spvtools::OperandDesc* entry = nullptr;
  679. if (spvtools::LookupOperand(type, mask, &entry)) {
  680. return diagnostic()
  681. << "Invalid " << spvOperandTypeStr(parsed_operand.type)
  682. << " operand: " << word << " has invalid mask component "
  683. << mask;
  684. }
  685. remaining_word ^= mask;
  686. spvPushOperandTypes(entry->operands(), expected_operands);
  687. }
  688. }
  689. if (word == 0) {
  690. // An all-zeroes mask *might* also be valid.
  691. const spvtools::OperandDesc* entry = nullptr;
  692. if (SPV_SUCCESS == spvtools::LookupOperand(type, 0, &entry)) {
  693. // Prepare for its operands, if any.
  694. spvPushOperandTypes(entry->operands(), expected_operands);
  695. }
  696. }
  697. } break;
  698. default:
  699. return diagnostic() << "Internal error: Unhandled operand type: " << type;
  700. }
  701. assert(spvOperandIsConcrete(parsed_operand.type));
  702. operands->push_back(parsed_operand);
  703. const size_t index_after_operand = _.word_index + parsed_operand.num_words;
  704. // Avoid buffer overrun for the cases where the operand has more than one
  705. // word, and where it isn't a string. (Those other cases have already been
  706. // handled earlier.) For example, this error can occur for a multi-word
  707. // argument to OpConstant, or a multi-word case literal operand for OpSwitch.
  708. if (_.num_words < index_after_operand)
  709. return exhaustedInputDiagnostic(inst_offset, opcode, type);
  710. if (_.requires_endian_conversion) {
  711. // Copy instruction words. Translate to native endianness as needed.
  712. if (convert_operand_endianness) {
  713. const spv_endianness_t endianness = _.endian;
  714. std::transform(_.words + _.word_index, _.words + index_after_operand,
  715. std::back_inserter(*words),
  716. [endianness](const uint32_t raw_word) {
  717. return spvFixWord(raw_word, endianness);
  718. });
  719. } else {
  720. words->insert(words->end(), _.words + _.word_index,
  721. _.words + index_after_operand);
  722. }
  723. }
  724. // Advance past the operand.
  725. _.word_index = index_after_operand;
  726. return SPV_SUCCESS;
  727. }
  728. spv_result_t Parser::setNumericTypeInfoForType(
  729. spv_parsed_operand_t* parsed_operand, uint32_t type_id) {
  730. assert(type_id != 0);
  731. auto type_info_iter = _.type_id_to_number_type_info.find(type_id);
  732. if (type_info_iter == _.type_id_to_number_type_info.end()) {
  733. return diagnostic() << "Type Id " << type_id << " is not a type";
  734. }
  735. const NumberType& info = type_info_iter->second;
  736. if (info.type == SPV_NUMBER_NONE) {
  737. // This is a valid type, but for something other than a scalar number.
  738. return diagnostic() << "Type Id " << type_id
  739. << " is not a scalar numeric type";
  740. }
  741. parsed_operand->number_kind = info.type;
  742. parsed_operand->number_bit_width = info.bit_width;
  743. parsed_operand->fp_encoding = info.encoding;
  744. // Round up the word count.
  745. parsed_operand->num_words = static_cast<uint16_t>((info.bit_width + 31) / 32);
  746. return SPV_SUCCESS;
  747. }
  748. void Parser::recordNumberType(size_t inst_offset,
  749. const spv_parsed_instruction_t* inst) {
  750. const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
  751. if (spvOpcodeGeneratesType(opcode)) {
  752. NumberType info = {SPV_NUMBER_NONE, 0};
  753. if (spv::Op::OpTypeInt == opcode) {
  754. const bool is_signed = peekAt(inst_offset + 3) != 0;
  755. info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
  756. info.bit_width = peekAt(inst_offset + 2);
  757. } else if (spv::Op::OpTypeFloat == opcode) {
  758. info.type = SPV_NUMBER_FLOATING;
  759. info.bit_width = peekAt(inst_offset + 2);
  760. if (inst->num_words >= 4) {
  761. const spvtools::OperandDesc* desc = nullptr;
  762. spv_result_t status = spvtools::LookupOperand(
  763. SPV_OPERAND_TYPE_FPENCODING, peekAt(inst_offset + 3), &desc);
  764. if (status == SPV_SUCCESS) {
  765. info.encoding = spvFPEncodingFromOperandFPEncoding(
  766. static_cast<spv::FPEncoding>(desc->value));
  767. } else {
  768. info.encoding = SPV_FP_ENCODING_UNKNOWN;
  769. }
  770. }
  771. }
  772. // The *result* Id of a type generating instruction is the type Id.
  773. _.type_id_to_number_type_info[inst->result_id] = info;
  774. }
  775. }
  776. } // anonymous namespace
  777. spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
  778. const uint32_t* code, const size_t num_words,
  779. spv_parsed_header_fn_t parsed_header,
  780. spv_parsed_instruction_fn_t parsed_instruction,
  781. spv_diagnostic* diagnostic) {
  782. spv_context_t hijack_context = *context;
  783. if (diagnostic) {
  784. *diagnostic = nullptr;
  785. spvtools::UseDiagnosticAsMessageConsumer(&hijack_context, diagnostic);
  786. }
  787. Parser parser(&hijack_context, user_data, parsed_header, parsed_instruction);
  788. return parser.parse(code, num_words, diagnostic);
  789. }
  790. // TODO(dneto): This probably belongs in text.cpp since that's the only place
  791. // that a spv_binary_t value is created.
  792. void spvBinaryDestroy(spv_binary binary) {
  793. if (binary) {
  794. if (binary->code) delete[] binary->code;
  795. delete binary;
  796. }
  797. }
  798. size_t spv_strnlen_s(const char* str, size_t strsz) {
  799. if (!str) return 0;
  800. for (size_t i = 0; i < strsz; i++) {
  801. if (!str[i]) return i;
  802. }
  803. return strsz;
  804. }