Use syntax tables for SPIR-V 1.0 Rev3
authorDavid Neto <dneto@google.com>
Mon, 15 Feb 2016 18:50:00 +0000 (13:50 -0500)
committerDavid Neto <dneto@google.com>
Tue, 16 Feb 2016 21:47:04 +0000 (16:47 -0500)
- The SPIR-V spec generator has changed how it represents optional
  operands.  Now it tracks a separate boolean flag indicating optionality.
  However, SPIRV-Tools still wants to represent both operand class
  and optionality in the same enums space (SPV_OPERAND_TYPE_*).
  So there's extra work in the patch.

- In the spec generator, OperandImage is now OperandImageOperands.
  This affects enum translation in opcode.cpp.

- In the spec generator, image operands are explicitly followed by
  Id, and VariableIds.  However, SPIRV-Tools uses the bits set
  in the image operand bitmask to control the number and meaning
  of the Ids that follow.  So in writing the opcode.inc syntax
  table, drop all operands after OperandImageOperands.

- Some enums are now more explicitly represented in the generated
  opcode.inc:
    - AccessQualifier (e.g. on OpTypeImage), in both required and
      optional flavours.
    - MemoryAccess (e.g. on loads and stores)

- Add SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER

- Add tests for the optional AccessQualifier operand on OpTypeImage.

- Update the AccessQualifier test for OpTypeImage so it's a round
  trip test through the disassembler as well.

include/libspirv/libspirv.h
source/binary.cpp
source/opcode.cpp
source/opcode.inc
source/operand.cpp
source/spirv_operands.h
source/syntax_tables.patch
source/text.cpp
test/TextToBinary.TypeDeclaration.cpp

index 348a59f..25b9755 100644 (file)
@@ -205,6 +205,8 @@ typedef enum spv_operand_type_t {
   SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING,
   // An optional execution mode.
   SPV_OPERAND_TYPE_OPTIONAL_EXECUTION_MODE,
+  // An optional access qualifier
+  SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER,
   // An optional context-independent value, or CIV.  CIVs are tokens that we can
   // assemble regardless of where they occur -- literals, IDs, immediate
   // integers, etc.
index ae11152..bedd3b0 100644 (file)
@@ -656,6 +656,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
     case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
     case SPV_OPERAND_TYPE_LINKAGE_TYPE:
     case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
+    case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
     case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
     case SPV_OPERAND_TYPE_DECORATION:
     case SPV_OPERAND_TYPE_BUILT_IN:
@@ -663,6 +664,11 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
     case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
     case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: {
       // 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;
+
       spv_operand_desc entry;
       if (grammar_.lookupOperand(type, word, &entry)) {
         return diagnostic() << "Invalid "
@@ -676,6 +682,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
     case SPV_OPERAND_TYPE_LOOP_CONTROL:
+    case SPV_OPERAND_TYPE_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
     case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
index ab627ce..68c45bb 100644 (file)
@@ -86,13 +86,6 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
   // what is being repeated.
   if (operandClass == OperandOptionalLiteral) {
     switch (opcode) {
-      case SpvOpLoad:
-      case SpvOpStore:
-      case SpvOpCopyMemory:
-      case SpvOpCopyMemorySized:
-        // Expect an optional mask.  When the Aligned bit is set in the mask,
-        // we will later add the expectation of a literal number operand.
-        return SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS;
       case SpvOpExecutionMode:
         return SPV_OPERAND_TYPE_VARIABLE_EXECUTION_MODE;
       default:
@@ -121,8 +114,6 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
       return SPV_OPERAND_TYPE_ID;
     case OperandOptionalId:
       return SPV_OPERAND_TYPE_OPTIONAL_ID;
-    case OperandOptionalImage:
-      return SPV_OPERAND_TYPE_OPTIONAL_IMAGE;
     case OperandVariableIds:
       if (opcode == SpvOpSpecConstantOp) {
         // These are the operands to the specialization constant opcode.
@@ -188,10 +179,9 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
       // OpImageQueryFormat. It is not used as an operand.
       break;
     case OperandImageOperands:
-      // This is not used in opcode.inc. It only exists to generate the
-      // corresponding spec section. In parsing, image operands meld into the
-      // OperandOptionalImage case.
-      break;
+      return SPV_OPERAND_TYPE_IMAGE;
+    case OperandOptionalImageOperands:
+      return SPV_OPERAND_TYPE_OPTIONAL_IMAGE;
     case OperandFPFastMath:
       return SPV_OPERAND_TYPE_FP_FAST_MATH_MODE;
     case OperandFPRoundingMode:
@@ -200,6 +190,8 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
       return SPV_OPERAND_TYPE_LINKAGE_TYPE;
     case OperandAccessQualifier:
       return SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
+    case OperandOptionalAccessQualifier:
+      return SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER;
     case OperandFuncParamAttr:
       return SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE;
     case OperandDecoration:
@@ -220,6 +212,10 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
       // and we can remove the special casing above for memory operation
       // instructions.
       break;
+    case OperandOptionalMemoryAccess:
+      // Expect an optional mask.  When the Aligned bit is set in the mask,
+      // we will later add the expectation of a literal number operand.
+      return SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS;
     case OperandScope:
       return SPV_OPERAND_TYPE_SCOPE_ID;
     case OperandGroupOperation:
index 588dc78..6199e18 100644 (file)
@@ -6,7 +6,7 @@
 //    numCapabilities - we only handle 0 or 1 required capabilities
 //    Capability(<capability-name>) - capability required to use this instruction. Might be None.
 //       There can be Capability2(a,b) for dependence on two capabilities.
-//    {0|1} - whether the instruction is variable number of words
+//    {0|1} - whether the instruction is variable number of logical operands
 //    EmptyList or List(...) - list of classes of logical operands
 // Example use:
 // #define EmptyList {}
@@ -36,7 +36,7 @@ Instruction(TypeInt, 1, 0, 2, 0, Capability(None), 0, List(OperandLiteralNumber,
 Instruction(TypeFloat, 1, 0, 1, 0, Capability(None), 0, List(OperandLiteralNumber))
 Instruction(TypeVector, 1, 0, 2, 0, Capability(None), 0, List(OperandId, OperandLiteralNumber))
 Instruction(TypeMatrix, 1, 0, 2, 1, Capability(Matrix), 0, List(OperandId, OperandLiteralNumber))
-Instruction(TypeImage, 1, 0, 8, 0, Capability(None), 1, List(OperandId, OperandDimensionality, OperandLiteralNumber, OperandLiteralNumber, OperandLiteralNumber, OperandLiteralNumber, OperandSamplerImageFormat, OperandOptionalLiteral))
+Instruction(TypeImage, 1, 0, 8, 0, Capability(None), 1, List(OperandId, OperandDimensionality, OperandLiteralNumber, OperandLiteralNumber, OperandLiteralNumber, OperandLiteralNumber, OperandSamplerImageFormat, OperandOptionalAccessQualifier))
 Instruction(TypeSampler, 1, 0, 0, 0, Capability(None), 0, EmptyList)
 Instruction(TypeSampledImage, 1, 0, 1, 0, Capability(None), 0, List(OperandId))
 Instruction(TypeArray, 1, 0, 2, 0, Capability(None), 0, List(OperandId, OperandId))
@@ -68,10 +68,10 @@ Instruction(FunctionEnd, 0, 0, 0, 0, Capability(None), 0, EmptyList)
 Instruction(FunctionCall, 1, 1, 2, 0, Capability(None), 1, List(OperandId, OperandVariableIds))
 Instruction(Variable, 1, 1, 2, 0, Capability(None), 1, List(OperandStorage, OperandOptionalId))
 Instruction(ImageTexelPointer, 1, 1, 3, 0, Capability(None), 0, List(OperandId, OperandId, OperandId))
-Instruction(Load, 1, 1, 2, 0, Capability(None), 1, List(OperandId, OperandOptionalLiteral))
-Instruction(Store, 0, 0, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalLiteral))
-Instruction(CopyMemory, 0, 0, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalLiteral))
-Instruction(CopyMemorySized, 0, 0, 4, 1, Capability(Addresses), 1, List(OperandId, OperandId, OperandId, OperandOptionalLiteral))
+Instruction(Load, 1, 1, 2, 0, Capability(None), 1, List(OperandId, OperandOptionalMemoryAccess))
+Instruction(Store, 0, 0, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalMemoryAccess))
+Instruction(CopyMemory, 0, 0, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalMemoryAccess))
+Instruction(CopyMemorySized, 0, 0, 4, 1, Capability(Addresses), 1, List(OperandId, OperandId, OperandId, OperandOptionalMemoryAccess))
 Instruction(AccessChain, 1, 1, 2, 0, Capability(None), 1, List(OperandId, OperandVariableIds))
 Instruction(InBoundsAccessChain, 1, 1, 2, 0, Capability(None), 1, List(OperandId, OperandVariableIds))
 Instruction(PtrAccessChain, 1, 1, 3, 1, Capability(Addresses), 1, List(OperandId, OperandId, OperandVariableIds))
@@ -92,19 +92,19 @@ Instruction(CompositeInsert, 1, 1, 3, 0, Capability(None), 1, List(OperandId, Op
 Instruction(CopyObject, 1, 1, 1, 0, Capability(None), 0, List(OperandId))
 Instruction(Transpose, 1, 1, 1, 1, Capability(Matrix), 0, List(OperandId))
 Instruction(SampledImage, 1, 1, 2, 0, Capability(None), 0, List(OperandId, OperandId))
-Instruction(ImageSampleImplicitLod, 1, 1, 3, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleExplicitLod, 1, 1, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleDrefImplicitLod, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleDrefExplicitLod, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleProjImplicitLod, 1, 1, 3, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleProjExplicitLod, 1, 1, 3, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleProjDrefImplicitLod, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSampleProjDrefExplicitLod, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageFetch, 1, 1, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageGather, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageDrefGather, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageRead, 1, 1, 3, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageWrite, 0, 0, 4, 0, Capability(None), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
+Instruction(ImageSampleImplicitLod, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSampleExplicitLod, 1, 1, 5, 0, Capability(None), 1, List(OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSampleDrefImplicitLod, 1, 1, 5, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSampleDrefExplicitLod, 1, 1, 6, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSampleProjImplicitLod, 1, 1, 4, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSampleProjExplicitLod, 1, 1, 5, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSampleProjDrefImplicitLod, 1, 1, 5, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSampleProjDrefExplicitLod, 1, 1, 6, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandImageOperands))
+Instruction(ImageFetch, 1, 1, 4, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageGather, 1, 1, 5, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageDrefGather, 1, 1, 5, 1, Capability(Shader), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageRead, 1, 1, 4, 0, Capability(None), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageWrite, 0, 0, 5, 0, Capability(None), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
 Instruction(Image, 1, 1, 1, 0, Capability(None), 0, List(OperandId))
 Instruction(ImageQueryFormat, 1, 1, 1, 1, Capability(Kernel), 0, List(OperandId))
 Instruction(ImageQueryOrder, 1, 1, 1, 1, Capability(Kernel), 0, List(OperandId))
@@ -292,18 +292,19 @@ Instruction(SetUserEventStatus, 0, 0, 2, 1, Capability(DeviceEnqueue), 0, List(O
 Instruction(CaptureEventProfilingInfo, 0, 0, 3, 1, Capability(DeviceEnqueue), 0, List(OperandId, OperandId, OperandId))
 Instruction(GetDefaultQueue, 1, 1, 0, 1, Capability(DeviceEnqueue), 0, EmptyList)
 Instruction(BuildNDRange, 1, 1, 3, 1, Capability(DeviceEnqueue), 0, List(OperandId, OperandId, OperandId))
-Instruction(ImageSparseSampleImplicitLod, 1, 1, 3, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleExplicitLod, 1, 1, 3, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleDrefImplicitLod, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleDrefExplicitLod, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleProjImplicitLod, 1, 1, 3, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleProjExplicitLod, 1, 1, 3, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleProjDrefImplicitLod, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseSampleProjDrefExplicitLod, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseFetch, 1, 1, 3, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseGather, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
-Instruction(ImageSparseDrefGather, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImage))
+Instruction(ImageSparseSampleImplicitLod, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSparseSampleExplicitLod, 1, 1, 5, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSparseSampleDrefImplicitLod, 1, 1, 5, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSparseSampleDrefExplicitLod, 1, 1, 6, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSparseSampleProjImplicitLod, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSparseSampleProjExplicitLod, 1, 1, 5, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSparseSampleProjDrefImplicitLod, 1, 1, 5, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSparseSampleProjDrefExplicitLod, 1, 1, 6, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandImageOperands))
+Instruction(ImageSparseFetch, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSparseGather, 1, 1, 5, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
+Instruction(ImageSparseDrefGather, 1, 1, 5, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandId, OperandOptionalImageOperands))
 Instruction(ImageSparseTexelsResident, 1, 1, 1, 1, Capability(SparseResidency), 0, List(OperandId))
 Instruction(NoLine, 0, 0, 0, 0, Capability(None), 0, EmptyList)
 Instruction(AtomicFlagTestAndSet, 1, 1, 3, 1, Capability(Kernel), 0, List(OperandId, OperandScope, OperandMemorySemantics))
 Instruction(AtomicFlagClear, 0, 0, 3, 1, Capability(Kernel), 0, List(OperandId, OperandScope, OperandMemorySemantics))
+Instruction(ImageSparseRead, 1, 1, 4, 1, Capability(SparseResidency), 1, List(OperandId, OperandId, OperandOptionalImageOperands))
index 6870657..00ea7d1 100644 (file)
@@ -1051,6 +1051,8 @@ static const spv_operand_desc_group_t opcodeEntryTypes[] = {
      linkageTypeEntries},
     {SPV_OPERAND_TYPE_ACCESS_QUALIFIER, ARRAY_SIZE(accessQualifierEntries),
      accessQualifierEntries},
+    {SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER,  // Same as *_ACCESS_QUALIFIER
+     ARRAY_SIZE(accessQualifierEntries), accessQualifierEntries},
     {SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
      ARRAY_SIZE(functionParameterAttributeEntries),
      functionParameterAttributeEntries},
@@ -1194,6 +1196,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
     case SPV_OPERAND_TYPE_LINKAGE_TYPE:
       return "linkage type";
     case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
+    case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
       return "access qualifier";
     case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
       return "function parameter attribute";
index aa8322b..ed8c7e5 100644 (file)
@@ -47,7 +47,6 @@ enum OperandClass {
   OperandNone,
   OperandId,
   OperandOptionalId,
-  OperandOptionalImage,
   OperandVariableIds,
   OperandOptionalLiteral,
   OperandOptionalLiteralString,
@@ -69,10 +68,12 @@ enum OperandClass {
   OperandImageChannelOrder,
   OperandImageChannelDataType,
   OperandImageOperands,
+  OperandOptionalImageOperands,
   OperandFPFastMath,
   OperandFPRoundingMode,
   OperandLinkageType,
   OperandAccessQualifier,
+  OperandOptionalAccessQualifier,
   OperandFuncParamAttr,
   OperandDecoration,
   OperandBuiltIn,
@@ -81,6 +82,7 @@ enum OperandClass {
   OperandFunction,
   OperandMemorySemantics,
   OperandMemoryAccess,
+  OperandOptionalMemoryAccess,
   OperandScope,
   OperandGroupOperation,
   OperandKernelEnqueueFlags,
index 6422132..e2ab8f9 100644 (file)
@@ -11,7 +11,7 @@ index af51f86..5775510 100644
      header.cpp
      doc.cpp
 diff --git a/tools/spirv/OclDoc.cpp b/tools/spirv/OclDoc.cpp
-index c94eae2..ea47d42 100644
+index 1f25221..ff2c7c6 100644
 --- a/tools/spirv/OclDoc.cpp
 +++ b/tools/spirv/OclDoc.cpp
 @@ -28,11 +28,14 @@
@@ -30,7 +30,7 @@ index c94eae2..ea47d42 100644
  #include <algorithm>
  #include <map>
  
-@@ -2358,4 +2361,27 @@ void PrintOclCommonDoc()
+@@ -2187,4 +2190,31 @@ void PrintOclCommonDoc()
      PrintOclDoc(SPIROpenCLCommonVersion);
  }
  
@@ -52,7 +52,11 @@ index c94eae2..ea47d42 100644
 +    assert(inst.hasType());
 +    assert(inst.hasResult());
 +    out << "ExtInst(" << inst.opName << ", " << i << ", ";
-+    PrintOperandClasses(inst.operands.classes(), out);
++    std::vector<OperandClassInfo> classes_info;
++    for (const auto& operand_class : inst.operands.classes()) {
++      classes_info.push_back({operand_class, false /* not optional */});
++    }
++    PrintOperandClasses(classes_info, out);
 +    out << ")" << std::endl;
 +  }
 +}
@@ -90,10 +94,10 @@ index 8568880..7cf8a31 100644
  };  // end namespace spv
 diff --git a/tools/spirv/assembler_table.cpp b/tools/spirv/assembler_table.cpp
 new file mode 100644
-index 0000000..85bca89
+index 0000000..8dd8fa1
 --- /dev/null
 +++ b/tools/spirv/assembler_table.cpp
-@@ -0,0 +1,214 @@
+@@ -0,0 +1,229 @@
 +// Copyright (c) 2015-2016 The Khronos Group Inc.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a
@@ -137,8 +141,6 @@ index 0000000..85bca89
 +  const OperandParameters& operands = inst.operands;
 +  for (int i = 0; i < operands.getNum() ; i++) {
 +    switch (operands.getClass(i)) {
-+      case spv::OperandOptionalId:
-+      case spv::OperandOptionalImage:
 +      case spv::OperandVariableIds:
 +      case spv::OperandOptionalLiteral:
 +      case spv::OperandOptionalLiteralString:
@@ -150,6 +152,7 @@ index 0000000..85bca89
 +      default:
 +        break;
 +    }
++    if (operands.isOptional(i)) return true;
 +  }
 +  return false;
 +}
@@ -160,8 +163,6 @@ index 0000000..85bca89
 +#define CASE(X) case X: return #X;
 +    CASE(OperandNone)
 +    CASE(OperandId)
-+    CASE(OperandOptionalId)
-+    CASE(OperandOptionalImage)
 +    CASE(OperandVariableIds)
 +    CASE(OperandOptionalLiteral)
 +    CASE(OperandOptionalLiteralString)
@@ -214,14 +215,35 @@ index 0000000..85bca89
 +// Prints a listing of the operand kinds for the given instruction.
 +// If the list is empty, then emit just "EmptyList",
 +// otherwise the output looks like a call to the "List" macro.
-+void PrintOperandClasses(const std::vector<OperandClass>& classes, std::ostream& out) {
++void PrintOperandClasses(const std::vector<OperandClassInfo>& classes, std::ostream& out) {
 +  std::stringstream contents;
 +  int numPrinted = 0;
-+  for (auto operandClass : classes) {
-+    if (const char* name = GetOperandClassString(operandClass)) {
++  for (auto class_info : classes) {
++    if (const char* name = GetOperandClassString(class_info.value)) {
 +      if (numPrinted) contents << ", ";
-+      contents << name;
++      switch (class_info.value) {
++        case OperandId:
++        case OperandImageOperands:
++        case OperandLiteralString:
++        case OperandMemoryAccess:
++        case OperandAccessQualifier:
++          if (class_info.is_optional) {
++            contents << "OperandOptional" << (name + strlen("Operand"));
++          } else {
++            contents << name;
++          }
++          break;
++        default:
++          contents << name;
++          break;
++      }
 +      numPrinted++;
++      if (class_info.value == OperandImageOperands) {
++        // There are Id and/or VariableIds after this.  Skip them
++        // because the bits in an OperandImageOperands determine
++        // exactly the number of Ids required to follow.
++        break;
++      }
 +    }
 +  }
 +
@@ -233,18 +255,17 @@ index 0000000..85bca89
 +}  // namespace spv
 +
 +namespace spv {
-+namespace {
 +
 +// Prints a listing of the operand kinds for the given instruction.
 +// If the list is empty, then emit just "EmptyList",
 +// otherwise the output looks like a call to the "List" macro.
 +void PrintOperandClassesForInstruction(const InstructionParameters& inst,
 +                                       std::ostream& out) {
-+  std::vector<OperandClass> result;
++  std::vector<OperandClassInfo> result;
 +
 +  const OperandParameters& operands = inst.operands;
 +  for (int i = 0; i < operands.getNum(); i++) {
-+    result.push_back(operands.getClass(i));
++    result.push_back({operands.getClass(i), operands.isOptional(i)});
 +  }
 +  PrintOperandClasses(result, out);
 +}
@@ -282,8 +303,6 @@ index 0000000..85bca89
 +  }
 +}
 +
-+} // anonymous namespace
-+
 +void PrintAssemblerTable(std::ostream& out) {
 +  out << "// Instruction fields are:\n"
 +      << "//    name - skips the \"Op\" prefix\n"
@@ -293,7 +312,7 @@ index 0000000..85bca89
 +      << "//    numCapabilities - we only handle 0 or 1 required capabilities\n"
 +      << "//    Capability(<capability-name>) - capability required to use this instruction. Might be None.\n"
 +      << "//       There can be Capability2(a,b) for dependence on two capabilities.\n"
-+      << "//    {0|1} - whether the instruction is variable number of words\n"
++      << "//    {0|1} - whether the instruction is variable number of logical operands\n"
 +      << "//    EmptyList or List(...) - list of classes of logical operands\n"
 +      << "// Example use:\n"
 +      << "// #define EmptyList {}\n"
@@ -310,10 +329,10 @@ index 0000000..85bca89
 +}
 diff --git a/tools/spirv/assembler_table.h b/tools/spirv/assembler_table.h
 new file mode 100644
-index 0000000..b98303a
+index 0000000..16ea384
 --- /dev/null
 +++ b/tools/spirv/assembler_table.h
-@@ -0,0 +1,49 @@
+@@ -0,0 +1,55 @@
 +// Copyright (c) 2015-2016 The Khronos Group Inc.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a
@@ -351,6 +370,12 @@ index 0000000..b98303a
 +
 +namespace spv {
 +
++    // Relevant facts about an operand class value.
++    struct OperandClassInfo {
++      OperandClass value;
++      bool is_optional;
++    };
++
 +    // Prints the tables used to define the structure of instructions.
 +    // Assumes that parameterization has already occurred
 +    void PrintAssemblerTable(std::ostream& out);
@@ -358,13 +383,13 @@ index 0000000..b98303a
 +    // Prints a listing of the operand kinds.
 +    // If the list is empty, then emit just "EmptyList",
 +    // otherwise the output looks like a call to the "List" macro.
-+    void PrintOperandClasses(const std::vector<OperandClass>& classes, std::ostream& out);
++    void PrintOperandClasses(const std::vector<OperandClassInfo>& classes, std::ostream& out);
 +
 +};  // end namespace spv
 +
 +#endif // ASSEMBLER_TABLE_H
 diff --git a/tools/spirv/doc.h b/tools/spirv/doc.h
-index 78b1031..a182509 100644
+index 4c11d3b..6e1718a 100644
 --- a/tools/spirv/doc.h
 +++ b/tools/spirv/doc.h
 @@ -32,6 +32,9 @@
@@ -385,7 +410,7 @@ index 78b1031..a182509 100644
  
  // For grouping opcodes into subsections
  enum OpcodeClass {
-@@ -159,6 +163,10 @@ enum OperandClass {
+@@ -157,6 +161,10 @@ enum OperandClass {
  
      OperandOpcode,
  
@@ -396,7 +421,7 @@ index 78b1031..a182509 100644
      OperandCount
  };
  
-@@ -257,3 +265,5 @@ const char* AccessQualifierString(int attr);
+@@ -259,3 +267,5 @@ const char* AccessQualifierString(int attr);
  void PrintOperands(const OperandParameters& operands, int reservedOperands);
  
  };  // end namespace spv
index 28a7ca5..bdac21b 100644 (file)
@@ -379,6 +379,7 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
     case SPV_OPERAND_TYPE_LOOP_CONTROL:
+    case SPV_OPERAND_TYPE_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
     case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
index c08a0e8..01db4fe 100644 (file)
@@ -81,7 +81,7 @@ TEST_F(DimTest, WrongDim) {
 using ImageFormatTest = spvtest::TextToBinaryTestBase<
     ::testing::TestWithParam<EnumCase<SpvImageFormat>>>;
 
-TEST_P(ImageFormatTest, AnyImageFormat) {
+TEST_P(ImageFormatTest, AnyImageFormatAndNoAccessQualifier) {
   const std::string input =
       "%1 = OpTypeImage %2 1D 2 3 0 4 " + GetParam().name() + "\n";
   EXPECT_THAT(CompiledInstructions(input),
@@ -145,15 +145,44 @@ TEST_F(ImageFormatTest, WrongFormat) {
               Eq("Invalid image format 'xxyyzz'."));
 }
 
+// Test AccessQualifier enums via OpTypeImage.
+using ImageAccessQualifierTest = spvtest::TextToBinaryTestBase<
+    ::testing::TestWithParam<EnumCase<SpvAccessQualifier>>>;
+
+TEST_P(ImageAccessQualifierTest, AnyAccessQualifier) {
+  const std::string input =
+      "%1 = OpTypeImage %2 1D 2 3 0 4 Rgba8 " + GetParam().name() + "\n";
+  EXPECT_THAT(CompiledInstructions(input),
+              Eq(MakeInstruction(SpvOpTypeImage,
+                                 {1, 2, SpvDim1D, 2, 3, 0, 4,
+                                  SpvImageFormatRgba8, GetParam().value()})));
+  // Check the disassembler as well.
+  EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
+}
+
+// clang-format off
+#define CASE(NAME) {SpvAccessQualifier##NAME, #NAME}
+INSTANTIATE_TEST_CASE_P(
+    AccessQualifier, ImageAccessQualifierTest,
+    ::testing::ValuesIn(std::vector<EnumCase<SpvAccessQualifier>>{
+      CASE(ReadOnly),
+      CASE(WriteOnly),
+      CASE(ReadWrite),
+    }));
+// clang-format on
+#undef CASE
+
 // Test AccessQualifier enums via OpTypePipe.
 
 using OpTypePipeTest = spvtest::TextToBinaryTestBase<
     ::testing::TestWithParam<EnumCase<SpvAccessQualifier>>>;
 
 TEST_P(OpTypePipeTest, AnyAccessQualifier) {
-  const std::string input = "%1 = OpTypePipe " + GetParam().name();
+  const std::string input = "%1 = OpTypePipe " + GetParam().name() + "\n";
   EXPECT_THAT(CompiledInstructions(input),
               Eq(MakeInstruction(SpvOpTypePipe, {1, GetParam().value()})));
+  // Check the disassembler as well.
+  EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
 }
 
 // clang-format off