aboutsummaryrefslogtreecommitdiff
path: root/src/arch/x86_64/Encoding.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86_64/Encoding.zig')
-rw-r--r--src/arch/x86_64/Encoding.zig556
1 files changed, 385 insertions, 171 deletions
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index a977af7842..625a5283b9 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -23,6 +23,7 @@ const Data = struct {
opc: [7]u8,
modrm_ext: u3,
mode: Mode,
+ feature: Feature,
};
pub fn findByMnemonic(
@@ -57,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, .sse2_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;
@@ -88,28 +89,13 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
if (modrm_ext) |ext| if (ext != data.modrm_ext) continue;
if (!std.mem.eql(u8, opc, enc.opcode())) continue;
if (prefixes.rex.w) {
- switch (data.mode) {
- .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
- .long, .sse2_long, .rex => {},
- }
+ if (!data.mode.isLong()) continue;
} else if (prefixes.rex.present and !prefixes.rex.isSet()) {
- switch (data.mode) {
- .rex => {},
- else => continue,
- }
+ if (!data.mode.isRex()) continue;
} else if (prefixes.legacy.prefix_66) {
- switch (enc.operandBitSize()) {
- 16 => {},
- else => continue,
- }
+ if (!data.mode.isShort()) continue;
} else {
- switch (data.mode) {
- .none => switch (enc.operandBitSize()) {
- 16 => continue,
- else => {},
- },
- else => continue,
- }
+ if (data.mode.isShort()) continue;
}
return enc;
};
@@ -130,30 +116,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 {
- switch (encoding.data.mode) {
- .short => return 16,
- .long, .sse2_long => return 64,
- else => {},
- }
- const bit_size: u64 = switch (encoding.data.op_en) {
- .np => switch (encoding.data.ops[0]) {
- .o16 => 16,
- .o32 => 32,
- .o64 => 64,
- else => 32,
- },
- .td => encoding.data.ops[1].bitSize(),
- else => encoding.data.ops[0].bitSize(),
- };
- return bit_size;
-}
-
pub fn format(
encoding: Encoding,
comptime fmt: []const u8,
@@ -162,14 +129,41 @@ pub fn format(
) !void {
_ = options;
_ = fmt;
- switch (encoding.data.mode) {
- .long, .sse2_long => try writer.writeAll("REX.W + "),
- else => {},
- }
- for (encoding.opcode()) |byte| {
- try writer.print("{x:0>2} ", .{byte});
- }
+ var opc = encoding.opcode();
+ if (encoding.data.mode.isVex()) {
+ try writer.writeAll("VEX.");
+
+ try writer.writeAll(switch (encoding.data.mode) {
+ .vex_128_w0, .vex_128_w1, .vex_128_wig => "128",
+ .vex_256_w0, .vex_256_w1, .vex_256_wig => "256",
+ .vex_lig_w0, .vex_lig_w1, .vex_lig_wig => "LIG",
+ .vex_lz_w0, .vex_lz_w1, .vex_lz_wig => "LZ",
+ else => unreachable,
+ });
+
+ switch (opc[0]) {
+ else => {},
+ 0x66, 0xf3, 0xf2 => {
+ try writer.print(".{X:0>2}", .{opc[0]});
+ opc = opc[1..];
+ },
+ }
+
+ try writer.print(".{}", .{std.fmt.fmtSliceHexUpper(opc[0 .. opc.len - 1])});
+ opc = opc[opc.len - 1 ..];
+
+ try writer.writeAll(".W");
+ try writer.writeAll(switch (encoding.data.mode) {
+ .vex_128_w0, .vex_256_w0, .vex_lig_w0, .vex_lz_w0 => "0",
+ .vex_128_w1, .vex_256_w1, .vex_lig_w1, .vex_lz_w1 => "1",
+ .vex_128_wig, .vex_256_wig, .vex_lig_wig, .vex_lz_wig => "IG",
+ else => unreachable,
+ });
+
+ try writer.writeByte(' ');
+ } else if (encoding.data.mode.isLong()) try writer.writeAll("REX.W + ");
+ for (opc) |byte| try writer.print("{x:0>2} ", .{byte});
switch (encoding.data.op_en) {
.np, .fd, .td, .i, .zi, .d => {},
@@ -183,16 +177,17 @@ pub fn format(
};
try writer.print("+{s} ", .{tag});
},
- .m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),
- .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),
+ .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
+ .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr => try writer.writeAll("/r "),
}
switch (encoding.data.op_en) {
- .i, .d, .zi, .oi, .mi, .rmi, .mri => {
+ .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],
+ .rmi, .mri, .vmi => encoding.data.ops[2],
+ .rvmi => encoding.data.ops[3],
else => unreachable,
};
const tag = switch (op) {
@@ -207,7 +202,8 @@ pub fn format(
};
try writer.print("{s} ", .{tag});
},
- .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc => {},
+ .rvmr => try writer.writeAll("/is4 "),
+ .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr => {},
}
try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
@@ -238,7 +234,6 @@ pub const Mnemonic = enum {
cmpxchg, cmpxchg8b, cmpxchg16b,
cqo, cwd, cwde,
div,
- fisttp, fld,
idiv, imul, int3,
ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe,
jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz,
@@ -264,29 +259,127 @@ pub const Mnemonic = enum {
@"test", tzcnt,
ud2,
xadd, xchg, xor,
+ // X87
+ fisttp, fld,
// MMX
- movd,
+ movd, movq,
+ packssdw, packsswb, packuswb,
+ paddb, paddd, paddq, paddsb, paddsw, paddusb, paddusw, paddw,
+ pand, pandn, por, pxor,
+ pmulhw, pmullw,
+ psubb, psubd, psubq, psubsb, psubsw, psubusb, psubusw, psubw,
// SSE
- addss,
- cmpss,
- divss,
- maxss, minss,
- movss,
- mulss,
- subss,
+ addps, addss,
+ andps,
+ andnps,
+ cmpps, cmpss,
+ cvtpi2ps, cvtps2pi, cvtsi2ss, cvtss2si, cvttps2pi, cvttss2si,
+ divps, divss,
+ maxps, maxss,
+ minps, minss,
+ movaps, movhlps, movlhps,
+ movss, movups,
+ mulps, mulss,
+ orps,
+ pextrw, pinsrw,
+ pmaxsw, pmaxub, pminsw, pminub,
+ shufps,
+ sqrtps, sqrtss,
+ subps, subss,
ucomiss,
+ xorps,
// SSE2
- addsd,
- //cmpsd,
- divsd,
- maxsd, minsd,
- movq, //movd, movsd,
- mulsd,
- subsd,
+ addpd, addsd,
+ andpd,
+ andnpd,
+ cmppd, //cmpsd,
+ cvtdq2pd, cvtdq2ps, cvtpd2dq, cvtpd2pi, cvtpd2ps, cvtpi2pd,
+ cvtps2dq, cvtps2pd, cvtsd2si, cvtsd2ss, cvtsi2sd, cvtss2sd,
+ cvttpd2dq, cvttpd2pi, cvttps2dq, cvttsd2si,
+ divpd, divsd,
+ maxpd, maxsd,
+ minpd, minsd,
+ movapd,
+ movdqa, movdqu,
+ //movsd,
+ movupd,
+ mulpd, mulsd,
+ orpd,
+ pshufhw, pshuflw,
+ psrld, psrlq, psrlw,
+ punpckhbw, punpckhdq, punpckhqdq, punpckhwd,
+ punpcklbw, punpckldq, punpcklqdq, punpcklwd,
+ shufpd,
+ sqrtpd, sqrtsd,
+ subpd, subsd,
ucomisd,
+ xorpd,
+ // SSE3
+ movddup, movshdup, movsldup,
// SSE4.1
- roundss,
- roundsd,
+ blendpd, blendps, blendvpd, blendvps,
+ extractps,
+ insertps,
+ packusdw,
+ pextrb, pextrd, pextrq,
+ pinsrb, pinsrd, pinsrq,
+ pmaxsb, pmaxsd, pmaxud, pmaxuw, pminsb, pminsd, pminud, pminuw,
+ pmulld,
+ roundpd, roundps, roundsd, roundss,
+ // AVX
+ vaddpd, vaddps, vaddsd, vaddss,
+ vandnpd, vandnps, vandpd, vandps,
+ vblendpd, vblendps, vblendvpd, vblendvps,
+ vbroadcastf128, vbroadcastsd, vbroadcastss,
+ vcmppd, vcmpps, vcmpsd, vcmpss,
+ vcvtdq2pd, vcvtdq2ps, vcvtpd2dq, vcvtpd2ps,
+ vcvtps2dq, vcvtps2pd, vcvtsd2si, vcvtsd2ss,
+ vcvtsi2sd, vcvtsi2ss, vcvtss2sd, vcvtss2si,
+ vcvttpd2dq, vcvttps2dq, vcvttsd2si, vcvttss2si,
+ vdivpd, vdivps, vdivsd, vdivss,
+ vextractf128, vextractps,
+ vinsertf128, vinsertps,
+ vmaxpd, vmaxps, vmaxsd, vmaxss,
+ vminpd, vminps, vminsd, vminss,
+ vmovapd, vmovaps,
+ vmovd,
+ vmovddup,
+ vmovdqa, vmovdqu,
+ vmovhlps, vmovlhps,
+ vmovq,
+ vmovsd,
+ vmovshdup, vmovsldup,
+ vmovss,
+ vmovupd, vmovups,
+ vmulpd, vmulps, vmulsd, vmulss,
+ vorpd, vorps,
+ vpackssdw, vpacksswb, vpackusdw, vpackuswb,
+ vpaddb, vpaddd, vpaddq, vpaddsb, vpaddsw, vpaddusb, vpaddusw, vpaddw,
+ vpand, vpandn,
+ vpextrb, vpextrd, vpextrq, vpextrw,
+ vpinsrb, vpinsrd, vpinsrq, vpinsrw,
+ vpmaxsb, vpmaxsd, vpmaxsw, vpmaxub, vpmaxud, vpmaxuw,
+ vpminsb, vpminsd, vpminsw, vpminub, vpminud, vpminuw,
+ vpmulhw, vpmulld, vpmullw,
+ vpor,
+ vpshufhw, vpshuflw,
+ vpsrld, vpsrlq, vpsrlw,
+ vpsubb, vpsubd, vpsubq, vpsubsb, vpsubsw, vpsubusb, vpsubusw, vpsubw,
+ vpunpckhbw, vpunpckhdq, vpunpckhqdq, vpunpckhwd,
+ vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,
+ vpxor,
+ vroundpd, vroundps, vroundsd, vroundss,
+ vshufpd, vshufps,
+ vsqrtpd, vsqrtps, vsqrtsd, vsqrtss,
+ vsubpd, vsubps, vsubsd, vsubss,
+ vxorpd, vxorps,
+ // F16C
+ vcvtph2ps, vcvtps2ph,
+ // FMA
+ vfmadd132pd, vfmadd213pd, vfmadd231pd,
+ vfmadd132ps, vfmadd213ps, vfmadd231ps,
+ vfmadd132sd, vfmadd213sd, vfmadd231sd,
+ vfmadd132ss, vfmadd213ss, vfmadd231ss,
// zig fmt: on
};
@@ -299,6 +392,7 @@ pub const OpEn = enum {
fd, td,
m1, mc, mi, mr, rm,
rmi, mri, mrc,
+ rm0, vmi, rvm, rvmr, rvmi, mvr,
// zig fmt: on
};
@@ -313,94 +407,143 @@ pub const Op = enum {
cl,
r8, r16, r32, r64,
rm8, rm16, rm32, rm64,
- m8, m16, m32, m64, m80, m128,
+ r32_m8, r32_m16, r64_m16,
+ m8, m16, m32, m64, m80, m128, m256,
rel8, rel16, rel32,
m,
moffs,
sreg,
- xmm, xmm_m32, xmm_m64,
+ st, mm, mm_m64,
+ xmm0, xmm, xmm_m32, xmm_m64, xmm_m128,
+ ymm, ymm_m256,
// zig fmt: on
pub fn fromOperand(operand: Instruction.Operand) Op {
- switch (operand) {
- .none => return .none,
-
- .reg => |reg| {
- switch (reg.class()) {
- .segment => return .sreg,
- .floating_point => return switch (reg.bitSize()) {
- 128 => .xmm,
+ return switch (operand) {
+ .none => .none,
+
+ .reg => |reg| switch (reg.class()) {
+ .general_purpose => if (reg.to64() == .rax)
+ switch (reg) {
+ .al => .al,
+ .ax => .ax,
+ .eax => .eax,
+ .rax => .rax,
else => unreachable,
- },
- .general_purpose => {
- if (reg.to64() == .rax) return switch (reg) {
- .al => .al,
- .ax => .ax,
- .eax => .eax,
- .rax => .rax,
- else => unreachable,
- };
- if (reg == .cl) return .cl;
- return switch (reg.bitSize()) {
- 8 => .r8,
- 16 => .r16,
- 32 => .r32,
- 64 => .r64,
- else => unreachable,
- };
- },
- }
+ }
+ else if (reg == .cl)
+ .cl
+ else switch (reg.bitSize()) {
+ 8 => .r8,
+ 16 => .r16,
+ 32 => .r32,
+ 64 => .r64,
+ else => unreachable,
+ },
+ .segment => .sreg,
+ .x87 => .st,
+ .mmx => .mm,
+ .sse => if (reg == .xmm0)
+ .xmm0
+ else switch (reg.bitSize()) {
+ 128 => .xmm,
+ 256 => .ymm,
+ else => unreachable,
+ },
},
.mem => |mem| switch (mem) {
- .moffs => return .moffs,
- .sib, .rip => {
- const bit_size = mem.bitSize();
- return switch (bit_size) {
- 8 => .m8,
- 16 => .m16,
- 32 => .m32,
- 64 => .m64,
- 80 => .m80,
- 128 => .m128,
- else => unreachable,
- };
+ .moffs => .moffs,
+ .sib, .rip => switch (mem.bitSize()) {
+ 8 => .m8,
+ 16 => .m16,
+ 32 => .m32,
+ 64 => .m64,
+ 80 => .m80,
+ 128 => .m128,
+ 256 => .m256,
+ else => unreachable,
},
},
- .imm => |imm| {
- 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;
- },
- }
+ .imm => |imm| switch (imm) {
+ .signed => |x| if (x == 1)
+ .unity
+ else if (math.cast(i8, x)) |_|
+ .imm8s
+ else if (math.cast(i16, x)) |_|
+ .imm16s
+ else
+ .imm32s,
+ .unsigned => |x| if (x == 1)
+ .unity
+ else if (math.cast(i8, x)) |_|
+ .imm8s
+ else if (math.cast(u8, x)) |_|
+ .imm8
+ else if (math.cast(i16, x)) |_|
+ .imm16s
+ else if (math.cast(u16, x)) |_|
+ .imm16
+ else if (math.cast(i32, x)) |_|
+ .imm32s
+ else if (math.cast(u32, x)) |_|
+ .imm32
+ else
+ .imm64,
},
- }
+ };
}
- 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, .r32_m8 => unreachable,
+ .ax, .r16, .rm16 => unreachable,
+ .eax, .r32, .rm32, .r32_m16 => unreachable,
+ .rax, .r64, .rm64, .r64_m16 => unreachable,
+ .st, .mm, .mm_m64 => unreachable,
+ .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
+ .ymm, .ymm_m256 => unreachable,
+ .m8, .m16, .m32, .m64, .m80, .m128, .m256 => 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, .m256 => unreachable,
+ .al, .cl, .r8, .rm8 => 8,
+ .ax, .r16, .rm16 => 16,
+ .eax, .r32, .rm32, .r32_m8, .r32_m16 => 32,
+ .rax, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
+ .st => 80,
+ .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
+ .ymm, .ymm_m256 => 256,
+ };
+ }
+
+ 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 => unreachable,
+ .st, .mm, .xmm0, .xmm, .ymm => unreachable,
+ .m8, .rm8, .r32_m8 => 8,
+ .m16, .rm16, .r32_m16, .r64_m16 => 16,
+ .m32, .rm32, .xmm_m32 => 32,
+ .m64, .rm64, .mm_m64, .xmm_m64 => 64,
.m80 => 80,
- .m128, .xmm => 128,
+ .m128, .xmm_m128 => 128,
+ .m256, .ymm_m256 => 256,
};
}
@@ -423,8 +566,11 @@ pub const Op = enum {
.al, .ax, .eax, .rax,
.r8, .r16, .r32, .r64,
.rm8, .rm16, .rm32, .rm64,
- .xmm, .xmm_m32, .xmm_m64,
- => true,
+ .r32_m8, .r32_m16, .r64_m16,
+ .st, .mm, .mm_m64,
+ .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
+ .ymm, .ymm_m256,
+ => true,
else => false,
};
// zig fmt: on
@@ -447,9 +593,12 @@ pub const Op = enum {
// zig fmt: off
return switch (op) {
.rm8, .rm16, .rm32, .rm64,
- .m8, .m16, .m32, .m64, .m80, .m128,
+ .r32_m8, .r32_m16, .r64_m16,
+ .m8, .m16, .m32, .m64, .m80, .m128, .m256,
.m,
- .xmm_m32, .xmm_m64,
+ .mm_m64,
+ .xmm_m32, .xmm_m64, .xmm_m128,
+ .ymm_m256,
=> true,
else => false,
};
@@ -469,15 +618,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_m8, .r32_m16, .r64_m16 => .general_purpose,
.sreg => .segment,
- .xmm, .xmm_m32, .xmm_m64 => .floating_point,
- };
- }
-
- pub fn isFloatingPointRegister(op: Op) bool {
- return switch (op) {
- .xmm, .xmm_m32, .xmm_m64 => true,
- else => false,
+ .st => .x87,
+ .mm, .mm_m64 => .mmx,
+ .xmm0, .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
+ .ymm, .ymm_m256 => .sse,
};
}
@@ -493,31 +639,28 @@ pub const Op = enum {
else => {
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(),
- },
+ .cl, .al, .ax, .eax, .rax, .xmm0 => op == target,
+ 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;
@@ -529,15 +672,85 @@ pub const Op = enum {
};
pub const Mode = enum {
+ // zig fmt: off
none,
- short,
- fpu,
- rex,
- long,
+ short, long,
+ rex, rex_short,
+ vex_128_w0, vex_128_w1, vex_128_wig,
+ vex_256_w0, vex_256_w1, vex_256_wig,
+ vex_lig_w0, vex_lig_w1, vex_lig_wig,
+ vex_lz_w0, vex_lz_w1, vex_lz_wig,
+ // zig fmt: on
+
+ pub fn isShort(mode: Mode) bool {
+ return switch (mode) {
+ .short, .rex_short => true,
+ else => false,
+ };
+ }
+
+ pub fn isLong(mode: Mode) bool {
+ return switch (mode) {
+ .long,
+ .vex_128_w1,
+ .vex_256_w1,
+ .vex_lig_w1,
+ .vex_lz_w1,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn isRex(mode: Mode) bool {
+ return switch (mode) {
+ else => false,
+ .rex, .rex_short => true,
+ };
+ }
+
+ pub fn isVex(mode: Mode) bool {
+ return switch (mode) {
+ // zig fmt: off
+ else => false,
+ .vex_128_w0, .vex_128_w1, .vex_128_wig,
+ .vex_256_w0, .vex_256_w1, .vex_256_wig,
+ .vex_lig_w0, .vex_lig_w1, .vex_lig_wig,
+ .vex_lz_w0, .vex_lz_w1, .vex_lz_wig,
+ => true,
+ // zig fmt: on
+ };
+ }
+
+ pub fn isVecLong(mode: Mode) bool {
+ return switch (mode) {
+ // zig fmt: off
+ else => unreachable,
+ .vex_128_w0, .vex_128_w1, .vex_128_wig,
+ .vex_lig_w0, .vex_lig_w1, .vex_lig_wig,
+ .vex_lz_w0, .vex_lz_w1, .vex_lz_wig,
+ => false,
+ .vex_256_w0, .vex_256_w1, .vex_256_wig,
+ => true,
+ // zig fmt: on
+ };
+ }
+};
+
+pub const Feature = enum {
+ none,
+ avx,
+ avx2,
+ bmi,
+ f16c,
+ fma,
+ lzcnt,
+ movbe,
+ popcnt,
sse,
sse2,
- sse2_long,
+ sse3,
sse4_1,
+ x87,
};
fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize {
@@ -554,10 +767,10 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
}
const mnemonic_to_encodings_map = init: {
- @setEvalBranchQuota(100_000);
+ @setEvalBranchQuota(30_000);
const encodings = @import("encodings.zig");
var entries = encodings.table;
- std.sort.sort(encodings.Entry, &entries, {}, struct {
+ std.mem.sort(encodings.Entry, &entries, {}, struct {
fn lessThan(_: void, lhs: encodings.Entry, rhs: encodings.Entry) bool {
return @enumToInt(lhs[0]) < @enumToInt(rhs[0]);
}
@@ -574,6 +787,7 @@ const mnemonic_to_encodings_map = init: {
.opc = undefined,
.modrm_ext = entry[4],
.mode = entry[5],
+ .feature = entry[6],
};
// TODO: use `@memcpy` for these. When I did that, I got a false positive
// compile error for this copy happening at compile time.