Support SPV_AMD_gcn_shader
authorDavid Neto <dneto@google.com>
Tue, 21 Mar 2017 16:43:26 +0000 (12:43 -0400)
committerDavid Neto <dneto@google.com>
Thu, 23 Mar 2017 20:32:35 +0000 (16:32 -0400)
Supported in assembler, disassembler, and binary parser.

The validator does not check SPV_AMD_gcn_shader validation rules
beyond parsing the extension.

Adds generic support for generating instruction tables for vendor
extensions.

Adds generic support for extensions the validator should recognize
(but not check) but which aren't derived from the SPIR-V core
grammar file.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/594

include/spirv-tools/libspirv.h
source/CMakeLists.txt
source/ext_inst.cpp
source/extinst.amd-gcn-shader.grammar.json [new file with mode: 0644]
test/text_to_binary.extension_test.cpp
test/val/val_extensions_test.cpp
utils/generate_grammar_tables.py

index 8052c1c..1d7247f 100644 (file)
@@ -227,6 +227,7 @@ typedef enum spv_ext_inst_type_t {
   SPV_EXT_INST_TYPE_NONE = 0,
   SPV_EXT_INST_TYPE_GLSL_STD_450,
   SPV_EXT_INST_TYPE_OPENCL_STD,
+  SPV_EXT_INST_TYPE_SPV_AMD_GCN_SHADER,
 
   SPV_FORCE_32_BIT_ENUM(spv_ext_inst_type_t)
 } spv_ext_inst_type_t;
index 56d13c8..5586216 100644 (file)
@@ -95,11 +95,25 @@ macro(spvtools_opencl_tables VERSION)
   list(APPEND EXTINST_CPP_DEPENDS ${GRAMMAR_INC_FILE})
 endmacro(spvtools_opencl_tables)
 
+macro(spvtools_vendor_tables VENDOR_TABLE)
+  set(INSTS_FILE "${spirv-tools_BINARY_DIR}/${VENDOR_TABLE}.insts.inc")
+  set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json")
+  add_custom_command(OUTPUT ${INSTS_FILE}
+    COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
+      --extinst-vendor-grammar=${GRAMMAR_FILE}
+      --vendor-insts-output=${INSTS_FILE}
+    DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${GRAMMAR_FILE}
+    COMMENT "Generate extended instruction tables for ${VENDOR_TABLE}.")
+  list(APPEND EXTINST_CPP_DEPENDS ${INSTS_FILE})
+  add_custom_target(spirv-tools-${VENDOR_TABLE} DEPENDS ${INSTS_FILE})
+endmacro(spvtools_vendor_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")
+spvtools_vendor_tables("amd-gcn-shader")
 
 spvtools_vimsyntax("1.1" "1.0")
 add_custom_target(spirv-tools-vimsyntax DEPENDS ${VIMSYNTAX_FILE})
index 9b5d0ca..3cac7ac 100644 (file)
@@ -31,6 +31,10 @@ static const spv_ext_inst_desc_t openclEntries_1_0[] = {
 #include "opencl.std.insts-1.0.inc"
 };
 
+static const spv_ext_inst_desc_t amd_gcn_shader_entries[] = {
+#include "amd-gcn-shader.insts.inc"
+};
+
 spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable,
                                 spv_target_env env) {
   if (!pExtInstTable) return SPV_ERROR_INVALID_POINTER;
@@ -40,6 +44,8 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable,
        glslStd450Entries_1_0},
       {SPV_EXT_INST_TYPE_OPENCL_STD, ARRAY_SIZE(openclEntries_1_0),
        openclEntries_1_0},
+      {SPV_EXT_INST_TYPE_SPV_AMD_GCN_SHADER, ARRAY_SIZE(amd_gcn_shader_entries),
+       amd_gcn_shader_entries},
   };
 
   static const spv_ext_inst_table_t table_1_0 = {ARRAY_SIZE(groups_1_0),
@@ -74,6 +80,9 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) {
   if (!strcmp("OpenCL.std", name)) {
     return SPV_EXT_INST_TYPE_OPENCL_STD;
   }
+  if (!strcmp("SPV_AMD_gcn_shader", name)) {
+    return SPV_EXT_INST_TYPE_SPV_AMD_GCN_SHADER;
+  }
   return SPV_EXT_INST_TYPE_NONE;
 }
 
diff --git a/source/extinst.amd-gcn-shader.grammar.json b/source/extinst.amd-gcn-shader.grammar.json
new file mode 100644 (file)
index 0000000..275186b
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "revision" : 2,
+  "instructions" : [
+    {
+      "opname" : "CubeFaceIndexAMD",
+      "opcode" : 1,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'P'" }
+      ],
+      "extensions" : [ "SPV_KHR_gcn_shader" ]
+    },
+    {
+      "opname" : "CubeFaceCoordAMD",
+      "opcode" : 2,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'P'" }
+      ],
+      "extensions" : [ "SPV_KHR_gcn_shader" ]
+    },
+    {
+      "opname" : "TimeAMD",
+      "opcode" : 3,
+      "extensions" : [ "SPV_KHR_gcn_shader" ]
+    }
+  ]
+}
index 93fc0e5..7614034 100644 (file)
@@ -243,4 +243,29 @@ INSTANTIATE_TEST_CASE_P(
                                                  SpvBuiltInViewIndex})},
             })), );
 
+// SPV_AMD_gcn_shader
+
+#define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n"
+INSTANTIATE_TEST_CASE_P(
+    SPV_AMD_gcn_shader, ExtensionRoundTripTest,
+    // We'll get coverage over operand tables by trying the universal
+    // environments, and at least one specific environment.
+    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
+                   SPV_ENV_VULKAN_1_0),
+            ValuesIn(std::vector<AssemblyCase>{
+                {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceCoordAMD %4\n",
+                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
+                                              MakeVector("SPV_AMD_gcn_shader")),
+                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4})})},
+                {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceIndexAMD %4\n",
+                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
+                                              MakeVector("SPV_AMD_gcn_shader")),
+                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4})})},
+                {PREAMBLE "%3 = OpExtInst %2 %1 TimeAMD\n",
+                 Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
+                                              MakeVector("SPV_AMD_gcn_shader")),
+                              MakeInstruction(SpvOpExtInst, {2, 3, 1, 3})})},
+            })), );
+#undef PREAMBLE
+
 }  // anonymous namespace
index d43e89f..1afc0c4 100644 (file)
@@ -43,6 +43,7 @@ string GetErrorString(const std::string& extension) {
 }
 
 INSTANTIATE_TEST_CASE_P(ExpectSuccess, ValidateKnownExtensions, Values(
+    "SPV_AMD_gcn_shader",
     "SPV_KHR_shader_ballot",
     "SPV_KHR_shader_draw_parameters",
     "SPV_KHR_subgroup_vote",
index 7ee70e3..fc7e56c 100755 (executable)
@@ -25,6 +25,9 @@ import re
 # Prefix for all C variables generated by this script.
 PYGEN_VARIABLE_PREFIX = 'pygen_variable'
 
+# Extensions to recognize, but which don't come from the SPIRV-V core grammar.
+NONSTANDARD_EXTENSIONS = ['SPV_AMD_gcn_shader',]
+
 def make_path_to_file(f):
     """Makes all ancestor directories to the given file, if they
     don't yet exist.
@@ -356,6 +359,8 @@ def get_extension_list(operands):
     extensions = sum([item.get('extensions', []) for item in enumerants
                       if item.get('extensions')], [])
 
+    extensions.extend(NONSTANDARD_EXTENSIONS)
+
     return sorted(set(extensions))
 
 
@@ -457,7 +462,7 @@ def main():
     import argparse
     parser = argparse.ArgumentParser(description='Generate SPIR-V info tables')
     parser.add_argument('--spirv-core-grammar', metavar='<path>',
-                        type=str, required=True,
+                        type=str, required=False,
                         help='input JSON grammar file for core SPIR-V '
                         'instructions')
     parser.add_argument('--extinst-glsl-grammar', metavar='<path>',
@@ -466,7 +471,7 @@ def main():
                         'instruction set')
     parser.add_argument('--extinst-opencl-grammar', metavar='<path>',
                         type=str, required=False, default=None,
-                        help='input JSON grammar file for OpenGL extended '
+                        help='input JSON grammar file for OpenCL extended '
                         'instruction set')
     parser.add_argument('--core-insts-output', metavar='<path>',
                         type=str, required=False, default=None,
@@ -486,6 +491,13 @@ def main():
     parser.add_argument('--enum-string-mapping-output', metavar='<path>',
                         type=str, required=False, default=None,
                         help='output file for enum-string mappings')
+    parser.add_argument('--extinst-vendor-grammar', metavar='<path>',
+                        type=str, required=False, default=None,
+                        help='input JSON grammar file for vendor extended '
+                        'instruction set'),
+    parser.add_argument('--vendor-insts-output', metavar='<path>',
+                        type=str, required=False, default=None,
+                        help='output file for vendor extended instruction set')
     args = parser.parse_args()
 
     if (args.core_insts_output is None) != \
@@ -503,32 +515,39 @@ def main():
         print('error: --opencl-insts-output and --extinst-opencl-grammar '
               'should be specified together.')
         exit(1)
+    if (args.vendor_insts_output is None) != \
+            (args.extinst_vendor_grammar is None):
+        print('error: --vendor-insts-output and '
+              '--extinst-vendor-grammar should be specified together.')
+        exit(1)
     if all([args.core_insts_output is None,
             args.glsl_insts_output is None,
             args.opencl_insts_output is None,
+            args.vendor_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)
 
-    with open(args.spirv_core_grammar) as json_file:
-        grammar = json.loads(json_file.read())
-        if args.core_insts_output is not None:
-            make_path_to_file(args.core_insts_output)
-            make_path_to_file(args.operand_kinds_output)
-            print(generate_instruction_table(grammar['instructions'], False),
-                  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.spirv_core_grammar is not None:
+        with open(args.spirv_core_grammar) as json_file:
+            grammar = json.loads(json_file.read())
+            if args.core_insts_output is not None:
+                make_path_to_file(args.core_insts_output)
+                make_path_to_file(args.operand_kinds_output)
+                print(generate_instruction_table(grammar['instructions'], False),
+                      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:
@@ -544,6 +563,13 @@ def main():
             print(generate_instruction_table(grammar['instructions'], True),
                   file=open(args.opencl_insts_output, 'w'))
 
+    if args.extinst_vendor_grammar is not None:
+        with open(args.extinst_vendor_grammar) as json_file:
+            grammar = json.loads(json_file.read())
+            make_path_to_file(args.vendor_insts_output)
+            print(generate_instruction_table(grammar['instructions'], True),
+                  file=open(args.vendor_insts_output, 'w'))
+
 
 if __name__ == '__main__':
     main()