diff --git a/CMakeLists.txt b/CMakeLists.txt index d4cba3817..5cc0df4c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/source/opcode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/operand.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/print.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/table.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/text.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/text_handler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/validate.cpp diff --git a/include/libspirv/libspirv.h b/include/libspirv/libspirv.h index 12b35b1f5..74ea9b0c5 100644 --- a/include/libspirv/libspirv.h +++ b/include/libspirv/libspirv.h @@ -321,6 +321,10 @@ typedef struct spv_diagnostic_t { bool isTextSource; } spv_diagnostic_t; +// Opaque struct containing the context used to operate on a SPIR-V module. +// Its object is used by various tranformation API functions. +struct spv_context_t; + // Type Definitions typedef spv_const_binary_t* spv_const_binary; @@ -328,14 +332,23 @@ typedef spv_binary_t* spv_binary; typedef spv_text_t* spv_text; typedef spv_position_t* spv_position; typedef spv_diagnostic_t* spv_diagnostic; +typedef const spv_context_t* spv_const_context; +typedef spv_context_t* spv_context; // Platform API +// Creates a context object. +spv_context spvContextCreate(); + +// Destroys the given context object. +void spvContextDestroy(spv_context context); + // Encodes the given SPIR-V assembly text to its binary representation. The // length parameter specifies the number of bytes for text. Encoded binary will // be stored into *binary. Any error will be written into *diagnostic. -spv_result_t spvTextToBinary(const char* text, const size_t length, - spv_binary* binary, spv_diagnostic* diagnostic); +spv_result_t spvTextToBinary(const spv_const_context context, const char* text, + const size_t length, spv_binary* binary, + spv_diagnostic* diagnostic); // @brief Frees an allocated text stream. This is a no-op if the text parameter // is a null pointer. @@ -345,7 +358,8 @@ void spvTextDestroy(spv_text text); // word_count parameter specifies the number of words for binary. The options // parameter is a bit field of spv_binary_to_text_options_t. Decoded text will // be stored into *text. Any error will be written into *diagnostic. -spv_result_t spvBinaryToText(const uint32_t* binary, const size_t word_count, +spv_result_t spvBinaryToText(const spv_const_context context, + const uint32_t* binary, const size_t word_count, const uint32_t options, spv_text* text, spv_diagnostic* diagnostic); @@ -355,7 +369,8 @@ void spvBinaryDestroy(spv_binary binary); // Validates a SPIR-V binary for correctness. The options parameter is a bit // field of spv_validation_options_t. -spv_result_t spvValidate(const spv_const_binary binary, const uint32_t options, +spv_result_t spvValidate(const spv_const_context context, + const spv_const_binary binary, const uint32_t options, spv_diagnostic* pDiagnostic); // Creates a diagnostic object. The position parameter specifies the location in @@ -396,8 +411,8 @@ typedef spv_result_t (*spv_parsed_instruction_fn_t)( // returns SPV_ERROR_INVALID_BINARY and emits a diagnostic. If a callback // returns anything other than SPV_SUCCESS, then that error code is returned // and parsing terminates early. -spv_result_t spvBinaryParse(void* user_data, const uint32_t* words, - const size_t num_words, +spv_result_t spvBinaryParse(const spv_const_context context, void* user_data, + const uint32_t* words, const size_t num_words, spv_parsed_header_fn_t parse_header, spv_parsed_instruction_fn_t parse_instruction, spv_diagnostic* diagnostic); diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp index 448d9dcfb..2419bd555 100644 --- a/source/assembly_grammar.cpp +++ b/source/assembly_grammar.cpp @@ -86,30 +86,6 @@ spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable, return SPV_SUCCESS; } -// Returns the operand table. -spv_operand_table GetDefaultOperandTable() { - spv_operand_table result = nullptr; - spvOperandTableGet(&result); - assert(result); - return result; -} - -// Returns the opcode table. -spv_opcode_table GetDefaultOpcodeTable() { - spv_opcode_table result = nullptr; - spvOpcodeTableGet(&result); - assert(result); - return result; -} - -// Returns the extended instruction table. -spv_ext_inst_table GetDefaultExtInstTable() { - spv_ext_inst_table result = nullptr; - spvExtInstTableGet(&result); - assert(result); - return result; -} - // Associates an opcode with its name. struct SpecConstantOpcodeEntry { SpvOp opcode; @@ -197,12 +173,6 @@ const size_t kNumOpSpecConstantOpcodes = namespace libspirv { -AssemblyGrammar::AssemblyGrammar() - : AssemblyGrammar(GetDefaultOperandTable(), GetDefaultOpcodeTable(), - GetDefaultExtInstTable()) { - assert(isValid()); -} - bool AssemblyGrammar::isValid() const { return operandTable_ && opcodeTable_ && extInstTable_; } diff --git a/source/assembly_grammar.h b/source/assembly_grammar.h index 4966ed6f5..4aabfe059 100644 --- a/source/assembly_grammar.h +++ b/source/assembly_grammar.h @@ -37,15 +37,10 @@ namespace libspirv { // Contains methods to query for valid instructions and operands. class AssemblyGrammar { public: - AssemblyGrammar(const spv_operand_table operand_table, - const spv_opcode_table opcode_table, - const spv_ext_inst_table ext_inst_table) - : operandTable_(operand_table), - opcodeTable_(opcode_table), - extInstTable_(ext_inst_table) {} - - // Constructor that gets the required data itself. - AssemblyGrammar(); + AssemblyGrammar(const spv_const_context context) + : operandTable_(context->operand_table), + opcodeTable_(context->opcode_table), + extInstTable_(context->ext_inst_table) {} // Returns true if the internal tables have been initialized with valid data. bool isValid() const; diff --git a/source/binary.cpp b/source/binary.cpp index 062eaddeb..fe052cf83 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -108,9 +108,11 @@ namespace { class Parser { public: // The user_data value is provided to the callbacks as context. - Parser(void* user_data, spv_parsed_header_fn_t parsed_header_fn, + Parser(const spv_const_context context, void* user_data, + spv_parsed_header_fn_t parsed_header_fn, spv_parsed_instruction_fn_t parsed_instruction_fn) - : user_data_(user_data), + : grammar_(context), + user_data_(user_data), parsed_header_fn_(parsed_header_fn), parsed_instruction_fn_(parsed_instruction_fn) {} @@ -672,12 +674,12 @@ void Parser::recordNumberType(const spv_parsed_instruction_t* inst) { } // anonymous namespace -spv_result_t spvBinaryParse(void* user_data, const uint32_t* code, - const size_t num_words, +spv_result_t spvBinaryParse(const spv_const_context context, void* user_data, + const uint32_t* code, const size_t num_words, spv_parsed_header_fn_t parsed_header, spv_parsed_instruction_fn_t parsed_instruction, spv_diagnostic* diagnostic) { - Parser parser(user_data, parsed_header, parsed_instruction); + Parser parser(context, user_data, parsed_header, parsed_instruction); return parser.parse(code, num_words, diagnostic); } diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 181f433df..5fccf43d4 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -370,19 +370,20 @@ spv_result_t DisassembleInstruction( } // anonymous namespace -spv_result_t spvBinaryToText(const uint32_t* code, const size_t wordCount, +spv_result_t spvBinaryToText(const spv_const_context context, + const uint32_t* code, const size_t wordCount, const uint32_t options, spv_text* pText, spv_diagnostic* pDiagnostic) { // Invalid arguments return error codes, but don't necessarily generate // diagnostics. These are programmer errors, not user errors. if (!pDiagnostic) return SPV_ERROR_INVALID_DIAGNOSTIC; - const libspirv::AssemblyGrammar grammar; + const libspirv::AssemblyGrammar grammar(context); if (!grammar.isValid()) return SPV_ERROR_INVALID_TABLE; Disassembler disassembler(grammar, code, wordCount, options); - if (auto error = - spvBinaryParse(&disassembler, code, wordCount, DisassembleHeader, - DisassembleInstruction, pDiagnostic)) { + if (auto error = spvBinaryParse(context, &disassembler, code, wordCount, + DisassembleHeader, DisassembleInstruction, + pDiagnostic)) { return error; } diff --git a/source/opcode.cpp b/source/opcode.cpp index c78997c79..c2cab6df7 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include "endian.h" #include "instruction.h" #include "libspirv/libspirv.h" @@ -46,7 +48,7 @@ namespace { // // TODO(dneto): Some of the macros are quite unreadable. We could make // good use of constexpr functions, but some compilers don't support that yet. -spv_opcode_desc_t opcodeTableEntries[] = { +const spv_opcode_desc_t opcodeTableEntries[] = { #define EmptyList \ {} #define List(...) \ @@ -71,10 +73,6 @@ spv_opcode_desc_t opcodeTableEntries[] = { #undef Instruction }; -// Has the opcodeTableEntries table been fully elaborated? -// That is, are the operandTypes fields initialized? -bool opcodeTableInitialized = false; - // Opcode API // Converts the given operand class enum (from the SPIR-V document generation @@ -244,9 +242,11 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode, } // anonymous namespace // Finish populating the opcodeTableEntries array. -void spvOpcodeTableInitialize() { +void spvOpcodeTableInitialize(spv_opcode_desc_t* entries, + uint32_t num_entries) { // Compute the operandTypes field for each entry. - for (auto& opcode : opcodeTableEntries) { + for (uint32_t i = 0; i < num_entries; ++i) { + spv_opcode_desc_t& opcode = entries[i]; opcode.numTypes = 0; // Type ID always comes first, if present. if (opcode.hasType) @@ -282,7 +282,6 @@ void spvOpcodeTableInitialize() { "Operand class list is too long. Expand " "spv_opcode_desc_t.operandClass"); } - opcodeTableInitialized = true; } const char* spvGeneratorStr(uint32_t generator) { @@ -320,15 +319,18 @@ void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount, SpvOp* pOpcode) { spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable) { if (!pInstTable) return SPV_ERROR_INVALID_POINTER; - static spv_opcode_table_t table = { - sizeof(opcodeTableEntries) / sizeof(spv_opcode_desc_t), - opcodeTableEntries}; + const uint32_t size = sizeof(opcodeTableEntries); + spv_opcode_desc_t* copied_entries = + static_cast(::malloc(size)); + if (!copied_entries) return SPV_ERROR_OUT_OF_MEMORY; + ::memcpy(copied_entries, opcodeTableEntries, size); - // TODO(dneto): Consider thread safety of initialization. - // That is, ordering effects of the flag vs. the table updates. - if (!opcodeTableInitialized) spvOpcodeTableInitialize(); + const uint32_t count = sizeof(opcodeTableEntries) / sizeof(spv_opcode_desc_t); + spv_opcode_table_t* table = new spv_opcode_table_t{count, copied_entries}; - *pInstTable = &table; + spvOpcodeTableInitialize(copied_entries, count); + + *pInstTable = table; return SPV_SUCCESS; } diff --git a/source/table.cpp b/source/table.cpp new file mode 100644 index 000000000..b05617649 --- /dev/null +++ b/source/table.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2015 The Khronos Group Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and/or associated documentation files (the +// "Materials"), to deal in the Materials without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Materials, and to +// permit persons to whom the Materials are furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Materials. +// +// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT +// https://www.khronos.org/registry/ +// +// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + +#include "table.h" + +#include + +spv_context spvContextCreate() { + spv_opcode_table opcode_table; + spv_operand_table operand_table; + spv_ext_inst_table ext_inst_table; + + spvOpcodeTableGet(&opcode_table); + spvOperandTableGet(&operand_table); + spvExtInstTableGet(&ext_inst_table); + + return new spv_context_t{opcode_table, operand_table, ext_inst_table}; +} + +void spvContextDestroy(spv_context context) { + ::free(context->opcode_table->entries); + delete context->opcode_table; + delete context; +} diff --git a/source/table.h b/source/table.h index d87f17c30..e6559afe1 100644 --- a/source/table.h +++ b/source/table.h @@ -76,7 +76,7 @@ typedef struct spv_ext_inst_group_t { typedef struct spv_opcode_table_t { const uint32_t count; - const spv_opcode_desc_t* entries; + spv_opcode_desc_t* entries; } spv_opcode_table_t; typedef struct spv_operand_table_t { @@ -97,6 +97,12 @@ typedef const spv_opcode_table_t* spv_opcode_table; typedef const spv_operand_table_t* spv_operand_table; typedef const spv_ext_inst_table_t* spv_ext_inst_table; +struct spv_context_t { + const spv_opcode_table opcode_table; + const spv_operand_table operand_table; + const spv_ext_inst_table ext_inst_table; +}; + /// @brief Populate the Opcode table /// /// @param[out] pOpcodeTable table to be populated diff --git a/source/text.cpp b/source/text.cpp index aa870c7d5..bc8fd9678 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -735,11 +735,12 @@ spv_result_t spvTextToBinaryInternal(const libspirv::AssemblyGrammar& grammar, } // anonymous namespace -spv_result_t spvTextToBinary(const char* input_text, +spv_result_t spvTextToBinary(const spv_const_context context, + const char* input_text, const size_t input_text_size, spv_binary* pBinary, spv_diagnostic* pDiagnostic) { spv_text_t text = {input_text, input_text_size}; - libspirv::AssemblyGrammar grammar; + libspirv::AssemblyGrammar grammar(context); spv_result_t result = spvTextToBinaryInternal(grammar, &text, pBinary, pDiagnostic); diff --git a/source/validate.cpp b/source/validate.cpp index 65ee86f79..e7b52d562 100644 --- a/source/validate.cpp +++ b/source/validate.cpp @@ -261,20 +261,10 @@ spv_result_t spvValidateIDs(const spv_instruction_t* pInsts, return SPV_SUCCESS; } -spv_result_t spvValidate(const spv_const_binary binary, const uint32_t options, +spv_result_t spvValidate(const spv_const_context context, + const spv_const_binary binary, const uint32_t options, spv_diagnostic* pDiagnostic) { if (!pDiagnostic) return SPV_ERROR_INVALID_DIAGNOSTIC; - spv_opcode_table opcode_table = nullptr; - spvOpcodeTableGet(&opcode_table); - assert(opcode_table); - - spv_operand_table operand_table = nullptr; - spvOperandTableGet(&operand_table); - assert(operand_table); - - spv_ext_inst_table ext_inst_table = nullptr; - spvExtInstTableGet(&ext_inst_table); - assert(ext_inst_table); spv_endianness_t endian; spv_position_t position = {}; @@ -306,9 +296,9 @@ spv_result_t spvValidate(const spv_const_binary binary, const uint32_t options, if (spvIsInBitfield(SPV_VALIDATE_BASIC_BIT, options)) { position.index = SPV_INDEX_INSTRUCTION; // TODO: Imcomplete implementation - spvCheckReturn(spvValidateBasic(instructions.data(), instructions.size(), - opcode_table, operand_table, &position, - pDiagnostic)); + spvCheckReturn(spvValidateBasic( + instructions.data(), instructions.size(), context->opcode_table, + context->operand_table, &position, pDiagnostic)); } if (spvIsInBitfield(SPV_VALIDATE_LAYOUT_BIT, options)) { @@ -318,9 +308,10 @@ spv_result_t spvValidate(const spv_const_binary binary, const uint32_t options, if (spvIsInBitfield(SPV_VALIDATE_ID_BIT, options)) { position.index = SPV_INDEX_INSTRUCTION; - spvCheckReturn(spvValidateIDs(instructions.data(), instructions.size(), - header.bound, opcode_table, operand_table, - ext_inst_table, &position, pDiagnostic)); + spvCheckReturn( + spvValidateIDs(instructions.data(), instructions.size(), header.bound, + context->opcode_table, context->operand_table, + context->ext_inst_table, &position, pDiagnostic)); } if (spvIsInBitfield(SPV_VALIDATE_RULES_BIT, options)) { diff --git a/test/AssemblyFormat.cpp b/test/AssemblyFormat.cpp index 3d9957cce..aa5bda888 100644 --- a/test/AssemblyFormat.cpp +++ b/test/AssemblyFormat.cpp @@ -32,8 +32,9 @@ using spvtest::TextToBinaryTest; TEST_F(TextToBinaryTest, NotPlacingResultIDAtTheBeginning) { SetText("OpTypeMatrix %1 %2 1000"); - EXPECT_EQ(SPV_ERROR_INVALID_TEXT, - spvTextToBinary(text.str, text.length, &binary, &diagnostic)); + EXPECT_EQ( + SPV_ERROR_INVALID_TEXT, + spvTextToBinary(context, text.str, text.length, &binary, &diagnostic)); ASSERT_NE(nullptr, diagnostic); EXPECT_STREQ( "Expected at the beginning of an instruction, found " diff --git a/test/BinaryDestroy.cpp b/test/BinaryDestroy.cpp index 29f6e319f..5ff2aff29 100644 --- a/test/BinaryDestroy.cpp +++ b/test/BinaryDestroy.cpp @@ -40,13 +40,15 @@ using BinaryDestroySomething = spvtest::TextToBinaryTest; // Checks safety of destroying a validly constructed binary. TEST_F(BinaryDestroySomething, Default) { + spv_context context = spvContextCreate(); // Use a binary object constructed by the API instead of rolling our own. SetText("OpSource OpenCL_C 120"); spv_binary my_binary = nullptr; - ASSERT_EQ(SPV_SUCCESS, - spvTextToBinary(text.str, text.length, &my_binary, &diagnostic)); + ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.str, text.length, + &my_binary, &diagnostic)); ASSERT_NE(nullptr, my_binary); spvBinaryDestroy(my_binary); + spvContextDestroy(context); } } // anonymous namespace diff --git a/test/BinaryToText.cpp b/test/BinaryToText.cpp index c4b9d3afb..5ca8737e1 100644 --- a/test/BinaryToText.cpp +++ b/test/BinaryToText.cpp @@ -40,6 +40,9 @@ using spvtest::TextToBinaryTest; namespace { class BinaryToText : public ::testing::Test { public: + BinaryToText() : context(spvContextCreate()) {} + ~BinaryToText() { spvContextDestroy(context); } + virtual void SetUp() { const char* textStr = R"( OpSource OpenCL_C 12 @@ -65,7 +68,7 @@ class BinaryToText : public ::testing::Test { spv_text_t text = {textStr, strlen(textStr)}; spv_diagnostic diagnostic = nullptr; spv_result_t error = - spvTextToBinary(text.str, text.length, &binary, &diagnostic); + spvTextToBinary(context, text.str, text.length, &binary, &diagnostic); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); @@ -78,19 +81,21 @@ class BinaryToText : public ::testing::Test { // Compiles the given assembly text, and saves it into 'binary'. void CompileSuccessfully(std::string text) { spv_diagnostic diagnostic = nullptr; - EXPECT_EQ(SPV_SUCCESS, - spvTextToBinary(text.c_str(), text.size(), &binary, &diagnostic)); + EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(), + &binary, &diagnostic)); } + spv_context context; spv_binary binary; }; TEST_F(BinaryToText, Default) { spv_text text = nullptr; spv_diagnostic diagnostic = nullptr; - ASSERT_EQ(SPV_SUCCESS, spvBinaryToText(binary->code, binary->wordCount, - SPV_BINARY_TO_TEXT_OPTION_NONE, &text, - &diagnostic)); + ASSERT_EQ( + SPV_SUCCESS, + spvBinaryToText(context, binary->code, binary->wordCount, + SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic)); printf("%s", text->str); spvTextDestroy(text); } @@ -98,9 +103,10 @@ TEST_F(BinaryToText, Default) { TEST_F(BinaryToText, MissingModule) { spv_text text; spv_diagnostic diagnostic = nullptr; - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - spvBinaryToText(nullptr, 42, SPV_BINARY_TO_TEXT_OPTION_NONE, &text, - &diagnostic)); + EXPECT_EQ( + SPV_ERROR_INVALID_BINARY, + spvBinaryToText(context, nullptr, 42, SPV_BINARY_TO_TEXT_OPTION_NONE, + &text, &diagnostic)); EXPECT_THAT(diagnostic->error, Eq(std::string("Missing module."))); if (diagnostic) { spvDiagnosticPrint(diagnostic); @@ -118,8 +124,8 @@ TEST_F(BinaryToText, TruncatedModule) { spv_diagnostic diagnostic = nullptr; EXPECT_EQ( SPV_ERROR_INVALID_BINARY, - spvBinaryToText(binary->code, length, SPV_BINARY_TO_TEXT_OPTION_NONE, - &text, &diagnostic)); + spvBinaryToText(context, binary->code, length, + SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic)); ASSERT_NE(nullptr, diagnostic); std::stringstream expected; expected << "Module has incomplete header: only " << length @@ -139,7 +145,7 @@ TEST_F(BinaryToText, InvalidMagicNumber) { spv_text text; EXPECT_EQ( SPV_ERROR_INVALID_BINARY, - spvBinaryToText(damaged_binary.data(), damaged_binary.size(), + spvBinaryToText(context, damaged_binary.data(), damaged_binary.size(), SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic)); ASSERT_NE(nullptr, diagnostic); std::stringstream expected; @@ -152,7 +158,7 @@ TEST_F(BinaryToText, InvalidMagicNumber) { TEST_F(BinaryToText, InvalidDiagnostic) { spv_text text; ASSERT_EQ(SPV_ERROR_INVALID_DIAGNOSTIC, - spvBinaryToText(binary->code, binary->wordCount, + spvBinaryToText(context, binary->code, binary->wordCount, SPV_BINARY_TO_TEXT_OPTION_NONE, &text, nullptr)); } diff --git a/test/ExtInstGLSLstd450.cpp b/test/ExtInstGLSLstd450.cpp index 649f56d32..4a7cb52b1 100644 --- a/test/ExtInstGLSLstd450.cpp +++ b/test/ExtInstGLSLstd450.cpp @@ -49,6 +49,7 @@ struct ExtInstContext { using ExtInstGLSLstd450RoundTripTest = ::testing::TestWithParam; TEST_P(ExtInstGLSLstd450RoundTripTest, ParameterizedExtInst) { + spv_context context = spvContextCreate(); const std::string spirv = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -71,8 +72,8 @@ OpFunctionEnd ; Schema: 0)"; spv_binary binary; spv_diagnostic diagnostic; - spv_result_t error = - spvTextToBinary(spirv.c_str(), spirv.size(), &binary, &diagnostic); + spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(), + &binary, &diagnostic); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); @@ -98,7 +99,7 @@ OpFunctionEnd // Check round trip gives the same text. spv_text output_text = nullptr; - error = spvBinaryToText(binary->code, binary->wordCount, + error = spvBinaryToText(context, binary->code, binary->wordCount, SPV_BINARY_TO_TEXT_OPTION_NONE, &output_text, &diagnostic); @@ -109,6 +110,7 @@ OpFunctionEnd } EXPECT_EQ(spirv_header + spirv, output_text->str); spvTextDestroy(output_text); + spvContextDestroy(context); } static const char* kF32Type = R"(%4 = OpTypeFloat 32)"; diff --git a/test/ImmediateInt.cpp b/test/ImmediateInt.cpp index 56c0b7d81..e78ddfe4d 100644 --- a/test/ImmediateInt.cpp +++ b/test/ImmediateInt.cpp @@ -46,8 +46,8 @@ using ::testing::StrEq; TEST_F(TextToBinaryTest, ImmediateIntOpCode) { SetText("!0x00FF00FF"); - ASSERT_EQ(SPV_SUCCESS, - spvTextToBinary(text.str, text.length, &binary, &diagnostic)); + ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.str, text.length, + &binary, &diagnostic)); EXPECT_EQ(0x00FF00FF, binary->code[5]); if (diagnostic) { spvDiagnosticPrint(diagnostic); @@ -56,8 +56,8 @@ TEST_F(TextToBinaryTest, ImmediateIntOpCode) { TEST_F(TextToBinaryTest, ImmediateIntOperand) { SetText("OpCapability !0x00FF00FF"); - EXPECT_EQ(SPV_SUCCESS, - spvTextToBinary(text.str, text.length, &binary, &diagnostic)); + EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.str, text.length, + &binary, &diagnostic)); EXPECT_EQ(0x00FF00FF, binary->code[6]); if (diagnostic) { spvDiagnosticPrint(diagnostic); diff --git a/test/NamedId.cpp b/test/NamedId.cpp index 7b4a318e0..4fe9c8d78 100644 --- a/test/NamedId.cpp +++ b/test/NamedId.cpp @@ -32,6 +32,7 @@ namespace { TEST(NamedId, Default) { + spv_context context = spvContextCreate(); const char* spirv = R"( OpCapability Shader OpMemoryModel Logical Simple @@ -48,7 +49,7 @@ TEST(NamedId, Default) { spv_binary binary = nullptr; spv_diagnostic diagnostic; spv_result_t error = - spvTextToBinary(text.str, text.length, &binary, &diagnostic); + spvTextToBinary(context, text.str, text.length, &binary, &diagnostic); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); @@ -56,7 +57,7 @@ TEST(NamedId, Default) { ASSERT_EQ(SPV_SUCCESS, error); } error = spvBinaryToText( - binary->code, binary->wordCount, + context, binary->code, binary->wordCount, SPV_BINARY_TO_TEXT_OPTION_PRINT | SPV_BINARY_TO_TEXT_OPTION_COLOR, nullptr, &diagnostic); if (error) { @@ -66,6 +67,7 @@ TEST(NamedId, Default) { ASSERT_EQ(SPV_SUCCESS, error); } spvBinaryDestroy(binary); + spvContextDestroy(context); } struct IdCheckCase { diff --git a/test/TestFixture.h b/test/TestFixture.h index 6fabd434c..3aef86d51 100644 --- a/test/TestFixture.h +++ b/test/TestFixture.h @@ -42,7 +42,11 @@ class TextToBinaryTestBase : public T { // Offset into a SpirvVector at which the first instruction starts. const SpirvVector::size_type kFirstInstruction = 5; - TextToBinaryTestBase() : diagnostic(nullptr), text(), binary(nullptr) { + TextToBinaryTestBase() + : context(spvContextCreate()), + diagnostic(nullptr), + text(), + binary(nullptr) { char textStr[] = "substitute the text member variable with your test"; text = {textStr, strlen(textStr)}; } @@ -50,6 +54,7 @@ class TextToBinaryTestBase : public T { virtual ~TextToBinaryTestBase() { DestroyBinary(); if (diagnostic) spvDiagnosticDestroy(diagnostic); + spvContextDestroy(context); } // Returns subvector v[from:end). @@ -61,8 +66,8 @@ class TextToBinaryTestBase : public T { // Compiles SPIR-V text in the given assembly syntax format, asserting // compilation success. Returns the compiled code. SpirvVector CompileSuccessfully(const std::string& text) { - spv_result_t status = - spvTextToBinary(text.c_str(), text.size(), &binary, &diagnostic); + spv_result_t status = spvTextToBinary(context, text.c_str(), text.size(), + &binary, &diagnostic); EXPECT_EQ(SPV_SUCCESS, status) << text; SpirvVector code_copy; if (status == SPV_SUCCESS) { @@ -77,8 +82,8 @@ class TextToBinaryTestBase : public T { // Compiles SPIR-V text with the given format, asserting compilation failure. // Returns the error message(s). std::string CompileFailure(const std::string& text) { - EXPECT_NE(SPV_SUCCESS, - spvTextToBinary(text.c_str(), text.size(), &binary, &diagnostic)) + EXPECT_NE(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(), + &binary, &diagnostic)) << text; DestroyBinary(); return diagnostic->error; @@ -95,8 +100,8 @@ class TextToBinaryTestBase : public T { std::string EncodeAndDecodeSuccessfully(const std::string& text, uint32_t disassemble_options) { DestroyBinary(); - spv_result_t error = - spvTextToBinary(text.c_str(), text.size(), &binary, &diagnostic); + spv_result_t error = spvTextToBinary(context, text.c_str(), text.size(), + &binary, &diagnostic); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); @@ -105,7 +110,7 @@ class TextToBinaryTestBase : public T { if (!binary) return ""; spv_text decoded_text; - error = spvBinaryToText(binary->code, binary->wordCount, + error = spvBinaryToText(context, binary->code, binary->wordCount, disassemble_options, &decoded_text, &diagnostic); if (error) { spvDiagnosticPrint(diagnostic); @@ -132,7 +137,7 @@ class TextToBinaryTestBase : public T { spvtest::Concatenate({CompileSuccessfully(text), words_to_append}); spv_text decoded_text; - EXPECT_NE(SPV_SUCCESS, spvBinaryToText(code.data(), code.size(), + EXPECT_NE(SPV_SUCCESS, spvBinaryToText(context, code.data(), code.size(), SPV_BINARY_TO_TEXT_OPTION_NONE, &decoded_text, &diagnostic)); if (diagnostic) { @@ -169,6 +174,7 @@ class TextToBinaryTestBase : public T { binary = nullptr; } + spv_context context; spv_diagnostic diagnostic; std::string textString; diff --git a/test/TextDestroy.cpp b/test/TextDestroy.cpp index 86e56e6d5..a55d5726d 100644 --- a/test/TextDestroy.cpp +++ b/test/TextDestroy.cpp @@ -31,6 +31,7 @@ namespace { TEST(TextDestroy, DestroyNull) { spvBinaryDestroy(nullptr); } TEST(TextDestroy, Default) { + spv_context context = spvContextCreate(); char textStr[] = R"( OpSource OpenCL_C 12 OpMemoryModel Physical64 OpenCL @@ -55,8 +56,8 @@ TEST(TextDestroy, Default) { spv_binary binary = nullptr; spv_diagnostic diagnostic = nullptr; - EXPECT_EQ(SPV_SUCCESS, - spvTextToBinary(textStr, strlen(textStr), &binary, &diagnostic)); + EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, textStr, strlen(textStr), + &binary, &diagnostic)); EXPECT_NE(nullptr, binary); EXPECT_NE(nullptr, binary->code); EXPECT_NE(0, binary->wordCount); @@ -66,8 +67,9 @@ TEST(TextDestroy, Default) { } spv_text resultText = nullptr; - EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(binary->code, binary->wordCount, 0, - &resultText, &diagnostic)); + EXPECT_EQ(SPV_SUCCESS, + spvBinaryToText(context, binary->code, binary->wordCount, 0, + &resultText, &diagnostic)); spvBinaryDestroy(binary); if (diagnostic) { spvDiagnosticPrint(diagnostic); @@ -77,6 +79,7 @@ TEST(TextDestroy, Default) { EXPECT_NE(nullptr, resultText->str); EXPECT_NE(0, resultText->length); spvTextDestroy(resultText); + spvContextDestroy(context); } } // anonymous namespace diff --git a/test/TextToBinary.cpp b/test/TextToBinary.cpp index e854bb550..a5f54939e 100644 --- a/test/TextToBinary.cpp +++ b/test/TextToBinary.cpp @@ -71,14 +71,15 @@ struct MaskCase { using GoodMaskParseTest = ::testing::TestWithParam; TEST_P(GoodMaskParseTest, GoodMaskExpressions) { - spv_operand_table operandTable; - ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable)); + spv_context context = spvContextCreate(); uint32_t value; - EXPECT_EQ(SPV_SUCCESS, AssemblyGrammar(operandTable, nullptr, nullptr) - .parseMaskOperand(GetParam().which_enum, - GetParam().expression, &value)); + EXPECT_EQ(SPV_SUCCESS, + AssemblyGrammar(context).parseMaskOperand( + GetParam().which_enum, GetParam().expression, &value)); EXPECT_EQ(GetParam().expected_value, value); + + spvContextDestroy(context); } INSTANTIATE_TEST_CASE_P( @@ -115,14 +116,14 @@ INSTANTIATE_TEST_CASE_P( using BadFPFastMathMaskParseTest = ::testing::TestWithParam; TEST_P(BadFPFastMathMaskParseTest, BadMaskExpressions) { - spv_operand_table operandTable; - ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable)); + spv_context context = spvContextCreate(); uint32_t value; EXPECT_NE(SPV_SUCCESS, - AssemblyGrammar(operandTable, nullptr, nullptr) - .parseMaskOperand(SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, - GetParam(), &value)); + AssemblyGrammar(context).parseMaskOperand( + SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, GetParam(), &value)); + + spvContextDestroy(context); } INSTANTIATE_TEST_CASE_P(ParseMask, BadFPFastMathMaskParseTest, @@ -141,7 +142,7 @@ union char_word_t { TEST_F(TextToBinaryTest, InvalidText) { spv_binary binary; ASSERT_EQ(SPV_ERROR_INVALID_TEXT, - spvTextToBinary(nullptr, 0, &binary, &diagnostic)); + spvTextToBinary(context, nullptr, 0, &binary, &diagnostic)); EXPECT_NE(nullptr, diagnostic); EXPECT_THAT(diagnostic->error, Eq(std::string("Missing assembly text."))); } @@ -149,8 +150,9 @@ TEST_F(TextToBinaryTest, InvalidText) { TEST_F(TextToBinaryTest, InvalidPointer) { SetText( "OpEntryPoint Kernel 0 \"\"\nOpExecutionMode 0 LocalSizeHint 1 1 1\n"); - ASSERT_EQ(SPV_ERROR_INVALID_POINTER, - spvTextToBinary(text.str, text.length, nullptr, &diagnostic)); + ASSERT_EQ( + SPV_ERROR_INVALID_POINTER, + spvTextToBinary(context, text.str, text.length, nullptr, &diagnostic)); } TEST_F(TextToBinaryTest, InvalidDiagnostic) { @@ -158,7 +160,7 @@ TEST_F(TextToBinaryTest, InvalidDiagnostic) { "OpEntryPoint Kernel 0 \"\"\nOpExecutionMode 0 LocalSizeHint 1 1 1\n"); spv_binary binary; ASSERT_EQ(SPV_ERROR_INVALID_DIAGNOSTIC, - spvTextToBinary(text.str, text.length, &binary, nullptr)); + spvTextToBinary(context, text.str, text.length, &binary, nullptr)); } TEST_F(TextToBinaryTest, InvalidPrefix) { diff --git a/test/Validate.cpp b/test/Validate.cpp index 8222a2000..2733ace95 100644 --- a/test/Validate.cpp +++ b/test/Validate.cpp @@ -30,11 +30,13 @@ namespace { class Validate : public ::testing::Test { public: - Validate() : binary() {} + Validate() : context(spvContextCreate()), binary() {} + ~Validate() { spvContextDestroy(context); } virtual void TearDown() { spvBinaryDestroy(binary); } spv_const_binary get_const_binary() { return spv_const_binary(binary); } + spv_context context; spv_binary binary; }; @@ -52,9 +54,9 @@ OpFunctionEnd )"; spv_diagnostic diagnostic = nullptr; ASSERT_EQ(SPV_SUCCESS, - spvTextToBinary(str, strlen(str), &binary, &diagnostic)); - ASSERT_EQ(SPV_SUCCESS, - spvValidate(get_const_binary(), SPV_VALIDATE_ALL, &diagnostic)); + spvTextToBinary(context, str, strlen(str), &binary, &diagnostic)); + ASSERT_EQ(SPV_SUCCESS, spvValidate(context, get_const_binary(), + SPV_VALIDATE_ALL, &diagnostic)); if (diagnostic) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); @@ -75,9 +77,9 @@ OpFunctionEnd )"; spv_diagnostic diagnostic = nullptr; ASSERT_EQ(SPV_SUCCESS, - spvTextToBinary(str, strlen(str), &binary, &diagnostic)); - ASSERT_EQ(SPV_ERROR_INVALID_ID, - spvValidate(get_const_binary(), SPV_VALIDATE_ALL, &diagnostic)); + spvTextToBinary(context, str, strlen(str), &binary, &diagnostic)); + ASSERT_EQ(SPV_ERROR_INVALID_ID, spvValidate(context, get_const_binary(), + SPV_VALIDATE_ALL, &diagnostic)); ASSERT_NE(nullptr, diagnostic); spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); @@ -97,10 +99,10 @@ OpFunctionEnd )"; spv_diagnostic diagnostic = nullptr; ASSERT_EQ(SPV_SUCCESS, - spvTextToBinary(str, strlen(str), &binary, &diagnostic)); + spvTextToBinary(context, str, strlen(str), &binary, &diagnostic)); // TODO: Fix setting of bound in spvTextTo, then remove this! - ASSERT_EQ(SPV_ERROR_INVALID_ID, - spvValidate(get_const_binary(), SPV_VALIDATE_ALL, &diagnostic)); + ASSERT_EQ(SPV_ERROR_INVALID_ID, spvValidate(context, get_const_binary(), + SPV_VALIDATE_ALL, &diagnostic)); ASSERT_NE(nullptr, diagnostic); spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); diff --git a/test/ValidateID.cpp b/test/ValidateID.cpp index ca5c53a5c..956eb047f 100644 --- a/test/ValidateID.cpp +++ b/test/ValidateID.cpp @@ -41,22 +41,24 @@ class ValidateID : public ::testing::Test { spv_binary binary; }; -#define CHECK(str, expected) \ - spv_diagnostic diagnostic; \ - spv_result_t error = \ - spvTextToBinary(str, strlen(str), &binary, &diagnostic); \ - if (error) { \ - spvDiagnosticPrint(diagnostic); \ - spvDiagnosticDestroy(diagnostic); \ - ASSERT_EQ(SPV_SUCCESS, error); \ - } \ - spv_result_t result = \ - spvValidate(get_const_binary(), SPV_VALIDATE_ID_BIT, &diagnostic); \ - if (SPV_SUCCESS != result) { \ - spvDiagnosticPrint(diagnostic); \ - spvDiagnosticDestroy(diagnostic); \ - } \ - ASSERT_EQ(expected, result); +#define CHECK(str, expected) \ + spv_diagnostic diagnostic; \ + spv_context context = spvContextCreate(); \ + spv_result_t error = \ + spvTextToBinary(context, str, strlen(str), &binary, &diagnostic); \ + if (error) { \ + spvDiagnosticPrint(diagnostic); \ + spvDiagnosticDestroy(diagnostic); \ + ASSERT_EQ(SPV_SUCCESS, error); \ + } \ + spv_result_t result = spvValidate(context, get_const_binary(), \ + SPV_VALIDATE_ID_BIT, &diagnostic); \ + if (SPV_SUCCESS != result) { \ + spvDiagnosticPrint(diagnostic); \ + spvDiagnosticDestroy(diagnostic); \ + } \ + ASSERT_EQ(expected, result); \ + spvContextDestroy(context); // TODO: OpUndef diff --git a/tools/as/as.cpp b/tools/as/as.cpp index f78a0087a..82b91fe0c 100644 --- a/tools/as/as.cpp +++ b/tools/as/as.cpp @@ -94,8 +94,10 @@ int main(int argc, char** argv) { spv_binary binary; spv_diagnostic diagnostic = nullptr; - spv_result_t error = - spvTextToBinary(contents.data(), contents.size(), &binary, &diagnostic); + spv_context context = spvContextCreate(); + spv_result_t error = spvTextToBinary(context, contents.data(), + contents.size(), &binary, &diagnostic); + spvContextDestroy(context); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); diff --git a/tools/dis/dis.cpp b/tools/dis/dis.cpp index a1a58d814..1bf04a283 100644 --- a/tools/dis/dis.cpp +++ b/tools/dis/dis.cpp @@ -146,8 +146,11 @@ int main(int argc, char** argv) { spv_text text; spv_text* textOrNull = print_to_stdout ? nullptr : &text; spv_diagnostic diagnostic = nullptr; - spv_result_t error = spvBinaryToText(contents.data(), contents.size(), - options, textOrNull, &diagnostic); + spv_context context = spvContextCreate(); + spv_result_t error = + spvBinaryToText(context, contents.data(), contents.size(), options, + textOrNull, &diagnostic); + spvContextDestroy(context); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); diff --git a/tools/val/val.cpp b/tools/val/val.cpp index 35b443259..29e7035dc 100644 --- a/tools/val/val.cpp +++ b/tools/val/val.cpp @@ -99,7 +99,9 @@ int main(int argc, char** argv) { spv_const_binary_t binary = {contents.data(), contents.size()}; spv_diagnostic diagnostic = nullptr; - spv_result_t error = spvValidate(&binary, options, &diagnostic); + spv_context context = spvContextCreate(); + spv_result_t error = spvValidate(context, &binary, options, &diagnostic); + spvContextDestroy(context); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic);