1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4import os
5import copy
6import json
7
8from typing import List
9from typing import Tuple
10from typing import Iterable
11from opcodes import x86_64
12
13def 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
31def 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
36instrs = {}
37domains = instruction_domains()
38
39for 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
47for _, _, forms in instrs.values():
48 forms.sort(key = lambda f: max([x.score for x in f.isa_extensions], default = 0))
49
50OPCHECKS = {
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
122IMMCHECKS = {
123 'imm8' : 'isImm8Ext(%s, %d)',
124 'imm32' : 'isImm32Ext(%s, %d)',
125}
126
127EVEXCHECKS = {
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
136VEXBYTES = {
137 'VEX': '0xc4',
138 'XOP': '0x8f',
139}
140
141ISAMAPPING = {
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
199DOMAIN_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
210BRANCH_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
230def is_avx512(form: x86_64.InstructionForm) -> bool:
231 return any(v.name.startswith('AVX512') for v in form.isa_extensions)
232
233def 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
239def 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
247def 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
260def 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
503class 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
521class 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
532cc = CodeGen()
533cc.line('// Code generated by "mkasm_amd64.py", DO NOT EDIT.')
534cc.line()
535cc.line('package x86_64')
536cc.line()
537
538nargs = 0
539nforms = 0
540argsmap = {}
541for 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
552cc.line('const (')
553with CodeBlock(cc):
554 cc.line('_N_args = %d' % nargs)
555 cc.line('_N_forms = %d' % nforms)
556cc.line(')')
557cc.line()
558cc.line('// Instructions maps all the instruction name to it\'s encoder function.')
559cc.line('var Instructions = map[string]_InstructionEncoder {')
560
561width = max(
562 len(x)
563 for x in instrs
564)
565
566with 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
571cc.line('}')
572cc.line()
573
574for 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
604with open('x86_64/instructions_table.go', 'w') as fp:
605 fp.write(cc.src)
606
607cc = CodeGen()
608cc.line('// Code generated by "mkasm_amd64.py", DO NOT EDIT.')
609cc.line()
610cc.line('package x86_64')
611cc.line()
612
613for 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
702with open('x86_64/instructions.go', 'w') as fp:
703 fp.write(cc.src)
View as plain text