Home | History | Annotate | Download | only in utils
      1 #!/usr/bin/env python
      2 # Copyright (c) 2016 Google Inc.
      3 
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #     http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 """Generates various info tables from SPIR-V JSON grammar."""
     16 
     17 from __future__ import print_function
     18 
     19 import errno
     20 import json
     21 import os.path
     22 import re
     23 
     24 # Prefix for all C variables generated by this script.
     25 PYGEN_VARIABLE_PREFIX = 'pygen_variable'
     26 
     27 # Extensions to recognize, but which don't necessarily come from the SPIR-V
     28 # core or KHR grammar files.  Get this list from the SPIR-V registery web page.
     29 # NOTE: Only put things on this list if it is not in those grammar files.
     30 EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS = """
     31 SPV_AMD_gcn_shader
     32 SPV_AMD_gpu_shader_half_float
     33 SPV_AMD_gpu_shader_int16
     34 SPV_AMD_shader_trinary_minmax
     35 """
     36 
     37 
     38 def make_path_to_file(f):
     39     """Makes all ancestor directories to the given file, if they
     40     don't yet exist.
     41 
     42     Arguments:
     43         f: The file whose ancestor directories are to be created.
     44     """
     45     dir = os.path.dirname(os.path.abspath(f))
     46     try:
     47         os.makedirs(dir)
     48     except OSError as e:
     49         if e.errno == errno.EEXIST and os.path.isdir(dir):
     50             pass
     51         else:
     52             raise
     53 
     54 
     55 def convert_min_required_version(version):
     56     """Converts the minimal required SPIR-V version encoded in the
     57     grammar to the symbol in SPIRV-Tools"""
     58     if version is None:
     59         return 'SPV_SPIRV_VERSION_WORD(1, 0)'
     60     if version == 'None':
     61         return '0xffffffffu'
     62     return 'SPV_SPIRV_VERSION_WORD({})'.format(version.replace('.', ','))
     63 
     64 
     65 def compose_capability_list(caps):
     66     """Returns a string containing a braced list of capabilities as enums.
     67 
     68     Arguments:
     69       - caps: a sequence of capability names
     70 
     71     Returns:
     72       a string containing the braced list of SpvCapability* enums named by caps.
     73     """
     74     return "{" + ", ".join(['SpvCapability{}'.format(c) for c in caps]) + "}"
     75 
     76 
     77 def get_capability_array_name(caps):
     78     """Returns the name of the array containing all the given capabilities.
     79 
     80     Args:
     81       - caps: a sequence of capability names
     82     """
     83     if not caps:
     84         return 'nullptr'
     85     return '{}_caps_{}'.format(PYGEN_VARIABLE_PREFIX, ''.join(caps))
     86 
     87 
     88 def generate_capability_arrays(caps):
     89     """Returns the arrays of capabilities.
     90 
     91     Arguments:
     92       - caps: a sequence of sequence of capability names
     93     """
     94     caps = sorted(set([tuple(c) for c in caps if c]))
     95     arrays = [
     96         'static const SpvCapability {}[] = {};'.format(
     97             get_capability_array_name(c), compose_capability_list(c))
     98         for c in caps]
     99     return '\n'.join(arrays)
    100 
    101 
    102 def compose_extension_list(exts):
    103     """Returns a string containing a braced list of extensions as enums.
    104 
    105     Arguments:
    106       - exts: a sequence of extension names
    107 
    108     Returns:
    109       a string containing the braced list of extensions named by exts.
    110     """
    111     return "{" + ", ".join(
    112         ['spvtools::Extension::k{}'.format(e) for e in exts]) + "}"
    113 
    114 
    115 def get_extension_array_name(extensions):
    116     """Returns the name of the array containing all the given extensions.
    117 
    118     Args:
    119       - extensions: a sequence of extension names
    120     """
    121     if not extensions:
    122         return 'nullptr'
    123     else:
    124         return '{}_exts_{}'.format(
    125             PYGEN_VARIABLE_PREFIX, ''.join(extensions))
    126 
    127 
    128 def generate_extension_arrays(extensions):
    129     """Returns the arrays of extensions.
    130 
    131     Arguments:
    132       - caps: a sequence of sequence of extension names
    133     """
    134     extensions = sorted(set([tuple(e) for e in extensions if e]))
    135     arrays = [
    136         'static const spvtools::Extension {}[] = {};'.format(
    137             get_extension_array_name(e), compose_extension_list(e))
    138         for e in extensions]
    139     return '\n'.join(arrays)
    140 
    141 
    142 def convert_operand_kind(operand_tuple):
    143     """Returns the corresponding operand type used in spirv-tools for
    144     the given operand kind and quantifier used in the JSON grammar.
    145 
    146     Arguments:
    147       - operand_tuple: a tuple of two elements:
    148           - operand kind: used in the JSON grammar
    149           - quantifier: '', '?', or '*'
    150 
    151     Returns:
    152       a string of the enumerant name in spv_operand_type_t
    153     """
    154     kind, quantifier = operand_tuple
    155     # The following cases are where we differ between the JSON grammar and
    156     # spirv-tools.
    157     if kind == 'IdResultType':
    158         kind = 'TypeId'
    159     elif kind == 'IdResult':
    160         kind = 'ResultId'
    161     elif kind == 'IdMemorySemantics' or kind == 'MemorySemantics':
    162         kind = 'MemorySemanticsId'
    163     elif kind == 'IdScope' or kind == 'Scope':
    164         kind = 'ScopeId'
    165     elif kind == 'IdRef':
    166         kind = 'Id'
    167 
    168     elif kind == 'ImageOperands':
    169         kind = 'Image'
    170     elif kind == 'Dim':
    171         kind = 'Dimensionality'
    172     elif kind == 'ImageFormat':
    173         kind = 'SamplerImageFormat'
    174     elif kind == 'KernelEnqueueFlags':
    175         kind = 'KernelEnqFlags'
    176 
    177     elif kind == 'LiteralExtInstInteger':
    178         kind = 'ExtensionInstructionNumber'
    179     elif kind == 'LiteralSpecConstantOpInteger':
    180         kind = 'SpecConstantOpNumber'
    181     elif kind == 'LiteralContextDependentNumber':
    182         kind = 'TypedLiteralNumber'
    183 
    184     elif kind == 'PairLiteralIntegerIdRef':
    185         kind = 'LiteralIntegerId'
    186     elif kind == 'PairIdRefLiteralInteger':
    187         kind = 'IdLiteralInteger'
    188     elif kind == 'PairIdRefIdRef':  # Used by OpPhi in the grammar
    189         kind = 'Id'
    190 
    191     if kind == 'FPRoundingMode':
    192         kind = 'FpRoundingMode'
    193     elif kind == 'FPFastMathMode':
    194         kind = 'FpFastMathMode'
    195 
    196     if quantifier == '?':
    197         kind = 'Optional{}'.format(kind)
    198     elif quantifier == '*':
    199         kind = 'Variable{}'.format(kind)
    200 
    201     return 'SPV_OPERAND_TYPE_{}'.format(
    202         re.sub(r'([a-z])([A-Z])', r'\1_\2', kind).upper())
    203 
    204 
    205 class InstInitializer(object):
    206     """Instances holds a SPIR-V instruction suitable for printing as
    207     the initializer for spv_opcode_desc_t."""
    208 
    209     def __init__(self, opname, caps, exts, operands, version):
    210         """Initialization.
    211 
    212         Arguments:
    213           - opname: opcode name (with the 'Op' prefix)
    214           - caps: a sequence of capability names required by this opcode
    215           - exts: a sequence of names of extensions enabling this enumerant
    216           - operands: a sequence of (operand-kind, operand-quantifier) tuples
    217           - version: minimal SPIR-V version required for this opcode
    218         """
    219 
    220         assert opname.startswith('Op')
    221         self.opname = opname[2:]  # Remove the "Op" prefix.
    222         self.num_caps = len(caps)
    223         self.caps_mask = get_capability_array_name(caps)
    224         self.num_exts = len(exts)
    225         self.exts = get_extension_array_name(exts)
    226         self.operands = [convert_operand_kind(o) for o in operands]
    227 
    228         self.fix_syntax()
    229 
    230         operands = [o[0] for o in operands]
    231         self.ref_type_id = 'IdResultType' in operands
    232         self.def_result_id = 'IdResult' in operands
    233 
    234         self.version = convert_min_required_version(version)
    235 
    236     def fix_syntax(self):
    237         """Fix an instruction's syntax, adjusting for differences between
    238         the officially released grammar and how SPIRV-Tools uses the grammar.
    239 
    240         Fixes:
    241             - ExtInst should not end with SPV_OPERAND_VARIABLE_ID.
    242             https://github.com/KhronosGroup/SPIRV-Tools/issues/233
    243         """
    244         if (self.opname == 'ExtInst'
    245                 and self.operands[-1] == 'SPV_OPERAND_TYPE_VARIABLE_ID'):
    246             self.operands.pop()
    247 
    248     def __str__(self):
    249         template = ['{{"{opname}"', 'SpvOp{opname}',
    250                     '{num_caps}', '{caps_mask}',
    251                     '{num_operands}', '{{{operands}}}',
    252                     '{def_result_id}', '{ref_type_id}',
    253                     '{num_exts}', '{exts}',
    254                     '{min_version}}}']
    255         return ', '.join(template).format(
    256             opname=self.opname,
    257             num_caps=self.num_caps,
    258             caps_mask=self.caps_mask,
    259             num_operands=len(self.operands),
    260             operands=', '.join(self.operands),
    261             def_result_id=(1 if self.def_result_id else 0),
    262             ref_type_id=(1 if self.ref_type_id else 0),
    263             num_exts=self.num_exts,
    264             exts=self.exts,
    265             min_version=self.version)
    266 
    267 
    268 class ExtInstInitializer(object):
    269     """Instances holds a SPIR-V extended instruction suitable for printing as
    270     the initializer for spv_ext_inst_desc_t."""
    271 
    272     def __init__(self, opname, opcode, caps, operands):
    273         """Initialization.
    274 
    275         Arguments:
    276           - opname: opcode name
    277           - opcode: enumerant value for this opcode
    278           - caps: a sequence of capability names required by this opcode
    279           - operands: a sequence of (operand-kind, operand-quantifier) tuples
    280         """
    281         self.opname = opname
    282         self.opcode = opcode
    283         self.num_caps = len(caps)
    284         self.caps_mask = get_capability_array_name(caps)
    285         self.operands = [convert_operand_kind(o) for o in operands]
    286         self.operands.append('SPV_OPERAND_TYPE_NONE')
    287 
    288     def __str__(self):
    289         template = ['{{"{opname}"', '{opcode}', '{num_caps}', '{caps_mask}',
    290                     '{{{operands}}}}}']
    291         return ', '.join(template).format(
    292             opname=self.opname,
    293             opcode=self.opcode,
    294             num_caps=self.num_caps,
    295             caps_mask=self.caps_mask,
    296             operands=', '.join(self.operands))
    297 
    298 
    299 def generate_instruction(inst, is_ext_inst):
    300     """Returns the C initializer for the given SPIR-V instruction.
    301 
    302     Arguments:
    303       - inst: a dict containing information about a SPIR-V instruction
    304       - is_ext_inst: a bool indicating whether |inst| is an extended
    305                      instruction.
    306 
    307     Returns:
    308       a string containing the C initializer for spv_opcode_desc_t or
    309       spv_ext_inst_desc_t
    310     """
    311     opname = inst.get('opname')
    312     opcode = inst.get('opcode')
    313     caps = inst.get('capabilities', [])
    314     exts = inst.get('extensions', [])
    315     operands = inst.get('operands', {})
    316     operands = [(o['kind'], o.get('quantifier', '')) for o in operands]
    317     min_version = inst.get('version', None)
    318 
    319     assert opname is not None
    320 
    321     if is_ext_inst:
    322         return str(ExtInstInitializer(opname, opcode, caps, operands))
    323     else:
    324         return str(InstInitializer(opname, caps, exts, operands, min_version))
    325 
    326 
    327 def generate_instruction_table(inst_table):
    328     """Returns the info table containing all SPIR-V instructions,
    329     sorted by opcode, and prefixed by capability arrays.
    330 
    331     Note:
    332       - the built-in sorted() function is guaranteed to be stable.
    333         https://docs.python.org/3/library/functions.html#sorted
    334 
    335     Arguments:
    336       - inst_table: a list containing all SPIR-V instructions.
    337     """
    338     inst_table = sorted(inst_table, key=lambda k: (k['opcode'], k['opname']))
    339 
    340     caps_arrays = generate_capability_arrays(
    341         [inst.get('capabilities', []) for inst in inst_table])
    342     exts_arrays = generate_extension_arrays(
    343         [inst.get('extensions', []) for inst in inst_table])
    344 
    345     insts = [generate_instruction(inst, False) for inst in inst_table]
    346     insts = ['static const spv_opcode_desc_t kOpcodeTableEntries[] = {{\n'
    347              '  {}\n}};'.format(',\n  '.join(insts))]
    348 
    349     return '{}\n\n{}\n\n{}'.format(caps_arrays, exts_arrays, '\n'.join(insts))
    350 
    351 
    352 def generate_extended_instruction_table(inst_table, set_name):
    353     """Returns the info table containing all SPIR-V extended instructions,
    354     sorted by opcode, and prefixed by capability arrays.
    355 
    356     Arguments:
    357       - inst_table: a list containing all SPIR-V instructions.
    358       - set_name: the name of the extended instruction set.
    359     """
    360     inst_table = sorted(inst_table, key=lambda k: k['opcode'])
    361     caps = [inst.get('capabilities', []) for inst in inst_table]
    362     caps_arrays = generate_capability_arrays(caps)
    363     insts = [generate_instruction(inst, True) for inst in inst_table]
    364     insts = ['static const spv_ext_inst_desc_t {}_entries[] = {{\n'
    365              '  {}\n}};'.format(set_name, ',\n  '.join(insts))]
    366 
    367     return '{}\n\n{}'.format(caps_arrays, '\n'.join(insts))
    368 
    369 
    370 class EnumerantInitializer(object):
    371     """Prints an enumerant as the initializer for spv_operand_desc_t."""
    372 
    373     def __init__(self, enumerant, value, caps, exts, parameters, version):
    374         """Initialization.
    375 
    376         Arguments:
    377           - enumerant: enumerant name
    378           - value: enumerant value
    379           - caps: a sequence of capability names required by this enumerant
    380           - exts: a sequence of names of extensions enabling this enumerant
    381           - parameters: a sequence of (operand-kind, operand-quantifier) tuples
    382           - version: minimal SPIR-V version required for this opcode
    383         """
    384         self.enumerant = enumerant
    385         self.value = value
    386         self.num_caps = len(caps)
    387         self.caps = get_capability_array_name(caps)
    388         self.num_exts = len(exts)
    389         self.exts = get_extension_array_name(exts)
    390         self.parameters = [convert_operand_kind(p) for p in parameters]
    391         self.version = convert_min_required_version(version)
    392 
    393     def __str__(self):
    394         template = ['{{"{enumerant}"', '{value}', '{num_caps}',
    395                     '{caps}', '{num_exts}', '{exts}',
    396                     '{{{parameters}}}', '{min_version}}}']
    397         return ', '.join(template).format(
    398             enumerant=self.enumerant,
    399             value=self.value,
    400             num_caps=self.num_caps,
    401             caps=self.caps,
    402             num_exts=self.num_exts,
    403             exts=self.exts,
    404             parameters=', '.join(self.parameters),
    405             min_version=self.version)
    406 
    407 
    408 def generate_enum_operand_kind_entry(entry):
    409     """Returns the C initializer for the given operand enum entry.
    410 
    411     Arguments:
    412       - entry: a dict containing information about an enum entry
    413 
    414     Returns:
    415       a string containing the C initializer for spv_operand_desc_t
    416     """
    417     enumerant = entry.get('enumerant')
    418     value = entry.get('value')
    419     caps = entry.get('capabilities', [])
    420     exts = entry.get('extensions', [])
    421     params = entry.get('parameters', [])
    422     params = [p.get('kind') for p in params]
    423     params = zip(params, [''] * len(params))
    424     version = entry.get('version', None)
    425 
    426     assert enumerant is not None
    427     assert value is not None
    428 
    429     return str(EnumerantInitializer(
    430         enumerant, value, caps, exts, params, version))
    431 
    432 
    433 def generate_enum_operand_kind(enum):
    434     """Returns the C definition for the given operand kind."""
    435     kind = enum.get('kind')
    436     assert kind is not None
    437 
    438     # Sort all enumerants first according to their values and then
    439     # their names so that the symbols with the same values are
    440     # grouped together.
    441     if enum.get('category') == 'ValueEnum':
    442         functor = lambda k: (k['value'], k['enumerant'])
    443     else:
    444         functor = lambda k: (int(k['value'], 16), k['enumerant'])
    445     entries = sorted(enum.get('enumerants', []), key=functor)
    446 
    447     name = '{}_{}Entries'.format(PYGEN_VARIABLE_PREFIX, kind)
    448     entries = ['  {}'.format(generate_enum_operand_kind_entry(e))
    449                for e in entries]
    450 
    451     template = ['static const spv_operand_desc_t {name}[] = {{',
    452                 '{entries}', '}};']
    453     entries = '\n'.join(template).format(
    454         name=name,
    455         entries=',\n'.join(entries))
    456 
    457     return kind, name, entries
    458 
    459 
    460 def generate_operand_kind_table(enums):
    461     """Returns the info table containing all SPIR-V operand kinds."""
    462     # We only need to output info tables for those operand kinds that are enums.
    463     enums = [e for e in enums if e.get('category') in ['ValueEnum', 'BitEnum']]
    464 
    465     caps = [entry.get('capabilities', [])
    466             for enum in enums
    467             for entry in enum.get('enumerants', [])]
    468     caps_arrays = generate_capability_arrays(caps)
    469 
    470     exts = [entry.get('extensions', [])
    471             for enum in enums
    472             for entry in enum.get('enumerants', [])]
    473     exts_arrays = generate_extension_arrays(exts)
    474 
    475     enums = [generate_enum_operand_kind(e) for e in enums]
    476     # We have three operand kinds that requires their optional counterpart to
    477     # exist in the operand info table.
    478     three_optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess']
    479     three_optional_enums = [e for e in enums if e[0] in three_optional_enums]
    480     enums.extend(three_optional_enums)
    481 
    482     enum_kinds, enum_names, enum_entries = zip(*enums)
    483     # Mark the last three as optional ones.
    484     enum_quantifiers = [''] * (len(enums) - 3) + ['?'] * 3
    485     # And we don't want redefinition of them.
    486     enum_entries = enum_entries[:-3]
    487     enum_kinds = [convert_operand_kind(e)
    488                   for e in zip(enum_kinds, enum_quantifiers)]
    489     table_entries = zip(enum_kinds, enum_names, enum_names)
    490     table_entries = ['  {{{}, ARRAY_SIZE({}), {}}}'.format(*e)
    491                      for e in table_entries]
    492 
    493     template = [
    494         'static const spv_operand_desc_group_t {p}_OperandInfoTable[] = {{',
    495         '{enums}', '}};']
    496     table = '\n'.join(template).format(
    497         p=PYGEN_VARIABLE_PREFIX, enums=',\n'.join(table_entries))
    498 
    499     return '\n\n'.join((caps_arrays,) + (exts_arrays,) + enum_entries + (table,))
    500 
    501 
    502 def get_extension_list(instructions, operand_kinds):
    503     """Returns extensions as an alphabetically sorted list of strings."""
    504 
    505     things_with_an_extensions_field = [item for item in instructions]
    506 
    507     enumerants = sum([item.get('enumerants', []) for item in operand_kinds], [])
    508 
    509     things_with_an_extensions_field.extend(enumerants)
    510 
    511     extensions = sum([item.get('extensions', [])
    512                       for item in things_with_an_extensions_field
    513                       if item.get('extensions')], [])
    514 
    515     for item in EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split():
    516         # If it's already listed in a grammar, then don't put it in the
    517         # special exceptions list.
    518         assert item not in extensions, "Extension %s is already in a grammar file" % item
    519 
    520     extensions.extend(EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split())
    521 
    522     # Validator would ignore type declaration unique check. Should only be used
    523     # for legacy autogenerated test files containing multiple instances of the
    524     # same type declaration, if fixing the test by other methods is too
    525     # difficult. Shouldn't be used for any other reasons.
    526     extensions.append('SPV_VALIDATOR_ignore_type_decl_unique')
    527 
    528     return sorted(set(extensions))
    529 
    530 
    531 def get_capabilities(operand_kinds):
    532     """Returns capabilities as a list of JSON objects, in order of
    533     appearance.
    534     """
    535     enumerants = sum([item.get('enumerants', []) for item in operand_kinds
    536                       if item.get('kind') in ['Capability']], [])
    537     return enumerants
    538 
    539 
    540 def generate_extension_enum(extensions):
    541     """Returns enumeration containing extensions declared in the grammar."""
    542     return ',\n'.join(['k' + extension for extension in extensions])
    543 
    544 
    545 def generate_extension_to_string_mapping(extensions):
    546     """Returns mapping function from extensions to corresponding strings."""
    547     function = 'const char* ExtensionToString(Extension extension) {\n'
    548     function += '  switch (extension) {\n'
    549     template = '    case Extension::k{extension}:\n' \
    550         '      return "{extension}";\n'
    551     function += ''.join([template.format(extension=extension)
    552                          for extension in extensions])
    553     function += '  };\n\n  return "";\n}'
    554     return function
    555 
    556 
    557 def generate_string_to_extension_mapping(extensions):
    558     """Returns mapping function from strings to corresponding extensions."""
    559 
    560     function = '''
    561     bool GetExtensionFromString(const char* str, Extension* extension) {{
    562         static const char* known_ext_strs[] = {{ {strs} }};
    563         static const Extension known_ext_ids[] = {{ {ids} }};
    564         const auto b = std::begin(known_ext_strs);
    565         const auto e = std::end(known_ext_strs);
    566         const auto found = std::equal_range(
    567             b, e, str, [](const char* str1, const char* str2) {{
    568                 return std::strcmp(str1, str2) < 0;
    569             }});
    570         if (found.first == e || found.first == found.second) return false;
    571 
    572         *extension = known_ext_ids[found.first - b];
    573         return true;
    574     }}
    575     '''.format(strs=', '.join(['"{}"'.format(e) for e in extensions]),
    576                ids=', '.join(['Extension::k{}'.format(e) for e in extensions]))
    577 
    578     return function
    579 
    580 
    581 def generate_capability_to_string_mapping(operand_kinds):
    582     """Returns mapping function from capabilities to corresponding strings.
    583     We take care to avoid emitting duplicate values.
    584     """
    585     function = 'const char* CapabilityToString(SpvCapability capability) {\n'
    586     function += '  switch (capability) {\n'
    587     template = '    case SpvCapability{capability}:\n' \
    588         '      return "{capability}";\n'
    589     emitted = set()  # The values of capabilities we already have emitted
    590     for capability in get_capabilities(operand_kinds):
    591         value = capability.get('value')
    592         if value not in emitted:
    593             emitted.add(value)
    594             function += template.format(capability=capability.get('enumerant'))
    595     function += '    case SpvCapabilityMax:\n' \
    596         '      assert(0 && "Attempting to convert SpvCapabilityMax to string");\n' \
    597         '      return "";\n'
    598     function += '  };\n\n  return "";\n}'
    599     return function
    600 
    601 
    602 def generate_all_string_enum_mappings(extensions, operand_kinds):
    603     """Returns all string-to-enum / enum-to-string mapping tables."""
    604     tables = []
    605     tables.append(generate_extension_to_string_mapping(extensions))
    606     tables.append(generate_string_to_extension_mapping(extensions))
    607     tables.append(generate_capability_to_string_mapping(operand_kinds))
    608     return '\n\n'.join(tables)
    609 
    610 
    611 def main():
    612     import argparse
    613     parser = argparse.ArgumentParser(description='Generate SPIR-V info tables')
    614 
    615     parser.add_argument('--spirv-core-grammar', metavar='<path>',
    616                         type=str, required=False,
    617                         help='input JSON grammar file for core SPIR-V '
    618                         'instructions')
    619     parser.add_argument('--extinst-debuginfo-grammar', metavar='<path>',
    620                         type=str, required=False, default=None,
    621                         help='input JSON grammar file for DebugInfo extended '
    622                         'instruction set')
    623     parser.add_argument('--extinst-glsl-grammar', metavar='<path>',
    624                         type=str, required=False, default=None,
    625                         help='input JSON grammar file for GLSL extended '
    626                         'instruction set')
    627     parser.add_argument('--extinst-opencl-grammar', metavar='<path>',
    628                         type=str, required=False, default=None,
    629                         help='input JSON grammar file for OpenCL extended '
    630                         'instruction set')
    631 
    632     parser.add_argument('--core-insts-output', metavar='<path>',
    633                         type=str, required=False, default=None,
    634                         help='output file for core SPIR-V instructions')
    635     parser.add_argument('--glsl-insts-output', metavar='<path>',
    636                         type=str, required=False, default=None,
    637                         help='output file for GLSL extended instruction set')
    638     parser.add_argument('--opencl-insts-output', metavar='<path>',
    639                         type=str, required=False, default=None,
    640                         help='output file for OpenCL extended instruction set')
    641     parser.add_argument('--operand-kinds-output', metavar='<path>',
    642                         type=str, required=False, default=None,
    643                         help='output file for operand kinds')
    644     parser.add_argument('--extension-enum-output', metavar='<path>',
    645                         type=str, required=False, default=None,
    646                         help='output file for extension enumeration')
    647     parser.add_argument('--enum-string-mapping-output', metavar='<path>',
    648                         type=str, required=False, default=None,
    649                         help='output file for enum-string mappings')
    650     parser.add_argument('--extinst-vendor-grammar', metavar='<path>',
    651                         type=str, required=False, default=None,
    652                         help='input JSON grammar file for vendor extended '
    653                         'instruction set'),
    654     parser.add_argument('--vendor-insts-output', metavar='<path>',
    655                         type=str, required=False, default=None,
    656                         help='output file for vendor extended instruction set')
    657     args = parser.parse_args()
    658 
    659     if (args.core_insts_output is None) != \
    660             (args.operand_kinds_output is None):
    661         print('error: --core-insts-output and --operand-kinds-output '
    662               'should be specified together.')
    663         exit(1)
    664     if args.operand_kinds_output and not (args.spirv_core_grammar and args.extinst_debuginfo_grammar):
    665         print('error: --operand-kinds-output requires --spirv-core-grammar '
    666               'and --exinst-debuginfo-grammar')
    667         exit(1)
    668     if (args.glsl_insts_output is None) != \
    669             (args.extinst_glsl_grammar is None):
    670         print('error: --glsl-insts-output and --extinst-glsl-grammar '
    671               'should be specified together.')
    672         exit(1)
    673     if (args.opencl_insts_output is None) != \
    674             (args.extinst_opencl_grammar is None):
    675         print('error: --opencl-insts-output and --extinst-opencl-grammar '
    676               'should be specified together.')
    677         exit(1)
    678     if (args.vendor_insts_output is None) != \
    679             (args.extinst_vendor_grammar is None):
    680         print('error: --vendor-insts-output and '
    681               '--extinst-vendor-grammar should be specified together.')
    682         exit(1)
    683     if all([args.core_insts_output is None,
    684             args.glsl_insts_output is None,
    685             args.opencl_insts_output is None,
    686             args.vendor_insts_output is None,
    687             args.extension_enum_output is None,
    688             args.enum_string_mapping_output is None]):
    689         print('error: at least one output should be specified.')
    690         exit(1)
    691 
    692     if args.spirv_core_grammar is not None:
    693         with open(args.spirv_core_grammar) as json_file:
    694             core_grammar = json.loads(json_file.read())
    695             with open(args.extinst_debuginfo_grammar) as debuginfo_json_file:
    696                 debuginfo_grammar = json.loads(debuginfo_json_file.read())
    697                 instructions = []
    698                 instructions.extend(core_grammar['instructions'])
    699                 instructions.extend(debuginfo_grammar['instructions'])
    700                 operand_kinds = []
    701                 operand_kinds.extend(core_grammar['operand_kinds'])
    702                 operand_kinds.extend(debuginfo_grammar['operand_kinds'])
    703                 extensions = get_extension_list(instructions, operand_kinds)
    704         if args.core_insts_output is not None:
    705             make_path_to_file(args.core_insts_output)
    706             make_path_to_file(args.operand_kinds_output)
    707             print(generate_instruction_table(core_grammar['instructions']),
    708               file=open(args.core_insts_output, 'w'))
    709             print(generate_operand_kind_table(operand_kinds),
    710               file=open(args.operand_kinds_output, 'w'))
    711         if args.extension_enum_output is not None:
    712             make_path_to_file(args.extension_enum_output)
    713             print(generate_extension_enum(extensions),
    714               file=open(args.extension_enum_output, 'w'))
    715         if args.enum_string_mapping_output is not None:
    716             make_path_to_file(args.enum_string_mapping_output)
    717             print(generate_all_string_enum_mappings(extensions, operand_kinds),
    718               file=open(args.enum_string_mapping_output, 'w'))
    719 
    720     if args.extinst_glsl_grammar is not None:
    721         with open(args.extinst_glsl_grammar) as json_file:
    722             grammar = json.loads(json_file.read())
    723             make_path_to_file(args.glsl_insts_output)
    724             print(generate_extended_instruction_table(
    725                     grammar['instructions'], "glsl"),
    726                   file=open(args.glsl_insts_output, 'w'))
    727 
    728     if args.extinst_opencl_grammar is not None:
    729         with open(args.extinst_opencl_grammar) as json_file:
    730             grammar = json.loads(json_file.read())
    731             make_path_to_file(args.opencl_insts_output)
    732             print(generate_extended_instruction_table(
    733                     grammar['instructions'], "opencl"),
    734                   file=open(args.opencl_insts_output, 'w'))
    735 
    736     if args.extinst_vendor_grammar is not None:
    737         with open(args.extinst_vendor_grammar) as json_file:
    738             grammar = json.loads(json_file.read())
    739             make_path_to_file(args.vendor_insts_output)
    740             name = args.extinst_vendor_grammar
    741             start = name.find("extinst.") + len("extinst.")
    742             name = name[start:-len(".grammar.json")].replace("-", "_")
    743             print(generate_extended_instruction_table(
    744                     grammar['instructions'], name),
    745                   file=open(args.vendor_insts_output, 'w'))
    746 
    747 
    748 if __name__ == '__main__':
    749     main()
    750