github.com/cloudwego/iasm@v0.2.0/mkasm_x86_64.py (about) 1 #!/usr/bin/env python3 2 # -*- coding: utf-8 -*- 3 4 import os 5 import copy 6 import json 7 8 from typing import List 9 from typing import Tuple 10 from typing import Iterable 11 from opcodes import x86_64 12 13 def instruction_set(): 14 for ins in x86_64.read_instruction_set(): 15 fv = [] 16 for form in ins.forms: 17 if any(op.type in ['{sae}', '{er}'] for op in form.operands): 18 new = copy.deepcopy(form) 19 new.operands = [op for op in new.operands if op.type not in ['{sae}', '{er}']] 20 new_evex = next(v for v in new.encodings[0].components if isinstance(v, x86_64.EVEX)) 21 new_evex.b = 0 22 new_evex.LL = 0b10 23 fv.append(new) 24 old = next(v for v in form.encodings[0].components if isinstance(v, x86_64.EVEX)) 25 if not isinstance(old.LL, x86_64.Operand): 26 old.LL = 0 27 old.b = 1 28 ins.forms.extend(fv) 29 yield ins 30 31 def instruction_domains(): 32 with open(os.path.join(os.path.dirname(__file__), 'domains_x86_64.json')) as fp: 33 domains = json.load(fp) 34 return { ins: dom for dom, insv in domains.items() for ins in insv } 35 36 instrs = {} 37 domains = instruction_domains() 38 39 for instr in instruction_set(): 40 for form in instr.forms: 41 if all([v.type not in ('r8l', 'r16l', 'r32l', 'moffs32', 'moffs64') for v in form.operands]): 42 name = form.gas_name.upper() 43 if name not in instrs: 44 instrs[name] = (instr.name, instr.summary, []) 45 instrs[name][2].append(form) 46 47 for _, _, forms in instrs.values(): 48 forms.sort(key = lambda f: max([x.score for x in f.isa_extensions], default = 0)) 49 50 OPCHECKS = { 51 '1' : 'isConst1(%s)', 52 '3' : 'isConst3(%s)', 53 'al' : '%s == AL', 54 'ax' : '%s == AX', 55 'eax' : '%s == EAX', 56 'rax' : '%s == RAX', 57 'cl' : '%s == CL', 58 'xmm0' : '%s == XMM0', 59 'rel8' : 'isRel8(%s)', 60 'rel32' : 'isRel32(%s)', 61 'imm4' : 'isImm4(%s)', 62 'imm8' : 'isImm8(%s)', 63 'imm16' : 'isImm16(%s)', 64 'imm32' : 'isImm32(%s)', 65 'imm64' : 'isImm64(%s)', 66 'r8' : 'isReg8(%s)', 67 'r16' : 'isReg16(%s)', 68 'r32' : 'isReg32(%s)', 69 'r64' : 'isReg64(%s)', 70 'mm' : 'isMM(%s)', 71 'xmm' : 'isXMM(%s)', 72 'xmm{k}' : 'isXMMk(%s)', 73 'xmm{k}{z}' : 'isXMMkz(%s)', 74 'ymm' : 'isYMM(%s)', 75 'ymm{k}' : 'isYMMk(%s)', 76 'ymm{k}{z}' : 'isYMMkz(%s)', 77 'zmm' : 'isZMM(%s)', 78 'zmm{k}' : 'isZMMk(%s)', 79 'zmm{k}{z}' : 'isZMMkz(%s)', 80 'k' : 'isK(%s)', 81 'k{k}' : 'isKk(%s)', 82 'm' : 'isM(%s)', 83 'm8' : 'isM8(%s)', 84 'm16' : 'isM16(%s)', 85 'm16{k}{z}' : 'isM16kz(%s)', 86 'm32' : 'isM32(%s)', 87 'm32{k}' : 'isM32k(%s)', 88 'm32{k}{z}' : 'isM32kz(%s)', 89 'm64' : 'isM64(%s)', 90 'm64{k}' : 'isM64k(%s)', 91 'm64{k}{z}' : 'isM64kz(%s)', 92 'm80' : 'isM80(%s)', 93 'm128' : 'isM128(%s)', 94 'm128{k}{z}' : 'isM128kz(%s)', 95 'm256' : 'isM256(%s)', 96 'm256{k}{z}' : 'isM256kz(%s)', 97 'm512' : 'isM512(%s)', 98 'm512{k}{z}' : 'isM512kz(%s)', 99 'm64/m32bcst' : 'isM64M32bcst(%s)', 100 'm128/m32bcst' : 'isM128M32bcst(%s)', 101 'm256/m32bcst' : 'isM256M32bcst(%s)', 102 'm512/m32bcst' : 'isM512M32bcst(%s)', 103 'm128/m64bcst' : 'isM128M64bcst(%s)', 104 'm256/m64bcst' : 'isM256M64bcst(%s)', 105 'm512/m64bcst' : 'isM512M64bcst(%s)', 106 'vm32x' : 'isVMX(%s)', 107 'vm32x{k}' : 'isVMXk(%s)', 108 'vm32y' : 'isVMY(%s)', 109 'vm32y{k}' : 'isVMYk(%s)', 110 'vm32z' : 'isVMZ(%s)', 111 'vm32z{k}' : 'isVMZk(%s)', 112 'vm64x' : 'isVMX(%s)', 113 'vm64x{k}' : 'isVMXk(%s)', 114 'vm64y' : 'isVMY(%s)', 115 'vm64y{k}' : 'isVMYk(%s)', 116 'vm64z' : 'isVMZ(%s)', 117 'vm64z{k}' : 'isVMZk(%s)', 118 '{sae}' : 'isSAE(%s)', 119 '{er}' : 'isER(%s)', 120 } 121 122 IMMCHECKS = { 123 'imm8' : 'isImm8Ext(%s, %d)', 124 'imm32' : 'isImm32Ext(%s, %d)', 125 } 126 127 EVEXCHECKS = { 128 'xmm' : 'isEVEXXMM(%s)', 129 'ymm' : 'isEVEXYMM(%s)', 130 'vm32x' : 'isEVEXVMX(%s)', 131 'vm64x' : 'isEVEXVMX(%s)', 132 'vm32y' : 'isEVEXVMY(%s)', 133 'vm64y' : 'isEVEXVMY(%s)', 134 } 135 136 VEXBYTES = { 137 'VEX': '0xc4', 138 'XOP': '0x8f', 139 } 140 141 ISAMAPPING = { 142 'CPUID' : 'ISA_CPUID', 143 'RDTSC' : 'ISA_RDTSC', 144 'RDTSCP' : 'ISA_RDTSCP', 145 'CMOV' : 'ISA_CMOV', 146 'MOVBE' : 'ISA_MOVBE', 147 'POPCNT' : 'ISA_POPCNT', 148 'LZCNT' : 'ISA_LZCNT', 149 'TBM' : 'ISA_TBM', 150 'BMI' : 'ISA_BMI', 151 'BMI2' : 'ISA_BMI2', 152 'ADX' : 'ISA_ADX', 153 'MMX' : 'ISA_MMX', 154 'MMX+' : 'ISA_MMX_PLUS', 155 'FEMMS' : 'ISA_FEMMS', 156 '3dnow!' : 'ISA_3DNOW', 157 '3dnow!+' : 'ISA_3DNOW_PLUS', 158 'SSE' : 'ISA_SSE', 159 'SSE2' : 'ISA_SSE2', 160 'SSE3' : 'ISA_SSE3', 161 'SSSE3' : 'ISA_SSSE3', 162 'SSE4A' : 'ISA_SSE4A', 163 'SSE4.1' : 'ISA_SSE4_1', 164 'SSE4.2' : 'ISA_SSE4_2', 165 'FMA3' : 'ISA_FMA3', 166 'FMA4' : 'ISA_FMA4', 167 'XOP' : 'ISA_XOP', 168 'F16C' : 'ISA_F16C', 169 'AVX' : 'ISA_AVX', 170 'AVX2' : 'ISA_AVX2', 171 'AVX512F' : 'ISA_AVX512F', 172 'AVX512BW' : 'ISA_AVX512BW', 173 'AVX512DQ' : 'ISA_AVX512DQ', 174 'AVX512VL' : 'ISA_AVX512VL', 175 'AVX512PF' : 'ISA_AVX512PF', 176 'AVX512ER' : 'ISA_AVX512ER', 177 'AVX512CD' : 'ISA_AVX512CD', 178 'AVX512VBMI' : 'ISA_AVX512VBMI', 179 'AVX512IFMA' : 'ISA_AVX512IFMA', 180 'AVX512VPOPCNTDQ' : 'ISA_AVX512VPOPCNTDQ', 181 'AVX512_4VNNIW' : 'ISA_AVX512_4VNNIW', 182 'AVX512_4FMAPS' : 'ISA_AVX512_4FMAPS', 183 'PREFETCH' : 'ISA_PREFETCH', 184 'PREFETCHW' : 'ISA_PREFETCHW', 185 'PREFETCHWT1' : 'ISA_PREFETCHWT1', 186 'CLFLUSH' : 'ISA_CLFLUSH', 187 'CLFLUSHOPT' : 'ISA_CLFLUSHOPT', 188 'CLWB' : 'ISA_CLWB', 189 'CLZERO' : 'ISA_CLZERO', 190 'RDRAND' : 'ISA_RDRAND', 191 'RDSEED' : 'ISA_RDSEED', 192 'PCLMULQDQ' : 'ISA_PCLMULQDQ', 193 'AES' : 'ISA_AES', 194 'SHA' : 'ISA_SHA', 195 'MONITOR' : 'ISA_MONITOR', 196 'MONITORX' : 'ISA_MONITORX', 197 } 198 199 DOMAIN_MAP = { 200 'generic' : 'DomainGeneric', 201 'mmxsse' : 'DomainMMXSSE', 202 'avx' : 'DomainAVX', 203 'fma' : 'DomainFMA', 204 'crypto' : 'DomainCrypto', 205 'mask' : 'DomainMask', 206 'amd' : 'DomainAMDSpecific', 207 'misc' : 'DomainMisc', 208 } 209 210 BRANCH_INSTRUCTIONS = { 211 'JA' , 'JNA', 212 'JAE' , 'JNAE', 213 'JB' , 'JNB', 214 'JBE' , 'JNBE', 215 'JC' , 'JNC', 216 'JE' , 'JNE', 217 'JG' , 'JNG', 218 'JGE' , 'JNGE', 219 'JL' , 'JNL', 220 'JLE' , 'JNLE', 221 'JO' , 'JNO', 222 'JP' , 'JNP', 223 'JS' , 'JNS', 224 'JZ' , 'JNZ', 225 'JPE' , 'JPO', 226 'JECXZ' , 'JRCXZ', 227 'JMP' 228 } 229 230 def is_avx512(form: x86_64.InstructionForm) -> bool: 231 return any(v.name.startswith('AVX512') for v in form.isa_extensions) 232 233 def dump_form(form: x86_64.InstructionForm) -> str: 234 if not form.operands: 235 return form.gas_name.upper() 236 else: 237 return form.gas_name.upper() + ' ' + ', '.join(v.type for v in reversed(form.operands)) 238 239 def require_isa(isa: List[x86_64.ISAExtension]) -> str: 240 flags = [] 241 for v in isa: 242 if v.name not in ISAMAPPING: 243 raise RuntimeError('invalid ISA: ' + v.name) 244 flags.append(ISAMAPPING[v.name]) 245 return ' | '.join(flags) 246 247 def operand_match(ops: List[x86_64.Operand], argc: int, avx512: bool) -> Iterable[str]: 248 for i, op in enumerate(ops): 249 if i < argc: 250 argv = 'v%d' % i 251 else: 252 argv = 'vv[%d]' % (i - argc) 253 if op.extended_size is not None and op.type in IMMCHECKS: 254 yield IMMCHECKS[op.type] % (argv, op.extended_size) 255 elif avx512 and op.type in EVEXCHECKS: 256 yield EVEXCHECKS[op.type] % argv 257 else: 258 yield OPCHECKS[op.type] % argv 259 260 def generate_encoding(enc: x86_64.Encoding, ops: List[x86_64.Operand], gen_branch: bool = False) -> Tuple[str, List[str]]: 261 buf = [] 262 flags = [] 263 disp8v = None 264 for item in enc.components: 265 if isinstance(item, x86_64.Prefix): 266 buf.append('m.emit(0x%02x)' % item.byte) 267 elif isinstance(item, x86_64.REX): 268 item.set_ignored() 269 if item.is_mandatory: 270 if isinstance(item.X, x86_64.Operand): 271 args = [str(item.W)] 272 if isinstance(item.R, x86_64.Operand): 273 args.append('hcode(v[%d])' % ops.index(item.R)) 274 else: 275 args.append(str(item.R)) 276 args.append('addr(v[%d])' % ops.index(item.X)) 277 buf.append('m.rexm(%s)' % ', '.join(args)) 278 else: 279 rex = 0x40 | (item.W << 3) 280 args = [] 281 if isinstance(item.R, x86_64.Operand): 282 args.append('hcode(v[%d]) << 2' % ops.index(item.R)) 283 else: 284 rex |= item.R << 2 285 if isinstance(item.B, x86_64.Operand): 286 args.append('hcode(v[%d])' % ops.index(item.B)) 287 else: 288 rex |= item.B 289 rex |= item.X << 1 290 buf.append('m.emit(%s)' % ' | '.join(['0x%02x' % rex] + args)) 291 else: 292 args = [] 293 if isinstance(item.R, x86_64.Operand): 294 args.append('hcode(v[%d])' % ops.index(item.R)) 295 else: 296 args.append(str(item.R)) 297 if isinstance(item.X, x86_64.Operand): 298 args.append('addr(v[%d])' % ops.index(item.X)) 299 else: 300 args.append('v[%d]' % ops.index(item.B)) 301 rexv = [] 302 for i, op in enumerate(ops): 303 if op.type == 'r8': 304 rexv.append('isReg8REX(v[%d])' % i) 305 if not rexv: 306 args.append('false') 307 else: 308 args.append(' || '.join(rexv)) 309 buf.append('m.rexo(%s)' % ', '.join(args)) 310 elif isinstance(item, x86_64.VEX): 311 item.set_ignored() 312 if item.type == 'VEX' and item.mmmmm == 0b00001 and item.W == 0: 313 if item.R == 1 and item.X == 1 and item.B == 1: 314 buf.append('m.emit(0xc5)') 315 buf.append('m.emit(0x%02x)' % (0xf8 | (item.L << 2) | int(item.pp))) 316 else: 317 args = [str(int(item.L << 2) | item.pp)] 318 if isinstance(item.R, x86_64.Operand): 319 args.append('hcode(v[%d])' % ops.index(item.R)) 320 else: 321 args.append('0') 322 if isinstance(item.X, x86_64.Operand): 323 args.append('addr(v[%d])' % ops.index(item.X)) 324 elif isinstance(item.B, x86_64.Operand): 325 args.append('v[%d]' % ops.index(item.B)) 326 else: 327 args.append('nil') 328 if isinstance(item.vvvv, x86_64.Operand): 329 args.append('hlcode(v[%d])' % ops.index(item.vvvv)) 330 else: 331 args.append('0') 332 buf.append('m.vex2(%s)' % ', '.join(args)) 333 else: 334 if isinstance(item.X, x86_64.Operand): 335 args = [ 336 VEXBYTES[item.type], 337 bin(item.mmmmm), 338 '0x%02x' % ((item.W << 7) | (item.L << 2) | int(item.pp)), 339 ] 340 if isinstance(item.R, x86_64.Operand): 341 args.append('hcode(v[%d])' % ops.index(item.R)) 342 else: 343 args.append('0') 344 args.append('addr(v[%d])' % ops.index(item.X)) 345 if isinstance(item.vvvv, x86_64.Operand): 346 args.append('hlcode(v[%d])' % ops.index(item.vvvv)) 347 else: 348 args.append('0') 349 buf.append('m.vex3(%s)' % ', '.join(args)) 350 else: 351 buf.append('m.emit(%s)' % VEXBYTES[item.type]) 352 v0 = '0x%02x' % (0xe0 | item.mmmmm) 353 if isinstance(item.R, x86_64.Operand): 354 v0 += ' ^ (hcode(v[%d]) << 7)' % ops.index(item.R) 355 if isinstance(item.B, x86_64.Operand): 356 v0 += ' ^ (hcode(v[%d]) << 5)' % ops.index(item.B) 357 buf.append('m.emit(%s)' % v0) 358 vex = 0x78 | (item.W << 7) | (item.L << 2) | int(item.pp) 359 if isinstance(item.vvvv, x86_64.Operand): 360 buf.append('m.emit(0x%02x ^ (hlcode(v[%d]) << 3))' % (vex, ops.index(item.vvvv))) 361 else: 362 buf.append('m.emit(0x%02x)' % vex) 363 elif isinstance(item, x86_64.EVEX): 364 disp8v = item.disp8xN 365 item.set_ignored() 366 if item.X.is_memory: 367 args = ['0b' + format(item.mm, '02b'), '0x%02x' % (item.W << 7 | int(item.pp) | 0b100)] 368 if isinstance(item.LL, x86_64.Operand): 369 args.append('vcode(v[%d])' % ops.index(item.LL)) 370 else: 371 args.append('0b' + format(item.LL, '02b')) 372 if isinstance(item.RR, x86_64.Operand): 373 args.append('ehcode(v[%d])' % ops.index(item.RR)) 374 else: 375 args.append(str(item.RR)) 376 args.append('addr(v[%d])' % ops.index(item.X)) 377 if item.vvvv != 0: 378 args.append('vcode(v[%d])' % ops.index(item.vvvv)) 379 else: 380 args.append('0') 381 if item.aaa != 0: 382 args.append('kcode(v[%d])' % ops.index(item.aaa)) 383 else: 384 args.append('0') 385 if item.z != 0: 386 args.append('zcode(v[%d])' % ops.index(item.z)) 387 else: 388 args.append('0') 389 if isinstance(item.b, x86_64.Operand): 390 args.append('bcode(v[%d])' % ops.index(item.b)) 391 elif item.b != 0: 392 args.append(str(item.b)) 393 else: 394 args.append('0') 395 buf.append('m.evex(%s)' % ', '.join(args)) 396 else: 397 buf.append('m.emit(0x62)') 398 if isinstance(item.RR, x86_64.Operand): 399 v0, v1, v2, v3 = 0xf0 | item.mm, ops.index(item.RR), ops.index(item.B), ops.index(item.RR) 400 buf.append('m.emit(0x%02x ^ ((hcode(v[%d]) << 7) | (ehcode(v[%d]) << 5) | (ecode(v[%d]) << 4)))' % (v0, v1, v2, v3)) 401 else: 402 r0 = item.RR & 1 403 r1 = (item.RR >> 1) & 1 404 byte = (item.mm | (r0 << 7) | (r1 << 4)) ^ 0xf0 405 if byte == 0: 406 buf.append('m.emit(ehcode(v[%d]) << 5)' % ops.index(item.B)) 407 else: 408 buf.append('m.emit(0x%02x ^ (ehcode(v[%d]) << 5))' % (byte, ops.index(item.B))) 409 vvvv = item.W << 7 | int(item.pp) | 0b01111100 410 if isinstance(item.vvvv, x86_64.Operand): 411 buf.append('m.emit(0x%02x ^ (hlcode(v[%d]) << 3))' % (vvvv, ops.index(item.vvvv))) 412 else: 413 buf.append('m.emit(0x%02x)' % vvvv) 414 byte = item.b << 4 415 parts = [] 416 if isinstance(item.z, x86_64.Operand): 417 parts.append('(zcode(v[%d]) << 7)' % ops.index(item.z)) 418 else: 419 byte |= item.z << 7 420 if isinstance(item.LL, x86_64.Operand): 421 parts.append('(vcode(v[%d]) << 5)' % ops.index(item.LL)) 422 else: 423 byte |= item.LL << 5 424 if isinstance(item.V, x86_64.Operand): 425 parts.append('(0x08 ^ (ecode(v[%d]) << 3))' % ops.index(item.V)) 426 else: 427 byte |= (item.V ^ 1) << 3 428 if isinstance(item.aaa, x86_64.Operand): 429 parts.append('kcode(v[%d])' % ops.index(item.aaa)) 430 parts.append('0x%02x' % byte) 431 buf.append('m.emit(%s)' % ' | '.join(parts)) 432 elif isinstance(item, x86_64.Opcode): 433 if not item.addend: 434 buf.append('m.emit(0x%02x)' % item.byte) 435 else: 436 buf.append('m.emit(0x%02x | lcode(v[%d]))' % (item.byte, ops.index(item.addend))) 437 elif isinstance(item, x86_64.ModRM): 438 if isinstance(item.mode, x86_64.Operand): 439 if isinstance(item.reg, x86_64.Operand): 440 reg = 'lcode(v[%d])' % ops.index(item.reg) 441 else: 442 reg = str(item.reg) 443 if disp8v is None: 444 disp = 1 445 else: 446 disp = disp8v 447 buf.append('m.mrsd(%s, addr(v[%d]), %d)' % (reg, ops.index(item.rm), disp)) 448 else: 449 mod = item.mode << 6 450 parts = [] 451 if isinstance(item.reg, x86_64.Operand): 452 parts.append('lcode(v[%d]) << 3' % ops.index(item.reg)) 453 elif item.reg: 454 mod |= item.reg << 3 455 parts.append('lcode(v[%d])' % ops.index(item.rm)) 456 buf.append('m.emit(%s)' % ' | '.join(['0x%02x' % mod] + parts)) 457 elif isinstance(item, x86_64.Immediate): 458 if isinstance(item.value, x86_64.Operand): 459 if item.size == 1: 460 buf.append('m.imm1(toImmAny(v[%d]))' % ops.index(item.value)) 461 elif item.size == 2: 462 buf.append('m.imm2(toImmAny(v[%d]))' % ops.index(item.value)) 463 elif item.size == 4: 464 buf.append('m.imm4(toImmAny(v[%d]))' % ops.index(item.value)) 465 elif item.size == 8: 466 buf.append('m.imm8(toImmAny(v[%d]))' % ops.index(item.value)) 467 else: 468 raise RuntimeError('invalid imm size: ' + str(item.size)) 469 else: 470 if item.size == 1: 471 buf.append('m.imm1(0x%02x)' % item.value) 472 elif item.size == 2: 473 buf.append('m.imm2(0x%04x)' % item.value) 474 elif item.size == 4: 475 buf.append('m.imm4(0x%08x)' % item.value) 476 elif item.size == 8: 477 buf.append('m.imm8(0x%016x)' % item.value) 478 else: 479 raise RuntimeError('invalid imm size: ' + str(item.size)) 480 elif isinstance(item, x86_64.RegisterByte): 481 ibr = 'hlcode(v[%d]) << 4' % ops.index(item.register) 482 if item.payload is not None: 483 ibr = '(%s) | imml(v[%d])' % (ibr, ops.index(item.payload)) 484 buf.append('m.emit(%s)' % ibr) 485 elif isinstance(item, x86_64.CodeOffset): 486 if item.size == 1: 487 buf.append('m.imm1(relv(v[%d]))' % ops.index(item.value)) 488 if gen_branch: 489 flags.append('_F_rel1') 490 elif item.size == 4: 491 buf.append('m.imm4(relv(v[%d]))' % ops.index(item.value)) 492 if gen_branch: 493 flags.append('_F_rel4') 494 else: 495 raise RuntimeError('invalid code offset size: ' + repr(item.size)) 496 else: 497 raise RuntimeError('unknown encoding component: ' + repr(item)) 498 if not flags: 499 return '0', buf 500 else: 501 return ' | '.join(flags), buf 502 503 class CodeGen: 504 def __init__(self): 505 self.buf = [] 506 self.level = 0 507 508 @property 509 def src(self) -> str: 510 return '\n'.join(self.buf) 511 512 def line(self, src: str = ''): 513 self.buf.append(' ' * (self.level * 4) + src) 514 515 def dedent(self): 516 self.level -= 1 517 518 def indent(self): 519 self.level += 1 520 521 class CodeBlock: 522 def __init__(self, gen: CodeGen): 523 self.gen = gen 524 525 def __exit__(self, *_): 526 self.gen.dedent() 527 528 def __enter__(self): 529 self.gen.indent() 530 return self 531 532 cc = CodeGen() 533 cc.line('// Code generated by "mkasm_amd64.py", DO NOT EDIT.') 534 cc.line() 535 cc.line('package x86_64') 536 cc.line() 537 538 nargs = 0 539 nforms = 0 540 argsmap = {} 541 for name, (_, _, forms) in instrs.items(): 542 fcnt = 0 543 for form in forms: 544 acnt = len(form.operands) 545 fcnt += len(form.encodings) 546 argsmap.setdefault(name, set()).add(acnt) 547 if nargs < acnt: 548 nargs = acnt 549 if nforms < fcnt: 550 nforms = fcnt 551 552 cc.line('const (') 553 with CodeBlock(cc): 554 cc.line('_N_args = %d' % nargs) 555 cc.line('_N_forms = %d' % nforms) 556 cc.line(')') 557 cc.line() 558 cc.line('// Instructions maps all the instruction name to it\'s encoder function.') 559 cc.line('var Instructions = map[string]_InstructionEncoder {') 560 561 width = max( 562 len(x) 563 for x in instrs 564 ) 565 566 with CodeBlock(cc): 567 for name in sorted(instrs): 568 key = '"%s"' % name.lower() 569 cc.line('%s: __asm_proxy_%s__,' % (key.ljust(width + 3), name)) 570 571 cc.line('}') 572 cc.line() 573 574 for name in sorted(instrs): 575 cc.line('func __asm_proxy_%s__(p *Program, v ...interface{}) *Instruction {' % name) 576 with CodeBlock(cc): 577 args = argsmap[name] 578 if len(args) == 1: 579 argc = next(iter(args)) 580 cc.line('if len(v) == %d {' % argc) 581 with CodeBlock(cc): 582 argv = ['v[%d]' % i for i in range(argc)] 583 cc.line('return p.%s(%s)' % (name, ', '.join(argv))) 584 cc.line('} else {') 585 with CodeBlock(cc): 586 if argc == 0: 587 cc.line('panic("instruction %s takes no operands")' % name) 588 elif argc == 1: 589 cc.line('panic("instruction %s takes exactly 1 operand")' % name) 590 else: 591 cc.line('panic("instruction %s takes exactly %d operands")' % (name, argc)) 592 cc.line('}') 593 else: 594 cc.line('switch len(v) {') 595 with CodeBlock(cc): 596 for argc in sorted(args): 597 argv = ['v[%d]' % i for i in range(argc)] 598 cc.line('case %d : return p.%s(%s)' % (argc, name, ', '.join(argv))) 599 cc.line('default : panic("instruction %s takes %s operands")' % (name, ' or '.join(map(str, sorted(args))))) 600 cc.line('}') 601 cc.line('}') 602 cc.line() 603 604 with open('x86_64/instructions_table.go', 'w') as fp: 605 fp.write(cc.src) 606 607 cc = CodeGen() 608 cc.line('// Code generated by "mkasm_amd64.py", DO NOT EDIT.') 609 cc.line() 610 cc.line('package x86_64') 611 cc.line() 612 613 for name, (ins, desc, forms) in sorted(instrs.items()): 614 cc.line('// %s performs "%s".' % (name, desc)) 615 cc.line('//') 616 cc.line('// Mnemonic : ' + ins) 617 cc.line('// Supported forms : (%d form%s)' % (len(forms), '' if len(forms) == 1 else 's')) 618 cc.line('//') 619 nops = set() 620 fwidth = max(map(len, map(dump_form, forms))) 621 for form in forms: 622 nops.add(len(form.operands)) 623 if not form.isa_extensions: 624 cc.line('// * ' + dump_form(form)) 625 else: 626 cc.line('// * %-*s [%s]' % (fwidth, dump_form(form), ','.join(sorted(v.name for v in form.isa_extensions)))) 627 nfix = min(nops) 628 args = ['v%d interface{}' % i for i in range(nfix)] 629 if len(nops) != 1: 630 args.append('vv ...interface{}') 631 cc.line('//') 632 cc.line('func (self *Program) %s(%s) *Instruction {' % (name, ', '.join(args))) 633 with CodeBlock(cc): 634 base = ['v%d' % i for i in range(nfix)] 635 if len(nops) == 1: 636 cc.line('p := self.alloc("%s", %d, Operands { %s })' % (name, nfix, ', '.join(base))) 637 else: 638 cc.line('var p *Instruction') 639 cc.line('switch len(vv) {') 640 with CodeBlock(cc): 641 for argc in sorted(nops): 642 args = base[:] + ['vv[%d]' % i for i in range(argc - nfix)] 643 cc.line('case %d : p = self.alloc("%s", %d, Operands { %s })' % (argc - nfix, name, argc, ', '.join(args))) 644 cc.line('default : panic("instruction %s takes %s operands")' % (name, ' or '.join(map(str, sorted(nops))))) 645 cc.line('}') 646 if name == 'JMP': 647 cc.line('p.branch = _B_unconditional') 648 elif name in BRANCH_INSTRUCTIONS: 649 cc.line('p.branch = _B_conditional') 650 is_labeled = False 651 must_success = False 652 for form in forms: 653 ops = list(reversed(form.operands)) 654 if len(ops) == 1 and ops[0].type in ('rel8', 'rel32'): 655 is_labeled = True 656 conds = [] 657 cc.line('// ' + dump_form(form)) 658 if len(nops) != 1: 659 conds.append('len(vv) == %d' % (len(ops) - nfix)) 660 conds.extend(operand_match(ops, nfix, is_avx512(form))) 661 if conds: 662 cc.line('if %s {' % ' && '.join(conds)) 663 cc.indent() 664 else: 665 must_success = True 666 if form.isa_extensions: 667 cc.line('self.require(%s)' % require_isa(form.isa_extensions)) 668 cc.line('p.domain = ' + DOMAIN_MAP[domains.get(form.name, 'misc')]) 669 for enc in form.encodings: 670 flags, instr = generate_encoding(enc, ops, gen_branch = False) 671 cc.line('p.add(%s, func(m *_Encoding, v []interface{}) {' % flags) 672 with CodeBlock(cc): 673 for line in instr: 674 cc.line(line) 675 cc.line('})') 676 if conds: 677 cc.dedent() 678 cc.line('}') 679 if is_labeled: 680 cc.line('// %s label' % name) 681 cc.line('if isLabel(v0) {') 682 with CodeBlock(cc): 683 for form in forms: 684 ops = list(reversed(form.operands)) 685 for enc in form.encodings: 686 flags, instr = generate_encoding(enc, ops, gen_branch = True) 687 cc.line('p.add(%s, func(m *_Encoding, v []interface{}) {' % flags) 688 with CodeBlock(cc): 689 for line in instr: 690 cc.line(line) 691 cc.line('})') 692 cc.line('}') 693 if not must_success: 694 cc.line('if p.len == 0 {') 695 with CodeBlock(cc): 696 cc.line('panic("invalid operands for %s")' % name) 697 cc.line('}') 698 cc.line('return p') 699 cc.line('}') 700 cc.line() 701 702 with open('x86_64/instructions.go', 'w') as fp: 703 fp.write(cc.src)