1#!/usr/bin/python3 2# 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18"""Generate intrinsics code.""" 19 20from collections import OrderedDict 21 22import asm_defs 23import json 24import os 25import re 26import sys 27 28# C-level intrinsic calling convention: 29# 1. All arguments are passed using the natural data types: 30# - int8_t passed as one byte argument (on the stack in IA32 mode, in GP register in x86-64 mode) 31# - int32_t passed as 4 bytes argument (on the stack in IA32 mode, in GP register in x86-64 mode) 32# - int64_t is passed as 8 byte argument (on the stack in IA32 mode, in GP register in x86-64 mode) 33# - float is passed as float (on the stack in IA32 mode, in XMM register in x86-64 mode) 34# - double is passed as double (on the stack in IA32 mode, in XMM register in x86-64 mode) 35# - vector formats are passed as pointers to 128bit data structure 36# 2. Return values. 37# - Values are returned as std::tuple. This means that on IA32 it's always returned on stack. 38 39INDENT = ' ' 40AUTOGEN = """\ 41// This file automatically generated by gen_intrinsics.py 42// DO NOT EDIT! 43""" 44 45 46class VecFormat(object): 47 48 def __init__(self, num_elements, element_size, is_unsigned, is_float, index, 49 c_type): 50 self.num_elements = num_elements 51 self.element_size = element_size 52 self.is_unsigned = is_unsigned 53 self.is_float = is_float 54 self.index = index 55 self.c_type = c_type 56 57 58# Vector format defined as: 59# vector_size, element_size, is_unsigned, is_float, index, ir_format, c_type 60# TODO(olonho): make flat numbering after removing legacy macro compat. 61_VECTOR_FORMATS = { 62 'U8x8': VecFormat(8, 1, True, False, 1, 'uint8_t'), 63 'U16x4': VecFormat(4, 2, True, False, 2, 'uint16_t'), 64 'U32x2': VecFormat(2, 4, True, False, 3, 'uint32_t'), 65 'U64x1': VecFormat(1, 8, True, False, 4, 'uint64_t'), 66 'U8x16': VecFormat(16, 1, True, False, 5, 'uint8_t'), 67 'U16x8': VecFormat(8, 2, True, False, 6, 'uint16_t'), 68 'U32x4': VecFormat(4, 4, True, False, 7, 'uint32_t'), 69 'U64x2': VecFormat(2, 8, True, False, 8, 'uint64_t'), 70 'I8x8': VecFormat(8, 1, False, False, 9, 'int8_t'), 71 'I16x4': VecFormat(4, 2, False, False, 10, 'int16_t'), 72 'I32x2': VecFormat(2, 4, False, False, 11, 'int32_t'), 73 'I64x1': VecFormat(1, 8, False, False, 12, 'int64_t'), 74 'I8x16': VecFormat(16, 1, False, False, 13, 'int8_t'), 75 'I16x8': VecFormat(8, 2, False, False, 14, 'int16_t'), 76 'I32x4': VecFormat(4, 4, False, False, 15, 'int32_t'), 77 'I64x2': VecFormat(2, 8, False, False, 16, 'int64_t'), 78 'U8x1': VecFormat(1, 1, True, False, 17, 'uint8_t'), 79 'I8x1': VecFormat(1, 1, False, False, 18, 'int8_t'), 80 'U16x1': VecFormat(1, 2, True, False, 19, 'uint16_t'), 81 'I16x1': VecFormat(1, 2, False, False, 20, 'int16_t'), 82 'U32x1': VecFormat(1, 4, True, False, 21, 'uint32_t'), 83 'I32x1': VecFormat(1, 4, False, False, 22, 'int32_t'), 84 # These vector formats can never intersect with above, so can reuse index. 85 'F32x1': VecFormat(1, 4, False, True, 1, 'Float32'), 86 'F32x2': VecFormat(2, 4, False, True, 2, 'Float32'), 87 'F32x4': VecFormat(4, 4, False, True, 3, 'Float32'), 88 'F64x1': VecFormat(1, 8, False, True, 4, 'Float64'), 89 'F64x2': VecFormat(2, 8, False, True, 5, 'Float64'), 90 # Those vector formats can never intersect with above, so can reuse index. 91 'U8x4': VecFormat(4, 1, True, False, 1, 'uint8_t'), 92 'U16x2': VecFormat(2, 2, True, False, 2, 'uint16_t'), 93 'I8x4': VecFormat(4, 1, False, False, 3, 'int8_t'), 94 'I16x2': VecFormat(2, 2, False, False, 4, 'int16_t'), 95} 96 97 98class VecSize(object): 99 100 def __init__(self, num_elements, index): 101 self.num_elements = num_elements 102 self.index = index 103 104 105_VECTOR_SIZES = {'X64': VecSize(64, 1), 'X128': VecSize(128, 2)} 106 107 108def _is_imm_type(arg_type): 109 return 'imm' in arg_type 110 111 112def _is_template_type(arg_type): 113 if not arg_type.startswith('Type'): 114 return False 115 assert isinstance(int(arg_type[4:]), int) 116 return True 117 118 119def _get_imm_c_type(arg_type): 120 return { 121 'imm8' : 'int8_t', 122 'uimm8' : 'uint8_t', 123 'uimm16' : 'uint16_t', 124 'uimm32' : 'uint32_t', 125 }[arg_type] 126 127 128def _get_c_type(arg_type): 129 if (arg_type in ('Float32', 'Float64', 'int8_t', 'uint8_t', 'int16_t', 130 'uint16_t', 'int32_t', 'uint32_t', 'int64_t', 'uint64_t', 131 'volatile uint8_t*', 'volatile uint32_t*') or 132 _is_template_type(arg_type)): 133 return arg_type 134 if arg_type in ('fp_flags', 'fp_control', 'int', 'flag', 'flags', 'vec32'): 135 return 'uint32_t' 136 if _is_imm_type(arg_type): 137 return _get_imm_c_type(arg_type) 138 if arg_type == 'vec': 139 return 'SIMD128Register' 140 raise Exception('Type %s not supported' % (arg_type)) 141 142 143def _get_semantic_player_type(arg_type, type_map): 144 if type_map is not None and arg_type in type_map: 145 return type_map[arg_type] 146 if arg_type in ('Float32', 'Float64', 'vec'): 147 return 'SimdRegister' 148 if _is_imm_type(arg_type): 149 return _get_imm_c_type(arg_type) 150 return 'Register' 151 152 153def _gen_scalar_intr_decl(f, name, intr): 154 ins = intr.get('in') 155 outs = intr.get('out') 156 params = [_get_c_type(op) for op in ins] 157 if len(outs) > 0: 158 retval = 'std::tuple<' + ', '.join(_get_c_type(out) for out in outs) + '>' 159 else: 160 retval = 'void' 161 comment = intr.get('comment') 162 if comment: 163 print('// %s.' % (comment), file=f) 164 if intr.get('precise_nans', False): 165 print('template <bool precise_nan_operations_handling, ' 166 'enum PreferredIntrinsicsImplementation = kUseAssemblerImplementationIfPossible>', 167 file=f) 168 print('%s %s(%s);' % (retval, name, ', '.join(params)), file=f) 169 170 171def _gen_template_intr_decl(f, name, intr): 172 ins = intr.get('in') 173 outs = intr.get('out') 174 params = [_get_c_type(op) for op in ins] 175 if len(outs) > 0: 176 retval = 'std::tuple<' + ', '.join(_get_c_type(out) for out in outs) + '>' 177 else: 178 retval = 'void' 179 comment = intr.get('comment') 180 if comment: 181 print('// %s.' % (comment), file=f) 182 print('template <%s>' % _get_template_arguments(intr.get('variants')), file=f) 183 print('%s %s(%s);' % (retval, name, ', '.join(params)), file=f) 184 185 186def _get_template_arguments(variants, 187 extra = ['enum PreferredIntrinsicsImplementation = kUseAssemblerImplementationIfPossible']): 188 template = None 189 for variant in variants: 190 counter = -1 191 def get_counter(): 192 nonlocal counter 193 counter += 1 194 return counter 195 new_template = ', '.join([ 196 'bool kBool%s' % get_counter() if param.strip() in ('true', 'false') else 197 'typename Type%d' % get_counter() if re.search('[_a-zA-Z]', param) else 198 'int kInt%s' % get_counter() 199 for param in variant.split(',')] + extra) 200 assert template is None or template == new_template 201 template = new_template 202 return template 203 204 205def _is_vector_class(intr): 206 return intr.get('class') in ('vector_4', 'vector_8', 'vector_16', 207 'vector_8/16', 'vector_8/16/single', 208 'vector_8/single', 'vector_16/single') 209 210 211def _is_simd128_conversion_required(t, type_map=None): 212 return (_get_semantic_player_type(t, type_map) == 'SimdRegister' and 213 _get_c_type(t) != 'SIMD128Register') 214 215 216def _get_semantics_player_hook_result(intr): 217 outs = intr['out'] 218 if len(outs) == 0: 219 return 'void' 220 elif len(outs) == 1: 221 # No tuple for single result. 222 return _get_semantic_player_type(outs[0], intr.get('sem-player-types')) 223 return 'std::tuple<' + ', '.join( 224 _get_semantic_player_type(out, intr.get('sem-player-types')) 225 for out in outs) + '>' 226 227 228def _get_semantics_player_hook_proto_components(name, intr): 229 ins = intr['in'] 230 231 args = [] 232 if _is_vector_class(intr): 233 if 'raw' in intr['variants']: 234 assert len(intr['variants']) == 1, "Unexpected length of variants" 235 args = ["uint8_t size"] 236 else: 237 args = ["uint8_t elem_size", "uint8_t elem_num"] 238 if (_is_signed(intr) and _is_unsigned(intr)): 239 args += ['bool is_signed'] 240 241 args += [ 242 '%s arg%d' % ( 243 _get_semantic_player_type(op, intr.get('sem-player-types')), num) 244 for num, op in enumerate(ins) 245 ] 246 247 result = _get_semantics_player_hook_result(intr) 248 249 return result, name, ', '.join(args) 250 251 252def _get_semantics_player_hook_proto(name, intr): 253 result, name, args = _get_semantics_player_hook_proto_components(name, intr) 254 if intr.get('class') == 'template': 255 return 'template<%s>\n%s %s(%s)' % ( 256 _get_template_arguments(intr.get('variants'), []), result, name, args) 257 return '%s %s(%s)' % (result, name, args) 258 259 260def _get_interpreter_hook_call_expr(name, intr, desc=None): 261 ins = intr['in'] 262 outs = intr['out'] 263 264 call_params = [] 265 for num, op in enumerate(ins): 266 arg = 'arg%d' % (num) 267 semantic_player_type = _get_semantic_player_type( 268 op, intr.get('sem-player-types')) 269 if semantic_player_type == 'FpRegister': 270 call_params.append('FPRegToFloat<%s>(%s)' % (op, arg)) 271 elif semantic_player_type == 'SimdRegister': 272 call_params.append(_get_cast_from_simd128(arg, op, ptr_bits=64)) 273 elif '*' in _get_c_type(op): 274 call_params.append('berberis::bit_cast<%s>(%s)' % (_get_c_type(op), arg)) 275 else: 276 call_params.append('GPRRegToInteger<%s>(%s)' % (_get_c_type(op), arg)) 277 278 call_expr = 'intrinsics::%s%s(%s)' % ( 279 name, _get_desc_specializations(intr, desc).replace( 280 'Float', 'intrinsics::Float'), ', '.join(call_params)) 281 282 if len(outs) == 1: 283 # Unwrap tuple for single result. 284 call_expr = 'std::get<0>(%s)' % call_expr 285 if 'sem-player-types' in intr: 286 out_type = _get_semantic_player_type(outs[0], intr.get('sem-player-types')) 287 if out_type == "FpRegister": 288 call_expr = 'FloatToFPReg(%s)' % call_expr 289 elif out_type != "SimdRegister": 290 assert out_type == "Register" 291 assert not _is_simd128_conversion_required( 292 outs[0], intr.get('sem-player-types')) 293 call_expr = 'IntegerToGPRReg(%s)' % call_expr 294 else: 295 # Currently this kind of mismatch can only happen for single result, so we 296 # can keep simple code here for now. 297 if _is_simd128_conversion_required(outs[0]): 298 out_type = _get_c_type(outs[0]) 299 if out_type in ('Float32', 'Float64'): 300 call_expr = 'FloatToFPReg(%s)' % call_expr 301 else: 302 raise Exception('Type %s is not supported' % (out_type)) 303 else: 304 if any(_is_simd128_conversion_required(out) for out in outs): 305 raise Exception( 306 'Unsupported SIMD128Register conversion with multiple results') 307 308 return call_expr 309 310 311def _get_interpreter_hook_return_stmt(name, intr, desc=None): 312 return 'return ' + _get_interpreter_hook_call_expr(name, intr, desc) + ';' 313 314 315def _get_semantics_player_hook_raw_vector_body(name, intr, get_return_stmt): 316 outs = intr['out'] 317 if (len(outs) == 0): 318 raise Exception('No result raw vector intrinsic is not supported') 319 reg_class = intr.get('class') 320 yield 'switch (size) {' 321 for fmt, desc in _VECTOR_SIZES.items(): 322 if _check_reg_class_size(reg_class, desc.num_elements / 8): 323 yield INDENT + 'case %s:' % desc.num_elements 324 yield 2 * INDENT + get_return_stmt(name, intr, desc) 325 yield INDENT + 'default:' 326 yield 2 * INDENT + 'LOG_ALWAYS_FATAL("Unsupported size");' 327 yield 2 * INDENT + 'return {};' 328 yield '}' 329 330 331def _is_signed(intr): 332 return any(v.startswith("signed") for v in intr['variants']) 333 334 335def _is_unsigned(intr): 336 return any(v.startswith("unsigned") for v in intr['variants']) 337 338 339def _get_vector_format_init_expr(intr): 340 variants = intr.get('variants') 341 342 if ('Float32' in variants or 'Float64' in variants): 343 return 'intrinsics::GetVectorFormatFP(elem_size, elem_num)' 344 345 assert _is_signed(intr) or _is_unsigned(intr), "Unexpected intrinsic class" 346 if _is_signed(intr) and _is_unsigned(intr): 347 signed_arg = ', is_signed' 348 else: 349 signed_arg = ', true' if _is_signed(intr) else ', false' 350 return 'intrinsics::GetVectorFormatInt(elem_size, elem_num%s)' % signed_arg 351 352 353def _get_semantics_player_hook_vector_body(name, intr, get_return_stmt): 354 outs = intr['out'] 355 if (len(outs) == 0): 356 raise Exception('No result vector intrinsic is not supported') 357 reg_class = intr.get('class') 358 yield 'auto format = %s;' % _get_vector_format_init_expr(intr) 359 yield 'switch (format) {' 360 for variant in intr.get('variants'): 361 for fmt, desc in _VECTOR_FORMATS.items(): 362 if (_check_reg_class_size(reg_class, 363 desc.element_size * desc.num_elements) and 364 _check_typed_variant(variant, desc)): 365 yield INDENT + 'case intrinsics::kVector%s:' % fmt 366 yield 2 * INDENT + get_return_stmt(name, intr, desc) 367 elif (reg_class in ('vector_8/single', 'vector_8/16/single', 'vector_16/single') and 368 desc.num_elements == 1 and 369 _check_typed_variant(variant, desc)): 370 assert desc.element_size <= 8, "Unexpected element size" 371 yield INDENT + 'case intrinsics::kVector%s:' % fmt 372 yield 2 * INDENT + get_return_stmt(name, intr, desc) 373 yield INDENT + 'default:' 374 yield 2 * INDENT + 'LOG_ALWAYS_FATAL("Unsupported format");' 375 yield 2 * INDENT + 'return {};' 376 yield '}' 377 378 379# Syntax sugar heavily used in tests. 380def _get_interpreter_hook_vector_body(name, intr): 381 return _get_semantics_player_hook_vector_body( 382 name, intr, _get_interpreter_hook_return_stmt) 383 384 385def _gen_interpreter_hook(f, name, intr): 386 print('%s const {' % (_get_semantics_player_hook_proto(name, intr)), file=f) 387 388 if _is_vector_class(intr): 389 if 'raw' in intr['variants']: 390 assert len(intr['variants']) == 1, "Unexpected length of variants" 391 lines = _get_semantics_player_hook_raw_vector_body( 392 name, 393 intr, 394 _get_interpreter_hook_return_stmt) 395 else: 396 lines = _get_interpreter_hook_vector_body(name, intr) 397 398 lines = [INDENT + l for l in lines] 399 print('\n'.join(lines), file=f) 400 else: 401 print(INDENT + _get_interpreter_hook_return_stmt(name, intr), file=f) 402 403 print('}\n', file=f) 404 405 406def _get_translator_hook_call_expr(name, intr, desc = None): 407 desc_spec = _get_desc_specializations(intr, desc).replace( 408 'Float', 'intrinsics::Float') 409 args = [('arg%d' % n) for n, _ in enumerate(intr['in'])] 410 template_params = ['&intrinsics::' + name + desc_spec] 411 template_params += [_get_semantics_player_hook_result(intr)] 412 return 'CallIntrinsic<%s>(%s)' % (', '.join(template_params), ', '.join(args)) 413 414 415def _get_translator_hook_return_stmt(name, intr, desc=None): 416 return 'return ' + _get_translator_hook_call_expr(name, intr, desc) + ';' 417 418 419def _gen_translator_hook(f, name, intr): 420 print('%s {' % (_get_semantics_player_hook_proto(name, intr)), file=f) 421 422 if _is_vector_class(intr): 423 if 'raw' in intr['variants']: 424 assert len(intr['variants']) == 1, "Unexpected length of variants" 425 lines = _get_semantics_player_hook_raw_vector_body( 426 name, 427 intr, 428 _get_translator_hook_return_stmt) 429 else: 430 lines = _get_semantics_player_hook_vector_body( 431 name, 432 intr, 433 _get_translator_hook_return_stmt) 434 lines = [INDENT + l for l in lines] 435 print('\n'.join(lines), file=f) 436 else: 437 print(INDENT + _get_translator_hook_return_stmt(name, intr), file=f) 438 439 print('}\n', file=f) 440 441 442def _gen_mock_semantics_listener_hook(f, name, intr): 443 result, name, args = _get_semantics_player_hook_proto_components(name, intr) 444 if intr.get('class') == 'template': 445 print('template<%s>\n%s %s(%s) {\n return %s(%s);\n}' % ( 446 _get_template_arguments(intr.get('variants'), []), result, name, args, name, ', '.join([ 447 'intrinsics::kEnumFromTemplateType<%s>' % arg if arg.startswith('Type') else arg 448 for arg in _get_template_spec_arguments(intr.get('variants'))] + 449 [('arg%d' % n) for n, _ in enumerate(intr['in'])])), file=f) 450 args = ', '.join([ 451 '%s %s' % ( 452 { 453 'kBoo': 'bool', 454 'kInt': 'int', 455 'Type': 'intrinsics::EnumFromTemplateType' 456 }[argument[0:4]], 457 argument) 458 for argument in _get_template_spec_arguments(intr.get('variants'))] + [args]) 459 print('MOCK_METHOD((%s), %s, (%s));' % (result, name, args), file=f) 460 461 462def _check_signed_variant(variant, desc): 463 if variant == 'signed': 464 return True 465 if variant == 'signed_32': 466 return desc.element_size == 4 467 if variant == 'signed_64': 468 return desc.element_size == 8 469 if variant == 'signed_16/32': 470 return desc.element_size in (2, 4) 471 if variant == 'signed_8/16/32': 472 return desc.element_size in (1, 2, 4) 473 if variant == 'signed_16/32/64': 474 return desc.element_size in (2, 4, 8) 475 if variant == 'signed_8/16/32/64': 476 return desc.element_size in (1, 2, 4, 8) 477 if variant == 'signed_32/64': 478 return desc.element_size in (4, 8) 479 return False 480 481 482def _check_unsigned_variant(variant, desc): 483 if variant == 'unsigned': 484 return True 485 if variant == 'unsigned_8': 486 return desc.element_size == 1 487 if variant == 'unsigned_16': 488 return desc.element_size == 2 489 if variant == 'unsigned_32': 490 return desc.element_size == 4 491 if variant == 'unsigned_64': 492 return desc.element_size == 8 493 if variant == 'unsigned_8/16': 494 return desc.element_size in (1, 2) 495 if variant == 'unsigned_8/16/32': 496 return desc.element_size in (1, 2, 4) 497 if variant == 'unsigned_16/32/64': 498 return desc.element_size in (2, 4, 8) 499 if variant == 'unsigned_8/16/32/64': 500 return desc.element_size in (1, 2, 4, 8) 501 if variant == 'unsigned_32/64': 502 return desc.element_size in (4, 8) 503 return False 504 505 506def _check_reg_class_size(reg_class, size): 507 # Small vectors are separate namespace. 508 if size == 4 and reg_class == 'vector_4': 509 return True 510 if size == 8 and reg_class in ('vector_8', 'vector_8/16', 'vector_8/16/single', 511 'vector_8/single'): 512 return True 513 if size == 16 and reg_class in ('vector_16', 'vector_8/16', 'vector_8/16/single', 514 'vector_16/single'): 515 return True 516 return False 517 518 519def _check_typed_variant(variant, desc): 520 if desc.is_unsigned and not desc.is_float: 521 return _check_unsigned_variant(variant, desc) 522 if not desc.is_unsigned and not desc.is_float: 523 return _check_signed_variant(variant, desc) 524 if desc.is_float: 525 if desc.element_size == 4: 526 return variant == 'Float32' 527 if desc.element_size == 8: 528 return variant == 'Float64' 529 return False 530 531 532def _get_formats_with_descriptions(intr): 533 reg_class = intr.get('class') 534 for variant in intr.get('variants'): 535 found_fmt = False 536 for fmt, desc in _VECTOR_FORMATS.items(): 537 if (_check_reg_class_size(reg_class, 538 desc.element_size * desc.num_elements) and 539 _check_typed_variant(variant, desc) and 540 (reg_class != 'vector_4' or desc.element_size < 4)): 541 found_fmt = True 542 yield fmt, desc 543 544 if variant == 'raw': 545 for fmt, desc in _VECTOR_SIZES.items(): 546 if _check_reg_class_size(reg_class, desc.num_elements / 8): 547 found_fmt = True 548 yield fmt, desc 549 550 assert found_fmt, 'Couldn\'t expand %s' % reg_class 551 552 553def _get_result_type(outs): 554 result_type = 'void' 555 return_stmt = '' 556 if len(outs) >= 1: 557 result_type = ('std::tuple<' + 558 ', '.join(_get_c_type(out) for out in outs) + '>') 559 return_stmt = 'return ' 560 return result_type, return_stmt 561 562 563def _get_in_params(params): 564 for param_index, param in enumerate(params): 565 yield _get_c_type(param), 'in%d' % (param_index) 566 567 568def _get_out_params(params): 569 for param_index, param in enumerate(params): 570 yield _get_c_type(param), 'out%d' % (param_index) 571 572 573def _get_cast_from_simd128(var, target_type, ptr_bits): 574 if ('*' in target_type): 575 return 'berberis::bit_cast<%s>(%s.Get<uint%d_t>(0))' % (_get_c_type(target_type), var, 576 ptr_bits) 577 578 c_type = _get_c_type(target_type) 579 if c_type in ('Float32', 'Float64'): 580 return 'FPRegToFloat<intrinsics::%s>(%s)' % (c_type, var) 581 582 cast_map = { 583 'int8_t': '.Get<int8_t>(0)', 584 'uint8_t': '.Get<uint8_t>(0)', 585 'int16_t': '.Get<int16_t>(0)', 586 'uint16_t': '.Get<uint16_t>(0)', 587 'int32_t': '.Get<int32_t>(0)', 588 'uint32_t': '.Get<uint32_t>(0)', 589 'int64_t': '.Get<int64_t>(0)', 590 'uint64_t': '.Get<uint64_t>(0)', 591 'SIMD128Register': '' 592 } 593 return '%s%s' % (var, cast_map[c_type]) 594 595 596def _get_desc_specializations(intr, desc=None): 597 if intr.get('class') == 'template': 598 spec = _get_template_spec_arguments(intr.get('variants')) 599 elif hasattr(desc, 'c_type'): 600 spec = [desc.c_type, str(desc.num_elements)] 601 elif hasattr(desc, 'num_elements'): 602 spec = [str(desc.num_elements)] 603 else: 604 spec = [] 605 if intr.get('precise_nans', False): 606 spec = ['config::kPreciseNaNOperationsHandling'] + spec 607 if not len(spec): 608 return '' 609 return '<%s>' % ', '.join(spec) 610 611 612def _get_template_spec_arguments(variants): 613 spec = None 614 for variant in variants: 615 counter = -1 616 def get_counter(): 617 nonlocal counter 618 counter += 1 619 return counter 620 new_spec = [ 621 'kBool%s' % get_counter() if param.strip() in ('true', 'false') else 622 'Type%d' % get_counter() if re.search('[_a-zA-Z]', param) else 623 'kInt%s' % get_counter() 624 for param in variant.split(',')] 625 assert spec is None or spec == new_spec 626 spec = new_spec 627 return spec 628 629 630def _intr_has_side_effects(intr, fmt=None): 631 # If we have 'has_side_effects' mark in JSON file then we use it "as is". 632 if 'has_side_effects' in intr: 633 return intr.get('has_side_effects') 634 # Otherwise we mark all floating-point related intrinsics as "volatile". 635 # TODO(b/68857496): move that information in HIR/LIR and stop doing that. 636 if 'Float32' in intr.get('in') or 'Float64' in intr.get('in'): 637 return True 638 if 'Float32' in intr.get('out') or 'Float64' in intr.get('out'): 639 return True 640 if fmt is not None and fmt.startswith('F'): 641 return True 642 return False 643 644 645def _gen_intrinsics_inl_h(f, intrs): 646 print(AUTOGEN, file=f) 647 for name, intr in intrs: 648 if intr.get('class') == 'scalar': 649 _gen_scalar_intr_decl(f, name, intr) 650 elif intr.get('class') == 'template': 651 _gen_template_intr_decl(f, name, intr) 652 653 654def _gen_semantic_player_types(intrs): 655 for name, intr in intrs: 656 if intr.get('class') == 'template': 657 map = None 658 for variant in intr.get('variants'): 659 counter = -1 660 def get_counter(): 661 nonlocal counter 662 counter += 1 663 return counter 664 new_map = { 665 'Float32': 'FpRegister', 666 'Float64': 'FpRegister', 667 } 668 for type in filter( 669 lambda param: param.strip() not in ('true', 'false') and 670 re.search('[_a-zA-Z]', param), 671 variant.split(',')): 672 new_map['Type%d' % get_counter()] = ( 673 'FpRegister' if type.strip() in ('Float32', 'Float64') else 674 _get_semantic_player_type(type, None)) 675 assert map is None or map == new_map 676 map = new_map 677 intr['sem-player-types'] = map 678 679 680def _gen_interpreter_intrinsics_hooks_impl_inl_h(f, intrs): 681 print(AUTOGEN, file=f) 682 for name, intr in intrs: 683 _gen_interpreter_hook(f, name, intr) 684 685 686def _gen_translator_intrinsics_hooks_impl_inl_h(f, intrs): 687 print(AUTOGEN, file=f) 688 for name, intr in intrs: 689 _gen_translator_hook(f, name, intr) 690 691 692def _gen_mock_semantics_listener_intrinsics_hooks_impl_inl_h(f, intrs): 693 print(AUTOGEN, file=f) 694 for name, intr in intrs: 695 _gen_mock_semantics_listener_hook(f, name, intr) 696 697 698def _get_reg_operand_info(arg, info_prefix=None): 699 need_tmp = arg['class'] in ('EAX', 'EDX', 'CL', 'ECX') 700 if info_prefix is None: 701 class_info = 'void' 702 else: 703 class_info = '%s::%s' % (info_prefix, arg['class']) 704 if arg['class'] == 'Imm8': 705 return 'ImmArg<%d, int8_t, %s>' % (arg['ir_arg'], class_info) 706 if info_prefix is None: 707 using_info = 'void' 708 else: 709 using_info = '%s::%s' % (info_prefix, { 710 'def': 'Def', 711 'def_early_clobber': 'DefEarlyClobber', 712 'use': 'Use', 713 'use_def': 'UseDef' 714 }[arg['usage']]) 715 if arg['usage'] == 'use': 716 if need_tmp: 717 return 'InTmpArg<%d, %s, %s>' % (arg['ir_arg'], class_info, using_info) 718 return 'InArg<%d, %s, %s>' % (arg['ir_arg'], class_info, using_info) 719 if arg['usage'] in ('def', 'def_early_clobber'): 720 assert 'ir_arg' not in arg 721 if 'ir_res' in arg: 722 if need_tmp: 723 return 'OutTmpArg<%d, %s, %s>' % (arg['ir_res'], class_info, using_info) 724 return 'OutArg<%d, %s, %s>' % (arg['ir_res'], class_info, using_info) 725 return 'TmpArg<%s, %s>' % (class_info, using_info) 726 if arg['usage'] == 'use_def': 727 if 'ir_res' in arg: 728 if need_tmp: 729 return 'InOutTmpArg<%s, %s, %s, %s>' % (arg['ir_arg'], arg['ir_res'], 730 class_info, using_info) 731 return 'InOutArg<%s, %s, %s, %s>' % (arg['ir_arg'], arg['ir_res'], 732 class_info, using_info) 733 return 'InTmpArg<%s, %s, %s>' % (arg['ir_arg'], class_info, using_info) 734 assert False, 'unknown operand usage %s' % (arg['usage']) 735 736 737def _gen_make_intrinsics(f, intrs, archs): 738 print("""%s 739template <%s, 740 typename MacroAssembler, 741 typename Callback, 742 typename... Args> 743void ProcessAllBindings(Callback callback, Args&&... args) {""" % ( 744 AUTOGEN, 745 ',\n '.join(['typename Assembler_%s' % arch for arch in archs])), 746 file=f) 747 for line in _gen_c_intrinsics_generator( 748 intrs, _is_interpreter_compatible_assembler, False): # False for gen_builder 749 print(line, file=f) 750 print('}', file=f) 751 752def _gen_opcode_generators_f(f, intrs): 753 for line in _gen_opcode_generators(intrs): 754 print(line, file=f) 755 756def _gen_opcode_generators(intrs): 757 opcode_generators = {} 758 for name, intr in intrs: 759 if 'asm' not in intr: 760 continue 761 if 'variants' in intr: 762 variants = _get_formats_with_descriptions(intr) 763 variants = sorted(variants, key=lambda variant: variant[1].index) 764 # Collect intr_asms for all variants of intrinsic. 765 # Note: not all variants are guaranteed to have an asm variant! 766 # If that happens the list of intr_asms for that variant will be empty. 767 variants = [[ 768 intr_asm for intr_asm in _gen_sorted_asms(intr) 769 if fmt in intr_asm['variants'] 770 ] for fmt, _ in variants] 771 # Print intrinsic generator 772 for intr_asms in variants: 773 if len(intr_asms) > 0: 774 for intr_asm in intr_asms: 775 if not _is_translator_compatible_assembler(intr_asm): 776 continue 777 for line in _gen_opcode_generator(intr_asm, opcode_generators): 778 yield line 779 else: 780 for intr_asm in _gen_sorted_asms(intr): 781 if not _is_translator_compatible_assembler(intr_asm): 782 continue 783 for line in _gen_opcode_generator(intr_asm, opcode_generators): 784 yield line 785 786def _gen_opcode_generator(asm, opcode_generators): 787 name = asm['name'] 788 num_mem_args = sum(1 for arg in asm['args'] if arg.get('class').startswith("Mem") and arg.get('usage') == 'def_early_clobber') 789 opcode = 'Undefined' if num_mem_args > 2 else (asm_defs.get_mem_macro_name(asm, '').replace("Mem", "MemBaseDisp")) if num_mem_args > 0 else name 790 791 if name not in opcode_generators: 792 opcode_generators[name] = True 793 yield """ 794// TODO(b/260725458): Pass lambda as template argument after C++20 becomes available. 795class GetOpcode%s { 796 public: 797 template <typename Opcode> 798 constexpr auto operator()() { 799 return Opcode::kMachineOp%s; 800 } 801};""" % (name, opcode) 802 803def _gen_process_bindings(f, intrs, archs): 804 print('%s' % AUTOGEN, file=f) 805 _gen_opcode_generators_f(f, intrs) 806 print(""" 807template <auto kFunc, 808 %s, 809 typename MacroAssembler, 810 typename Result, 811 typename Callback, 812 typename... Args> 813Result ProcessBindings(Callback callback, Result def_result, Args&&... args) {""" % ( 814 ',\n '.join(['typename Assembler_%s' % arch for arch in archs])), 815 file=f) 816 for line in _gen_c_intrinsics_generator( 817 intrs, _is_translator_compatible_assembler, True): # True for gen_builder 818 print(line, file=f) 819 print(""" } 820 return std::forward<Result>(def_result); 821}""", file=f) 822 823 824def _gen_c_intrinsics_generator(intrs, check_compatible_assembler, gen_builder): 825 string_labels = {} 826 mnemo_idx = [0] 827 for name, intr in intrs: 828 ins = intr.get('in') 829 outs = intr.get('out') 830 params = _get_in_params(ins) 831 formal_args = ', '.join('%s %s' % (type, param) for type, param in params) 832 result_type, _ = _get_result_type(outs) 833 if 'asm' not in intr: 834 continue 835 if 'variants' in intr: 836 variants = _get_formats_with_descriptions(intr) 837 # Sort by index, to keep order close to what _gen_intrs_enum produces. 838 variants = sorted(variants, key=lambda variant: variant[1].index) 839 # Collect intr_asms for all versions of intrinsic. 840 # Note: not all variants are guaranteed to have asm version! 841 # If that happens list of intr_asms for that variant would be empty. 842 variants = [(desc, [ 843 intr_asm for intr_asm in _gen_sorted_asms(intr) 844 if fmt in intr_asm['variants'] 845 ]) for fmt, desc in variants] 846 # Print intrinsic generator 847 for desc, intr_asms in variants: 848 if len(intr_asms) > 0: 849 if 'raw' in intr['variants']: 850 spec = '%d' % (desc.num_elements) 851 else: 852 spec = '%s, %d' % (desc.c_type, desc.num_elements) 853 for intr_asm in intr_asms: 854 for line in _gen_c_intrinsic('%s<%s>' % (name, spec), 855 intr, 856 intr_asm, 857 string_labels, 858 mnemo_idx, 859 check_compatible_assembler, 860 gen_builder): 861 yield line 862 else: 863 for intr_asm in _gen_sorted_asms(intr): 864 for line in _gen_c_intrinsic(name, 865 intr, 866 intr_asm, 867 string_labels, 868 mnemo_idx, 869 check_compatible_assembler, 870 gen_builder): 871 yield line 872 873 874def _gen_sorted_asms(intr): 875 return sorted(intr['asm'], 876 key = lambda intr: 877 intr.get('nan', '') + 878 _KNOWN_FEATURES_KEYS.get( 879 intr.get('feature', ''), intr.get('feature', '')), reverse = True) 880 881_KNOWN_FEATURES_KEYS = { 882 'LZCNT': '001', 883 'BMI': '002', 884 'BMI2': '003', 885 'SSE': '010', 886 'SSE2': '011', 887 'SSE3': '012', 888 'SSSE3': '013', 889 'SSE4a': '014', 890 'SSE4_1': '015', 891 'SSE4_2': '016', 892 'AVX': '017', 893 'AVX2': '018', 894 'FMA': '019', 895 'FMA4': '020' 896} 897 898 899def _gen_c_intrinsic(name, 900 intr, 901 asm, 902 string_labels, 903 mnemo_idx, 904 check_compatible_assembler, 905 gen_builder): 906 if not check_compatible_assembler(asm): 907 return 908 909 cpuid_restriction = 'intrinsics::bindings::kNoCPUIDRestriction' 910 if 'feature' in asm: 911 if asm['feature'] == 'AuthenticAMD': 912 cpuid_restriction = 'intrinsics::bindings::kIsAuthenticAMD' 913 else: 914 cpuid_restriction = 'intrinsics::bindings::kHas%s' % asm['feature'] 915 916 nan_restriction = 'intrinsics::bindings::kNoNansOperation' 917 if 'nan' in asm: 918 nan_restriction = 'intrinsics::bindings::k%sNanOperationsHandling' % asm['nan'] 919 template_arg = 'true' if asm['nan'] == "Precise" else "false" 920 if '<' in name: 921 template_pos = name.index('<') 922 name = name[0:template_pos+1] + template_arg + ", " + name[template_pos+1:] 923 else: 924 name += '<' + template_arg + '>' 925 926 if name not in string_labels: 927 name_label = 'kName%d' % len(string_labels) 928 string_labels[name] = name_label 929 if check_compatible_assembler == _is_translator_compatible_assembler: 930 yield ' %s if constexpr (std::is_same_v<FunctionCompareTag<kFunc>,' % ( 931 '' if name_label == 'kName0' else ' } else' 932 ) 933 yield ' FunctionCompareTag<%s>>) {' % name 934 yield ' static constexpr const char %s[] = "%s";' % ( 935 name_label, name) 936 else: 937 name_label = string_labels[name] 938 939 mnemo = asm['mnemo'] 940 mnemo_label = 'kMnemo%d' % mnemo_idx[0] 941 mnemo_idx[0] += 1 942 yield ' static constexpr const char %s[] = "%s";' % ( 943 mnemo_label, mnemo) 944 945 restriction = [cpuid_restriction, nan_restriction] 946 947 if check_compatible_assembler == _is_translator_compatible_assembler: 948 yield ' if (auto result = callback(' 949 else: 950 yield ' callback(' 951 yield ' intrinsics::bindings::AsmCallInfo<' 952 yield ' %s>(),' % ( 953 ',\n '.join( 954 [name_label, 955 _get_asm_reference(asm), 956 mnemo_label, 957 _get_builder_reference(intr, asm) if gen_builder else 'void', 958 cpuid_restriction, 959 nan_restriction, 960 'true' if _intr_has_side_effects(intr) else 'false', 961 _get_c_type_tuple(intr['in']), 962 _get_c_type_tuple(intr['out'])] + 963 [_get_reg_operand_info(arg, 'intrinsics::bindings') 964 for arg in asm['args']])) 965 if check_compatible_assembler == _is_translator_compatible_assembler: 966 yield ' std::forward<Args>(args)...); result.has_value()) {' 967 yield ' return *std::move(result);' 968 yield ' }' 969 else: 970 yield ' std::forward<Args>(args)...);' 971 972 973def _get_c_type_tuple(arguments): 974 return 'std::tuple<%s>' % ', '.join( 975 _get_c_type(argument) for argument in arguments).replace( 976 'Float', 'intrinsics::Float') 977 978 979def _get_asm_type(asm, prefix=''): 980 args = filter( 981 lambda arg: not asm_defs.is_implicit_reg(arg['class']), asm['args']) 982 return ', '.join(_get_asm_operand_type(arg, prefix) for arg in args) 983 984 985def _get_asm_operand_type(arg, prefix=''): 986 cls = arg.get('class') 987 if asm_defs.is_x87reg(cls): 988 return prefix + 'X87Register' 989 if asm_defs.is_greg(cls): 990 return prefix + 'Register' 991 if asm_defs.is_xreg(cls): 992 return prefix + 'XMMRegister' 993 if asm_defs.is_mem_op(cls): 994 return 'const ' + prefix + 'Operand&' 995 if asm_defs.is_imm(cls): 996 if cls == 'Imm2': 997 return 'int8_t' 998 return 'int' + cls[3:] + '_t' 999 assert False 1000 1001 1002def _get_asm_reference(asm): 1003 # Because of misfeature of Itanium C++ ABI we couldn't just use MacroAssembler 1004 # to static cast these references if we want to use them as template argument: 1005 # https://ibob.bg/blog/2018/08/18/a-bug-in-the-cpp-standard/ 1006 1007 # Thankfully there are usually no need to use the same trick for MacroInstructions 1008 # since we may always rename these, except when immediates are involved. 1009 1010 # But for assembler we need to use actual type from where these 1011 # instructions come from! 1012 # 1013 # E.g. LZCNT have to be processed like this: 1014 # static_cast<void (Assembler_common_x86::*)( 1015 # typename Assembler_common_x86::Register, 1016 # typename Assembler_common_x86::Register)>( 1017 # &Assembler_common_x86::Lzcntl) 1018 if 'arch' in asm: 1019 assembler = 'Assembler_%s' % asm['arch'] 1020 else: 1021 assembler = 'std::tuple_element_t<%s, MacroAssembler>' % asm['macroassembler'] 1022 return 'static_cast<void (%s::*)(%s)>(%s&%s::%s%s)' % ( 1023 assembler, 1024 _get_asm_type(asm, 'typename %s::' % assembler), 1025 '\n ', 1026 assembler, 1027 'template ' if '<' in asm['asm'] else '', 1028 asm['asm']) 1029 1030def _get_builder_reference(intr, asm): 1031 return 'GetOpcode%s' % (asm['name']) 1032 1033def _load_intrs_def_files(intrs_def_files): 1034 result = {} 1035 for intrs_def in intrs_def_files: 1036 with open(intrs_def) as intrs: 1037 result.update(json.load(intrs)) 1038 result.pop('License', None) 1039 return result 1040 1041 1042def _load_intrs_arch_def(intrs_defs): 1043 json_data = [] 1044 for intrs_def in intrs_defs: 1045 with open(intrs_def) as intrs: 1046 json_array = json.load(intrs) 1047 while isinstance(json_array[0], str): 1048 json_array.pop(0) 1049 json_data.extend(json_array) 1050 return json_data 1051 1052 1053def _load_macro_def(intrs, arch_intrs, insns_def, macroassembler): 1054 arch, insns = asm_defs.load_asm_defs(insns_def) 1055 if arch is not None: 1056 for insn in insns: 1057 insn['arch'] = arch 1058 else: 1059 for insn in insns: 1060 insn['macroassembler'] = macroassembler 1061 insns_map = dict((insn['name'], insn) for insn in insns) 1062 unprocessed_intrs = [] 1063 for arch_intr in arch_intrs: 1064 if arch_intr['insn'] in insns_map: 1065 insn = insns_map[arch_intr['insn']] 1066 _add_asm_insn(intrs, arch_intr, insn) 1067 else: 1068 unprocessed_intrs.append(arch_intr) 1069 return arch, unprocessed_intrs 1070 1071 1072def _is_interpreter_compatible_assembler(intr_asm): 1073 if intr_asm.get('usage', '') == 'translate-only': 1074 return False 1075 return True 1076 1077 1078def _is_translator_compatible_assembler(intr_asm): 1079 if intr_asm.get('usage', '') == 'interpret-only': 1080 return False 1081 return True 1082 1083 1084 1085def _add_asm_insn(intrs, arch_intr, insn): 1086 name = ','.join(name_part.strip() for name_part in arch_intr['name'].split(',')) 1087 # Sanity checks: MacroInstruction could implement few different intrinsics but 1088 # number of arguments in arch intrinsic and arch-independent intrinsic 1089 # should match. 1090 # 1091 # Note: we allow combining intrinsics with variants and intrinsics without 1092 # variants (e.g. AbsF32 is combined with VectorAbsoluteFP for F32x2 and F32x4), 1093 # but don't allow macroinstructions which would handle different set of 1094 # variants for different intrinsics. 1095 1096 assert 'variants' not in insn or insn['variants'] == arch_intr['variants'] 1097 assert 'feature' not in insn or insn['feature'] == arch_intr['feature'] 1098 assert 'nan' not in insn or insn['nan'] == arch_intr['nan'] 1099 assert 'usage' not in insn or insn['usage'] == arch_intr['usage'] 1100 assert len(intrs[name]['in']) == len(arch_intr['in']) 1101 assert len(intrs[name]['out']) == len(arch_intr['out']) 1102 1103 if 'variants' in arch_intr: 1104 insn['variants'] = arch_intr['variants'] 1105 if 'feature' in arch_intr: 1106 insn['feature'] = arch_intr['feature'] 1107 if 'nan' in arch_intr: 1108 insn['nan'] = arch_intr['nan'] 1109 if 'usage' in arch_intr: 1110 insn['usage'] = arch_intr['usage'] 1111 1112 for count, in_arg in enumerate(arch_intr['in']): 1113 # Sanity check: each in argument should only be used once - but if two 1114 # different intrinsics use them same macroinstruction it could be already 1115 # defined... yet it must be defined identically. 1116 assert ('ir_arg' not in insn['args'][in_arg] or 1117 insn['args'][in_arg]['ir_arg'] == count) 1118 insn['args'][in_arg]['ir_arg'] = count 1119 1120 for count, out_arg in enumerate(arch_intr['out']): 1121 # Sanity check: each out argument should only be used once, too. 1122 assert ('ir_res' not in insn['args'][out_arg] or 1123 insn['args'][out_arg]['ir_res'] == count) 1124 insn['args'][out_arg]['ir_res'] = count 1125 1126 # Note: one intrinsic could have more than one implementation (e.g. 1127 # SSE2 vs SSE4.2). 1128 if 'asm' not in intrs[name]: 1129 intrs[name]['asm'] = [] 1130 intrs[name]['asm'].append(insn) 1131 1132 1133def _open_asm_def_files(def_files, arch_def_files, asm_def_files, need_archs=True): 1134 intrs = _load_intrs_def_files(def_files) 1135 expanded_intrs = _expand_template_intrinsics(intrs) 1136 arch_intrs = _load_intrs_arch_def(arch_def_files) 1137 archs = [] 1138 macro_assemblers = 0 1139 for macro_def in asm_def_files: 1140 arch, arch_intrs = _load_macro_def(expanded_intrs, arch_intrs, macro_def, macro_assemblers) 1141 if arch is not None: 1142 archs.append(arch) 1143 else: 1144 macro_assemblers += 1 1145 # Make sure that all intrinsics were found during processing of arch_intrs. 1146 assert arch_intrs == [] 1147 if need_archs: 1148 return archs, sorted(intrs.items()), sorted(expanded_intrs.items()) 1149 else: 1150 return sorted(intrs.items()) 1151 1152 1153def _expand_template_intrinsics(intrs): 1154 expanded_intrs = {} 1155 for name, intr in intrs.items(): 1156 if intr.get('class') != 'template': 1157 expanded_intrs[name] = intr 1158 else: 1159 for variant in intr.get('variants'): 1160 types = {} 1161 params = [param.strip() for param in variant.split(',')] 1162 for param in params: 1163 if param in ('true', 'false'): 1164 continue 1165 if re.search('[_a-zA-Z]', param): 1166 types['Type'+str(len(types))] = param 1167 new_intr = intr.copy() 1168 del new_intr['variants'] 1169 new_intr['in'] = [types.get(param, param) for param in new_intr.get('in')] 1170 new_intr['out'] = [types.get(param, param) for param in new_intr.get('out')] 1171 expanded_intrs[name+'<'+','.join(params)+'>'] = new_intr 1172 return expanded_intrs 1173 1174 1175def main(argv): 1176 # Usage: 1177 # gen_intrinsics.py --public_headers <intrinsics-inl.h> 1178 # <intrinsics_process_bindings-inl.h> 1179 # <interpreter_intrinsics_hooks-inl.h> 1180 # <translator_intrinsics_hooks-inl.h> 1181 # <mock_semantics_listener_intrinsics_hooks-inl.h> 1182 # <riscv64_to_x86_64/intrinsic_def.json", 1183 # ... 1184 # <riscv64_to_x86_64/machine_ir_intrinsic_binding.json>, 1185 # ... 1186 # <riscv64_to_x86_64/macro_def.json>, 1187 # ... 1188 # gen_intrinsics.py --text_asm_intrinsics_bindings <make_intrinsics-inl.h> 1189 # <riscv64_to_x86_64/intrinsic_def.json", 1190 # ... 1191 # <riscv64_to_x86_64/machine_ir_intrinsic_binding.json>, 1192 # ... 1193 # <riscv64_to_x86_64/macro_def.json>, 1194 # ... 1195 1196 def open_out_file(name): 1197 try: 1198 os.makedirs(os.path.dirname(name)) 1199 except: 1200 pass 1201 return open(name, 'w') 1202 1203 mode = argv[1] 1204 if mode in ('--text_asm_intrinsics_bindings', '--public_headers'): 1205 out_files_end = 3 if mode == '--text_asm_intrinsics_bindings' else 7 1206 def_files_end = out_files_end 1207 while argv[def_files_end].endswith('intrinsic_def.json'): 1208 def_files_end += 1 1209 arch_def_files_end = def_files_end 1210 while argv[arch_def_files_end].endswith('machine_ir_intrinsic_binding.json'): 1211 arch_def_files_end += 1 1212 archs, intrs, expanded_intrs = _open_asm_def_files( 1213 argv[out_files_end:def_files_end], 1214 argv[def_files_end:arch_def_files_end], 1215 argv[arch_def_files_end:], 1216 True) 1217 if mode == '--text_asm_intrinsics_bindings': 1218 _gen_make_intrinsics(open_out_file(argv[2]), expanded_intrs, archs) 1219 else: 1220 _gen_intrinsics_inl_h(open_out_file(argv[2]), intrs) 1221 _gen_process_bindings(open_out_file(argv[3]), expanded_intrs, archs) 1222 _gen_semantic_player_types(intrs) 1223 _gen_interpreter_intrinsics_hooks_impl_inl_h(open_out_file(argv[4]), intrs) 1224 _gen_translator_intrinsics_hooks_impl_inl_h( 1225 open_out_file(argv[5]), intrs) 1226 _gen_mock_semantics_listener_intrinsics_hooks_impl_inl_h( 1227 open_out_file(argv[6]), intrs) 1228 else: 1229 assert False, 'unknown option %s' % (mode) 1230 1231 return 0 1232 1233 1234if __name__ == '__main__': 1235 sys.exit(main(sys.argv)) 1236