Autogenererating enum-string mappings from grammar
authorAndrey Tuganov <andreyt@google.com>
Wed, 15 Mar 2017 21:28:24 +0000 (17:28 -0400)
committerDavid Neto <dneto@google.com>
Thu, 16 Mar 2017 19:29:17 +0000 (15:29 -0400)
Autogenerating the following code:
- extension enum
- extension-to-string
- string-to-extension
- capability-to-string

Capability mapping table will not compile if incomplete.
TODO: Use "spirv-latest-version.h" instead of 1.1.

Added function to generate capability tables for tests.

13 files changed:
source/CMakeLists.txt
source/enum_string_mapping.cpp [new file with mode: 0644]
source/enum_string_mapping.h [new file with mode: 0644]
source/extensions.cpp
source/extensions.h
source/opt/CMakeLists.txt
source/validate.cpp
source/validate_instruction.cpp
test/CMakeLists.txt
test/enum_string_mapping_test.cpp [new file with mode: 0644]
test/val/val_extensions_test.cpp
tools/CMakeLists.txt
utils/generate_grammar_tables.py

index f8b5aa0..bd35a6e 100644 (file)
@@ -35,6 +35,22 @@ macro(spvtools_core_tables VERSION)
   list(APPEND OPERAND_CPP_DEPENDS ${GRAMMAR_KINDS_INC_FILE})
 endmacro(spvtools_core_tables)
 
+macro(spvtools_enum_string_mapping VERSION)
+  set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json")
+  set(GRAMMAR_EXTENSION_ENUM_INC_FILE "${spirv-tools_BINARY_DIR}/extension_enum.inc")
+  set(GRAMMAR_ENUM_STRING_MAPPING_INC_FILE "${spirv-tools_BINARY_DIR}/enum_string_mapping.inc")
+  add_custom_command(OUTPUT ${GRAMMAR_EXTENSION_ENUM_INC_FILE}
+     ${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}
+    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+      --spirv-core-grammar=${GRAMMAR_JSON_FILE}
+      --extension-enum-output=${GRAMMAR_EXTENSION_ENUM_INC_FILE}
+      --enum-string-mapping-output=${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}
+    DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${GRAMMAR_JSON_FILE}
+    COMMENT "Generate enum-string mapping for SPIR-V v${VERSION}.")
+  list(APPEND EXTENSION_H_DEPENDS ${GRAMMAR_EXTENSION_ENUM_INC_FILE})
+  list(APPEND ENUM_STRING_MAPPING_CPP_DEPENDS ${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE})
+endmacro(spvtools_enum_string_mapping)
+
 macro(spvtools_vimsyntax VERSION CLVERSION)
   set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json")
   set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.glsl.std.450.grammar.json")
@@ -81,6 +97,7 @@ endmacro(spvtools_opencl_tables)
 
 spvtools_core_tables("1.0")
 spvtools_core_tables("1.1")
+spvtools_enum_string_mapping("1.1")
 spvtools_opencl_tables("1.0")
 spvtools_glsl_tables("1.0")
 
@@ -122,6 +139,16 @@ set_source_files_properties(
 set_source_files_properties(
   ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp
   PROPERTIES OBJECT_DEPENDS "${EXTINST_CPP_DEPENDS}")
+set_source_files_properties(
+  ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.cpp
+  PROPERTIES OBJECT_DEPENDS "${ENUM_STRING_MAPPING_CPP_DEPENDS}")
+
+set_source_files_properties(
+  ${CMAKE_CURRENT_SOURCE_DIR}/extension.h
+  PROPERTIES HEADER_FILE_ONLY TRUE)
+set_source_files_properties(
+  ${CMAKE_CURRENT_SOURCE_DIR}/extension.h
+  PROPERTIES OBJECT_DEPENDS "${EXTENSION_H_DEPENDS}")
 
 set(SPIRV_TOOLS_BUILD_VERSION_INC
   ${spirv-tools_BINARY_DIR}/build-version.inc)
@@ -154,6 +181,7 @@ set(SPIRV_SOURCES
   ${CMAKE_CURRENT_SOURCE_DIR}/binary.h
   ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.h
   ${CMAKE_CURRENT_SOURCE_DIR}/enum_set.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.h
   ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.h
   ${CMAKE_CURRENT_SOURCE_DIR}/extensions.h
   ${CMAKE_CURRENT_SOURCE_DIR}/instruction.h
@@ -179,6 +207,7 @@ set(SPIRV_SOURCES
   ${CMAKE_CURRENT_SOURCE_DIR}/binary.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/extensions.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/libspirv.cpp
diff --git a/source/enum_string_mapping.cpp b/source/enum_string_mapping.cpp
new file mode 100644 (file)
index 0000000..ff40bd8
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (c) 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "enum_string_mapping.h"
+
+#include <cassert>
+#include <string>
+#include <unordered_map>
+
+#include "extensions.h"
+
+namespace libspirv {
+
+#include "enum_string_mapping.inc"
+
+}  // namespace libspirv
diff --git a/source/enum_string_mapping.h b/source/enum_string_mapping.h
new file mode 100644 (file)
index 0000000..773d40c
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_ENUM_STRING_MAPPING_H_
+#define LIBSPIRV_ENUM_STRING_MAPPING_H_
+
+#include <string>
+
+#include "spirv/1.1/spirv.h"
+
+namespace libspirv {
+
+enum class Extension;
+
+// Finds Extension enum corresponding to |str|. Returns false if not found.
+bool GetExtensionFromString(const std::string& str, Extension* extension);
+
+// Returns text string corresponding to |extension|.
+std::string ExtensionToString(Extension extension);
+
+// Returns text string corresponding to |capability|.
+std::string CapabilityToString(SpvCapability capability);
+
+}  // namespace libspirv
+
+#endif  // LIBSPIRV_ENUM_STRING_MAPPING_H_
index 75a5aee..260a15b 100644 (file)
@@ -18,6 +18,8 @@
 #include <sstream>
 #include <string>
 
+#include "enum_string_mapping.h"
+
 namespace libspirv {
 
 std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
@@ -33,65 +35,6 @@ std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
   return reinterpret_cast<const char*>(inst->words + operand.offset);
 }
 
-bool ParseSpvExtensionFromString(const std::string& str, Extension* extension) {
-  if (str == "SPV_KHR_shader_ballot") {
-    *extension = Extension::kSPV_KHR_shader_ballot;
-  } else if (str == "SPV_KHR_shader_draw_parameters") {
-    *extension = Extension::kSPV_KHR_shader_draw_parameters;
-  } else if (str == "SPV_KHR_subgroup_vote") {
-    *extension = Extension::kSPV_KHR_subgroup_vote;
-  } else if (str == "SPV_KHR_16bit_storage") {
-    *extension = Extension::kSPV_KHR_16bit_storage;
-  } else if (str == "SPV_KHR_device_group") {
-    *extension = Extension::kSPV_KHR_device_group;
-  } else if (str == "SPV_KHR_multiview") {
-    *extension = Extension::kSPV_KHR_multiview;
-  } else if (str == "SPV_NV_sample_mask_override_coverage") {
-    *extension = Extension::kSPV_NV_sample_mask_override_coverage;
-  } else if (str == "SPV_NV_geometry_shader_passthrough") {
-    *extension = Extension::kSPV_NV_geometry_shader_passthrough;
-  } else if (str == "SPV_NV_viewport_array2") {
-    *extension = Extension::kSPV_NV_viewport_array2;
-  } else if (str == "SPV_NV_stereo_view_rendering") {
-    *extension = Extension::kSPV_NV_stereo_view_rendering;
-  } else if (str == "SPV_NVX_multiview_per_view_attributes") {
-    *extension = Extension::kSPV_NVX_multiview_per_view_attributes;
-  } else {
-    return false;
-  }
-
-  return true;
-}
-
-std::string ExtensionToString(Extension extension) {
-  switch (extension) {
-    case Extension::kSPV_KHR_shader_ballot:
-      return "SPV_KHR_shader_ballot";
-    case Extension::kSPV_KHR_shader_draw_parameters:
-      return "SPV_KHR_shader_draw_parameters";
-    case Extension::kSPV_KHR_subgroup_vote:
-      return "SPV_KHR_subgroup_vote";
-    case Extension::kSPV_KHR_16bit_storage:
-      return "SPV_KHR_16bit_storage";
-    case Extension::kSPV_KHR_device_group:
-      return "SPV_KHR_device_group";
-    case Extension::kSPV_KHR_multiview:
-      return "SPV_KHR_multiview";
-    case Extension::kSPV_NV_sample_mask_override_coverage:
-      return "SPV_NV_sample_mask_override_coverage";
-    case Extension::kSPV_NV_geometry_shader_passthrough:
-      return "SPV_NV_geometry_shader_passthrough";
-    case Extension::kSPV_NV_viewport_array2:
-      return "SPV_NV_viewport_array2";
-    case Extension::kSPV_NV_stereo_view_rendering:
-      return "SPV_NV_stereo_view_rendering";
-    case Extension::kSPV_NVX_multiview_per_view_attributes:
-      return "SPV_NVX_multiview_per_view_attributes";
-  }
-
-  return "ERROR_unknown_extension";
-}
-
 std::string ExtensionSetToString(const ExtensionSet& extensions) {
   std::stringstream ss;
   extensions.ForEach([&ss](Extension ext) {
index 8101182..2eee7cf 100644 (file)
 namespace libspirv {
 
 // The known SPIR-V extensions.
-// TODO(dneto): Consider auto-generating this list?
-// When updating this list, consider also updating ParseSpvExtensionFromString
-// and SpvExtensionToString.
 enum class Extension {
-  kSPV_KHR_shader_ballot,
-  kSPV_KHR_shader_draw_parameters,
-  kSPV_KHR_subgroup_vote,
-  kSPV_KHR_16bit_storage,
-  kSPV_KHR_device_group,
-  kSPV_KHR_multiview,
-  kSPV_NV_sample_mask_override_coverage,
-  kSPV_NV_geometry_shader_passthrough,
-  kSPV_NV_viewport_array2,
-  kSPV_NV_stereo_view_rendering,
-  kSPV_NVX_multiview_per_view_attributes,
+#include "extension_enum.inc"
 };
 
 using ExtensionSet = EnumSet<Extension>;
@@ -45,12 +32,6 @@ using ExtensionSet = EnumSet<Extension>;
 // Returns literal string operand of OpExtension instruction.
 std::string GetExtensionString(const spv_parsed_instruction_t* inst);
 
-// Finds Extension enum corresponding to |str|. Returns false if not found.
-bool ParseSpvExtensionFromString(const std::string& str, Extension* extension);
-
-// Returns text string corresponding to |extension|.
-std::string ExtensionToString(Extension extension);
-
 // Returns text string listing |extensions| separated by whitespace.
 std::string ExtensionSetToString(const ExtensionSet& extensions);
 
index 7bc47ac..f1420e8 100644 (file)
@@ -57,6 +57,7 @@ spvtools_default_compile_options(SPIRV-Tools-opt)
 target_include_directories(SPIRV-Tools-opt
   PUBLIC ${spirv-tools_SOURCE_DIR}/include
   PUBLIC ${SPIRV_HEADER_INCLUDE_DIR}
+  PRIVATE ${spirv-tools_BINARY_DIR}
 )
 # We need the assembling and disassembling functionalities in the main library.
 target_link_libraries(SPIRV-Tools-opt
index b4c8535..21a3855 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "binary.h"
 #include "diagnostic.h"
+#include "enum_string_mapping.h"
 #include "extensions.h"
 #include "instruction.h"
 #include "opcode.h"
@@ -124,7 +125,7 @@ void RegisterExtension(ValidationState_t& _,
                        const spv_parsed_instruction_t* inst) {
   const std::string extension_str = libspirv::GetExtensionString(inst);
   Extension extension;
-  if (!ParseSpvExtensionFromString(extension_str, &extension)) {
+  if (!GetExtensionFromString(extension_str, &extension)) {
     // The error will be logged in the ProcessInstruction pass.
     return;
   }
index fcd9dce..49d2113 100644 (file)
@@ -25,6 +25,7 @@
 #include "binary.h"
 #include "diagnostic.h"
 #include "enum_set.h"
+#include "enum_string_mapping.h"
 #include "extensions.h"
 #include "opcode.h"
 #include "operand.h"
@@ -383,7 +384,7 @@ void CheckIfKnownExtension(ValidationState_t& _,
                            const spv_parsed_instruction_t* inst) {
   const std::string extension_str = GetExtensionString(inst);
   Extension extension;
-  if (!ParseSpvExtensionFromString(extension_str, &extension)) {
+  if (!GetExtensionFromString(extension_str, &extension)) {
     _.diag(SPV_SUCCESS) << "Found unrecognized extension " << extension_str;
     return;
   }
index 10b4cb0..79c2684 100644 (file)
@@ -52,6 +52,7 @@ function(add_spvtools_unittest)
       ${spirv-tools_SOURCE_DIR}
       ${spirv-tools_SOURCE_DIR}/include
       ${spirv-tools_SOURCE_DIR}/test
+      ${spirv-tools_BINARY_DIR}
       ${gtest_SOURCE_DIR}/include
       ${gmock_SOURCE_DIR}/include
     )
@@ -75,6 +76,7 @@ set(TEST_SOURCES
   binary_to_text_test.cpp
   binary_to_text.literal_test.cpp
   comment_test.cpp
+  enum_string_mapping_test.cpp
   enum_set_test.cpp
   ext_inst.glsl_test.cpp
   ext_inst.opencl_test.cpp
diff --git a/test/enum_string_mapping_test.cpp b/test/enum_string_mapping_test.cpp
new file mode 100644 (file)
index 0000000..be1b77d
--- /dev/null
@@ -0,0 +1,249 @@
+// Copyright (c) 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Tests for OpExtension validator rules.
+
+#include <string>
+
+#include "enum_string_mapping.h"
+#include "extensions.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using ::libspirv::Extension;
+
+using ::testing::Values;
+using ::testing::ValuesIn;
+
+using ExtensionTest = ::testing::TestWithParam<std::pair<Extension, std::string>>;
+using UnknownExtensionTest = ::testing::TestWithParam<std::string>;
+using CapabilityTest = ::testing::TestWithParam<std::pair<SpvCapability, std::string>>;
+
+TEST_P(ExtensionTest, TestExtensionFromString) {
+  const std::pair<Extension, std::string>& param = GetParam();
+  const Extension extension = param.first;
+  const std::string extension_str = param.second;
+  Extension result_extension;
+  ASSERT_TRUE(libspirv::GetExtensionFromString(extension_str, &result_extension));
+  EXPECT_EQ(extension, result_extension);
+}
+
+TEST_P(ExtensionTest, TestExtensionToString) {
+  const std::pair<Extension, std::string>& param = GetParam();
+  const Extension extension = param.first;
+  const std::string extension_str = param.second;
+  const std::string result_str = libspirv::ExtensionToString(extension);
+  EXPECT_EQ(extension_str, result_str);
+}
+
+TEST_P(UnknownExtensionTest, TestExtensionFromStringFails) {
+  Extension result_extension;
+  ASSERT_FALSE(libspirv::GetExtensionFromString(GetParam(), &result_extension));
+}
+
+TEST_P(CapabilityTest, TestCapabilityToString) {
+  const std::pair<SpvCapability, std::string>& param = GetParam();
+  const SpvCapability capability = param.first;
+  const std::string capability_str = param.second;
+  const std::string result_str = libspirv::CapabilityToString(capability);
+  EXPECT_EQ(capability_str, result_str);
+}
+
+INSTANTIATE_TEST_CASE_P(AllExtensions, ExtensionTest,
+    ValuesIn(std::vector<std::pair<Extension, std::string>>({
+      {Extension::kSPV_KHR_16bit_storage,
+        "SPV_KHR_16bit_storage"},
+      {Extension::kSPV_KHR_device_group,
+        "SPV_KHR_device_group"},
+      {Extension::kSPV_KHR_multiview,
+        "SPV_KHR_multiview"},
+      {Extension::kSPV_KHR_shader_ballot,
+        "SPV_KHR_shader_ballot"},
+      {Extension::kSPV_KHR_shader_draw_parameters,
+        "SPV_KHR_shader_draw_parameters"},
+      {Extension::kSPV_KHR_subgroup_vote,
+        "SPV_KHR_subgroup_vote"},
+      {Extension::kSPV_NVX_multiview_per_view_attributes,
+        "SPV_NVX_multiview_per_view_attributes"},
+      {Extension::kSPV_NV_geometry_shader_passthrough,
+        "SPV_NV_geometry_shader_passthrough"},
+      {Extension::kSPV_NV_sample_mask_override_coverage,
+        "SPV_NV_sample_mask_override_coverage"},
+      {Extension::kSPV_NV_stereo_view_rendering,
+        "SPV_NV_stereo_view_rendering"},
+      {Extension::kSPV_NV_viewport_array2,
+        "SPV_NV_viewport_array2"}
+    })));
+
+INSTANTIATE_TEST_CASE_P(UnknownExtensions, UnknownExtensionTest, Values(
+      "",
+      "SPV_KHR_",
+      "SPV_KHR_device_group_ERROR",
+      "SPV_ERROR_random_string_hfsdklhlktherh"
+    ));
+
+INSTANTIATE_TEST_CASE_P(AllCapabilities, CapabilityTest,
+    ValuesIn(std::vector<std::pair<SpvCapability, std::string>>({
+      {SpvCapabilityMatrix,
+       "Matrix"},
+      {SpvCapabilityShader,
+       "Shader"},
+      {SpvCapabilityGeometry,
+       "Geometry"},
+      {SpvCapabilityTessellation,
+       "Tessellation"},
+      {SpvCapabilityAddresses,
+       "Addresses"},
+      {SpvCapabilityLinkage,
+       "Linkage"},
+      {SpvCapabilityKernel,
+       "Kernel"},
+      {SpvCapabilityVector16,
+       "Vector16"},
+      {SpvCapabilityFloat16Buffer,
+       "Float16Buffer"},
+      {SpvCapabilityFloat16,
+       "Float16"},
+      {SpvCapabilityFloat64,
+       "Float64"},
+      {SpvCapabilityInt64,
+       "Int64"},
+      {SpvCapabilityInt64Atomics,
+       "Int64Atomics"},
+      {SpvCapabilityImageBasic,
+       "ImageBasic"},
+      {SpvCapabilityImageReadWrite,
+       "ImageReadWrite"},
+      {SpvCapabilityImageMipmap,
+       "ImageMipmap"},
+      {SpvCapabilityPipes,
+       "Pipes"},
+      {SpvCapabilityGroups,
+       "Groups"},
+      {SpvCapabilityDeviceEnqueue,
+       "DeviceEnqueue"},
+      {SpvCapabilityLiteralSampler,
+       "LiteralSampler"},
+      {SpvCapabilityAtomicStorage,
+       "AtomicStorage"},
+      {SpvCapabilityInt16,
+       "Int16"},
+      {SpvCapabilityTessellationPointSize,
+       "TessellationPointSize"},
+      {SpvCapabilityGeometryPointSize,
+       "GeometryPointSize"},
+      {SpvCapabilityImageGatherExtended,
+       "ImageGatherExtended"},
+      {SpvCapabilityStorageImageMultisample,
+       "StorageImageMultisample"},
+      {SpvCapabilityUniformBufferArrayDynamicIndexing,
+       "UniformBufferArrayDynamicIndexing"},
+      {SpvCapabilitySampledImageArrayDynamicIndexing,
+       "SampledImageArrayDynamicIndexing"},
+      {SpvCapabilityStorageBufferArrayDynamicIndexing,
+       "StorageBufferArrayDynamicIndexing"},
+      {SpvCapabilityStorageImageArrayDynamicIndexing,
+       "StorageImageArrayDynamicIndexing"},
+      {SpvCapabilityClipDistance,
+       "ClipDistance"},
+      {SpvCapabilityCullDistance,
+       "CullDistance"},
+      {SpvCapabilityImageCubeArray,
+       "ImageCubeArray"},
+      {SpvCapabilitySampleRateShading,
+       "SampleRateShading"},
+      {SpvCapabilityImageRect,
+       "ImageRect"},
+      {SpvCapabilitySampledRect,
+       "SampledRect"},
+      {SpvCapabilityGenericPointer,
+       "GenericPointer"},
+      {SpvCapabilityInt8,
+       "Int8"},
+      {SpvCapabilityInputAttachment,
+       "InputAttachment"},
+      {SpvCapabilitySparseResidency,
+       "SparseResidency"},
+      {SpvCapabilityMinLod,
+       "MinLod"},
+      {SpvCapabilitySampled1D,
+       "Sampled1D"},
+      {SpvCapabilityImage1D,
+       "Image1D"},
+      {SpvCapabilitySampledCubeArray,
+       "SampledCubeArray"},
+      {SpvCapabilitySampledBuffer,
+       "SampledBuffer"},
+      {SpvCapabilityImageBuffer,
+       "ImageBuffer"},
+      {SpvCapabilityImageMSArray,
+       "ImageMSArray"},
+      {SpvCapabilityStorageImageExtendedFormats,
+       "StorageImageExtendedFormats"},
+      {SpvCapabilityImageQuery,
+       "ImageQuery"},
+      {SpvCapabilityDerivativeControl,
+       "DerivativeControl"},
+      {SpvCapabilityInterpolationFunction,
+       "InterpolationFunction"},
+      {SpvCapabilityTransformFeedback,
+       "TransformFeedback"},
+      {SpvCapabilityGeometryStreams,
+       "GeometryStreams"},
+      {SpvCapabilityStorageImageReadWithoutFormat,
+       "StorageImageReadWithoutFormat"},
+      {SpvCapabilityStorageImageWriteWithoutFormat,
+       "StorageImageWriteWithoutFormat"},
+      {SpvCapabilityMultiViewport,
+       "MultiViewport"},
+      {SpvCapabilitySubgroupDispatch,
+       "SubgroupDispatch"},
+      {SpvCapabilityNamedBarrier,
+       "NamedBarrier"},
+      {SpvCapabilityPipeStorage,
+       "PipeStorage"},
+      {SpvCapabilitySubgroupBallotKHR,
+       "SubgroupBallotKHR"},
+      {SpvCapabilityDrawParameters,
+       "DrawParameters"},
+      {SpvCapabilitySubgroupVoteKHR,
+       "SubgroupVoteKHR"},
+      {SpvCapabilityStorageUniformBufferBlock16,
+       "StorageUniformBufferBlock16"},
+      {SpvCapabilityStorageUniform16,
+       "StorageUniform16"},
+      {SpvCapabilityStoragePushConstant16,
+       "StoragePushConstant16"},
+      {SpvCapabilityStorageInputOutput16,
+       "StorageInputOutput16"},
+      {SpvCapabilityDeviceGroup,
+       "DeviceGroup"},
+      {SpvCapabilityMultiView,
+       "MultiView"},
+      {SpvCapabilitySampleMaskOverrideCoverageNV,
+       "SampleMaskOverrideCoverageNV"},
+      {SpvCapabilityGeometryShaderPassthroughNV,
+       "GeometryShaderPassthroughNV"},
+      {SpvCapabilityShaderViewportIndexLayerNV,
+       "ShaderViewportIndexLayerNV"},
+      {SpvCapabilityShaderViewportMaskNV,
+       "ShaderViewportMaskNV"},
+      {SpvCapabilityShaderStereoViewNV,
+       "ShaderStereoViewNV"},
+      {SpvCapabilityPerViewAttributesNV,
+       "PerViewAttributesNV"}
+    })));
+
+}  // anonymous namespace
index e452532..d43e89f 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <string>
 
+#include "enum_string_mapping.h"
 #include "extensions.h"
 #include "gmock/gmock.h"
 #include "test_fixture.h"
@@ -81,14 +82,6 @@ TEST_P(ValidateUnknownExtensions, FailSilently) {
   EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(extension)));
 }
 
-TEST_P(ValidateKnownExtensions, ToAndFromString) {
-  const std::string extension_str = GetParam();
-  Extension extension;
-  ASSERT_TRUE(ParseSpvExtensionFromString(extension_str, &extension));
-  const std::string result_str = ExtensionToString(extension);
-  EXPECT_EQ(extension_str, result_str);
-}
-
 TEST_F(ValidateExtensionCapabilities, DeclCapabilitySuccess) {
   const string str =
       "OpCapability Shader\nOpCapability Linkage\nOpCapability DeviceGroup\n"
index 44c2201..ac680f8 100644 (file)
@@ -30,7 +30,10 @@ function(add_spvtools_tool)
   add_executable(${ARG_TARGET} ${ARG_SRCS})
   spvtools_default_compile_options(${ARG_TARGET})
   target_link_libraries(${ARG_TARGET} PRIVATE ${ARG_LIBS})
-  target_include_directories(${ARG_TARGET} PRIVATE ${spirv-tools_SOURCE_DIR})
+  target_include_directories(${ARG_TARGET} PRIVATE
+    ${spirv-tools_SOURCE_DIR}
+    ${spirv-tools_BINARY_DIR}
+)
 endfunction()
 
 if (NOT ${SPIRV_SKIP_EXECUTABLES})
index 823fcbf..7ee70e3 100755 (executable)
@@ -348,6 +348,111 @@ def generate_operand_kind_table(enums):
     return '\n\n'.join(enum_entries + (table,))
 
 
+def get_extension_list(operands):
+    """Returns extensions as an alphabetically sorted list of strings."""
+    enumerants = sum([item.get('enumerants', []) for item in operands
+                      if item.get('category') in ['ValueEnum']], [])
+
+    extensions = sum([item.get('extensions', []) for item in enumerants
+                      if item.get('extensions')], [])
+
+    return sorted(set(extensions))
+
+
+def get_capability_list(operands):
+    """Returns capabilities as a list of strings in the order of appearance."""
+    enumerants = sum([item.get('enumerants', []) for item in operands
+                      if item.get('kind') in ['Capability']], [])
+    return [item.get('enumerant') for item in enumerants]
+
+
+def generate_extension_enum(operands):
+    """Returns enumeration containing extensions declared in the grammar."""
+    extensions = get_extension_list(operands)
+    return ',\n'.join(['k' + extension for extension in extensions])
+
+
+def generate_extension_to_string_table(operands):
+    """Returns extension to string mapping table."""
+    extensions = get_extension_list(operands)
+    entry_template = '  {{Extension::k{extension},\n   "{extension}"}}'
+    table_entries = [entry_template.format(extension=extension)
+                     for extension in extensions]
+    table_template = '{{\n{enums}\n}}'
+    return table_template.format(enums=',\n'.join(table_entries))
+
+
+def generate_string_to_extension_table(operands):
+    """Returns string to extension mapping table."""
+    extensions = get_extension_list(operands)
+    entry_template = '  {{"{extension}",\n   Extension::k{extension}}}'
+    table_entries = [entry_template.format(extension=extension)
+                     for extension in extensions]
+    table_template = '{{\n{enums}\n}}'
+    return table_template.format(enums=',\n'.join(table_entries))
+
+
+def generate_capability_to_string_table(operands):
+    """Returns capability to string mapping table."""
+    capabilities = get_capability_list(operands)
+    entry_template = '  {{SpvCapability{capability},\n   "{capability}"}}'
+    table_entries = [entry_template.format(capability=capability)
+                     for capability in capabilities]
+    table_template = '{{\n{enums}\n}}'
+    return table_template.format(enums=',\n'.join(table_entries))
+
+
+def generate_extension_to_string_mapping(operands):
+    """Returns mapping function from extensions to corresponding strings."""
+    extensions = get_extension_list(operands)
+    function = 'std::string ExtensionToString(Extension extension) {\n'
+    function += '  switch (extension) {\n'
+    template = '    case Extension::k{extension}:\n' \
+        '      return "{extension}";\n'
+    function += ''.join([template.format(extension=extension)
+                         for extension in extensions])
+    function += '  };\n\n  return "";\n}'
+    return function
+
+
+def generate_string_to_extension_mapping(operands):
+    """Returns mapping function from strings to corresponding extensions."""
+    function = 'bool GetExtensionFromString(' \
+        'const std::string& str, Extension* extension) {\n ' \
+        'static const std::unordered_map<std::string, Extension> mapping =\n'
+    function += generate_string_to_extension_table(operands)
+    function += ';\n\n'
+    function += '  const auto it = mapping.find(str);\n\n' \
+        '  if (it == mapping.end()) return false;\n\n' \
+        '  *extension = it->second;\n  return true;\n}'
+    return function
+
+
+def generate_capability_to_string_mapping(operands):
+    """Returns mapping function from capabilities to corresponding strings."""
+    capabilities = get_capability_list(operands)
+    function = 'std::string CapabilityToString(SpvCapability capability) {\n'
+    function += '  switch (capability) {\n'
+    template = '    case SpvCapability{capability}:\n' \
+        '      return "{capability}";\n'
+    function += ''.join([template.format(capability=capability)
+                         for capability in capabilities])
+    function += '    case SpvCapabilityMax:\n' \
+        '      assert(0 && "Attempting to convert SpvCapabilityMax to string");\n' \
+        '      return "";\n'
+    function += '  };\n\n  return "";\n}'
+    return function
+
+
+def generate_all_string_enum_mappings(operands):
+    """Returns all string-to-enum / enum-to-string mapping tables."""
+    tables = []
+    tables.append(generate_extension_to_string_mapping(operands))
+    tables.append(generate_string_to_extension_mapping(operands))
+    tables.append(generate_capability_to_string_mapping(operands))
+    return '\n\n'.join(tables)
+
+
 def main():
     import argparse
     parser = argparse.ArgumentParser(description='Generate SPIR-V info tables')
@@ -375,6 +480,12 @@ def main():
     parser.add_argument('--operand-kinds-output', metavar='<path>',
                         type=str, required=False, default=None,
                         help='output file for operand kinds')
+    parser.add_argument('--extension-enum-output', metavar='<path>',
+                        type=str, required=False, default=None,
+                        help='output file for extension enumeration')
+    parser.add_argument('--enum-string-mapping-output', metavar='<path>',
+                        type=str, required=False, default=None,
+                        help='output file for enum-string mappings')
     args = parser.parse_args()
 
     if (args.core_insts_output is None) != \
@@ -394,7 +505,9 @@ def main():
         exit(1)
     if all([args.core_insts_output is None,
             args.glsl_insts_output is None,
-            args.opencl_insts_output is None]):
+            args.opencl_insts_output is None,
+            args.extension_enum_output is None,
+            args.enum_string_mapping_output is None]):
         print('error: at least one output should be specified.')
         exit(1)
 
@@ -407,6 +520,15 @@ def main():
                   file=open(args.core_insts_output, 'w'))
             print(generate_operand_kind_table(grammar['operand_kinds']),
                   file=open(args.operand_kinds_output, 'w'))
+        if args.extension_enum_output is not None:
+            make_path_to_file(args.extension_enum_output)
+            print(generate_extension_enum(grammar['operand_kinds']),
+                  file=open(args.extension_enum_output, 'w'))
+        if args.enum_string_mapping_output is not None:
+            make_path_to_file(args.enum_string_mapping_output)
+            print(generate_all_string_enum_mappings(
+                      grammar['operand_kinds']),
+                  file=open(args.enum_string_mapping_output, 'w'))
 
     if args.extinst_glsl_grammar is not None:
         with open(args.extinst_glsl_grammar) as json_file: