Support multiple word literal numbers as constants.
authorLei Zhang <antiagainst@google.com>
Mon, 14 Sep 2015 19:22:23 +0000 (15:22 -0400)
committerDavid Neto <dneto@google.com>
Mon, 26 Oct 2015 16:55:33 +0000 (12:55 -0400)
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
source/binary.cpp
source/binary.h
source/opcode.cpp
source/operand.cpp
source/text.cpp
test/BinaryToText.cpp
test/FixWord.cpp

index 2e10a24..4c9c700 100644 (file)
@@ -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,
index beeba5d..4fa862b 100644 (file)
@@ -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)) {
index 3959e0a..1a95757 100644 (file)
 /// @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);
index 4507da6..8701eaf 100644 (file)
@@ -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) {
index 89912e0..91814b0 100644 (file)
@@ -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:
index c8a0f8a..fe23d25 100644 (file)
@@ -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: {
index 9779c4a..6fc0b8b 100644 (file)
@@ -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
index e3ed4cc..fd9702f 100644 (file)
@@ -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