Commit abb37a7cb8

Jacob Young <jacobly0@users.noreply.github.com>
2023-03-27 03:33:56
x86_64: factor out lowering from emitting
1 parent 0e5e001
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,
         };
     }
 };
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.
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");
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);
         }
     }
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;
+};
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
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;
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,
+        } };
     }
 };