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 22from __future__ import print_function 23import os, sys, re 24from gen_common import * 25from argparse import FileType 26 27inst_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 44intrinsics = [ 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'], 'getVectorType(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 65llvm_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 85this_dir = os.path.dirname(os.path.abspath(__file__)) 86template = os.path.join(this_dir, 'templates', 'gen_builder.hpp') 87 88def 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''' 95def 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''' 215def 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''' 241def 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 283def 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''' 316def 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 361if __name__ == '__main__': 362 sys.exit(main()) 363# END OF FILE 364