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