x86_64: implement f16 cmp

This commit is contained in:
Jacob Young 2023-05-05 22:16:13 -04:00
parent 32ab930f1d
commit ae588a09f2
6 changed files with 957 additions and 727 deletions

View File

@ -6737,26 +6737,43 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
try self.genBinOpMir(switch (ty.zigTypeTag()) {
else => .cmp,
switch (ty.zigTypeTag()) {
else => try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv),
.Float => switch (ty.floatBits(self.target.*)) {
32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
.ucomiss
else
return self.fail("TODO implement airCmp for {} without sse", .{
ty.fmt(self.bin_file.options.module.?),
}),
64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
.ucomisd
else
return self.fail("TODO implement airCmp for {} without sse2", .{
ty.fmt(self.bin_file.options.module.?),
}),
16 => if (self.hasFeature(.f16c)) {
const dst_reg = dst_mcv.getReg().?.to128();
const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
defer self.register_manager.unlockReg(tmp_lock);
if (src_mcv.isRegister())
try self.asmRegisterRegisterRegister(
.vpunpcklwd,
dst_reg,
dst_reg,
src_mcv.getReg().?.to128(),
)
else
try self.asmRegisterMemoryImmediate(
.vpinsrw,
dst_reg,
src_mcv.mem(.word),
Immediate.u(1),
);
try self.asmRegisterRegister(.vcvtph2ps, dst_reg, dst_reg);
try self.asmRegisterRegister(.vmovshdup, tmp_reg, dst_reg);
try self.genBinOpMir(.ucomiss, ty, dst_mcv, .{ .register = tmp_reg });
} else return self.fail("TODO implement airCmp for {}", .{
ty.fmt(self.bin_file.options.module.?),
}),
32 => try self.genBinOpMir(.ucomiss, ty, dst_mcv, src_mcv),
64 => try self.genBinOpMir(.ucomisd, ty, dst_mcv, src_mcv),
else => return self.fail("TODO implement airCmp for {}", .{
ty.fmt(self.bin_file.options.module.?),
}),
},
}, ty, dst_mcv, src_mcv);
}
const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
const result = MCValue{
@ -7834,8 +7851,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
else switch (abi_size) {
2 => return try self.asmRegisterRegisterImmediate(
if (dst_reg.class() == .floating_point) .pinsrw else .pextrw,
registerAlias(dst_reg, abi_size),
registerAlias(src_reg, abi_size),
registerAlias(dst_reg, 4),
registerAlias(src_reg, 4),
Immediate.u(0),
),
4 => .movd,
@ -8045,7 +8062,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
try self.asmMemoryRegisterImmediate(
.pextrw,
dst_mem,
registerAlias(src_reg, abi_size),
src_reg.to128(),
Immediate.u(0),
)
else

View File

@ -58,9 +58,9 @@ pub fn findByMnemonic(
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,
.none, .short => if (rex_required) continue,
.rex, .rex_short => if (!rex_required) continue,
else => {},
}
for (input_ops, data.ops) |input_op, data_op|
if (!input_op.isSubset(data_op)) continue :next;
@ -90,24 +90,26 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
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, .sse_long, .sse2_long, .rex => {},
.none, .short, .rex, .rex_short, .vex_128, .vex_256 => continue,
.long, .vex_128_long, .vex_256_long => {},
}
} else if (prefixes.rex.present and !prefixes.rex.isSet()) {
switch (data.mode) {
.rex => {},
.rex, .rex_short => {},
else => continue,
}
} else if (prefixes.legacy.prefix_66) {
switch (enc.operandBitSize()) {
16 => {},
else => continue,
switch (data.mode) {
.short, .rex_short => {},
.none, .rex, .vex_128, .vex_256 => continue,
.long, .vex_128_long, .vex_256_long => continue,
}
} else {
switch (data.mode) {
.none => switch (enc.operandBitSize()) {
16 => continue,
else => {},
.none => switch (data.mode) {
.short, .rex_short => continue,
.none, .rex, .vex_128, .vex_256 => {},
.long, .vex_128_long, .vex_256_long => {},
},
else => continue,
}
@ -131,28 +133,11 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
pub fn modRmExt(encoding: Encoding) u3 {
return switch (encoding.data.op_en) {
.m, .mi, .m1, .mc => encoding.data.modrm_ext,
.m, .mi, .m1, .mc, .vmi => encoding.data.modrm_ext,
else => unreachable,
};
}
pub fn operandBitSize(encoding: Encoding) u64 {
return switch (encoding.data.mode) {
.short => 16,
.long => 64,
else => switch (encoding.data.op_en) {
.np => switch (encoding.data.ops[0]) {
.o16 => 16,
.o32 => 32,
.o64 => 64,
else => 32,
},
.td => encoding.data.ops[1].bitSize(),
else => encoding.data.ops[0].bitSize(),
},
};
}
pub fn format(
encoding: Encoding,
comptime fmt: []const u8,
@ -220,17 +205,17 @@ pub fn format(
};
try writer.print("+{s} ", .{tag});
},
.m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),
.mr, .rm, .rmi, .mri, .mrc, .rrm, .rrmi => try writer.writeAll("/r "),
.m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
.mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi => try writer.writeAll("/r "),
}
switch (encoding.data.op_en) {
.i, .d, .zi, .oi, .mi, .rmi, .mri, .rrmi => {
.i, .d, .zi, .oi, .mi, .rmi, .mri, .vmi, .rvmi => {
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],
.rrmi => encoding.data.ops[3],
.rmi, .mri, .vmi => encoding.data.ops[2],
.rvmi => encoding.data.ops[3],
else => unreachable,
};
const tag = switch (op) {
@ -245,7 +230,7 @@ pub fn format(
};
try writer.print("{s} ", .{tag});
},
.np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rrm => {},
.np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm => {},
}
try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
@ -315,8 +300,7 @@ pub const Mnemonic = enum {
movaps, movss, movups,
mulss,
orps,
pextrw,
pinsrw,
pextrw, pinsrw,
sqrtps,
sqrtss,
subss,
@ -335,14 +319,25 @@ pub const Mnemonic = enum {
movupd,
mulsd,
orpd,
sqrtpd,
sqrtsd,
pshufhw, pshuflw,
psrld, psrlq, psrlw,
punpckhbw, punpckhdq, punpckhqdq, punpckhwd,
punpcklbw, punpckldq, punpcklqdq, punpcklwd,
sqrtpd, sqrtsd,
subsd,
ucomisd,
xorpd,
// SSE3
movddup, movshdup, movsldup,
// SSE4.1
roundss,
roundsd,
roundsd, roundss,
// AVX
vmovddup, vmovshdup, vmovsldup,
vpextrw, vpinsrw,
vpshufhw, vpshuflw,
vpsrld, vpsrlq, vpsrlw,
vpunpckhbw, vpunpckhdq, vpunpckhqdq, vpunpckhwd,
vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,
// F16C
vcvtph2ps, vcvtps2ph,
// zig fmt: on
@ -357,7 +352,7 @@ pub const OpEn = enum {
fd, td,
m1, mc, mi, mr, rm,
rmi, mri, mrc,
rrm, rrmi,
vmi, rvm, rvmi,
// zig fmt: on
};
@ -372,6 +367,7 @@ pub const Op = enum {
cl,
r8, r16, r32, r64,
rm8, rm16, rm32, rm64,
r32_m16, r64_m16,
m8, m16, m32, m64, m80, m128,
rel8, rel16, rel32,
m,
@ -450,16 +446,49 @@ pub const Op = enum {
}
}
pub fn bitSize(op: Op) u64 {
pub fn immBitSize(op: Op) u64 {
return switch (op) {
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
.al, .cl, .r8, .rm8 => unreachable,
.ax, .r16, .rm16 => unreachable,
.eax, .r32, .rm32, .r32_m16 => unreachable,
.rax, .r64, .rm64, .r64_m16 => unreachable,
.xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
.m8, .m16, .m32, .m64, .m80, .m128 => unreachable,
.unity => 1,
.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,
.imm8, .imm8s, .rel8 => 8,
.imm16, .imm16s, .rel16 => 16,
.imm32, .imm32s, .rel32 => 32,
.imm64 => 64,
};
}
pub fn regBitSize(op: Op) u64 {
return switch (op) {
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
.unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
.rel8, .rel16, .rel32 => unreachable,
.m8, .m16, .m32, .m64, .m80, .m128 => unreachable,
.al, .cl, .r8, .rm8 => 8,
.ax, .r16, .rm16 => 16,
.eax, .r32, .rm32, .r32_m16 => 32,
.rax, .r64, .rm64, .r64_m16 => 64,
.xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
};
}
pub fn memBitSize(op: Op) u64 {
return switch (op) {
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
.unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
.rel8, .rel16, .rel32 => unreachable,
.al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .xmm => unreachable,
.m8, .rm8 => 8,
.m16, .rm16, .r32_m16, .r64_m16 => 16,
.m32, .rm32, .xmm_m32 => 32,
.m64, .rm64, .xmm_m64 => 64,
.m80 => 80,
.m128, .xmm, .xmm_m128 => 128,
.m128, .xmm_m128 => 128,
};
}
@ -482,6 +511,7 @@ pub const Op = enum {
.al, .ax, .eax, .rax,
.r8, .r16, .r32, .r64,
.rm8, .rm16, .rm32, .rm64,
.r32_m16, .r64_m16,
.xmm, .xmm_m32, .xmm_m64, .xmm_m128,
=> true,
else => false,
@ -506,6 +536,7 @@ pub const Op = enum {
// zig fmt: off
return switch (op) {
.rm8, .rm16, .rm32, .rm64,
.r32_m16, .r64_m16,
.m8, .m16, .m32, .m64, .m80, .m128,
.m,
.xmm_m32, .xmm_m64, .xmm_m128,
@ -528,18 +559,12 @@ pub const Op = enum {
.al, .ax, .eax, .rax, .cl => .general_purpose,
.r8, .r16, .r32, .r64 => .general_purpose,
.rm8, .rm16, .rm32, .rm64 => .general_purpose,
.r32_m16, .r64_m16 => .general_purpose,
.sreg => .segment,
.xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
};
}
pub fn isFloatingPointRegister(op: Op) bool {
return switch (op) {
.xmm, .xmm_m32, .xmm_m64, .xmm_m128 => true,
else => false,
};
}
/// Given an operand `op` checks if `target` is a subset for the purposes of the encoding.
pub fn isSubset(op: Op, target: Op) bool {
switch (op) {
@ -553,30 +578,27 @@ pub const Op = enum {
if (op.isRegister() and target.isRegister()) {
return switch (target) {
.cl, .al, .ax, .eax, .rax => op == target,
else => op.class() == target.class() and switch (target.class()) {
.floating_point => true,
else => op.bitSize() == target.bitSize(),
},
else => op.class() == target.class() and op.regBitSize() == target.regBitSize(),
};
}
if (op.isMemory() and target.isMemory()) {
switch (target) {
.m => return true,
else => return op.bitSize() == target.bitSize(),
else => return op.memBitSize() == target.memBitSize(),
}
}
if (op.isImmediate() and target.isImmediate()) {
switch (target) {
.imm64 => if (op.bitSize() <= 64) return true,
.imm32s, .rel32 => if (op.bitSize() < 32 or (op.bitSize() == 32 and op.isSigned()))
.imm64 => if (op.immBitSize() <= 64) return true,
.imm32s, .rel32 => if (op.immBitSize() < 32 or (op.immBitSize() == 32 and op.isSigned()))
return true,
.imm32 => if (op.bitSize() <= 32) return true,
.imm16s, .rel16 => if (op.bitSize() < 16 or (op.bitSize() == 16 and op.isSigned()))
.imm32 => if (op.immBitSize() <= 32) return true,
.imm16s, .rel16 => if (op.immBitSize() < 16 or (op.immBitSize() == 16 and op.isSigned()))
return true,
.imm16 => if (op.bitSize() <= 16) return true,
.imm8s, .rel8 => if (op.bitSize() < 8 or (op.bitSize() == 8 and op.isSigned()))
.imm16 => if (op.immBitSize() <= 16) return true,
.imm8s, .rel8 => if (op.immBitSize() < 8 or (op.immBitSize() == 8 and op.isSigned()))
return true,
.imm8 => if (op.bitSize() <= 8) return true,
.imm8 => if (op.immBitSize() <= 8) return true,
else => {},
}
return op == target;
@ -590,8 +612,9 @@ pub const Op = enum {
pub const Mode = enum {
none,
short,
rex,
long,
rex,
rex_short,
vex_128,
vex_128_long,
vex_256,
@ -600,9 +623,11 @@ pub const Mode = enum {
pub const Feature = enum {
none,
avx,
f16c,
sse,
sse2,
sse3,
sse4_1,
x87,
};

View File

@ -108,12 +108,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
.orps,
.pextrw,
.pinsrw,
.roundss,
.sqrtps,
.sqrtss,
.subss,
.ucomiss,
.xorps,
.addsd,
.andnpd,
.andpd,
@ -127,13 +127,51 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
.movsd,
.mulsd,
.orpd,
.roundsd,
.pshufhw,
.pshuflw,
.psrld,
.psrlq,
.psrlw,
.punpckhbw,
.punpckhdq,
.punpckhqdq,
.punpckhwd,
.punpcklbw,
.punpckldq,
.punpcklqdq,
.punpcklwd,
.sqrtpd,
.sqrtsd,
.subsd,
.ucomisd,
.xorpd,
.movddup,
.movshdup,
.movsldup,
.roundsd,
.roundss,
.vmovddup,
.vmovshdup,
.vmovsldup,
.vpextrw,
.vpinsrw,
.vpshufhw,
.vpshuflw,
.vpsrld,
.vpsrlq,
.vpsrlw,
.vpunpckhbw,
.vpunpckhdq,
.vpunpckhqdq,
.vpunpckhwd,
.vpunpcklbw,
.vpunpckldq,
.vpunpcklqdq,
.vpunpcklwd,
.vcvtph2ps,
.vcvtps2ph,
=> try lower.mirGeneric(inst),

View File

@ -196,8 +196,6 @@ pub const Inst = struct {
pextrw,
/// Insert word
pinsrw,
/// Round scalar single-precision floating-point values
roundss,
/// Square root of scalar single precision floating-point value
sqrtps,
/// Subtract scalar single-precision floating-point values
@ -208,6 +206,7 @@ pub const Inst = struct {
ucomiss,
/// Bitwise logical xor of packed single precision floating-point values
xorps,
/// Add double precision floating point values
addsd,
/// Bitwise logical and not of packed double precision floating-point values
@ -234,8 +233,32 @@ pub const Inst = struct {
mulsd,
/// Bitwise logical or of packed double precision floating-point values
orpd,
/// Round scalar double-precision floating-point values
roundsd,
/// Shuffle packed high words
pshufhw,
/// Shuffle packed low words
pshuflw,
/// Shift packed data right logical
psrld,
/// Shift packed data right logical
psrlq,
/// Shift packed data right logical
psrlw,
/// Unpack high data
punpckhbw,
/// Unpack high data
punpckhdq,
/// Unpack high data
punpckhqdq,
/// Unpack high data
punpckhwd,
/// Unpack low data
punpcklbw,
/// Unpack low data
punpckldq,
/// Unpack low data
punpcklqdq,
/// Unpack low data
punpcklwd,
/// Square root of double precision floating-point values
sqrtpd,
/// Square root of scalar double precision floating-point value
@ -247,6 +270,55 @@ pub const Inst = struct {
/// Bitwise logical xor of packed double precision floating-point values
xorpd,
/// Replicate double floating-point values
movddup,
/// Replicate single floating-point values
movshdup,
/// Replicate single floating-point values
movsldup,
/// Round scalar double-precision floating-point values
roundsd,
/// Round scalar single-precision floating-point values
roundss,
/// Replicate double floating-point values
vmovddup,
/// Replicate single floating-point values
vmovshdup,
/// Replicate single floating-point values
vmovsldup,
/// Extract word
vpextrw,
/// Insert word
vpinsrw,
/// Shuffle packed high words
vpshufhw,
/// Shuffle packed low words
vpshuflw,
/// Shift packed data right logical
vpsrld,
/// Shift packed data right logical
vpsrlq,
/// Shift packed data right logical
vpsrlw,
/// Unpack high data
vpunpckhbw,
/// Unpack high data
vpunpckhdq,
/// Unpack high data
vpunpckhqdq,
/// Unpack high data
vpunpckhwd,
/// Unpack low data
vpunpcklbw,
/// Unpack low data
vpunpckldq,
/// Unpack low data
vpunpcklqdq,
/// Unpack low data
vpunpcklwd,
/// Convert 16-bit floating-point values to single-precision floating-point values
vcvtph2ps,
/// Convert single-precision floating-point values to 16-bit floating-point values

View File

@ -151,15 +151,12 @@ pub const Instruction = struct {
moffs.offset,
}),
},
.imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
.imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
}
}
pub fn fmtPrint(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(fmt) {
return .{ .data = .{
.op = op,
.enc_op = enc_op,
} };
return .{ .data = .{ .op = op, .enc_op = enc_op } };
}
};
@ -210,7 +207,7 @@ pub const Instruction = struct {
const data = enc.data;
switch (data.mode) {
.none, .short, .rex, .long => {
.none, .short, .long, .rex, .rex_short => {
try inst.encodeLegacyPrefixes(encoder);
try inst.encodeMandatoryPrefix(encoder);
try inst.encodeRexPrefix(encoder);
@ -232,15 +229,16 @@ pub const Instruction = struct {
else => {
const mem_op = switch (data.op_en) {
.m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
.rm, .rmi => inst.ops[1],
.rm, .rmi, .vmi => inst.ops[1],
.rvm, .rvmi => inst.ops[2],
else => unreachable,
};
switch (mem_op) {
.reg => |reg| {
const rm = switch (data.op_en) {
.m, .mi, .m1, .mc => enc.modRmExt(),
.m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
.mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
.rm, .rmi => inst.ops[0].reg.lowEnc(),
.rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(),
else => unreachable,
};
try encoder.modRm_direct(rm, reg.lowEnc());
@ -259,7 +257,8 @@ pub const Instruction = struct {
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),
.rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
.rvmi => try encodeImm(inst.ops[3].imm, data.ops[3], encoder),
else => {},
}
},
@ -291,11 +290,9 @@ pub const Instruction = struct {
.rep, .repe, .repz => legacy.prefix_f3 = true,
}
if (data.mode == .none) {
const bit_size = enc.operandBitSize();
if (bit_size == 16) {
legacy.set16BitOverride();
}
switch (data.mode) {
.short, .rex_short => legacy.set16BitOverride(),
else => {},
}
const segment_override: ?Register = switch (op_en) {
@ -318,7 +315,7 @@ pub const Instruction = struct {
}
else
null,
.rrm, .rrmi => unreachable,
.vmi, .rvm, .rvmi => unreachable,
};
if (segment_override) |seg| {
legacy.setSegmentOverride(seg);
@ -353,7 +350,7 @@ pub const Instruction = struct {
rex.b = b_x_op.isBaseExtended();
rex.x = b_x_op.isIndexExtended();
},
.rrm, .rrmi => unreachable,
.vmi, .rvm, .rvmi => unreachable,
}
try encoder.rex(rex);
@ -375,18 +372,19 @@ pub const Instruction = struct {
switch (op_en) {
.np, .i, .zi, .fd, .td, .d => {},
.o, .oi => vex.b = inst.ops[0].reg.isExtended(),
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rrm, .rrmi => {
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi => {
const r_op = switch (op_en) {
.rm, .rmi, .rrm, .rrmi => inst.ops[0],
.rm, .rmi, .rvm, .rvmi => inst.ops[0],
.mr, .mri, .mrc => inst.ops[1],
else => .none,
.m, .mi, .m1, .mc, .vmi => .none,
else => unreachable,
};
vex.r = r_op.isBaseExtended();
const b_x_op = switch (op_en) {
.rm, .rmi => inst.ops[1],
.rm, .rmi, .vmi => inst.ops[1],
.m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
.rrm, .rrmi => inst.ops[2],
.rvm, .rvmi => inst.ops[2],
else => unreachable,
};
vex.b = b_x_op.isBaseExtended();
@ -417,7 +415,8 @@ pub const Instruction = struct {
switch (op_en) {
else => {},
.rrm, .rrmi => vex.v = inst.ops[1].reg,
.vmi => vex.v = inst.ops[0].reg,
.rvm, .rvmi => vex.v = inst.ops[1].reg,
}
try encoder.vex(vex);
@ -515,8 +514,8 @@ pub const Instruction = struct {
}
fn encodeImm(imm: Immediate, kind: Encoding.Op, encoder: anytype) !void {
const raw = imm.asUnsigned(kind.bitSize());
switch (kind.bitSize()) {
const raw = imm.asUnsigned(kind.immBitSize());
switch (kind.immBitSize()) {
8 => try encoder.imm8(@intCast(u8, raw)),
16 => try encoder.imm16(@intCast(u16, raw)),
32 => try encoder.imm32(@intCast(u32, raw)),

File diff suppressed because it is too large Load Diff