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