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