1fd4e5da5Sopenharmony_ci#!/usr/bin/env python3 2fd4e5da5Sopenharmony_ci# Copyright (c) 2017 Google Inc. 3fd4e5da5Sopenharmony_ci 4fd4e5da5Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 5fd4e5da5Sopenharmony_ci# you may not use this file except in compliance with the License. 6fd4e5da5Sopenharmony_ci# You may obtain a copy of the License at 7fd4e5da5Sopenharmony_ci# 8fd4e5da5Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 9fd4e5da5Sopenharmony_ci# 10fd4e5da5Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 11fd4e5da5Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 12fd4e5da5Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fd4e5da5Sopenharmony_ci# See the License for the specific language governing permissions and 14fd4e5da5Sopenharmony_ci# limitations under the License. 15fd4e5da5Sopenharmony_ci"""Generates language headers from a JSON grammar file""" 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ciimport errno 18fd4e5da5Sopenharmony_ciimport json 19fd4e5da5Sopenharmony_ciimport os.path 20fd4e5da5Sopenharmony_ciimport re 21fd4e5da5Sopenharmony_ci 22fd4e5da5Sopenharmony_ci 23fd4e5da5Sopenharmony_cidef make_path_to_file(f): 24fd4e5da5Sopenharmony_ci """Makes all ancestor directories to the given file, if they 25fd4e5da5Sopenharmony_ci don't yet exist. 26fd4e5da5Sopenharmony_ci 27fd4e5da5Sopenharmony_ci Arguments: 28fd4e5da5Sopenharmony_ci f: The file whose ancestor directories are to be created. 29fd4e5da5Sopenharmony_ci """ 30fd4e5da5Sopenharmony_ci dir = os.path.dirname(os.path.abspath(f)) 31fd4e5da5Sopenharmony_ci try: 32fd4e5da5Sopenharmony_ci os.makedirs(dir) 33fd4e5da5Sopenharmony_ci except OSError as e: 34fd4e5da5Sopenharmony_ci if e.errno == errno.EEXIST and os.path.isdir(dir): 35fd4e5da5Sopenharmony_ci pass 36fd4e5da5Sopenharmony_ci else: 37fd4e5da5Sopenharmony_ci raise 38fd4e5da5Sopenharmony_ci 39fd4e5da5Sopenharmony_ciclass ExtInstGrammar: 40fd4e5da5Sopenharmony_ci """The grammar for an extended instruction set""" 41fd4e5da5Sopenharmony_ci 42fd4e5da5Sopenharmony_ci def __init__(self, name, copyright, instructions, operand_kinds, version = None, revision = None): 43fd4e5da5Sopenharmony_ci self.name = name 44fd4e5da5Sopenharmony_ci self.copyright = copyright 45fd4e5da5Sopenharmony_ci self.instructions = instructions 46fd4e5da5Sopenharmony_ci self.operand_kinds = operand_kinds 47fd4e5da5Sopenharmony_ci self.version = version 48fd4e5da5Sopenharmony_ci self.revision = revision 49fd4e5da5Sopenharmony_ci 50fd4e5da5Sopenharmony_ci 51fd4e5da5Sopenharmony_ciclass LangGenerator: 52fd4e5da5Sopenharmony_ci """A language-specific generator""" 53fd4e5da5Sopenharmony_ci 54fd4e5da5Sopenharmony_ci def __init__(self): 55fd4e5da5Sopenharmony_ci self.upper_case_initial = re.compile('^[A-Z]') 56fd4e5da5Sopenharmony_ci pass 57fd4e5da5Sopenharmony_ci 58fd4e5da5Sopenharmony_ci def comment_prefix(self): 59fd4e5da5Sopenharmony_ci return "" 60fd4e5da5Sopenharmony_ci 61fd4e5da5Sopenharmony_ci def namespace_prefix(self): 62fd4e5da5Sopenharmony_ci return "" 63fd4e5da5Sopenharmony_ci 64fd4e5da5Sopenharmony_ci def uses_guards(self): 65fd4e5da5Sopenharmony_ci return False 66fd4e5da5Sopenharmony_ci 67fd4e5da5Sopenharmony_ci def cpp_guard_preamble(self): 68fd4e5da5Sopenharmony_ci return "" 69fd4e5da5Sopenharmony_ci 70fd4e5da5Sopenharmony_ci def cpp_guard_postamble(self): 71fd4e5da5Sopenharmony_ci return "" 72fd4e5da5Sopenharmony_ci 73fd4e5da5Sopenharmony_ci def enum_value(self, prefix, name, value): 74fd4e5da5Sopenharmony_ci if self.upper_case_initial.match(name): 75fd4e5da5Sopenharmony_ci use_name = name 76fd4e5da5Sopenharmony_ci else: 77fd4e5da5Sopenharmony_ci use_name = '_' + name 78fd4e5da5Sopenharmony_ci 79fd4e5da5Sopenharmony_ci return " {}{} = {},".format(prefix, use_name, value) 80fd4e5da5Sopenharmony_ci 81fd4e5da5Sopenharmony_ci def generate(self, grammar): 82fd4e5da5Sopenharmony_ci """Returns a string that is the language-specific header for the given grammar""" 83fd4e5da5Sopenharmony_ci 84fd4e5da5Sopenharmony_ci parts = [] 85fd4e5da5Sopenharmony_ci if grammar.copyright: 86fd4e5da5Sopenharmony_ci parts.extend(["{}{}".format(self.comment_prefix(), f) for f in grammar.copyright]) 87fd4e5da5Sopenharmony_ci parts.append('') 88fd4e5da5Sopenharmony_ci 89fd4e5da5Sopenharmony_ci guard = 'SPIRV_EXTINST_{}_H_'.format(grammar.name) 90fd4e5da5Sopenharmony_ci if self.uses_guards: 91fd4e5da5Sopenharmony_ci parts.append('#ifndef {}'.format(guard)) 92fd4e5da5Sopenharmony_ci parts.append('#define {}'.format(guard)) 93fd4e5da5Sopenharmony_ci parts.append('') 94fd4e5da5Sopenharmony_ci 95fd4e5da5Sopenharmony_ci parts.append(self.cpp_guard_preamble()) 96fd4e5da5Sopenharmony_ci 97fd4e5da5Sopenharmony_ci if grammar.version: 98fd4e5da5Sopenharmony_ci parts.append(self.const_definition(grammar.name, 'Version', grammar.version)) 99fd4e5da5Sopenharmony_ci 100fd4e5da5Sopenharmony_ci if grammar.revision is not None: 101fd4e5da5Sopenharmony_ci parts.append(self.const_definition(grammar.name, 'Revision', grammar.revision)) 102fd4e5da5Sopenharmony_ci 103fd4e5da5Sopenharmony_ci parts.append('') 104fd4e5da5Sopenharmony_ci 105fd4e5da5Sopenharmony_ci if grammar.instructions: 106fd4e5da5Sopenharmony_ci parts.append(self.enum_prefix(grammar.name, 'Instructions')) 107fd4e5da5Sopenharmony_ci for inst in grammar.instructions: 108fd4e5da5Sopenharmony_ci parts.append(self.enum_value(grammar.name, inst['opname'], inst['opcode'])) 109fd4e5da5Sopenharmony_ci parts.append(self.enum_end(grammar.name, 'Instructions')) 110fd4e5da5Sopenharmony_ci parts.append('') 111fd4e5da5Sopenharmony_ci 112fd4e5da5Sopenharmony_ci if grammar.operand_kinds: 113fd4e5da5Sopenharmony_ci for kind in grammar.operand_kinds: 114fd4e5da5Sopenharmony_ci parts.append(self.enum_prefix(grammar.name, kind['kind'])) 115fd4e5da5Sopenharmony_ci for e in kind['enumerants']: 116fd4e5da5Sopenharmony_ci parts.append(self.enum_value(grammar.name, e['enumerant'], e['value'])) 117fd4e5da5Sopenharmony_ci parts.append(self.enum_end(grammar.name, kind['kind'])) 118fd4e5da5Sopenharmony_ci parts.append('') 119fd4e5da5Sopenharmony_ci 120fd4e5da5Sopenharmony_ci parts.append(self.cpp_guard_postamble()) 121fd4e5da5Sopenharmony_ci 122fd4e5da5Sopenharmony_ci if self.uses_guards: 123fd4e5da5Sopenharmony_ci parts.append('#endif // {}'.format(guard)) 124fd4e5da5Sopenharmony_ci 125fd4e5da5Sopenharmony_ci return '\n'.join(parts) 126fd4e5da5Sopenharmony_ci 127fd4e5da5Sopenharmony_ci 128fd4e5da5Sopenharmony_ciclass CLikeGenerator(LangGenerator): 129fd4e5da5Sopenharmony_ci def uses_guards(self): 130fd4e5da5Sopenharmony_ci return True 131fd4e5da5Sopenharmony_ci 132fd4e5da5Sopenharmony_ci def comment_prefix(self): 133fd4e5da5Sopenharmony_ci return "// " 134fd4e5da5Sopenharmony_ci 135fd4e5da5Sopenharmony_ci def const_definition(self, prefix, var, value): 136fd4e5da5Sopenharmony_ci # Use an anonymous enum. Don't use a static const int variable because 137fd4e5da5Sopenharmony_ci # that can bloat binary size. 138fd4e5da5Sopenharmony_ci return 'enum {0} {1}{2} = {3}, {1}{2}_BitWidthPadding = 0x7fffffff {4};'.format( 139fd4e5da5Sopenharmony_ci '{', prefix, var, value, '}') 140fd4e5da5Sopenharmony_ci 141fd4e5da5Sopenharmony_ci def enum_prefix(self, prefix, name): 142fd4e5da5Sopenharmony_ci return 'enum {}{} {}'.format(prefix, name, '{') 143fd4e5da5Sopenharmony_ci 144fd4e5da5Sopenharmony_ci def enum_end(self, prefix, enum): 145fd4e5da5Sopenharmony_ci return ' {}{}Max = 0x7ffffff\n{};\n'.format(prefix, enum, '}') 146fd4e5da5Sopenharmony_ci 147fd4e5da5Sopenharmony_ci def cpp_guard_preamble(self): 148fd4e5da5Sopenharmony_ci return '#ifdef __cplusplus\nextern "C" {\n#endif\n' 149fd4e5da5Sopenharmony_ci 150fd4e5da5Sopenharmony_ci def cpp_guard_postamble(self): 151fd4e5da5Sopenharmony_ci return '#ifdef __cplusplus\n}\n#endif\n' 152fd4e5da5Sopenharmony_ci 153fd4e5da5Sopenharmony_ci 154fd4e5da5Sopenharmony_ciclass CGenerator(CLikeGenerator): 155fd4e5da5Sopenharmony_ci pass 156fd4e5da5Sopenharmony_ci 157fd4e5da5Sopenharmony_ci 158fd4e5da5Sopenharmony_cidef main(): 159fd4e5da5Sopenharmony_ci import argparse 160fd4e5da5Sopenharmony_ci parser = argparse.ArgumentParser(description='Generate language headers from a JSON grammar') 161fd4e5da5Sopenharmony_ci 162fd4e5da5Sopenharmony_ci parser.add_argument('--extinst-grammar', metavar='<path>', 163fd4e5da5Sopenharmony_ci type=str, required=True, 164fd4e5da5Sopenharmony_ci help='input JSON grammar file for extended instruction set') 165fd4e5da5Sopenharmony_ci parser.add_argument('--extinst-output-path', metavar='<path>', 166fd4e5da5Sopenharmony_ci type=str, required=True, 167fd4e5da5Sopenharmony_ci help='Path of the language-specific output file.') 168fd4e5da5Sopenharmony_ci args = parser.parse_args() 169fd4e5da5Sopenharmony_ci 170fd4e5da5Sopenharmony_ci with open(args.extinst_grammar) as json_file: 171fd4e5da5Sopenharmony_ci grammar_json = json.loads(json_file.read()) 172fd4e5da5Sopenharmony_ci grammar_name = os.path.splitext(os.path.basename(args.extinst_output_path))[0] 173fd4e5da5Sopenharmony_ci grammar = ExtInstGrammar(name = grammar_name, 174fd4e5da5Sopenharmony_ci copyright = grammar_json['copyright'], 175fd4e5da5Sopenharmony_ci instructions = grammar_json['instructions'], 176fd4e5da5Sopenharmony_ci operand_kinds = grammar_json['operand_kinds'], 177fd4e5da5Sopenharmony_ci version = grammar_json['version'], 178fd4e5da5Sopenharmony_ci revision = grammar_json['revision']) 179fd4e5da5Sopenharmony_ci make_path_to_file(args.extinst_output_path) 180fd4e5da5Sopenharmony_ci with open(args.extinst_output_path, 'w') as f: 181fd4e5da5Sopenharmony_ci f.write(CGenerator().generate(grammar)) 182fd4e5da5Sopenharmony_ci 183fd4e5da5Sopenharmony_ci 184fd4e5da5Sopenharmony_ciif __name__ == '__main__': 185fd4e5da5Sopenharmony_ci main() 186