Commit bc43cee775

Jakub Konka <kubkon@jakubkonka.com>
2023-03-07 12:57:06
Get more things passing
1 parent ea3b3e9
src/arch/x86_64/bits.zig
@@ -207,7 +207,7 @@ pub const Register = enum(u7) {
         return @intCast(u6, @enumToInt(reg) - base);
     }
 
-    pub fn size(reg: Register) u32 {
+    pub fn bitSize(reg: Register) u64 {
         return switch (@enumToInt(reg)) {
             // zig fmt: off
             @enumToInt(Register.rax)  ... @enumToInt(Register.r15)   => 64,
@@ -273,7 +273,7 @@ pub const Register = enum(u7) {
         return @truncate(u3, reg.enc());
     }
 
-    pub fn toSize(reg: Register, bit_size: u32) Register {
+    pub fn toBitSize(reg: Register, bit_size: u64) Register {
         return switch (bit_size) {
             8 => reg.to8(),
             16 => reg.to16(),
@@ -334,7 +334,17 @@ pub const Register = enum(u7) {
 
     pub fn dwarfLocOp(reg: Register) u8 {
         return switch (reg.class()) {
-            .general_purpose => @intCast(u8, @enumToInt(reg) - reg.gpBase()) + DW.OP.reg0,
+            .general_purpose => switch (reg.to64()) {
+                .rax => DW.OP.reg0,
+                .rdx => DW.OP.reg1,
+                .rcx => DW.OP.reg2,
+                .rbx => DW.OP.reg3,
+                .rsi => DW.OP.reg4,
+                .rdi => DW.OP.reg5,
+                .rbp => DW.OP.reg6,
+                .rsp => DW.OP.reg7,
+                else => @intCast(u8, @enumToInt(reg) - reg.gpBase()) + DW.OP.reg0,
+            },
             .floating_point => @intCast(u8, @enumToInt(reg) - reg.fpBase()) + DW.OP.reg17,
             else => unreachable,
         };
@@ -345,7 +355,17 @@ pub const Register = enum(u7) {
     /// register to a given signed offset.
     pub fn dwarfLocOpDeref(reg: Register) u8 {
         return switch (reg.class()) {
-            .general_purpose => @intCast(u8, @enumToInt(reg) - reg.gpBase()) + DW.OP.breg0,
+            .general_purpose => switch (reg.to64()) {
+                .rax => DW.OP.breg0,
+                .rdx => DW.OP.breg1,
+                .rcx => DW.OP.breg2,
+                .rbx => DW.OP.breg3,
+                .rsi => DW.OP.breg4,
+                .rdi => DW.OP.breg5,
+                .rbp => DW.OP.breg6,
+                .rsp => DW.OP.breg7,
+                else => @intCast(u8, @enumToInt(reg) - reg.gpBase()) + DW.OP.breg0,
+            },
             .floating_point => @intCast(u8, @enumToInt(reg) - reg.fpBase()) + DW.OP.breg17,
             else => unreachable,
         };
@@ -397,7 +417,7 @@ pub const Memory = union(enum) {
         qword,
         tbyte,
 
-        pub fn fromSize(bit_size: u32) PtrSize {
+        pub fn fromBitSize(bit_size: u64) PtrSize {
             return switch (bit_size) {
                 8 => .byte,
                 16 => .word,
@@ -408,7 +428,7 @@ pub const Memory = union(enum) {
             };
         }
 
-        pub fn size(s: PtrSize) u32 {
+        pub fn bitSize(s: PtrSize) u64 {
             return switch (s) {
                 .byte => 8,
                 .word => 16,
@@ -481,11 +501,42 @@ pub const Memory = union(enum) {
         };
     }
 
-    pub fn size(mem: Memory) u32 {
+    pub fn bitSize(mem: Memory) u64 {
         return switch (mem) {
-            .rip => |r| r.ptr_size.size(),
-            .sib => |s| s.ptr_size.size(),
+            .rip => |r| r.ptr_size.bitSize(),
+            .sib => |s| s.ptr_size.bitSize(),
             .moffs => unreachable,
         };
     }
 };
+
+pub const Immediate = union(enum) {
+    signed: i32,
+    unsigned: u64,
+
+    pub fn u(x: u64) Immediate {
+        return .{ .unsigned = x };
+    }
+
+    pub fn s(x: i32) Immediate {
+        return .{ .signed = x };
+    }
+
+    pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {
+        return switch (imm) {
+            .signed => |x| switch (bit_size) {
+                8 => @bitCast(u8, @intCast(i8, x)),
+                16 => @bitCast(u16, @intCast(i16, x)),
+                32 => @bitCast(u32, @intCast(i32, x)),
+                else => unreachable,
+            },
+            .unsigned => |x| switch (bit_size) {
+                8 => @intCast(u8, x),
+                16 => @intCast(u16, x),
+                32 => @intCast(u32, x),
+                64 => x,
+                else => unreachable,
+            },
+        };
+    }
+};
src/arch/x86_64/CodeGen.zig
@@ -852,10 +852,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
     branch.inst_table.putAssumeCapacity(inst, .dead);
     switch (prev_value) {
         .register => |reg| {
-            self.register_manager.freeReg(reg.to64());
+            self.register_manager.freeReg(reg);
         },
         .register_overflow => |ro| {
-            self.register_manager.freeReg(ro.reg.to64());
+            self.register_manager.freeReg(ro.reg);
             self.eflags_inst = null;
         },
         .eflags => {
@@ -1253,7 +1253,13 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
         };
         defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
 
-        const mask = ~@as(u64, 0);
+        const mask = switch (operand_ty.abiSize(self.target.*)) {
+            1 => ~@as(u8, 0),
+            2 => ~@as(u16, 0),
+            4 => ~@as(u32, 0),
+            8 => ~@as(u64, 0),
+            else => unreachable,
+        };
         try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = mask });
 
         break :result dst_mcv;
@@ -2777,15 +2783,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                         1, 2, 4 => {
                             // TODO this is wasteful!
                             // introduce new MIR tag specifically for mov [reg + 0], imm
-                            const operand = switch (abi_size) {
-                                1 => @truncate(u8, imm),
-                                2 => @truncate(u16, imm),
-                                4 => @truncate(u32, imm),
-                                else => unreachable,
-                            };
                             const payload = try self.addExtra(Mir.ImmPair{
                                 .dest_off = 0,
-                                .operand = operand,
+                                .operand = @intCast(u32, imm),
                             });
                             _ = try self.addInst(.{
                                 .tag = .mov_mem_imm,
@@ -2896,17 +2896,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                         return self.fail("TODO saving imm to memory for abi_size {}", .{abi_size});
                     }
 
-                    const operand = switch (abi_size) {
-                        1 => @truncate(u8, imm),
-                        2 => @truncate(u16, imm),
-                        4 => @truncate(u32, imm),
-                        8 => @truncate(u32, imm),
-                        else => unreachable,
-                    };
                     const payload = try self.addExtra(Mir.ImmPair{
                         .dest_off = 0,
                         // TODO check if this logic is correct
-                        .operand = operand,
+                        .operand = @intCast(u32, imm),
                     });
                     const flags: u2 = switch (abi_size) {
                         1 => 0b00,
@@ -3102,8 +3095,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
                 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
 
-                // Mask with reg.size() - struct_field_size
-                const max_reg_bit_width = Register.rax.size();
+                // Mask with reg.bitSize() - struct_field_size
+                const max_reg_bit_width = Register.rax.bitSize();
                 const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*)));
                 const mask = (~@as(u64, 0)) >> mask_shift;
 
@@ -3631,13 +3624,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
                     _ = try self.addInst(.{
                         .tag = mir_tag,
                         .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size) }),
-                        .data = .{ .imm = switch (abi_size) {
-                            1 => @truncate(u8, imm),
-                            2 => @truncate(u16, imm),
-                            4 => @truncate(u32, imm),
-                            8 => @truncate(u32, imm),
-                            else => unreachable,
-                        } },
+                        .data = .{ .imm = @intCast(u32, imm) },
                     });
                 },
                 .memory,
@@ -3708,16 +3695,9 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
                         8 => 0b11,
                         else => unreachable,
                     };
-                    const operand = switch (abi_size) {
-                        1 => @truncate(u8, imm),
-                        2 => @truncate(u16, imm),
-                        4 => @truncate(u32, imm),
-                        8 => @truncate(u32, imm),
-                        else => unreachable,
-                    };
                     const payload = try self.addExtra(Mir.ImmPair{
                         .dest_off = -off,
-                        .operand = operand,
+                        .operand = @intCast(u32, imm),
                     });
                     _ = try self.addInst(.{
                         .tag = tag,
@@ -3791,7 +3771,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
                                 .reg2 = dst_reg.to32(),
                                 .flags = 0b10,
                             }),
-                            .data = .{ .imm = @truncate(u32, imm) },
+                            .data = .{ .imm = @intCast(u32, imm) },
                         });
                     } else {
                         // TODO verify we don't spill and assign to the same register as dst_mcv
@@ -4899,13 +4879,7 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
                     _ = try self.addInst(.{
                         .tag = .xor,
                         .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size) }),
-                        .data = .{ .imm = switch (abi_size) {
-                            1 => @truncate(u8, imm),
-                            2 => @truncate(u16, imm),
-                            4 => @truncate(u32, imm),
-                            8 => @truncate(u32, imm),
-                            else => unreachable,
-                        } },
+                        .data = .{ .imm = @intCast(u32, imm) },
                     });
                 },
                 .register => |reg| {
@@ -5416,12 +5390,6 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
                     // We have a positive stack offset value but we want a twos complement negative
                     // offset from rbp, which is at the top of the stack frame.
                     // mov [rbp+offset], immediate
-                    const operand = switch (abi_size) {
-                        1 => @truncate(u8, imm),
-                        2 => @truncate(u16, imm),
-                        4 => @truncate(u32, imm),
-                        else => unreachable,
-                    };
                     const flags: u2 = switch (abi_size) {
                         1 => 0b00,
                         2 => 0b01,
@@ -5430,7 +5398,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
                     };
                     const payload = try self.addExtra(Mir.ImmPair{
                         .dest_off = -stack_offset,
-                        .operand = operand,
+                        .operand = @intCast(u32, imm),
                     });
                     _ = try self.addInst(.{
                         .tag = .mov_mem_imm,
@@ -5575,7 +5543,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
                     assert(ty.isError());
                     const payload = try self.addExtra(Mir.ImmPair{
                         .dest_off = -stack_offset,
-                        .operand = @truncate(u8, x_big),
+                        .operand = @intCast(u32, x_big),
                     });
                     _ = try self.addInst(.{
                         .tag = .mov_mem_imm,
@@ -5587,15 +5555,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
                     });
                 },
                 1, 2, 4 => {
-                    const operand = switch (abi_size) {
-                        1 => @truncate(u8, x_big),
-                        2 => @truncate(u16, x_big),
-                        4 => @truncate(u32, x_big),
-                        else => unreachable,
-                    };
                     const payload = try self.addExtra(Mir.ImmPair{
                         .dest_off = -stack_offset,
-                        .operand = operand,
+                        .operand = @intCast(u32, x_big),
                     });
                     _ = try self.addInst(.{
                         .tag = .mov_mem_imm,
@@ -5724,7 +5686,7 @@ fn genInlineMemcpyRegisterRegister(
     src_reg: Register,
     offset: i32,
 ) InnerError!void {
-    assert(dst_reg.size() == 64);
+    assert(dst_reg.bitSize() == 64);
 
     const dst_reg_lock = self.register_manager.lockReg(dst_reg);
     defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
@@ -5823,7 +5785,7 @@ fn genInlineMemcpy(
             _ = try self.addInst(.{
                 .tag = .mov,
                 .ops = Mir.Inst.Ops.encode(.{
-                    .reg1 = registerAlias(dst_addr_reg, @divExact(reg.size(), 8)),
+                    .reg1 = registerAlias(dst_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
                     .reg2 = reg,
                 }),
                 .data = undefined,
@@ -5852,7 +5814,7 @@ fn genInlineMemcpy(
             _ = try self.addInst(.{
                 .tag = .mov,
                 .ops = Mir.Inst.Ops.encode(.{
-                    .reg1 = registerAlias(src_addr_reg, @divExact(reg.size(), 8)),
+                    .reg1 = registerAlias(src_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
                     .reg2 = reg,
                 }),
                 .data = undefined,
@@ -5976,7 +5938,7 @@ fn genInlineMemset(
             _ = try self.addInst(.{
                 .tag = .mov,
                 .ops = Mir.Inst.Ops.encode(.{
-                    .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),
+                    .reg1 = registerAlias(addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
                     .reg2 = reg,
                 }),
                 .data = undefined,
@@ -5994,8 +5956,11 @@ fn genInlineMemset(
     // cmp index_reg, -1
     const loop_start = try self.addInst(.{
         .tag = .cmp,
-        .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
-        .data = .{ .imm = @bitCast(u8, @as(i8, -1)) },
+        .ops = Mir.Inst.Ops.encode(.{
+            .reg1 = index_reg,
+            .flags = 0b11,
+        }),
+        .data = .{ .imm_s = -1 },
     });
 
     // je end
@@ -6016,8 +5981,14 @@ fn genInlineMemset(
             // mov byte ptr [rbp + index_reg + stack_offset], imm
             _ = try self.addInst(.{
                 .tag = .mov_mem_index_imm,
-                .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg }),
-                .data = .{ .payload = try self.addExtra(Mir.IndexRegisterDispImm.encode(index_reg, 0, @truncate(u32, x))) },
+                .ops = Mir.Inst.Ops.encode(.{
+                    .reg1 = addr_reg,
+                }),
+                .data = .{ .payload = try self.addExtra(Mir.IndexRegisterDispImm.encode(
+                    index_reg,
+                    0,
+                    @intCast(u32, x),
+                )) },
             });
         },
         else => return self.fail("TODO inline memset for value of type {}", .{value}),
@@ -6064,7 +6035,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
             if (!self.wantSafety())
                 return; // The already existing value will do just fine.
             // Write the debug undefined value.
-            switch (registerAlias(reg, abi_size).size()) {
+            switch (registerAlias(reg, abi_size).bitSize()) {
                 8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }),
                 16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }),
                 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }),
@@ -6100,13 +6071,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
                 _ = try self.addInst(.{
                     .tag = .mov,
                     .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }),
-                    .data = .{ .imm = switch (abi_size) {
-                        1 => @truncate(u8, x),
-                        2 => @truncate(u16, x),
-                        4 => @truncate(u32, x),
-                        8 => @truncate(u32, x),
-                        else => unreachable,
-                    } },
+                    .data = .{ .imm = @intCast(u32, x) },
                 });
                 return;
             }
@@ -6273,13 +6238,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
                             .reg1 = registerAlias(reg, abi_size),
                             .flags = 0b01,
                         }),
-                        .data = .{ .imm = switch (abi_size) {
-                            1 => @truncate(u8, x),
-                            2 => @truncate(u16, x),
-                            4 => @truncate(u32, x),
-                            8 => @truncate(u32, x),
-                            else => unreachable,
-                        } },
+                        .data = .{ .disp = @intCast(i32, x) },
                     });
                 } else {
                     // If this is RAX, we can use a direct load.
@@ -6949,7 +6908,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
                 if (ret_ty_size == 0) {
                     assert(ret_ty.isError());
                     result.return_value = .{ .immediate = 0 };
-                } else if (ret_ty_size <= 8) {
+                } else if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) {
                     const aliased_reg = registerAlias(abi.getCAbiIntReturnRegs(self.target.*)[0], ret_ty_size);
                     result.return_value = .{ .register = aliased_reg };
                 } else {
@@ -7024,28 +6983,34 @@ fn parseRegName(name: []const u8) ?Register {
 
 /// Returns register wide enough to hold at least `size_bytes`.
 fn registerAlias(reg: Register, size_bytes: u32) Register {
-    if (size_bytes == 0) {
-        unreachable; // should be comptime-known
-    } else if (size_bytes <= 1) {
-        return reg.to8();
-    } else if (size_bytes <= 2) {
-        return reg.to16();
-    } else if (size_bytes <= 4) {
-        return reg.to32();
-    } else if (size_bytes <= 8) {
-        return reg.to64();
-    } else if (size_bytes <= 16) {
-        return reg.to128();
-    } else if (size_bytes <= 32) {
-        return reg.to256();
-    } else unreachable;
+    return switch (reg.class()) {
+        .general_purpose => if (size_bytes == 0)
+            unreachable // should be comptime-known
+        else if (size_bytes <= 1)
+            reg.to8()
+        else if (size_bytes <= 2)
+            reg.to16()
+        else if (size_bytes <= 4)
+            reg.to32()
+        else if (size_bytes <= 8)
+            reg.to64()
+        else
+            unreachable,
+        .floating_point => if (size_bytes <= 16)
+            reg.to128()
+        else if (size_bytes <= 32)
+            reg.to256()
+        else
+            unreachable,
+        .segment => unreachable,
+    };
 }
 
 /// Truncates the value in the register in place.
 /// Clobbers any remaining bits.
 fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
     const int_info = ty.intInfo(self.target.*);
-    const max_reg_bit_width = Register.rax.size();
+    const max_reg_bit_width = Register.rax.bitSize();
     switch (int_info.signedness) {
         .signed => {
             const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
src/arch/x86_64/Emit.zig
@@ -21,6 +21,7 @@ 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;
@@ -283,7 +284,7 @@ fn mirPushPop(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index)
         0b10 => {
             const imm = emit.mir.instructions.items(.data)[inst].imm;
             return emit.encode(.push, .{
-                .op1 = .{ .imm = imm },
+                .op1 = .{ .imm = Immediate.u(imm) },
             });
         },
         0b11 => unreachable,
@@ -327,9 +328,7 @@ fn mirJmpCall(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index)
             const target = emit.mir.instructions.items(.data)[inst].inst;
             const source = emit.code.items.len;
             try emit.encode(mnemonic, .{
-                .op1 = .{
-                    .imm = 0,
-                },
+                .op1 = .{ .imm = Immediate.s(0) },
             });
             try emit.relocs.append(emit.bin_file.allocator, .{
                 .source = source,
@@ -400,7 +399,7 @@ fn mirCondJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
     };
     const source = emit.code.items.len;
     try emit.encode(mnemonic, .{
-        .op1 = .{ .imm = 0 },
+        .op1 = .{ .imm = Immediate.s(0) },
     });
     try emit.relocs.append(emit.bin_file.allocator, .{
         .source = source,
@@ -521,7 +520,7 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
                 const imm = emit.mir.instructions.items(.data)[inst].imm;
                 return emit.encode(.@"test", .{
                     .op1 = .{ .reg = ops.reg1 },
-                    .op2 = .{ .imm = imm },
+                    .op2 = .{ .imm = Immediate.u(imm) },
                 });
             }
             return emit.encode(.@"test", .{
@@ -543,7 +542,7 @@ fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
         0b10 => {
             const imm = emit.mir.instructions.items(.data)[inst].imm;
             return emit.encode(.ret, .{
-                .op1 = .{ .imm = imm },
+                .op1 = .{ .imm = Immediate.u(imm) },
             });
         },
         0b11 => {
@@ -560,7 +559,7 @@ fn mirArith(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index) I
                 const imm = emit.mir.instructions.items(.data)[inst].imm;
                 return emit.encode(mnemonic, .{
                     .op1 = .{ .reg = ops.reg1 },
-                    .op2 = .{ .imm = imm },
+                    .op2 = .{ .imm = Immediate.u(imm) },
                 });
             }
             return emit.encode(mnemonic, .{
@@ -573,7 +572,7 @@ fn mirArith(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index) I
             const base: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg1.size()), .{
+                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), .{
                     .base = base,
                     .disp = disp,
                 }) },
@@ -585,7 +584,7 @@ fn mirArith(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index) I
             }
             const disp = emit.mir.instructions.items(.data)[inst].disp;
             return emit.encode(mnemonic, .{
-                .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg2.size()), .{
+                .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg2.bitSize()), .{
                     .base = ops.reg1,
                     .disp = disp,
                 }) },
@@ -593,7 +592,11 @@ fn mirArith(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index) I
             });
         },
         0b11 => {
-            return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
+            const imm_s = emit.mir.instructions.items(.data)[inst].imm_s;
+            return emit.encode(mnemonic, .{
+                .op1 = .{ .reg = ops.reg1 },
+                .op2 = .{ .imm = Immediate.s(imm_s) },
+            });
         },
     }
 }
@@ -614,7 +617,7 @@ fn mirArithMemImm(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.In
             .disp = imm_pair.dest_off,
             .base = ops.reg1,
         }) },
-        .op2 = .{ .imm = imm_pair.operand },
+        .op2 = .{ .imm = Immediate.u(imm_pair.operand) },
     });
 }
 
@@ -629,7 +632,7 @@ fn mirArithScaleSrc(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.
     };
     return emit.encode(mnemonic, .{
         .op1 = .{ .reg = ops.reg1 },
-        .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg1.size()), .{
+        .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), .{
             .base = ops.reg2,
             .scale_index = scale_index,
             .disp = index_reg_disp.disp,
@@ -648,7 +651,7 @@ fn mirArithScaleDst(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.
     };
     assert(ops.reg2 != .none);
     return emit.encode(mnemonic, .{
-        .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg2.size()), .{
+        .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg2.bitSize()), .{
             .base = ops.reg1,
             .scale_index = scale_index,
             .disp = index_reg_disp.disp,
@@ -672,7 +675,7 @@ fn mirArithScaleImm(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.
             .disp = index_reg_disp_imm.disp,
             .scale_index = scale_index,
         }) },
-        .op2 = .{ .imm = index_reg_disp_imm.imm },
+        .op2 = .{ .imm = Immediate.u(index_reg_disp_imm.imm) },
     });
 }
 
@@ -697,7 +700,7 @@ fn mirArithMemIndexImm(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.In
             .base = ops.reg1,
             .scale_index = scale_index,
         }) },
-        .op2 = .{ .imm = index_reg_disp_imm.imm },
+        .op2 = .{ .imm = Immediate.u(index_reg_disp_imm.imm) },
     });
 }
 
@@ -708,7 +711,7 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
     const disp = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].disp else undefined;
     switch (ops.flags) {
         0b00 => {
-            const mnemonic: Instruction.Mnemonic = if (ops.reg2.size() == 32) .movsxd else .movsx;
+            const mnemonic: Instruction.Mnemonic = if (ops.reg2.bitSize() == 32) .movsxd else .movsx;
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = ops.reg1 },
                 .op2 = .{ .reg = ops.reg2 },
@@ -718,14 +721,15 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
             const ptr_size: Memory.PtrSize = switch (ops.flags) {
                 0b01 => .byte,
                 0b10 => .word,
-                0b11 => .qword,
+                0b11 => .dword,
                 else => unreachable,
             };
-            return emit.encode(.movsx, .{
+            const mnemonic: Instruction.Mnemonic = if (ops.flags == 0b11) .movsxd else .movsx;
+            return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = ops.reg1 },
                 .op2 = .{ .mem = Memory.sib(ptr_size, .{
-                    .disp = disp,
                     .base = ops.reg2,
+                    .disp = disp,
                 }) },
             });
         },
@@ -770,19 +774,19 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
     const ops = emit.mir.instructions.items(.ops)[inst].decode();
     switch (ops.flags) {
         0b00 => {
-            const imm: u64 = if (ops.reg1.size() == 64) blk: {
+            const imm: u64 = if (ops.reg1.bitSize() == 64) blk: {
                 const payload = emit.mir.instructions.items(.data)[inst].payload;
                 const imm = emit.mir.extraData(Mir.Imm64, payload).data;
                 break :blk imm.decode();
             } else emit.mir.instructions.items(.data)[inst].imm;
             return emit.encode(.mov, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .imm = imm },
+                .op2 = .{ .imm = Immediate.u(imm) },
             });
         },
         0b01 => {
             if (ops.reg1 == .none) {
-                const imm: u64 = if (ops.reg2.size() == 64) blk: {
+                const imm: u64 = if (ops.reg2.bitSize() == 64) blk: {
                     const payload = emit.mir.instructions.items(.data)[inst].payload;
                     const imm = emit.mir.extraData(Mir.Imm64, payload).data;
                     break :blk imm.decode();
@@ -792,7 +796,7 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
                     .op2 = .{ .reg = .rax },
                 });
             }
-            const imm: u64 = if (ops.reg1.size() == 64) blk: {
+            const imm: u64 = if (ops.reg1.bitSize() == 64) blk: {
                 const payload = emit.mir.instructions.items(.data)[inst].payload;
                 const imm = emit.mir.extraData(Mir.Imm64, payload).data;
                 break :blk imm.decode();
@@ -847,7 +851,7 @@ fn mirShift(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index) I
         0b00 => {
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .imm = 1 },
+                .op2 = .{ .imm = Immediate.u(1) },
             });
         },
         0b01 => {
@@ -860,7 +864,7 @@ fn mirShift(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index) I
             const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .imm = imm },
+                .op2 = .{ .imm = Immediate.u(imm) },
             });
         },
         0b11 => {
@@ -920,7 +924,7 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
             return emit.encode(.imul, .{
                 .op1 = .{ .reg = ops.reg1 },
                 .op2 = .{ .reg = ops.reg2 },
-                .op3 = .{ .imm = imm },
+                .op3 = .{ .imm = Immediate.u(imm) },
             });
         },
         0b11 => {
@@ -932,7 +936,7 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
                     .base = ops.reg2,
                     .disp = imm_pair.dest_off,
                 }) },
-                .op3 = .{ .imm = imm_pair.operand },
+                .op3 = .{ .imm = Immediate.u(imm_pair.operand) },
             });
         },
     }
@@ -959,7 +963,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
             const src_reg: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
             return emit.encode(.lea, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg1.size()), .{
+                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), .{
                     .base = src_reg,
                     .disp = disp,
                 }) },
@@ -969,7 +973,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
             const start_offset = emit.code.items.len;
             try emit.encode(.lea, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromSize(ops.reg1.size()), 0) },
+                .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), 0) },
             });
             const end_offset = emit.code.items.len;
             // Backpatch the displacement
@@ -988,7 +992,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
             };
             return emit.encode(.lea, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg1.size()), .{
+                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), .{
                     .base = src_reg,
                     .scale_index = scale_index,
                     .disp = index_reg_disp.disp,
@@ -1012,7 +1016,7 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
 
     try emit.encode(.lea, .{
         .op1 = .{ .reg = ops.reg1 },
-        .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromSize(ops.reg1.size()), 0) },
+        .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), 0) },
     });
 
     const end_offset = emit.code.items.len;
@@ -1065,7 +1069,7 @@ fn mirMovFloat(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index
             const disp = emit.mir.instructions.items(.data)[inst].disp;
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = ops.reg1 },
-                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg2.size()), .{
+                .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg2.bitSize()), .{
                     .base = ops.reg2,
                     .disp = disp,
                 }) },
@@ -1074,7 +1078,7 @@ fn mirMovFloat(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.Index
         0b01 => {
             const disp = emit.mir.instructions.items(.data)[inst].disp;
             return emit.encode(mnemonic, .{
-                .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromSize(ops.reg1.size()), .{
+                .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(ops.reg1.bitSize()), .{
                     .base = ops.reg1,
                     .disp = disp,
                 }) },
@@ -1127,7 +1131,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
     const offset = blk: {
         // callq
         try emit.encode(.call, .{
-            .op1 = .{ .imm = 0 },
+            .op1 = .{ .imm = Immediate.s(0) },
         });
         break :blk @intCast(u32, emit.code.items.len) - 4;
     };
src/arch/x86_64/encoder.zig
@@ -4,6 +4,7 @@ const math = std.math;
 
 const bits = @import("bits.zig");
 const Encoding = @import("Encoding.zig");
+const Immediate = bits.Immediate;
 const Memory = bits.Memory;
 const Moffs = bits.Moffs;
 const PtrSize = bits.PtrSize;
@@ -22,15 +23,14 @@ pub const Instruction = struct {
         none,
         reg: Register,
         mem: Memory,
-        imm: u64,
+        imm: Immediate,
 
         /// Returns the bitsize of the operand.
-        /// Asserts the operand is either register or memory.
-        pub fn size(op: Operand) u64 {
+        pub fn bitSize(op: Operand) u64 {
             return switch (op) {
                 .none => unreachable,
-                .reg => |reg| reg.size(),
-                .mem => |mem| mem.size(),
+                .reg => |reg| reg.bitSize(),
+                .mem => |mem| mem.bitSize(),
                 .imm => unreachable,
             };
         }
@@ -47,7 +47,6 @@ pub const Instruction = struct {
         }
 
         pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) !void {
-            _ = enc_op;
             switch (op) {
                 .none => {},
                 .reg => |reg| try writer.writeAll(@tagName(reg)),
@@ -92,9 +91,7 @@ pub const Instruction = struct {
                     },
                     .moffs => |moffs| try writer.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset }),
                 },
-                .imm => |imm| {
-                    try writer.print("0x{x}", .{imm});
-                },
+                .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
             }
         }
     };
@@ -110,8 +107,17 @@ pub const Instruction = struct {
             .op2 = args.op2,
             .op3 = args.op3,
             .op4 = args.op4,
-        }) orelse return error.InvalidInstruction;
-        std.log.warn("{}", .{encoding});
+        }) orelse {
+            std.log.debug("{s} {s} {s} {s} {s}", .{
+                @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)),
+            });
+            return error.InvalidInstruction;
+        };
+        std.log.debug("{}", .{encoding});
         return .{
             .op1 = args.op1,
             .op2 = args.op2,
@@ -210,7 +216,7 @@ pub const Instruction = struct {
 
         var legacy = LegacyPrefixes{};
         if (enc.mode == .none) {
-            const bit_size = enc.operandSize();
+            const bit_size = enc.operandBitSize();
             if (bit_size == 16) {
                 legacy.set16BitOverride();
             }
@@ -380,12 +386,13 @@ pub const Instruction = struct {
         }
     }
 
-    fn encodeImm(imm: u64, kind: Encoding.Op, encoder: anytype) !void {
-        switch (kind) {
-            .imm8, .rel8 => try encoder.imm8(@bitCast(i8, @truncate(u8, imm))),
-            .imm16, .rel16 => try encoder.imm16(@bitCast(i16, @truncate(u16, imm))),
-            .imm32, .rel32 => try encoder.imm32(@bitCast(i32, @truncate(u32, imm))),
-            .imm64 => try encoder.imm64(imm),
+    fn encodeImm(imm: Immediate, kind: Encoding.Op, encoder: anytype) !void {
+        const raw = imm.asUnsigned(kind.bitSize());
+        switch (kind.bitSize()) {
+            8 => try encoder.imm8(@intCast(u8, raw)),
+            16 => try encoder.imm16(@intCast(u16, raw)),
+            32 => try encoder.imm32(@intCast(u32, raw)),
+            64 => try encoder.imm64(raw),
             else => unreachable,
         }
     }
@@ -732,39 +739,39 @@ fn Encoder(comptime T: type) type {
         // Trivial (no bit fiddling)
         // -------------------------
 
-        /// Encode an 8 bit immediate
+        /// Encode an 8 bit displacement
         ///
         /// It is sign-extended to 64 bits by the cpu.
-        pub fn imm8(self: Self, imm: i8) !void {
-            try self.writer.writeByte(@bitCast(u8, imm));
+        pub fn disp8(self: Self, disp: i8) !void {
+            try self.writer.writeByte(@bitCast(u8, disp));
         }
 
-        /// Encode an 8 bit displacement
+        /// Encode an 32 bit displacement
         ///
         /// It is sign-extended to 64 bits by the cpu.
-        pub fn disp8(self: Self, disp: i8) !void {
-            try self.writer.writeByte(@bitCast(u8, disp));
+        pub fn disp32(self: Self, disp: i32) !void {
+            try self.writer.writeIntLittle(i32, disp);
         }
 
-        /// Encode an 16 bit immediate
+        /// Encode an 8 bit immediate
         ///
         /// It is sign-extended to 64 bits by the cpu.
-        pub fn imm16(self: Self, imm: i16) !void {
-            try self.writer.writeIntLittle(i16, imm);
+        pub fn imm8(self: Self, imm: u8) !void {
+            try self.writer.writeByte(imm);
         }
 
-        /// Encode an 32 bit immediate
+        /// Encode an 16 bit immediate
         ///
         /// It is sign-extended to 64 bits by the cpu.
-        pub fn imm32(self: Self, imm: i32) !void {
-            try self.writer.writeIntLittle(i32, imm);
+        pub fn imm16(self: Self, imm: u16) !void {
+            try self.writer.writeIntLittle(u16, imm);
         }
 
-        /// Encode an 32 bit displacement
+        /// Encode an 32 bit immediate
         ///
         /// It is sign-extended to 64 bits by the cpu.
-        pub fn disp32(self: Self, disp: i32) !void {
-            try self.writer.writeIntLittle(i32, disp);
+        pub fn imm32(self: Self, imm: u32) !void {
+            try self.writer.writeIntLittle(u32, imm);
         }
 
         /// Encode an 64 bit immediate
src/arch/x86_64/Encoding.zig
@@ -144,20 +144,20 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
                         // rex.W mov dil, 0x1
                         // Here, rex.W is not needed.
                         const rex_w_allowed = blk: {
-                            const bit_size = enc.operandSize();
+                            const bit_size = enc.operandBitSize();
                             break :blk bit_size == 64 or bit_size == 8;
                         };
                         if (rex_w_allowed) return enc;
                     },
                 }
             } else if (prefixes.legacy.prefix_66) {
-                switch (enc.operandSize()) {
+                switch (enc.operandBitSize()) {
                     16 => return enc,
                     else => {},
                 }
             } else {
                 if (enc.mode == .none) {
-                    switch (enc.operandSize()) {
+                    switch (enc.operandBitSize()) {
                         16 => {},
                         else => return enc,
                     }
@@ -187,17 +187,17 @@ pub fn modRmExt(encoding: Encoding) u3 {
     };
 }
 
-pub fn operandSize(encoding: Encoding) u32 {
+pub fn operandBitSize(encoding: Encoding) u64 {
     if (encoding.mode == .long) return 64;
-    const bit_size: u32 = switch (encoding.op_en) {
+    const bit_size: u64 = switch (encoding.op_en) {
         .np => switch (encoding.op1) {
             .o16 => 16,
             .o32 => 32,
             .o64 => 64,
             else => 32,
         },
-        .td => encoding.op2.size(),
-        else => encoding.op1.size(),
+        .td => encoding.op2.bitSize(),
+        else => encoding.op1.bitSize(),
     };
     return bit_size;
 }
@@ -244,9 +244,9 @@ pub fn format(
                 else => unreachable,
             };
             const tag = switch (op) {
-                .imm8 => "ib",
-                .imm16 => "iw",
-                .imm32 => "id",
+                .imm8, .imm8s => "ib",
+                .imm16, .imm16s => "iw",
+                .imm32, .imm32s => "id",
                 .imm64 => "io",
                 .rel8 => "cb",
                 .rel16 => "cw",
@@ -330,6 +330,7 @@ pub const Op = enum {
     o16, o32, o64,
     unity,
     imm8, imm16, imm32, imm64,
+    imm8s, imm16s, imm32s,
     al, ax, eax, rax,
     cl,
     r8, r16, r32, r64,
@@ -349,7 +350,7 @@ pub const Op = enum {
             .reg => |reg| {
                 switch (reg.class()) {
                     .segment => return .sreg,
-                    .floating_point => return switch (reg.size()) {
+                    .floating_point => return switch (reg.bitSize()) {
                         128 => .xmm,
                         else => unreachable,
                     },
@@ -362,7 +363,7 @@ pub const Op = enum {
                             else => unreachable,
                         };
                         if (reg == .cl) return .cl;
-                        return switch (reg.size()) {
+                        return switch (reg.bitSize()) {
                             8 => .r8,
                             16 => .r16,
                             32 => .r32,
@@ -376,7 +377,7 @@ pub const Op = enum {
             .mem => |mem| switch (mem) {
                 .moffs => return .moffs,
                 .sib, .rip => {
-                    const bit_size = mem.size();
+                    const bit_size = mem.bitSize();
                     return switch (bit_size) {
                         8 => .m8,
                         16 => .m16,
@@ -389,21 +390,34 @@ pub const Op = enum {
             },
 
             .imm => |imm| {
-                if (imm == 1) return .unity;
-                if (math.cast(u8, imm)) |_| return .imm8;
-                if (math.cast(u16, imm)) |_| return .imm16;
-                if (math.cast(u32, imm)) |_| return .imm32;
-                return .imm64;
+                switch (imm) {
+                    .signed => |x| {
+                        if (x == 1) return .unity;
+                        if (math.cast(i8, x)) |_| return .imm8s;
+                        if (math.cast(i16, x)) |_| return .imm16s;
+                        return .imm32s;
+                    },
+                    .unsigned => |x| {
+                        if (x == 1) return .unity;
+                        if (math.cast(i8, x)) |_| return .imm8s;
+                        if (math.cast(u8, x)) |_| return .imm8;
+                        if (math.cast(i16, x)) |_| return .imm16s;
+                        if (math.cast(u16, x)) |_| return .imm16;
+                        if (math.cast(i32, x)) |_| return .imm32s;
+                        if (math.cast(u32, x)) |_| return .imm32;
+                        return .imm64;
+                    },
+                }
             },
         }
     }
 
-    pub fn size(op: Op) u32 {
+    pub fn bitSize(op: Op) u64 {
         return switch (op) {
-            .none, .o16, .o32, .o64, .moffs, .m, .sreg, .unity => unreachable,
-            .imm8, .al, .cl, .r8, .m8, .rm8, .rel8 => 8,
-            .imm16, .ax, .r16, .m16, .rm16, .rel16 => 16,
-            .imm32, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
+            .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
+            .unity, .imm8, .imm8s, .al, .cl, .r8, .m8, .rm8, .rel8 => 8,
+            .imm16, .imm16s, .ax, .r16, .m16, .rm16, .rel16 => 16,
+            .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
             .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
             .m80 => 80,
             .xmm => 128,
@@ -428,6 +442,7 @@ pub const Op = enum {
         // zig fmt: off
         return switch (op) {
             .imm8, .imm16, .imm32, .imm64, 
+            .imm8s, .imm16s, .imm32s,
             .rel8, .rel16, .rel32,
             .unity,
             =>  true,
@@ -479,28 +494,40 @@ pub const Op = enum {
                         .sse, .sse2 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(),
                         else => switch (target) {
                             .cl, .al, .ax, .eax, .rax => return op == target,
-                            else => return op.size() == target.size(),
+                            else => return op.bitSize() == target.bitSize(),
                         },
                     }
                 }
                 if (op.isMemory() and target.isMemory()) {
                     switch (target) {
                         .m => return true,
-                        else => return op.size() == target.size(),
+                        else => return op.bitSize() == target.bitSize(),
                     }
                 }
                 if (op.isImmediate() and target.isImmediate()) {
                     switch (target) {
-                        .imm32, .rel32 => switch (op) {
-                            .unity, .imm8, .imm16, .imm32 => return true,
+                        .imm32s, .rel32 => switch (op) {
+                            .unity, .imm8s, .imm8, .imm16s, .imm16, .imm32s => return true,
+                            else => return op == target,
+                        },
+                        .imm32 => switch (op) {
+                            .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s => return true,
+                            else => return op == target,
+                        },
+                        .imm16s, .rel16 => switch (op) {
+                            .unity, .imm8s, .imm8, .imm16s => return true,
+                            else => return op == target,
+                        },
+                        .imm16 => switch (op) {
+                            .unity, .imm8, .imm8s, .imm16, .imm16s => return true,
                             else => return op == target,
                         },
-                        .imm16, .rel16 => switch (op) {
-                            .unity, .imm8, .imm16 => return true,
+                        .imm8s, .rel8 => switch (op) {
+                            .unity, .imm8s => return true,
                             else => return op == target,
                         },
-                        .imm8, .rel8 => switch (op) {
-                            .unity, .imm8 => return true,
+                        .imm8 => switch (op) {
+                            .unity, .imm8, .imm8s => return true,
                             else => return op == target,
                         },
                         else => return op == target,
src/arch/x86_64/encodings.zig
@@ -13,65 +13,65 @@ const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, opcode_len, u8, u8, u8, m
 // zig fmt: off
 pub const table = &[_]Entry{
     // General-purpose
-    .{ .adc, .zi, .al,   .imm8,  .none, .none, 1, 0x14, 0x00, 0x00, 0, .none  },
-    .{ .adc, .zi, .ax,   .imm16, .none, .none, 1, 0x15, 0x00, 0x00, 0, .none  },
-    .{ .adc, .zi, .eax,  .imm32, .none, .none, 1, 0x15, 0x00, 0x00, 0, .none  },
-    .{ .adc, .zi, .rax,  .imm32, .none, .none, 1, 0x15, 0x00, 0x00, 0, .long  },
-    .{ .adc, .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 2, .none  },
-    .{ .adc, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 2, .none  },
-    .{ .adc, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 2, .none  },
-    .{ .adc, .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 2, .long  },
-    .{ .adc, .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 2, .none  },
-    .{ .adc, .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 2, .none  },
-    .{ .adc, .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 2, .long  },
-    .{ .adc, .mr, .rm8,  .r8,    .none, .none, 1, 0x10, 0x00, 0x00, 0, .none  },
-    .{ .adc, .mr, .rm16, .r16,   .none, .none, 1, 0x11, 0x00, 0x00, 0, .none  },
-    .{ .adc, .mr, .rm32, .r32,   .none, .none, 1, 0x11, 0x00, 0x00, 0, .none  },
-    .{ .adc, .mr, .rm64, .r64,   .none, .none, 1, 0x11, 0x00, 0x00, 0, .long  },
-    .{ .adc, .rm, .r8,   .rm8,   .none, .none, 1, 0x12, 0x00, 0x00, 0, .none  },
-    .{ .adc, .rm, .r16,  .rm16,  .none, .none, 1, 0x13, 0x00, 0x00, 0, .none  },
-    .{ .adc, .rm, .r32,  .rm32,  .none, .none, 1, 0x13, 0x00, 0x00, 0, .none  },
-    .{ .adc, .rm, .r64,  .rm64,  .none, .none, 1, 0x13, 0x00, 0x00, 0, .long  },
-
-    .{ .add, .zi, .al,   .imm8,  .none, .none, 1, 0x04, 0x00, 0x00, 0, .none  },
-    .{ .add, .zi, .ax,   .imm16, .none, .none, 1, 0x05, 0x00, 0x00, 0, .none  },
-    .{ .add, .zi, .eax,  .imm32, .none, .none, 1, 0x05, 0x00, 0x00, 0, .none  },
-    .{ .add, .zi, .rax,  .imm32, .none, .none, 1, 0x05, 0x00, 0x00, 0, .long  },
-    .{ .add, .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 0, .none  },
-    .{ .add, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 0, .none  },
-    .{ .add, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 0, .none  },
-    .{ .add, .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 0, .long  },
-    .{ .add, .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 0, .none  },
-    .{ .add, .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 0, .none  },
-    .{ .add, .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 0, .long  },
-    .{ .add, .mr, .rm8,  .r8,    .none, .none, 1, 0x00, 0x00, 0x00, 0, .none  },
-    .{ .add, .mr, .rm16, .r16,   .none, .none, 1, 0x01, 0x00, 0x00, 0, .none  },
-    .{ .add, .mr, .rm32, .r32,   .none, .none, 1, 0x01, 0x00, 0x00, 0, .none  },
-    .{ .add, .mr, .rm64, .r64,   .none, .none, 1, 0x01, 0x00, 0x00, 0, .long  },
-    .{ .add, .rm, .r8,   .rm8,   .none, .none, 1, 0x02, 0x00, 0x00, 0, .none  },
-    .{ .add, .rm, .r16,  .rm16,  .none, .none, 1, 0x03, 0x00, 0x00, 0, .none  },
-    .{ .add, .rm, .r32,  .rm32,  .none, .none, 1, 0x03, 0x00, 0x00, 0, .none  },
-    .{ .add, .rm, .r64,  .rm64,  .none, .none, 1, 0x03, 0x00, 0x00, 0, .long  },
-
-    .{ .@"and", .zi, .al,   .imm8,  .none, .none, 1, 0x24, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .zi, .ax,   .imm16, .none, .none, 1, 0x25, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .zi, .eax,  .imm32, .none, .none, 1, 0x25, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .zi, .rax,  .imm32, .none, .none, 1, 0x25, 0x00, 0x00, 0, .long  },
-    .{ .@"and", .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 4, .none  },
-    .{ .@"and", .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 4, .none  },
-    .{ .@"and", .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 4, .none  },
-    .{ .@"and", .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 4, .long  },
-    .{ .@"and", .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 4, .none  },
-    .{ .@"and", .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 4, .none  },
-    .{ .@"and", .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 4, .long  },
-    .{ .@"and", .mr, .rm8,  .r8,    .none, .none, 1, 0x20, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .mr, .rm16, .r16,   .none, .none, 1, 0x21, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .mr, .rm32, .r32,   .none, .none, 1, 0x21, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .mr, .rm64, .r64,   .none, .none, 1, 0x21, 0x00, 0x00, 0, .long  },
-    .{ .@"and", .rm, .r8,   .rm8,   .none, .none, 1, 0x22, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .rm, .r16,  .rm16,  .none, .none, 1, 0x23, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .rm, .r32,  .rm32,  .none, .none, 1, 0x23, 0x00, 0x00, 0, .none  },
-    .{ .@"and", .rm, .r64,  .rm64,  .none, .none, 1, 0x23, 0x00, 0x00, 0, .long  },
+    .{ .adc, .zi, .al,   .imm8,   .none, .none, 1, 0x14, 0x00, 0x00, 0, .none  },
+    .{ .adc, .zi, .ax,   .imm16,  .none, .none, 1, 0x15, 0x00, 0x00, 0, .none  },
+    .{ .adc, .zi, .eax,  .imm32,  .none, .none, 1, 0x15, 0x00, 0x00, 0, .none  },
+    .{ .adc, .zi, .rax,  .imm32s, .none, .none, 1, 0x15, 0x00, 0x00, 0, .long  },
+    .{ .adc, .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 2, .none  },
+    .{ .adc, .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 2, .none  },
+    .{ .adc, .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 2, .none  },
+    .{ .adc, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 2, .long  },
+    .{ .adc, .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 2, .none  },
+    .{ .adc, .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 2, .none  },
+    .{ .adc, .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 2, .long  },
+    .{ .adc, .mr, .rm8,  .r8,     .none, .none, 1, 0x10, 0x00, 0x00, 0, .none  },
+    .{ .adc, .mr, .rm16, .r16,    .none, .none, 1, 0x11, 0x00, 0x00, 0, .none  },
+    .{ .adc, .mr, .rm32, .r32,    .none, .none, 1, 0x11, 0x00, 0x00, 0, .none  },
+    .{ .adc, .mr, .rm64, .r64,    .none, .none, 1, 0x11, 0x00, 0x00, 0, .long  },
+    .{ .adc, .rm, .r8,   .rm8,    .none, .none, 1, 0x12, 0x00, 0x00, 0, .none  },
+    .{ .adc, .rm, .r16,  .rm16,   .none, .none, 1, 0x13, 0x00, 0x00, 0, .none  },
+    .{ .adc, .rm, .r32,  .rm32,   .none, .none, 1, 0x13, 0x00, 0x00, 0, .none  },
+    .{ .adc, .rm, .r64,  .rm64,   .none, .none, 1, 0x13, 0x00, 0x00, 0, .long  },
+
+    .{ .add, .zi, .al,   .imm8,   .none, .none, 1, 0x04, 0x00, 0x00, 0, .none  },
+    .{ .add, .zi, .ax,   .imm16,  .none, .none, 1, 0x05, 0x00, 0x00, 0, .none  },
+    .{ .add, .zi, .eax,  .imm32,  .none, .none, 1, 0x05, 0x00, 0x00, 0, .none  },
+    .{ .add, .zi, .rax,  .imm32s, .none, .none, 1, 0x05, 0x00, 0x00, 0, .long  },
+    .{ .add, .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 0, .none  },
+    .{ .add, .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 0, .none  },
+    .{ .add, .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 0, .none  },
+    .{ .add, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 0, .long  },
+    .{ .add, .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 0, .none  },
+    .{ .add, .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 0, .none  },
+    .{ .add, .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 0, .long  },
+    .{ .add, .mr, .rm8,  .r8,     .none, .none, 1, 0x00, 0x00, 0x00, 0, .none  },
+    .{ .add, .mr, .rm16, .r16,    .none, .none, 1, 0x01, 0x00, 0x00, 0, .none  },
+    .{ .add, .mr, .rm32, .r32,    .none, .none, 1, 0x01, 0x00, 0x00, 0, .none  },
+    .{ .add, .mr, .rm64, .r64,    .none, .none, 1, 0x01, 0x00, 0x00, 0, .long  },
+    .{ .add, .rm, .r8,   .rm8,    .none, .none, 1, 0x02, 0x00, 0x00, 0, .none  },
+    .{ .add, .rm, .r16,  .rm16,   .none, .none, 1, 0x03, 0x00, 0x00, 0, .none  },
+    .{ .add, .rm, .r32,  .rm32,   .none, .none, 1, 0x03, 0x00, 0x00, 0, .none  },
+    .{ .add, .rm, .r64,  .rm64,   .none, .none, 1, 0x03, 0x00, 0x00, 0, .long  },
+
+    .{ .@"and", .zi, .al,   .imm8,   .none, .none, 1, 0x24, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .zi, .ax,   .imm16,  .none, .none, 1, 0x25, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .zi, .eax,  .imm32,  .none, .none, 1, 0x25, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .zi, .rax,  .imm32s, .none, .none, 1, 0x25, 0x00, 0x00, 0, .long  },
+    .{ .@"and", .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 4, .none  },
+    .{ .@"and", .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 4, .none  },
+    .{ .@"and", .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 4, .none  },
+    .{ .@"and", .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 4, .long  },
+    .{ .@"and", .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 4, .none  },
+    .{ .@"and", .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 4, .none  },
+    .{ .@"and", .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 4, .long  },
+    .{ .@"and", .mr, .rm8,  .r8,     .none, .none, 1, 0x20, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .mr, .rm16, .r16,    .none, .none, 1, 0x21, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .mr, .rm32, .r32,    .none, .none, 1, 0x21, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .mr, .rm64, .r64,    .none, .none, 1, 0x21, 0x00, 0x00, 0, .long  },
+    .{ .@"and", .rm, .r8,   .rm8,    .none, .none, 1, 0x22, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .rm, .r16,  .rm16,   .none, .none, 1, 0x23, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .rm, .r32,  .rm32,   .none, .none, 1, 0x23, 0x00, 0x00, 0, .none  },
+    .{ .@"and", .rm, .r64,  .rm64,   .none, .none, 1, 0x23, 0x00, 0x00, 0, .long  },
 
     // This is M encoding according to Intel, but D makes more sense here.
     .{ .call, .d, .rel32, .none, .none, .none, 1, 0xe8, 0x00, 0x00, 0, .none },
@@ -176,25 +176,25 @@ pub const table = &[_]Entry{
     .{ .cmovz,   .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none  },
     .{ .cmovz,   .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .long  },
 
-    .{ .cmp, .zi, .al,   .imm8,  .none, .none, 1, 0x3c, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .zi, .ax,   .imm16, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .zi, .eax,  .imm32, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .zi, .rax,  .imm32, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .long  },
-    .{ .cmp, .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 7, .none  },
-    .{ .cmp, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 7, .none  },
-    .{ .cmp, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 7, .none  },
-    .{ .cmp, .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 7, .long  },
-    .{ .cmp, .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 7, .none  },
-    .{ .cmp, .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 7, .none  },
-    .{ .cmp, .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 7, .long  },
-    .{ .cmp, .mr, .rm8,  .r8,    .none, .none, 1, 0x38, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .mr, .rm16, .r16,   .none, .none, 1, 0x39, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .mr, .rm32, .r32,   .none, .none, 1, 0x39, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .mr, .rm64, .r64,   .none, .none, 1, 0x39, 0x00, 0x00, 0, .long  },
-    .{ .cmp, .rm, .r8,   .rm8,   .none, .none, 1, 0x3a, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .rm, .r16,  .rm16,  .none, .none, 1, 0x3b, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .rm, .r32,  .rm32,  .none, .none, 1, 0x3b, 0x00, 0x00, 0, .none  },
-    .{ .cmp, .rm, .r64,  .rm64,  .none, .none, 1, 0x3b, 0x00, 0x00, 0, .long  },
+    .{ .cmp, .zi, .al,   .imm8,   .none, .none, 1, 0x3c, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .zi, .ax,   .imm16,  .none, .none, 1, 0x3d, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .zi, .eax,  .imm32,  .none, .none, 1, 0x3d, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .zi, .rax,  .imm32s, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .long  },
+    .{ .cmp, .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 7, .none  },
+    .{ .cmp, .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 7, .none  },
+    .{ .cmp, .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 7, .none  },
+    .{ .cmp, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 7, .long  },
+    .{ .cmp, .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 7, .none  },
+    .{ .cmp, .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 7, .none  },
+    .{ .cmp, .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 7, .long  },
+    .{ .cmp, .mr, .rm8,  .r8,     .none, .none, 1, 0x38, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .mr, .rm16, .r16,    .none, .none, 1, 0x39, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .mr, .rm32, .r32,    .none, .none, 1, 0x39, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .mr, .rm64, .r64,    .none, .none, 1, 0x39, 0x00, 0x00, 0, .long  },
+    .{ .cmp, .rm, .r8,   .rm8,    .none, .none, 1, 0x3a, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .rm, .r16,  .rm16,   .none, .none, 1, 0x3b, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .rm, .r32,  .rm32,   .none, .none, 1, 0x3b, 0x00, 0x00, 0, .none  },
+    .{ .cmp, .rm, .r64,  .rm64,   .none, .none, 1, 0x3b, 0x00, 0x00, 0, .long  },
 
     .{ .div, .m, .rm8,  .none, .none, .none, 1, 0xf6, 0x00, 0x00, 6, .none  },
     .{ .div, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .none  },
@@ -214,19 +214,19 @@ pub const table = &[_]Entry{
     .{ .idiv, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 7, .none  },
     .{ .idiv, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 7, .long  },
 
-    .{ .imul, .m,   .rm8,  .none, .none,  .none, 1, 0xf6, 0x00, 0x00, 5, .none  },
-    .{ .imul, .m,   .rm16, .none, .none,  .none, 1, 0xf7, 0x00, 0x00, 5, .none  },
-    .{ .imul, .m,   .rm32, .none, .none,  .none, 1, 0xf7, 0x00, 0x00, 5, .none  },
-    .{ .imul, .m,   .rm64, .none, .none,  .none, 1, 0xf7, 0x00, 0x00, 5, .long  },
-    .{ .imul, .rm,  .r16,  .rm16, .none,  .none, 2, 0x0f, 0xaf, 0x00, 0, .none  },
-    .{ .imul, .rm,  .r32,  .rm32, .none,  .none, 2, 0x0f, 0xaf, 0x00, 0, .none  },
-    .{ .imul, .rm,  .r64,  .rm64, .none,  .none, 2, 0x0f, 0xaf, 0x00, 0, .long  },
-    .{ .imul, .rmi, .r16,  .rm16, .imm8,  .none, 1, 0x6b, 0x00, 0x00, 0, .none  },
-    .{ .imul, .rmi, .r32,  .rm32, .imm8,  .none, 1, 0x6b, 0x00, 0x00, 0, .none  },
-    .{ .imul, .rmi, .r64,  .rm64, .imm8,  .none, 1, 0x6b, 0x00, 0x00, 0, .long  },
-    .{ .imul, .rmi, .r16,  .rm16, .imm16, .none, 1, 0x69, 0x00, 0x00, 0, .none  },
-    .{ .imul, .rmi, .r32,  .rm32, .imm32, .none, 1, 0x69, 0x00, 0x00, 0, .none  },
-    .{ .imul, .rmi, .r64,  .rm64, .imm32, .none, 1, 0x69, 0x00, 0x00, 0, .long  },
+    .{ .imul, .m,   .rm8,  .none, .none,   .none, 1, 0xf6, 0x00, 0x00, 5, .none  },
+    .{ .imul, .m,   .rm16, .none, .none,   .none, 1, 0xf7, 0x00, 0x00, 5, .none  },
+    .{ .imul, .m,   .rm32, .none, .none,   .none, 1, 0xf7, 0x00, 0x00, 5, .none  },
+    .{ .imul, .m,   .rm64, .none, .none,   .none, 1, 0xf7, 0x00, 0x00, 5, .long  },
+    .{ .imul, .rm,  .r16,  .rm16, .none,   .none, 2, 0x0f, 0xaf, 0x00, 0, .none  },
+    .{ .imul, .rm,  .r32,  .rm32, .none,   .none, 2, 0x0f, 0xaf, 0x00, 0, .none  },
+    .{ .imul, .rm,  .r64,  .rm64, .none,   .none, 2, 0x0f, 0xaf, 0x00, 0, .long  },
+    .{ .imul, .rmi, .r16,  .rm16, .imm8s,  .none, 1, 0x6b, 0x00, 0x00, 0, .none  },
+    .{ .imul, .rmi, .r32,  .rm32, .imm8s,  .none, 1, 0x6b, 0x00, 0x00, 0, .none  },
+    .{ .imul, .rmi, .r64,  .rm64, .imm8s,  .none, 1, 0x6b, 0x00, 0x00, 0, .long  },
+    .{ .imul, .rmi, .r16,  .rm16, .imm16,  .none, 1, 0x69, 0x00, 0x00, 0, .none  },
+    .{ .imul, .rmi, .r32,  .rm32, .imm32,  .none, 1, 0x69, 0x00, 0x00, 0, .none  },
+    .{ .imul, .rmi, .r64,  .rm64, .imm32,  .none, 1, 0x69, 0x00, 0x00, 0, .long  },
 
     .{ .int3, .np, .none, .none, .none, .none, 1, 0xcc, 0x00, 0x00, 0, .none },
 
@@ -269,34 +269,34 @@ pub const table = &[_]Entry{
     .{ .lea, .rm, .r32, .m, .none, .none, 1, 0x8d, 0x00, 0x00, 0, .none  },
     .{ .lea, .rm, .r64, .m, .none, .none, 1, 0x8d, 0x00, 0x00, 0, .long  },
 
-    .{ .mov, .mr, .rm8,   .r8,    .none, .none, 1, 0x88, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mr, .rm16,  .r16,   .none, .none, 1, 0x89, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mr, .rm32,  .r32,   .none, .none, 1, 0x89, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mr, .rm64,  .r64,   .none, .none, 1, 0x89, 0x00, 0x00, 0, .long  },
-    .{ .mov, .rm, .r8,    .rm8,   .none, .none, 1, 0x8a, 0x00, 0x00, 0, .none  },
-    .{ .mov, .rm, .r16,   .rm16,  .none, .none, 1, 0x8b, 0x00, 0x00, 0, .none  },
-    .{ .mov, .rm, .r32,   .rm32,  .none, .none, 1, 0x8b, 0x00, 0x00, 0, .none  },
-    .{ .mov, .rm, .r64,   .rm64,  .none, .none, 1, 0x8b, 0x00, 0x00, 0, .long  },
-    .{ .mov, .mr, .rm16,  .sreg,  .none, .none, 1, 0x8c, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mr, .rm64,  .sreg,  .none, .none, 1, 0x8c, 0x00, 0x00, 0, .long  },
-    .{ .mov, .rm, .sreg,  .rm16,  .none, .none, 1, 0x8e, 0x00, 0x00, 0, .none  },
-    .{ .mov, .rm, .sreg,  .rm64,  .none, .none, 1, 0x8e, 0x00, 0x00, 0, .long  },
-    .{ .mov, .fd, .al,    .moffs, .none, .none, 1, 0xa0, 0x00, 0x00, 0, .none  },
-    .{ .mov, .fd, .ax,    .moffs, .none, .none, 1, 0xa1, 0x00, 0x00, 0, .none  },
-    .{ .mov, .fd, .eax,   .moffs, .none, .none, 1, 0xa1, 0x00, 0x00, 0, .none  },
-    .{ .mov, .fd, .rax,   .moffs, .none, .none, 1, 0xa1, 0x00, 0x00, 0, .long  },
-    .{ .mov, .td, .moffs, .al,    .none, .none, 1, 0xa2, 0x00, 0x00, 0, .none  },
-    .{ .mov, .td, .moffs, .ax,    .none, .none, 1, 0xa3, 0x00, 0x00, 0, .none  },
-    .{ .mov, .td, .moffs, .eax,   .none, .none, 1, 0xa3, 0x00, 0x00, 0, .none  },
-    .{ .mov, .td, .moffs, .rax,   .none, .none, 1, 0xa3, 0x00, 0x00, 0, .long  },
-    .{ .mov, .oi, .r8,    .imm8,  .none, .none, 1, 0xb0, 0x00, 0x00, 0, .none  },
-    .{ .mov, .oi, .r16,   .imm16, .none, .none, 1, 0xb8, 0x00, 0x00, 0, .none  },
-    .{ .mov, .oi, .r32,   .imm32, .none, .none, 1, 0xb8, 0x00, 0x00, 0, .none  },
-    .{ .mov, .oi, .r64,   .imm64, .none, .none, 1, 0xb8, 0x00, 0x00, 0, .long  },
-    .{ .mov, .mi, .rm8,   .imm8,  .none, .none, 1, 0xc6, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mi, .rm16,  .imm16, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mi, .rm32,  .imm32, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .none  },
-    .{ .mov, .mi, .rm64,  .imm32, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .long  },
+    .{ .mov, .mr, .rm8,   .r8,     .none, .none, 1, 0x88, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mr, .rm16,  .r16,    .none, .none, 1, 0x89, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mr, .rm32,  .r32,    .none, .none, 1, 0x89, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mr, .rm64,  .r64,    .none, .none, 1, 0x89, 0x00, 0x00, 0, .long  },
+    .{ .mov, .rm, .r8,    .rm8,    .none, .none, 1, 0x8a, 0x00, 0x00, 0, .none  },
+    .{ .mov, .rm, .r16,   .rm16,   .none, .none, 1, 0x8b, 0x00, 0x00, 0, .none  },
+    .{ .mov, .rm, .r32,   .rm32,   .none, .none, 1, 0x8b, 0x00, 0x00, 0, .none  },
+    .{ .mov, .rm, .r64,   .rm64,   .none, .none, 1, 0x8b, 0x00, 0x00, 0, .long  },
+    .{ .mov, .mr, .rm16,  .sreg,   .none, .none, 1, 0x8c, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mr, .rm64,  .sreg,   .none, .none, 1, 0x8c, 0x00, 0x00, 0, .long  },
+    .{ .mov, .rm, .sreg,  .rm16,   .none, .none, 1, 0x8e, 0x00, 0x00, 0, .none  },
+    .{ .mov, .rm, .sreg,  .rm64,   .none, .none, 1, 0x8e, 0x00, 0x00, 0, .long  },
+    .{ .mov, .fd, .al,    .moffs,  .none, .none, 1, 0xa0, 0x00, 0x00, 0, .none  },
+    .{ .mov, .fd, .ax,    .moffs,  .none, .none, 1, 0xa1, 0x00, 0x00, 0, .none  },
+    .{ .mov, .fd, .eax,   .moffs,  .none, .none, 1, 0xa1, 0x00, 0x00, 0, .none  },
+    .{ .mov, .fd, .rax,   .moffs,  .none, .none, 1, 0xa1, 0x00, 0x00, 0, .long  },
+    .{ .mov, .td, .moffs, .al,     .none, .none, 1, 0xa2, 0x00, 0x00, 0, .none  },
+    .{ .mov, .td, .moffs, .ax,     .none, .none, 1, 0xa3, 0x00, 0x00, 0, .none  },
+    .{ .mov, .td, .moffs, .eax,    .none, .none, 1, 0xa3, 0x00, 0x00, 0, .none  },
+    .{ .mov, .td, .moffs, .rax,    .none, .none, 1, 0xa3, 0x00, 0x00, 0, .long  },
+    .{ .mov, .oi, .r8,    .imm8,   .none, .none, 1, 0xb0, 0x00, 0x00, 0, .none  },
+    .{ .mov, .oi, .r16,   .imm16,  .none, .none, 1, 0xb8, 0x00, 0x00, 0, .none  },
+    .{ .mov, .oi, .r32,   .imm32,  .none, .none, 1, 0xb8, 0x00, 0x00, 0, .none  },
+    .{ .mov, .oi, .r64,   .imm64,  .none, .none, 1, 0xb8, 0x00, 0x00, 0, .long  },
+    .{ .mov, .mi, .rm8,   .imm8,   .none, .none, 1, 0xc6, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mi, .rm16,  .imm16,  .none, .none, 1, 0xc7, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mi, .rm32,  .imm32,  .none, .none, 1, 0xc7, 0x00, 0x00, 0, .none  },
+    .{ .mov, .mi, .rm64,  .imm32s, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .long  },
 
     .{ .movsx, .rm, .r16, .rm8,  .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .none  },
     .{ .movsx, .rm, .r32, .rm8,  .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .none  },
@@ -321,25 +321,25 @@ pub const table = &[_]Entry{
 
     .{ .nop, .np, .none, .none, .none, .none, 1, 0x90, 0x00, 0x00, 0, .none },
 
-    .{ .@"or", .zi, .al,   .imm8,  .none, .none, 1, 0x0c, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .zi, .ax,   .imm16, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .zi, .eax,  .imm32, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .zi, .rax,  .imm32, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .long  },
-    .{ .@"or", .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 1, .none  },
-    .{ .@"or", .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 1, .none  },
-    .{ .@"or", .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 1, .none  },
-    .{ .@"or", .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 1, .long  },
-    .{ .@"or", .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 1, .none  },
-    .{ .@"or", .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 1, .none  },
-    .{ .@"or", .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 1, .long  },
-    .{ .@"or", .mr, .rm8,  .r8,    .none, .none, 1, 0x08, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .mr, .rm16, .r16,   .none, .none, 1, 0x09, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .mr, .rm32, .r32,   .none, .none, 1, 0x09, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .mr, .rm64, .r64,   .none, .none, 1, 0x09, 0x00, 0x00, 0, .long  },
-    .{ .@"or", .rm, .r8,   .rm8,   .none, .none, 1, 0x0a, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .rm, .r16,  .rm16,  .none, .none, 1, 0x0b, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .rm, .r32,  .rm32,  .none, .none, 1, 0x0b, 0x00, 0x00, 0, .none  },
-    .{ .@"or", .rm, .r64,  .rm64,  .none, .none, 1, 0x0b, 0x00, 0x00, 0, .long  },
+    .{ .@"or", .zi, .al,   .imm8,   .none, .none, 1, 0x0c, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .zi, .ax,   .imm16,  .none, .none, 1, 0x0d, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .zi, .eax,  .imm32,  .none, .none, 1, 0x0d, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .zi, .rax,  .imm32s, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .long  },
+    .{ .@"or", .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 1, .none  },
+    .{ .@"or", .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 1, .none  },
+    .{ .@"or", .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 1, .none  },
+    .{ .@"or", .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 1, .long  },
+    .{ .@"or", .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 1, .none  },
+    .{ .@"or", .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 1, .none  },
+    .{ .@"or", .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 1, .long  },
+    .{ .@"or", .mr, .rm8,  .r8,     .none, .none, 1, 0x08, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .mr, .rm16, .r16,    .none, .none, 1, 0x09, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .mr, .rm32, .r32,    .none, .none, 1, 0x09, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .mr, .rm64, .r64,    .none, .none, 1, 0x09, 0x00, 0x00, 0, .long  },
+    .{ .@"or", .rm, .r8,   .rm8,    .none, .none, 1, 0x0a, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .rm, .r16,  .rm16,   .none, .none, 1, 0x0b, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .rm, .r32,  .rm32,   .none, .none, 1, 0x0b, 0x00, 0x00, 0, .none  },
+    .{ .@"or", .rm, .r64,  .rm64,   .none, .none, 1, 0x0b, 0x00, 0x00, 0, .long  },
 
     .{ .pop, .o, .r16,  .none, .none, .none, 1, 0x58, 0x00, 0x00, 0, .none  },
     .{ .pop, .o, .r64,  .none, .none, .none, 1, 0x58, 0x00, 0x00, 0, .none  },
@@ -382,25 +382,25 @@ pub const table = &[_]Entry{
     .{ .sar, .mi, .rm32, .imm8,  .none, .none, 1, 0xc1, 0x00, 0x00, 7, .none  },
     .{ .sar, .mi, .rm64, .imm8,  .none, .none, 1, 0xc1, 0x00, 0x00, 7, .long  },
 
-    .{ .sbb, .zi, .al,   .imm8,  .none, .none, 1, 0x1c, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .zi, .ax,   .imm16, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .zi, .eax,  .imm32, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .zi, .rax,  .imm32, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .long  },
-    .{ .sbb, .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 3, .none  },
-    .{ .sbb, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 3, .none  },
-    .{ .sbb, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 3, .none  },
-    .{ .sbb, .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 3, .long  },
-    .{ .sbb, .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 3, .none  },
-    .{ .sbb, .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 3, .none  },
-    .{ .sbb, .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 3, .long  },
-    .{ .sbb, .mr, .rm8,  .r8,    .none, .none, 1, 0x18, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .mr, .rm16, .r16,   .none, .none, 1, 0x19, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .mr, .rm32, .r32,   .none, .none, 1, 0x19, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .mr, .rm64, .r64,   .none, .none, 1, 0x19, 0x00, 0x00, 0, .long  },
-    .{ .sbb, .rm, .r8,   .rm8,   .none, .none, 1, 0x1a, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .rm, .r16,  .rm16,  .none, .none, 1, 0x1b, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .rm, .r32,  .rm32,  .none, .none, 1, 0x1b, 0x00, 0x00, 0, .none  },
-    .{ .sbb, .rm, .r64,  .rm64,  .none, .none, 1, 0x1b, 0x00, 0x00, 0, .long  },
+    .{ .sbb, .zi, .al,   .imm8,   .none, .none, 1, 0x1c, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .zi, .ax,   .imm16,  .none, .none, 1, 0x1d, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .zi, .eax,  .imm32,  .none, .none, 1, 0x1d, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .zi, .rax,  .imm32s, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .long  },
+    .{ .sbb, .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 3, .none  },
+    .{ .sbb, .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 3, .none  },
+    .{ .sbb, .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 3, .none  },
+    .{ .sbb, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 3, .long  },
+    .{ .sbb, .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 3, .none  },
+    .{ .sbb, .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 3, .none  },
+    .{ .sbb, .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 3, .long  },
+    .{ .sbb, .mr, .rm8,  .r8,     .none, .none, 1, 0x18, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .mr, .rm16, .r16,    .none, .none, 1, 0x19, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .mr, .rm32, .r32,    .none, .none, 1, 0x19, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .mr, .rm64, .r64,    .none, .none, 1, 0x19, 0x00, 0x00, 0, .long  },
+    .{ .sbb, .rm, .r8,   .rm8,    .none, .none, 1, 0x1a, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .rm, .r16,  .rm16,   .none, .none, 1, 0x1b, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .rm, .r32,  .rm32,   .none, .none, 1, 0x1b, 0x00, 0x00, 0, .none  },
+    .{ .sbb, .rm, .r64,  .rm64,   .none, .none, 1, 0x1b, 0x00, 0x00, 0, .long  },
 
     .{ .seta,   .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .none },
     .{ .setae,  .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
@@ -459,62 +459,62 @@ pub const table = &[_]Entry{
     .{ .shr, .mi, .rm32, .imm8,  .none, .none, 1, 0xc1, 0x00, 0x00, 5, .none  },
     .{ .shr, .mi, .rm64, .imm8,  .none, .none, 1, 0xc1, 0x00, 0x00, 5, .long  },
 
-    .{ .sub, .zi, .al,   .imm8,  .none, .none, 1, 0x2c, 0x00, 0x00, 0, .none  },
-    .{ .sub, .zi, .ax,   .imm16, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .none  },
-    .{ .sub, .zi, .eax,  .imm32, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .none  },
-    .{ .sub, .zi, .rax,  .imm32, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .long  },
-    .{ .sub, .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 5, .none  },
-    .{ .sub, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 5, .none  },
-    .{ .sub, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 5, .none  },
-    .{ .sub, .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 5, .long  },
-    .{ .sub, .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 5, .none  },
-    .{ .sub, .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 5, .none  },
-    .{ .sub, .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 5, .long  },
-    .{ .sub, .mr, .rm8,  .r8,    .none, .none, 1, 0x28, 0x00, 0x00, 0, .none  },
-    .{ .sub, .mr, .rm16, .r16,   .none, .none, 1, 0x29, 0x00, 0x00, 0, .none  },
-    .{ .sub, .mr, .rm32, .r32,   .none, .none, 1, 0x29, 0x00, 0x00, 0, .none  },
-    .{ .sub, .mr, .rm64, .r64,   .none, .none, 1, 0x29, 0x00, 0x00, 0, .long  },
-    .{ .sub, .rm, .r8,   .rm8,   .none, .none, 1, 0x2a, 0x00, 0x00, 0, .none  },
-    .{ .sub, .rm, .r16,  .rm16,  .none, .none, 1, 0x2b, 0x00, 0x00, 0, .none  },
-    .{ .sub, .rm, .r32,  .rm32,  .none, .none, 1, 0x2b, 0x00, 0x00, 0, .none  },
-    .{ .sub, .rm, .r64,  .rm64,  .none, .none, 1, 0x2b, 0x00, 0x00, 0, .long  },
+    .{ .sub, .zi, .al,   .imm8,   .none, .none, 1, 0x2c, 0x00, 0x00, 0, .none  },
+    .{ .sub, .zi, .ax,   .imm16,  .none, .none, 1, 0x2d, 0x00, 0x00, 0, .none  },
+    .{ .sub, .zi, .eax,  .imm32,  .none, .none, 1, 0x2d, 0x00, 0x00, 0, .none  },
+    .{ .sub, .zi, .rax,  .imm32s, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .long  },
+    .{ .sub, .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 5, .none  },
+    .{ .sub, .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 5, .none  },
+    .{ .sub, .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 5, .none  },
+    .{ .sub, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 5, .long  },
+    .{ .sub, .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 5, .none  },
+    .{ .sub, .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 5, .none  },
+    .{ .sub, .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 5, .long  },
+    .{ .sub, .mr, .rm8,  .r8,     .none, .none, 1, 0x28, 0x00, 0x00, 0, .none  },
+    .{ .sub, .mr, .rm16, .r16,    .none, .none, 1, 0x29, 0x00, 0x00, 0, .none  },
+    .{ .sub, .mr, .rm32, .r32,    .none, .none, 1, 0x29, 0x00, 0x00, 0, .none  },
+    .{ .sub, .mr, .rm64, .r64,    .none, .none, 1, 0x29, 0x00, 0x00, 0, .long  },
+    .{ .sub, .rm, .r8,   .rm8,    .none, .none, 1, 0x2a, 0x00, 0x00, 0, .none  },
+    .{ .sub, .rm, .r16,  .rm16,   .none, .none, 1, 0x2b, 0x00, 0x00, 0, .none  },
+    .{ .sub, .rm, .r32,  .rm32,   .none, .none, 1, 0x2b, 0x00, 0x00, 0, .none  },
+    .{ .sub, .rm, .r64,  .rm64,   .none, .none, 1, 0x2b, 0x00, 0x00, 0, .long  },
 
     .{ .syscall, .np, .none, .none, .none, .none, 2, 0x0f, 0x05, 0x00, 0, .none },
 
-    .{ .@"test", .zi, .al,   .imm8,  .none, .none, 1, 0xa8, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .zi, .ax,   .imm16, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .zi, .eax,  .imm32, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .zi, .rax,  .imm32, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .long  },
-    .{ .@"test", .mi, .rm8,  .imm8,  .none, .none, 1, 0xf6, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .mi, .rm16, .imm16, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .mi, .rm32, .imm32, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .mi, .rm64, .imm32, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .long  },
-    .{ .@"test", .mr, .rm8,  .r8,    .none, .none, 1, 0x84, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .mr, .rm16, .r16,   .none, .none, 1, 0x85, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .mr, .rm32, .r32,   .none, .none, 1, 0x85, 0x00, 0x00, 0, .none  },
-    .{ .@"test", .mr, .rm64, .r64,   .none, .none, 1, 0x85, 0x00, 0x00, 0, .long  },
-
-    .{ .ud2, .np, .none, .none, .none, .none, 2, 0x0f, 0x0b, 0x00, 0, .none },
-
-    .{ .xor, .zi, .al,   .imm8,  .none, .none, 1, 0x34, 0x00, 0x00, 0, .none  },
-    .{ .xor, .zi, .ax,   .imm16, .none, .none, 1, 0x35, 0x00, 0x00, 0, .none  },
-    .{ .xor, .zi, .eax,  .imm32, .none, .none, 1, 0x35, 0x00, 0x00, 0, .none  },
-    .{ .xor, .zi, .rax,  .imm32, .none, .none, 1, 0x35, 0x00, 0x00, 0, .long  },
-    .{ .xor, .mi, .rm8,  .imm8,  .none, .none, 1, 0x80, 0x00, 0x00, 6, .none  },
-    .{ .xor, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 6, .none  },
-    .{ .xor, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 6, .none  },
-    .{ .xor, .mi, .rm64, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 6, .long  },
-    .{ .xor, .mi, .rm16, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 6, .none  },
-    .{ .xor, .mi, .rm32, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 6, .none  },
-    .{ .xor, .mi, .rm64, .imm8,  .none, .none, 1, 0x83, 0x00, 0x00, 6, .long  },
-    .{ .xor, .mr, .rm8,  .r8,    .none, .none, 1, 0x30, 0x00, 0x00, 0, .none  },
-    .{ .xor, .mr, .rm16, .r16,   .none, .none, 1, 0x31, 0x00, 0x00, 0, .none  },
-    .{ .xor, .mr, .rm32, .r32,   .none, .none, 1, 0x31, 0x00, 0x00, 0, .none  },
-    .{ .xor, .mr, .rm64, .r64,   .none, .none, 1, 0x31, 0x00, 0x00, 0, .long  },
-    .{ .xor, .rm, .r8,   .rm8,   .none, .none, 1, 0x32, 0x00, 0x00, 0, .none  },
-    .{ .xor, .rm, .r16,  .rm16,  .none, .none, 1, 0x33, 0x00, 0x00, 0, .none  },
-    .{ .xor, .rm, .r32,  .rm32,  .none, .none, 1, 0x33, 0x00, 0x00, 0, .none  },
-    .{ .xor, .rm, .r64,  .rm64,  .none, .none, 1, 0x33, 0x00, 0x00, 0, .long  },
+    .{ .@"test", .zi, .al,   .imm8,   .none, .none, 1, 0xa8, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .zi, .ax,   .imm16,  .none, .none, 1, 0xa9, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .zi, .eax,  .imm32,  .none, .none, 1, 0xa9, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .zi, .rax,  .imm32s, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .long  },
+    .{ .@"test", .mi, .rm8,  .imm8,   .none, .none, 1, 0xf6, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .mi, .rm16, .imm16,  .none, .none, 1, 0xf7, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .mi, .rm32, .imm32,  .none, .none, 1, 0xf7, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .mi, .rm64, .imm32s, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .long  },
+    .{ .@"test", .mr, .rm8,  .r8,     .none, .none, 1, 0x84, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .mr, .rm16, .r16,    .none, .none, 1, 0x85, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .mr, .rm32, .r32,    .none, .none, 1, 0x85, 0x00, 0x00, 0, .none  },
+    .{ .@"test", .mr, .rm64, .r64,    .none, .none, 1, 0x85, 0x00, 0x00, 0, .long  },
+
+    .{ .ud2, .np, .none, .none, .none, .none, 2, 0x0f, 0x0b, 0x00, 0, .none  },
+
+    .{ .xor, .zi, .al,   .imm8,   .none, .none, 1, 0x34, 0x00, 0x00, 0, .none  },
+    .{ .xor, .zi, .ax,   .imm16,  .none, .none, 1, 0x35, 0x00, 0x00, 0, .none  },
+    .{ .xor, .zi, .eax,  .imm32,  .none, .none, 1, 0x35, 0x00, 0x00, 0, .none  },
+    .{ .xor, .zi, .rax,  .imm32s, .none, .none, 1, 0x35, 0x00, 0x00, 0, .long  },
+    .{ .xor, .mi, .rm8,  .imm8,   .none, .none, 1, 0x80, 0x00, 0x00, 6, .none  },
+    .{ .xor, .mi, .rm16, .imm16,  .none, .none, 1, 0x81, 0x00, 0x00, 6, .none  },
+    .{ .xor, .mi, .rm32, .imm32,  .none, .none, 1, 0x81, 0x00, 0x00, 6, .none  },
+    .{ .xor, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 6, .long  },
+    .{ .xor, .mi, .rm16, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 6, .none  },
+    .{ .xor, .mi, .rm32, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 6, .none  },
+    .{ .xor, .mi, .rm64, .imm8s,  .none, .none, 1, 0x83, 0x00, 0x00, 6, .long  },
+    .{ .xor, .mr, .rm8,  .r8,     .none, .none, 1, 0x30, 0x00, 0x00, 0, .none  },
+    .{ .xor, .mr, .rm16, .r16,    .none, .none, 1, 0x31, 0x00, 0x00, 0, .none  },
+    .{ .xor, .mr, .rm32, .r32,    .none, .none, 1, 0x31, 0x00, 0x00, 0, .none  },
+    .{ .xor, .mr, .rm64, .r64,    .none, .none, 1, 0x31, 0x00, 0x00, 0, .long  },
+    .{ .xor, .rm, .r8,   .rm8,    .none, .none, 1, 0x32, 0x00, 0x00, 0, .none  },
+    .{ .xor, .rm, .r16,  .rm16,   .none, .none, 1, 0x33, 0x00, 0x00, 0, .none  },
+    .{ .xor, .rm, .r32,  .rm32,   .none, .none, 1, 0x33, 0x00, 0x00, 0, .none  },
+    .{ .xor, .rm, .r64,  .rm64,   .none, .none, 1, 0x33, 0x00, 0x00, 0, .long  },
 
     // SSE
     .{ .addss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x58, 0, .sse },
@@ -540,3 +540,4 @@ pub const table = &[_]Entry{
     .{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0x66, 0x0f, 0x2e, 0, .sse2 },
 };
 // zig fmt: on
+
src/arch/x86_64/Mir.zig
@@ -34,6 +34,7 @@ pub const Inst = struct {
         ///       0b01  reg1, [reg2 + imm32]
         ///       0b01  reg1, [ds:imm32]
         ///       0b10  [reg1 + imm32], reg2
+        ///       0b11  reg1, imm_s
         /// Notes:
         ///  * If reg2 is `none` then it means Data field `imm` is used as the immediate.
         ///  * When two imm32 values are required, Data field `payload` points at `ImmPair`.
@@ -421,6 +422,8 @@ pub const Inst = struct {
         inst: Index,
         /// A 32-bit immediate value.
         imm: u32,
+        /// A 32-bit signed immediate value.
+        imm_s: i32,
         /// A 32-bit signed displacement value.
         disp: i32,
         /// A condition code for use with EFLAGS register.