Fix folding insert feeding extract
[platform/upstream/SPIRV-Tools.git] / utils / generate_language_headers.py
1 #!/usr/bin/env python
2 # Copyright (c) 2017 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 language headers from a JSON grammar file"""
16
17 from __future__ import print_function
18
19 import errno
20 import json
21 import os.path
22 import re
23
24
25 def make_path_to_file(f):
26     """Makes all ancestor directories to the given file, if they
27     don't yet exist.
28
29     Arguments:
30         f: The file whose ancestor directories are to be created.
31     """
32     dir = os.path.dirname(os.path.abspath(f))
33     try:
34         os.makedirs(dir)
35     except OSError as e:
36         if e.errno == errno.EEXIST and os.path.isdir(dir):
37             pass
38         else:
39             raise
40
41 class ExtInstGrammar:
42     """The grammar for an extended instruction set"""
43
44     def __init__(self, name, copyright, instructions, operand_kinds, version = None, revision = None):
45        self.name = name
46        self.copyright = copyright
47        self.instructions = instructions
48        self.operand_kinds = operand_kinds
49        self.version = version
50        self.revision = revision
51
52
53 class LangGenerator:
54     """A language-specific generator"""
55
56     def __init__(self):
57         self.upper_case_initial = re.compile('^[A-Z]')
58         pass
59
60     def comment_prefix(self):
61         return ""
62
63     def namespace_prefix(self):
64         return ""
65
66     def uses_guards(self):
67         return False
68
69     def cpp_guard_preamble(self):
70         return ""
71
72     def cpp_guard_postamble(self):
73         return ""
74
75     def enum_value(self, prefix, name, value):
76         if self.upper_case_initial.match(name):
77             use_name = name
78         else:
79             use_name = '_' + name
80
81         return "    {}{} = {},".format(prefix, use_name, value)
82
83     def generate(self, grammar):
84         """Returns a string that is the language-specific header for the given grammar"""
85
86         parts = []
87         if grammar.copyright:
88             parts.extend(["{}{}".format(self.comment_prefix(), f) for f in grammar.copyright])
89         parts.append('')
90
91         guard = 'SPIRV_EXTINST_{}_H_'.format(grammar.name)
92         if self.uses_guards:
93             parts.append('#ifndef {}'.format(guard))
94             parts.append('#define {}'.format(guard))
95         parts.append('')
96
97         parts.append(self.cpp_guard_preamble())
98
99         if grammar.version:
100             parts.append(self.const_definition(grammar.name, 'Version', grammar.version))
101
102         if grammar.revision is not None:
103             parts.append(self.const_definition(grammar.name, 'Revision', grammar.revision))
104
105         parts.append('')
106
107         if grammar.instructions:
108             parts.append(self.enum_prefix(grammar.name, 'Instructions'))
109             for inst in grammar.instructions:
110                 parts.append(self.enum_value(grammar.name, inst['opname'], inst['opcode']))
111             parts.append(self.enum_end(grammar.name, 'Instructions'))
112             parts.append('')
113
114         if grammar.operand_kinds:
115             for kind in grammar.operand_kinds:
116                 parts.append(self.enum_prefix(grammar.name, kind['kind']))
117                 for e in kind['enumerants']:
118                     parts.append(self.enum_value(grammar.name, e['enumerant'], e['value']))
119                 parts.append(self.enum_end(grammar.name, kind['kind']))
120             parts.append('')
121
122         parts.append(self.cpp_guard_postamble())
123
124         if self.uses_guards:
125             parts.append('#endif // {}'.format(guard))
126
127         return '\n'.join(parts)
128
129
130 class CLikeGenerator(LangGenerator):
131     def uses_guards(self):
132         return True
133
134     def comment_prefix(self):
135         return "// "
136
137     def const_definition(self, prefix, var, value):
138         # Use an anonymous enum.  Don't use a static const int variable because
139         # that can bloat binary size.
140         return 'enum {0} {1}{2} = {3}, {1}{2}_BitWidthPadding = 0x7fffffff {4};'.format(
141                '{', prefix, var, value, '}')
142
143     def enum_prefix(self, prefix, name):
144         return 'enum {}{} {}'.format(prefix, name, '{')
145
146     def enum_end(self, prefix, enum):
147         return '    {}{}Max = 0x7ffffff\n{};\n'.format(prefix, enum, '}')
148
149     def cpp_guard_preamble(self):
150         return '#ifdef __cplusplus\nextern "C" {\n#endif\n'
151
152     def cpp_guard_postamble(self):
153         return '#ifdef __cplusplus\n}\n#endif\n'
154
155
156 class CGenerator(CLikeGenerator):
157     pass
158
159
160 def main():
161     import argparse
162     parser = argparse.ArgumentParser(description='Generate language headers from a JSON grammar')
163
164     parser.add_argument('--extinst-name',
165                         type=str, required=True,
166                         help='The name to use in tokens')
167     parser.add_argument('--extinst-grammar', metavar='<path>',
168                         type=str, required=True,
169                         help='input JSON grammar file for extended instruction set')
170     parser.add_argument('--extinst-output-base', metavar='<path>',
171                         type=str, required=True,
172                         help='Basename of the language-specific output file.')
173     args = parser.parse_args()
174
175     with open(args.extinst_grammar) as json_file:
176         grammar_json = json.loads(json_file.read())
177         grammar = ExtInstGrammar(name = args.extinst_name,
178                                  copyright = grammar_json['copyright'],
179                                  instructions = grammar_json['instructions'],
180                                  operand_kinds = grammar_json['operand_kinds'],
181                                  version = grammar_json['version'],
182                                  revision = grammar_json['revision'])
183         make_path_to_file(args.extinst_output_base)
184         print(CGenerator().generate(grammar), file=open(args.extinst_output_base + '.h', 'w'))
185
186
187 if __name__ == '__main__':
188     main()