Implement alternate-parsing mode for !<integer>.
authorDejan Mircevski <deki@google.com>
Mon, 28 Sep 2015 21:04:39 +0000 (17:04 -0400)
committerDavid Neto <dneto@google.com>
Mon, 26 Oct 2015 16:55:33 +0000 (12:55 -0400)
include/libspirv/libspirv.h
source/operand.cpp
source/operand.h
source/text.cpp
test/ImmediateInt.cpp

index 9224c03..1d17051 100644 (file)
@@ -209,6 +209,12 @@ typedef enum spv_operand_type_t {
   // This must be present if the first operand in the tuple is present.
   SPV_OPERAND_TYPE_LITERAL_NUMBER_IN_OPTIONAL_TUPLE,
 
+  // An optional context-independent value, or CIV.  CIVs are tokens that we can
+  // assemble regardless of where they occur -- literals, IDs, immediate
+  // integers, etc.
+  SPV_OPERAND_TYPE_OPTIONAL_CIV,
+
+
   // This is a sentinel value, and does not represent an operand type.
   // It should come last.
   SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
index 901a058..be1d58a 100644 (file)
@@ -1543,6 +1543,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) {
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
     case SPV_OPERAND_TYPE_OPTIONAL_EXECUTION_MODE:
+    case SPV_OPERAND_TYPE_OPTIONAL_CIV:
       return true;
     default:
       break;
@@ -1605,3 +1606,23 @@ spv_operand_type_t spvTakeFirstMatchableOperand(spv_operand_pattern_t* pattern)
   } while(spvExpandOperandSequenceOnce(result, pattern));
   return result;
 }
+
+void spvSwitchToAlternateParsingAfterImmediate(
+    spv_operand_pattern_t* pExpectedOperands) {
+  if (pExpectedOperands->empty()) {
+    pExpectedOperands->push_back(SPV_OPERAND_TYPE_OPTIONAL_CIV);
+  } else if (pExpectedOperands->size() == 1 &&
+             (*pExpectedOperands)[0] == SPV_OPERAND_TYPE_RESULT_ID) {
+    // Must preserve the result-id position.
+    pExpectedOperands->push_back(SPV_OPERAND_TYPE_OPTIONAL_CIV);
+  } else {
+    // Must preserve the result-id position.
+    for (auto& operand : *pExpectedOperands) {
+      if (operand != SPV_OPERAND_TYPE_RESULT_ID) {
+        // This may end up inserting multiple SPV_OPERAND_TYPE_OPTIONAL_CIVs,
+        // but that's OK because it's an optional type.
+        operand = SPV_OPERAND_TYPE_OPTIONAL_CIV;
+      }
+    }
+  }
+}
index db3f1c1..8fa7ae9 100644 (file)
@@ -152,4 +152,9 @@ bool spvExpandOperandSequenceOnce(spv_operand_type_t type,
 /// operand type.
 spv_operand_type_t spvTakeFirstMatchableOperand(spv_operand_pattern_t* pattern);
 
+/// Switches *pExpectedOperands to the post-immediate alternate pattern, which
+/// allows a limited set of operand types.
+void spvSwitchToAlternateParsingAfterImmediate(
+    spv_operand_pattern_t *pExpectedOperands);
+
 #endif
index d9a2e7d..0c190b3 100644 (file)
@@ -52,7 +52,7 @@ using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
 
 // Text API
 
-std::string spvGetWord(const char *str) {
+std::string spvGetWord(const charstr) {
   size_t index = 0;
   while (true) {
     switch (str[index]) {
@@ -71,8 +71,8 @@ std::string spvGetWord(const char *str) {
   return "";  // Make certain compilers happy.
 }
 
-uint32_t spvNamedIdAssignOrGet(spv_named_id_table* table, const char *textValue,
-                               uint32_t *pBound) {
+uint32_t spvNamedIdAssignOrGet(spv_named_id_table* table, const chartextValue,
+                               uint32_tpBound) {
   if (table->end() == table->find(textValue)) {
     (*table)[std::string(textValue)] = *pBound;
   }
@@ -139,7 +139,7 @@ spv_result_t spvTextAdvance(const spv_text text, spv_position position) {
 }
 
 spv_result_t spvTextWordGet(const spv_text text,
-                            const spv_position startPosition, std::string &word,
+                            const spv_position startPosition, std::stringword,
                             spv_position endPosition) {
   if (!text->str || !text->length) return SPV_ERROR_INVALID_TEXT;
   if (!startPosition || !endPosition) return SPV_ERROR_INVALID_POINTER;
@@ -218,7 +218,7 @@ bool spvTextIsStartOfNewInst(const spv_text text, const spv_position position) {
 
 spv_result_t spvTextStringGet(const spv_text text,
                               const spv_position startPosition,
-                              std::string &string, spv_position endPosition) {
+                              std::stringstring, spv_position endPosition) {
   if (!text->str || !text->length) return SPV_ERROR_INVALID_TEXT;
   if (!startPosition || !endPosition) return SPV_ERROR_INVALID_POINTER;
 
@@ -250,8 +250,8 @@ spv_result_t spvTextStringGet(const spv_text text,
   }
 }
 
-spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue) {
-  char *endPtr = nullptr;
+spv_result_t spvTextToUInt32(const char* textValue, uint32_t* pValue) {
+  charendPtr = nullptr;
   *pValue = strtoul(textValue, &endPtr, 0);
   if (0 == *pValue && textValue == endPtr) {
     return SPV_ERROR_INVALID_TEXT;
@@ -259,7 +259,7 @@ spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue) {
   return SPV_SUCCESS;
 }
 
-spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral) {
+spv_result_t spvTextToLiteral(const char* textValue, spv_literal_t* pLiteral) {
   bool isSigned = false;
   int numPeriods = 0;
   bool isString = false;
@@ -345,11 +345,11 @@ spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral) {
 
 spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
                                      const spv_operand_type_t type,
-                                     const char *textValue, uint32_t *pValue) {
+                                     const char* textValue, uint32_t* pValue) {
   if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
   size_t text_length = strlen(textValue);
   if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
-  const char *text_end = textValue + text_length;
+  const chartext_end = textValue + text_length;
 
   // We only support mask expressions in ASCII, so the separator value is a
   // char.
@@ -358,8 +358,8 @@ spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
   // Accumulate the result by interpreting one word at a time, scanning
   // from left to right.
   uint32_t value = 0;
-  const char *begin = textValue;  // The left end of the current word.
-  const char *end = nullptr;  // One character past the end of the current word.
+  const charbegin = textValue;  // The left end of the current word.
+  const charend = nullptr;  // One character past the end of the current word.
   do {
     end = std::find(begin, text_end, separator);
 
@@ -378,8 +378,6 @@ spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
   return SPV_SUCCESS;
 }
 
-
-
 /// @brief Translate an Opcode operand to binary form
 ///
 /// @param[in] type of the operand
@@ -394,15 +392,15 @@ spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
 ///
 /// @return result code
 spv_result_t spvTextEncodeOperand(
-    const spv_operand_type_t type, const char *textValue,
+    const spv_operand_type_t type, const chartextValue,
     const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
-    spv_named_id_table* namedIdTable, spv_instruction_t *pInst,
-    spv_operand_pattern_t *pExpectedOperands, uint32_t *pBound,
-    const spv_position position, spv_diagnostic *pDiagnostic) {
+    spv_named_id_table* namedIdTable, spv_instruction_tpInst,
+    spv_operand_pattern_t* pExpectedOperands, uint32_t* pBound,
+    const spv_position position, spv_diagnosticpDiagnostic) {
   // NOTE: Handle immediate int in the stream
   if ('!' == textValue[0]) {
-    const char *begin = textValue + 1;
-    char *end = nullptr;
+    const charbegin = textValue + 1;
+    charend = nullptr;
     uint32_t immediateInt = strtoul(begin, &end, 0);
     size_t size = strlen(textValue);
     size_t length = (end - begin);
@@ -414,6 +412,7 @@ spv_result_t spvTextEncodeOperand(
     position->index += size;
     pInst->words[pInst->wordCount] = immediateInt;
     pInst->wordCount += 1;
+    spvSwitchToAlternateParsingAfterImmediate(pExpectedOperands);
     return SPV_SUCCESS;
   }
 
@@ -551,7 +550,35 @@ spv_result_t spvTextEncodeOperand(
       if (auto error = spvBinaryEncodeU32(value, pInst, position, pDiagnostic))
         return error;
       // Prepare to parse the operands for this logical operand.
-      spvPrependOperandTypesForMask(operandTable, type, value, pExpectedOperands);
+      spvPrependOperandTypesForMask(operandTable, type, value,
+                                    pExpectedOperands);
+    } break;
+    case SPV_OPERAND_TYPE_OPTIONAL_CIV: {
+      auto error = spvTextEncodeOperand(
+          SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER, textValue, operandTable,
+          extInstTable, namedIdTable, pInst, pExpectedOperands, pBound,
+          position, pDiagnostic);
+      if (error == SPV_FAILED_MATCH) {
+        // It's not a literal number -- is it a literal string?
+        error = spvTextEncodeOperand(SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING,
+                                     textValue, operandTable, extInstTable,
+                                     namedIdTable, pInst, pExpectedOperands,
+                                     pBound, position, pDiagnostic);
+      }
+      if (error == SPV_FAILED_MATCH) {
+        // It's not a literal -- is it an ID?
+        error = spvTextEncodeOperand(SPV_OPERAND_TYPE_OPTIONAL_ID, textValue,
+                                     operandTable, extInstTable, namedIdTable,
+                                     pInst, pExpectedOperands, pBound, position,
+                                     pDiagnostic);
+      }
+      if (error) {
+        DIAGNOSTIC << "Invalid word following !<integer>: " << textValue;
+        return error;
+      }
+      if (pExpectedOperands->empty()) {
+        pExpectedOperands->push_back(SPV_OPERAND_TYPE_OPTIONAL_CIV);
+      }
     } break;
     default: {
       // NOTE: All non literal operands are handled here using the operand
@@ -586,8 +613,8 @@ namespace {
 spv_result_t encodeInstructionStartingWithImmediate(
     const spv_text text, const spv_operand_table operandTable,
     const spv_ext_inst_table extInstTable, spv_named_id_table* namedIdTable,
-    uint32_t *pBound, spv_instruction_t *pInst, spv_position position,
-    spv_diagnostic *pDiagnostic) {
+    uint32_t* pBound, spv_instruction_t* pInst, spv_position position,
+    spv_diagnosticpDiagnostic) {
   std::string firstWord;
   spv_position_t nextPosition = {};
   auto error = spvTextWordGet(text, position, firstWord, &nextPosition);
@@ -597,8 +624,8 @@ spv_result_t encodeInstructionStartingWithImmediate(
   }
 
   assert(firstWord[0] == '!');
-  const char *begin = firstWord.data() + 1;
-  char *end = nullptr;
+  const charbegin = firstWord.data() + 1;
+  charend = nullptr;
   uint32_t immediateInt = strtoul(begin, &end, 0);
   if ((begin + firstWord.size() - 1) != end) {
     DIAGNOSTIC << "Invalid immediate integer '" << firstWord << "'.";
@@ -629,27 +656,9 @@ spv_result_t encodeInstructionStartingWithImmediate(
     // expanded.
     spv_operand_pattern_t dummyExpectedOperands;
     error = spvTextEncodeOperand(
-        SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER, operandValue.c_str(),
-        operandTable, extInstTable, namedIdTable, pInst, &dummyExpectedOperands,
-        pBound, position, pDiagnostic);
-    if (error == SPV_FAILED_MATCH) {
-      // It's not a literal number -- is it a literal string?
-      error = spvTextEncodeOperand(
-          SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING, operandValue.c_str(),
-          operandTable, extInstTable, namedIdTable, pInst,
-          &dummyExpectedOperands, pBound, position, pDiagnostic);
-    }
-    if (error == SPV_FAILED_MATCH) {
-      // It's not a literal -- is it an ID?
-      error = spvTextEncodeOperand(
-          SPV_OPERAND_TYPE_OPTIONAL_ID, operandValue.c_str(), operandTable,
-          extInstTable, namedIdTable, pInst, &dummyExpectedOperands, pBound,
-          position, pDiagnostic);
-      if (error) {
-        DIAGNOSTIC << "Invalid word following " << firstWord << ": "
-                   << operandValue;
-      }
-    }
+        SPV_OPERAND_TYPE_OPTIONAL_CIV, operandValue.c_str(), operandTable,
+        extInstTable, namedIdTable, pInst, &dummyExpectedOperands, pBound,
+        position, pDiagnostic);
     if (error) return error;
     *position = nextPosition;
   }
@@ -675,9 +684,8 @@ spv_result_t spvTextEncodeOpcode(
     const spv_text text, spv_assembly_syntax_format_t format,
     const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
     const spv_ext_inst_table extInstTable, spv_named_id_table* namedIdTable,
-    uint32_t *pBound, spv_instruction_t *pInst, spv_position position,
-    spv_diagnostic *pDiagnostic) {
-
+    uint32_t* pBound, spv_instruction_t* pInst, spv_position position,
+    spv_diagnostic* pDiagnostic) {
   // Check for !<integer> first.
   if ('!' == text->str[position->index]) {
     return encodeInstructionStartingWithImmediate(
@@ -752,7 +760,7 @@ spv_result_t spvTextEncodeOpcode(
   }
 
   // NOTE: The table contains Opcode names without the "Op" prefix.
-  const char *pInstName = opcodeName.data() + 2;
+  const charpInstName = opcodeName.data() + 2;
 
   spv_opcode_desc opcodeEntry;
   error = spvOpcodeTableNameLookup(opcodeTable, pInstName, &opcodeEntry);
@@ -861,8 +869,8 @@ spv_result_t spvTextToBinaryInternal(const spv_text text,
                                      const spv_opcode_table opcodeTable,
                                      const spv_operand_table operandTable,
                                      const spv_ext_inst_table extInstTable,
-                                     spv_binary *pBinary,
-                                     spv_diagnostic *pDiagnostic) {
+                                     spv_binarypBinary,
+                                     spv_diagnosticpDiagnostic) {
   spv_position_t position = {};
   if (!text->str || !text->length) {
     DIAGNOSTIC << "Text stream is empty.";
@@ -908,14 +916,14 @@ spv_result_t spvTextToBinaryInternal(const spv_text text,
   }
 
   size_t totalSize = SPV_INDEX_INSTRUCTION;
-  for (auto &inst : instructions) {
+  for (autoinst : instructions) {
     totalSize += inst.wordCount;
   }
 
-  uint32_t *data = new uint32_t[totalSize];
+  uint32_tdata = new uint32_t[totalSize];
   if (!data) return SPV_ERROR_OUT_OF_MEMORY;
   uint64_t currentIndex = SPV_INDEX_INSTRUCTION;
-  for (auto &inst : instructions) {
+  for (autoinst : instructions) {
     memcpy(data + currentIndex, inst.words, sizeof(uint32_t) * inst.wordCount);
     currentIndex += inst.wordCount;
   }
@@ -941,22 +949,22 @@ spv_result_t spvTextToBinaryInternal(const spv_text text,
 
 }  // anonymous namespace
 
-spv_result_t spvTextToBinary(const char *input_text,
+spv_result_t spvTextToBinary(const charinput_text,
                              const uint64_t input_text_size,
                              const spv_opcode_table opcodeTable,
                              const spv_operand_table operandTable,
                              const spv_ext_inst_table extInstTable,
-                             spv_binary *pBinary, spv_diagnostic *pDiagnostic) {
+                             spv_binary* pBinary, spv_diagnostic* pDiagnostic) {
   return spvTextWithFormatToBinary(
       input_text, input_text_size, SPV_ASSEMBLY_SYNTAX_FORMAT_DEFAULT,
       opcodeTable, operandTable, extInstTable, pBinary, pDiagnostic);
 }
 
 spv_result_t spvTextWithFormatToBinary(
-    const char *input_text, const uint64_t input_text_size,
+    const charinput_text, const uint64_t input_text_size,
     spv_assembly_syntax_format_t format, const spv_opcode_table opcodeTable,
     const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
-    spv_binary *pBinary, spv_diagnostic *pDiagnostic) {
+    spv_binary* pBinary, spv_diagnostic* pDiagnostic) {
   spv_text_t text = {input_text, input_text_size};
 
   spv_result_t result =
index 3fbb729..c0afd06 100644 (file)
@@ -262,9 +262,9 @@ TEST_F(ImmediateIntTest, ConsecutiveImmediateOpcodes) {
 // !<integer> followed by, eg, an enum or '=' or a random bareword.
 TEST_F(ImmediateIntTest, ForbiddenOperands) {
 // TODO(deki): uncomment assertions below and make them pass.
-#if 0
   EXPECT_THAT(CompileFailure("OpMemoryModel !0 OpenCL"), HasSubstr("OpenCL"));
   EXPECT_THAT(CompileFailure("!1 %0 = !2"), HasSubstr("="));
+#if 0
   // Immediate integers longer than one 32-bit word.
   EXPECT_THAT(CompileFailure("!5000000000"), HasSubstr("5000000000"));
   EXPECT_THAT(CompileFailure("!0x00020049 !5000000000"), HasSubstr("5000000000"));