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
17from __future__ import print_function
18
19import errno
20import json
21import os.path
22import re
23
24# Prefix for all C variables generated by this script.
25PYGEN_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.
30EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS = """
31SPV_AMD_gcn_shader
32SPV_AMD_gpu_shader_half_float
33SPV_AMD_gpu_shader_int16
34SPV_AMD_shader_trinary_minmax
35"""
36
37
38def 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
55def 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
65def 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
77def 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
88def 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
102def 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
115def 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
128def 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
142def 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
205class 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
268class 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
299def 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
327def 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
352def 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
370class 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
408def 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
433def 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
460def 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
502def 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
531def 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
540def 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
545def 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
557def 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
581def 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
602def 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
611def 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
748if __name__ == '__main__':
749    main()
750