Assembler support for image operands from Rev31
authorDavid Neto <dneto@google.com>
Fri, 18 Sep 2015 15:19:18 +0000 (11:19 -0400)
committerDavid Neto <dneto@google.com>
Mon, 26 Oct 2015 16:55:33 +0000 (12:55 -0400)
Rev32 and later add many more image operands, and
rearrange their values.

CMakeLists.txt
include/libspirv/libspirv.h
source/operand.cpp
source/text.cpp
test/TextToBinary.Image.cpp [new file with mode: 0644]

index 431300d..2609c15 100644 (file)
@@ -191,6 +191,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
       ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Debug.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Function.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Group.cpp
+      ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Image.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Literal.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Memory.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Miscellaneous.cpp
index af67d3e..293bdf8 100644 (file)
@@ -186,6 +186,8 @@ typedef enum spv_operand_type_t {
   // In an instruction definition, this may only appear at the end of the
   // operand types.
   SPV_OPERAND_TYPE_OPTIONAL_ID,
+  // An optional image operands mask.  A set bit in the mask may
+  // imply that more arguments are required.
   SPV_OPERAND_TYPE_OPTIONAL_IMAGE,
   // A literal number or string, but optional.
   // TODO(antiagainst): change to SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER.
index f0909b9..b3a53ee 100644 (file)
@@ -466,6 +466,31 @@ static const spv_operand_desc_t samplerImageFormatEntries[] = {
 #undef CASE
 };
 
+// Image operand definitions.  Each enum value is a mask.  When that mask
+// bit is set, the instruction should have further ID operands.
+// Some mask values depend on a capability.
+static const spv_operand_desc_t imageOperandEntries[] = {
+// Rev32 and later adds many more enums.
+#define CASE(NAME) \
+  #NAME, spv::ImageOperands##NAME##Mask, SPV_OPCODE_FLAGS_NONE, 0
+#define CASE_CAP(NAME, CAP) \
+  #NAME, spv::ImageOperands##NAME##Mask, SPV_OPCODE_FLAGS_CAPABILITIES, CAP
+#define ID SPV_OPERAND_TYPE_ID
+#define NONE SPV_OPERAND_TYPE_NONE
+    {"None", spv::ImageOperandsMaskNone, SPV_OPCODE_FLAGS_NONE, 0, {NONE}},
+    {CASE_CAP(Bias, CapabilityShader), {ID, NONE}},
+    {CASE(Lod), {ID, NONE}},
+    {CASE(Grad), {ID, ID, NONE}},
+    {CASE(ConstOffset), {ID, NONE}},
+    {CASE_CAP(Offset, CapabilityImageGatherExtended), {ID, NONE}},
+    {CASE(ConstOffsets), {ID, NONE}},
+    {CASE(Sample), {ID, NONE}},
+#undef CASE
+#undef CASE_CAP
+#undef ID
+#undef NONE
+};
+
 static const spv_operand_desc_t fpFastMathModeEntries[] = {
     {"None",
      FPFastMathModeMaskNone,
@@ -1392,6 +1417,9 @@ static const spv_operand_desc_group_t opcodeEntryTypes[] = {
     {SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT,
      sizeof(samplerImageFormatEntries) / sizeof(spv_operand_desc_t),
      samplerImageFormatEntries},
+    {SPV_OPERAND_TYPE_OPTIONAL_IMAGE,
+     sizeof(imageOperandEntries) / sizeof(spv_operand_desc_t),
+     imageOperandEntries},
     {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE,
      sizeof(fpFastMathModeEntries) / sizeof(spv_operand_desc_t),
      fpFastMathModeEntries},
@@ -1572,6 +1600,8 @@ const char *spvOperandTypeStr(spv_operand_type_t type) {
       return "kernel profiling info";
     case SPV_OPERAND_TYPE_CAPABILITY:
       return "capability";
+    case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
+      return "image operand";
     case SPV_OPERAND_TYPE_NONE:
       return "NONE";
     default:
index afb50a9..95b82d9 100644 (file)
@@ -560,12 +560,10 @@ spv_result_t spvTextEncodeOperand(
                                 pDiagnostic))
         return SPV_ERROR_INVALID_TEXT;
     } break;
-    case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
-      assert(0 && " Handle optional optional image operands");
-      break;
     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
     case SPV_OPERAND_TYPE_LOOP_CONTROL:
+    case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
     case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
       uint32_t value;
diff --git a/test/TextToBinary.Image.cpp b/test/TextToBinary.Image.cpp
new file mode 100644 (file)
index 0000000..911e056
--- /dev/null
@@ -0,0 +1,112 @@
+// 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.
+
+// Assembler tests for instructions in the "Image Instructions" section of
+// the SPIR-V spec.
+
+#include "UnitSPIRV.h"
+
+#include "gmock/gmock.h"
+#include "TestFixture.h"
+
+namespace {
+
+using spvtest::MakeInstruction;
+using ::testing::Eq;
+
+// An example case for a mask value with operands.
+struct ImageOperandsCase {
+  std::string image_operands;
+  // The expected mask, followed by its operands.
+  std::vector<uint32_t> expected_mask_and_operands;
+};
+
+// Test all kinds of image operands.
+
+using ImageOperandsTest = test_fixture::TextToBinaryTestBase<
+    ::testing::TestWithParam<ImageOperandsCase>>;
+
+TEST_P(ImageOperandsTest, Sample) {
+  std::string input =
+      "%result = OpImageFetch %type %image %coord " + GetParam().image_operands;
+  std::vector<uint32_t> expected_operands{1, 2, 3, 4};
+  expected_operands.insert(expected_operands.end(),
+                           GetParam().expected_mask_and_operands.begin(),
+                           GetParam().expected_mask_and_operands.end());
+  EXPECT_THAT(CompiledInstructions(input),
+              Eq(MakeInstruction(spv::OpImageFetch, expected_operands)));
+}
+
+#define MASK(NAME) spv::ImageOperands##NAME##Mask
+INSTANTIATE_TEST_CASE_P(
+    TextToBinaryImageOperandsAny, ImageOperandsTest,
+    ::testing::ValuesIn(std::vector<ImageOperandsCase>{
+        // TODO(dneto): Rev32 adds many more values, and rearranges their
+        // values.
+        // Image operands are optional.
+        {"", {}},
+        // Test each kind, alone.
+        {"Bias %5", {MASK(Bias), 5}},
+        {"Lod %10", {MASK(Lod), 10}},
+        {"Grad %11 %12", {MASK(Grad), 11, 12}},
+        {"ConstOffset %13", {MASK(ConstOffset), 13}},
+        {"Offset %14", {MASK(Offset), 14}},
+        {"ConstOffsets %15", {MASK(ConstOffsets), 15}},
+        {"Sample %16", {MASK(Sample), 16}},
+    }));
+
+INSTANTIATE_TEST_CASE_P(
+    TextToBinaryImageOperandsCombination, ImageOperandsTest,
+    ::testing::ValuesIn(std::vector<ImageOperandsCase>{
+        // TODO(dneto): Rev32 adds many more values, and rearranges their
+        // values.
+        // Test adjacent pairs, so we can easily debug the values when it fails.
+        {"Bias|Lod %10 %11", {MASK(Bias) | MASK(Lod), 10, 11}},
+        {"Lod|Grad %12 %13 %14", {MASK(Lod) | MASK(Grad), 12, 13, 14}},
+        {"Grad|ConstOffset %15 %16 %17",
+         {MASK(Grad) | MASK(ConstOffset), 15, 16, 17}},
+        {"ConstOffset|Offset %18 %19",
+         {MASK(ConstOffset) | MASK(Offset), 18, 19}},
+        {"Offset|ConstOffsets %20 %21",
+         {MASK(Offset) | MASK(ConstOffsets), 20, 21}},
+        {"ConstOffsets|Sample %22 %23",
+         {MASK(ConstOffsets) | MASK(Sample), 22, 23}},
+        // Test all masks together.
+        {"Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample"
+         " %5 %10 %11 %12 %13 %14 %15 %16",
+         {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
+              MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
+          5, 10, 11, 12, 13, 14, 15, 16}},
+        // The same, but with mask value names reversed.
+        {"Sample|ConstOffsets|Offset|ConstOffset|Grad|Lod|Bias"
+         " %5 %10 %11 %12 %13 %14 %15 %16",
+         {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
+              MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
+          5, 10, 11, 12, 13, 14, 15, 16}},
+    }));
+#undef MASK
+
+}  // anonymous namespace