swr: [rasterizer codegen] Rewrite gen_llvm_types.py to use mako
[mesa.git] / src / gallium / drivers / swr / rasterizer / codegen / gen_llvm_types.py
1 # Copyright (C) 2014-2017 Intel Corporation. All Rights Reserved.
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the "Software"),
5 # to deal in the Software without restriction, including without limitation
6 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 # and/or sell copies of the Software, and to permit persons to whom the
8 # Software is furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice (including the next
11 # paragraph) shall be included in all copies or substantial portions of the
12 # Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21
22 from __future__ import print_function
23 import os, sys, re
24 import argparse
25 import json as JSON
26 import operator
27 from mako.template import Template
28 from mako.exceptions import RichTraceback
29
30 def write_template_to_string(template_filename, **kwargs):
31 try:
32 template = Template(filename=os.path.abspath(template_filename))
33 # Split + Join fixes line-endings for whatever platform you are using
34 return '\n'.join(template.render(**kwargs).splitlines())
35 except:
36 traceback = RichTraceback()
37 for (filename, lineno, function, line) in traceback.traceback:
38 print('File %s, line %s, in %s' % (filename, lineno, function))
39 print(line, '\n')
40 print('%s: %s' % (str(traceback.error.__class__.__name__), traceback.error))
41
42 def write_template_to_file(template_filename, output_filename, **kwargs):
43 output_dirname = os.path.dirname(output_filename)
44 if not os.path.exists(output_dirname):
45 os.makedirs(output_dirname)
46 with open(output_filename, 'w') as outfile:
47 print(write_template_to_string(template_filename, **kwargs), file=outfile)
48
49 '''
50 '''
51 def gen_llvm_type(type, name, is_pointer, is_pointer_pointer, is_array, is_array_array, array_count, array_count1, is_llvm_struct, is_llvm_enum, is_llvm_pfn, output_file):
52
53 llvm_type = ''
54
55 if is_llvm_struct:
56 if is_pointer or is_pointer_pointer:
57 llvm_type = 'Type::getInt32Ty(ctx)'
58 else:
59 llvm_type = 'ArrayType::get(Type::getInt8Ty(ctx), sizeof(%s))' % type
60 elif is_llvm_enum:
61 llvm_type = 'Type::getInt32Ty(ctx)'
62 elif is_llvm_pfn:
63 llvm_type = 'PointerType::get(Type::getInt8Ty(ctx), 0)'
64 else:
65 if type == 'BYTE' or type == 'char' or type == 'uint8_t' or type == 'int8_t' or type == 'bool':
66 llvm_type = 'Type::getInt8Ty(ctx)'
67 elif type == 'UINT64' or type == 'INT64' or type == 'uint64_t' or type == 'int64_t':
68 llvm_type = 'Type::getInt64Ty(ctx)'
69 elif type == 'UINT16' or type == 'int16_t' or type == 'uint16_t':
70 llvm_type = 'Type::getInt16Ty(ctx)'
71 elif type == 'UINT' or type == 'INT' or type == 'int' or type == 'BOOL' or type == 'uint32_t' or type == 'int32_t':
72 llvm_type = 'Type::getInt32Ty(ctx)'
73 elif type == 'float' or type == 'FLOAT':
74 llvm_type = 'Type::getFloatTy(ctx)'
75 elif type == 'double' or type == 'DOUBLE':
76 llvm_type = 'Type::getDoubleTy(ctx)'
77 elif type == 'void' or type == 'VOID':
78 llvm_type = 'Type::getInt32Ty(ctx)'
79 elif type == 'HANDLE':
80 llvm_type = 'PointerType::get(Type::getInt32Ty(ctx), 0)'
81 elif type == 'simdscalar':
82 llvm_type = 'VectorType::get(Type::getFloatTy(ctx), pJitMgr->mVWidth)'
83 elif type == 'simdscalari':
84 llvm_type = 'VectorType::get(Type::getInt32Ty(ctx), pJitMgr->mVWidth)'
85 elif type == 'SIMD8::vector_t':
86 llvm_type = 'VectorType::get(Type::getFloatTy(ctx), 8)'
87 elif type == 'SIMD8::vectori_t':
88 llvm_type = 'VectorType::get(Type::getInt32Ty(ctx), 8)'
89 elif type == 'SIMD16::vector_t':
90 llvm_type = 'VectorType::get(Type::getFloatTy(ctx), 16)'
91 elif type == 'SIMD16::vectori_t':
92 llvm_type = 'VectorType::get(Type::getInt32Ty(ctx), 16)'
93 elif type == 'simdvector':
94 llvm_type = 'ArrayType::get(VectorType::get(Type::getFloatTy(ctx), pJitMgr->mVWidth), 4)'
95 elif type == 'SIMD8::attrib_t':
96 llvm_type = 'ArrayType::get(VectorType::get(Type::getFloatTy(ctx), 8), 4)'
97 elif type == 'SIMD16::attrib_t':
98 llvm_type = 'ArrayType::get(VectorType::get(Type::getFloatTy(ctx), 16), 4)'
99 else:
100 llvm_type = 'Gen_%s(pJitMgr)' % type
101
102 if is_pointer:
103 llvm_type = 'PointerType::get(%s, 0)' % llvm_type
104
105 if is_pointer_pointer:
106 llvm_type = 'PointerType::get(%s, 0)' % llvm_type
107
108 if is_array_array:
109 llvm_type = 'ArrayType::get(ArrayType::get(%s, %s), %s)' % (llvm_type, array_count1, array_count)
110 elif is_array:
111 llvm_type = 'ArrayType::get(%s, %s)' % (llvm_type, array_count)
112
113 return {
114 'name' : name,
115 'type' : llvm_type,
116 }
117
118 '''
119 '''
120 def gen_llvm_types(input_file, output_file):
121
122 lines = input_file.readlines()
123
124 types = []
125
126 for idx in range(len(lines)):
127 line = lines[idx].rstrip()
128
129 if 'gen_llvm_types FINI' in line:
130 break
131
132 match = re.match(r'(\s*)struct(\s*)(\w+)', line)
133 if match:
134 llvm_args = []
135
136 # Detect start of structure
137 is_fwd_decl = re.search(r';', line)
138
139 if not is_fwd_decl:
140
141 # Extract the command name
142 struct_name = match.group(3).strip()
143
144 type_entry = {
145 'name' : struct_name,
146 'members' : [],
147 }
148
149 end_of_struct = False
150
151 while not end_of_struct and idx < len(lines)-1:
152 idx += 1
153 line = lines[idx].rstrip()
154
155 is_llvm_typedef = re.search(r'@llvm_typedef', line)
156 if is_llvm_typedef is not None:
157 is_llvm_typedef = True
158 else:
159 is_llvm_typedef = False
160
161 ###########################################
162 # Is field a llvm struct? Tells script to treat type as array of bytes that is size of structure.
163 is_llvm_struct = re.search(r'@llvm_struct', line)
164
165 if is_llvm_struct is not None:
166 is_llvm_struct = True
167 else:
168 is_llvm_struct = False
169
170 ###########################################
171 # Is field a llvm enum? Tells script to treat type as an enum and replaced with uint32 type.
172 is_llvm_enum = re.search(r'@llvm_enum', line)
173
174 if is_llvm_enum is not None:
175 is_llvm_enum = True
176 else:
177 is_llvm_enum = False
178
179 ###########################################
180 # Is field a llvm function pointer? Tells script to treat type as an enum and replaced with uint32 type.
181 is_llvm_pfn = re.search(r'@llvm_pfn', line)
182
183 if is_llvm_pfn is not None:
184 is_llvm_pfn = True
185 else:
186 is_llvm_pfn = False
187
188 ###########################################
189 # Is field const?
190 is_const = re.search(r'\s+const\s+', line)
191
192 if is_const is not None:
193 is_const = True
194 else:
195 is_const = False
196
197 ###########################################
198 # Is field a pointer?
199 is_pointer_pointer = re.search('\*\*', line)
200
201 if is_pointer_pointer is not None:
202 is_pointer_pointer = True
203 else:
204 is_pointer_pointer = False
205
206 ###########################################
207 # Is field a pointer?
208 is_pointer = re.search('\*', line)
209
210 if is_pointer is not None:
211 is_pointer = True
212 else:
213 is_pointer = False
214
215 ###########################################
216 # Is field an array of arrays?
217 # TODO: Can add this to a list.
218 is_array_array = re.search('\[(\w*)\]\[(\w*)\]', line)
219 array_count = '0'
220 array_count1 = '0'
221
222 if is_array_array is not None:
223 array_count = is_array_array.group(1)
224 array_count1 = is_array_array.group(2)
225 is_array_array = True
226 else:
227 is_array_array = False
228
229 ###########################################
230 # Is field an array?
231 is_array = re.search('\[(\w*)\]', line)
232
233 if is_array is not None:
234 array_count = is_array.group(1)
235 is_array = True
236 else:
237 is_array = False
238
239 is_scoped = re.search('::', line)
240
241 if is_scoped is not None:
242 is_scoped = True
243 else:
244 is_scoped = False
245
246 type = None
247 name = None
248 if is_const and is_pointer:
249
250 if is_scoped:
251 field_match = re.match(r'(\s*)(\w+\<*\w*\>*)(\s+)(\w+::)(\w+)(\s*\**\s*)(\w+)', line)
252
253 type = '%s%s' % (field_match.group(4), field_match.group(5))
254 name = field_match.group(7)
255 else:
256 field_match = re.match(r'(\s*)(\w+\<*\w*\>*)(\s+)(\w+)(\s*\**\s*)(\w+)', line)
257
258 type = field_match.group(4)
259 name = field_match.group(6)
260
261 elif is_pointer:
262 field_match = re.match(r'(\s*)(\s+)(\w+\<*\w*\>*)(\s*\**\s*)(\w+)', line)
263
264 if field_match:
265 type = field_match.group(3)
266 name = field_match.group(5)
267 elif is_const:
268 field_match = re.match(r'(\s*)(\w+\<*\w*\>*)(\s+)(\w+)(\s*)(\w+)', line)
269
270 if field_match:
271 type = field_match.group(4)
272 name = field_match.group(6)
273 else:
274 if is_scoped:
275 field_match = re.match(r'\s*(\w+\<*\w*\>*)\s*::\s*(\w+\<*\w*\>*)\s+(\w+)', line)
276
277 if field_match:
278 type = field_match.group(1) + '::' + field_match.group(2)
279 name = field_match.group(3)
280 else:
281 field_match = re.match(r'(\s*)(\w+\<*\w*\>*)(\s+)(\w+)', line)
282
283 if field_match:
284 type = field_match.group(2)
285 name = field_match.group(4)
286
287 if is_llvm_typedef is False:
288 if type is not None:
289 type_entry['members'].append(
290 gen_llvm_type(
291 type, name, is_pointer, is_pointer_pointer, is_array, is_array_array,
292 array_count, array_count1, is_llvm_struct, is_llvm_enum, is_llvm_pfn, output_file))
293
294 # Detect end of structure
295 end_of_struct = re.match(r'(\s*)};', line)
296
297 if end_of_struct:
298 types.append(type_entry)
299
300 cur_dir = os.path.dirname(os.path.abspath(__file__))
301 template = os.path.join(cur_dir, 'templates', 'gen_llvm.hpp')
302
303 write_template_to_file(
304 template,
305 output_file,
306 cmdline=sys.argv,
307 filename=os.path.basename(output_file),
308 types=types)
309
310 '''
311 Function which is invoked when this script is started from a command line.
312 Will present and consume a set of arguments which will tell this script how
313 to behave
314 '''
315 def main():
316
317 # Parse args...
318 parser = argparse.ArgumentParser()
319 parser.add_argument('--input', '-i', type=argparse.FileType('r'),
320 help='Path to input file containing structs', required=True)
321 parser.add_argument('--output', '-o', action='store',
322 help='Path to output file', required=True)
323 args = parser.parse_args()
324
325 gen_llvm_types(args.input, args.output)
326
327 if __name__ == '__main__':
328 main()
329 # END OF FILE