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