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