b0002d888fb2958aede15c9804e4f64b9a3f1926
[mesa.git] / src / gallium / drivers / swr / rasterizer / codegen / gen_llvm_ir_macros.py
1 # Copyright (C) 2014-2018 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 from gen_common import *
25 from argparse import FileType
26
27 inst_aliases = {
28 'SHUFFLE_VECTOR': 'VSHUFFLE',
29 'INSERT_ELEMENT': 'VINSERT',
30 'EXTRACT_ELEMENT': 'VEXTRACT',
31 'MEM_SET': 'MEMSET',
32 'MEM_CPY': 'MEMCOPY',
33 'MEM_MOVE': 'MEMMOVE',
34 'L_SHR': 'LSHR',
35 'A_SHR': 'ASHR',
36 'BIT_CAST': 'BITCAST',
37 'U_DIV': 'UDIV',
38 'S_DIV': 'SDIV',
39 'U_REM': 'UREM',
40 'S_REM': 'SREM',
41 'BIN_OP': 'BINOP',
42 }
43
44 intrinsics = [
45 ['VGATHERPD', ['src', 'pBase', 'indices', 'mask', 'scale'], 'src'],
46 ['VGATHERPS', ['src', 'pBase', 'indices', 'mask', 'scale'], 'src'],
47 ['VGATHERDD', ['src', 'pBase', 'indices', 'mask', 'scale'], 'src'],
48 ['VSCATTERPS', ['pBase', 'mask', 'indices', 'src', 'scale'], 'src'],
49 ['VRCPPS', ['a'], 'a'],
50 ['VROUND', ['a', 'rounding'], 'a'],
51 ['BEXTR_32', ['src', 'control'], 'src'],
52 ['VPSHUFB', ['a', 'b'], 'a'],
53 ['VPERMD', ['a', 'idx'], 'a'],
54 ['VPERMPS', ['idx', 'a'], 'a'],
55 ['VCVTPD2PS', ['a'], 'VectorType::get(mFP32Ty, VEC_GET_NUM_ELEMS)'],
56 ['VCVTPS2PH', ['a', 'round'], 'mSimdInt16Ty'],
57 ['VHSUBPS', ['a', 'b'], 'a'],
58 ['VPTESTC', ['a', 'b'], 'mInt32Ty'],
59 ['VPTESTZ', ['a', 'b'], 'mInt32Ty'],
60 ['VPHADDD', ['a', 'b'], 'a'],
61 ['PDEP32', ['a', 'b'], 'a'],
62 ['RDTSC', [], 'mInt64Ty'],
63 ]
64
65 llvm_intrinsics = [
66 ['CTTZ', 'cttz', ['a', 'flag'], ['a']],
67 ['CTLZ', 'ctlz', ['a', 'flag'], ['a']],
68 ['VSQRTPS', 'sqrt', ['a'], ['a']],
69 ['STACKSAVE', 'stacksave', [], []],
70 ['STACKRESTORE', 'stackrestore', ['a'], []],
71 ['VMINPS', 'minnum', ['a', 'b'], ['a']],
72 ['VMAXPS', 'maxnum', ['a', 'b'], ['a']],
73 ['VFMADDPS', 'fmuladd', ['a', 'b', 'c'], ['a']],
74 ['DEBUGTRAP', 'debugtrap', [], []],
75 ['POPCNT', 'ctpop', ['a'], ['a']],
76 ['LOG2', 'log2', ['a'], ['a']],
77 ['FABS', 'fabs', ['a'], ['a']],
78 ['EXP2', 'exp2', ['a'], ['a']],
79 ['COS', 'cos', ['a'], ['a']],
80 ['SIN', 'sin', ['a'], ['a']],
81 ['FLOOR', 'floor', ['a'], ['a']],
82 ['POW', 'pow', ['a', 'b'], ['a']]
83 ]
84
85 this_dir = os.path.dirname(os.path.abspath(__file__))
86 template = os.path.join(this_dir, 'templates', 'gen_builder.hpp')
87
88 def convert_uppercamel(name):
89 s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
90 return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).upper()
91
92 '''
93 Given an input file (e.g. IRBuilder.h) generates function dictionary.
94 '''
95 def parse_ir_builder(input_file):
96
97 functions = []
98
99 lines = input_file.readlines()
100 deprecated = None
101
102 idx = 0
103 while idx < len(lines) - 1:
104 line = lines[idx].rstrip()
105 idx += 1
106
107 if deprecated is None:
108 deprecated = re.search(r'LLVM_ATTRIBUTE_DEPRECATED', line)
109
110 #match = re.search(r'\*Create', line)
111 match = re.search(r'[\*\s]Create(\w*)\(', line)
112 if match is not None:
113 #print('Line: %s' % match.group(1))
114
115 # Skip function if LLVM_ATTRIBUTE_DEPRECATED found before
116 if deprecated is not None:
117 deprecated = None
118 continue
119
120 if re.search(r'^\s*Create', line) is not None:
121 func_sig = lines[idx-2].rstrip() + line
122 else:
123 func_sig = line
124
125 end_of_args = False
126 while not end_of_args:
127 end_paren = re.search(r'\)', line)
128 if end_paren is not None:
129 end_of_args = True
130 else:
131 line = lines[idx].rstrip()
132 func_sig += line
133 idx += 1
134
135 delfunc = re.search(r'LLVM_DELETED_FUNCTION|= delete;', func_sig)
136
137 if not delfunc:
138 func = re.search(r'(.*?)\*[\n\s]*(Create\w*)\((.*?)\)', func_sig)
139 if func is not None:
140
141 return_type = func.group(1).strip() + '*'
142 func_name = func.group(2)
143 arguments = func.group(3)
144
145 func_args = []
146 arg_names = []
147 args = arguments.split(',')
148 for arg in args:
149 arg = arg.strip()
150 if arg:
151 func_args.append(arg)
152
153 split_args = arg.split('=')
154 arg_name = split_args[0].rsplit(None, 1)[-1]
155
156 reg_arg = re.search(r'[\&\*]*(\w*)', arg_name)
157 if reg_arg:
158 arg_names += [reg_arg.group(1)]
159
160 ignore = False
161
162 # The following functions need to be ignored in openswr.
163 # API change in llvm-5.0 breaks baked autogen files
164 if (
165 (func_name == 'CreateFence' or
166 func_name == 'CreateAtomicCmpXchg' or
167 func_name == 'CreateAtomicRMW')):
168 ignore = True
169
170 # The following functions need to be ignored.
171 if (func_name == 'CreateInsertNUWNSWBinOp' or
172 func_name == 'CreateMaskedIntrinsic' or
173 func_name == 'CreateAlignmentAssumptionHelper' or
174 func_name == 'CreateGEP' or
175 func_name == 'CreateLoad' or
176 func_name == 'CreateMaskedLoad' or
177 func_name == 'CreateStore' or
178 func_name == 'CreateMaskedStore' or
179 func_name == 'CreateFCmpHelper' or
180 func_name == 'CreateElementUnorderedAtomicMemCpy'):
181 ignore = True
182
183 # Convert CamelCase to CAMEL_CASE
184 func_mod = re.search(r'Create(\w*)', func_name)
185 if func_mod:
186 func_mod = func_mod.group(1)
187 func_mod = convert_uppercamel(func_mod)
188 if func_mod[0:2] == 'F_' or func_mod[0:2] == 'I_':
189 func_mod = func_mod[0] + func_mod[2:]
190
191 # Substitute alias based on CAMEL_CASE name.
192 func_alias = inst_aliases.get(func_mod)
193 if not func_alias:
194 func_alias = func_mod
195
196 if func_name == 'CreateCall' or func_name == 'CreateGEP':
197 arglist = re.search(r'ArrayRef', ', '.join(func_args))
198 if arglist:
199 func_alias = func_alias + 'A'
200
201 if not ignore:
202 functions.append({
203 'name' : func_name,
204 'alias' : func_alias,
205 'return' : return_type,
206 'args' : ', '.join(func_args),
207 'arg_names' : arg_names,
208 })
209
210 return functions
211
212 '''
213 Auto-generates macros for LLVM IR
214 '''
215 def generate_gen_h(functions, output_dir):
216 filename = 'gen_builder.hpp'
217 output_filename = os.path.join(output_dir, filename)
218
219 templfuncs = []
220 for func in functions:
221 decl = '%s %s(%s)' % (func['return'], func['alias'], func['args'])
222
223 templfuncs.append({
224 'decl' : decl,
225 'intrin' : func['name'],
226 'args' : func['arg_names'],
227 })
228
229 MakoTemplateWriter.to_file(
230 template,
231 output_filename,
232 cmdline=sys.argv,
233 comment='Builder IR Wrappers',
234 filename=filename,
235 functions=templfuncs,
236 isX86=False, isIntrin=False)
237
238 '''
239 Auto-generates macros for LLVM IR
240 '''
241 def generate_meta_h(output_dir):
242 filename = 'gen_builder_meta.hpp'
243 output_filename = os.path.join(output_dir, filename)
244
245 functions = []
246 for inst in intrinsics:
247 name = inst[0]
248 args = inst[1]
249 ret = inst[2]
250
251 #print('Inst: %s, x86: %s numArgs: %d' % (inst[0], inst[1], len(inst[2])))
252 if len(args) != 0:
253 declargs = 'Value* ' + ', Value* '.join(args)
254 decl = 'Value* %s(%s, const llvm::Twine& name = "")' % (name, declargs)
255 else:
256 decl = 'Value* %s(const llvm::Twine& name = "")' % (name)
257
258 # determine the return type of the intrinsic. It can either be:
259 # - type of one of the input arguments
260 # - snippet of code to set the return type
261
262 if ret in args:
263 returnTy = ret + '->getType()'
264 else:
265 returnTy = ret
266
267 functions.append({
268 'decl' : decl,
269 'name' : name,
270 'args' : args,
271 'returnType': returnTy
272 })
273
274 MakoTemplateWriter.to_file(
275 template,
276 output_filename,
277 cmdline=sys.argv,
278 comment='meta intrinsics',
279 filename=filename,
280 functions=functions,
281 isX86=True, isIntrin=False)
282
283 def generate_intrin_h(output_dir):
284 filename = 'gen_builder_intrin.hpp'
285 output_filename = os.path.join(output_dir, filename)
286
287 functions = []
288 for inst in llvm_intrinsics:
289 #print('Inst: %s, x86: %s numArgs: %d' % (inst[0], inst[1], len(inst[2])))
290 if len(inst[2]) != 0:
291 declargs = 'Value* ' + ', Value* '.join(inst[2])
292 decl = 'Value* %s(%s, const llvm::Twine& name = "")' % (inst[0], declargs)
293 else:
294 decl = 'Value* %s(const llvm::Twine& name = "")' % (inst[0])
295
296 functions.append({
297 'decl' : decl,
298 'intrin' : inst[1],
299 'args' : inst[2],
300 'types' : inst[3],
301 })
302
303 MakoTemplateWriter.to_file(
304 template,
305 output_filename,
306 cmdline=sys.argv,
307 comment='llvm intrinsics',
308 filename=filename,
309 functions=functions,
310 isX86=False, isIntrin=True)
311 '''
312 Function which is invoked when this script is started from a command line.
313 Will present and consume a set of arguments which will tell this script how
314 to behave
315 '''
316 def main():
317
318 # Parse args...
319 parser = ArgumentParser()
320 parser.add_argument('--input', '-i', type=FileType('r'), help='Path to IRBuilder.h', required=False)
321 parser.add_argument('--output-dir', '-o', action='store', dest='output', help='Path to output directory', required=True)
322 parser.add_argument('--gen_h', help='Generate builder_gen.h', action='store_true', default=False)
323 parser.add_argument('--gen_meta_h', help='Generate meta intrinsics. No input is needed.', action='store_true', default=False)
324 parser.add_argument('--gen_intrin_h', help='Generate llvm intrinsics. No input is needed.', action='store_true', default=False)
325 args = parser.parse_args()
326
327 if not os.path.exists(args.output):
328 os.makedirs(args.output)
329
330 final_output_dir = args.output
331 args.output = MakeTmpDir('_codegen')
332
333 rval = 0
334 try:
335 if args.input:
336 functions = parse_ir_builder(args.input)
337
338 if args.gen_h:
339 generate_gen_h(functions, args.output)
340
341 elif args.gen_h:
342 print('Need to specify --input for --gen_h!')
343
344 if args.gen_meta_h:
345 generate_meta_h(args.output)
346
347 if args.gen_intrin_h:
348 generate_intrin_h(args.output)
349
350 rval = CopyDirFilesIfDifferent(args.output, final_output_dir)
351
352 except:
353 print('ERROR: Could not generate llvm_ir_macros', file=sys.stderr)
354 rval = 1
355
356 finally:
357 DeleteDirTree(args.output)
358
359 return rval
360
361 if __name__ == '__main__':
362 sys.exit(main())
363 # END OF FILE