diff options
Diffstat (limited to '3rdparty/bgfx/3rdparty/spirv-tools/source/binary.cpp')
-rw-r--r-- | 3rdparty/bgfx/3rdparty/spirv-tools/source/binary.cpp | 108 |
1 files changed, 78 insertions, 30 deletions
diff --git a/3rdparty/bgfx/3rdparty/spirv-tools/source/binary.cpp b/3rdparty/bgfx/3rdparty/spirv-tools/source/binary.cpp index 6604d80945d..24d32f8c4a5 100644 --- a/3rdparty/bgfx/3rdparty/spirv-tools/source/binary.cpp +++ b/3rdparty/bgfx/3rdparty/spirv-tools/source/binary.cpp @@ -1,4 +1,6 @@ -// Copyright (c) 2015-2016 The Khronos Group Inc. +// Copyright (c) 2015-2020 The Khronos Group Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights +// reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -31,6 +33,7 @@ #include "source/operand.h" #include "source/spirv_constant.h" #include "source/spirv_endian.h" +#include "source/util/string_utils.h" spv_result_t spvBinaryHeaderGet(const spv_const_binary binary, const spv_endianness_t endian, @@ -43,6 +46,14 @@ spv_result_t spvBinaryHeaderGet(const spv_const_binary binary, // TODO: Validation checking? pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian); pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian); + // Per 2.3.1 version's high and low bytes are 0 + if ((pHeader->version & 0x000000ff) || pHeader->version & 0xff000000) + return SPV_ERROR_INVALID_BINARY; + // Minimum version was 1.0 and max version is defined by SPV_VERSION. + if (pHeader->version < SPV_SPIRV_VERSION_WORD(1, 0) || + pHeader->version > SPV_VERSION) + return SPV_ERROR_INVALID_BINARY; + pHeader->generator = spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian); pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian); @@ -52,6 +63,15 @@ spv_result_t spvBinaryHeaderGet(const spv_const_binary binary, return SPV_SUCCESS; } +std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst, + const uint16_t operand_index) { + assert(operand_index < inst.num_operands); + const spv_parsed_operand_t& operand = inst.operands[operand_index]; + + return spvtools::utils::MakeString(inst.words + operand.offset, + operand.num_words); +} + namespace { // A SPIR-V binary parser. A parser instance communicates detailed parse @@ -123,8 +143,8 @@ class Parser { // returned object will be propagated to the current parse's diagnostic // object. spvtools::DiagnosticStream diagnostic(spv_result_t error) { - return spvtools::DiagnosticStream({0, 0, _.word_index}, consumer_, "", - error); + return spvtools::DiagnosticStream({0, 0, _.instruction_count}, consumer_, + "", error); } // Returns a diagnostic stream object with the default parse error code. @@ -179,6 +199,7 @@ class Parser { num_words(num_words_arg), diagnostic(diagnostic_arg), word_index(0), + instruction_count(0), endian(), requires_endian_conversion(false) { // Temporary storage for parser state within a single instruction. @@ -192,8 +213,9 @@ class Parser { size_t num_words; // Number of words in the module. spv_diagnostic* diagnostic; // Where diagnostics go. size_t word_index; // The current position in words. + size_t instruction_count; // The count of processed instructions spv_endianness_t endian; // The endianness of the binary. - // Is the SPIR-V binary in a different endiannes from the host native + // Is the SPIR-V binary in a different endianness from the host native // endianness? bool requires_endian_conversion; @@ -269,6 +291,8 @@ spv_result_t Parser::parseModule() { } spv_result_t Parser::parseInstruction() { + _.instruction_count++; + // The zero values for all members except for opcode are the // correct initial values. spv_parsed_instruction_t inst = {}; @@ -276,7 +300,7 @@ spv_result_t Parser::parseInstruction() { const uint32_t first_word = peek(); // If the module's endianness is different from the host native endianness, - // then converted_words contains the the endian-translated words in the + // then converted_words contains the endian-translated words in the // instruction. _.endian_converted_words.clear(); _.endian_converted_words.push_back(first_word); @@ -473,14 +497,28 @@ spv_result_t Parser::parseOperand(size_t inst_offset, assert(SpvOpExtInst == opcode); assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE); spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst)) - return diagnostic() << "Invalid extended instruction number: " << word; - spvPushOperandTypes(ext_inst->operandTypes, expected_operands); + if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) == + SPV_SUCCESS) { + // if we know about this ext inst, push the expected operands + spvPushOperandTypes(ext_inst->operandTypes, expected_operands); + } else { + // if we don't know this extended instruction and the set isn't + // non-semantic, we cannot process further + if (!spvExtInstIsNonSemantic(inst->ext_inst_type)) { + return diagnostic() + << "Invalid extended instruction number: " << word; + } else { + // for non-semantic instruction sets, we know the form of all such + // extended instructions contains a series of IDs as parameters + expected_operands->push_back(SPV_OPERAND_TYPE_VARIABLE_ID); + } + } } break; case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: { assert(SpvOpSpecConstantOp == opcode); - if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) { + if (word > static_cast<uint32_t>(SpvOp::SpvOpMax) || + grammar_.lookupSpecConstantOpcode(SpvOp(word))) { return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": " << word; } @@ -549,27 +587,18 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_LITERAL_STRING: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { - convert_operand_endianness = false; - const char* string = - reinterpret_cast<const char*>(_.words + _.word_index); - // Compute the length of the string, but make sure we don't run off the - // end of the input. - const size_t remaining_input_bytes = - sizeof(uint32_t) * (_.num_words - _.word_index); - const size_t string_num_content_bytes = - spv_strnlen_s(string, remaining_input_bytes); - // If there was no terminating null byte, then that's an end-of-input - // error. - if (string_num_content_bytes == remaining_input_bytes) + const size_t max_words = _.num_words - _.word_index; + std::string string = + spvtools::utils::MakeString(_.words + _.word_index, max_words, false); + + if (string.length() == max_words * 4) return exhaustedInputDiagnostic(inst_offset, opcode, type); - // Account for null in the word length, so add 1 for null, then add 3 to - // make sure we round up. The following is equivalent to: - // (string_num_content_bytes + 1 + 3) / 4 - const size_t string_num_words = string_num_content_bytes / 4 + 1; + // Make sure we can record the word count without overflow. // // This error can't currently be triggered because of validity // checks elsewhere. + const size_t string_num_words = string.length() / 4 + 1; if (string_num_words > std::numeric_limits<uint16_t>::max()) { return diagnostic() << "Literal string is longer than " << std::numeric_limits<uint16_t>::max() @@ -583,7 +612,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, // There is only one string literal argument to OpExtInstImport, // so it's sufficient to guard this just on the opcode. const spv_ext_inst_type_t ext_inst_type = - spvExtInstImportTypeGet(string); + spvExtInstImportTypeGet(string.c_str()); if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) { return diagnostic() << "Invalid extended instruction import '" << string << "'"; @@ -616,15 +645,32 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_GROUP_OPERATION: case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: + case SPV_OPERAND_TYPE_RAY_FLAGS: + case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION: + case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE: + case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE: case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: - case SPV_OPERAND_TYPE_DEBUG_OPERATION: { + case SPV_OPERAND_TYPE_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: + case SPV_OPERAND_TYPE_FPDENORM_MODE: + case SPV_OPERAND_TYPE_FPOPERATION_MODE: + case SPV_OPERAND_TYPE_QUANTIZATION_MODES: + case SPV_OPERAND_TYPE_OVERFLOW_MODES: + case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: + case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: { // A single word that is a plain enum value. // Map an optional operand type to its corresponding concrete type. if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER) parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; + if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT) + parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT; spv_operand_desc entry; if (grammar_.lookupOperand(type, word, &entry)) { @@ -643,6 +689,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: { // This operand is a mask. @@ -777,9 +824,10 @@ spv_result_t spvBinaryParse(const spv_const_context context, void* user_data, // TODO(dneto): This probably belongs in text.cpp since that's the only place // that a spv_binary_t value is created. void spvBinaryDestroy(spv_binary binary) { - if (!binary) return; - delete[] binary->code; - delete binary; + if (binary) { + if (binary->code) delete[] binary->code; + delete binary; + } } size_t spv_strnlen_s(const char* str, size_t strsz) { |