| # Copyright (C) 2014-2018 Intel Corporation. All Rights Reserved. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a |
| # copy of this software and associated documentation files (the "Software"), |
| # to deal in the Software without restriction, including without limitation |
| # the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| # and/or sell copies of the Software, and to permit persons to whom the |
| # Software is furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice (including the next |
| # paragraph) shall be included in all copies or substantial portions of the |
| # Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| # IN THE SOFTWARE. |
| |
| from __future__ import print_function |
| import os, sys, re |
| from gen_common import * |
| from argparse import FileType |
| |
| inst_aliases = { |
| 'SHUFFLE_VECTOR': 'VSHUFFLE', |
| 'INSERT_ELEMENT': 'VINSERT', |
| 'EXTRACT_ELEMENT': 'VEXTRACT', |
| 'MEM_SET': 'MEMSET', |
| 'MEM_CPY': 'MEMCOPY', |
| 'MEM_MOVE': 'MEMMOVE', |
| 'L_SHR': 'LSHR', |
| 'A_SHR': 'ASHR', |
| 'BIT_CAST': 'BITCAST', |
| 'U_DIV': 'UDIV', |
| 'S_DIV': 'SDIV', |
| 'U_REM': 'UREM', |
| 'S_REM': 'SREM', |
| 'BIN_OP': 'BINOP', |
| } |
| |
| intrinsics = [ |
| ['VGATHERPD', ['src', 'pBase', 'indices', 'mask', 'scale'], 'src'], |
| ['VGATHERPS', ['src', 'pBase', 'indices', 'mask', 'scale'], 'src'], |
| ['VGATHERDD', ['src', 'pBase', 'indices', 'mask', 'scale'], 'src'], |
| ['VRCPPS', ['a'], 'a'], |
| ['VROUND', ['a', 'rounding'], 'a'], |
| ['BEXTR_32', ['src', 'control'], 'src'], |
| ['VPSHUFB', ['a', 'b'], 'a'], |
| ['VPERMD', ['a', 'idx'], 'a'], |
| ['VPERMPS', ['idx', 'a'], 'a'], |
| ['VCVTPD2PS', ['a'], 'VectorType::get(mFP32Ty, a->getType()->getVectorNumElements())'], |
| ['VCVTPH2PS', ['a'], 'VectorType::get(mFP32Ty, a->getType()->getVectorNumElements())'], |
| ['VCVTPS2PH', ['a', 'round'], 'mSimdInt16Ty'], |
| ['VHSUBPS', ['a', 'b'], 'a'], |
| ['VPTESTC', ['a', 'b'], 'mInt32Ty'], |
| ['VPTESTZ', ['a', 'b'], 'mInt32Ty'], |
| ['VPHADDD', ['a', 'b'], 'a'], |
| ['PDEP32', ['a', 'b'], 'a'], |
| ['RDTSC', [], 'mInt64Ty'], |
| ] |
| |
| llvm_intrinsics = [ |
| ['CTTZ', 'cttz', ['a', 'flag'], ['a']], |
| ['CTLZ', 'ctlz', ['a', 'flag'], ['a']], |
| ['VSQRTPS', 'sqrt', ['a'], ['a']], |
| ['STACKSAVE', 'stacksave', [], []], |
| ['STACKRESTORE', 'stackrestore', ['a'], []], |
| ['VMINPS', 'minnum', ['a', 'b'], ['a']], |
| ['VMAXPS', 'maxnum', ['a', 'b'], ['a']], |
| ['VFMADDPS', 'fmuladd', ['a', 'b', 'c'], ['a']], |
| ['DEBUGTRAP', 'debugtrap', [], []], |
| ['POPCNT', 'ctpop', ['a'], ['a']], |
| ['LOG2', 'log2', ['a'], ['a']], |
| ['FABS', 'fabs', ['a'], ['a']], |
| ['EXP2', 'exp2', ['a'], ['a']], |
| ['POW', 'pow', ['a', 'b'], ['a']] |
| ] |
| |
| this_dir = os.path.dirname(os.path.abspath(__file__)) |
| template = os.path.join(this_dir, 'templates', 'gen_builder.hpp') |
| |
| def convert_uppercamel(name): |
| s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) |
| return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).upper() |
| |
| ''' |
| Given an input file (e.g. IRBuilder.h) generates function dictionary. |
| ''' |
| def parse_ir_builder(input_file): |
| |
| functions = [] |
| |
| lines = input_file.readlines() |
| |
| idx = 0 |
| while idx < len(lines) - 1: |
| line = lines[idx].rstrip() |
| idx += 1 |
| |
| #match = re.search(r'\*Create', line) |
| match = re.search(r'[\*\s]Create(\w*)\(', line) |
| if match is not None: |
| #print('Line: %s' % match.group(1)) |
| |
| if re.search(r'^\s*Create', line) is not None: |
| func_sig = lines[idx-2].rstrip() + line |
| else: |
| func_sig = line |
| |
| end_of_args = False |
| while not end_of_args: |
| end_paren = re.search(r'\)', line) |
| if end_paren is not None: |
| end_of_args = True |
| else: |
| line = lines[idx].rstrip() |
| func_sig += line |
| idx += 1 |
| |
| delfunc = re.search(r'LLVM_DELETED_FUNCTION|= delete;', func_sig) |
| |
| if not delfunc: |
| func = re.search(r'(.*?)\*[\n\s]*(Create\w*)\((.*?)\)', func_sig) |
| if func is not None: |
| |
| return_type = func.group(1).strip() + '*' |
| func_name = func.group(2) |
| arguments = func.group(3) |
| |
| func_args = [] |
| arg_names = [] |
| args = arguments.split(',') |
| for arg in args: |
| arg = arg.strip() |
| if arg: |
| func_args.append(arg) |
| |
| split_args = arg.split('=') |
| arg_name = split_args[0].rsplit(None, 1)[-1] |
| |
| reg_arg = re.search(r'[\&\*]*(\w*)', arg_name) |
| if reg_arg: |
| arg_names += [reg_arg.group(1)] |
| |
| ignore = False |
| |
| # The following functions need to be ignored in openswr. |
| # API change in llvm-5.0 breaks baked autogen files |
| if ( |
| (func_name == 'CreateFence' or |
| func_name == 'CreateAtomicCmpXchg' or |
| func_name == 'CreateAtomicRMW')): |
| ignore = True |
| |
| # The following functions need to be ignored. |
| if (func_name == 'CreateInsertNUWNSWBinOp' or |
| func_name == 'CreateMaskedIntrinsic' or |
| func_name == 'CreateAlignmentAssumptionHelper' or |
| func_name == 'CreateGEP' or |
| func_name == 'CreateLoad' or |
| func_name == 'CreateMaskedLoad' or |
| func_name == 'CreateElementUnorderedAtomicMemCpy'): |
| ignore = True |
| |
| # Convert CamelCase to CAMEL_CASE |
| func_mod = re.search(r'Create(\w*)', func_name) |
| if func_mod: |
| func_mod = func_mod.group(1) |
| func_mod = convert_uppercamel(func_mod) |
| if func_mod[0:2] == 'F_' or func_mod[0:2] == 'I_': |
| func_mod = func_mod[0] + func_mod[2:] |
| |
| # Substitute alias based on CAMEL_CASE name. |
| func_alias = inst_aliases.get(func_mod) |
| if not func_alias: |
| func_alias = func_mod |
| |
| if func_name == 'CreateCall' or func_name == 'CreateGEP': |
| arglist = re.search(r'ArrayRef', ', '.join(func_args)) |
| if arglist: |
| func_alias = func_alias + 'A' |
| |
| if not ignore: |
| functions.append({ |
| 'name' : func_name, |
| 'alias' : func_alias, |
| 'return' : return_type, |
| 'args' : ', '.join(func_args), |
| 'arg_names' : arg_names, |
| }) |
| |
| return functions |
| |
| ''' |
| Auto-generates macros for LLVM IR |
| ''' |
| def generate_gen_h(functions, output_dir): |
| filename = 'gen_builder.hpp' |
| output_filename = os.path.join(output_dir, filename) |
| |
| templfuncs = [] |
| for func in functions: |
| decl = '%s %s(%s)' % (func['return'], func['alias'], func['args']) |
| |
| templfuncs.append({ |
| 'decl' : decl, |
| 'intrin' : func['name'], |
| 'args' : func['arg_names'], |
| }) |
| |
| MakoTemplateWriter.to_file( |
| template, |
| output_filename, |
| cmdline=sys.argv, |
| comment='Builder IR Wrappers', |
| filename=filename, |
| functions=templfuncs, |
| isX86=False, isIntrin=False) |
| |
| ''' |
| Auto-generates macros for LLVM IR |
| ''' |
| def generate_meta_h(output_dir): |
| filename = 'gen_builder_meta.hpp' |
| output_filename = os.path.join(output_dir, filename) |
| |
| functions = [] |
| for inst in intrinsics: |
| name = inst[0] |
| args = inst[1] |
| ret = inst[2] |
| |
| #print('Inst: %s, x86: %s numArgs: %d' % (inst[0], inst[1], len(inst[2]))) |
| if len(args) != 0: |
| declargs = 'Value* ' + ', Value* '.join(args) |
| decl = 'Value* %s(%s, const llvm::Twine& name = "")' % (name, declargs) |
| else: |
| decl = 'Value* %s(const llvm::Twine& name = "")' % (name) |
| |
| # determine the return type of the intrinsic. It can either be: |
| # - type of one of the input arguments |
| # - snippet of code to set the return type |
| |
| if ret in args: |
| returnTy = ret + '->getType()' |
| else: |
| returnTy = ret |
| |
| functions.append({ |
| 'decl' : decl, |
| 'name' : name, |
| 'args' : args, |
| 'returnType': returnTy |
| }) |
| |
| MakoTemplateWriter.to_file( |
| template, |
| output_filename, |
| cmdline=sys.argv, |
| comment='meta intrinsics', |
| filename=filename, |
| functions=functions, |
| isX86=True, isIntrin=False) |
| |
| def generate_intrin_h(output_dir): |
| filename = 'gen_builder_intrin.hpp' |
| output_filename = os.path.join(output_dir, filename) |
| |
| functions = [] |
| for inst in llvm_intrinsics: |
| #print('Inst: %s, x86: %s numArgs: %d' % (inst[0], inst[1], len(inst[2]))) |
| if len(inst[2]) != 0: |
| declargs = 'Value* ' + ', Value* '.join(inst[2]) |
| decl = 'Value* %s(%s, const llvm::Twine& name = "")' % (inst[0], declargs) |
| else: |
| decl = 'Value* %s(const llvm::Twine& name = "")' % (inst[0]) |
| |
| functions.append({ |
| 'decl' : decl, |
| 'intrin' : inst[1], |
| 'args' : inst[2], |
| 'types' : inst[3], |
| }) |
| |
| MakoTemplateWriter.to_file( |
| template, |
| output_filename, |
| cmdline=sys.argv, |
| comment='llvm intrinsics', |
| filename=filename, |
| functions=functions, |
| isX86=False, isIntrin=True) |
| ''' |
| Function which is invoked when this script is started from a command line. |
| Will present and consume a set of arguments which will tell this script how |
| to behave |
| ''' |
| def main(): |
| |
| # Parse args... |
| parser = ArgumentParser() |
| parser.add_argument('--input', '-i', type=FileType('r'), help='Path to IRBuilder.h', required=False) |
| parser.add_argument('--output-dir', '-o', action='store', dest='output', help='Path to output directory', required=True) |
| parser.add_argument('--gen_h', help='Generate builder_gen.h', action='store_true', default=False) |
| parser.add_argument('--gen_meta_h', help='Generate meta intrinsics. No input is needed.', action='store_true', default=False) |
| parser.add_argument('--gen_intrin_h', help='Generate llvm intrinsics. No input is needed.', action='store_true', default=False) |
| args = parser.parse_args() |
| |
| if not os.path.exists(args.output): |
| os.makedirs(args.output) |
| |
| final_output_dir = args.output |
| args.output = MakeTmpDir('_codegen') |
| |
| rval = 0 |
| try: |
| if args.input: |
| functions = parse_ir_builder(args.input) |
| |
| if args.gen_h: |
| generate_gen_h(functions, args.output) |
| |
| elif args.gen_h: |
| print('Need to specify --input for --gen_h!') |
| |
| if args.gen_meta_h: |
| generate_meta_h(args.output) |
| |
| if args.gen_intrin_h: |
| generate_intrin_h(args.output) |
| |
| rval = CopyDirFilesIfDifferent(args.output, final_output_dir) |
| |
| except: |
| print('ERROR: Could not generate llvm_ir_macros', file=sys.stderr) |
| rval = 1 |
| |
| finally: |
| DeleteDirTree(args.output) |
| |
| return rval |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |
| # END OF FILE |