1b2a28edaSopenharmony_ci#!/usr/bin/env python3 2b2a28edaSopenharmony_ci# Copyright (c) 2017-2020 Google LLC 3b2a28edaSopenharmony_ci# 4b2a28edaSopenharmony_ci# Permission is hereby granted, free of charge, to any person obtaining a 5b2a28edaSopenharmony_ci# copy of this software and/or associated documentation files (the 6b2a28edaSopenharmony_ci# "Materials"), to deal in the Materials without restriction, including 7b2a28edaSopenharmony_ci# without limitation the rights to use, copy, modify, merge, publish, 8b2a28edaSopenharmony_ci# distribute, sublicense, and/or sell copies of the Materials, and to 9b2a28edaSopenharmony_ci# permit persons to whom the Materials are furnished to do so, subject to 10b2a28edaSopenharmony_ci# the following conditions: 11b2a28edaSopenharmony_ci# 12b2a28edaSopenharmony_ci# The above copyright notice and this permission notice shall be included 13b2a28edaSopenharmony_ci# in all copies or substantial portions of the Materials. 14b2a28edaSopenharmony_ci# 15b2a28edaSopenharmony_ci# MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS 16b2a28edaSopenharmony_ci# KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS 17b2a28edaSopenharmony_ci# SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT 18b2a28edaSopenharmony_ci# https://www.khronos.org/registry/ 19b2a28edaSopenharmony_ci# 20b2a28edaSopenharmony_ci# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21b2a28edaSopenharmony_ci# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22b2a28edaSopenharmony_ci# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23b2a28edaSopenharmony_ci# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24b2a28edaSopenharmony_ci# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25b2a28edaSopenharmony_ci# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26b2a28edaSopenharmony_ci# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 27b2a28edaSopenharmony_ci 28b2a28edaSopenharmony_ci"""Generates a C language headers from a SPIR-V JSON grammar file""" 29b2a28edaSopenharmony_ci 30b2a28edaSopenharmony_ciimport errno 31b2a28edaSopenharmony_ciimport json 32b2a28edaSopenharmony_ciimport os.path 33b2a28edaSopenharmony_ciimport re 34b2a28edaSopenharmony_ci 35b2a28edaSopenharmony_ciDEFAULT_COPYRIGHT="""Copyright (c) 2020 The Khronos Group Inc. 36b2a28edaSopenharmony_ci 37b2a28edaSopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a 38b2a28edaSopenharmony_cicopy of this software and/or associated documentation files (the 39b2a28edaSopenharmony_ci"Materials"), to deal in the Materials without restriction, including 40b2a28edaSopenharmony_ciwithout limitation the rights to use, copy, modify, merge, publish, 41b2a28edaSopenharmony_cidistribute, sublicense, and/or sell copies of the Materials, and to 42b2a28edaSopenharmony_cipermit persons to whom the Materials are furnished to do so, subject to 43b2a28edaSopenharmony_cithe following conditions: 44b2a28edaSopenharmony_ci 45b2a28edaSopenharmony_ciThe above copyright notice and this permission notice shall be included 46b2a28edaSopenharmony_ciin all copies or substantial portions of the Materials. 47b2a28edaSopenharmony_ci 48b2a28edaSopenharmony_ciMODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS 49b2a28edaSopenharmony_ciKHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS 50b2a28edaSopenharmony_ciSPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT 51b2a28edaSopenharmony_ci https://www.khronos.org/registry/ 52b2a28edaSopenharmony_ci 53b2a28edaSopenharmony_ciTHE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 54b2a28edaSopenharmony_ciEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 55b2a28edaSopenharmony_ciMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 56b2a28edaSopenharmony_ciIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 57b2a28edaSopenharmony_ciCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 58b2a28edaSopenharmony_ciTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 59b2a28edaSopenharmony_ciMATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 60b2a28edaSopenharmony_ci""".split('\n') 61b2a28edaSopenharmony_ci 62b2a28edaSopenharmony_cidef make_path_to_file(f): 63b2a28edaSopenharmony_ci """Makes all ancestor directories to the given file, if they 64b2a28edaSopenharmony_ci don't yet exist. 65b2a28edaSopenharmony_ci 66b2a28edaSopenharmony_ci Arguments: 67b2a28edaSopenharmony_ci f: The file whose ancestor directories are to be created. 68b2a28edaSopenharmony_ci """ 69b2a28edaSopenharmony_ci dir = os.path.dirname(os.path.abspath(f)) 70b2a28edaSopenharmony_ci try: 71b2a28edaSopenharmony_ci os.makedirs(dir) 72b2a28edaSopenharmony_ci except OSError as e: 73b2a28edaSopenharmony_ci if e.errno == errno.EEXIST and os.path.isdir(dir): 74b2a28edaSopenharmony_ci pass 75b2a28edaSopenharmony_ci else: 76b2a28edaSopenharmony_ci raise 77b2a28edaSopenharmony_ci 78b2a28edaSopenharmony_ciclass ExtInstGrammar: 79b2a28edaSopenharmony_ci """The grammar for an extended instruction set""" 80b2a28edaSopenharmony_ci 81b2a28edaSopenharmony_ci def __init__(self, name, copyright, instructions, operand_kinds, version = None, revision = None): 82b2a28edaSopenharmony_ci self.name = name 83b2a28edaSopenharmony_ci self.copyright = copyright 84b2a28edaSopenharmony_ci self.instructions = instructions 85b2a28edaSopenharmony_ci self.operand_kinds = operand_kinds 86b2a28edaSopenharmony_ci self.version = version 87b2a28edaSopenharmony_ci self.revision = revision 88b2a28edaSopenharmony_ci 89b2a28edaSopenharmony_ci 90b2a28edaSopenharmony_ciclass LangGenerator: 91b2a28edaSopenharmony_ci """A language-specific generator""" 92b2a28edaSopenharmony_ci 93b2a28edaSopenharmony_ci def __init__(self): 94b2a28edaSopenharmony_ci self.upper_case_initial = re.compile('^[A-Z]') 95b2a28edaSopenharmony_ci pass 96b2a28edaSopenharmony_ci 97b2a28edaSopenharmony_ci def comment_prefix(self): 98b2a28edaSopenharmony_ci return "" 99b2a28edaSopenharmony_ci 100b2a28edaSopenharmony_ci def namespace_prefix(self): 101b2a28edaSopenharmony_ci return "" 102b2a28edaSopenharmony_ci 103b2a28edaSopenharmony_ci def uses_guards(self): 104b2a28edaSopenharmony_ci return False 105b2a28edaSopenharmony_ci 106b2a28edaSopenharmony_ci def cpp_guard_preamble(self): 107b2a28edaSopenharmony_ci return "" 108b2a28edaSopenharmony_ci 109b2a28edaSopenharmony_ci def cpp_guard_postamble(self): 110b2a28edaSopenharmony_ci return "" 111b2a28edaSopenharmony_ci 112b2a28edaSopenharmony_ci def enum_value(self, prefix, name, value): 113b2a28edaSopenharmony_ci if self.upper_case_initial.match(name): 114b2a28edaSopenharmony_ci use_name = name 115b2a28edaSopenharmony_ci else: 116b2a28edaSopenharmony_ci use_name = '_' + name 117b2a28edaSopenharmony_ci 118b2a28edaSopenharmony_ci return " {}{} = {},".format(prefix, use_name, value) 119b2a28edaSopenharmony_ci 120b2a28edaSopenharmony_ci def generate(self, grammar): 121b2a28edaSopenharmony_ci """Returns a string that is the language-specific header for the given grammar""" 122b2a28edaSopenharmony_ci 123b2a28edaSopenharmony_ci parts = [] 124b2a28edaSopenharmony_ci if grammar.copyright: 125b2a28edaSopenharmony_ci parts.extend(["{}{}".format(self.comment_prefix(), f) for f in grammar.copyright]) 126b2a28edaSopenharmony_ci parts.append('') 127b2a28edaSopenharmony_ci 128b2a28edaSopenharmony_ci guard = 'SPIRV_UNIFIED1_{}_H_'.format(grammar.name) 129b2a28edaSopenharmony_ci if self.uses_guards: 130b2a28edaSopenharmony_ci parts.append('#ifndef {}'.format(guard)) 131b2a28edaSopenharmony_ci parts.append('#define {}'.format(guard)) 132b2a28edaSopenharmony_ci parts.append('') 133b2a28edaSopenharmony_ci 134b2a28edaSopenharmony_ci parts.append(self.cpp_guard_preamble()) 135b2a28edaSopenharmony_ci 136b2a28edaSopenharmony_ci if grammar.version: 137b2a28edaSopenharmony_ci parts.append(self.const_definition(grammar.name, 'Version', grammar.version)) 138b2a28edaSopenharmony_ci 139b2a28edaSopenharmony_ci if grammar.revision is not None: 140b2a28edaSopenharmony_ci parts.append(self.const_definition(grammar.name, 'Revision', grammar.revision)) 141b2a28edaSopenharmony_ci 142b2a28edaSopenharmony_ci parts.append('') 143b2a28edaSopenharmony_ci 144b2a28edaSopenharmony_ci if grammar.instructions: 145b2a28edaSopenharmony_ci parts.append(self.enum_prefix(grammar.name, 'Instructions')) 146b2a28edaSopenharmony_ci for inst in grammar.instructions: 147b2a28edaSopenharmony_ci parts.append(self.enum_value(grammar.name, inst['opname'], inst['opcode'])) 148b2a28edaSopenharmony_ci parts.append(self.enum_end(grammar.name, 'Instructions')) 149b2a28edaSopenharmony_ci parts.append('') 150b2a28edaSopenharmony_ci 151b2a28edaSopenharmony_ci if grammar.operand_kinds: 152b2a28edaSopenharmony_ci for kind in grammar.operand_kinds: 153b2a28edaSopenharmony_ci parts.append(self.enum_prefix(grammar.name, kind['kind'])) 154b2a28edaSopenharmony_ci for e in kind['enumerants']: 155b2a28edaSopenharmony_ci parts.append(self.enum_value(grammar.name, e['enumerant'], e['value'])) 156b2a28edaSopenharmony_ci parts.append(self.enum_end(grammar.name, kind['kind'])) 157b2a28edaSopenharmony_ci parts.append('') 158b2a28edaSopenharmony_ci 159b2a28edaSopenharmony_ci parts.append(self.cpp_guard_postamble()) 160b2a28edaSopenharmony_ci 161b2a28edaSopenharmony_ci if self.uses_guards: 162b2a28edaSopenharmony_ci parts.append('#endif // {}'.format(guard)) 163b2a28edaSopenharmony_ci 164b2a28edaSopenharmony_ci # Ensre the file ends in an end of line 165b2a28edaSopenharmony_ci parts.append('') 166b2a28edaSopenharmony_ci 167b2a28edaSopenharmony_ci return '\n'.join(parts) 168b2a28edaSopenharmony_ci 169b2a28edaSopenharmony_ci 170b2a28edaSopenharmony_ciclass CLikeGenerator(LangGenerator): 171b2a28edaSopenharmony_ci def uses_guards(self): 172b2a28edaSopenharmony_ci return True 173b2a28edaSopenharmony_ci 174b2a28edaSopenharmony_ci def comment_prefix(self): 175b2a28edaSopenharmony_ci return "// " 176b2a28edaSopenharmony_ci 177b2a28edaSopenharmony_ci def const_definition(self, prefix, var, value): 178b2a28edaSopenharmony_ci # Use an anonymous enum. Don't use a static const int variable because 179b2a28edaSopenharmony_ci # that can bloat binary size. 180b2a28edaSopenharmony_ci return 'enum {0}{1}{2}{3} = {4},{1}{2}{3}_BitWidthPadding = 0x7fffffff{5};'.format( 181b2a28edaSopenharmony_ci '{', '\n ', prefix, var, value, '\n}') 182b2a28edaSopenharmony_ci 183b2a28edaSopenharmony_ci def enum_prefix(self, prefix, name): 184b2a28edaSopenharmony_ci return 'enum {}{} {}'.format(prefix, name, '{') 185b2a28edaSopenharmony_ci 186b2a28edaSopenharmony_ci def enum_end(self, prefix, enum): 187b2a28edaSopenharmony_ci return ' {}{}Max = 0x7fffffff\n{};\n'.format(prefix, enum, '}') 188b2a28edaSopenharmony_ci 189b2a28edaSopenharmony_ci def cpp_guard_preamble(self): 190b2a28edaSopenharmony_ci return '#ifdef __cplusplus\nextern "C" {\n#endif\n' 191b2a28edaSopenharmony_ci 192b2a28edaSopenharmony_ci def cpp_guard_postamble(self): 193b2a28edaSopenharmony_ci return '#ifdef __cplusplus\n}\n#endif\n' 194b2a28edaSopenharmony_ci 195b2a28edaSopenharmony_ci 196b2a28edaSopenharmony_ciclass CGenerator(CLikeGenerator): 197b2a28edaSopenharmony_ci pass 198b2a28edaSopenharmony_ci 199b2a28edaSopenharmony_ci 200b2a28edaSopenharmony_cidef main(): 201b2a28edaSopenharmony_ci import argparse 202b2a28edaSopenharmony_ci parser = argparse.ArgumentParser(description='Generate language headers from a JSON grammar') 203b2a28edaSopenharmony_ci 204b2a28edaSopenharmony_ci parser.add_argument('--extinst-name', 205b2a28edaSopenharmony_ci type=str, required=True, 206b2a28edaSopenharmony_ci help='The name to use in tokens') 207b2a28edaSopenharmony_ci parser.add_argument('--extinst-grammar', metavar='<path>', 208b2a28edaSopenharmony_ci type=str, required=True, 209b2a28edaSopenharmony_ci help='input JSON grammar file for extended instruction set') 210b2a28edaSopenharmony_ci parser.add_argument('--extinst-output-base', metavar='<path>', 211b2a28edaSopenharmony_ci type=str, required=True, 212b2a28edaSopenharmony_ci help='Basename of the language-specific output file.') 213b2a28edaSopenharmony_ci args = parser.parse_args() 214b2a28edaSopenharmony_ci 215b2a28edaSopenharmony_ci with open(args.extinst_grammar) as json_file: 216b2a28edaSopenharmony_ci grammar_json = json.loads(json_file.read()) 217b2a28edaSopenharmony_ci if 'copyright' in grammar_json: 218b2a28edaSopenharmony_ci copyright = grammar_json['copyright'] 219b2a28edaSopenharmony_ci else: 220b2a28edaSopenharmony_ci copyright = DEFAULT_COPYRIGHT 221b2a28edaSopenharmony_ci if 'version' in grammar_json: 222b2a28edaSopenharmony_ci version = grammar_json['version'] 223b2a28edaSopenharmony_ci else: 224b2a28edaSopenharmony_ci version = 0 225b2a28edaSopenharmony_ci if 'operand_kinds' in grammar_json: 226b2a28edaSopenharmony_ci operand_kinds = grammar_json['operand_kinds'] 227b2a28edaSopenharmony_ci else: 228b2a28edaSopenharmony_ci operand_kinds = [] 229b2a28edaSopenharmony_ci 230b2a28edaSopenharmony_ci grammar = ExtInstGrammar(name = args.extinst_name, 231b2a28edaSopenharmony_ci copyright = copyright, 232b2a28edaSopenharmony_ci instructions = grammar_json['instructions'], 233b2a28edaSopenharmony_ci operand_kinds = operand_kinds, 234b2a28edaSopenharmony_ci version = version, 235b2a28edaSopenharmony_ci revision = grammar_json['revision']) 236b2a28edaSopenharmony_ci make_path_to_file(args.extinst_output_base) 237b2a28edaSopenharmony_ci with open(args.extinst_output_base + '.h', 'w') as f: 238b2a28edaSopenharmony_ci f.write(CGenerator().generate(grammar)) 239b2a28edaSopenharmony_ci 240b2a28edaSopenharmony_ci 241b2a28edaSopenharmony_ciif __name__ == '__main__': 242b2a28edaSopenharmony_ci main() 243