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