mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
More automatic extension support
Update grammar table generation: - Get extensions from instructions, not just operand-kinds - Don't explicitly list extensions that come from the SPIR-V core grammar or from a KHR extended instruction set grammar. This makes it easier to support new extensions since the recommended extension strategy is to add instructions to the core grammar file. Also, test the validator has trivial support for passing through the extensions SPV_NV_shader_subgroup_partitioned and SPV_EXT_descriptor_indexing.
This commit is contained in:
parent
43ca2112b8
commit
082b8b08f1
@ -62,7 +62,8 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"SPV_KHR_shader_atomic_counter_ops", "SPV_EXT_shader_stencil_export",
|
||||
"SPV_EXT_shader_viewport_index_layer",
|
||||
"SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_fragment_mask",
|
||||
"SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1"));
|
||||
"SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_NV_shader_subgroup_partitioned", "SPV_EXT_descriptor_indexing"));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FailSilently, ValidateUnknownExtensions,
|
||||
Values("ERROR_unknown_extension", "SPV_KHR_",
|
||||
|
@ -25,39 +25,13 @@ import re
|
||||
PYGEN_VARIABLE_PREFIX = 'pygen_variable'
|
||||
|
||||
# Extensions to recognize, but which don't necessarily come from the SPIR-V
|
||||
# core grammar. Get this list from the SPIR-V registery web page.
|
||||
EXTENSIONS_FROM_SPIRV_REGISTRY = """
|
||||
SPV_AMD_shader_explicit_vertex_parameter
|
||||
SPV_AMD_shader_trinary_minmax
|
||||
# core or KHR grammar files. Get this list from the SPIR-V registery web page.
|
||||
# NOTE: Only put things on this list if it is not in those grammar files.
|
||||
EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS = """
|
||||
SPV_AMD_gcn_shader
|
||||
SPV_KHR_shader_ballot
|
||||
SPV_AMD_shader_ballot
|
||||
SPV_AMD_gpu_shader_half_float
|
||||
SPV_KHR_shader_draw_parameters
|
||||
SPV_KHR_subgroup_vote
|
||||
SPV_KHR_16bit_storage
|
||||
SPV_KHR_device_group
|
||||
SPV_KHR_multiview
|
||||
SPV_NVX_multiview_per_view_attributes
|
||||
SPV_NV_viewport_array2
|
||||
SPV_NV_stereo_view_rendering
|
||||
SPV_NV_sample_mask_override_coverage
|
||||
SPV_NV_geometry_shader_passthrough
|
||||
SPV_AMD_texture_gather_bias_lod
|
||||
SPV_KHR_storage_buffer_storage_class
|
||||
SPV_KHR_variable_pointers
|
||||
SPV_AMD_gpu_shader_int16
|
||||
SPV_KHR_post_depth_coverage
|
||||
SPV_KHR_shader_atomic_counter_ops
|
||||
SPV_EXT_shader_stencil_export
|
||||
SPV_EXT_shader_viewport_index_layer
|
||||
SPV_AMD_shader_image_load_store_lod
|
||||
SPV_AMD_shader_fragment_mask
|
||||
SPV_EXT_fragment_fully_covered
|
||||
SPV_AMD_gpu_shader_half_float_fetch
|
||||
SPV_GOOGLE_decorate_string
|
||||
SPV_GOOGLE_hlsl_functionality1
|
||||
SPV_NV_shader_subgroup_partitioned
|
||||
SPV_AMD_shader_trinary_minmax
|
||||
"""
|
||||
|
||||
|
||||
@ -242,6 +216,7 @@ class InstInitializer(object):
|
||||
- operands: a sequence of (operand-kind, operand-quantifier) tuples
|
||||
- version: minimal SPIR-V version required for this opcode
|
||||
"""
|
||||
|
||||
assert opname.startswith('Op')
|
||||
self.opname = opname[2:] # Remove the "Op" prefix.
|
||||
self.num_caps = len(caps)
|
||||
@ -524,15 +499,25 @@ def generate_operand_kind_table(enums):
|
||||
return '\n\n'.join((caps_arrays,) + (exts_arrays,) + enum_entries + (table,))
|
||||
|
||||
|
||||
def get_extension_list(operands):
|
||||
def get_extension_list(instructions, operand_kinds):
|
||||
"""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
|
||||
things_with_an_extensions_field = [item for item in instructions]
|
||||
|
||||
enumerants = sum([item.get('enumerants', []) for item in operand_kinds], [])
|
||||
|
||||
things_with_an_extensions_field.extend(enumerants)
|
||||
|
||||
extensions = sum([item.get('extensions', [])
|
||||
for item in things_with_an_extensions_field
|
||||
if item.get('extensions')], [])
|
||||
|
||||
extensions.extend(EXTENSIONS_FROM_SPIRV_REGISTRY.split())
|
||||
for item in EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split():
|
||||
# If it's already listed in a grammar, then don't put it in the
|
||||
# special exceptions list.
|
||||
assert item not in extensions, "Extension %s is already in a grammar file" % item
|
||||
|
||||
extensions.extend(EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split())
|
||||
|
||||
# Validator would ignore type declaration unique check. Should only be used
|
||||
# for legacy autogenerated test files containing multiple instances of the
|
||||
@ -543,55 +528,22 @@ def get_extension_list(operands):
|
||||
return sorted(set(extensions))
|
||||
|
||||
|
||||
def get_capabilities(operands):
|
||||
def get_capabilities(operand_kinds):
|
||||
"""Returns capabilities as a list of JSON objects, in order of
|
||||
appearance.
|
||||
"""
|
||||
enumerants = sum([item.get('enumerants', []) for item in operands
|
||||
enumerants = sum([item.get('enumerants', []) for item in operand_kinds
|
||||
if item.get('kind') in ['Capability']], [])
|
||||
return enumerants
|
||||
|
||||
|
||||
def generate_extension_enum(operands):
|
||||
def generate_extension_enum(extensions):
|
||||
"""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 = [item.get('enumerant')
|
||||
for item in get_capabilities(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):
|
||||
def generate_extension_to_string_mapping(extensions):
|
||||
"""Returns mapping function from extensions to corresponding strings."""
|
||||
extensions = get_extension_list(operands)
|
||||
function = 'const char* ExtensionToString(Extension extension) {\n'
|
||||
function += ' switch (extension) {\n'
|
||||
template = ' case Extension::k{extension}:\n' \
|
||||
@ -602,9 +554,8 @@ def generate_extension_to_string_mapping(operands):
|
||||
return function
|
||||
|
||||
|
||||
def generate_string_to_extension_mapping(operands):
|
||||
def generate_string_to_extension_mapping(extensions):
|
||||
"""Returns mapping function from strings to corresponding extensions."""
|
||||
extensions = get_extension_list(operands) # Already sorted
|
||||
|
||||
function = '''
|
||||
bool GetExtensionFromString(const char* str, Extension* extension) {{
|
||||
@ -627,7 +578,7 @@ def generate_string_to_extension_mapping(operands):
|
||||
return function
|
||||
|
||||
|
||||
def generate_capability_to_string_mapping(operands):
|
||||
def generate_capability_to_string_mapping(operand_kinds):
|
||||
"""Returns mapping function from capabilities to corresponding strings.
|
||||
We take care to avoid emitting duplicate values.
|
||||
"""
|
||||
@ -636,7 +587,7 @@ def generate_capability_to_string_mapping(operands):
|
||||
template = ' case SpvCapability{capability}:\n' \
|
||||
' return "{capability}";\n'
|
||||
emitted = set() # The values of capabilities we already have emitted
|
||||
for capability in get_capabilities(operands):
|
||||
for capability in get_capabilities(operand_kinds):
|
||||
value = capability.get('value')
|
||||
if value not in emitted:
|
||||
emitted.add(value)
|
||||
@ -648,12 +599,12 @@ def generate_capability_to_string_mapping(operands):
|
||||
return function
|
||||
|
||||
|
||||
def generate_all_string_enum_mappings(operands):
|
||||
def generate_all_string_enum_mappings(extensions, operand_kinds):
|
||||
"""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))
|
||||
tables.append(generate_extension_to_string_mapping(extensions))
|
||||
tables.append(generate_string_to_extension_mapping(extensions))
|
||||
tables.append(generate_capability_to_string_mapping(operand_kinds))
|
||||
return '\n\n'.join(tables)
|
||||
|
||||
|
||||
@ -740,25 +691,30 @@ def main():
|
||||
|
||||
if args.spirv_core_grammar is not None:
|
||||
with open(args.spirv_core_grammar) as json_file:
|
||||
grammar = json.loads(json_file.read())
|
||||
core_grammar = json.loads(json_file.read())
|
||||
with open(args.extinst_debuginfo_grammar) as debuginfo_json_file:
|
||||
debuginfo_grammar = json.loads(debuginfo_json_file.read())
|
||||
operand_kinds = grammar['operand_kinds']
|
||||
instructions = []
|
||||
instructions.extend(core_grammar['instructions'])
|
||||
instructions.extend(debuginfo_grammar['instructions'])
|
||||
operand_kinds = []
|
||||
operand_kinds.extend(core_grammar['operand_kinds'])
|
||||
operand_kinds.extend(debuginfo_grammar['operand_kinds'])
|
||||
extensions = get_extension_list(instructions, operand_kinds)
|
||||
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']),
|
||||
print(generate_instruction_table(core_grammar['instructions']),
|
||||
file=open(args.core_insts_output, 'w'))
|
||||
print(generate_operand_kind_table(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']),
|
||||
print(generate_extension_enum(extensions),
|
||||
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(operand_kinds),
|
||||
print(generate_all_string_enum_mappings(extensions, operand_kinds),
|
||||
file=open(args.enum_string_mapping_output, 'w'))
|
||||
|
||||
if args.extinst_glsl_grammar is not None:
|
||||
|
Loading…
Reference in New Issue
Block a user