mirror of
https://github.com/ziglang/zig.git
synced 2026-01-02 03:25:01 +00:00
x86_64: implement f16 cmp
This commit is contained in:
parent
32ab930f1d
commit
ae588a09f2
@ -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
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user