...

Text file src/github.com/chenzhuoyu/iasm/mkasm_x86_64.py

Documentation: github.com/chenzhuoyu/iasm

     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