|
|
|
@ -14,8 +14,6 @@
|
|
|
|
|
# limitations under the License.
|
|
|
|
|
"""Generates various info tables from SPIR-V JSON grammar."""
|
|
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
|
|
import errno
|
|
|
|
|
import json
|
|
|
|
|
import os.path
|
|
|
|
@ -36,8 +34,8 @@ SPV_AMD_shader_trinary_minmax
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_path_to_file(f):
|
|
|
|
|
"""Makes all ancestor directories to the given file, if they
|
|
|
|
|
don't yet exist.
|
|
|
|
|
"""Makes all ancestor directories to the given file, if they don't yet
|
|
|
|
|
exist.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
f: The file whose ancestor directories are to be created.
|
|
|
|
@ -53,8 +51,8 @@ def make_path_to_file(f):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convert_min_required_version(version):
|
|
|
|
|
"""Converts the minimal required SPIR-V version encoded in the
|
|
|
|
|
grammar to the symbol in SPIRV-Tools"""
|
|
|
|
|
"""Converts the minimal required SPIR-V version encoded in the grammar to
|
|
|
|
|
the symbol in SPIRV-Tools."""
|
|
|
|
|
if version is None:
|
|
|
|
|
return 'SPV_SPIRV_VERSION_WORD(1, 0)'
|
|
|
|
|
if version == 'None':
|
|
|
|
@ -63,8 +61,8 @@ def convert_min_required_version(version):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convert_max_required_version(version):
|
|
|
|
|
"""Converts the maximum required SPIR-V version encoded in the
|
|
|
|
|
grammar to the symbol in SPIRV-Tools"""
|
|
|
|
|
"""Converts the maximum required SPIR-V version encoded in the grammar to
|
|
|
|
|
the symbol in SPIRV-Tools."""
|
|
|
|
|
if version is None:
|
|
|
|
|
return '0xffffffffu'
|
|
|
|
|
return 'SPV_SPIRV_VERSION_WORD({})'.format(version.replace('.', ','))
|
|
|
|
@ -79,7 +77,7 @@ def compose_capability_list(caps):
|
|
|
|
|
Returns:
|
|
|
|
|
a string containing the braced list of SpvCapability* enums named by caps.
|
|
|
|
|
"""
|
|
|
|
|
return "{" + ", ".join(['SpvCapability{}'.format(c) for c in caps]) + "}"
|
|
|
|
|
return '{' + ', '.join(['SpvCapability{}'.format(c) for c in caps]) + '}'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_capability_array_name(caps):
|
|
|
|
@ -116,8 +114,8 @@ def compose_extension_list(exts):
|
|
|
|
|
Returns:
|
|
|
|
|
a string containing the braced list of extensions named by exts.
|
|
|
|
|
"""
|
|
|
|
|
return "{" + ", ".join(
|
|
|
|
|
['spvtools::Extension::k{}'.format(e) for e in exts]) + "}"
|
|
|
|
|
return '{' + ', '.join(
|
|
|
|
|
['spvtools::Extension::k{}'.format(e) for e in exts]) + '}'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_extension_array_name(extensions):
|
|
|
|
@ -148,8 +146,8 @@ def generate_extension_arrays(extensions):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convert_operand_kind(operand_tuple):
|
|
|
|
|
"""Returns the corresponding operand type used in spirv-tools for
|
|
|
|
|
the given operand kind and quantifier used in the JSON grammar.
|
|
|
|
|
"""Returns the corresponding operand type used in spirv-tools for the given
|
|
|
|
|
operand kind and quantifier used in the JSON grammar.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
- operand_tuple: a tuple of two elements:
|
|
|
|
@ -211,8 +209,8 @@ def convert_operand_kind(operand_tuple):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InstInitializer(object):
|
|
|
|
|
"""Instances holds a SPIR-V instruction suitable for printing as
|
|
|
|
|
the initializer for spv_opcode_desc_t."""
|
|
|
|
|
"""Instances holds a SPIR-V instruction suitable for printing as the
|
|
|
|
|
initializer for spv_opcode_desc_t."""
|
|
|
|
|
|
|
|
|
|
def __init__(self, opname, caps, exts, operands, version, lastVersion):
|
|
|
|
|
"""Initialization.
|
|
|
|
@ -244,8 +242,8 @@ class InstInitializer(object):
|
|
|
|
|
self.lastVersion = convert_max_required_version(lastVersion)
|
|
|
|
|
|
|
|
|
|
def fix_syntax(self):
|
|
|
|
|
"""Fix an instruction's syntax, adjusting for differences between
|
|
|
|
|
the officially released grammar and how SPIRV-Tools uses the grammar.
|
|
|
|
|
"""Fix an instruction's syntax, adjusting for differences between the
|
|
|
|
|
officially released grammar and how SPIRV-Tools uses the grammar.
|
|
|
|
|
|
|
|
|
|
Fixes:
|
|
|
|
|
- ExtInst should not end with SPV_OPERAND_VARIABLE_ID.
|
|
|
|
@ -337,8 +335,8 @@ def generate_instruction(inst, is_ext_inst):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_instruction_table(inst_table):
|
|
|
|
|
"""Returns the info table containing all SPIR-V instructions,
|
|
|
|
|
sorted by opcode, and prefixed by capability arrays.
|
|
|
|
|
"""Returns the info table containing all SPIR-V instructions, sorted by
|
|
|
|
|
opcode, and prefixed by capability arrays.
|
|
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
- the built-in sorted() function is guaranteed to be stable.
|
|
|
|
@ -435,9 +433,9 @@ def generate_enum_operand_kind_entry(entry, extension_map):
|
|
|
|
|
value = entry.get('value')
|
|
|
|
|
caps = entry.get('capabilities', [])
|
|
|
|
|
if value in extension_map:
|
|
|
|
|
exts = extension_map[value]
|
|
|
|
|
exts = extension_map[value]
|
|
|
|
|
else:
|
|
|
|
|
exts = []
|
|
|
|
|
exts = []
|
|
|
|
|
params = entry.get('parameters', [])
|
|
|
|
|
params = [p.get('kind') for p in params]
|
|
|
|
|
params = zip(params, [''] * len(params))
|
|
|
|
@ -453,8 +451,10 @@ def generate_enum_operand_kind_entry(entry, extension_map):
|
|
|
|
|
|
|
|
|
|
def generate_enum_operand_kind(enum, synthetic_exts_list):
|
|
|
|
|
"""Returns the C definition for the given operand kind.
|
|
|
|
|
Also appends to |synthetic_exts_list| a list of extension
|
|
|
|
|
lists used."""
|
|
|
|
|
|
|
|
|
|
Also appends to |synthetic_exts_list| a list of extension lists
|
|
|
|
|
used.
|
|
|
|
|
"""
|
|
|
|
|
kind = enum.get('kind')
|
|
|
|
|
assert kind is not None
|
|
|
|
|
|
|
|
|
@ -462,9 +462,9 @@ def generate_enum_operand_kind(enum, synthetic_exts_list):
|
|
|
|
|
# preserve their order so the first name listed in the grammar
|
|
|
|
|
# as the preferred name for disassembly.
|
|
|
|
|
if enum.get('category') == 'ValueEnum':
|
|
|
|
|
functor = lambda k: (k['value'])
|
|
|
|
|
def functor(k): return (k['value'])
|
|
|
|
|
else:
|
|
|
|
|
functor = lambda k: (int(k['value'], 16))
|
|
|
|
|
def functor(k): return (int(k['value'], 16))
|
|
|
|
|
entries = sorted(enum.get('enumerants', []), key=functor)
|
|
|
|
|
|
|
|
|
|
# SubgroupEqMask and SubgroupEqMaskKHR are the same number with
|
|
|
|
@ -472,16 +472,16 @@ def generate_enum_operand_kind(enum, synthetic_exts_list):
|
|
|
|
|
# does. Both should have the extension list.
|
|
|
|
|
# So create a mapping from enum value to the union of the extensions
|
|
|
|
|
# across all those grammar entries. Preserve order.
|
|
|
|
|
extension_map = { }
|
|
|
|
|
extension_map = {}
|
|
|
|
|
for e in entries:
|
|
|
|
|
value = e.get('value')
|
|
|
|
|
extension_map[value] = []
|
|
|
|
|
value = e.get('value')
|
|
|
|
|
extension_map[value] = []
|
|
|
|
|
for e in entries:
|
|
|
|
|
value = e.get('value')
|
|
|
|
|
exts = e.get('extensions', [])
|
|
|
|
|
for ext in exts:
|
|
|
|
|
if ext not in extension_map[value]:
|
|
|
|
|
extension_map[value].append(ext)
|
|
|
|
|
value = e.get('value')
|
|
|
|
|
exts = e.get('extensions', [])
|
|
|
|
|
for ext in exts:
|
|
|
|
|
if ext not in extension_map[value]:
|
|
|
|
|
extension_map[value].append(ext)
|
|
|
|
|
synthetic_exts_list.extend(extension_map.values())
|
|
|
|
|
|
|
|
|
|
name = '{}_{}Entries'.format(PYGEN_VARIABLE_PREFIX, kind)
|
|
|
|
@ -544,7 +544,8 @@ def get_extension_list(instructions, operand_kinds):
|
|
|
|
|
|
|
|
|
|
things_with_an_extensions_field = [item for item in instructions]
|
|
|
|
|
|
|
|
|
|
enumerants = sum([item.get('enumerants', []) for item in operand_kinds], [])
|
|
|
|
|
enumerants = sum([item.get('enumerants', [])
|
|
|
|
|
for item in operand_kinds], [])
|
|
|
|
|
|
|
|
|
|
things_with_an_extensions_field.extend(enumerants)
|
|
|
|
|
|
|
|
|
@ -553,11 +554,12 @@ def get_extension_list(instructions, operand_kinds):
|
|
|
|
|
if item.get('extensions')], [])
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
# 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())
|
|
|
|
|
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
|
|
|
|
@ -570,8 +572,7 @@ def get_extension_list(instructions, operand_kinds):
|
|
|
|
|
|
|
|
|
|
def get_capabilities(operand_kinds):
|
|
|
|
|
"""Returns capabilities as a list of JSON objects, in order of
|
|
|
|
|
appearance.
|
|
|
|
|
"""
|
|
|
|
|
appearance."""
|
|
|
|
|
enumerants = sum([item.get('enumerants', []) for item in operand_kinds
|
|
|
|
|
if item.get('kind') in ['Capability']], [])
|
|
|
|
|
return enumerants
|
|
|
|
@ -620,6 +621,7 @@ def generate_string_to_extension_mapping(extensions):
|
|
|
|
|
|
|
|
|
|
def generate_capability_to_string_mapping(operand_kinds):
|
|
|
|
|
"""Returns mapping function from capabilities to corresponding strings.
|
|
|
|
|
|
|
|
|
|
We take care to avoid emitting duplicate values.
|
|
|
|
|
"""
|
|
|
|
|
function = 'const char* CapabilityToString(SpvCapability capability) {\n'
|
|
|
|
@ -649,8 +651,8 @@ def generate_all_string_enum_mappings(extensions, operand_kinds):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def precondition_operand_kinds(operand_kinds):
|
|
|
|
|
"""For operand kinds that have the same number, make sure they all have
|
|
|
|
|
the same extension list"""
|
|
|
|
|
"""For operand kinds that have the same number, make sure they all have the
|
|
|
|
|
same extension list."""
|
|
|
|
|
return operand_kinds
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -751,45 +753,47 @@ def main():
|
|
|
|
|
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(core_grammar['instructions']),
|
|
|
|
|
file=open(args.core_insts_output, 'w'))
|
|
|
|
|
print(generate_operand_kind_table(operand_kinds),
|
|
|
|
|
file=open(args.operand_kinds_output, 'w'))
|
|
|
|
|
with open(args.core_insts_output, 'w') as f:
|
|
|
|
|
f.write(generate_instruction_table(
|
|
|
|
|
core_grammar['instructions']))
|
|
|
|
|
with open(args.operand_kinds_output, 'w') as f:
|
|
|
|
|
f.write(generate_operand_kind_table(operand_kinds))
|
|
|
|
|
if args.extension_enum_output is not None:
|
|
|
|
|
make_path_to_file(args.extension_enum_output)
|
|
|
|
|
print(generate_extension_enum(extensions),
|
|
|
|
|
file=open(args.extension_enum_output, 'w'))
|
|
|
|
|
with open(args.extension_enum_output, 'w') as f:
|
|
|
|
|
f.write(generate_extension_enum(extensions))
|
|
|
|
|
if args.enum_string_mapping_output is not None:
|
|
|
|
|
make_path_to_file(args.enum_string_mapping_output)
|
|
|
|
|
print(generate_all_string_enum_mappings(extensions, operand_kinds),
|
|
|
|
|
file=open(args.enum_string_mapping_output, 'w'))
|
|
|
|
|
with open(args.enum_string_mapping_output, 'w') as f:
|
|
|
|
|
f.write(generate_all_string_enum_mappings(
|
|
|
|
|
extensions, operand_kinds))
|
|
|
|
|
|
|
|
|
|
if args.extinst_glsl_grammar is not None:
|
|
|
|
|
with open(args.extinst_glsl_grammar) as json_file:
|
|
|
|
|
grammar = json.loads(json_file.read())
|
|
|
|
|
make_path_to_file(args.glsl_insts_output)
|
|
|
|
|
print(generate_extended_instruction_table(
|
|
|
|
|
grammar['instructions'], "glsl"),
|
|
|
|
|
file=open(args.glsl_insts_output, 'w'))
|
|
|
|
|
with open(args.glsl_insts_output, 'w') as f:
|
|
|
|
|
f.write(generate_extended_instruction_table(
|
|
|
|
|
grammar['instructions'], 'glsl'))
|
|
|
|
|
|
|
|
|
|
if args.extinst_opencl_grammar is not None:
|
|
|
|
|
with open(args.extinst_opencl_grammar) as json_file:
|
|
|
|
|
grammar = json.loads(json_file.read())
|
|
|
|
|
make_path_to_file(args.opencl_insts_output)
|
|
|
|
|
print(generate_extended_instruction_table(
|
|
|
|
|
grammar['instructions'], "opencl"),
|
|
|
|
|
file=open(args.opencl_insts_output, 'w'))
|
|
|
|
|
with open(args.opencl_insts_output, 'w') as f:
|
|
|
|
|
f.write(generate_extended_instruction_table(
|
|
|
|
|
grammar['instructions'], 'opencl'))
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
name = args.extinst_vendor_grammar
|
|
|
|
|
start = name.find("extinst.") + len("extinst.")
|
|
|
|
|
name = name[start:-len(".grammar.json")].replace("-", "_")
|
|
|
|
|
print(generate_extended_instruction_table(
|
|
|
|
|
grammar['instructions'], name),
|
|
|
|
|
file=open(args.vendor_insts_output, 'w'))
|
|
|
|
|
start = name.find('extinst.') + len('extinst.')
|
|
|
|
|
name = name[start:-len('.grammar.json')].replace('-', '_')
|
|
|
|
|
with open(args.vendor_insts_output, 'w') as f:
|
|
|
|
|
f.write(generate_extended_instruction_table(
|
|
|
|
|
grammar['instructions'], name))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|