1#!src/build/run_python
2#
3# Copyright (C) 2014 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
18import itertools
19import json
20import sys
21
22import gen_asm
23
24
25# Enable to avoid cycles.  Only use one register combo for tests.
26fast_mode = False
27
28
29def main(argv):
30  # Usage: gen_asm.tests_py <assembler_ref.S>
31  #                         <assembler_test.cc>
32  #                         <def_common>
33  #                         <def_arch>
34  att_assembler_file_name = argv[1]
35  arc_assembler_file_name = argv[2]
36  # Generate empty files if we don't have assembler files to test.
37  if len(argv) <= 4:
38    with open(att_assembler_file_name, 'w') as att_assembler_file:
39      pass
40    with open(arc_assembler_file_name, 'w') as arc_assembler_file:
41      pass
42    return 0
43  _, common_defs = gen_asm._load_asm_defs(argv[3])
44  _, arch_defs = gen_asm._load_asm_defs(argv[4])
45
46  fast_mode = globals()["fast_mode"]
47  if len(argv) > 5 and argv[5] == '--fast':
48    fast_mode = True
49
50  with open(argv[4]) as arch_def:
51    obj = json.load(arch_def)
52    arch = obj.get('arch')
53    assert arch in ('x86_32', 'x86_64')
54    _update_arguments(arch == 'x86_64')
55
56  with open(att_assembler_file_name, 'w') as att_assembler_file:
57    print('.globl berberis_gnu_as_output_start_%s' % arch,
58          file=att_assembler_file)
59    print('.globl berberis_gnu_as_output_end_%s' % arch,
60          file=att_assembler_file)
61    print('.data', file=att_assembler_file)
62    print('berberis_gnu_as_output_start_%s:' % arch,
63          file=att_assembler_file)
64    print('.code%d' % (32 if arch == 'x86_32' else 64), file=att_assembler_file)
65    _gen_att_assembler(att_assembler_file, common_defs, fast_mode)
66    _gen_att_assembler(att_assembler_file, arch_defs, fast_mode)
67    print('berberis_gnu_as_output_end_%s:' % arch, file=att_assembler_file)
68
69  with open(arc_assembler_file_name, 'w') as arc_assembler_file:
70    print('#include "berberis/assembler/%s.h"' % (arch), file=arc_assembler_file)
71    print('namespace berberis {', file=arc_assembler_file)
72    print('namespace %s {' % (arch), file=arc_assembler_file)
73    _gen_arc_generators(arc_assembler_file)
74    _gen_arc_assembler(arc_assembler_file, 'Common', common_defs, fast_mode)
75    _gen_arc_assembler(arc_assembler_file, 'Arch', arch_defs, fast_mode)
76    print('}  // namespace %s' % (arch), file=arc_assembler_file)
77    print('}  // namespace berberis', file=arc_assembler_file)
78  return 0
79
80
81sample_att_arguments = {
82    # Note: st(0) is not tested on purpose: many instructions have ambiguity
83    # where st(0) to st(0) version can be encoded in two different ways and both
84    # work fine, but assemblers produce different versions!
85    # Rather than try to match everything perfectly we limit ourselves to st(1),
86    # st(2), and st(4) which ensures that all bits are ancoded correctly.
87    'RegX87': ('%st(1)', '%st(2)', '%st(4)'),
88    'Imm2': ('$0', '$1', '$2', '$3'),
89    'Imm8': ('$-1', '$0', '$1', '$2'),
90    'Imm16': ('$-1', '$0', '$1', '$2', '$256'),
91    'Imm32': ('$-1', '$0', '$1', '$2', '$256', '$65536')
92}
93
94sample_att_arguments_x86_32 = {
95    # Note: accumulator comes last to ensure that --fast version doesn't pick it,
96    # except as accumulator.  That way we test both instruction where accumulator
97    # is encoded specially (such as “add %al,$1”) and instructios where
98    # accumulator is not used (such as “add %cl,$1”.
99    'GeneralReg8': ('%CL', '%DL', '%BL', '%AL'),
100    'GeneralReg16': ('%CX', '%DX', '%BX', '%SP', '%BP', '%SI', '%DI', '%AX'),
101    'GeneralReg32': ('%ECX', '%EDX', '%EBX', '%ESP',
102                     '%EBP', '%ESI', '%EDI', '%EAX'),
103    'VecReg128': tuple('%%XMM%d' % N for N in (0, 4, 7)),
104    'VecReg256': tuple('%%YMM%d' % N for N in (0, 4, 7)),
105    'XmmReg': tuple('%%XMM%d' % N for N in (0, 4, 7)),
106    'YmmReg': tuple('%%YMM%d' % N for N in (0, 4, 7)),
107    'FpReg32': tuple('%%XMM%d' % N for N in range(8)),
108    'FpReg64': tuple('%%XMM%d' % N for N in range(8)),
109    'Label': ('0b', '1b', '2f'),
110}
111
112sample_att_arguments_x86_64 = {
113    'Imm64': ('$-1', '$0', '$1', '$2', '$256', '$65536', '$4294967296'),
114    # Note: accumulator comes last to ensure that --fast version doesn't pick it,
115    # except as accumulator.  That way we test both instruction where accumulator
116    # is encoded specially (such as “add %al,$1”) and instructios where
117    # accumulator is not used (such as “add %cl,$1”.
118    'GeneralReg8': ('%CL', '%DL', '%BL', '%SPL',
119                    '%BPL', '%SIL', '%DIL', '%R8B',
120                    '%R9B', '%R10B', '%R11B', '%R12B',
121                    '%R13B', '%R14B', '%R15B', '%AL', ),
122    'GeneralReg16': ('%CX', '%DX', '%BX', '%SP',
123                     '%BP', '%SI', '%DI', '%R8W',
124                     '%R9W', '%R10W', '%R11W', '%R12W',
125                     '%R13W', '%R14W', '%R15W', '%AX'),
126    'GeneralReg32': ('%ECX', '%EDX', '%EBX', '%ESP',
127                     '%EBP', '%ESI', '%EDI', '%R8D',
128                     '%R9D', '%R10D', '%R11D', '%R12D',
129                     '%R13D', '%R14D', '%R15D', '%EAX'),
130    'GeneralReg64': ('%RCX', '%RDX', '%RBX', '%RSP',
131                     '%RBP', '%RSI', '%RDI', '%R8',
132                     '%R9', '%R10', '%R11', '%R12',
133                     '%R13', '%R14', '%R15', '%RAX',),
134    'VecReg128': tuple('%%XMM%d' % N for N in range(0, 16, 5)),
135    'VecReg256': tuple('%%YMM%d' % N for N in range(0, 16, 5)),
136    'XmmReg': tuple('%%XMM%d' % N for N in range(0, 16, 5)),
137    'YmmReg': tuple('%%YMM%d' % N for N in range(0, 16, 5)),
138    'FpReg32': tuple('%%XMM%d' % N for N in range(16)),
139    'FpReg64': tuple('%%XMM%d' % N for N in range(16)),
140    'Label': ('0b', '1b', '2f'),
141}
142
143sample_arc_arguments = {
144    # Note: st(0) is not tested on purpose: many instructions have ambiguity
145    # where st(0) to st(0) version can be encoded in two different ways and both
146    # work fine, but assemblers produce different versions!
147    # Rather than try to match everything perfectly we limit ourselves to st(1),
148    # st(2), and st(4) which ensures that all bits are ancoded correctly.
149    'RegX87': ('Assembler::st1', 'Assembler::st2', 'Assembler::st4'),
150    'Imm2': ('0', '1', '2', '3'),
151    'Imm8': ('-1', '0', '1', '2'),
152    'Imm16': ('-1', '0', '1', '2', '256'),
153    'Imm32': ('-1', '0', '1', '2', '256', '65536'),
154    'Cond': ('Assembler::Condition::kOverflow', 'Assembler::Condition::kNoOverflow',
155             'Assembler::Condition::kBelow', 'Assembler::Condition::kAboveEqual',
156             'Assembler::Condition::kEqual', 'Assembler::Condition::kNotEqual',
157             'Assembler::Condition::kBelowEqual', 'Assembler::Condition::kAbove',
158             'Assembler::Condition::kNegative', 'Assembler::Condition::kPositiveOrZero',
159             'Assembler::Condition::kParityEven', 'Assembler::Condition::kParityOdd',
160             'Assembler::Condition::kLess', 'Assembler::Condition::kGreaterEqual',
161             'Assembler::Condition::kLessEqual', 'Assembler::Condition::kGreater'),
162}
163
164# Note: have to match sample_att_arguments_x86_32.
165# Read comment there about why accumulator is last.
166gp_registers_32 = ('Assembler::ecx', 'Assembler::edx',
167                   'Assembler::ebx', 'Assembler::esp',
168                   'Assembler::ebp', 'Assembler::esi',
169                   'Assembler::edi', 'Assembler::eax', )
170
171# Note: have to match sample_att_arguments_x86_32.
172# Read comment there about why accumulator is last.
173gp_registers_64 = ('Assembler::rcx', 'Assembler::rdx',
174                   'Assembler::rbx', 'Assembler::rsp',
175                   'Assembler::rbp', 'Assembler::rsi',
176                   'Assembler::rdi', 'Assembler::r8',
177                   'Assembler::r9', 'Assembler::r10',
178                   'Assembler::r11', 'Assembler::r12',
179                   'Assembler::r13', 'Assembler::r14',
180                   'Assembler::r15', 'Assembler::rax',)
181
182sample_arc_arguments_x86_32 = {
183    # Note: have to match sample_att_arguments_x86_32.
184    # Read comment there about why accumulator is last.
185    'GeneralReg8': ('Assembler::ecx', 'Assembler::edx',
186                    'Assembler::ebx', 'Assembler::eax'),
187    'GeneralReg16': gp_registers_32,
188    'GeneralReg32': gp_registers_32,
189    'VecReg128': tuple('Assembler::xmm%d' % N for N in (0, 4, 7)),
190    'VecReg256': tuple('Assembler::xmm%d.To256Bit()' % N for N in (0, 4, 7)),
191    'XmmReg': tuple('Assembler::xmm%d' % N for N in (0, 4, 7)),
192    'YmmReg': tuple('Assembler::xmm%d.To256Bit()' % N for N in (0, 4, 7)),
193    'FpReg32': tuple('Assembler::xmm%d' % N for N in range(8)),
194    'FpReg64': tuple('Assembler::xmm%d' % N for N in range(8)),
195}
196
197sample_arc_arguments_x86_64 = {
198    'Imm64': ('-1', '0', '1', '2', '256', '65536', '4294967296LL'),
199    'GeneralReg8': gp_registers_64,
200    'GeneralReg16': gp_registers_64,
201    'GeneralReg32': gp_registers_64,
202    'GeneralReg64': gp_registers_64,
203    'VecReg128': tuple('Assembler::xmm%d' % N for N in range(0, 16, 5)),
204    'VecReg256': tuple('Assembler::xmm%d.To256Bit()' % N for N in range(0, 16, 5)),
205    'XmmReg': tuple('Assembler::xmm%d' % N for N in range(0, 16, 5)),
206    'YmmReg': tuple('Assembler::xmm%d.To256Bit()' % N for N in range(0, 16, 5)),
207    'FpReg32': tuple('Assembler::xmm%d' % N for N in range(16)),
208    'FpReg64': tuple('Assembler::xmm%d' % N for N in range(16)),
209}
210
211MNEMO_TO_ASM = {
212    'MOVDQ': 'MOVAPS',
213    'MOVSXBL': 'MOVSBL',
214    'MOVSXBQ': 'MOVSBQ',
215    'MOVSXWL': 'MOVSWL',
216    'MOVSXWQ': 'MOVSWQ',
217    'MOVSXLQ': 'MOVSLQ',
218    'MOVZXBL': 'MOVZBL',
219    'MOVZXBQ': 'MOVZBQ',
220    'MOVZXWL': 'MOVZWL',
221    'MOVZXWQ': 'MOVZWQ',
222    'VCVTPD2DQ': 'VCVTPD2DQX',
223    'VCVTPD2PS': 'VCVTPD2PSX',
224    'VCVTTPD2DQ': 'VCVTTPD2DQX'
225}
226
227FIXED_REGISTER_CLASSES = (
228    'AL', 'AX', 'EAX', 'RAX',
229    'CL', 'ECX', 'RCX', 'ST', 'ST1',
230    'DX', 'EDX', 'RDX', 'CC',
231    'BX', 'EBX', 'RBX', 'SW',
232    'EBP', 'RSP', 'FLAGS'
233)
234
235
236def _update_arguments(x86_64):
237  if x86_64:
238    addr = 'GeneralReg64'
239    sample_att_arguments.update(sample_att_arguments_x86_64)
240    sample_arc_arguments_add = sample_arc_arguments_x86_64
241  else:
242    addr = 'GeneralReg32'
243    sample_att_arguments.update(sample_att_arguments_x86_32)
244    sample_arc_arguments_add = sample_arc_arguments_x86_32
245  for key, values in sample_arc_arguments_add.items():
246    sample_arc_arguments[key] = values
247  addrs = ['0']
248  addrs += ['(%s)' % reg for reg in sample_att_arguments[addr]]
249  addrs += ['%s(,%s%s)' % (offset, index, scale)
250            for offset in ('', '64', '32768')
251            for index in sample_att_arguments[addr]
252            for scale in ('', ',2', ',4', ',8')
253            if index not in ('%ESP', '%RSP')]
254  addrs += ['%s(%s,%s%s)' % (offset, base, index, scale)
255            for offset in ('', '64', '32768')
256            for base in sample_att_arguments[addr]
257            for index in sample_att_arguments[addr]
258            for scale in ('', ',2', ',4', ',8')
259            if index not in ('%ESP', '%RSP')]
260  for mem_arg in ('Mem', 'Mem8', 'Mem16', 'Mem32', 'Mem64', 'Mem128',
261                  'MemX87', 'MemX8716', 'MemX8732', 'MemX8764', 'MemX8780',
262                  'VecMem32', 'VecMem64', 'VecMem128', 'VecMem256'):
263    sample_att_arguments[mem_arg] = tuple(addrs)
264
265  sample_att_arguments['GeneralReg'] = sample_att_arguments[addr]
266
267  def peel_constructor(s):
268    return s.split('(', 1)[1][:-1] if '(' in s else s
269
270  addrs = ['Assembler::Operand()']
271  addrs += ['{.base = %s}' % peel_constructor(reg)
272            for reg in sample_arc_arguments[addr]]
273  addrs += ['{.index = %s, .scale = Assembler::kTimes%s, .disp = %d}' %
274            (peel_constructor(index), scale, disp)
275            for disp in (0, 64, 32768)
276            for index in sample_arc_arguments[addr]
277            for scale in ('One', 'Two', 'Four', 'Eight')
278            if 'Assembler::esp' not in index and 'Assembler::rsp' not in index]
279  addrs += ['{.base = %s, .index = %s, .scale = Assembler::kTimes%s, .disp = %d}' %
280            (peel_constructor(base), peel_constructor(index), scale, disp)
281            for disp in (0, 64, 32768)
282            for base in sample_arc_arguments[addr]
283            for index in sample_arc_arguments[addr]
284            for scale in ('One', 'Two', 'Four', 'Eight')
285            if 'Assembler::esp' not in index and 'Assembler::rsp' not in index]
286  for mem_arg in ('Mem', 'Mem8', 'Mem16', 'Mem32', 'Mem64', 'Mem128',
287                  'MemX87', 'MemX8716', 'MemX8732', 'MemX8764', 'MemX8780',
288                  'VecMem32', 'VecMem64', 'VecMem128', 'VecMem256'):
289    sample_arc_arguments[mem_arg] = tuple(addrs)
290
291  sample_arc_arguments['GeneralReg'] = sample_arc_arguments[addr]
292
293
294def _gen_att_assembler(file, insns, fast_mode):
295  for insn in insns:
296    arc_name = insn['asm']
297    insn_name = insn['mnemo']
298    if len(insn['args']) and insn['args'][0]['class'] == 'Cond':
299      if insn_name in ('CMOVW', 'CMOVL', 'CMOVQ'):
300        insn_name = 'CMOV'
301      else:
302        assert insn_name.endswith('CC')
303        insn_name = insn_name[:-2]
304      for insn_suffix in ('O', 'NO', 'B', 'AE', 'E', 'NE', 'BE', 'A',
305                          'S', 'NS', 'P', 'NP', 'L', 'GE', 'LE', 'G'):
306        _gen_att_instruction_variants(
307            file, arc_name, insn_name + insn_suffix, insn['args'], fast_mode)
308    elif arc_name == 'Call' and insn['args'][1]['class'] != 'Label':
309      _gen_att_call_variants(file, insn['args'], fast_mode)
310    else:
311      _gen_att_instruction_variants(
312          file, arc_name, insn_name, insn['args'], fast_mode)
313
314
315def _gen_att_instruction_variants(
316    file, arc_name, insn_name, insn_args, fast_mode):
317  if insn_name in MNEMO_TO_ASM:
318    insn_name = MNEMO_TO_ASM[insn_name]
319  insn_sample_args = []
320  label_present = False
321  if arc_name.endswith('ByOne'):
322    assert insn_name.endswith('BYONE')
323    insn_name = insn_name[:-5]
324  elif arc_name.endswith('Imm2'):
325    assert insn_name.endswith('IMM2')
326    insn_name = insn_name[:-4]
327  elif arc_name.endswith('Imm8'):
328    assert insn_name.endswith('IMM8')
329    insn_name = insn_name[:-4]
330  elif arc_name.endswith('Accumulator'):
331    assert insn_name.endswith('ACCUMULATOR')
332    insn_name = insn_name[:-11]
333  elif arc_name.endswith('ByCl'):
334    assert insn_name.endswith('BYCL')
335    insn_name = insn_name[:-4]
336  elif arc_name.endswith('FromSt'):
337    assert insn_name.endswith('FROMST')
338    insn_name = insn_name[:-6]
339  elif arc_name.endswith('ToSt'):
340    assert insn_name.endswith('TOST')
341    insn_name = insn_name[:-4]
342  for arg_nr, insn_arg in enumerate(insn_args):
343    arg_class = insn_arg['class']
344    if arg_class == 'Cond':
345      # This argument was already embedded into the name of instruction.
346      continue
347    if arg_class == 'Label':
348      label_present = True
349    if arg_class in ('AL', 'AX', 'EAX', 'RAX') and (
350       arc_name.endswith('Accumulator') or arc_name == "Fnstsw"):
351      arg_variants = ('%%%s' % arg_class,)
352    elif arg_class == 'CL' and arc_name.endswith('ByCl'):
353      arg_variants = ('%CL',)
354    elif arg_class == 'ST' and (arc_name.endswith('FromSt') or arc_name.endswith('ToSt')):
355      arg_variants = ('%ST',)
356    elif arg_class == 'GeneralReg' and insn_name not in ('PUSH', 'POP'):
357      arg_variants = tuple('*%s' % reg for reg in sample_att_arguments['GeneralReg'])
358    elif arg_class[:3] == 'Imm' and insn_name in (
359        'PSLLW', 'PSRAW', 'PSRLW', 'PSLLD', 'PSRAD', 'PSRLD',
360        'PSLLQ', 'PSRLQ', 'PSLLDQ', 'PSRLDQ',
361        'RCLB', 'RCLW', 'RCLL', 'RCLQ', 'RCRB', 'RCRW', 'RCRL', 'RCRQ',
362        'ROLB', 'ROLW', 'ROLL', 'ROLQ', 'RORB', 'RORW', 'RORL', 'RORQ',
363        'SHLB', 'SHLW', 'SHLL', 'SHLQ', 'SHRB', 'SHRW', 'SHRL', 'SHRQ',
364        'SARB', 'SARW', 'SARL', 'SARQ', 'BTCB', 'BTCW', 'BTCL', 'BTCQ'):
365      arg_variants = sample_att_arguments[insn_arg['class']][1:]
366    elif ((arg_class == 'Mem32' and insn_name in ('JMPL', 'CALLL')) or
367          (arg_class == 'VecMem64' and insn_name in ('JMPQ', 'CALLQ'))):
368      arg_variants = tuple('*%s' % reg for reg in sample_att_arguments[insn_arg['class']])
369    elif arg_class in FIXED_REGISTER_CLASSES:
370      # Note: arguments from FIXED_REGISTER_CLASSES are implicit in AT&T assembler
371      # (except for accumulator in some instructions).  Skip them.
372      continue
373    else:
374      arg_variants = sample_att_arguments[insn_arg['class']]
375    # Some instructions have special encodings with certain immediates
376    # (e.g. shifts by 1, introduced in 8086, are encoded differently than
377    # shifts by 2, introduced in 80186).
378    # Keep all variants even in --fast mode.
379    if fast_mode and not arg_class.startswith('Imm'):
380      # In --fast mode we want to keep only one variant, but it's important for
381      # us to pick different registers for diffetent position.
382      # This way we are testting “vmfaddps %xmm0, %xmm1, %xmm2, %xmm3” instead
383      # of “vmfaddps %xmm0, %xmm0, %xmm0, %xmm0” which is important to detect
384      # cases where operands are specified in a wrong order in JSON.
385      arg_variants = (arg_variants[arg_nr % len(arg_variants)],)
386    insn_sample_args.append(arg_variants)
387  for insn_args in itertools.product(*insn_sample_args):
388    fixed_name = insn_name
389    if insn_name == 'MOVQ' and not '(' in insn_args[0] and '%' in insn_args[0]:
390      # This is rare case where ARC code emitter produces code more optimal than
391      # GNU assembler.  Reproduce that optimization here.
392      if insn_args[1][0] == '$' and insn_args[1] not in ('$-1', '$4294967296'):
393        fixed_name = 'MOVL'
394        # Make 32-bit version of register name.  High registers need to add
395        # 'D' suffix, for low ones we need to replace 'R' with 'E'.
396        if insn_args[0] in ('%R8', '%R9', '%R10', '%R11',
397                            '%R12', '%R13', '%R14', '%R15'):
398          insn_args = (insn_args[0] + 'D',) + insn_args[1:]
399        else:
400          insn_args = ('%E' + insn_args[0][2:],) + insn_args[1:]
401    if insn_name[0:4] == 'LOCK':
402      # TODO(b/161986409): replace '\n' with ' ' when clang would be fixed.
403      fixed_name = '%s\n%s' % (insn_name[0:4], insn_name[4:])
404    fixed_name = {
405      # GNU disassembler accepts these instructions, but not Clang assembler.
406      'FNDISI': '.byte 0xdb, 0xe1',
407      'FNENI': '.byte 0xdb, 0xe0',
408      'FNSETPM': '.byte 0xdb, 0xe4',
409    }.get(fixed_name, fixed_name)
410    if label_present:
411      print('.p2align 5, 0x90', file=file)
412      print('0:', file=file)
413      for _ in range(256):
414        print('nop', file=file)
415      print('1:', file=file)
416    print('%s %s' % (fixed_name, ', '.join(reversed(insn_args))), file=file)
417    if label_present:
418      for _ in range(256):
419        print('nop', file=file)
420      print('2:', file=file)
421
422
423def _gen_att_call_variants(file, call_args, fast_mode):
424  assert len(call_args) == 2
425  assert call_args[0]['class'] == 'RSP'
426  assert call_args[1]['class'] == 'GeneralReg'
427  arg_variants = sample_att_arguments['GeneralReg']
428  if fast_mode:
429    arg_variants = (arg_variants[1],)
430  for call_arg in arg_variants:
431    print('CALL *%s' % call_arg, file=file)
432
433
434def _gen_arc_generators(file):
435  for arg_class, arc_args in sample_arc_arguments.items():
436    if arg_class == 'Label':
437      continue
438    arg_type = _argument_class_to_arc_type(arg_class)
439    print('%s* %sArgs() {' % (arg_type, arg_class), file=file)
440    print('  static %s* arg_list;' % arg_type, file=file)
441    print('  if (!arg_list) {', file=file)
442    print('    arg_list = reinterpret_cast<%s*>(malloc(%d * sizeof(%s)));' %
443          (arg_type, len(arc_args), arg_type), file=file)
444    for arg_nr, arg in enumerate(arc_args):
445      print('    arg_list[%d] = %s;' % (arg_nr, arg), file=file)
446    print('  }', file=file)
447    print('  return arg_list;', file=file)
448    print('}', file=file)
449    print('', file=file)
450
451
452def _gen_arc_assembler(file, insn_kind, insns, fast_mode):
453  for insn in insns:
454    _gen_arc_instruction_variants(file, insn['asm'], insn['args'], fast_mode)
455  print('void GenInsns%s(Assembler* as) {' %
456        insn_kind, file=file)
457  for insn in insns:
458    classes = [insn_arg['class'] for insn_arg in insn['args']]
459    print('  %s_%s(as);' % (insn['asm'], '_'.join(classes)), file=file)
460  if not insns:
461    print('  UNUSED(as);', file=file)
462  print('}', file=file)
463  print('', file=file)
464
465
466def _gen_arc_instruction_variants(file, arc_name, insn_args, fast_mode):
467  classes = [insn_arg['class'] for insn_arg in insn_args]
468  print('void %s_%s(Assembler* as) {' %
469        (arc_name, '_'.join(classes)), file=file)
470  label_present = False
471  arg_type_count = 0
472  indent = ''
473  for arg_nr, insn_arg in enumerate(insn_args):
474    arg_class = insn_arg['class']
475    arg_ref = '*'
476    indent = ' ' * (2 * arg_type_count)
477    if arg_class == 'Label':
478      label_present = True
479      print('%s  Assembler::Label* labels[3];' % indent, file=file)
480      args_generator = 'labels'
481      arg_ref = '**'
482    else:
483      args_generator = '%sArgs()' % arg_class
484    if arg_class not in FIXED_REGISTER_CLASSES:
485      arg_type = _argument_class_to_arc_type(arg_class)
486      if arg_class == 'Label':
487        arg_choices = 3
488      else:
489        arg_choices = len(sample_arc_arguments[arg_class])
490      arg_shift = ''
491      if arg_class[:3] == 'Imm' and arc_name in (
492          'Psllw', 'Psraw', 'Psrlw', 'Pslld', 'Psrad', 'Psrld',
493          'Psllq', 'Psrlq', 'Pslldq', 'Psrldq',
494          'Rclb', 'Rclw', 'Rcll', 'Rclq', 'Rcrb', 'Rcrw', 'Rcrl', 'Rcrq',
495          'Rolb', 'Rolw', 'Roll', 'Rolq', 'Rorb', 'Rorw', 'Rorl', 'Rorq',
496          'Shlb', 'Shlw', 'Shll', 'Shlq', 'Shrb', 'Shrw', 'Shrl', 'Shrq',
497          'Sarb', 'Sarw', 'Sarl', 'Sarq', 'Btcb', 'Btcw', 'Btcl', 'Btcq'):
498        arg_choices = arg_choices - 1
499        arg_shift = ' + 1'
500      # See notes about fast_mode handing in _gen_att_instruction_variants.
501      if fast_mode and not arg_class.startswith('Imm') and not arg_class == 'Cond':
502        print('%s  %s %sarg%d = %s%s + %d;' %
503              (indent, arg_type, arg_ref, arg_nr, args_generator, arg_shift,
504               arg_nr % arg_choices),
505              file=file)
506      else:
507        arg_type_count += 1
508        print('%s  for (%s %sarg%d = %s%s, %sarg%d_list = arg%d;'
509              ' arg%d != arg%d_list + %d; ++arg%d) {' %
510              (indent, arg_type, arg_ref, arg_nr, args_generator, arg_shift,
511               arg_ref, arg_nr, arg_nr, arg_nr, arg_nr, arg_choices, arg_nr),
512              file=file)
513  indent = ' ' * (2 * arg_type_count)
514  if label_present:
515    print('%s  labels[0] = as->MakeLabel();' % indent, file=file)
516    print('%s  labels[1] = as->MakeLabel();' % indent, file=file)
517    print('%s  labels[2] = as->MakeLabel();' % indent, file=file)
518    print('%s  // Don\'t use as->Align(32) for compatibility with GNU as'
519          % indent, file=file)
520    print('%s  while (as->pc()%%32) as->Nop();' % indent, file=file)
521    print('%s  as->Bind(labels[0]);' % indent, file=file)
522    print('%s  for (int nr=0; nr < 256; ++nr)' % indent, file=file)
523    print('%s    as->Nop();' % indent, file=file)
524    print('%s  as->Bind(labels[1]);' % indent, file=file)
525  print('%s  as->%s(%s);' %
526        (indent,
527         arc_name,
528         ', '.join((
529             '%sarg%d' % ('*' if arg['class'] != 'Label' else '**', nr)
530             for nr, arg in enumerate(insn_args)
531             if arg['class'] not in FIXED_REGISTER_CLASSES))),
532        file=file)
533  if label_present:
534    print('%s  for (int nr=0; nr < 256; ++nr)' % indent, file=file)
535    print('%s    as->Nop();' % indent, file=file)
536    print('%s  as->Bind(labels[2]);' % indent, file=file)
537  for arg_nr in range(arg_type_count, 0, -1):
538    print('%s}' % (' ' * (2 * arg_nr)), file=file)
539  print('}', file=file)
540  print('', file=file)
541
542
543def _argument_class_to_arc_type(arg_class):
544  if arg_class == 'Imm2':
545    return 'int8_t'
546  elif arg_class[:3] == 'Imm':
547    return 'int%s_t' % arg_class[3:]
548  elif arg_class == 'Cond':
549    return 'Assembler::Condition'
550  elif arg_class == 'Label':
551    return 'Assembler::Label'
552  elif sample_arc_arguments[arg_class][0] in gp_registers_32 + gp_registers_64:
553    return 'Assembler::Register'
554  elif sample_arc_arguments[arg_class][0].startswith('Assembler::st'):
555    return 'Assembler::X87Register'
556  elif sample_arc_arguments[arg_class][0].startswith('Assembler::xmm'):
557    if sample_arc_arguments[arg_class][0].endswith(".To256Bit()"):
558      return 'Assembler::YMMRegister'
559    else:
560      return 'Assembler::XMMRegister'
561  else:
562    return sample_arc_arguments[arg_class][0].split('(')[0]
563
564
565if __name__ == '__main__':
566  sys.exit(main(sys.argv))
567