From b41d150b7fefe5da4b4cbebd16bfa91ac0218a00 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Mon, 14 Sep 2015 15:22:23 -0400 Subject: [PATCH] Support multiple word literal numbers as constants. Add a new operand type SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER to represent those operands that can expand into multiple words. Now only OpConstant and OpSpecConstant have such kind of operand. --- include/libspirv/libspirv.h | 2 ++ source/binary.cpp | 40 ++++++++++++++++++++++---- source/binary.h | 12 +++++++- source/opcode.cpp | 3 ++ source/operand.cpp | 2 ++ source/text.cpp | 3 ++ test/BinaryToText.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++++ test/FixWord.cpp | 20 +++++++++++++ 8 files changed, 146 insertions(+), 6 deletions(-) diff --git a/include/libspirv/libspirv.h b/include/libspirv/libspirv.h index 2e10a24..4c9c700 100644 --- a/include/libspirv/libspirv.h +++ b/include/libspirv/libspirv.h @@ -146,6 +146,8 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL, // Either a literal number or literal string SPV_OPERAND_TYPE_LITERAL_NUMBER, + // A literal number that can (but is not required to) expand multiple words. + SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER, SPV_OPERAND_TYPE_LITERAL_STRING, SPV_OPERAND_TYPE_SOURCE_LANGUAGE, SPV_OPERAND_TYPE_EXECUTION_MODEL, diff --git a/source/binary.cpp b/source/binary.cpp index beeba5d..4fa862b 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -83,6 +83,11 @@ uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian) { return word; } +uint64_t spvFixDoubleWord(const uint32_t low, const uint32_t high, + const spv_endianness_t endian) { + return (uint64_t(spvFixWord(high, endian)) << 32) | spvFixWord(low, endian); +} + spv_result_t spvBinaryHeaderGet(const spv_binary binary, const spv_endianness_t endian, spv_header_t *pHeader) { @@ -205,7 +210,7 @@ spv_operand_type_t spvBinaryOperandInfo(const uint32_t word, spv_result_t spvBinaryDecodeOperand( const Op opcode, const spv_operand_type_t type, const uint32_t *words, - const spv_endianness_t endian, const uint32_t options, + uint16_t numWords, const spv_endianness_t endian, const uint32_t options, const spv_operand_table operandTable, const spv_ext_inst_table extInstTable, spv_operand_pattern_t *pExpectedOperands, spv_ext_inst_type_t *pExtInstType, out_stream &stream, spv_position position, spv_diagnostic *pDiagnostic) { @@ -249,14 +254,23 @@ spv_result_t spvBinaryDecodeOperand( break; } } // Fall through for the general case. + case SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER: case SPV_OPERAND_TYPE_LITERAL: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL: case SPV_OPERAND_TYPE_LITERAL_IN_OPTIONAL_TUPLE: { // TODO: Need to support multiple word literals stream.get() << (color ? clr::red() : ""); - stream.get() << spvFixWord(words[0], endian); + if (numWords > 2) { + DIAGNOSTIC << "Literal numbers larger than 64-bit not supported yet."; + return SPV_UNSUPPORTED; + } else if (numWords == 2) { + stream.get() << spvFixDoubleWord(words[0], words[1], endian); + position->index += 2; + } else { + stream.get() << spvFixWord(words[0], endian); + position->index++; + } stream.get() << (color ? clr::reset() : ""); - position->index++; } break; case SPV_OPERAND_TYPE_LITERAL_STRING: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { @@ -415,9 +429,25 @@ spv_result_t spvBinaryDecodeOpcode( } else { stream.get() << " "; } + + uint16_t numWords = 1; + if (type == SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER) { + // Make sure this is the last operand for this instruction. + if (expectedOperands.empty()) { + numWords = wordCount - index; + } else { + // TODO(antiagainst): This may not be an error. The exact design has not + // been settled yet. + DIAGNOSTIC << "Multiple word literal numbers can only appear as the " + "last operand of an instruction."; + return SPV_ERROR_INVALID_BINARY; + } + } + if (spvBinaryDecodeOperand( - opcodeEntry->opcode, type, pInst->words + index, endian, options, - operandTable, extInstTable, &expectedOperands, &pInst->extInstType, + opcodeEntry->opcode, type, pInst->words + index, numWords, endian, + options, operandTable, extInstTable, &expectedOperands, + &pInst->extInstType, (isAssigmentFormat && !currentIsResultId ? no_result_id_stream : stream), position, pDiagnostic)) { diff --git a/source/binary.h b/source/binary.h index 3959e0a..1a95757 100644 --- a/source/binary.h +++ b/source/binary.h @@ -41,6 +41,16 @@ /// @return word with host endianness correction uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian); +/// @brief Fix the endianness of a double word +/// +/// @param[in] low the lower 32-bit of the double word +/// @param[in] high the higher 32-bit of the double word +/// @param[in] endian the desired endianness +/// +/// @return word with host endianness correction +uint64_t spvFixDoubleWord(const uint32_t low, const uint32_t high, + const spv_endianness_t endian); + /// @brief Determine the endianness of the SPV binary /// /// Gets the endianness of the SPV source. Returns SPV_ENDIANNESS_UNKNOWN if @@ -141,7 +151,7 @@ spv_operand_type_t spvBinaryOperandInfo(const uint32_t word, /// @return result code spv_result_t spvBinaryDecodeOperand( const Op opcode, const spv_operand_type_t type, const uint32_t *words, - const spv_endianness_t endian, const uint32_t options, + uint16_t numWords, const spv_endianness_t endian, const uint32_t options, const spv_operand_table operandTable, const spv_ext_inst_table extInstTable, spv_operand_pattern_t *pExpectedOperands, spv_ext_inst_type_t *pExtInstType, out_stream &stream, spv_position position, spv_diagnostic *pDiagnostic); diff --git a/source/opcode.cpp b/source/opcode.cpp index 4507da6..8701eaf 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -90,6 +90,9 @@ spv_operand_type_t convertOperandClassToType(spv::Op opcode, default: break; } + } else if (operandClass == OperandVariableLiterals) { + if (opcode == spv::OpConstant || opcode == spv::OpSpecConstant) + return SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER; } switch(operandClass) { diff --git a/source/operand.cpp b/source/operand.cpp index 89912e0..91814b0 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -1454,6 +1454,8 @@ const char *spvOperandTypeStr(spv_operand_type_t type) { return "literal"; case SPV_OPERAND_TYPE_LITERAL_NUMBER: return "literal number"; + case SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER: + return "multiple word literal number"; case SPV_OPERAND_TYPE_LITERAL_STRING: return "literal string"; case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: diff --git a/source/text.cpp b/source/text.cpp index c8a0f8a..fe23d25 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -435,6 +435,9 @@ spv_result_t spvTextEncodeOperand( return SPV_ERROR_INVALID_TEXT; } } break; + // TODO(antiagainst): the handling of literal numbers in this function need + // to be reorganized. + case SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER: case SPV_OPERAND_TYPE_LITERAL: case SPV_OPERAND_TYPE_LITERAL_IN_OPTIONAL_TUPLE: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL: { diff --git a/test/BinaryToText.cpp b/test/BinaryToText.cpp index 9779c4a..6fc0b8b 100644 --- a/test/BinaryToText.cpp +++ b/test/BinaryToText.cpp @@ -194,4 +194,74 @@ TEST(BinaryToTextSmall, OperandWithOperands) { spvTextDestroy(text); } +TEST(BinaryToTextSmall, LiteralInt64) { + spv_opcode_table opcodeTable; + spv_operand_table operandTable; + spv_ext_inst_table extInstTable; + ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable)); + ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable)); + ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable)); + spv_binary binary; + spv_diagnostic diagnostic = nullptr; + + AutoText input("%1 = OpTypeInt 64 0\n%2 = OpConstant %1 123456789021\n"); + spv_result_t error = + spvTextToBinary(input.str.c_str(), input.str.length(), opcodeTable, + operandTable, extInstTable, &binary, &diagnostic); + ASSERT_EQ(SPV_SUCCESS, error); + spv_text text = nullptr; + error = spvBinaryToText(binary->code, binary->wordCount, + SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable, + operandTable, extInstTable, &text, &diagnostic); + EXPECT_EQ(SPV_SUCCESS, error); + if (error) { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + } + const std::string header = + "; SPIR-V\n; Version: 99\n; Generator: Khronos\n; " + "Bound: 3\n; Schema: 0\n"; + EXPECT_EQ(header + input.str, text->str); + spvTextDestroy(text); +} + +TEST(BinaryToTextSmall, LiteralDouble) { + spv_opcode_table opcodeTable; + spv_operand_table operandTable; + spv_ext_inst_table extInstTable; + ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable)); + ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable)); + ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable)); + spv_binary binary; + spv_diagnostic diagnostic = nullptr; + + // Pi: 3.1415926535897930 => 0x400921fb54442d18 => 4614256656552045848 + AutoText input( + "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 3.1415926535897930"); + spv_result_t error = + spvTextToBinary(input.str.c_str(), input.str.length(), opcodeTable, + operandTable, extInstTable, &binary, &diagnostic); + ASSERT_EQ(SPV_SUCCESS, error); + spv_text text = nullptr; + error = spvBinaryToText(binary->code, binary->wordCount, + SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable, + operandTable, extInstTable, &text, &diagnostic); + EXPECT_EQ(SPV_SUCCESS, error); + if (error) { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + } + const std::string output = + R"(; SPIR-V +; Version: 99 +; Generator: Khronos +; Bound: 3 +; Schema: 0 +%1 = OpTypeFloat 64 +%2 = OpSpecConstant %1 4614256656552045848 +)"; + EXPECT_EQ(output, text->str); + spvTextDestroy(text); +} + } // anonymous namespace diff --git a/test/FixWord.cpp b/test/FixWord.cpp index e3ed4cc..fd9702f 100644 --- a/test/FixWord.cpp +++ b/test/FixWord.cpp @@ -51,4 +51,24 @@ TEST(FixWord, Reorder) { ASSERT_EQ(result, spvFixWord(word, endian)); } +TEST(FixDoubleWord, Default) { + spv_endianness_t endian = + (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE ? SPV_ENDIANNESS_LITTLE + : SPV_ENDIANNESS_BIG); + uint32_t low = 0x53780921; + uint32_t high = 0xdeadbeef; + uint64_t result = 0xdeadbeef53780921; + ASSERT_EQ(result, spvFixDoubleWord(low, high, endian)); +} + +TEST(FixDoubleWord, Reorder) { + spv_endianness_t endian = + (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE ? SPV_ENDIANNESS_BIG + : SPV_ENDIANNESS_LITTLE); + uint32_t low = 0x53780921; + uint32_t high = 0xdeadbeef; + uint64_t result = 0xefbeadde21097853; + ASSERT_EQ(result, spvFixDoubleWord(low, high, endian)); +} + } // anonymous namespace -- 2.7.4