From abb37a7cb8d4bfae2da6d2cb9e9e6305ef6e52c4 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 26 Mar 2023 21:33:56 -0400 Subject: x86_64: factor out lowering from emitting --- src/arch/x86_64/CodeGen.zig | 21 +- src/arch/x86_64/Emit.zig | 905 +++++----------------- src/arch/x86_64/Encoding.zig | 294 ++++---- src/arch/x86_64/Lower.zig | 465 ++++++++++++ src/arch/x86_64/Mir.zig | 19 +- src/arch/x86_64/bits.zig | 2 +- src/arch/x86_64/encoder.zig | 919 +++++++++++++---------- src/arch/x86_64/encodings.zig | 1669 +++++++++++++++++++++-------------------- 8 files changed, 2167 insertions(+), 2127 deletions(-) create mode 100644 src/arch/x86_64/Lower.zig diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b32d7ef214..5ab0e64615 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -341,19 +341,22 @@ pub fn generate( defer mir.deinit(bin_file.allocator); var emit = Emit{ - .mir = mir, + .lower = .{ + .allocator = bin_file.allocator, + .mir = mir, + .target = &bin_file.options.target, + .src_loc = src_loc, + }, .bin_file = bin_file, .debug_output = debug_output, - .target = &bin_file.options.target, - .src_loc = src_loc, .code = code, .prev_di_pc = 0, .prev_di_line = module_fn.lbrace_line, .prev_di_column = module_fn.lbrace_column, }; defer emit.deinit(); - emit.lowerMir() catch |err| switch (err) { - error.EmitFail => return Result{ .fail = emit.err_msg.? }, + emit.emitMir() catch |err| switch (err) { + error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? }, error.InvalidInstruction, error.CannotEncode => |e| { const msg = switch (e) { error.InvalidInstruction => "CodeGen failed to find a viable instruction.", @@ -7070,16 +7073,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void if (reg.to64() == .rax) { // If this is RAX, we can use a direct load. // Otherwise, we need to load the address, then indirectly load the value. - var moffs: Mir.MemoryMoffs = .{ - .seg = @enumToInt(Register.ds), - .msb = undefined, - .lsb = undefined, - }; - moffs.encodeOffset(x); _ = try self.addInst(.{ .tag = .mov_moffs, .ops = .rax_moffs, - .data = .{ .payload = try self.addExtra(moffs) }, + .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, x)) }, }); } else { // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue. diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index b65d22807a..052139a4e5 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -1,40 +1,8 @@ -//! This file contains the functionality for lowering x86_64 MIR into -//! machine code +//! This file contains the functionality for emitting x86_64 MIR as machine code -const Emit = @This(); - -const std = @import("std"); -const assert = std.debug.assert; -const bits = @import("bits.zig"); -const abi = @import("abi.zig"); -const encoder = @import("encoder.zig"); -const link = @import("../../link.zig"); -const log = std.log.scoped(.codegen); -const math = std.math; -const mem = std.mem; -const testing = std.testing; - -const Air = @import("../../Air.zig"); -const Allocator = mem.Allocator; -const CodeGen = @import("CodeGen.zig"); -const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; -const Encoder = bits.Encoder; -const ErrorMsg = Module.ErrorMsg; -const Immediate = bits.Immediate; -const Instruction = encoder.Instruction; -const MCValue = @import("CodeGen.zig").MCValue; -const Memory = bits.Memory; -const Mir = @import("Mir.zig"); -const Module = @import("../../Module.zig"); -const Register = bits.Register; -const Type = @import("../../type.zig").Type; - -mir: Mir, +lower: Lower, bin_file: *link.File, debug_output: DebugInfoOutput, -target: *const std.Target, -err_msg: ?*ErrorMsg = null, -src_loc: Module.SrcLoc, code: *std.ArrayList(u8), prev_di_line: u32, @@ -45,166 +13,176 @@ prev_di_pc: usize, code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{}, relocs: std.ArrayListUnmanaged(Reloc) = .{}, -const InnerError = error{ - OutOfMemory, - EmitFail, - InvalidInstruction, - CannotEncode, -}; - -const Reloc = struct { - /// Offset of the instruction. - source: usize, - /// Target of the relocation. - target: Mir.Inst.Index, - /// Offset of the relocation within the instruction. - offset: usize, - /// Length of the instruction. - length: u5, -}; - -pub fn lowerMir(emit: *Emit) InnerError!void { - const mir_tags = emit.mir.instructions.items(.tag); - - for (mir_tags, 0..) |tag, index| { - const inst = @intCast(u32, index); - try emit.code_offset_mapping.putNoClobber(emit.bin_file.allocator, inst, emit.code.items.len); - switch (tag) { - .adc, - .add, - .@"and", - .bsf, - .bsr, - .bswap, - .bt, - .btc, - .btr, - .bts, - .call, - .cbw, - .cwde, - .cdqe, - .cwd, - .cdq, - .cqo, - .cmp, - .cmpxchg, - .div, - .fisttp, - .fld, - .idiv, - .imul, - .int3, - .jmp, - .lea, - .lfence, - .lzcnt, - .mfence, - .mov, - .movbe, - .movzx, - .mul, - .neg, - .nop, - .not, - .@"or", - .pop, - .popcnt, - .push, - .rcl, - .rcr, - .ret, - .rol, - .ror, - .sal, - .sar, - .sbb, - .sfence, - .shl, - .shld, - .shr, - .shrd, - .sub, - .syscall, - .@"test", - .tzcnt, - .ud2, - .xadd, - .xchg, - .xor, - - .addss, - .cmpss, - .divss, - .maxss, - .minss, - .movss, - .mulss, - .roundss, - .subss, - .ucomiss, - .addsd, - .cmpsd, - .divsd, - .maxsd, - .minsd, - .movsd, - .mulsd, - .roundsd, - .subsd, - .ucomisd, - => try emit.mirEncodeGeneric(tag, inst), - - .cmps, - .lods, - .movs, - .scas, - .stos, - => try emit.mirString(tag, inst), - - .cmpxchgb => try emit.mirCmpxchgBytes(inst), - - .jmp_reloc => try emit.mirJmpReloc(inst), - - .call_extern => try emit.mirCallExtern(inst), - - .lea_linker => try emit.mirLeaLinker(inst), - - .mov_moffs => try emit.mirMovMoffs(inst), - - .movsx => try emit.mirMovsx(inst), - .cmovcc => try emit.mirCmovcc(inst), - .setcc => try emit.mirSetcc(inst), - .jcc => try emit.mirJcc(inst), +pub const Error = Lower.Error || error{EmitFail}; + +pub fn emitMir(emit: *Emit) Error!void { + for (0..emit.lower.mir.instructions.len) |i| { + const index = @intCast(Mir.Inst.Index, i); + const inst = emit.lower.mir.instructions.get(index); + + const start_offset = @intCast(u32, emit.code.items.len); + try emit.code_offset_mapping.putNoClobber(emit.lower.allocator, index, start_offset); + for (try emit.lower.lowerMir(inst)) |lower_inst| try lower_inst.encode(emit.code.writer()); + const end_offset = @intCast(u32, emit.code.items.len); + + switch (inst.tag) { + else => {}, + + .jmp_reloc => try emit.relocs.append(emit.lower.allocator, .{ + .source = start_offset, + .target = inst.data.inst, + .offset = end_offset - 4, + .length = 5, + }), + + .call_extern => if (emit.bin_file.cast(link.File.MachO)) |macho_file| { + // Add relocation to the decl. + const atom_index = macho_file.getAtomIndexForSymbol( + .{ .sym_index = inst.data.relocation.atom_index, .file = null }, + ).?; + const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index); + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ + .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), + .target = target, + .offset = end_offset - 4, + .addend = 0, + .pcrel = true, + .length = 2, + }); + } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { + // Add relocation to the decl. + const atom_index = coff_file.getAtomIndexForSymbol( + .{ .sym_index = inst.data.relocation.atom_index, .file = null }, + ).?; + const target = coff_file.getGlobalByIndex(inst.data.relocation.sym_index); + try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ + .type = .direct, + .target = target, + .offset = end_offset - 4, + .addend = 0, + .pcrel = true, + .length = 2, + }); + } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }), + + .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| { + const metadata = + emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data; + const reloc_type = switch (inst.ops) { + .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT), + .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), + else => unreachable, + }; + const atom_index = macho_file.getAtomIndexForSymbol(.{ + .sym_index = metadata.atom_index, + .file = null, + }).?; + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ + .type = reloc_type, + .target = .{ .sym_index = metadata.sym_index, .file = null }, + .offset = @intCast(u32, end_offset - 4), + .addend = 0, + .pcrel = true, + .length = 2, + }); + } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { + const metadata = + emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data; + const atom_index = coff_file.getAtomIndexForSymbol(.{ + .sym_index = metadata.atom_index, + .file = null, + }).?; + try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ + .type = switch (inst.ops) { + .got_reloc => .got, + .direct_reloc => .direct, + .import_reloc => .import, + else => unreachable, + }, + .target = switch (inst.ops) { + .got_reloc, + .direct_reloc, + => .{ .sym_index = metadata.sym_index, .file = null }, + .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index), + else => unreachable, + }, + .offset = @intCast(u32, end_offset - 4), + .addend = 0, + .pcrel = true, + .length = 2, + }); + } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }), + + .jcc => try emit.relocs.append(emit.lower.allocator, .{ + .source = start_offset, + .target = inst.data.inst_cc.inst, + .offset = end_offset - 4, + .length = 6, + }), - .dbg_line => try emit.mirDbgLine(inst), - .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst), - .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst), + .dbg_line => { + const dbg_line_column = + emit.lower.mir.extraData(Mir.DbgLineColumn, inst.data.payload).data; + try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column); + }, - .push_regs => try emit.mirPushPopRegisterList(.push, inst), - .pop_regs => try emit.mirPushPopRegisterList(.pop, inst), + .dbg_prologue_end => { + switch (emit.debug_output) { + .dwarf => |dw| { + try dw.setPrologueEnd(); + log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ + emit.prev_di_line, emit.prev_di_column, + }); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); + }, + .plan9 => {}, + .none => {}, + } + }, - .dead => {}, + .dbg_epilogue_begin => { + switch (emit.debug_output) { + .dwarf => |dw| { + try dw.setEpilogueBegin(); + log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ + emit.prev_di_line, emit.prev_di_column, + }); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); + }, + .plan9 => {}, + .none => {}, + } + }, } } - try emit.fixupRelocs(); } pub fn deinit(emit: *Emit) void { - emit.relocs.deinit(emit.bin_file.allocator); - emit.code_offset_mapping.deinit(emit.bin_file.allocator); + emit.relocs.deinit(emit.lower.allocator); + emit.code_offset_mapping.deinit(emit.lower.allocator); emit.* = undefined; } -fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { - @setCold(true); - assert(emit.err_msg == null); - emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); - return error.EmitFail; +fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error { + return switch (emit.lower.fail(format, args)) { + error.LowerFail => error.EmitFail, + else => |e| e, + }; } -fn fixupRelocs(emit: *Emit) InnerError!void { +const Reloc = struct { + /// Offset of the instruction. + source: usize, + /// Target of the relocation. + target: Mir.Inst.Index, + /// Offset of the relocation within the instruction. + offset: usize, + /// Length of the instruction. + length: u5, +}; + +fn fixupRelocs(emit: *Emit) Error!void { // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size. // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest // possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution @@ -217,532 +195,7 @@ fn fixupRelocs(emit: *Emit) InnerError!void { } } -fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: Instruction.Init) InnerError!void { - const inst = try Instruction.new(mnemonic, ops); - return inst.encode(emit.code.writer()); -} - -fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { - const mnemonic = inline for (@typeInfo(Instruction.Mnemonic).Enum.fields) |field| { - if (mem.eql(u8, field.name, @tagName(tag))) break @field(Instruction.Mnemonic, field.name); - } else unreachable; - - const ops = emit.mir.instructions.items(.ops)[inst]; - const data = emit.mir.instructions.items(.data)[inst]; - - const prefix: Instruction.Prefix = switch (ops) { - .lock_m_sib, - .lock_m_rip, - .lock_mi_sib_u, - .lock_mi_rip_u, - .lock_mi_sib_s, - .lock_mi_rip_s, - .lock_mr_sib, - .lock_mr_rip, - .lock_moffs_rax, - => .lock, - else => .none, - }; - - var op1: Instruction.Operand = .none; - var op2: Instruction.Operand = .none; - var op3: Instruction.Operand = .none; - var op4: Instruction.Operand = .none; - - switch (ops) { - .none => {}, - .i_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.i)) }, - .i_u => op1 = .{ .imm = Immediate.u(data.i) }, - .r => op1 = .{ .reg = data.r }, - .rr => { - op1 = .{ .reg = data.rr.r1 }; - op2 = .{ .reg = data.rr.r2 }; - }, - .rrr => { - op1 = .{ .reg = data.rrr.r1 }; - op2 = .{ .reg = data.rrr.r2 }; - op3 = .{ .reg = data.rrr.r3 }; - }, - .ri_s, .ri_u => { - const imm = switch (ops) { - .ri_s => Immediate.s(@bitCast(i32, data.ri.i)), - .ri_u => Immediate.u(data.ri.i), - else => unreachable, - }; - op1 = .{ .reg = data.ri.r }; - op2 = .{ .imm = imm }; - }, - .ri64 => { - const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data; - op1 = .{ .reg = data.rx.r }; - op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) }; - }, - .rri_s, .rri_u => { - const imm = switch (ops) { - .rri_s => Immediate.s(@bitCast(i32, data.rri.i)), - .rri_u => Immediate.u(data.rri.i), - else => unreachable, - }; - op1 = .{ .reg = data.rri.r1 }; - op2 = .{ .reg = data.rri.r2 }; - op3 = .{ .imm = imm }; - }, - .m_sib, .lock_m_sib => { - const msib = emit.mir.extraData(Mir.MemorySib, data.payload).data; - op1 = .{ .mem = Mir.MemorySib.decode(msib) }; - }, - .m_rip, .lock_m_rip => { - const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data; - op1 = .{ .mem = Mir.MemoryRip.decode(mrip) }; - }, - .mi_sib_s, .mi_sib_u, .lock_mi_sib_s, .lock_mi_sib_u => { - const msib = emit.mir.extraData(Mir.MemorySib, data.ix.payload).data; - const imm = switch (ops) { - .mi_sib_s, .lock_mi_sib_s => Immediate.s(@bitCast(i32, data.ix.i)), - .mi_sib_u, .lock_mi_sib_u => Immediate.u(data.ix.i), - else => unreachable, - }; - op1 = .{ .mem = Mir.MemorySib.decode(msib) }; - op2 = .{ .imm = imm }; - }, - .mi_rip_u, .mi_rip_s, .lock_mi_rip_u, .lock_mi_rip_s => { - const mrip = emit.mir.extraData(Mir.MemoryRip, data.ix.payload).data; - const imm = switch (ops) { - .mi_rip_s, .lock_mi_rip_s => Immediate.s(@bitCast(i32, data.ix.i)), - .mi_rip_u, .lock_mi_rip_u => Immediate.u(data.ix.i), - else => unreachable, - }; - op1 = .{ .mem = Mir.MemoryRip.decode(mrip) }; - op2 = .{ .imm = imm }; - }, - .rm_sib, .mr_sib, .lock_mr_sib => { - const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data; - const op_r = .{ .reg = data.rx.r }; - const op_m = .{ .mem = Mir.MemorySib.decode(msib) }; - switch (ops) { - .rm_sib => { - op1 = op_r; - op2 = op_m; - }, - .mr_sib, .lock_mr_sib => { - op1 = op_m; - op2 = op_r; - }, - else => unreachable, - } - }, - .rm_rip, .mr_rip, .lock_mr_rip => { - const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data; - const op_r = .{ .reg = data.rx.r }; - const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) }; - switch (ops) { - .rm_rip => { - op1 = op_r; - op2 = op_m; - }, - .mr_rip, .lock_mr_rip => { - op1 = op_m; - op2 = op_r; - }, - else => unreachable, - } - }, - .mrr_sib => { - const msib = emit.mir.extraData(Mir.MemorySib, data.rrx.payload).data; - op1 = .{ .mem = Mir.MemorySib.decode(msib) }; - op2 = .{ .reg = data.rrx.r1 }; - op2 = .{ .reg = data.rrx.r2 }; - }, - .mrr_rip => { - const mrip = emit.mir.extraData(Mir.MemoryRip, data.rrx.payload).data; - op1 = .{ .mem = Mir.MemoryRip.decode(mrip) }; - op2 = .{ .reg = data.rrx.r1 }; - op2 = .{ .reg = data.rrx.r2 }; - }, - .mri_sib => { - const msib = emit.mir.extraData(Mir.MemorySib, data.rix.payload).data; - op1 = .{ .mem = Mir.MemorySib.decode(msib) }; - op2 = .{ .reg = data.rix.r }; - op3 = .{ .imm = Immediate.u(data.rix.i) }; - }, - .mri_rip => { - const mrip = emit.mir.extraData(Mir.MemoryRip, data.rix.payload).data; - op1 = .{ .mem = Mir.MemoryRip.decode(mrip) }; - op2 = .{ .reg = data.rix.r }; - op3 = .{ .imm = Immediate.u(data.rix.i) }; - }, - else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{ - @tagName(mnemonic), - @tagName(ops), - }), - } - - return emit.encode(mnemonic, .{ - .prefix = prefix, - .op1 = op1, - .op2 = op2, - .op3 = op3, - .op4 = op4, - }); -} - -fn mirString(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - switch (ops) { - .string => { - const data = emit.mir.instructions.items(.data)[inst].string; - const mnemonic = switch (tag) { - inline .cmps, .lods, .movs, .scas, .stos => |comptime_tag| switch (data.width) { - inline else => |comptime_width| @field( - Instruction.Mnemonic, - @tagName(comptime_tag) ++ @tagName(comptime_width), - ), - }, - else => unreachable, - }; - return emit.encode(mnemonic, .{ .prefix = switch (data.repeat) { - inline else => |comptime_repeat| @field(Instruction.Prefix, @tagName(comptime_repeat)), - } }); - }, - else => unreachable, - } -} - -fn mirCmpxchgBytes(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - const data = emit.mir.instructions.items(.data)[inst]; - - var op1: Instruction.Operand = .none; - switch (ops) { - .m_sib, .lock_m_sib => { - const sib = emit.mir.extraData(Mir.MemorySib, data.payload).data; - op1 = .{ .mem = Mir.MemorySib.decode(sib) }; - }, - .m_rip, .lock_m_rip => { - const rip = emit.mir.extraData(Mir.MemoryRip, data.payload).data; - op1 = .{ .mem = Mir.MemoryRip.decode(rip) }; - }, - else => unreachable, - } - - const mnemonic: Instruction.Mnemonic = switch (op1.mem.bitSize()) { - 64 => .cmpxchg8b, - 128 => .cmpxchg16b, - else => unreachable, - }; - - return emit.encode(mnemonic, .{ - .prefix = switch (ops) { - .m_sib, .m_rip => .none, - .lock_m_sib, .lock_m_rip => .lock, - else => unreachable, - }, - .op1 = op1, - }); -} - -fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - const payload = emit.mir.instructions.items(.data)[inst].payload; - const moffs = emit.mir.extraData(Mir.MemoryMoffs, payload).data; - const seg = @intToEnum(Register, moffs.seg); - const offset = moffs.decodeOffset(); - switch (ops) { - .rax_moffs => { - try emit.encode(.mov, .{ - .op1 = .{ .reg = .rax }, - .op2 = .{ .mem = Memory.moffs(seg, offset) }, - }); - }, - .moffs_rax, .lock_moffs_rax => { - try emit.encode(.mov, .{ - .prefix = switch (ops) { - .moffs_rax => .none, - .lock_moffs_rax => .lock, - else => unreachable, - }, - .op1 = .{ .mem = Memory.moffs(seg, offset) }, - .op2 = .{ .reg = .rax }, - }); - }, - else => unreachable, - } -} - -fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - const data = emit.mir.instructions.items(.data)[inst]; - - var op1: Instruction.Operand = .none; - var op2: Instruction.Operand = .none; - switch (ops) { - .rr => { - op1 = .{ .reg = data.rr.r1 }; - op2 = .{ .reg = data.rr.r2 }; - }, - .rm_sib => { - const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data; - op1 = .{ .reg = data.rx.r }; - op2 = .{ .mem = Mir.MemorySib.decode(msib) }; - }, - .rm_rip => { - const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data; - op1 = .{ .reg = data.rx.r }; - op2 = .{ .mem = Mir.MemoryRip.decode(mrip) }; - }, - else => unreachable, // TODO - } - - const mnemonic: Instruction.Mnemonic = switch (op1.bitSize()) { - 32, 64 => if (op2.bitSize() == 32) .movsxd else .movsx, - else => .movsx, - }; - - return emit.encode(mnemonic, .{ - .op1 = op1, - .op2 = op2, - }); -} - -fn mnemonicFromConditionCode(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic { - return switch (cc) { - inline else => |comptime_cc| @field(Instruction.Mnemonic, basename ++ @tagName(comptime_cc)), - }; -} - -fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - switch (ops) { - .rr_cc => { - const data = emit.mir.instructions.items(.data)[inst].rr_cc; - const mnemonic = mnemonicFromConditionCode("cmov", data.cc); - return emit.encode(mnemonic, .{ - .op1 = .{ .reg = data.r1 }, - .op2 = .{ .reg = data.r2 }, - }); - }, - .rm_sib_cc => { - const data = emit.mir.instructions.items(.data)[inst].rx_cc; - const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data; - const mnemonic = mnemonicFromConditionCode("cmov", data.cc); - return emit.encode(mnemonic, .{ - .op1 = .{ .reg = data.r }, - .op2 = .{ .mem = Mir.MemorySib.decode(extra) }, - }); - }, - .rm_rip_cc => { - const data = emit.mir.instructions.items(.data)[inst].rx_cc; - const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data; - const mnemonic = mnemonicFromConditionCode("cmov", data.cc); - return emit.encode(mnemonic, .{ - .op1 = .{ .reg = data.r }, - .op2 = .{ .mem = Mir.MemoryRip.decode(extra) }, - }); - }, - else => unreachable, - } -} - -fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - switch (ops) { - .r_cc => { - const data = emit.mir.instructions.items(.data)[inst].r_cc; - const mnemonic = mnemonicFromConditionCode("set", data.cc); - return emit.encode(mnemonic, .{ - .op1 = .{ .reg = data.r }, - }); - }, - .m_sib_cc => { - const data = emit.mir.instructions.items(.data)[inst].x_cc; - const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data; - const mnemonic = mnemonicFromConditionCode("set", data.cc); - return emit.encode(mnemonic, .{ - .op1 = .{ .mem = Mir.MemorySib.decode(extra) }, - }); - }, - .m_rip_cc => { - const data = emit.mir.instructions.items(.data)[inst].x_cc; - const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data; - const mnemonic = mnemonicFromConditionCode("set", data.cc); - return emit.encode(mnemonic, .{ - .op1 = .{ .mem = Mir.MemoryRip.decode(extra) }, - }); - }, - else => unreachable, // TODO - } -} - -fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - switch (ops) { - .inst_cc => { - const data = emit.mir.instructions.items(.data)[inst].inst_cc; - const mnemonic = mnemonicFromConditionCode("j", data.cc); - const source = emit.code.items.len; - try emit.encode(mnemonic, .{ - .op1 = .{ .imm = Immediate.s(0) }, - }); - try emit.relocs.append(emit.bin_file.allocator, .{ - .source = source, - .target = data.inst, - .offset = emit.code.items.len - 4, - .length = 6, - }); - }, - else => unreachable, // TODO - } -} - -fn mirJmpReloc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const target = emit.mir.instructions.items(.data)[inst].inst; - const source = emit.code.items.len; - try emit.encode(.jmp, .{ - .op1 = .{ .imm = Immediate.s(0) }, - }); - try emit.relocs.append(emit.bin_file.allocator, .{ - .source = source, - .target = target, - .offset = emit.code.items.len - 4, - .length = 5, - }); -} - -fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const relocation = emit.mir.instructions.items(.data)[inst].relocation; - - const offset = blk: { - try emit.encode(.call, .{ - .op1 = .{ .imm = Immediate.s(0) }, - }); - break :blk @intCast(u32, emit.code.items.len) - 4; - }; - - if (emit.bin_file.cast(link.File.MachO)) |macho_file| { - // Add relocation to the decl. - const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; - const target = macho_file.getGlobalByIndex(relocation.sym_index); - try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ - .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), - .target = target, - .offset = offset, - .addend = 0, - .pcrel = true, - .length = 2, - }); - } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { - // Add relocation to the decl. - const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; - const target = coff_file.getGlobalByIndex(relocation.sym_index); - try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ - .type = .direct, - .target = target, - .offset = offset, - .addend = 0, - .pcrel = true, - .length = 2, - }); - } else { - return emit.fail("TODO implement call_extern for linking backends different than MachO and COFF", .{}); - } -} - -fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { - const payload = emit.mir.instructions.items(.data)[inst].payload; - const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data; - const base = @intToEnum(Register, save_reg_list.base_reg); - var disp: i32 = -@intCast(i32, save_reg_list.stack_end); - const reg_list = Mir.RegisterList.fromInt(save_reg_list.register_list); - const callee_preserved_regs = abi.getCalleePreservedRegs(emit.target.*); - for (callee_preserved_regs) |reg| { - if (reg_list.isSet(callee_preserved_regs, reg)) { - const op1: Instruction.Operand = .{ .mem = Memory.sib(.qword, .{ - .base = base, - .disp = disp, - }) }; - const op2: Instruction.Operand = .{ .reg = reg }; - switch (tag) { - .push => try emit.encode(.mov, .{ - .op1 = op1, - .op2 = op2, - }), - .pop => try emit.encode(.mov, .{ - .op1 = op2, - .op2 = op1, - }), - else => unreachable, - } - disp += 8; - } - } -} - -fn mirLeaLinker(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const ops = emit.mir.instructions.items(.ops)[inst]; - const payload = emit.mir.instructions.items(.data)[inst].payload; - const metadata = emit.mir.extraData(Mir.LeaRegisterReloc, payload).data; - const reg = @intToEnum(Register, metadata.reg); - - try emit.encode(.lea, .{ - .op1 = .{ .reg = reg }, - .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, - }); - - const end_offset = emit.code.items.len; - - if (emit.bin_file.cast(link.File.MachO)) |macho_file| { - const reloc_type = switch (ops) { - .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT), - .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), - else => unreachable, - }; - const atom_index = macho_file.getAtomIndexForSymbol(.{ - .sym_index = metadata.atom_index, - .file = null, - }).?; - try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ - .type = reloc_type, - .target = .{ .sym_index = metadata.sym_index, .file = null }, - .offset = @intCast(u32, end_offset - 4), - .addend = 0, - .pcrel = true, - .length = 2, - }); - } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getAtomIndexForSymbol(.{ - .sym_index = metadata.atom_index, - .file = null, - }).?; - try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ - .type = switch (ops) { - .got_reloc => .got, - .direct_reloc => .direct, - .import_reloc => .import, - else => unreachable, - }, - .target = switch (ops) { - .got_reloc, .direct_reloc => .{ .sym_index = metadata.sym_index, .file = null }, - .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index), - else => unreachable, - }, - .offset = @intCast(u32, end_offset - 4), - .addend = 0, - .pcrel = true, - .length = 2, - }); - } else { - return emit.fail("TODO implement lea reg, [rip + reloc] for linking backends different than MachO", .{}); - } -} - -fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - const payload = emit.mir.instructions.items(.data)[inst].payload; - const dbg_line_column = emit.mir.extraData(Mir.DbgLineColumn, payload).data; - log.debug("mirDbgLine", .{}); - try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column); -} - -fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { +fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line); const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc }); @@ -756,7 +209,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes // we have already checked the target in the linker to make sure it is compatable - const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.target.cpu.arch) catch unreachable; + const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.lower.target.cpu.arch) catch unreachable; // increasing the line number try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line); @@ -792,34 +245,12 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { } } -fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - _ = inst; - switch (emit.debug_output) { - .dwarf => |dw| { - try dw.setPrologueEnd(); - log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ - emit.prev_di_line, - emit.prev_di_column, - }); - try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); - }, - .plan9 => {}, - .none => {}, - } -} +const link = @import("../../link.zig"); +const log = std.log.scoped(.emit); +const mem = std.mem; +const std = @import("std"); -fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { - _ = inst; - switch (emit.debug_output) { - .dwarf => |dw| { - try dw.setEpilogueBegin(); - log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ - emit.prev_di_line, - emit.prev_di_column, - }); - try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); - }, - .plan9 => {}, - .none => {}, - } -} +const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; +const Emit = @This(); +const Lower = @import("Lower.zig"); +const Mir = @import("Mir.zig"); diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index de669a9f8d..1361570405 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -7,30 +7,32 @@ const math = std.math; const bits = @import("bits.zig"); const encoder = @import("encoder.zig"); const Instruction = encoder.Instruction; +const Operand = Instruction.Operand; +const Prefix = Instruction.Prefix; const Register = bits.Register; const Rex = encoder.Rex; const LegacyPrefixes = encoder.LegacyPrefixes; -const table = @import("encodings.zig").table; - mnemonic: Mnemonic, -op_en: OpEn, -op1: Op, -op2: Op, -op3: Op, -op4: Op, -opc_len: u3, -opc: [7]u8, -modrm_ext: u3, -mode: Mode, - -pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding { - const input_op1 = Op.fromOperand(args.op1); - const input_op2 = Op.fromOperand(args.op2); - const input_op3 = Op.fromOperand(args.op3); - const input_op4 = Op.fromOperand(args.op4); - - const ops = &[_]Instruction.Operand{ args.op1, args.op2, args.op3, args.op4 }; +data: Data, + +const Data = struct { + op_en: OpEn, + ops: [4]Op, + opc_len: u3, + opc: [7]u8, + modrm_ext: u3, + mode: Mode, +}; + +pub fn findByMnemonic( + prefix: Instruction.Prefix, + mnemonic: Mnemonic, + ops: []const Instruction.Operand, +) !?Encoding { + var input_ops = [1]Op{.none} ** 4; + for (input_ops[0..ops.len], ops) |*input_op, op| input_op.* = Op.fromOperand(op); + const rex_required = for (ops) |op| switch (op) { .reg => |r| switch (r) { .spl, .bpl, .sil, .dil => break true, @@ -60,88 +62,29 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding { if ((rex_required or rex_extended) and rex_invalid) return error.CannotEncode; - // TODO work out what is the maximum number of variants we can actually find in one swoop. - var candidates: [10]Encoding = undefined; - var count: usize = 0; - for (table) |entry| { - var enc = Encoding{ - .mnemonic = entry[0], - .op_en = entry[1], - .op1 = entry[2], - .op2 = entry[3], - .op3 = entry[4], - .op4 = entry[5], - .opc_len = @intCast(u3, entry[6].len), - .opc = undefined, - .modrm_ext = entry[7], - .mode = entry[8], - }; - std.mem.copy(u8, &enc.opc, entry[6]); - if (enc.mnemonic == mnemonic and - input_op1.isSubset(enc.op1, enc.mode) and - input_op2.isSubset(enc.op2, enc.mode) and - input_op3.isSubset(enc.op3, enc.mode) and - input_op4.isSubset(enc.op4, enc.mode)) - { - if (rex_required) { - switch (enc.mode) { - .rex, .long => { - candidates[count] = enc; - count += 1; - }, - else => {}, - } - } else { - if (enc.mode != .rex) { - candidates[count] = enc; - count += 1; - } - } + var shortest_enc: ?Encoding = null; + var shortest_len: ?usize = null; + next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { + switch (data.mode) { + .rex => if (!rex_required) continue, + .long => {}, + else => if (rex_required) continue, } + for (input_ops, data.ops) |input_op, data_op| + if (!input_op.isSubset(data_op, data.mode)) continue :next; + + const enc = Encoding{ .mnemonic = mnemonic, .data = data }; + if (shortest_enc) |previous_shortest_enc| { + const len = estimateInstructionLength(prefix, enc, ops); + const previous_shortest_len = shortest_len orelse + estimateInstructionLength(prefix, previous_shortest_enc, ops); + if (len < previous_shortest_len) { + shortest_enc = enc; + shortest_len = len; + } else shortest_len = previous_shortest_len; + } else shortest_enc = enc; } - - if (count == 0) return null; - if (count == 1) return candidates[0]; - - const EncodingLength = struct { - fn estimate(encoding: Encoding, params: Instruction.Init) usize { - var inst = Instruction{ - .op1 = params.op1, - .op2 = params.op2, - .op3 = params.op3, - .op4 = params.op4, - .prefix = params.prefix, - .encoding = encoding, - }; - var cwriter = std.io.countingWriter(std.io.null_writer); - inst.encode(cwriter.writer()) catch unreachable; // Not allowed to fail here unless OOM. - return @intCast(usize, cwriter.bytes_written); - } - }; - - var shortest_encoding: ?struct { - index: usize, - len: usize, - } = null; - var i: usize = 0; - while (i < count) : (i += 1) { - const candidate = candidates[i]; - switch (candidate.mode) { - .long, .rex => if (rex_invalid) return error.CannotEncode, - else => {}, - } - - const len = EncodingLength.estimate(candidate, args); - const current = shortest_encoding orelse { - shortest_encoding = .{ .index = i, .len = len }; - continue; - }; - if (len < current.len) { - shortest_encoding = .{ .index = i, .len = len }; - } - } - - return candidates[shortest_encoding.?.index]; + return shortest_enc; } /// Returns first matching encoding by opcode. @@ -149,57 +92,45 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { legacy: LegacyPrefixes, rex: Rex, }, modrm_ext: ?u3) ?Encoding { - for (table) |entry| { - const enc = Encoding{ - .mnemonic = entry[0], - .op_en = entry[1], - .op1 = entry[2], - .op2 = entry[3], - .op3 = entry[4], - .op4 = entry[5], - .opc_len = entry[6], - .opc = .{ entry[7], entry[8], entry[9] }, - .modrm_ext = entry[10], - .mode = entry[11], - }; - const match = match: { - if (modrm_ext) |ext| { - break :match ext == enc.modrm_ext and std.mem.eql(u8, enc.opcode(), opc); + for (mnemonic_to_encodings_map, 0..) |encs, mnemonic_int| for (encs) |data| { + const enc = Encoding{ .mnemonic = @intToEnum(Mnemonic, mnemonic_int), .data = data }; + if (modrm_ext) |ext| if (ext != data.modrm_ext) continue; + if (!std.mem.eql(u8, opc, enc.opcode())) continue; + if (prefixes.rex.w) { + switch (data.mode) { + .short, .fpu, .sse, .sse2, .sse4_1, .none => continue, + .long, .rex => {}, } - break :match std.mem.eql(u8, enc.opcode(), opc); - }; - if (match) { - if (prefixes.rex.w) { - switch (enc.mode) { - .fpu, .sse, .sse2, .sse4_1, .none => {}, - .long, .rex => return enc, - } - } else if (prefixes.rex.present and !prefixes.rex.isSet()) { - if (enc.mode == .rex) return enc; - } else if (prefixes.legacy.prefix_66) { - switch (enc.operandBitSize()) { - 16 => return enc, + } else if (prefixes.rex.present and !prefixes.rex.isSet()) { + switch (data.mode) { + .rex => {}, + else => continue, + } + } else if (prefixes.legacy.prefix_66) { + switch (enc.operandBitSize()) { + 16 => {}, + else => continue, + } + } else { + switch (data.mode) { + .none => switch (enc.operandBitSize()) { + 16 => continue, else => {}, - } - } else { - if (enc.mode == .none) { - switch (enc.operandBitSize()) { - 16 => {}, - else => return enc, - } - } + }, + else => continue, } } - } + return enc; + }; return null; } pub fn opcode(encoding: *const Encoding) []const u8 { - return encoding.opc[0..encoding.opc_len]; + return encoding.data.opc[0..encoding.data.opc_len]; } pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 { - const prefix = encoding.opc[0]; + const prefix = encoding.data.opc[0]; return switch (prefix) { 0x66, 0xf2, 0xf3 => prefix, else => null, @@ -207,27 +138,27 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 { } pub fn modRmExt(encoding: Encoding) u3 { - return switch (encoding.op_en) { - .m, .mi, .m1, .mc => encoding.modrm_ext, + return switch (encoding.data.op_en) { + .m, .mi, .m1, .mc => encoding.data.modrm_ext, else => unreachable, }; } pub fn operandBitSize(encoding: Encoding) u64 { - switch (encoding.mode) { + switch (encoding.data.mode) { .short => return 16, .long => return 64, else => {}, } - const bit_size: u64 = switch (encoding.op_en) { - .np => switch (encoding.op1) { + const bit_size: u64 = switch (encoding.data.op_en) { + .np => switch (encoding.data.ops[0]) { .o16 => 16, .o32 => 32, .o64 => 64, else => 32, }, - .td => encoding.op2.bitSize(), - else => encoding.op1.bitSize(), + .td => encoding.data.ops[1].bitSize(), + else => encoding.data.ops[0].bitSize(), }; return bit_size; } @@ -240,7 +171,7 @@ pub fn format( ) !void { _ = options; _ = fmt; - switch (encoding.mode) { + switch (encoding.data.mode) { .long => try writer.writeAll("REX.W + "), else => {}, } @@ -249,10 +180,10 @@ pub fn format( try writer.print("{x:0>2} ", .{byte}); } - switch (encoding.op_en) { + switch (encoding.data.op_en) { .np, .fd, .td, .i, .zi, .d => {}, .o, .oi => { - const tag = switch (encoding.op1) { + const tag = switch (encoding.data.ops[0]) { .r8 => "rb", .r16 => "rw", .r32 => "rd", @@ -265,12 +196,12 @@ pub fn format( .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "), } - switch (encoding.op_en) { + switch (encoding.data.op_en) { .i, .d, .zi, .oi, .mi, .rmi, .mri => { - const op = switch (encoding.op_en) { - .i, .d => encoding.op1, - .zi, .oi, .mi => encoding.op2, - .rmi, .mri => encoding.op3, + const op = switch (encoding.data.op_en) { + .i, .d => encoding.data.ops[0], + .zi, .oi, .mi => encoding.data.ops[1], + .rmi, .mri => encoding.data.ops[2], else => unreachable, }; const tag = switch (op) { @@ -290,13 +221,12 @@ pub fn format( try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); - const ops = &[_]Op{ encoding.op1, encoding.op2, encoding.op3, encoding.op4 }; - for (ops) |op| switch (op) { + for (encoding.data.ops) |op| switch (op) { .none, .o16, .o32, .o64 => break, else => try writer.print("{s} ", .{@tagName(op)}), }; - const op_en = switch (encoding.op_en) { + const op_en = switch (encoding.data.op_en) { .zi => .i, else => |op_en| op_en, }; @@ -604,3 +534,53 @@ pub const Mode = enum { sse2, sse4_1, }; + +fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize { + var inst = Instruction{ + .prefix = prefix, + .encoding = encoding, + .ops = [1]Operand{.none} ** 4, + }; + std.mem.copy(Operand, &inst.ops, ops); + + var cwriter = std.io.countingWriter(std.io.null_writer); + inst.encode(cwriter.writer()) catch unreachable; // Not allowed to fail here unless OOM. + return @intCast(usize, cwriter.bytes_written); +} + +const mnemonic_to_encodings_map = init: { + @setEvalBranchQuota(100_000); + const encodings = @import("encodings.zig"); + var entries = encodings.table; + std.sort.sort(encodings.Entry, &entries, {}, struct { + fn lessThan(_: void, lhs: encodings.Entry, rhs: encodings.Entry) bool { + return @enumToInt(lhs[0]) < @enumToInt(rhs[0]); + } + }.lessThan); + var data_storage: [entries.len]Data = undefined; + var mnemonic_map: [@typeInfo(Mnemonic).Enum.fields.len][]const Data = undefined; + var mnemonic_int = 0; + var mnemonic_start = 0; + for (&data_storage, entries, 0..) |*data, entry, data_index| { + data.* = .{ + .op_en = entry[1], + .ops = undefined, + .opc_len = entry[3].len, + .opc = undefined, + .modrm_ext = entry[4], + .mode = entry[5], + }; + std.mem.copy(Op, &data.ops, entry[2]); + std.mem.copy(u8, &data.opc, entry[3]); + + while (mnemonic_int < @enumToInt(entry[0])) : (mnemonic_int += 1) { + mnemonic_map[mnemonic_int] = data_storage[mnemonic_start..data_index]; + mnemonic_start = data_index; + } + } + while (mnemonic_int < mnemonic_map.len) : (mnemonic_int += 1) { + mnemonic_map[mnemonic_int] = data_storage[mnemonic_start..]; + mnemonic_start = data_storage.len; + } + break :init mnemonic_map; +}; diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig new file mode 100644 index 0000000000..f4d9db57e8 --- /dev/null +++ b/src/arch/x86_64/Lower.zig @@ -0,0 +1,465 @@ +//! This file contains the functionality for lowering x86_64 MIR to Instructions + +allocator: Allocator, +mir: Mir, +target: *const std.Target, +err_msg: ?*ErrorMsg = null, +src_loc: Module.SrcLoc, +result: [ + std.mem.max(usize, &.{ + abi.Win64.callee_preserved_regs.len, + abi.SysV.callee_preserved_regs.len, + }) +]Instruction = undefined, +result_len: usize = undefined, + +pub const Error = error{ + OutOfMemory, + LowerFail, + InvalidInstruction, + CannotEncode, +}; + +/// The returned slice is overwritten by the next call to lowerMir. +pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { + lower.result = undefined; + errdefer lower.result = undefined; + lower.result_len = 0; + defer lower.result_len = undefined; + + switch (inst.tag) { + .adc, + .add, + .@"and", + .bsf, + .bsr, + .bswap, + .bt, + .btc, + .btr, + .bts, + .call, + .cbw, + .cwde, + .cdqe, + .cwd, + .cdq, + .cqo, + .cmp, + .cmpxchg, + .div, + .fisttp, + .fld, + .idiv, + .imul, + .int3, + .jmp, + .lea, + .lfence, + .lzcnt, + .mfence, + .mov, + .movbe, + .movzx, + .mul, + .neg, + .nop, + .not, + .@"or", + .pop, + .popcnt, + .push, + .rcl, + .rcr, + .ret, + .rol, + .ror, + .sal, + .sar, + .sbb, + .sfence, + .shl, + .shld, + .shr, + .shrd, + .sub, + .syscall, + .@"test", + .tzcnt, + .ud2, + .xadd, + .xchg, + .xor, + + .addss, + .cmpss, + .divss, + .maxss, + .minss, + .movss, + .mulss, + .roundss, + .subss, + .ucomiss, + .addsd, + .cmpsd, + .divsd, + .maxsd, + .minsd, + .movsd, + .mulsd, + .roundsd, + .subsd, + .ucomisd, + => try lower.mirGeneric(inst), + + .cmps, + .lods, + .movs, + .scas, + .stos, + => try lower.mirString(inst), + + .cmpxchgb => try lower.mirCmpxchgBytes(inst), + + .jmp_reloc => try lower.emit(.none, .jmp, &.{.{ .imm = Immediate.s(0) }}), + + .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}), + + .lea_linker => try lower.mirLeaLinker(inst), + + .mov_moffs => try lower.mirMovMoffs(inst), + + .movsx => try lower.mirMovsx(inst), + .cmovcc => try lower.mirCmovcc(inst), + .setcc => try lower.mirSetcc(inst), + .jcc => try lower.emit(.none, mnem_cc(.j, inst.data.inst_cc.cc), &.{.{ .imm = Immediate.s(0) }}), + + .push_regs, .pop_regs => try lower.mirPushPopRegisterList(inst), + + .dbg_line, + .dbg_prologue_end, + .dbg_epilogue_begin, + .dead, + => {}, + } + + return lower.result[0..lower.result_len]; +} + +pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error { + @setCold(true); + assert(lower.err_msg == null); + lower.err_msg = try ErrorMsg.create(lower.allocator, lower.src_loc, format, args); + return error.LowerFail; +} + +fn mnem_cc(comptime base: @Type(.EnumLiteral), cc: bits.Condition) Mnemonic { + return switch (cc) { + inline else => |c| @field(Mnemonic, @tagName(base) ++ @tagName(c)), + }; +} + +fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate { + return switch (ops) { + .rri_s, + .ri_s, + .i_s, + .mi_sib_s, + .mi_rip_s, + .lock_mi_sib_s, + .lock_mi_rip_s, + => Immediate.s(@bitCast(i32, i)), + + .rri_u, + .ri_u, + .i_u, + .mi_sib_u, + .mi_rip_u, + .lock_mi_sib_u, + .lock_mi_rip_u, + .mri_sib, + .mri_rip, + => Immediate.u(i), + + .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()), + + else => unreachable, + }; +} + +fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory { + return switch (ops) { + .rm_sib, + .rm_sib_cc, + .m_sib, + .m_sib_cc, + .mi_sib_u, + .mi_sib_s, + .mr_sib, + .mrr_sib, + .mri_sib, + .lock_m_sib, + .lock_mi_sib_u, + .lock_mi_sib_s, + .lock_mr_sib, + => lower.mir.extraData(Mir.MemorySib, payload).data.decode(), + + .rm_rip, + .rm_rip_cc, + .m_rip, + .m_rip_cc, + .mi_rip_u, + .mi_rip_s, + .mr_rip, + .mrr_rip, + .mri_rip, + .lock_m_rip, + .lock_mi_rip_u, + .lock_mi_rip_s, + .lock_mr_rip, + => lower.mir.extraData(Mir.MemoryRip, payload).data.decode(), + + .rax_moffs, + .moffs_rax, + .lock_moffs_rax, + => lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(), + + else => unreachable, + }; +} + +fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { + lower.result[lower.result_len] = try Instruction.new(prefix, mnemonic, ops); + lower.result_len += 1; +} + +fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void { + try lower.emit(switch (inst.ops) { + else => .none, + .lock_m_sib, + .lock_m_rip, + .lock_mi_sib_u, + .lock_mi_rip_u, + .lock_mi_sib_s, + .lock_mi_rip_s, + .lock_mr_sib, + .lock_mr_rip, + .lock_moffs_rax, + => .lock, + }, switch (inst.tag) { + inline else => |tag| if (@hasField(Mnemonic, @tagName(tag))) + @field(Mnemonic, @tagName(tag)) + else + unreachable, + }, switch (inst.ops) { + .none => &.{}, + .i_s, .i_u => &.{ + .{ .imm = lower.imm(inst.ops, inst.data.i) }, + }, + .r => &.{ + .{ .reg = inst.data.r }, + }, + .rr => &.{ + .{ .reg = inst.data.rr.r1 }, + .{ .reg = inst.data.rr.r2 }, + }, + .rrr => &.{ + .{ .reg = inst.data.rrr.r1 }, + .{ .reg = inst.data.rrr.r2 }, + .{ .reg = inst.data.rrr.r3 }, + }, + .ri_s, .ri_u => &.{ + .{ .reg = inst.data.ri.r }, + .{ .imm = lower.imm(inst.ops, inst.data.ri.i) }, + }, + .ri64 => &.{ + .{ .reg = inst.data.rx.r }, + .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) }, + }, + .rri_s, .rri_u => &.{ + .{ .reg = inst.data.rri.r1 }, + .{ .reg = inst.data.rri.r2 }, + .{ .imm = lower.imm(inst.ops, inst.data.rri.i) }, + }, + .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => &.{ + .{ .mem = lower.mem(inst.ops, inst.data.payload) }, + }, + .mi_sib_s, + .lock_mi_sib_s, + .mi_sib_u, + .lock_mi_sib_u, + .mi_rip_u, + .lock_mi_rip_u, + .mi_rip_s, + .lock_mi_rip_s, + => &.{ + .{ .mem = lower.mem(inst.ops, inst.data.ix.payload) }, + .{ .imm = lower.imm(inst.ops, inst.data.ix.i) }, + }, + .rm_sib, .rm_rip => &.{ + .{ .reg = inst.data.rx.r }, + .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, + }, + .mr_sib, .lock_mr_sib, .mr_rip, .lock_mr_rip => &.{ + .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, + .{ .reg = inst.data.rx.r }, + }, + .mrr_sib, .mrr_rip => &.{ + .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) }, + .{ .reg = inst.data.rrx.r1 }, + .{ .reg = inst.data.rrx.r2 }, + }, + .mri_sib, .mri_rip => &.{ + .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) }, + .{ .reg = inst.data.rix.r }, + .{ .imm = lower.imm(inst.ops, inst.data.rix.i) }, + }, + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + }); +} + +fn mirString(lower: *Lower, inst: Mir.Inst) Error!void { + switch (inst.ops) { + .string => try lower.emit(switch (inst.data.string.repeat) { + inline else => |repeat| @field(Prefix, @tagName(repeat)), + }, switch (inst.tag) { + inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) { + inline else => |width| @field(Mnemonic, @tagName(tag) ++ @tagName(width)), + }, + else => unreachable, + }, &.{}), + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + } +} + +fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void { + const ops: [1]Operand = switch (inst.ops) { + .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => .{ + .{ .mem = lower.mem(inst.ops, inst.data.payload) }, + }, + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + }; + try lower.emit(switch (inst.ops) { + .m_sib, .m_rip => .none, + .lock_m_sib, .lock_m_rip => .lock, + else => unreachable, + }, switch (@divExact(ops[0].bitSize(), 8)) { + 8 => .cmpxchg8b, + 16 => .cmpxchg16b, + else => return lower.fail("invalid operand for {s}", .{@tagName(inst.tag)}), + }, &ops); +} + +fn mirMovMoffs(lower: *Lower, inst: Mir.Inst) Error!void { + try lower.emit(switch (inst.ops) { + .rax_moffs, .moffs_rax => .none, + .lock_moffs_rax => .lock, + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + }, .mov, switch (inst.ops) { + .rax_moffs => &.{ + .{ .reg = .rax }, + .{ .mem = lower.mem(inst.ops, inst.data.payload) }, + }, + .moffs_rax, .lock_moffs_rax => &.{ + .{ .mem = lower.mem(inst.ops, inst.data.payload) }, + .{ .reg = .rax }, + }, + else => unreachable, + }); +} + +fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void { + const ops: [2]Operand = switch (inst.ops) { + .rr => .{ + .{ .reg = inst.data.rr.r1 }, + .{ .reg = inst.data.rr.r2 }, + }, + .rm_sib, .rm_rip => .{ + .{ .reg = inst.data.rx.r }, + .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, + }, + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + }; + try lower.emit(.none, switch (ops[0].bitSize()) { + 32, 64 => switch (ops[1].bitSize()) { + 32 => .movsxd, + else => .movsx, + }, + else => .movsx, + }, &ops); +} + +fn mirCmovcc(lower: *Lower, inst: Mir.Inst) Error!void { + switch (inst.ops) { + .rr_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rr_cc.cc), &.{ + .{ .reg = inst.data.rr_cc.r1 }, + .{ .reg = inst.data.rr_cc.r2 }, + }), + .rm_sib_cc, .rm_rip_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rx_cc.cc), &.{ + .{ .reg = inst.data.rx_cc.r }, + .{ .mem = lower.mem(inst.ops, inst.data.rx_cc.payload) }, + }), + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + } +} + +fn mirSetcc(lower: *Lower, inst: Mir.Inst) Error!void { + switch (inst.ops) { + .r_cc => try lower.emit(.none, mnem_cc(.set, inst.data.r_cc.cc), &.{ + .{ .reg = inst.data.r_cc.r }, + }), + .m_sib_cc, .m_rip_cc => try lower.emit(.none, mnem_cc(.set, inst.data.x_cc.cc), &.{ + .{ .mem = lower.mem(inst.ops, inst.data.x_cc.payload) }, + }), + else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), + } +} + +fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst) Error!void { + const save_reg_list = lower.mir.extraData(Mir.SaveRegisterList, inst.data.payload).data; + const base = @intToEnum(Register, save_reg_list.base_reg); + var disp: i32 = -@intCast(i32, save_reg_list.stack_end); + const reg_list = Mir.RegisterList.fromInt(save_reg_list.register_list); + const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*); + for (callee_preserved_regs) |callee_preserved_reg| { + if (!reg_list.isSet(callee_preserved_regs, callee_preserved_reg)) continue; + const reg_op = Operand{ .reg = callee_preserved_reg }; + const mem_op = Operand{ .mem = Memory.sib(.qword, .{ .base = base, .disp = disp }) }; + try lower.emit(.none, .mov, switch (inst.tag) { + .push_regs => &.{ mem_op, reg_op }, + .pop_regs => &.{ reg_op, mem_op }, + else => unreachable, + }); + disp += 8; + } +} + +fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void { + const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data; + const reg = @intToEnum(Register, metadata.reg); + try lower.emit(.none, .lea, &.{ + .{ .reg = reg }, + .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, + }); +} + +const abi = @import("abi.zig"); +const assert = std.debug.assert; +const bits = @import("bits.zig"); +const encoder = @import("encoder.zig"); +const std = @import("std"); + +const Air = @import("../../Air.zig"); +const Allocator = std.mem.Allocator; +const ErrorMsg = Module.ErrorMsg; +const Immediate = bits.Immediate; +const Instruction = encoder.Instruction; +const Lower = @This(); +const Memory = bits.Memory; +const Mir = @import("Mir.zig"); +const Mnemonic = Instruction.Mnemonic; +const Module = @import("../../Module.zig"); +const Operand = Instruction.Operand; +const Prefix = Instruction.Prefix; +const Register = bits.Register; diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index a6a4115814..0ceee6bac1 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -655,16 +655,19 @@ pub const MemoryMoffs = struct { msb: u32, lsb: u32, - pub fn encodeOffset(moffs: *MemoryMoffs, v: u64) void { - moffs.msb = @truncate(u32, v >> 32); - moffs.lsb = @truncate(u32, v); + pub fn encode(seg: Register, offset: u64) MemoryMoffs { + return .{ + .seg = @enumToInt(seg), + .msb = @truncate(u32, offset >> 32), + .lsb = @truncate(u32, offset >> 0), + }; } - pub fn decodeOffset(moffs: *const MemoryMoffs) u64 { - var res: u64 = 0; - res |= (@intCast(u64, moffs.msb) << 32); - res |= @intCast(u64, moffs.lsb); - return res; + pub fn decode(moffs: MemoryMoffs) Memory { + return .{ .moffs = .{ + .seg = @intToEnum(Register, moffs.seg), + .offset = @as(u64, moffs.msb) << 32 | @as(u64, moffs.lsb) << 0, + } }; } }; diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 76ad26a9a0..b2a6b31749 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -515,7 +515,7 @@ pub const Memory = union(enum) { return switch (mem) { .rip => |r| r.ptr_size.bitSize(), .sib => |s| s.ptr_size.bitSize(), - .moffs => unreachable, + .moffs => 64, }; } }; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 05f66062ac..e7e231c063 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -11,12 +11,9 @@ const Memory = bits.Memory; const Register = bits.Register; pub const Instruction = struct { - op1: Operand = .none, - op2: Operand = .none, - op3: Operand = .none, - op4: Operand = .none, prefix: Prefix = .none, encoding: Encoding, + ops: [4]Operand = .{.none} ** 4, pub const Mnemonic = Encoding.Mnemonic; @@ -107,102 +104,87 @@ pub const Instruction = struct { } }; - pub const Init = struct { - prefix: Prefix = .none, - op1: Operand = .none, - op2: Operand = .none, - op3: Operand = .none, - op4: Operand = .none, - }; - - pub fn new(mnemonic: Mnemonic, args: Init) !Instruction { - const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse { + pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction { + const encoding = (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse { log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{ - @tagName(args.prefix), + @tagName(prefix), @tagName(mnemonic), - @tagName(Encoding.Op.fromOperand(args.op1)), - @tagName(Encoding.Op.fromOperand(args.op2)), - @tagName(Encoding.Op.fromOperand(args.op3)), - @tagName(Encoding.Op.fromOperand(args.op4)), + @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none), + @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none), + @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none), + @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none), }); return error.InvalidInstruction; }; log.debug("selected encoding: {}", .{encoding}); - return .{ - .prefix = args.prefix, - .op1 = args.op1, - .op2 = args.op2, - .op3 = args.op3, - .op4 = args.op4, + + var inst = Instruction{ + .prefix = prefix, .encoding = encoding, + .ops = [1]Operand{.none} ** 4, }; + std.mem.copy(Operand, &inst.ops, ops); + return inst; } pub fn fmtPrint(inst: Instruction, writer: anytype) !void { if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)}); try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)}); - const ops = [_]struct { Operand, Encoding.Op }{ - .{ inst.op1, inst.encoding.op1 }, - .{ inst.op2, inst.encoding.op2 }, - .{ inst.op3, inst.encoding.op3 }, - .{ inst.op4, inst.encoding.op4 }, - }; - for (&ops, 0..) |op, i| { - if (op[0] == .none) break; - if (i > 0) { - try writer.writeByte(','); - } + for (inst.ops, inst.encodings.ops, 0..) |op, enc, i| { + if (op == .none) break; + if (i > 0) try writer.writeByte(','); try writer.writeByte(' '); - try op[0].fmtPrint(op[1], writer); + try op.fmtPrint(enc, writer); } } pub fn encode(inst: Instruction, writer: anytype) !void { const encoder = Encoder(@TypeOf(writer)){ .writer = writer }; - const encoding = inst.encoding; + const enc = inst.encoding; + const data = enc.data; try inst.encodeLegacyPrefixes(encoder); try inst.encodeMandatoryPrefix(encoder); try inst.encodeRexPrefix(encoder); try inst.encodeOpcode(encoder); - switch (encoding.op_en) { + switch (data.op_en) { .np, .o => {}, - .i, .d => try encodeImm(inst.op1.imm, encoding.op1, encoder), - .zi, .oi => try encodeImm(inst.op2.imm, encoding.op2, encoder), - .fd => try encoder.imm64(inst.op2.mem.moffs.offset), - .td => try encoder.imm64(inst.op1.mem.moffs.offset), + .i, .d => try encodeImm(inst.ops[0].imm, data.ops[0], encoder), + .zi, .oi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder), + .fd => try encoder.imm64(inst.ops[1].mem.moffs.offset), + .td => try encoder.imm64(inst.ops[0].mem.moffs.offset), else => { - const mem_op = switch (encoding.op_en) { - .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1, - .rm, .rmi => inst.op2, + const mem_op = switch (data.op_en) { + .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0], + .rm, .rmi => inst.ops[1], else => unreachable, }; switch (mem_op) { .reg => |reg| { - const rm = switch (encoding.op_en) { - .m, .mi, .m1, .mc => encoding.modRmExt(), - .mr, .mri, .mrc => inst.op2.reg.lowEnc(), - .rm, .rmi => inst.op1.reg.lowEnc(), + const rm = switch (data.op_en) { + .m, .mi, .m1, .mc => enc.modRmExt(), + .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(), + .rm, .rmi => inst.ops[0].reg.lowEnc(), else => unreachable, }; try encoder.modRm_direct(rm, reg.lowEnc()); }, .mem => |mem| { - const op = switch (encoding.op_en) { + const op = switch (data.op_en) { .m, .mi, .m1, .mc => .none, - .mr, .mri, .mrc => inst.op2, - .rm, .rmi => inst.op1, + .mr, .mri, .mrc => inst.ops[1], + .rm, .rmi => inst.ops[0], else => unreachable, }; - try encodeMemory(encoding, mem, op, encoder); + try encodeMemory(enc, mem, op, encoder); }, else => unreachable, } - switch (encoding.op_en) { - .mi => try encodeImm(inst.op2.imm, encoding.op2, encoder), - .rmi, .mri => try encodeImm(inst.op3.imm, encoding.op3, encoder), + switch (data.op_en) { + .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder), + .rmi, .mri => try encodeImm(inst.ops[2].imm, data.ops[2], encoder), else => {}, } }, @@ -214,15 +196,16 @@ pub const Instruction = struct { const first = @boolToInt(inst.encoding.mandatoryPrefix() != null); const final = opcode.len - 1; for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte); - switch (inst.encoding.op_en) { - .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()), + switch (inst.encoding.data.op_en) { + .o, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()), else => try encoder.opcode_1byte(opcode[final]), } } fn encodeLegacyPrefixes(inst: Instruction, encoder: anytype) !void { const enc = inst.encoding; - const op_en = enc.op_en; + const data = enc.data; + const op_en = data.op_en; var legacy = LegacyPrefixes{}; @@ -233,7 +216,7 @@ pub const Instruction = struct { .rep, .repe, .repz => legacy.prefix_f3 = true, } - if (enc.mode == .none) { + if (data.mode == .none) { const bit_size = enc.operandBitSize(); if (bit_size == 16) { legacy.set16BitOverride(); @@ -242,17 +225,17 @@ pub const Instruction = struct { const segment_override: ?Register = switch (op_en) { .i, .zi, .o, .oi, .d, .np => null, - .fd => inst.op2.mem.base().?, - .td => inst.op1.mem.base().?, - .rm, .rmi => if (inst.op2.isSegmentRegister()) blk: { - break :blk switch (inst.op2) { + .fd => inst.ops[1].mem.base().?, + .td => inst.ops[0].mem.base().?, + .rm, .rmi => if (inst.ops[1].isSegmentRegister()) blk: { + break :blk switch (inst.ops[1]) { .reg => |r| r, .mem => |m| m.base().?, else => unreachable, }; } else null, - .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.op1.isSegmentRegister()) blk: { - break :blk switch (inst.op1) { + .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.ops[0].isSegmentRegister()) blk: { + break :blk switch (inst.ops[0]) { .reg => |r| r, .mem => |m| m.base().?, else => unreachable, @@ -267,19 +250,19 @@ pub const Instruction = struct { } fn encodeRexPrefix(inst: Instruction, encoder: anytype) !void { - const op_en = inst.encoding.op_en; + const op_en = inst.encoding.data.op_en; var rex = Rex{}; - rex.present = inst.encoding.mode == .rex; - rex.w = inst.encoding.mode == .long; + rex.present = inst.encoding.data.mode == .rex; + rex.w = inst.encoding.data.mode == .long; switch (op_en) { .np, .i, .zi, .fd, .td, .d => {}, - .o, .oi => rex.b = inst.op1.reg.isExtended(), + .o, .oi => rex.b = inst.ops[0].reg.isExtended(), .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => { const r_op = switch (op_en) { - .rm, .rmi => inst.op1, - .mr, .mri, .mrc => inst.op2, + .rm, .rmi => inst.ops[0], + .mr, .mri, .mrc => inst.ops[1], else => null, }; if (r_op) |op| { @@ -287,8 +270,8 @@ pub const Instruction = struct { } const b_x_op = switch (op_en) { - .rm, .rmi => inst.op2, - .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1, + .rm, .rmi => inst.ops[1], + .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0], else => unreachable, }; switch (b_x_op) { @@ -827,16 +810,14 @@ const TestEncode = struct { buffer: [32]u8 = undefined, index: usize = 0, - fn encode(enc: *TestEncode, mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { + fn encode( + enc: *TestEncode, + mnemonic: Instruction.Mnemonic, + ops: []const Instruction.Operand, + ) !void { var stream = std.io.fixedBufferStream(&enc.buffer); var count_writer = std.io.countingWriter(stream.writer()); - const inst = try Instruction.new(mnemonic, .{ - .prefix = args.prefix, - .op1 = args.op1, - .op2 = args.op2, - .op3 = args.op3, - .op4 = args.op4, - }); + const inst = try Instruction.new(.none, mnemonic, ops); try inst.encode(count_writer.writer()); enc.index = count_writer.bytes_written; } @@ -850,9 +831,9 @@ test "encode" { var buf = std.ArrayList(u8).init(testing.allocator); defer buf.deinit(); - const inst = try Instruction.new(.mov, .{ - .op1 = .{ .reg = .rbx }, - .op2 = .{ .imm = Immediate.u(4) }, + const inst = try Instruction.new(.none, .mov, &.{ + .{ .reg = .rbx }, + .{ .imm = Immediate.u(4) }, }); try inst.encode(buf.writer()); try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items); @@ -861,61 +842,94 @@ test "encode" { test "lower I encoding" { var enc = TestEncode{}; - try enc.encode(.push, .{ .op1 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.push, &.{ + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10"); - try enc.encode(.push, .{ .op1 = .{ .imm = Immediate.u(0x1000) } }); + try enc.encode(.push, &.{ + .{ .imm = Immediate.u(0x1000) }, + }); try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000"); - try enc.encode(.push, .{ .op1 = .{ .imm = Immediate.u(0x10000000) } }); + try enc.encode(.push, &.{ + .{ .imm = Immediate.u(0x10000000) }, + }); try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000"); - try enc.encode(.adc, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10000000) } }); + try enc.encode(.adc, &.{ + .{ .reg = .rax }, + .{ .imm = Immediate.u(0x10000000) }, + }); try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000"); - try enc.encode(.add, .{ .op1 = .{ .reg = .al }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.add, &.{ + .{ .reg = .al }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10"); - try enc.encode(.add, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.add, &.{ + .{ .reg = .rax }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); - try enc.encode(.sbb, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.sbb, &.{ + .{ .reg = .ax }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10"); - try enc.encode(.xor, .{ .op1 = .{ .reg = .al }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.xor, &.{ + .{ .reg = .al }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10"); } test "lower MI encoding" { var enc = TestEncode{}; - try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r12 }, + .{ .imm = Immediate.u(0x1000) }, + }); try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); - try enc.encode(.mov, .{ - .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, - .op2 = .{ .imm = Immediate.u(0x10) }, + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, + .{ .imm = Immediate.u(0x10) }, }); try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r12 }, + .{ .imm = Immediate.u(0x1000) }, + }); try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r12 }, + .{ .imm = Immediate.u(0x1000) }, + }); try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); - try enc.encode(.mov, .{ - .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) }, - .op2 = .{ .imm = Immediate.u(0x10) }, + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) }, + .{ .imm = Immediate.u(0x10) }, }); try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); - try enc.encode(.mov, .{ - .op1 = .{ .mem = Memory.rip(.qword, 0x10) }, - .op2 = .{ .imm = Immediate.u(0x10) }, + try enc.encode(.mov, &.{ + .{ .mem = Memory.rip(.qword, 0x10) }, + .{ .imm = Immediate.u(0x10) }, }); try expectEqualHexStrings( "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", @@ -923,99 +937,108 @@ test "lower MI encoding" { "mov QWORD PTR [rip + 0x10], 0x10", ); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .disp = -8, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.word, .{ - .base = .rbp, - .disp = -2, - }) }, .op2 = .{ .imm = Immediate.s(-16) } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) }, + .{ .imm = Immediate.s(-16) }, + }); try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{ - .base = .rbp, - .disp = -1, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .ds, - .disp = 0x10000000, - .scale_index = .{ - .scale = 2, - .index = .rcx, - }, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.qword, .{ + .base = .ds, + .disp = 0x10000000, + .scale_index = .{ .scale = 2, .index = .rcx }, + }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings( "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rcx*2 + 0x10000000], 0x10", ); - try enc.encode(.adc, .{ .op1 = .{ .mem = Memory.sib(.byte, .{ - .base = .rbp, - .disp = -0x10, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.adc, &.{ + .{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); - try enc.encode(.adc, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.adc, &.{ + .{ .mem = Memory.rip(.qword, 0) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10"); - try enc.encode(.adc, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.adc, &.{ + .{ .reg = .rax }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); - try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .rdx, - .disp = -8, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.add, &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); - try enc.encode(.add, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.add, &.{ + .{ .reg = .rax }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); - try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .disp = -0x10, - }) }, .op2 = .{ .imm = Immediate.s(-0x10) } }); + try enc.encode(.add, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) }, + .{ .imm = Immediate.s(-0x10) }, + }); try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); - try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .ds, - .disp = 0x10000000, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.@"and", &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings( "\x83\x24\x25\x00\x00\x00\x10\x10", enc.code(), "and DWORD PTR ds:0x10000000, 0x10", ); - try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .es, - .disp = 0x10000000, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.@"and", &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings( "\x26\x83\x24\x25\x00\x00\x00\x10\x10", enc.code(), "and DWORD PTR es:0x10000000, 0x10", ); - try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .r12, - .disp = 0x10000000, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.@"and", &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings( "\x41\x83\xA4\x24\x00\x00\x00\x10\x10", enc.code(), "and DWORD PTR [r12 + 0x10000000], 0x10", ); - try enc.encode(.sub, .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .r11, - .disp = 0x10000000, - }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.sub, &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings( "\x41\x83\xAB\x00\x00\x00\x10\x10", enc.code(), @@ -1026,185 +1049,227 @@ test "lower MI encoding" { test "lower RM encoding" { var enc = TestEncode{}; - try enc.encode(.mov, .{ - .op1 = .{ .reg = .rax }, - .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) }, + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) }, }); try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .ds, - .disp = 0x10, - }) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rbx }, + .{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) }, + }); try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .disp = -4, - }) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) }, + }); try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .scale_index = .{ - .scale = 1, - .index = .rcx, - }, - .disp = -8, - }) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.sib(.qword, .{ + .base = .rbp, + .scale_index = .{ .scale = 1, .index = .rcx }, + .disp = -8, + }) }, + }); try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", enc.code(), "mov rax, QWORD PTR [rbp + rcx*1 - 8]"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.dword, .{ - .base = .rbp, - .scale_index = .{ - .scale = 4, - .index = .rdx, - }, - .disp = -4, - }) } }); + try enc.encode(.mov, &.{ + .{ .reg = .eax }, + .{ .mem = Memory.sib(.dword, .{ + .base = .rbp, + .scale_index = .{ .scale = 4, .index = .rdx }, + .disp = -4, + }) }, + }); try expectEqualHexStrings("\x8B\x44\x95\xFC", enc.code(), "mov eax, dword ptr [rbp + rdx*4 - 4]"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .scale_index = .{ - .scale = 8, - .index = .rcx, - }, - .disp = -8, - }) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.sib(.qword, .{ + .base = .rbp, + .scale_index = .{ .scale = 8, .index = .rcx }, + .disp = -8, + }) }, + }); try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", enc.code(), "mov rax, QWORD PTR [rbp + rcx*8 - 8]"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r8b }, .op2 = .{ .mem = Memory.sib(.byte, .{ - .base = .rsi, - .scale_index = .{ - .scale = 1, - .index = .rcx, - }, - .disp = -24, - }) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r8b }, + .{ .mem = Memory.sib(.byte, .{ + .base = .rsi, + .scale_index = .{ .scale = 1, .index = .rcx }, + .disp = -24, + }) }, + }); try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", enc.code(), "mov r8b, BYTE PTR [rsi + rcx*1 - 24]"); // TODO this mnemonic needs cleanup as some prefixes are obsolete. - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .cs } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .reg = .cs }, + }); try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .disp = -16, - }) }, .op2 = .{ .reg = .fs } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) }, + .{ .reg = .fs }, + }); try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r12w }, .op2 = .{ .reg = .cs } }); + try enc.encode(.mov, &.{ + .{ .reg = .r12w }, + .{ .reg = .cs }, + }); try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.word, .{ - .base = .rbp, - .disp = -16, - }) }, .op2 = .{ .reg = .fs } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) }, + .{ .reg = .fs }, + }); try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs"); - try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .reg = .bx } }); + try enc.encode(.movsx, &.{ + .{ .reg = .eax }, + .{ .reg = .bx }, + }); try expectEqualHexStrings("\x0F\xBF\xC3", enc.code(), "movsx eax, bx"); - try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .reg = .bl } }); + try enc.encode(.movsx, &.{ + .{ .reg = .eax }, + .{ .reg = .bl }, + }); try expectEqualHexStrings("\x0F\xBE\xC3", enc.code(), "movsx eax, bl"); - try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } }); + try enc.encode(.movsx, &.{ + .{ .reg = .ax }, + .{ .reg = .bl }, + }); try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl"); - try enc.encode(.movsx, .{ - .op1 = .{ .reg = .eax }, - .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) }, + try enc.encode(.movsx, &.{ + .{ .reg = .eax }, + .{ .mem = Memory.sib(.word, .{ .base = .rbp }) }, }); try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); - try enc.encode(.movsx, .{ - .op1 = .{ .reg = .eax }, - .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) }, + try enc.encode(.movsx, &.{ + .{ .reg = .eax }, + .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) }, }); try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); - try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); + try enc.encode(.movsx, &.{ + .{ .reg = .ax }, + .{ .mem = Memory.rip(.byte, 0x10) }, + }); try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]"); - try enc.encode(.movsx, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .bx } }); + try enc.encode(.movsx, &.{ + .{ .reg = .rax }, + .{ .reg = .bx }, + }); try expectEqualHexStrings("\x48\x0F\xBF\xC3", enc.code(), "movsx rax, bx"); - try enc.encode(.movsxd, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .ebx } }); + try enc.encode(.movsxd, &.{ + .{ .reg = .rax }, + .{ .reg = .ebx }, + }); try expectEqualHexStrings("\x48\x63\xC3", enc.code(), "movsxd rax, ebx"); - try enc.encode(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.rip(.qword, 0x10) } }); + try enc.encode(.lea, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.rip(.qword, 0x10) }, + }); try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]"); - try enc.encode(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.rip(.dword, 0x10) } }); + try enc.encode(.lea, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.rip(.dword, 0x10) }, + }); try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]"); - try enc.encode(.lea, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.rip(.dword, 0x10) } }); + try enc.encode(.lea, &.{ + .{ .reg = .eax }, + .{ .mem = Memory.rip(.dword, 0x10) }, + }); try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]"); - try enc.encode(.lea, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.rip(.word, 0x10) } }); + try enc.encode(.lea, &.{ + .{ .reg = .eax }, + .{ .mem = Memory.rip(.word, 0x10) }, + }); try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]"); - try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); + try enc.encode(.lea, &.{ + .{ .reg = .ax }, + .{ .mem = Memory.rip(.byte, 0x10) }, + }); try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]"); - try enc.encode(.lea, .{ - .op1 = .{ .reg = .rsi }, - .op2 = .{ .mem = Memory.sib(.qword, .{ + try enc.encode(.lea, &.{ + .{ .reg = .rsi }, + .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .scale_index = .{ .scale = 1, .index = .rcx }, }) }, }); try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]"); - try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .ds, - .disp = 0x10000000, - }) } }); + try enc.encode(.add, &.{ + .{ .reg = .r11 }, + .{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) }, + }); try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000"); - try enc.encode(.add, .{ .op1 = .{ .reg = .r12b }, .op2 = .{ .mem = Memory.sib(.byte, .{ - .base = .ds, - .disp = 0x10000000, - }) } }); + try enc.encode(.add, &.{ + .{ .reg = .r12b }, + .{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) }, + }); try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000"); - try enc.encode(.add, .{ .op1 = .{ .reg = .r12b }, .op2 = .{ .mem = Memory.sib(.byte, .{ - .base = .fs, - .disp = 0x10000000, - }) } }); + try enc.encode(.add, &.{ + .{ .reg = .r12b }, + .{ .mem = Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) }, + }); try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000"); - try enc.encode(.sub, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .r13, - .disp = 0x10000000, - }) } }); + try enc.encode(.sub, &.{ + .{ .reg = .r11 }, + .{ .mem = Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) }, + }); try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]"); - try enc.encode(.sub, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{ - .base = .r12, - .disp = 0x10000000, - }) } }); + try enc.encode(.sub, &.{ + .{ .reg = .r11 }, + .{ .mem = Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) }, + }); try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]"); - try enc.encode(.imul, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .reg = .r12 } }); + try enc.encode(.imul, &.{ + .{ .reg = .r11 }, + .{ .reg = .r12 }, + }); try expectEqualHexStrings("\x4D\x0F\xAF\xDC", enc.code(), "mov r11, r12"); } test "lower RMI encoding" { var enc = TestEncode{}; - try enc.encode(.imul, .{ - .op1 = .{ .reg = .r11 }, - .op2 = .{ .reg = .r12 }, - .op3 = .{ .imm = Immediate.s(-2) }, + try enc.encode(.imul, &.{ + .{ .reg = .r11 }, + .{ .reg = .r12 }, + .{ .imm = Immediate.s(-2) }, }); try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2"); - try enc.encode(.imul, .{ - .op1 = .{ .reg = .r11 }, - .op2 = .{ .mem = Memory.rip(.qword, -16) }, - .op3 = .{ .imm = Immediate.s(-1024) }, + try enc.encode(.imul, &.{ + .{ .reg = .r11 }, + .{ .mem = Memory.rip(.qword, -16) }, + .{ .imm = Immediate.s(-1024) }, }); try expectEqualHexStrings( "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF", @@ -1212,13 +1277,10 @@ test "lower RMI encoding" { "imul r11, QWORD PTR [rip - 16], -1024", ); - try enc.encode(.imul, .{ - .op1 = .{ .reg = .bx }, - .op2 = .{ .mem = Memory.sib(.word, .{ - .base = .rbp, - .disp = -16, - }) }, - .op3 = .{ .imm = Immediate.s(-1024) }, + try enc.encode(.imul, &.{ + .{ .reg = .bx }, + .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) }, + .{ .imm = Immediate.s(-1024) }, }); try expectEqualHexStrings( "\x66\x69\x5D\xF0\x00\xFC", @@ -1226,13 +1288,10 @@ test "lower RMI encoding" { "imul bx, WORD PTR [rbp - 16], -1024", ); - try enc.encode(.imul, .{ - .op1 = .{ .reg = .bx }, - .op2 = .{ .mem = Memory.sib(.word, .{ - .base = .rbp, - .disp = -16, - }) }, - .op3 = .{ .imm = Immediate.u(1024) }, + try enc.encode(.imul, &.{ + .{ .reg = .bx }, + .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) }, + .{ .imm = Immediate.u(1024) }, }); try expectEqualHexStrings( "\x66\x69\x5D\xF0\x00\x04", @@ -1244,238 +1303,343 @@ test "lower RMI encoding" { test "lower MR encoding" { var enc = TestEncode{}; - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .rbx } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .reg = .rbx }, + }); try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .rbp, - .disp = -4, - }) }, .op2 = .{ .reg = .r11 } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) }, + .{ .reg = .r11 }, + }); try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.rip(.qword, 0x10) }, .op2 = .{ .reg = .r12 } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.rip(.qword, 0x10) }, + .{ .reg = .r12 }, + }); try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .r11, - .scale_index = .{ - .scale = 2, - .index = .r12, - }, - .disp = 0x10, - }) }, .op2 = .{ .reg = .r13 } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.qword, .{ + .base = .r11, + .scale_index = .{ .scale = 2, .index = .r12 }, + .disp = 0x10, + }) }, + .{ .reg = .r13 }, + }); try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.rip(.word, -0x10) }, .op2 = .{ .reg = .r12w } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.rip(.word, -0x10) }, + .{ .reg = .r12w }, + }); try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{ - .base = .r11, - .scale_index = .{ - .scale = 2, - .index = .r12, - }, - .disp = 0x10, - }) }, .op2 = .{ .reg = .r13b } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.sib(.byte, .{ + .base = .r11, + .scale_index = .{ .scale = 2, .index = .r12 }, + .disp = 0x10, + }) }, + .{ .reg = .r13b }, + }); try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b"); - try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.byte, .{ - .base = .ds, - .disp = 0x10000000, - }) }, .op2 = .{ .reg = .r12b } }); + try enc.encode(.add, &.{ + .{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) }, + .{ .reg = .r12b }, + }); try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b"); - try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .ds, - .disp = 0x10000000, - }) }, .op2 = .{ .reg = .r12d } }); + try enc.encode(.add, &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) }, + .{ .reg = .r12d }, + }); try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d"); - try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{ - .base = .gs, - .disp = 0x10000000, - }) }, .op2 = .{ .reg = .r12d } }); + try enc.encode(.add, &.{ + .{ .mem = Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) }, + .{ .reg = .r12d }, + }); try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d"); - try enc.encode(.sub, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ - .base = .r11, - .disp = 0x10000000, - }) }, .op2 = .{ .reg = .r12 } }); + try enc.encode(.sub, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) }, + .{ .reg = .r12 }, + }); try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12"); } test "lower M encoding" { var enc = TestEncode{}; - try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } }); + try enc.encode(.call, &.{ + .{ .reg = .r12 }, + }); try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); - try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) } }); + try enc.encode(.call, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) }, + }); try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); - try enc.encode(.call, .{ - .op1 = .{ .mem = Memory.sib(.qword, .{ + try enc.encode(.call, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = null, .scale_index = .{ .index = .r11, .scale = 2 }, }) }, }); try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]"); - try enc.encode(.call, .{ - .op1 = .{ .mem = Memory.sib(.qword, .{ + try enc.encode(.call, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = null, .scale_index = .{ .index = .r12, .scale = 2 }, }) }, }); try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); - try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .gs }) } }); + try enc.encode(.call, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .gs }) }, + }); try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); - try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } }); + try enc.encode(.call, &.{ + .{ .imm = Immediate.s(0) }, + }); try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); - try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) } }); + try enc.encode(.push, &.{ + .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) }, + }); try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); - try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) } }); + try enc.encode(.push, &.{ + .{ .mem = Memory.sib(.word, .{ .base = .rbp }) }, + }); try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); - try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) } }); + try enc.encode(.pop, &.{ + .{ .mem = Memory.rip(.qword, 0) }, + }); try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]"); - try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.word, 0) } }); + try enc.encode(.pop, &.{ + .{ .mem = Memory.rip(.word, 0) }, + }); try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]"); - try enc.encode(.imul, .{ .op1 = .{ .reg = .rax } }); + try enc.encode(.imul, &.{ + .{ .reg = .rax }, + }); try expectEqualHexStrings("\x48\xF7\xE8", enc.code(), "imul rax"); - try enc.encode(.imul, .{ .op1 = .{ .reg = .r12 } }); + try enc.encode(.imul, &.{ + .{ .reg = .r12 }, + }); try expectEqualHexStrings("\x49\xF7\xEC", enc.code(), "imul r12"); } test "lower O encoding" { var enc = TestEncode{}; - try enc.encode(.push, .{ .op1 = .{ .reg = .rax } }); + try enc.encode(.push, &.{ + .{ .reg = .rax }, + }); try expectEqualHexStrings("\x50", enc.code(), "push rax"); - try enc.encode(.push, .{ .op1 = .{ .reg = .r12w } }); + try enc.encode(.push, &.{ + .{ .reg = .r12w }, + }); try expectEqualHexStrings("\x66\x41\x54", enc.code(), "push r12w"); - try enc.encode(.pop, .{ .op1 = .{ .reg = .r12 } }); + try enc.encode(.pop, &.{ + .{ .reg = .r12 }, + }); try expectEqualHexStrings("\x41\x5c", enc.code(), "pop r12"); } test "lower OI encoding" { var enc = TestEncode{}; - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x1000000000000000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .imm = Immediate.u(0x1000000000000000) }, + }); try expectEqualHexStrings( "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10", enc.code(), "movabs rax, 0x1000000000000000", ); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .imm = Immediate.u(0x1000000000000000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r11 }, + .{ .imm = Immediate.u(0x1000000000000000) }, + }); try expectEqualHexStrings( "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10", enc.code(), "movabs r11, 0x1000000000000000", ); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r11d }, .op2 = .{ .imm = Immediate.u(0x10000000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r11d }, + .{ .imm = Immediate.u(0x10000000) }, + }); try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r11w }, .op2 = .{ .imm = Immediate.u(0x1000) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r11w }, + .{ .imm = Immediate.u(0x1000) }, + }); try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .r11b }, .op2 = .{ .imm = Immediate.u(0x10) } }); + try enc.encode(.mov, &.{ + .{ .reg = .r11b }, + .{ .imm = Immediate.u(0x10) }, + }); try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10"); } test "lower FD/TD encoding" { var enc = TestEncode{}; - try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.moffs(.cs, 0x10) } }); + try enc.encode(.mov, &.{ + .{ .reg = .rax }, + .{ .mem = Memory.moffs(.cs, 0x10) }, + }); try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.moffs(.fs, 0x10) } }); + try enc.encode(.mov, &.{ + .{ .reg = .eax }, + .{ .mem = Memory.moffs(.fs, 0x10) }, + }); try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.moffs(.gs, 0x10) } }); + try enc.encode(.mov, &.{ + .{ .reg = .ax }, + .{ .mem = Memory.moffs(.gs, 0x10) }, + }); try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10"); - try enc.encode(.mov, .{ .op1 = .{ .reg = .al }, .op2 = .{ .mem = Memory.moffs(.ds, 0x10) } }); + try enc.encode(.mov, &.{ + .{ .reg = .al }, + .{ .mem = Memory.moffs(.ds, 0x10) }, + }); try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.cs, 0x10) }, .op2 = .{ .reg = .rax } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.moffs(.cs, 0x10) }, + .{ .reg = .rax }, + }); try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.fs, 0x10) }, .op2 = .{ .reg = .eax } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.moffs(.fs, 0x10) }, + .{ .reg = .eax }, + }); try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.gs, 0x10) }, .op2 = .{ .reg = .ax } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.moffs(.gs, 0x10) }, + .{ .reg = .ax }, + }); try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax"); - try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.ds, 0x10) }, .op2 = .{ .reg = .al } }); + try enc.encode(.mov, &.{ + .{ .mem = Memory.moffs(.ds, 0x10) }, + .{ .reg = .al }, + }); try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al"); } test "lower NP encoding" { var enc = TestEncode{}; - try enc.encode(.int3, .{}); + try enc.encode(.int3, &.{}); try expectEqualHexStrings("\xCC", enc.code(), "int3"); - try enc.encode(.nop, .{}); + try enc.encode(.nop, &.{}); try expectEqualHexStrings("\x90", enc.code(), "nop"); - try enc.encode(.ret, .{}); + try enc.encode(.ret, &.{}); try expectEqualHexStrings("\xC3", enc.code(), "ret"); - try enc.encode(.syscall, .{}); + try enc.encode(.syscall, &.{}); try expectEqualHexStrings("\x0f\x05", enc.code(), "syscall"); } -fn invalidInstruction(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { - const err = Instruction.new(mnemonic, args); +fn invalidInstruction(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void { + const err = Instruction.new(.none, mnemonic, ops); try testing.expectError(error.InvalidInstruction, err); } test "invalid instruction" { - try invalidInstruction(.call, .{ .op1 = .{ .reg = .eax } }); - try invalidInstruction(.call, .{ .op1 = .{ .reg = .ax } }); - try invalidInstruction(.call, .{ .op1 = .{ .reg = .al } }); - try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.dword, 0) } }); - try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.word, 0) } }); - try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.byte, 0) } }); - try invalidInstruction(.mov, .{ .op1 = .{ .mem = Memory.rip(.word, 0x10) }, .op2 = .{ .reg = .r12 } }); - try invalidInstruction(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .rbx } }); - try invalidInstruction(.lea, .{ .op1 = .{ .reg = .al }, .op2 = .{ .mem = Memory.rip(.byte, 0) } }); - try invalidInstruction(.pop, .{ .op1 = .{ .reg = .r12b } }); - try invalidInstruction(.pop, .{ .op1 = .{ .reg = .r12d } }); - try invalidInstruction(.push, .{ .op1 = .{ .reg = .r12b } }); - try invalidInstruction(.push, .{ .op1 = .{ .reg = .r12d } }); - try invalidInstruction(.push, .{ .op1 = .{ .imm = Immediate.u(0x1000000000000000) } }); + try invalidInstruction(.call, &.{ + .{ .reg = .eax }, + }); + try invalidInstruction(.call, &.{ + .{ .reg = .ax }, + }); + try invalidInstruction(.call, &.{ + .{ .reg = .al }, + }); + try invalidInstruction(.call, &.{ + .{ .mem = Memory.rip(.dword, 0) }, + }); + try invalidInstruction(.call, &.{ + .{ .mem = Memory.rip(.word, 0) }, + }); + try invalidInstruction(.call, &.{ + .{ .mem = Memory.rip(.byte, 0) }, + }); + try invalidInstruction(.mov, &.{ + .{ .mem = Memory.rip(.word, 0x10) }, + .{ .reg = .r12 }, + }); + try invalidInstruction(.lea, &.{ + .{ .reg = .rax }, + .{ .reg = .rbx }, + }); + try invalidInstruction(.lea, &.{ + .{ .reg = .al }, + .{ .mem = Memory.rip(.byte, 0) }, + }); + try invalidInstruction(.pop, &.{ + .{ .reg = .r12b }, + }); + try invalidInstruction(.pop, &.{ + .{ .reg = .r12d }, + }); + try invalidInstruction(.push, &.{ + .{ .reg = .r12b }, + }); + try invalidInstruction(.push, &.{ + .{ .reg = .r12d }, + }); + try invalidInstruction(.push, &.{ + .{ .imm = Immediate.u(0x1000000000000000) }, + }); } -fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { - try testing.expectError(error.CannotEncode, Instruction.new(mnemonic, args)); +fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void { + try testing.expectError(error.CannotEncode, Instruction.new(.none, mnemonic, ops)); } test "cannot encode" { - try cannotEncode(.@"test", .{ - .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, - .op2 = .{ .reg = .ah }, + try cannotEncode(.@"test", &.{ + .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, + .{ .reg = .ah }, }); - try cannotEncode(.@"test", .{ - .op1 = .{ .reg = .r11b }, - .op2 = .{ .reg = .bh }, + try cannotEncode(.@"test", &.{ + .{ .reg = .r11b }, + .{ .reg = .bh }, }); - try cannotEncode(.mov, .{ - .op1 = .{ .reg = .sil }, - .op2 = .{ .reg = .ah }, + try cannotEncode(.mov, &.{ + .{ .reg = .sil }, + .{ .reg = .ah }, }); } @@ -1645,12 +1809,7 @@ const Assembler = struct { pub fn assemble(as: *Assembler, writer: anytype) !void { while (try as.next()) |parsed_inst| { - const inst = try Instruction.new(parsed_inst.mnemonic, .{ - .op1 = parsed_inst.ops[0], - .op2 = parsed_inst.ops[1], - .op3 = parsed_inst.ops[2], - .op4 = parsed_inst.ops[3], - }); + const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops); try inst.encode(writer); } } diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig index 9683ef991a..05933b68bb 100644 --- a/src/arch/x86_64/encodings.zig +++ b/src/arch/x86_64/encodings.zig @@ -6,869 +6,874 @@ const Mode = Encoding.Mode; const modrm_ext = u3; -const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, []const u8, modrm_ext, Mode }; +pub const Entry = struct { Mnemonic, OpEn, []const Op, []const u8, modrm_ext, Mode }; // TODO move this into a .zon file when Zig is capable of importing .zon files // zig fmt: off -pub const table = &[_]Entry{ +pub const table = [_]Entry{ // General-purpose - .{ .adc, .zi, .al, .imm8, .none, .none, &.{ 0x14 }, 0, .none }, - .{ .adc, .zi, .ax, .imm16, .none, .none, &.{ 0x15 }, 0, .none }, - .{ .adc, .zi, .eax, .imm32, .none, .none, &.{ 0x15 }, 0, .none }, - .{ .adc, .zi, .rax, .imm32s, .none, .none, &.{ 0x15 }, 0, .long }, - .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .none }, - .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .rex }, - .{ .adc, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 2, .none }, - .{ .adc, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 2, .none }, - .{ .adc, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 2, .long }, - .{ .adc, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 2, .none }, - .{ .adc, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 2, .none }, - .{ .adc, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 2, .long }, - .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .none }, - .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .rex }, - .{ .adc, .mr, .rm16, .r16, .none, .none, &.{ 0x11 }, 0, .none }, - .{ .adc, .mr, .rm32, .r32, .none, .none, &.{ 0x11 }, 0, .none }, - .{ .adc, .mr, .rm64, .r64, .none, .none, &.{ 0x11 }, 0, .long }, - .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .none }, - .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .rex }, - .{ .adc, .rm, .r16, .rm16, .none, .none, &.{ 0x13 }, 0, .none }, - .{ .adc, .rm, .r32, .rm32, .none, .none, &.{ 0x13 }, 0, .none }, - .{ .adc, .rm, .r64, .rm64, .none, .none, &.{ 0x13 }, 0, .long }, - - .{ .add, .zi, .al, .imm8, .none, .none, &.{ 0x04 }, 0, .none }, - .{ .add, .zi, .ax, .imm16, .none, .none, &.{ 0x05 }, 0, .none }, - .{ .add, .zi, .eax, .imm32, .none, .none, &.{ 0x05 }, 0, .none }, - .{ .add, .zi, .rax, .imm32s, .none, .none, &.{ 0x05 }, 0, .long }, - .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .none }, - .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .rex }, - .{ .add, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 0, .none }, - .{ .add, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 0, .none }, - .{ .add, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 0, .long }, - .{ .add, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 0, .none }, - .{ .add, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 0, .none }, - .{ .add, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 0, .long }, - .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .none }, - .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .rex }, - .{ .add, .mr, .rm16, .r16, .none, .none, &.{ 0x01 }, 0, .none }, - .{ .add, .mr, .rm32, .r32, .none, .none, &.{ 0x01 }, 0, .none }, - .{ .add, .mr, .rm64, .r64, .none, .none, &.{ 0x01 }, 0, .long }, - .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .none }, - .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .rex }, - .{ .add, .rm, .r16, .rm16, .none, .none, &.{ 0x03 }, 0, .none }, - .{ .add, .rm, .r32, .rm32, .none, .none, &.{ 0x03 }, 0, .none }, - .{ .add, .rm, .r64, .rm64, .none, .none, &.{ 0x03 }, 0, .long }, - - .{ .@"and", .zi, .al, .imm8, .none, .none, &.{ 0x24 }, 0, .none }, - .{ .@"and", .zi, .ax, .imm16, .none, .none, &.{ 0x25 }, 0, .none }, - .{ .@"and", .zi, .eax, .imm32, .none, .none, &.{ 0x25 }, 0, .none }, - .{ .@"and", .zi, .rax, .imm32s, .none, .none, &.{ 0x25 }, 0, .long }, - .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .none }, - .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .rex }, - .{ .@"and", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 4, .none }, - .{ .@"and", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 4, .none }, - .{ .@"and", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 4, .long }, - .{ .@"and", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 4, .none }, - .{ .@"and", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 4, .none }, - .{ .@"and", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 4, .long }, - .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .none }, - .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .rex }, - .{ .@"and", .mr, .rm16, .r16, .none, .none, &.{ 0x21 }, 0, .none }, - .{ .@"and", .mr, .rm32, .r32, .none, .none, &.{ 0x21 }, 0, .none }, - .{ .@"and", .mr, .rm64, .r64, .none, .none, &.{ 0x21 }, 0, .long }, - .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .none }, - .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .rex }, - .{ .@"and", .rm, .r16, .rm16, .none, .none, &.{ 0x23 }, 0, .none }, - .{ .@"and", .rm, .r32, .rm32, .none, .none, &.{ 0x23 }, 0, .none }, - .{ .@"and", .rm, .r64, .rm64, .none, .none, &.{ 0x23 }, 0, .long }, - - .{ .bsf, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbc }, 0, .none }, - .{ .bsf, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbc }, 0, .none }, - .{ .bsf, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbc }, 0, .long }, - - .{ .bsr, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, - .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, - .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long }, - - .{ .bswap, .o, .r32, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .none }, - .{ .bswap, .o, .r64, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .long }, - - .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, - .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, - .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long }, - .{ .bt, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none }, - .{ .bt, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none }, - .{ .bt, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .long }, - - .{ .btc, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xbb }, 0, .none }, - .{ .btc, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xbb }, 0, .none }, - .{ .btc, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xbb }, 0, .long }, - .{ .btc, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none }, - .{ .btc, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none }, - .{ .btc, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .long }, - - .{ .btr, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none }, - .{ .btr, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none }, - .{ .btr, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb3 }, 0, .long }, - .{ .btr, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none }, - .{ .btr, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none }, - .{ .btr, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .long }, - - .{ .bts, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xab }, 0, .none }, - .{ .bts, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xab }, 0, .none }, - .{ .bts, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xab }, 0, .long }, - .{ .bts, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none }, - .{ .bts, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none }, - .{ .bts, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .long }, + .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none }, + .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .none }, + .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none }, + .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long }, + .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none }, + .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex }, + .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .none }, + .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none }, + .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long }, + .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .none }, + .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none }, + .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long }, + .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none }, + .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex }, + .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .none }, + .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none }, + .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long }, + .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none }, + .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex }, + .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .none }, + .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none }, + .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long }, + + .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none }, + .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .none }, + .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none }, + .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long }, + .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none }, + .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex }, + .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .none }, + .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none }, + .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long }, + .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .none }, + .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none }, + .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long }, + .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none }, + .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex }, + .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .none }, + .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none }, + .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long }, + .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none }, + .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex }, + .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .none }, + .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none }, + .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long }, + + .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none }, + .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .none }, + .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none }, + .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long }, + .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none }, + .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex }, + .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .none }, + .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none }, + .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long }, + .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .none }, + .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none }, + .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long }, + .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none }, + .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex }, + .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .none }, + .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none }, + .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long }, + .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none }, + .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex }, + .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .none }, + .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none }, + .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long }, + + .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .none }, + .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none }, + .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long }, + + .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .none }, + .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none }, + .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long }, + + .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none }, + .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long }, + + .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .none }, + .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none }, + .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long }, + .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .none }, + .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none }, + .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long }, + + .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .none }, + .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none }, + .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long }, + .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .none }, + .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none }, + .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long }, + + .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .none }, + .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none }, + .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long }, + .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .none }, + .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none }, + .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long }, + + .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .none }, + .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none }, + .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long }, + .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .none }, + .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none }, + .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long }, // This is M encoding according to Intel, but D makes more sense here. - .{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none }, - .{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none }, - - .{ .cbw, .np, .o16, .none, .none, .none, &.{ 0x98 }, 0, .none }, - .{ .cwde, .np, .o32, .none, .none, .none, &.{ 0x98 }, 0, .none }, - .{ .cdqe, .np, .o64, .none, .none, .none, &.{ 0x98 }, 0, .long }, - - .{ .cwd, .np, .o16, .none, .none, .none, &.{ 0x99 }, 0, .none }, - .{ .cdq, .np, .o32, .none, .none, .none, &.{ 0x99 }, 0, .none }, - .{ .cqo, .np, .o64, .none, .none, .none, &.{ 0x99 }, 0, .long }, - - .{ .cmova, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none }, - .{ .cmova, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none }, - .{ .cmova, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long }, - .{ .cmovae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none }, - .{ .cmovae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none }, - .{ .cmovae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long }, - .{ .cmovb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none }, - .{ .cmovb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none }, - .{ .cmovb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long }, - .{ .cmovbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none }, - .{ .cmovbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none }, - .{ .cmovbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long }, - .{ .cmovc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none }, - .{ .cmovc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none }, - .{ .cmovc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long }, - .{ .cmove, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none }, - .{ .cmove, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none }, - .{ .cmove, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long }, - .{ .cmovg, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none }, - .{ .cmovg, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none }, - .{ .cmovg, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long }, - .{ .cmovge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none }, - .{ .cmovge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none }, - .{ .cmovge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long }, - .{ .cmovl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none }, - .{ .cmovl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none }, - .{ .cmovl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long }, - .{ .cmovle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none }, - .{ .cmovle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none }, - .{ .cmovle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long }, - .{ .cmovna, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none }, - .{ .cmovna, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none }, - .{ .cmovna, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long }, - .{ .cmovnae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none }, - .{ .cmovnae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none }, - .{ .cmovnae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long }, - .{ .cmovnb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none }, - .{ .cmovnb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none }, - .{ .cmovnb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long }, - .{ .cmovnbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none }, - .{ .cmovnbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none }, - .{ .cmovnbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long }, - .{ .cmovnc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none }, - .{ .cmovnc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none }, - .{ .cmovnc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long }, - .{ .cmovne, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none }, - .{ .cmovne, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none }, - .{ .cmovne, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long }, - .{ .cmovng, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none }, - .{ .cmovng, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none }, - .{ .cmovng, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long }, - .{ .cmovnge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none }, - .{ .cmovnge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none }, - .{ .cmovnge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long }, - .{ .cmovnl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none }, - .{ .cmovnl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none }, - .{ .cmovnl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long }, - .{ .cmovnle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none }, - .{ .cmovnle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none }, - .{ .cmovnle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long }, - .{ .cmovno, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x41 }, 0, .none }, - .{ .cmovno, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x41 }, 0, .none }, - .{ .cmovno, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x41 }, 0, .long }, - .{ .cmovnp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none }, - .{ .cmovnp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none }, - .{ .cmovnp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long }, - .{ .cmovns, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x49 }, 0, .none }, - .{ .cmovns, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x49 }, 0, .none }, - .{ .cmovns, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x49 }, 0, .long }, - .{ .cmovnz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none }, - .{ .cmovnz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none }, - .{ .cmovnz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long }, - .{ .cmovo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x40 }, 0, .none }, - .{ .cmovo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x40 }, 0, .none }, - .{ .cmovo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x40 }, 0, .long }, - .{ .cmovp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none }, - .{ .cmovp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none }, - .{ .cmovp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long }, - .{ .cmovpe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none }, - .{ .cmovpe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none }, - .{ .cmovpe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long }, - .{ .cmovpo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none }, - .{ .cmovpo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none }, - .{ .cmovpo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long }, - .{ .cmovs, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x48 }, 0, .none }, - .{ .cmovs, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x48 }, 0, .none }, - .{ .cmovs, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x48 }, 0, .long }, - .{ .cmovz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none }, - .{ .cmovz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none }, - .{ .cmovz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long }, - - .{ .cmp, .zi, .al, .imm8, .none, .none, &.{ 0x3c }, 0, .none }, - .{ .cmp, .zi, .ax, .imm16, .none, .none, &.{ 0x3d }, 0, .none }, - .{ .cmp, .zi, .eax, .imm32, .none, .none, &.{ 0x3d }, 0, .none }, - .{ .cmp, .zi, .rax, .imm32s, .none, .none, &.{ 0x3d }, 0, .long }, - .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .none }, - .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .rex }, - .{ .cmp, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 7, .none }, - .{ .cmp, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 7, .none }, - .{ .cmp, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 7, .long }, - .{ .cmp, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 7, .none }, - .{ .cmp, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 7, .none }, - .{ .cmp, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 7, .long }, - .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .none }, - .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .rex }, - .{ .cmp, .mr, .rm16, .r16, .none, .none, &.{ 0x39 }, 0, .none }, - .{ .cmp, .mr, .rm32, .r32, .none, .none, &.{ 0x39 }, 0, .none }, - .{ .cmp, .mr, .rm64, .r64, .none, .none, &.{ 0x39 }, 0, .long }, - .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .none }, - .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .rex }, - .{ .cmp, .rm, .r16, .rm16, .none, .none, &.{ 0x3b }, 0, .none }, - .{ .cmp, .rm, .r32, .rm32, .none, .none, &.{ 0x3b }, 0, .none }, - .{ .cmp, .rm, .r64, .rm64, .none, .none, &.{ 0x3b }, 0, .long }, - - .{ .cmps, .np, .m8, .m8, .none, .none, &.{ 0xa6 }, 0, .none }, - .{ .cmps, .np, .m16, .m16, .none, .none, &.{ 0xa7 }, 0, .none }, - .{ .cmps, .np, .m32, .m32, .none, .none, &.{ 0xa7 }, 0, .none }, - .{ .cmps, .np, .m64, .m64, .none, .none, &.{ 0xa7 }, 0, .long }, - .{ .cmpsb, .np, .none, .none, .none, .none, &.{ 0xa6 }, 0, .none }, - .{ .cmpsw, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .short }, - .{ .cmpsd, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .none }, - .{ .cmpsq, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .long }, - - .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none }, - .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex }, - .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none }, - .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none }, - .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long }, - - .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none }, - .{ .cmpxchg16b, .m, .m128, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .long }, - - .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none }, - .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex }, - .{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none }, - .{ .div, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 6, .none }, - .{ .div, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 6, .long }, - - .{ .fisttp, .m, .m16, .none, .none, .none, &.{ 0xdf }, 1, .fpu }, - .{ .fisttp, .m, .m32, .none, .none, .none, &.{ 0xdb }, 1, .fpu }, - .{ .fisttp, .m, .m64, .none, .none, .none, &.{ 0xdd }, 1, .fpu }, - - .{ .fld, .m, .m32, .none, .none, .none, &.{ 0xd9 }, 0, .fpu }, - .{ .fld, .m, .m64, .none, .none, .none, &.{ 0xdd }, 0, .fpu }, - .{ .fld, .m, .m80, .none, .none, .none, &.{ 0xdb }, 5, .fpu }, - - .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .none }, - .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .rex }, - .{ .idiv, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 7, .none }, - .{ .idiv, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 7, .none }, - .{ .idiv, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 7, .long }, - - .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .none }, - .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .rex }, - .{ .imul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 5, .none }, - .{ .imul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 5, .none }, - .{ .imul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 5, .long }, - .{ .imul, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xaf }, 0, .none }, - .{ .imul, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xaf }, 0, .none }, - .{ .imul, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xaf }, 0, .long }, - .{ .imul, .rmi, .r16, .rm16, .imm8s, .none, &.{ 0x6b }, 0, .none }, - .{ .imul, .rmi, .r32, .rm32, .imm8s, .none, &.{ 0x6b }, 0, .none }, - .{ .imul, .rmi, .r64, .rm64, .imm8s, .none, &.{ 0x6b }, 0, .long }, - .{ .imul, .rmi, .r16, .rm16, .imm16, .none, &.{ 0x69 }, 0, .none }, - .{ .imul, .rmi, .r32, .rm32, .imm32, .none, &.{ 0x69 }, 0, .none }, - .{ .imul, .rmi, .r64, .rm64, .imm32, .none, &.{ 0x69 }, 0, .long }, - - .{ .int3, .np, .none, .none, .none, .none, &.{ 0xcc }, 0, .none }, - - .{ .ja, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none }, - .{ .jae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none }, - .{ .jb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none }, - .{ .jbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none }, - .{ .jc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none }, - .{ .jrcxz, .d, .rel32, .none, .none, .none, &.{ 0xe3 }, 0, .none }, - .{ .je, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none }, - .{ .jg, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none }, - .{ .jge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none }, - .{ .jl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none }, - .{ .jle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none }, - .{ .jna, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none }, - .{ .jnae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none }, - .{ .jnb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none }, - .{ .jnbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none }, - .{ .jnc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none }, - .{ .jne, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none }, - .{ .jng, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none }, - .{ .jnge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none }, - .{ .jnl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none }, - .{ .jnle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none }, - .{ .jno, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x81 }, 0, .none }, - .{ .jnp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none }, - .{ .jns, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x89 }, 0, .none }, - .{ .jnz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none }, - .{ .jo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x80 }, 0, .none }, - .{ .jp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none }, - .{ .jpe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none }, - .{ .jpo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none }, - .{ .js, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x88 }, 0, .none }, - .{ .jz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none }, - - .{ .jmp, .d, .rel32, .none, .none, .none, &.{ 0xe9 }, 0, .none }, - .{ .jmp, .m, .rm64, .none, .none, .none, &.{ 0xff }, 4, .none }, - - .{ .lea, .rm, .r16, .m, .none, .none, &.{ 0x8d }, 0, .none }, - .{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none }, - .{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long }, - - .{ .lfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xe8 }, 0, .none }, - - .{ .lods, .np, .m8, .none, .none, .none, &.{ 0xac }, 0, .none }, - .{ .lods, .np, .m16, .none, .none, .none, &.{ 0xad }, 0, .none }, - .{ .lods, .np, .m32, .none, .none, .none, &.{ 0xad }, 0, .none }, - .{ .lods, .np, .m64, .none, .none, .none, &.{ 0xad }, 0, .long }, - .{ .lodsb, .np, .none, .none, .none, .none, &.{ 0xac }, 0, .none }, - .{ .lodsw, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .short }, - .{ .lodsd, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .none }, - .{ .lodsq, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .long }, - - .{ .lzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none }, - .{ .lzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none }, - .{ .lzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .long }, - - .{ .mfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf0 }, 0, .none }, - - .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none }, - .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex }, - .{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none }, - .{ .mov, .mr, .rm32, .r32, .none, .none, &.{ 0x89 }, 0, .none }, - .{ .mov, .mr, .rm64, .r64, .none, .none, &.{ 0x89 }, 0, .long }, - .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .none }, - .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .rex }, - .{ .mov, .rm, .r16, .rm16, .none, .none, &.{ 0x8b }, 0, .none }, - .{ .mov, .rm, .r32, .rm32, .none, .none, &.{ 0x8b }, 0, .none }, - .{ .mov, .rm, .r64, .rm64, .none, .none, &.{ 0x8b }, 0, .long }, - .{ .mov, .mr, .rm16, .sreg, .none, .none, &.{ 0x8c }, 0, .none }, - .{ .mov, .mr, .rm64, .sreg, .none, .none, &.{ 0x8c }, 0, .long }, - .{ .mov, .rm, .sreg, .rm16, .none, .none, &.{ 0x8e }, 0, .none }, - .{ .mov, .rm, .sreg, .rm64, .none, .none, &.{ 0x8e }, 0, .long }, - .{ .mov, .fd, .al, .moffs, .none, .none, &.{ 0xa0 }, 0, .none }, - .{ .mov, .fd, .ax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none }, - .{ .mov, .fd, .eax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none }, - .{ .mov, .fd, .rax, .moffs, .none, .none, &.{ 0xa1 }, 0, .long }, - .{ .mov, .td, .moffs, .al, .none, .none, &.{ 0xa2 }, 0, .none }, - .{ .mov, .td, .moffs, .ax, .none, .none, &.{ 0xa3 }, 0, .none }, - .{ .mov, .td, .moffs, .eax, .none, .none, &.{ 0xa3 }, 0, .none }, - .{ .mov, .td, .moffs, .rax, .none, .none, &.{ 0xa3 }, 0, .long }, - .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .none }, - .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .rex }, - .{ .mov, .oi, .r16, .imm16, .none, .none, &.{ 0xb8 }, 0, .none }, - .{ .mov, .oi, .r32, .imm32, .none, .none, &.{ 0xb8 }, 0, .none }, - .{ .mov, .oi, .r64, .imm64, .none, .none, &.{ 0xb8 }, 0, .long }, - .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .none }, - .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .rex }, - .{ .mov, .mi, .rm16, .imm16, .none, .none, &.{ 0xc7 }, 0, .none }, - .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none }, - .{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long }, - - .{ .movbe, .rm, .r16, .m16, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none }, - .{ .movbe, .rm, .r32, .m32, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none }, - .{ .movbe, .rm, .r64, .m64, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .long }, - .{ .movbe, .mr, .m16, .r16, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none }, - .{ .movbe, .mr, .m32, .r32, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none }, - .{ .movbe, .mr, .m64, .r64, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .long }, - - .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none }, - .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none }, - .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none }, - .{ .movs, .np, .m64, .m64, .none, .none, &.{ 0xa5 }, 0, .long }, - .{ .movsb, .np, .none, .none, .none, .none, &.{ 0xa4 }, 0, .none }, - .{ .movsw, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .short }, - .{ .movsd, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .none }, - .{ .movsq, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .long }, - - .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none }, - .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex }, - .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none }, - .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex }, - .{ .movsx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .long }, - .{ .movsx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .none }, - .{ .movsx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .long }, + .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none }, + .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none }, + + .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .none }, + .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none }, + .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long }, + + .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .none }, + .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none }, + .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long }, + + .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none }, + .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none }, + .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long }, + .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none }, + .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none }, + .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long }, + .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none }, + .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none }, + .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long }, + .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none }, + .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none }, + .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long }, + .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none }, + .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none }, + .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long }, + .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none }, + .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none }, + .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long }, + .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none }, + .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none }, + .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long }, + .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none }, + .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none }, + .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long }, + .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none }, + .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none }, + .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long }, + .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none }, + .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none }, + .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long }, + .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none }, + .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none }, + .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long }, + .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none }, + .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none }, + .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long }, + .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none }, + .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none }, + .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long }, + .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none }, + .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none }, + .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long }, + .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none }, + .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none }, + .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long }, + .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none }, + .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none }, + .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long }, + .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none }, + .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none }, + .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long }, + .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none }, + .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none }, + .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long }, + .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none }, + .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none }, + .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long }, + .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none }, + .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none }, + .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long }, + .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .none }, + .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none }, + .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long }, + .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none }, + .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none }, + .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long }, + .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .none }, + .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none }, + .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long }, + .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none }, + .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none }, + .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long }, + .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .none }, + .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none }, + .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long }, + .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none }, + .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none }, + .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long }, + .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none }, + .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none }, + .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long }, + .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none }, + .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none }, + .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long }, + .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .none }, + .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none }, + .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long }, + .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none }, + .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none }, + .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long }, + + .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none }, + .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .none }, + .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none }, + .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long }, + .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none }, + .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex }, + .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .none }, + .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none }, + .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long }, + .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .none }, + .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none }, + .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long }, + .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none }, + .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex }, + .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .none }, + .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none }, + .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long }, + .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none }, + .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex }, + .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .none }, + .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none }, + .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long }, + + .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none }, + .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .none }, + .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none }, + .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long }, + + .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none }, + .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short }, + .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none }, + .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long }, + + .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none }, + .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex }, + .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .none }, + .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none }, + .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long }, + + .{ .cmpxchg8b , .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none }, + .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long }, + + .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none }, + .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex }, + .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .none }, + .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none }, + .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long }, + + .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .fpu }, + .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .fpu }, + .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .fpu }, + + .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .fpu }, + .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .fpu }, + .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .fpu }, + + .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none }, + .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex }, + .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .none }, + .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none }, + .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long }, + + .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none }, + .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex }, + .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .none }, + .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none }, + .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long }, + .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .none }, + .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none }, + .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long }, + .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .none }, + .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none }, + .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long }, + .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .none }, + .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none }, + .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long }, + + .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none }, + + .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none }, + .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none }, + .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none }, + .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none }, + .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none }, + .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none }, + .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none }, + .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none }, + .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none }, + .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none }, + .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none }, + .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none }, + .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none }, + .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none }, + .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none }, + .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none }, + .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none }, + .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none }, + .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none }, + .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none }, + .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none }, + .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none }, + .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none }, + .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none }, + .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none }, + .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none }, + .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none }, + .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none }, + .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none }, + .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none }, + .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none }, + + .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none }, + .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none }, + + .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .none }, + .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none }, + .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long }, + + .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none }, + + .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none }, + .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .none }, + .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none }, + .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long }, + + .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none }, + .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short }, + .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none }, + .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long }, + + .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none }, + .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none }, + .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long }, + + .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none }, + + .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none }, + .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex }, + .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .none }, + .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none }, + .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long }, + .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none }, + .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex }, + .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .none }, + .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none }, + .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long }, + .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .none }, + .{ .mov, .mr, &.{ .rm64, .sreg }, &.{ 0x8c }, 0, .long }, + .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .none }, + .{ .mov, .rm, &.{ .sreg, .rm64 }, &.{ 0x8e }, 0, .long }, + .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none }, + .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none }, + .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none }, + .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long }, + .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none }, + .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none }, + .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none }, + .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long }, + .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none }, + .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex }, + .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .none }, + .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none }, + .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long }, + .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none }, + .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex }, + .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .none }, + .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none }, + .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long }, + + .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none }, + .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none }, + .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long }, + .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none }, + .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none }, + .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long }, + + .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none }, + .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .none }, + .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none }, + .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long }, + + .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none }, + .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short }, + .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none }, + .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long }, + + .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none }, + .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex }, + .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none }, + .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex }, + .{ .movsx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xbe }, 0, .long }, + .{ .movsx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xbf }, 0, .none }, + .{ .movsx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xbf }, 0, .long }, // This instruction is discouraged. - .{ .movsxd, .rm, .r32, .rm32, .none, .none, &.{ 0x63 }, 0, .none }, - .{ .movsxd, .rm, .r64, .rm32, .none, .none, &.{ 0x63 }, 0, .long }, - - .{ .movzx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none }, - .{ .movzx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none }, - .{ .movzx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .long }, - .{ .movzx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .none }, - .{ .movzx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .long }, - - .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .none }, - .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .rex }, - .{ .mul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 4, .none }, - .{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none }, - .{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long }, - - .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .none }, - .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .rex }, - .{ .neg, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 3, .none }, - .{ .neg, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 3, .none }, - .{ .neg, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 3, .long }, - - .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none }, - - .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .none }, - .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .rex }, - .{ .not, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 2, .none }, - .{ .not, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 2, .none }, - .{ .not, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 2, .long }, - - .{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none }, - .{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none }, - .{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none }, - .{ .@"or", .zi, .rax, .imm32s, .none, .none, &.{ 0x0d }, 0, .long }, - .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .none }, - .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .rex }, - .{ .@"or", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 1, .none }, - .{ .@"or", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 1, .none }, - .{ .@"or", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 1, .long }, - .{ .@"or", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 1, .none }, - .{ .@"or", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 1, .none }, - .{ .@"or", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 1, .long }, - .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .none }, - .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .rex }, - .{ .@"or", .mr, .rm16, .r16, .none, .none, &.{ 0x09 }, 0, .none }, - .{ .@"or", .mr, .rm32, .r32, .none, .none, &.{ 0x09 }, 0, .none }, - .{ .@"or", .mr, .rm64, .r64, .none, .none, &.{ 0x09 }, 0, .long }, - .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .none }, - .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .rex }, - .{ .@"or", .rm, .r16, .rm16, .none, .none, &.{ 0x0b }, 0, .none }, - .{ .@"or", .rm, .r32, .rm32, .none, .none, &.{ 0x0b }, 0, .none }, - .{ .@"or", .rm, .r64, .rm64, .none, .none, &.{ 0x0b }, 0, .long }, - - .{ .pop, .o, .r16, .none, .none, .none, &.{ 0x58 }, 0, .none }, - .{ .pop, .o, .r64, .none, .none, .none, &.{ 0x58 }, 0, .none }, - .{ .pop, .m, .rm16, .none, .none, .none, &.{ 0x8f }, 0, .none }, - .{ .pop, .m, .rm64, .none, .none, .none, &.{ 0x8f }, 0, .none }, - - .{ .popcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none }, - .{ .popcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none }, - .{ .popcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long }, - - .{ .push, .o, .r16, .none, .none, .none, &.{ 0x50 }, 0, .none }, - .{ .push, .o, .r64, .none, .none, .none, &.{ 0x50 }, 0, .none }, - .{ .push, .m, .rm16, .none, .none, .none, &.{ 0xff }, 6, .none }, - .{ .push, .m, .rm64, .none, .none, .none, &.{ 0xff }, 6, .none }, - .{ .push, .i, .imm8, .none, .none, .none, &.{ 0x6a }, 0, .none }, - .{ .push, .i, .imm16, .none, .none, .none, &.{ 0x68 }, 0, .none }, - .{ .push, .i, .imm32, .none, .none, .none, &.{ 0x68 }, 0, .none }, - - .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none }, - - .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .none }, - .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .rex }, - .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .none }, - .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .rex }, - .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .none }, - .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .rex }, - .{ .rcl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 2, .none }, - .{ .rcl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 2, .none }, - .{ .rcl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 2, .none }, - .{ .rcl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 2, .none }, - .{ .rcl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 2, .long }, - .{ .rcl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 2, .none }, - .{ .rcl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 2, .long }, - .{ .rcl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 2, .none }, - .{ .rcl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 2, .long }, - - .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .none }, - .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .rex }, - .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .none }, - .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .rex }, - .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .none }, - .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .rex }, - .{ .rcr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 3, .none }, - .{ .rcr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 3, .none }, - .{ .rcr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 3, .none }, - .{ .rcr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 3, .none }, - .{ .rcr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 3, .long }, - .{ .rcr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 3, .none }, - .{ .rcr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 3, .long }, - .{ .rcr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 3, .none }, - .{ .rcr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 3, .long }, - - .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .none }, - .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .rex }, - .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .none }, - .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .rex }, - .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .none }, - .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .rex }, - .{ .rol, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 0, .none }, - .{ .rol, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 0, .none }, - .{ .rol, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 0, .none }, - .{ .rol, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 0, .none }, - .{ .rol, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 0, .long }, - .{ .rol, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 0, .none }, - .{ .rol, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 0, .long }, - .{ .rol, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 0, .none }, - .{ .rol, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 0, .long }, - - .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .none }, - .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .rex }, - .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .none }, - .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .rex }, - .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .none }, - .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .rex }, - .{ .ror, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 1, .none }, - .{ .ror, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 1, .none }, - .{ .ror, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 1, .none }, - .{ .ror, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 1, .none }, - .{ .ror, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 1, .long }, - .{ .ror, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 1, .none }, - .{ .ror, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 1, .long }, - .{ .ror, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 1, .none }, - .{ .ror, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 1, .long }, - - .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none }, - .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex }, - .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, - .{ .sal, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, - .{ .sal, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long }, - .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none }, - .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex }, - .{ .sal, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none }, - .{ .sal, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none }, - .{ .sal, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long }, - .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none }, - .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex }, - .{ .sal, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none }, - .{ .sal, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none }, - .{ .sal, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long }, - - .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .none }, - .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .rex }, - .{ .sar, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 7, .none }, - .{ .sar, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 7, .none }, - .{ .sar, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 7, .long }, - .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .none }, - .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .rex }, - .{ .sar, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 7, .none }, - .{ .sar, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 7, .none }, - .{ .sar, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 7, .long }, - .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .none }, - .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .rex }, - .{ .sar, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 7, .none }, - .{ .sar, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 7, .none }, - .{ .sar, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 7, .long }, - - .{ .sbb, .zi, .al, .imm8, .none, .none, &.{ 0x1c }, 0, .none }, - .{ .sbb, .zi, .ax, .imm16, .none, .none, &.{ 0x1d }, 0, .none }, - .{ .sbb, .zi, .eax, .imm32, .none, .none, &.{ 0x1d }, 0, .none }, - .{ .sbb, .zi, .rax, .imm32s, .none, .none, &.{ 0x1d }, 0, .long }, - .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .none }, - .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .rex }, - .{ .sbb, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 3, .none }, - .{ .sbb, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 3, .none }, - .{ .sbb, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 3, .long }, - .{ .sbb, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 3, .none }, - .{ .sbb, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 3, .none }, - .{ .sbb, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 3, .long }, - .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .none }, - .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .rex }, - .{ .sbb, .mr, .rm16, .r16, .none, .none, &.{ 0x19 }, 0, .none }, - .{ .sbb, .mr, .rm32, .r32, .none, .none, &.{ 0x19 }, 0, .none }, - .{ .sbb, .mr, .rm64, .r64, .none, .none, &.{ 0x19 }, 0, .long }, - .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .none }, - .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .rex }, - .{ .sbb, .rm, .r16, .rm16, .none, .none, &.{ 0x1b }, 0, .none }, - .{ .sbb, .rm, .r32, .rm32, .none, .none, &.{ 0x1b }, 0, .none }, - .{ .sbb, .rm, .r64, .rm64, .none, .none, &.{ 0x1b }, 0, .long }, - - .{ .scas, .np, .m8, .none, .none, .none, &.{ 0xae }, 0, .none }, - .{ .scas, .np, .m16, .none, .none, .none, &.{ 0xaf }, 0, .none }, - .{ .scas, .np, .m32, .none, .none, .none, &.{ 0xaf }, 0, .none }, - .{ .scas, .np, .m64, .none, .none, .none, &.{ 0xaf }, 0, .long }, - .{ .scasb, .np, .none, .none, .none, .none, &.{ 0xae }, 0, .none }, - .{ .scasw, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .short }, - .{ .scasd, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .none }, - .{ .scasq, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .long }, - - .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none }, - .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex }, - .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none }, - .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex }, - .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none }, - .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex }, - .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none }, - .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex }, - .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none }, - .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex }, - .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none }, - .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex }, - .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none }, - .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex }, - .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none }, - .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex }, - .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none }, - .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex }, - .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none }, - .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex }, - .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none }, - .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex }, - .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none }, - .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex }, - .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none }, - .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex }, - .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none }, - .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex }, - .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none }, - .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex }, - .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none }, - .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex }, - .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none }, - .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex }, - .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none }, - .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex }, - .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none }, - .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex }, - .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none }, - .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex }, - .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .none }, - .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .rex }, - .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none }, - .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex }, - .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .none }, - .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .rex }, - .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none }, - .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex }, - .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .none }, - .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .rex }, - .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none }, - .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex }, - .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none }, - .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex }, - .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none }, - .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex }, - .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .none }, - .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .rex }, - .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none }, - .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex }, - - .{ .sfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf8 }, 0, .none }, - - .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none }, - .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex }, - .{ .shl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, - .{ .shl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, - .{ .shl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long }, - .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none }, - .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex }, - .{ .shl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none }, - .{ .shl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none }, - .{ .shl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long }, - .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none }, - .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex }, - .{ .shl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none }, - .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none }, - .{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long }, - - .{ .shld, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none }, - .{ .shld, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none }, - .{ .shld, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none }, - .{ .shld, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .long }, - .{ .shld, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none }, - .{ .shld, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .long }, - - .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none }, - .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex }, - .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none }, - .{ .shr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 5, .none }, - .{ .shr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 5, .long }, - .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .none }, - .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .rex }, - .{ .shr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 5, .none }, - .{ .shr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 5, .none }, - .{ .shr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 5, .long }, - .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .none }, - .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .rex }, - .{ .shr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 5, .none }, - .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none }, - .{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long }, - - .{ .shrd, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none }, - .{ .shrd, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xad }, 0, .none }, - .{ .shrd, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none }, - .{ .shrd, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xac }, 0, .long }, - .{ .shrd, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xad }, 0, .none }, - .{ .shrd, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xad }, 0, .long }, - - .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none }, - .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none }, - .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none }, - .{ .stos, .np, .m64, .none, .none, .none, &.{ 0xab }, 0, .long }, - .{ .stosb, .np, .none, .none, .none, .none, &.{ 0xaa }, 0, .none }, - .{ .stosw, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .short }, - .{ .stosd, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .none }, - .{ .stosq, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .long }, - - .{ .sub, .zi, .al, .imm8, .none, .none, &.{ 0x2c }, 0, .none }, - .{ .sub, .zi, .ax, .imm16, .none, .none, &.{ 0x2d }, 0, .none }, - .{ .sub, .zi, .eax, .imm32, .none, .none, &.{ 0x2d }, 0, .none }, - .{ .sub, .zi, .rax, .imm32s, .none, .none, &.{ 0x2d }, 0, .long }, - .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .none }, - .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .rex }, - .{ .sub, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 5, .none }, - .{ .sub, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 5, .none }, - .{ .sub, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 5, .long }, - .{ .sub, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 5, .none }, - .{ .sub, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 5, .none }, - .{ .sub, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 5, .long }, - .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .none }, - .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .rex }, - .{ .sub, .mr, .rm16, .r16, .none, .none, &.{ 0x29 }, 0, .none }, - .{ .sub, .mr, .rm32, .r32, .none, .none, &.{ 0x29 }, 0, .none }, - .{ .sub, .mr, .rm64, .r64, .none, .none, &.{ 0x29 }, 0, .long }, - .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .none }, - .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .rex }, - .{ .sub, .rm, .r16, .rm16, .none, .none, &.{ 0x2b }, 0, .none }, - .{ .sub, .rm, .r32, .rm32, .none, .none, &.{ 0x2b }, 0, .none }, - .{ .sub, .rm, .r64, .rm64, .none, .none, &.{ 0x2b }, 0, .long }, - - .{ .syscall, .np, .none, .none, .none, .none, &.{ 0x0f, 0x05 }, 0, .none } + .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none }, + .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long }, + + .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none }, + .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none }, + .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long }, + .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none }, + .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long }, + + .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none }, + .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex }, + .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .none }, + .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none }, + .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long }, + + .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none }, + .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex }, + .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .none }, + .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none }, + .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long }, + + .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none }, + + .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none }, + .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex }, + .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .none }, + .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none }, + .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long }, + + .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none }, + .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .none }, + .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none }, + .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long }, + .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none }, + .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex }, + .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .none }, + .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none }, + .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long }, + .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .none }, + .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none }, + .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long }, + .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none }, + .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex }, + .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .none }, + .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none }, + .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long }, + .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none }, + .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex }, + .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .none }, + .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none }, + .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long }, + + .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .none }, + .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none }, + .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .none }, + .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none }, + + .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none }, + .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none }, + .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long }, + + .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .none }, + .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none }, + .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .none }, + .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none }, + .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none }, + .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .none }, + .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none }, + + .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none }, + + .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none }, + .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex }, + .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none }, + .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex }, + .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none }, + .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex }, + .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .none }, + .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .none }, + .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .none }, + .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none }, + .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long }, + .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none }, + .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long }, + .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none }, + .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long }, + + .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none }, + .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex }, + .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none }, + .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex }, + .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none }, + .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex }, + .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .none }, + .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .none }, + .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .none }, + .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none }, + .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long }, + .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none }, + .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long }, + .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none }, + .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long }, + + .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none }, + .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex }, + .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none }, + .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex }, + .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none }, + .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex }, + .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .none }, + .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .none }, + .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .none }, + .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none }, + .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long }, + .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none }, + .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long }, + .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none }, + .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long }, + + .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none }, + .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex }, + .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none }, + .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex }, + .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none }, + .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex }, + .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .none }, + .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .none }, + .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .none }, + .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none }, + .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long }, + .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none }, + .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long }, + .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none }, + .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long }, + + .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none }, + .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex }, + .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none }, + .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none }, + .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long }, + .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none }, + .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex }, + .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none }, + .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none }, + .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long }, + .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none }, + .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex }, + .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none }, + .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none }, + .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long }, + + .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none }, + .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex }, + .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .none }, + .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none }, + .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long }, + .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none }, + .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex }, + .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .none }, + .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none }, + .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long }, + .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none }, + .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex }, + .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .none }, + .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none }, + .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long }, + + .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none }, + .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .none }, + .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none }, + .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long }, + .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none }, + .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex }, + .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .none }, + .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none }, + .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long }, + .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .none }, + .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none }, + .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long }, + .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none }, + .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex }, + .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .none }, + .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none }, + .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long }, + .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none }, + .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex }, + .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .none }, + .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none }, + .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long }, + + .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none }, + .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .none }, + .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none }, + .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long }, + + .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none }, + .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short }, + .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none }, + .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long }, + + .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none }, + .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex }, + .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none }, + .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex }, + .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none }, + .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex }, + .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none }, + .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex }, + .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none }, + .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex }, + .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none }, + .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex }, + .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none }, + .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex }, + .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none }, + .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex }, + .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none }, + .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex }, + .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none }, + .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex }, + .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none }, + .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex }, + .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none }, + .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex }, + .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none }, + .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex }, + .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none }, + .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex }, + .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none }, + .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex }, + .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none }, + .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex }, + .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none }, + .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex }, + .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none }, + .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex }, + .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none }, + .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex }, + .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none }, + .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex }, + .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none }, + .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex }, + .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none }, + .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex }, + .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none }, + .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex }, + .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none }, + .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex }, + .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none }, + .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex }, + .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none }, + .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex }, + .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none }, + .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex }, + .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none }, + .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex }, + .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none }, + .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex }, + .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none }, + .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex }, + + .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none }, + + .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none }, + .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex }, + .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none }, + .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none }, + .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long }, + .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none }, + .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex }, + .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none }, + .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none }, + .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long }, + .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none }, + .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex }, + .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none }, + .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none }, + .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long }, + + .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none }, + .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .none }, + .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none }, + .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long }, + .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none }, + .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long }, + + .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none }, + .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex }, + .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .none }, + .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none }, + .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long }, + .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none }, + .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex }, + .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .none }, + .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none }, + .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long }, + .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none }, + .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex }, + .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .none }, + .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none }, + .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long }, + + .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .none }, + .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .none }, + .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none }, + .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long }, + .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none }, + .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long }, + + .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none }, + .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .none }, + .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none }, + .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long }, + + .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none }, + .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short }, + .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none }, + .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long }, + + .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none }, + .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .none }, + .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none }, + .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long }, + .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none }, + .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex }, + .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .none }, + .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none }, + .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long }, + .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .none }, + .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none }, + .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long }, + .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none }, + .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex }, + .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .none }, + .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none }, + .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long }, + .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none }, + .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex }, + .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .none }, + .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none }, + .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long }, + + .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none } , - .{ .@"test", .zi, .al, .imm8, .none, .none, &.{ 0xa8 }, 0, .none }, - .{ .@"test", .zi, .ax, .imm16, .none, .none, &.{ 0xa9 }, 0, .none }, - .{ .@"test", .zi, .eax, .imm32, .none, .none, &.{ 0xa9 }, 0, .none }, - .{ .@"test", .zi, .rax, .imm32s, .none, .none, &.{ 0xa9 }, 0, .long }, - .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .none }, - .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .rex }, - .{ .@"test", .mi, .rm16, .imm16, .none, .none, &.{ 0xf7 }, 0, .none }, - .{ .@"test", .mi, .rm32, .imm32, .none, .none, &.{ 0xf7 }, 0, .none }, - .{ .@"test", .mi, .rm64, .imm32s, .none, .none, &.{ 0xf7 }, 0, .long }, - .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .none }, - .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .rex }, - .{ .@"test", .mr, .rm16, .r16, .none, .none, &.{ 0x85 }, 0, .none }, - .{ .@"test", .mr, .rm32, .r32, .none, .none, &.{ 0x85 }, 0, .none }, - .{ .@"test", .mr, .rm64, .r64, .none, .none, &.{ 0x85 }, 0, .long }, - - .{ .tzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none }, - .{ .tzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none }, - .{ .tzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .long }, - - .{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none }, - - .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .none }, - .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .rex }, - .{ .xadd, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none }, - .{ .xadd, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none }, - .{ .xadd, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xc1 }, 0, .long }, - - .{ .xchg, .o, .ax, .r16, .none, .none, &.{ 0x90 }, 0, .none }, - .{ .xchg, .o, .r16, .ax, .none, .none, &.{ 0x90 }, 0, .none }, - .{ .xchg, .o, .eax, .r32, .none, .none, &.{ 0x90 }, 0, .none }, - .{ .xchg, .o, .rax, .r64, .none, .none, &.{ 0x90 }, 0, .long }, - .{ .xchg, .o, .r32, .eax, .none, .none, &.{ 0x90 }, 0, .none }, - .{ .xchg, .o, .r64, .rax, .none, .none, &.{ 0x90 }, 0, .long }, - .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .none }, - .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .rex }, - .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .none }, - .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .rex }, - .{ .xchg, .mr, .rm16, .r16, .none, .none, &.{ 0x87 }, 0, .none }, - .{ .xchg, .rm, .r16, .rm16, .none, .none, &.{ 0x87 }, 0, .none }, - .{ .xchg, .mr, .rm32, .r32, .none, .none, &.{ 0x87 }, 0, .none }, - .{ .xchg, .mr, .rm64, .r64, .none, .none, &.{ 0x87 }, 0, .long }, - .{ .xchg, .rm, .r32, .rm32, .none, .none, &.{ 0x87 }, 0, .none }, - .{ .xchg, .rm, .r64, .rm64, .none, .none, &.{ 0x87 }, 0, .long }, - - .{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none }, - .{ .xor, .zi, .ax, .imm16, .none, .none, &.{ 0x35 }, 0, .none }, - .{ .xor, .zi, .eax, .imm32, .none, .none, &.{ 0x35 }, 0, .none }, - .{ .xor, .zi, .rax, .imm32s, .none, .none, &.{ 0x35 }, 0, .long }, - .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .none }, - .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .rex }, - .{ .xor, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 6, .none }, - .{ .xor, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 6, .none }, - .{ .xor, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 6, .long }, - .{ .xor, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 6, .none }, - .{ .xor, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 6, .none }, - .{ .xor, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 6, .long }, - .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .none }, - .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .rex }, - .{ .xor, .mr, .rm16, .r16, .none, .none, &.{ 0x31 }, 0, .none }, - .{ .xor, .mr, .rm32, .r32, .none, .none, &.{ 0x31 }, 0, .none }, - .{ .xor, .mr, .rm64, .r64, .none, .none, &.{ 0x31 }, 0, .long }, - .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .none }, - .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .rex }, - .{ .xor, .rm, .r16, .rm16, .none, .none, &.{ 0x33 }, 0, .none }, - .{ .xor, .rm, .r32, .rm32, .none, .none, &.{ 0x33 }, 0, .none }, - .{ .xor, .rm, .r64, .rm64, .none, .none, &.{ 0x33 }, 0, .long }, + .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none }, + .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .none }, + .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none }, + .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long }, + .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none }, + .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex }, + .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .none }, + .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none }, + .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long }, + .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none }, + .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex }, + .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .none }, + .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none }, + .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long }, + + .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none }, + .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none }, + .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long }, + + .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none }, + + .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none }, + .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex }, + .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .none }, + .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none }, + .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long }, + + .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .none }, + .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .none }, + .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none }, + .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long }, + .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none }, + .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long }, + .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none }, + .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex }, + .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none }, + .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex }, + .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .none }, + .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .none }, + .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none }, + .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long }, + .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none }, + .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long }, + + .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none }, + .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .none }, + .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none }, + .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long }, + .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none }, + .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex }, + .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .none }, + .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none }, + .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long }, + .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .none }, + .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none }, + .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long }, + .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none }, + .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex }, + .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .none }, + .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none }, + .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long }, + .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none }, + .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .rex }, + .{ .xor, .rm, &.{ .r16, .rm16 }, &.{ 0x33 }, 0, .none }, + .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none }, + .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long }, // SSE - .{ .addss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x58 }, 0, .sse }, + .{ .addss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x58 }, 0, .sse }, - .{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse }, + .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse }, - .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, + .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, - .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, + .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, - .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse }, + .{ .minss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse }, - .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse }, - .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse }, + .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse }, + .{ .movss, .mr, &.{ .xmm_m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse }, - .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse }, + .{ .mulss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse }, - .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse }, + .{ .subss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse }, - .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0x0f, 0x2e }, 0, .sse }, + .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse }, // SSE2 - .{ .addsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 }, + .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 }, - .{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 }, + .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 }, - .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, + .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, - .{ .maxsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, + .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, - .{ .minsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 }, + .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 }, - .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 }, - .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 }, + .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 }, + .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 }, - .{ .mulsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 }, + .{ .mulsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 }, - .{ .subsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 }, + .{ .subsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 }, - .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 }, - .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 }, + .{ .movsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 }, + .{ .movsd, .mr, &.{ .xmm_m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 }, - .{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, + .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, // SSE4.1 - .{ .roundss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 }, - .{ .roundsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 }, + .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 }, + .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 }, }; // zig fmt: on -- cgit v1.2.3