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
This commit is contained in:
David Neto 2017-03-21 12:43:26 -04:00
Родитель fa834dea40
Коммит 7fe8a57a5b
7 изменённых файлов: 122 добавлений и 20 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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})

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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" ]
}
]
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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",

Просмотреть файл

@ -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()