mirror of
https://github.com/ziglang/zig.git
synced 2026-01-10 01:15:14 +00:00
x86_64: downstream table-driven instruction encoder
This commit is contained in:
parent
4ea2f441df
commit
817fb263b5
@ -303,7 +303,12 @@ pub fn generate(
|
||||
var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {
|
||||
error.CodegenFail => return Result{ .fail = function.err_msg.? },
|
||||
error.OutOfRegisters => return Result{
|
||||
.fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.allocator,
|
||||
src_loc,
|
||||
"CodeGen ran out of registers. This is a bug in the Zig compiler.",
|
||||
.{},
|
||||
),
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
@ -342,6 +347,20 @@ pub fn generate(
|
||||
defer emit.deinit();
|
||||
emit.lowerMir() catch |err| switch (err) {
|
||||
error.EmitFail => return Result{ .fail = emit.err_msg.? },
|
||||
error.InvalidInstruction, error.CannotEncode => |e| {
|
||||
const msg = switch (e) {
|
||||
error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
|
||||
error.CannotEncode => "CodeGen failed to encode the instruction.",
|
||||
};
|
||||
return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.allocator,
|
||||
src_loc,
|
||||
"{s} This is a bug in the Zig compiler.",
|
||||
.{msg},
|
||||
),
|
||||
};
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
@ -1687,7 +1706,7 @@ fn genIntMulDivOpMir(
|
||||
else => unreachable,
|
||||
},
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
else => unreachable,
|
||||
@ -2191,7 +2210,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
|
||||
.reg2 = .rbp,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
|
||||
.data = .{ .disp = -@intCast(i32, off) },
|
||||
});
|
||||
},
|
||||
else => return self.fail("TODO implement slice_elem_ptr when slice is {}", .{slice_mcv}),
|
||||
@ -2275,7 +2294,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.reg1 = addr_reg.to64(),
|
||||
.reg2 = .rbp,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.stack_offset => |off| {
|
||||
@ -2286,7 +2305,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.reg1 = addr_reg.to64(),
|
||||
.reg2 = .rbp,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.memory, .linker_load => {
|
||||
@ -2352,7 +2371,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.reg2 = dst_mcv.register,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
|
||||
}
|
||||
@ -2615,7 +2634,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
||||
.reg2 = reg,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
},
|
||||
.stack_offset => |off| {
|
||||
@ -2842,7 +2861,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
||||
.reg2 = addr_reg.to64(),
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
|
||||
const new_ptr = MCValue{ .register = addr_reg.to64() };
|
||||
@ -2903,7 +2922,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
||||
.reg2 = tmp_reg,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
|
||||
}
|
||||
@ -3542,25 +3561,13 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
|
||||
if (intrinsicsAllowed(self.target.*, dst_ty)) {
|
||||
const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
|
||||
.f32 => switch (mir_tag) {
|
||||
.add => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.add_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.add_f32_sse,
|
||||
.cmp => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.cmp_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.cmp_f32_sse,
|
||||
.add => Mir.Inst.Tag.add_f32,
|
||||
.cmp => Mir.Inst.Tag.cmp_f32,
|
||||
else => return self.fail("TODO genBinOpMir for f32 register-register with MIR tag {}", .{mir_tag}),
|
||||
},
|
||||
.f64 => switch (mir_tag) {
|
||||
.add => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.add_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.add_f64_sse,
|
||||
.cmp => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.cmp_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.cmp_f64_sse,
|
||||
.add => Mir.Inst.Tag.add_f64,
|
||||
.cmp => Mir.Inst.Tag.cmp_f64,
|
||||
else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}),
|
||||
},
|
||||
else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}),
|
||||
@ -3618,7 +3625,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
|
||||
.reg2 = .rbp,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -3644,7 +3651,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
|
||||
.reg2 = registerAlias(src_reg, abi_size),
|
||||
.flags = 0b10,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.immediate => |imm| {
|
||||
@ -3665,7 +3672,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
|
||||
else => unreachable,
|
||||
};
|
||||
const payload = try self.addExtra(Mir.ImmPair{
|
||||
.dest_off = @bitCast(u32, -off),
|
||||
.dest_off = -off,
|
||||
.operand = @truncate(u32, imm),
|
||||
});
|
||||
_ = try self.addInst(.{
|
||||
@ -3756,7 +3763,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
|
||||
.reg2 = .rbp,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.memory => {
|
||||
@ -5360,7 +5367,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
|
||||
// offset from rbp, which is at the top of the stack frame.
|
||||
// mov [rbp+offset], immediate
|
||||
const payload = try self.addExtra(Mir.ImmPair{
|
||||
.dest_off = @bitCast(u32, -stack_offset),
|
||||
.dest_off = -stack_offset,
|
||||
.operand = @truncate(u32, imm),
|
||||
});
|
||||
_ = try self.addInst(.{
|
||||
@ -5400,14 +5407,8 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
|
||||
.Float => {
|
||||
if (intrinsicsAllowed(self.target.*, ty)) {
|
||||
const tag: Mir.Inst.Tag = switch (ty.tag()) {
|
||||
.f32 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f32_sse,
|
||||
.f64 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f64_sse,
|
||||
.f32 => Mir.Inst.Tag.mov_f32,
|
||||
.f64 => Mir.Inst.Tag.mov_f64,
|
||||
else => return self.fail("TODO genSetStackArg for register for type {}", .{ty.fmtDebug()}),
|
||||
};
|
||||
_ = try self.addInst(.{
|
||||
@ -5421,7 +5422,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
|
||||
.reg2 = reg.to128(),
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -stack_offset) },
|
||||
.data = .{ .disp = -stack_offset },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -5436,7 +5437,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
|
||||
.reg2 = registerAlias(reg, @intCast(u32, abi_size)),
|
||||
.flags = 0b10,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -stack_offset) },
|
||||
.data = .{ .disp = -stack_offset },
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -5516,7 +5517,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
0 => {
|
||||
assert(ty.isError());
|
||||
const payload = try self.addExtra(Mir.ImmPair{
|
||||
.dest_off = @bitCast(u32, -stack_offset),
|
||||
.dest_off = -stack_offset,
|
||||
.operand = @truncate(u32, x_big),
|
||||
});
|
||||
_ = try self.addInst(.{
|
||||
@ -5530,7 +5531,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
},
|
||||
1, 2, 4 => {
|
||||
const payload = try self.addExtra(Mir.ImmPair{
|
||||
.dest_off = @bitCast(u32, -stack_offset),
|
||||
.dest_off = -stack_offset,
|
||||
.operand = @truncate(u32, x_big),
|
||||
});
|
||||
_ = try self.addInst(.{
|
||||
@ -5552,7 +5553,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
// insted just use two 32 bit writes to avoid register allocation
|
||||
{
|
||||
const payload = try self.addExtra(Mir.ImmPair{
|
||||
.dest_off = @bitCast(u32, -stack_offset + 4),
|
||||
.dest_off = -stack_offset + 4,
|
||||
.operand = @truncate(u32, x_big >> 32),
|
||||
});
|
||||
_ = try self.addInst(.{
|
||||
@ -5566,7 +5567,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
}
|
||||
{
|
||||
const payload = try self.addExtra(Mir.ImmPair{
|
||||
.dest_off = @bitCast(u32, -stack_offset),
|
||||
.dest_off = -stack_offset,
|
||||
.operand = @truncate(u32, x_big),
|
||||
});
|
||||
_ = try self.addInst(.{
|
||||
@ -5595,14 +5596,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
.Float => {
|
||||
if (intrinsicsAllowed(self.target.*, ty)) {
|
||||
const tag: Mir.Inst.Tag = switch (ty.tag()) {
|
||||
.f32 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f32_sse,
|
||||
.f64 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f64_sse,
|
||||
.f32 => Mir.Inst.Tag.mov_f32,
|
||||
.f64 => Mir.Inst.Tag.mov_f64,
|
||||
else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}),
|
||||
};
|
||||
_ = try self.addInst(.{
|
||||
@ -5616,7 +5611,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
.reg2 = reg.to128(),
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -stack_offset) },
|
||||
.data = .{ .disp = -stack_offset },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -5691,7 +5686,7 @@ fn genInlineMemcpyRegisterRegister(
|
||||
.reg2 = registerAlias(tmp_reg, nearest_power_of_two),
|
||||
.flags = 0b10,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -next_offset) },
|
||||
.data = .{ .disp = -next_offset },
|
||||
});
|
||||
|
||||
if (nearest_power_of_two > 1) {
|
||||
@ -5711,7 +5706,7 @@ fn genInlineMemcpyRegisterRegister(
|
||||
.reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
|
||||
.flags = 0b10,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -offset) },
|
||||
.data = .{ .disp = -offset },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -5758,7 +5753,7 @@ fn genInlineMemcpy(
|
||||
.reg1 = dst_addr_reg.to64(),
|
||||
.reg2 = opts.dest_stack_base orelse .rbp,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.register => |reg| {
|
||||
@ -5787,7 +5782,7 @@ fn genInlineMemcpy(
|
||||
.reg1 = src_addr_reg.to64(),
|
||||
.reg2 = opts.source_stack_base orelse .rbp,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.register => |reg| {
|
||||
@ -5911,7 +5906,7 @@ fn genInlineMemset(
|
||||
.reg1 = addr_reg.to64(),
|
||||
.reg2 = opts.dest_stack_base orelse .rbp,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.register => |reg| {
|
||||
@ -5998,7 +5993,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.reg1 = registerAlias(reg, abi_size),
|
||||
.reg2 = .rbp,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
.unreach, .none => return, // Nothing to do.
|
||||
@ -6097,14 +6092,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.Float => {
|
||||
if (intrinsicsAllowed(self.target.*, ty)) {
|
||||
const tag: Mir.Inst.Tag = switch (ty.tag()) {
|
||||
.f32 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f32_sse,
|
||||
.f64 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f64_sse,
|
||||
.f32 => Mir.Inst.Tag.mov_f32,
|
||||
.f64 => Mir.Inst.Tag.mov_f64,
|
||||
else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}),
|
||||
};
|
||||
_ = try self.addInst(.{
|
||||
@ -6141,14 +6130,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
|
||||
if (intrinsicsAllowed(self.target.*, ty)) {
|
||||
const tag: Mir.Inst.Tag = switch (ty.tag()) {
|
||||
.f32 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f32_sse,
|
||||
.f64 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f64_sse,
|
||||
.f32 => Mir.Inst.Tag.mov_f32,
|
||||
.f64 => Mir.Inst.Tag.mov_f64,
|
||||
else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}),
|
||||
};
|
||||
|
||||
@ -6162,7 +6145,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
else => unreachable,
|
||||
},
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -6178,7 +6161,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.reg2 = reg.to64(),
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -6190,14 +6173,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
|
||||
if (intrinsicsAllowed(self.target.*, ty)) {
|
||||
const tag: Mir.Inst.Tag = switch (ty.tag()) {
|
||||
.f32 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f32_sse,
|
||||
.f64 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f64_sse,
|
||||
.f32 => Mir.Inst.Tag.mov_f32,
|
||||
.f64 => Mir.Inst.Tag.mov_f64,
|
||||
else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}),
|
||||
};
|
||||
|
||||
@ -6211,7 +6188,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
else => unreachable,
|
||||
},
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -6255,7 +6232,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.reg2 = reg.to64(),
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -6283,7 +6260,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.reg2 = .rbp,
|
||||
.flags = flags,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -6302,7 +6279,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.reg2 = .rbp,
|
||||
.flags = flags,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -6311,14 +6288,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.Float => {
|
||||
if (intrinsicsAllowed(self.target.*, ty)) {
|
||||
const tag: Mir.Inst.Tag = switch (ty.tag()) {
|
||||
.f32 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f32_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f32_sse,
|
||||
.f64 => if (hasAvxSupport(self.target.*))
|
||||
Mir.Inst.Tag.mov_f64_avx
|
||||
else
|
||||
Mir.Inst.Tag.mov_f64_sse,
|
||||
.f32 => Mir.Inst.Tag.mov_f32,
|
||||
.f64 => Mir.Inst.Tag.mov_f64,
|
||||
else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}),
|
||||
};
|
||||
_ = try self.addInst(.{
|
||||
@ -6331,7 +6302,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
else => unreachable,
|
||||
},
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -6347,7 +6318,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.reg2 = .rbp,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
.data = .{ .disp = -off },
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -6436,7 +6407,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
|
||||
else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}),
|
||||
},
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -stack_offset) },
|
||||
.data = .{ .disp = -stack_offset },
|
||||
});
|
||||
|
||||
// convert
|
||||
@ -6452,7 +6423,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
|
||||
else => |size| return self.fail("TODO convert float with abiSize={}", .{size}),
|
||||
},
|
||||
}),
|
||||
.data = .{ .imm = @bitCast(u32, -stack_dst.stack_offset) },
|
||||
.data = .{ .disp = -stack_dst.stack_offset },
|
||||
});
|
||||
|
||||
return self.finishAir(inst, stack_dst, .{ ty_op.operand, .none, .none });
|
||||
@ -6551,7 +6522,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.reg2 = reg,
|
||||
.flags = 0b01,
|
||||
}),
|
||||
.data = .{ .imm = 0 },
|
||||
.data = .{ .disp = 0 },
|
||||
});
|
||||
break :blk MCValue{ .register = reg };
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
521
src/arch/x86_64/Encoding.zig
Normal file
521
src/arch/x86_64/Encoding.zig
Normal file
@ -0,0 +1,521 @@
|
||||
const Encoding = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const math = std.math;
|
||||
|
||||
const bits = @import("bits.zig");
|
||||
const encoder = @import("encoder.zig");
|
||||
const Instruction = encoder.Instruction;
|
||||
const Register = bits.Register;
|
||||
const Rex = encoder.Rex;
|
||||
const LegacyPrefixes = encoder.LegacyPrefixes;
|
||||
|
||||
const table = @import("encodings.zig").table;
|
||||
|
||||
mnemonic: Mnemonic,
|
||||
op_en: OpEn,
|
||||
op1: Op,
|
||||
op2: Op,
|
||||
op3: Op,
|
||||
op4: Op,
|
||||
opc_len: u2,
|
||||
opc: [3]u8,
|
||||
modrm_ext: u3,
|
||||
mode: Mode,
|
||||
|
||||
pub fn findByMnemonic(mnemonic: Mnemonic, args: struct {
|
||||
op1: Instruction.Operand,
|
||||
op2: Instruction.Operand,
|
||||
op3: Instruction.Operand,
|
||||
op4: Instruction.Operand,
|
||||
}) ?Encoding {
|
||||
const input_op1 = Op.fromOperand(args.op1);
|
||||
const input_op2 = Op.fromOperand(args.op2);
|
||||
const input_op3 = Op.fromOperand(args.op3);
|
||||
const input_op4 = Op.fromOperand(args.op4);
|
||||
|
||||
// TODO work out what is the maximum number of variants we can actually find in one swoop.
|
||||
var candidates: [10]Encoding = undefined;
|
||||
var count: usize = 0;
|
||||
inline for (table) |entry| {
|
||||
const enc = Encoding{
|
||||
.mnemonic = entry[0],
|
||||
.op_en = entry[1],
|
||||
.op1 = entry[2],
|
||||
.op2 = entry[3],
|
||||
.op3 = entry[4],
|
||||
.op4 = entry[5],
|
||||
.opc_len = entry[6],
|
||||
.opc = .{ entry[7], entry[8], entry[9] },
|
||||
.modrm_ext = entry[10],
|
||||
.mode = entry[11],
|
||||
};
|
||||
if (enc.mnemonic == mnemonic and
|
||||
input_op1.isSubset(enc.op1, enc.mode) and
|
||||
input_op2.isSubset(enc.op2, enc.mode) and
|
||||
input_op3.isSubset(enc.op3, enc.mode) and
|
||||
input_op4.isSubset(enc.op4, enc.mode))
|
||||
{
|
||||
candidates[count] = enc;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0) return null;
|
||||
if (count == 1) return candidates[0];
|
||||
|
||||
const EncodingLength = struct {
|
||||
fn estimate(encoding: Encoding, params: struct {
|
||||
op1: Instruction.Operand,
|
||||
op2: Instruction.Operand,
|
||||
op3: Instruction.Operand,
|
||||
op4: Instruction.Operand,
|
||||
}) usize {
|
||||
var inst = Instruction{
|
||||
.op1 = params.op1,
|
||||
.op2 = params.op2,
|
||||
.op3 = params.op3,
|
||||
.op4 = params.op4,
|
||||
.encoding = encoding,
|
||||
};
|
||||
var cwriter = std.io.countingWriter(std.io.null_writer);
|
||||
inst.encode(cwriter.writer()) catch unreachable;
|
||||
return cwriter.bytes_written;
|
||||
}
|
||||
};
|
||||
|
||||
var shortest_encoding: ?struct {
|
||||
index: usize,
|
||||
len: usize,
|
||||
} = null;
|
||||
var i: usize = 0;
|
||||
while (i < count) : (i += 1) {
|
||||
const len = EncodingLength.estimate(candidates[i], .{
|
||||
.op1 = args.op1,
|
||||
.op2 = args.op2,
|
||||
.op3 = args.op3,
|
||||
.op4 = args.op4,
|
||||
});
|
||||
const current = shortest_encoding orelse {
|
||||
shortest_encoding = .{ .index = i, .len = len };
|
||||
continue;
|
||||
};
|
||||
if (len < current.len) {
|
||||
shortest_encoding = .{ .index = i, .len = len };
|
||||
}
|
||||
}
|
||||
|
||||
return candidates[shortest_encoding.?.index];
|
||||
}
|
||||
|
||||
/// Returns first matching encoding by opcode.
|
||||
pub fn findByOpcode(opc: []const u8, prefixes: struct {
|
||||
legacy: LegacyPrefixes,
|
||||
rex: Rex,
|
||||
}, modrm_ext: ?u3) ?Encoding {
|
||||
inline for (table) |entry| {
|
||||
const enc = Encoding{
|
||||
.mnemonic = entry[0],
|
||||
.op_en = entry[1],
|
||||
.op1 = entry[2],
|
||||
.op2 = entry[3],
|
||||
.op3 = entry[4],
|
||||
.op4 = entry[5],
|
||||
.opc_len = entry[6],
|
||||
.opc = .{ entry[7], entry[8], entry[9] },
|
||||
.modrm_ext = entry[10],
|
||||
.mode = entry[11],
|
||||
};
|
||||
const match = match: {
|
||||
if (modrm_ext) |ext| {
|
||||
break :match ext == enc.modrm_ext and std.mem.eql(u8, enc.opcode(), opc);
|
||||
}
|
||||
break :match std.mem.eql(u8, enc.opcode(), opc);
|
||||
};
|
||||
if (match) {
|
||||
if (prefixes.rex.w) {
|
||||
switch (enc.mode) {
|
||||
.fpu, .sse, .sse2 => {},
|
||||
.long => return enc,
|
||||
.none => {
|
||||
// TODO this is a hack to allow parsing of instructions which contain
|
||||
// spurious prefix bytes such as
|
||||
// rex.W mov dil, 0x1
|
||||
// Here, rex.W is not needed.
|
||||
const rex_w_allowed = blk: {
|
||||
const bit_size = enc.operandSize();
|
||||
break :blk bit_size == 64 or bit_size == 8;
|
||||
};
|
||||
if (rex_w_allowed) return enc;
|
||||
},
|
||||
}
|
||||
} else if (prefixes.legacy.prefix_66) {
|
||||
switch (enc.operandSize()) {
|
||||
16 => return enc,
|
||||
else => {},
|
||||
}
|
||||
} else {
|
||||
if (enc.mode == .none) {
|
||||
switch (enc.operandSize()) {
|
||||
16 => {},
|
||||
else => return enc,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn opcode(encoding: *const Encoding) []const u8 {
|
||||
return encoding.opc[0..encoding.opc_len];
|
||||
}
|
||||
|
||||
pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
|
||||
const prefix = encoding.opc[0];
|
||||
return switch (prefix) {
|
||||
0x66, 0xf2, 0xf3 => prefix,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn modRmExt(encoding: Encoding) u3 {
|
||||
return switch (encoding.op_en) {
|
||||
.m, .mi, .m1, .mc => encoding.modrm_ext,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn operandSize(encoding: Encoding) u32 {
|
||||
if (encoding.mode == .long) return 64;
|
||||
const bit_size: u32 = switch (encoding.op_en) {
|
||||
.np => switch (encoding.op1) {
|
||||
.o16 => 16,
|
||||
.o32 => 32,
|
||||
.o64 => 64,
|
||||
else => 32,
|
||||
},
|
||||
.td => encoding.op2.size(),
|
||||
else => encoding.op1.size(),
|
||||
};
|
||||
return bit_size;
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
encoding: Encoding,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = options;
|
||||
_ = fmt;
|
||||
switch (encoding.mode) {
|
||||
.long => try writer.writeAll("REX.W + "),
|
||||
else => {},
|
||||
}
|
||||
|
||||
for (encoding.opcode()) |byte| {
|
||||
try writer.print("{x:0>2} ", .{byte});
|
||||
}
|
||||
|
||||
switch (encoding.op_en) {
|
||||
.np, .fd, .td, .i, .zi, .d => {},
|
||||
.o, .oi => {
|
||||
const tag = switch (encoding.op1) {
|
||||
.r8 => "rb",
|
||||
.r16 => "rw",
|
||||
.r32 => "rd",
|
||||
.r64 => "rd",
|
||||
else => unreachable,
|
||||
};
|
||||
try writer.print("+{s} ", .{tag});
|
||||
},
|
||||
.m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),
|
||||
.mr, .rm, .rmi => try writer.writeAll("/r "),
|
||||
}
|
||||
|
||||
switch (encoding.op_en) {
|
||||
.i, .d, .zi, .oi, .mi, .rmi => {
|
||||
const op = switch (encoding.op_en) {
|
||||
.i, .d => encoding.op1,
|
||||
.zi, .oi, .mi => encoding.op2,
|
||||
.rmi => encoding.op3,
|
||||
else => unreachable,
|
||||
};
|
||||
const tag = switch (op) {
|
||||
.imm8 => "ib",
|
||||
.imm16 => "iw",
|
||||
.imm32 => "id",
|
||||
.imm64 => "io",
|
||||
.rel8 => "cb",
|
||||
.rel16 => "cw",
|
||||
.rel32 => "cd",
|
||||
else => unreachable,
|
||||
};
|
||||
try writer.print("{s} ", .{tag});
|
||||
},
|
||||
.np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm => {},
|
||||
}
|
||||
|
||||
try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
|
||||
|
||||
const ops = &[_]Op{ encoding.op1, encoding.op2, encoding.op3, encoding.op4 };
|
||||
for (ops) |op| switch (op) {
|
||||
.none, .o16, .o32, .o64 => break,
|
||||
else => try writer.print("{s} ", .{@tagName(op)}),
|
||||
};
|
||||
|
||||
const op_en = switch (encoding.op_en) {
|
||||
.zi => .i,
|
||||
else => |op_en| op_en,
|
||||
};
|
||||
try writer.print("{s}", .{@tagName(op_en)});
|
||||
}
|
||||
|
||||
pub const Mnemonic = enum {
|
||||
// zig fmt: off
|
||||
// General-purpose
|
||||
adc, add, @"and",
|
||||
call, cbw, cwde, cdqe, cwd, cdq, cqo, cmp,
|
||||
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
|
||||
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
|
||||
cmovnp, cmovns, cmovnz, cmovo, cmovp, cmovpe, cmovpo, cmovs, cmovz,
|
||||
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,
|
||||
jmp,
|
||||
lea,
|
||||
mov, movsx, movsxd, movzx, mul,
|
||||
nop,
|
||||
@"or",
|
||||
pop, push,
|
||||
ret,
|
||||
sal, sar, sbb, shl, shr, sub, syscall,
|
||||
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
|
||||
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
|
||||
setnz, seto, setp, setpe, setpo, sets, setz,
|
||||
@"test",
|
||||
ud2,
|
||||
xor,
|
||||
// SSE
|
||||
addss,
|
||||
cmpss,
|
||||
movss,
|
||||
ucomiss,
|
||||
// SSE2
|
||||
addsd,
|
||||
cmpsd,
|
||||
movq, movsd,
|
||||
ucomisd,
|
||||
// zig fmt: on
|
||||
};
|
||||
|
||||
pub const OpEn = enum {
|
||||
// zig fmt: off
|
||||
np,
|
||||
o, oi,
|
||||
i, zi,
|
||||
d, m,
|
||||
fd, td,
|
||||
m1, mc, mi, mr, rm, rmi,
|
||||
// zig fmt: on
|
||||
};
|
||||
|
||||
pub const Op = enum {
|
||||
// zig fmt: off
|
||||
none,
|
||||
o16, o32, o64,
|
||||
unity,
|
||||
imm8, imm16, imm32, imm64,
|
||||
al, ax, eax, rax,
|
||||
cl,
|
||||
r8, r16, r32, r64,
|
||||
rm8, rm16, rm32, rm64,
|
||||
m8, m16, m32, m64, m80,
|
||||
rel8, rel16, rel32,
|
||||
m,
|
||||
moffs,
|
||||
sreg,
|
||||
xmm, xmm_m32, xmm_m64,
|
||||
// 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.size()) {
|
||||
128 => .xmm,
|
||||
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.size()) {
|
||||
8 => .r8,
|
||||
16 => .r16,
|
||||
32 => .r32,
|
||||
64 => .r64,
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
.mem => |mem| switch (mem) {
|
||||
.moffs => return .moffs,
|
||||
.sib, .rip => {
|
||||
const bit_size = mem.size();
|
||||
return switch (bit_size) {
|
||||
8 => .m8,
|
||||
16 => .m16,
|
||||
32 => .m32,
|
||||
64 => .m64,
|
||||
80 => .m80,
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
.imm => |imm| {
|
||||
if (imm == 1) return .unity;
|
||||
if (math.cast(i8, imm)) |_| return .imm8;
|
||||
if (math.cast(i16, imm)) |_| return .imm16;
|
||||
if (math.cast(i32, imm)) |_| return .imm32;
|
||||
return .imm64;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(op: Op) u32 {
|
||||
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,
|
||||
.imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
|
||||
.m80 => 80,
|
||||
.xmm => 128,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isRegister(op: Op) bool {
|
||||
// zig fmt: off
|
||||
return switch (op) {
|
||||
.cl,
|
||||
.al, .ax, .eax, .rax,
|
||||
.r8, .r16, .r32, .r64,
|
||||
.rm8, .rm16, .rm32, .rm64,
|
||||
.xmm, .xmm_m32, .xmm_m64,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
// zig fmt: on
|
||||
}
|
||||
|
||||
pub fn isImmediate(op: Op) bool {
|
||||
// zig fmt: off
|
||||
return switch (op) {
|
||||
.imm8, .imm16, .imm32, .imm64,
|
||||
.rel8, .rel16, .rel32,
|
||||
.unity,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
// zig fmt: on
|
||||
}
|
||||
|
||||
pub fn isMemory(op: Op) bool {
|
||||
// zig fmt: off
|
||||
return switch (op) {
|
||||
.rm8, .rm16, .rm32, .rm64,
|
||||
.m8, .m16, .m32, .m64, .m80,
|
||||
.m,
|
||||
.xmm_m32, .xmm_m64,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
// zig fmt: on
|
||||
}
|
||||
|
||||
pub fn isSegmentRegister(op: Op) bool {
|
||||
return switch (op) {
|
||||
.moffs, .sreg => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isFloatingPointRegister(op: Op) bool {
|
||||
return switch (op) {
|
||||
.xmm, .xmm_m32, .xmm_m64 => 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, mode: Mode) bool {
|
||||
switch (op) {
|
||||
.m, .o16, .o32, .o64 => unreachable,
|
||||
.moffs, .sreg => return op == target,
|
||||
.none => switch (target) {
|
||||
.o16, .o32, .o64, .none => return true,
|
||||
else => return false,
|
||||
},
|
||||
else => {
|
||||
if (op.isRegister() and target.isRegister()) {
|
||||
switch (mode) {
|
||||
.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(),
|
||||
},
|
||||
}
|
||||
}
|
||||
if (op.isMemory() and target.isMemory()) {
|
||||
switch (target) {
|
||||
.m => return true,
|
||||
else => return op.size() == target.size(),
|
||||
}
|
||||
}
|
||||
if (op.isImmediate() and target.isImmediate()) {
|
||||
switch (target) {
|
||||
.imm32, .rel32 => switch (op) {
|
||||
.unity, .imm8, .imm16, .imm32 => return true,
|
||||
else => return op == target,
|
||||
},
|
||||
.imm16, .rel16 => switch (op) {
|
||||
.unity, .imm8, .imm16 => return true,
|
||||
else => return op == target,
|
||||
},
|
||||
.imm8, .rel8 => switch (op) {
|
||||
.unity, .imm8 => return true,
|
||||
else => return op == target,
|
||||
},
|
||||
else => return op == target,
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Mode = enum {
|
||||
none,
|
||||
fpu,
|
||||
long,
|
||||
sse,
|
||||
sse2,
|
||||
};
|
||||
@ -339,41 +339,23 @@ pub const Inst = struct {
|
||||
/// Nop
|
||||
nop,
|
||||
|
||||
/// SSE instructions
|
||||
/// SSE/AVX instructions
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, qword ptr [reg2 + imm32]
|
||||
/// 0b01 qword ptr [reg1 + imm32], reg2
|
||||
/// 0b10 reg1, reg2
|
||||
mov_f64_sse,
|
||||
mov_f32_sse,
|
||||
mov_f64,
|
||||
mov_f32,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, reg2
|
||||
add_f64_sse,
|
||||
add_f32_sse,
|
||||
add_f64,
|
||||
add_f32,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, reg2
|
||||
cmp_f64_sse,
|
||||
cmp_f32_sse,
|
||||
|
||||
/// AVX instructions
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, qword ptr [reg2 + imm32]
|
||||
/// 0b01 qword ptr [reg1 + imm32], reg2
|
||||
/// 0b10 reg1, reg1, reg2
|
||||
mov_f64_avx,
|
||||
mov_f32_avx,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, reg1, reg2
|
||||
add_f64_avx,
|
||||
add_f32_avx,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, reg1, reg2
|
||||
cmp_f64_avx,
|
||||
cmp_f32_avx,
|
||||
cmp_f64,
|
||||
cmp_f32,
|
||||
|
||||
/// Pseudo-instructions
|
||||
/// call extern function
|
||||
@ -439,6 +421,8 @@ pub const Inst = struct {
|
||||
inst: Index,
|
||||
/// A 32-bit immediate value.
|
||||
imm: u32,
|
||||
/// A 32-bit signed displacement value.
|
||||
disp: i32,
|
||||
/// A condition code for use with EFLAGS register.
|
||||
cc: bits.Condition,
|
||||
/// Another instruction with condition code.
|
||||
@ -476,9 +460,9 @@ pub const IndexRegisterDisp = struct {
|
||||
index: u32,
|
||||
|
||||
/// Displacement value
|
||||
disp: u32,
|
||||
disp: i32,
|
||||
|
||||
pub fn encode(index: Register, disp: u32) IndexRegisterDisp {
|
||||
pub fn encode(index: Register, disp: i32) IndexRegisterDisp {
|
||||
return .{
|
||||
.index = @enumToInt(index),
|
||||
.disp = disp,
|
||||
@ -487,7 +471,7 @@ pub const IndexRegisterDisp = struct {
|
||||
|
||||
pub fn decode(this: IndexRegisterDisp) struct {
|
||||
index: Register,
|
||||
disp: u32,
|
||||
disp: i32,
|
||||
} {
|
||||
return .{
|
||||
.index = @intToEnum(Register, this.index),
|
||||
@ -503,12 +487,12 @@ pub const IndexRegisterDispImm = struct {
|
||||
index: u32,
|
||||
|
||||
/// Displacement value
|
||||
disp: u32,
|
||||
disp: i32,
|
||||
|
||||
/// Immediate
|
||||
imm: u32,
|
||||
|
||||
pub fn encode(index: Register, disp: u32, imm: u32) IndexRegisterDispImm {
|
||||
pub fn encode(index: Register, disp: i32, imm: u32) IndexRegisterDispImm {
|
||||
return .{
|
||||
.index = @enumToInt(index),
|
||||
.disp = disp,
|
||||
@ -518,7 +502,7 @@ pub const IndexRegisterDispImm = struct {
|
||||
|
||||
pub fn decode(this: IndexRegisterDispImm) struct {
|
||||
index: Register,
|
||||
disp: u32,
|
||||
disp: i32,
|
||||
imm: u32,
|
||||
} {
|
||||
return .{
|
||||
@ -576,7 +560,7 @@ pub const SaveRegisterList = struct {
|
||||
};
|
||||
|
||||
pub const ImmPair = struct {
|
||||
dest_off: u32,
|
||||
dest_off: i32,
|
||||
operand: u32,
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
794
src/arch/x86_64/encoder.zig
Normal file
794
src/arch/x86_64/encoder.zig
Normal file
@ -0,0 +1,794 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const math = std.math;
|
||||
|
||||
const bits = @import("bits.zig");
|
||||
const Encoding = @import("Encoding.zig");
|
||||
const Memory = bits.Memory;
|
||||
const Moffs = bits.Moffs;
|
||||
const PtrSize = bits.PtrSize;
|
||||
const Register = bits.Register;
|
||||
|
||||
pub const Instruction = struct {
|
||||
op1: Operand = .none,
|
||||
op2: Operand = .none,
|
||||
op3: Operand = .none,
|
||||
op4: Operand = .none,
|
||||
encoding: Encoding,
|
||||
|
||||
pub const Mnemonic = Encoding.Mnemonic;
|
||||
|
||||
pub const Operand = union(enum) {
|
||||
none,
|
||||
reg: Register,
|
||||
mem: Memory,
|
||||
imm: i64,
|
||||
|
||||
/// Returns the bitsize of the operand.
|
||||
/// Asserts the operand is either register or memory.
|
||||
pub fn size(op: Operand) u64 {
|
||||
return switch (op) {
|
||||
.none => unreachable,
|
||||
.reg => |reg| reg.size(),
|
||||
.mem => |mem| mem.size(),
|
||||
.imm => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns true if the operand is a segment register.
|
||||
/// Asserts the operand is either register or memory.
|
||||
pub fn isSegmentRegister(op: Operand) bool {
|
||||
return switch (op) {
|
||||
.none => unreachable,
|
||||
.reg => |reg| reg.class() == .segment,
|
||||
.mem => |mem| mem.isSegmentRegister(),
|
||||
.imm => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) !void {
|
||||
switch (op) {
|
||||
.none => {},
|
||||
.reg => |reg| try writer.writeAll(@tagName(reg)),
|
||||
.mem => |mem| switch (mem) {
|
||||
.rip => |rip| {
|
||||
try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
|
||||
if (rip.disp != 0) {
|
||||
const sign_bit = if (sign(rip.disp) < 0) "-" else "+";
|
||||
const disp_abs = try std.math.absInt(rip.disp);
|
||||
try writer.print(" {s} 0x{x}", .{ sign_bit, disp_abs });
|
||||
}
|
||||
try writer.writeByte(']');
|
||||
},
|
||||
.sib => |sib| {
|
||||
try writer.print("{s} ptr ", .{@tagName(sib.ptr_size)});
|
||||
|
||||
if (mem.isSegmentRegister()) {
|
||||
return writer.print("{s}:0x{x}", .{ @tagName(sib.base.?), sib.disp });
|
||||
}
|
||||
|
||||
try writer.writeByte('[');
|
||||
|
||||
if (sib.base) |base| {
|
||||
try writer.print("{s}", .{@tagName(base)});
|
||||
}
|
||||
if (sib.scale_index) |si| {
|
||||
if (sib.base != null) {
|
||||
try writer.writeAll(" + ");
|
||||
}
|
||||
try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
|
||||
}
|
||||
if (sib.disp != 0) {
|
||||
if (sib.base != null or sib.scale_index != null) {
|
||||
try writer.writeByte(' ');
|
||||
}
|
||||
try writer.writeByte(if (sign(sib.disp) < 0) '-' else '+');
|
||||
const disp_abs = try std.math.absInt(sib.disp);
|
||||
try writer.print(" 0x{x}", .{disp_abs});
|
||||
}
|
||||
|
||||
try writer.writeByte(']');
|
||||
},
|
||||
.moffs => |moffs| try writer.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset }),
|
||||
},
|
||||
.imm => |imm| {
|
||||
if (enc_op == .imm64) {
|
||||
return writer.print("0x{x}", .{@bitCast(u64, imm)});
|
||||
}
|
||||
const imm_abs = try std.math.absInt(imm);
|
||||
if (sign(imm) < 0) {
|
||||
try writer.writeByte('-');
|
||||
}
|
||||
try writer.print("0x{x}", .{imm_abs});
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn new(mnemonic: Mnemonic, args: struct {
|
||||
op1: Operand = .none,
|
||||
op2: Operand = .none,
|
||||
op3: Operand = .none,
|
||||
op4: Operand = .none,
|
||||
}) !Instruction {
|
||||
const encoding = Encoding.findByMnemonic(mnemonic, .{
|
||||
.op1 = args.op1,
|
||||
.op2 = args.op2,
|
||||
.op3 = args.op3,
|
||||
.op4 = args.op4,
|
||||
}) orelse return error.InvalidInstruction;
|
||||
std.log.debug("{}", .{encoding});
|
||||
return .{
|
||||
.op1 = args.op1,
|
||||
.op2 = args.op2,
|
||||
.op3 = args.op3,
|
||||
.op4 = args.op4,
|
||||
.encoding = encoding,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fmtPrint(inst: Instruction, writer: anytype) !void {
|
||||
try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
|
||||
const ops = [_]struct { Operand, Encoding.Op }{
|
||||
.{ inst.op1, inst.encoding.op1 },
|
||||
.{ inst.op2, inst.encoding.op2 },
|
||||
.{ inst.op3, inst.encoding.op3 },
|
||||
.{ inst.op4, inst.encoding.op4 },
|
||||
};
|
||||
for (&ops, 0..) |op, i| {
|
||||
if (op[0] == .none) break;
|
||||
if (i > 0) {
|
||||
try writer.writeByte(',');
|
||||
}
|
||||
try writer.writeByte(' ');
|
||||
try op[0].fmtPrint(op[1], writer);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(inst: Instruction, writer: anytype) !void {
|
||||
const encoder = Encoder(@TypeOf(writer)){ .writer = writer };
|
||||
const encoding = inst.encoding;
|
||||
|
||||
try inst.encodeLegacyPrefixes(encoder);
|
||||
try inst.encodeMandatoryPrefix(encoder);
|
||||
try inst.encodeRexPrefix(encoder);
|
||||
try inst.encodeOpcode(encoder);
|
||||
|
||||
switch (encoding.op_en) {
|
||||
.np, .o => {},
|
||||
.i, .d => try encodeImm(inst.op1.imm, encoding.op1, encoder),
|
||||
.zi, .oi => try encodeImm(inst.op2.imm, encoding.op2, encoder),
|
||||
.fd => try encoder.imm64(inst.op2.mem.moffs.offset),
|
||||
.td => try encoder.imm64(inst.op1.mem.moffs.offset),
|
||||
else => {
|
||||
const mem_op = switch (encoding.op_en) {
|
||||
.m, .mi, .m1, .mc, .mr => inst.op1,
|
||||
.rm, .rmi => inst.op2,
|
||||
else => unreachable,
|
||||
};
|
||||
switch (mem_op) {
|
||||
.reg => |reg| {
|
||||
const rm = switch (encoding.op_en) {
|
||||
.m, .mi, .m1, .mc => encoding.modRmExt(),
|
||||
.mr => inst.op2.reg.lowEnc(),
|
||||
.rm, .rmi => inst.op1.reg.lowEnc(),
|
||||
else => unreachable,
|
||||
};
|
||||
try encoder.modRm_direct(rm, reg.lowEnc());
|
||||
},
|
||||
.mem => |mem| {
|
||||
const op = switch (encoding.op_en) {
|
||||
.m, .mi, .m1, .mc => .none,
|
||||
.mr => inst.op2,
|
||||
.rm, .rmi => inst.op1,
|
||||
else => unreachable,
|
||||
};
|
||||
try encodeMemory(encoding, mem, op, encoder);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
switch (encoding.op_en) {
|
||||
.mi => try encodeImm(inst.op2.imm, encoding.op2, encoder),
|
||||
.rmi => try encodeImm(inst.op3.imm, encoding.op3, encoder),
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn encodeOpcode(inst: Instruction, encoder: anytype) !void {
|
||||
const opcode = inst.encoding.opcode();
|
||||
switch (inst.encoding.op_en) {
|
||||
.o, .oi => try encoder.opcode_withReg(opcode[0], inst.op1.reg.lowEnc()),
|
||||
else => {
|
||||
const index: usize = if (inst.encoding.mandatoryPrefix()) |_| 1 else 0;
|
||||
for (opcode[index..]) |byte| {
|
||||
try encoder.opcode_1byte(byte);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn encodeLegacyPrefixes(inst: Instruction, encoder: anytype) !void {
|
||||
const enc = inst.encoding;
|
||||
const op_en = enc.op_en;
|
||||
|
||||
var legacy = LegacyPrefixes{};
|
||||
if (enc.mode == .none) {
|
||||
const bit_size = enc.operandSize();
|
||||
if (bit_size == 16) {
|
||||
legacy.set16BitOverride();
|
||||
}
|
||||
}
|
||||
|
||||
const segment_override: ?Register = switch (op_en) {
|
||||
.i, .zi, .o, .oi, .d, .np => null,
|
||||
.fd => inst.op2.mem.base().?,
|
||||
.td => inst.op1.mem.base().?,
|
||||
.rm, .rmi => if (inst.op2.isSegmentRegister()) blk: {
|
||||
break :blk switch (inst.op2) {
|
||||
.reg => |r| r,
|
||||
.mem => |m| m.base().?,
|
||||
else => unreachable,
|
||||
};
|
||||
} else null,
|
||||
.m, .mi, .m1, .mc, .mr => if (inst.op1.isSegmentRegister()) blk: {
|
||||
break :blk switch (inst.op1) {
|
||||
.reg => |r| r,
|
||||
.mem => |m| m.base().?,
|
||||
else => unreachable,
|
||||
};
|
||||
} else null,
|
||||
};
|
||||
if (segment_override) |seg| {
|
||||
legacy.setSegmentOverride(seg);
|
||||
}
|
||||
|
||||
try encoder.legacyPrefixes(legacy);
|
||||
}
|
||||
|
||||
fn encodeRexPrefix(inst: Instruction, encoder: anytype) !void {
|
||||
const op_en = inst.encoding.op_en;
|
||||
|
||||
// Check if we need REX and can actually encode it
|
||||
const is_rex_invalid = for (&[_]Operand{ inst.op1, inst.op2, inst.op3, inst.op4 }) |op| switch (op) {
|
||||
.reg => |r| if (r.isRexInvalid()) break true,
|
||||
else => {},
|
||||
} else false;
|
||||
|
||||
var rex = Rex{};
|
||||
rex.w = inst.encoding.mode == .long;
|
||||
|
||||
switch (op_en) {
|
||||
.np, .i, .zi, .fd, .td, .d => {},
|
||||
.o, .oi => {
|
||||
rex.b = inst.op1.reg.isExtended();
|
||||
},
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi => {
|
||||
const r_op = switch (op_en) {
|
||||
.rm, .rmi => inst.op1,
|
||||
.mr => inst.op2,
|
||||
else => null,
|
||||
};
|
||||
if (r_op) |op| {
|
||||
rex.r = op.reg.isExtended();
|
||||
}
|
||||
|
||||
const b_x_op = switch (op_en) {
|
||||
.rm, .rmi => inst.op2,
|
||||
.m, .mi, .m1, .mc, .mr => inst.op1,
|
||||
else => unreachable,
|
||||
};
|
||||
switch (b_x_op) {
|
||||
.reg => |r| {
|
||||
rex.b = r.isExtended();
|
||||
},
|
||||
.mem => |mem| {
|
||||
rex.b = if (mem.base()) |base| base.isExtended() else false;
|
||||
rex.x = if (mem.scaleIndex()) |si| si.index.isExtended() else false;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if (rex.isSet() and is_rex_invalid) return error.CannotEncode;
|
||||
|
||||
try encoder.rex(rex);
|
||||
}
|
||||
|
||||
fn encodeMandatoryPrefix(inst: Instruction, encoder: anytype) !void {
|
||||
const prefix = inst.encoding.mandatoryPrefix() orelse return;
|
||||
try encoder.opcode_1byte(prefix);
|
||||
}
|
||||
|
||||
fn encodeMemory(encoding: Encoding, mem: Memory, operand: Operand, encoder: anytype) !void {
|
||||
const operand_enc = switch (operand) {
|
||||
.reg => |reg| reg.lowEnc(),
|
||||
.none => encoding.modRmExt(),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
switch (mem) {
|
||||
.moffs => unreachable,
|
||||
.sib => |sib| {
|
||||
if (sib.base) |base| {
|
||||
if (base.class() == .segment) {
|
||||
// TODO audit this wrt SIB
|
||||
try encoder.modRm_SIBDisp0(operand_enc);
|
||||
if (sib.scale_index) |si| {
|
||||
const scale = math.log2_int(u4, si.scale);
|
||||
try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
|
||||
} else {
|
||||
try encoder.sib_disp32();
|
||||
}
|
||||
try encoder.disp32(sib.disp);
|
||||
} else {
|
||||
assert(base.class() == .general_purpose);
|
||||
const dst = base.lowEnc();
|
||||
const src = operand_enc;
|
||||
if (dst == 4 or sib.scale_index != null) {
|
||||
if (sib.disp == 0 and dst != 5) {
|
||||
try encoder.modRm_SIBDisp0(src);
|
||||
if (sib.scale_index) |si| {
|
||||
const scale = math.log2_int(u4, si.scale);
|
||||
try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst);
|
||||
} else {
|
||||
try encoder.sib_base(dst);
|
||||
}
|
||||
} else if (math.cast(i8, sib.disp)) |_| {
|
||||
try encoder.modRm_SIBDisp8(src);
|
||||
if (sib.scale_index) |si| {
|
||||
const scale = math.log2_int(u4, si.scale);
|
||||
try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst);
|
||||
} else {
|
||||
try encoder.sib_baseDisp8(dst);
|
||||
}
|
||||
try encoder.disp8(@truncate(i8, sib.disp));
|
||||
} else {
|
||||
try encoder.modRm_SIBDisp32(src);
|
||||
if (sib.scale_index) |si| {
|
||||
const scale = math.log2_int(u4, si.scale);
|
||||
try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst);
|
||||
} else {
|
||||
try encoder.sib_baseDisp32(dst);
|
||||
}
|
||||
try encoder.disp32(sib.disp);
|
||||
}
|
||||
} else {
|
||||
if (sib.disp == 0 and dst != 5) {
|
||||
try encoder.modRm_indirectDisp0(src, dst);
|
||||
} else if (math.cast(i8, sib.disp)) |_| {
|
||||
try encoder.modRm_indirectDisp8(src, dst);
|
||||
try encoder.disp8(@truncate(i8, sib.disp));
|
||||
} else {
|
||||
try encoder.modRm_indirectDisp32(src, dst);
|
||||
try encoder.disp32(sib.disp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try encoder.modRm_SIBDisp0(operand_enc);
|
||||
if (sib.scale_index) |si| {
|
||||
const scale = math.log2_int(u4, si.scale);
|
||||
try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
|
||||
} else {
|
||||
try encoder.sib_disp32();
|
||||
}
|
||||
try encoder.disp32(sib.disp);
|
||||
}
|
||||
},
|
||||
.rip => |rip| {
|
||||
try encoder.modRm_RIPDisp32(operand_enc);
|
||||
try encoder.disp32(rip.disp);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn encodeImm(imm: i64, kind: Encoding.Op, encoder: anytype) !void {
|
||||
switch (kind) {
|
||||
.imm8, .rel8 => try encoder.imm8(@truncate(i8, imm)),
|
||||
.imm16, .rel16 => try encoder.imm16(@truncate(i16, imm)),
|
||||
.imm32, .rel32 => try encoder.imm32(@truncate(i32, imm)),
|
||||
.imm64 => try encoder.imm64(@bitCast(u64, imm)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline fn sign(i: anytype) @TypeOf(i) {
|
||||
return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0);
|
||||
}
|
||||
|
||||
pub const LegacyPrefixes = packed struct {
|
||||
/// LOCK
|
||||
prefix_f0: bool = false,
|
||||
/// REPNZ, REPNE, REP, Scalar Double-precision
|
||||
prefix_f2: bool = false,
|
||||
/// REPZ, REPE, REP, Scalar Single-precision
|
||||
prefix_f3: bool = false,
|
||||
|
||||
/// CS segment override or Branch not taken
|
||||
prefix_2e: bool = false,
|
||||
/// SS segment override
|
||||
prefix_36: bool = false,
|
||||
/// ES segment override
|
||||
prefix_26: bool = false,
|
||||
/// FS segment override
|
||||
prefix_64: bool = false,
|
||||
/// GS segment override
|
||||
prefix_65: bool = false,
|
||||
|
||||
/// Branch taken
|
||||
prefix_3e: bool = false,
|
||||
|
||||
/// Address size override (enables 16 bit address size)
|
||||
prefix_67: bool = false,
|
||||
|
||||
/// Operand size override (enables 16 bit operation)
|
||||
prefix_66: bool = false,
|
||||
|
||||
padding: u5 = 0,
|
||||
|
||||
pub fn setSegmentOverride(self: *LegacyPrefixes, reg: Register) void {
|
||||
assert(reg.class() == .segment);
|
||||
switch (reg) {
|
||||
.cs => self.prefix_2e = true,
|
||||
.ss => self.prefix_36 = true,
|
||||
.es => self.prefix_26 = true,
|
||||
.fs => self.prefix_64 = true,
|
||||
.gs => self.prefix_65 = true,
|
||||
.ds => {},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set16BitOverride(self: *LegacyPrefixes) void {
|
||||
self.prefix_66 = true;
|
||||
}
|
||||
};
|
||||
|
||||
fn Encoder(comptime T: type) type {
|
||||
return struct {
|
||||
writer: T,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
// --------
|
||||
// Prefixes
|
||||
// --------
|
||||
|
||||
/// Encodes legacy prefixes
|
||||
pub fn legacyPrefixes(self: Self, prefixes: LegacyPrefixes) !void {
|
||||
if (@bitCast(u16, prefixes) != 0) {
|
||||
// Hopefully this path isn't taken very often, so we'll do it the slow way for now
|
||||
|
||||
// LOCK
|
||||
if (prefixes.prefix_f0) try self.writer.writeByte(0xf0);
|
||||
// REPNZ, REPNE, REP, Scalar Double-precision
|
||||
if (prefixes.prefix_f2) try self.writer.writeByte(0xf2);
|
||||
// REPZ, REPE, REP, Scalar Single-precision
|
||||
if (prefixes.prefix_f3) try self.writer.writeByte(0xf3);
|
||||
|
||||
// CS segment override or Branch not taken
|
||||
if (prefixes.prefix_2e) try self.writer.writeByte(0x2e);
|
||||
// DS segment override
|
||||
if (prefixes.prefix_36) try self.writer.writeByte(0x36);
|
||||
// ES segment override
|
||||
if (prefixes.prefix_26) try self.writer.writeByte(0x26);
|
||||
// FS segment override
|
||||
if (prefixes.prefix_64) try self.writer.writeByte(0x64);
|
||||
// GS segment override
|
||||
if (prefixes.prefix_65) try self.writer.writeByte(0x65);
|
||||
|
||||
// Branch taken
|
||||
if (prefixes.prefix_3e) try self.writer.writeByte(0x3e);
|
||||
|
||||
// Operand size override
|
||||
if (prefixes.prefix_66) try self.writer.writeByte(0x66);
|
||||
|
||||
// Address size override
|
||||
if (prefixes.prefix_67) try self.writer.writeByte(0x67);
|
||||
}
|
||||
}
|
||||
|
||||
/// Use 16 bit operand size
|
||||
///
|
||||
/// Note that this flag is overridden by REX.W, if both are present.
|
||||
pub fn prefix16BitMode(self: Self) !void {
|
||||
try self.writer.writeByte(0x66);
|
||||
}
|
||||
|
||||
/// Encodes a REX prefix byte given all the fields
|
||||
///
|
||||
/// Use this byte whenever you need 64 bit operation,
|
||||
/// or one of reg, index, r/m, base, or opcode-reg might be extended.
|
||||
///
|
||||
/// See struct `Rex` for a description of each field.
|
||||
///
|
||||
/// Does not add a prefix byte if none of the fields are set!
|
||||
pub fn rex(self: Self, byte: Rex) !void {
|
||||
var value: u8 = 0b0100_0000;
|
||||
|
||||
if (byte.w) value |= 0b1000;
|
||||
if (byte.r) value |= 0b0100;
|
||||
if (byte.x) value |= 0b0010;
|
||||
if (byte.b) value |= 0b0001;
|
||||
|
||||
if (value != 0b0100_0000) {
|
||||
try self.writer.writeByte(value);
|
||||
}
|
||||
}
|
||||
|
||||
// ------
|
||||
// Opcode
|
||||
// ------
|
||||
|
||||
/// Encodes a 1 byte opcode
|
||||
pub fn opcode_1byte(self: Self, opcode: u8) !void {
|
||||
try self.writer.writeByte(opcode);
|
||||
}
|
||||
|
||||
/// Encodes a 2 byte opcode
|
||||
///
|
||||
/// e.g. IMUL has the opcode 0x0f 0xaf, so you use
|
||||
///
|
||||
/// encoder.opcode_2byte(0x0f, 0xaf);
|
||||
pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) !void {
|
||||
try self.writer.writeAll(&.{ prefix, opcode });
|
||||
}
|
||||
|
||||
/// Encodes a 3 byte opcode
|
||||
///
|
||||
/// e.g. MOVSD has the opcode 0xf2 0x0f 0x10
|
||||
///
|
||||
/// encoder.opcode_3byte(0xf2, 0x0f, 0x10);
|
||||
pub fn opcode_3byte(self: Self, prefix_1: u8, prefix_2: u8, opcode: u8) !void {
|
||||
try self.writer.writeAll(&.{ prefix_1, prefix_2, opcode });
|
||||
}
|
||||
|
||||
/// Encodes a 1 byte opcode with a reg field
|
||||
///
|
||||
/// Remember to add a REX prefix byte if reg is extended!
|
||||
pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) !void {
|
||||
assert(opcode & 0b111 == 0);
|
||||
try self.writer.writeByte(opcode | reg);
|
||||
}
|
||||
|
||||
// ------
|
||||
// ModR/M
|
||||
// ------
|
||||
|
||||
/// Construct a ModR/M byte given all the fields
|
||||
///
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) !void {
|
||||
try self.writer.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using direct r/m addressing
|
||||
/// r/m effective address: r/m
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_direct(self: Self, reg_or_opx: u3, rm: u3) !void {
|
||||
try self.modRm(0b11, reg_or_opx, rm);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using indirect r/m addressing
|
||||
/// r/m effective address: [r/m]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_indirectDisp0(self: Self, reg_or_opx: u3, rm: u3) !void {
|
||||
assert(rm != 4 and rm != 5);
|
||||
try self.modRm(0b00, reg_or_opx, rm);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using indirect SIB addressing
|
||||
/// r/m effective address: [SIB]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_SIBDisp0(self: Self, reg_or_opx: u3) !void {
|
||||
try self.modRm(0b00, reg_or_opx, 0b100);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using RIP-relative addressing
|
||||
/// r/m effective address: [RIP + disp32]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_RIPDisp32(self: Self, reg_or_opx: u3) !void {
|
||||
try self.modRm(0b00, reg_or_opx, 0b101);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using indirect r/m with a 8bit displacement
|
||||
/// r/m effective address: [r/m + disp8]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_indirectDisp8(self: Self, reg_or_opx: u3, rm: u3) !void {
|
||||
assert(rm != 4);
|
||||
try self.modRm(0b01, reg_or_opx, rm);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using indirect SIB with a 8bit displacement
|
||||
/// r/m effective address: [SIB + disp8]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_SIBDisp8(self: Self, reg_or_opx: u3) !void {
|
||||
try self.modRm(0b01, reg_or_opx, 0b100);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using indirect r/m with a 32bit displacement
|
||||
/// r/m effective address: [r/m + disp32]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_indirectDisp32(self: Self, reg_or_opx: u3, rm: u3) !void {
|
||||
assert(rm != 4);
|
||||
try self.modRm(0b10, reg_or_opx, rm);
|
||||
}
|
||||
|
||||
/// Construct a ModR/M byte using indirect SIB with a 32bit displacement
|
||||
/// r/m effective address: [SIB + disp32]
|
||||
///
|
||||
/// Note reg's effective address is always just reg for the ModR/M byte.
|
||||
/// Remember to add a REX prefix byte if reg or rm are extended!
|
||||
pub fn modRm_SIBDisp32(self: Self, reg_or_opx: u3) !void {
|
||||
try self.modRm(0b10, reg_or_opx, 0b100);
|
||||
}
|
||||
|
||||
// ---
|
||||
// SIB
|
||||
// ---
|
||||
|
||||
/// Construct a SIB byte given all the fields
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib(self: Self, scale: u2, index: u3, base: u3) !void {
|
||||
try self.writer.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with scale * index + base, no frills.
|
||||
/// r/m effective address: [base + scale * index]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_scaleIndexBase(self: Self, scale: u2, index: u3, base: u3) !void {
|
||||
assert(base != 5);
|
||||
|
||||
try self.sib(scale, index, base);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with scale * index + disp32
|
||||
/// r/m effective address: [scale * index + disp32]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_scaleIndexDisp32(self: Self, scale: u2, index: u3) !void {
|
||||
// scale is actually ignored
|
||||
// index = 4 means no index if and only if we haven't extended the register
|
||||
// TODO enforce this
|
||||
// base = 5 means no base, if mod == 0.
|
||||
try self.sib(scale, index, 5);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with just base
|
||||
/// r/m effective address: [base]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_base(self: Self, base: u3) !void {
|
||||
assert(base != 5);
|
||||
|
||||
// scale is actually ignored
|
||||
// index = 4 means no index
|
||||
try self.sib(0, 4, base);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with just disp32
|
||||
/// r/m effective address: [disp32]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_disp32(self: Self) !void {
|
||||
// scale is actually ignored
|
||||
// index = 4 means no index
|
||||
// base = 5 means no base, if mod == 0.
|
||||
try self.sib(0, 4, 5);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with scale * index + base + disp8
|
||||
/// r/m effective address: [base + scale * index + disp8]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_scaleIndexBaseDisp8(self: Self, scale: u2, index: u3, base: u3) !void {
|
||||
try self.sib(scale, index, base);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with base + disp8, no index
|
||||
/// r/m effective address: [base + disp8]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_baseDisp8(self: Self, base: u3) !void {
|
||||
// scale is ignored
|
||||
// index = 4 means no index
|
||||
try self.sib(0, 4, base);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with scale * index + base + disp32
|
||||
/// r/m effective address: [base + scale * index + disp32]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_scaleIndexBaseDisp32(self: Self, scale: u2, index: u3, base: u3) !void {
|
||||
try self.sib(scale, index, base);
|
||||
}
|
||||
|
||||
/// Construct a SIB byte with base + disp32, no index
|
||||
/// r/m effective address: [base + disp32]
|
||||
///
|
||||
/// Remember to add a REX prefix byte if index or base are extended!
|
||||
pub fn sib_baseDisp32(self: Self, base: u3) !void {
|
||||
// scale is ignored
|
||||
// index = 4 means no index
|
||||
try self.sib(0, 4, base);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// Trivial (no bit fiddling)
|
||||
// -------------------------
|
||||
|
||||
/// Encode an 8 bit immediate
|
||||
///
|
||||
/// 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));
|
||||
}
|
||||
|
||||
/// Encode an 8 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));
|
||||
}
|
||||
|
||||
/// Encode an 16 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);
|
||||
}
|
||||
|
||||
/// Encode an 32 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);
|
||||
}
|
||||
|
||||
/// Encode an 32 bit displacement
|
||||
///
|
||||
/// It is sign-extended to 64 bits by the cpu.
|
||||
pub fn disp32(self: Self, disp: i32) !void {
|
||||
try self.writer.writeIntLittle(i32, disp);
|
||||
}
|
||||
|
||||
/// Encode an 64 bit immediate
|
||||
///
|
||||
/// It is sign-extended to 64 bits by the cpu.
|
||||
pub fn imm64(self: Self, imm: u64) !void {
|
||||
try self.writer.writeIntLittle(u64, imm);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const Rex = struct {
|
||||
w: bool = false,
|
||||
r: bool = false,
|
||||
x: bool = false,
|
||||
b: bool = false,
|
||||
|
||||
pub fn isSet(rex: Rex) bool {
|
||||
return rex.w or rex.r or rex.x or rex.b;
|
||||
}
|
||||
};
|
||||
542
src/arch/x86_64/encodings.zig
Normal file
542
src/arch/x86_64/encodings.zig
Normal file
@ -0,0 +1,542 @@
|
||||
const Encoding = @import("Encoding.zig");
|
||||
const Mnemonic = Encoding.Mnemonic;
|
||||
const OpEn = Encoding.OpEn;
|
||||
const Op = Encoding.Op;
|
||||
const Mode = Encoding.Mode;
|
||||
|
||||
const opcode_len = u2;
|
||||
const modrm_ext = u3;
|
||||
|
||||
const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, opcode_len, u8, u8, u8, modrm_ext, Mode };
|
||||
|
||||
// TODO move this into a .zon file when Zig is capable of importing .zon files
|
||||
// zig fmt: off
|
||||
pub const table = &[_]Entry{
|
||||
// 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 },
|
||||
|
||||
// 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 },
|
||||
.{ .call, .m, .rm64, .none, .none, .none, 1, 0xff, 0x00, 0x00, 2, .none },
|
||||
|
||||
.{ .cbw, .np, .o16, .none, .none, .none, 1, 0x98, 0x00, 0x00, 0, .none },
|
||||
.{ .cwde, .np, .o32, .none, .none, .none, 1, 0x98, 0x00, 0x00, 0, .none },
|
||||
.{ .cdqe, .np, .o64, .none, .none, .none, 1, 0x98, 0x00, 0x00, 0, .long },
|
||||
|
||||
.{ .cwd, .np, .o16, .none, .none, .none, 1, 0x99, 0x00, 0x00, 0, .none },
|
||||
.{ .cdq, .np, .o32, .none, .none, .none, 1, 0x99, 0x00, 0x00, 0, .none },
|
||||
.{ .cqo, .np, .o64, .none, .none, .none, 1, 0x99, 0x00, 0x00, 0, .long },
|
||||
|
||||
.{ .cmova, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
|
||||
.{ .cmova, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
|
||||
.{ .cmova, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .long },
|
||||
.{ .cmovae, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
|
||||
.{ .cmovae, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
|
||||
.{ .cmovae, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .long },
|
||||
.{ .cmovb, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
|
||||
.{ .cmovb, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
|
||||
.{ .cmovb, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .long },
|
||||
.{ .cmovbe, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
|
||||
.{ .cmovbe, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
|
||||
.{ .cmovbe, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .long },
|
||||
.{ .cmovc, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
|
||||
.{ .cmovc, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
|
||||
.{ .cmovc, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .long },
|
||||
.{ .cmove, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
|
||||
.{ .cmove, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
|
||||
.{ .cmove, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .long },
|
||||
.{ .cmovg, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
|
||||
.{ .cmovg, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
|
||||
.{ .cmovg, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .long },
|
||||
.{ .cmovge, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
|
||||
.{ .cmovge, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
|
||||
.{ .cmovge, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .long },
|
||||
.{ .cmovl, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
|
||||
.{ .cmovl, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
|
||||
.{ .cmovl, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .long },
|
||||
.{ .cmovle, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
|
||||
.{ .cmovle, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
|
||||
.{ .cmovle, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .long },
|
||||
.{ .cmovna, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
|
||||
.{ .cmovna, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
|
||||
.{ .cmovna, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .long },
|
||||
.{ .cmovnae, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
|
||||
.{ .cmovnae, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
|
||||
.{ .cmovnae, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .long },
|
||||
.{ .cmovnb, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
|
||||
.{ .cmovnb, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
|
||||
.{ .cmovnb, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .long },
|
||||
.{ .cmovnbe, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
|
||||
.{ .cmovnbe, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
|
||||
.{ .cmovnbe, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .long },
|
||||
.{ .cmovnc, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
|
||||
.{ .cmovnc, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
|
||||
.{ .cmovnc, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .long },
|
||||
.{ .cmovne, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
|
||||
.{ .cmovne, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
|
||||
.{ .cmovne, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .long },
|
||||
.{ .cmovng, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
|
||||
.{ .cmovng, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
|
||||
.{ .cmovng, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .long },
|
||||
.{ .cmovnge, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
|
||||
.{ .cmovnge, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
|
||||
.{ .cmovnge, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .long },
|
||||
.{ .cmovnl, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
|
||||
.{ .cmovnl, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
|
||||
.{ .cmovnl, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .long },
|
||||
.{ .cmovnle, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
|
||||
.{ .cmovnle, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
|
||||
.{ .cmovnle, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .long },
|
||||
.{ .cmovno, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x41, 0x00, 0, .none },
|
||||
.{ .cmovno, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x41, 0x00, 0, .none },
|
||||
.{ .cmovno, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x41, 0x00, 0, .long },
|
||||
.{ .cmovnp, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
|
||||
.{ .cmovnp, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
|
||||
.{ .cmovnp, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .long },
|
||||
.{ .cmovns, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x49, 0x00, 0, .none },
|
||||
.{ .cmovns, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x49, 0x00, 0, .none },
|
||||
.{ .cmovns, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x49, 0x00, 0, .long },
|
||||
.{ .cmovnz, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
|
||||
.{ .cmovnz, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
|
||||
.{ .cmovnz, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .long },
|
||||
.{ .cmovo, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x40, 0x00, 0, .none },
|
||||
.{ .cmovo, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x40, 0x00, 0, .none },
|
||||
.{ .cmovo, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x40, 0x00, 0, .long },
|
||||
.{ .cmovp, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
|
||||
.{ .cmovp, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
|
||||
.{ .cmovp, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .long },
|
||||
.{ .cmovpe, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
|
||||
.{ .cmovpe, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
|
||||
.{ .cmovpe, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .long },
|
||||
.{ .cmovpo, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
|
||||
.{ .cmovpo, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
|
||||
.{ .cmovpo, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .long },
|
||||
.{ .cmovs, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x48, 0x00, 0, .none },
|
||||
.{ .cmovs, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x48, 0x00, 0, .none },
|
||||
.{ .cmovs, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x48, 0x00, 0, .long },
|
||||
.{ .cmovz, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
|
||||
.{ .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 },
|
||||
|
||||
.{ .div, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 6, .none },
|
||||
.{ .div, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .none },
|
||||
.{ .div, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .none },
|
||||
.{ .div, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .long },
|
||||
|
||||
.{ .fisttp, .m, .m16, .none, .none, .none, 1, 0xdf, 0x00, 0x00, 1, .fpu },
|
||||
.{ .fisttp, .m, .m32, .none, .none, .none, 1, 0xdb, 0x00, 0x00, 1, .fpu },
|
||||
.{ .fisttp, .m, .m64, .none, .none, .none, 1, 0xdd, 0x00, 0x00, 1, .fpu },
|
||||
|
||||
.{ .fld, .m, .m32, .none, .none, .none, 1, 0xd9, 0x00, 0x00, 0, .fpu },
|
||||
.{ .fld, .m, .m64, .none, .none, .none, 1, 0xdd, 0x00, 0x00, 0, .fpu },
|
||||
.{ .fld, .m, .m80, .none, .none, .none, 1, 0xdb, 0x00, 0x00, 5, .fpu },
|
||||
|
||||
.{ .idiv, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 7, .none },
|
||||
.{ .idiv, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 7, .none },
|
||||
.{ .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 },
|
||||
|
||||
.{ .int3, .np, .none, .none, .none, .none, 1, 0xcc, 0x00, 0x00, 0, .none },
|
||||
|
||||
.{ .ja, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x87, 0x00, 0, .none },
|
||||
.{ .jae, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x83, 0x00, 0, .none },
|
||||
.{ .jb, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x82, 0x00, 0, .none },
|
||||
.{ .jbe, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x86, 0x00, 0, .none },
|
||||
.{ .jc, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x82, 0x00, 0, .none },
|
||||
.{ .jrcxz, .d, .rel32, .none, .none, .none, 1, 0xe3, 0x00, 0x00, 0, .none },
|
||||
.{ .je, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x84, 0x00, 0, .none },
|
||||
.{ .jg, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8f, 0x00, 0, .none },
|
||||
.{ .jge, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8d, 0x00, 0, .none },
|
||||
.{ .jl, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8c, 0x00, 0, .none },
|
||||
.{ .jle, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8e, 0x00, 0, .none },
|
||||
.{ .jna, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x86, 0x00, 0, .none },
|
||||
.{ .jnae, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x82, 0x00, 0, .none },
|
||||
.{ .jnb, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x83, 0x00, 0, .none },
|
||||
.{ .jnbe, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x87, 0x00, 0, .none },
|
||||
.{ .jnc, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x83, 0x00, 0, .none },
|
||||
.{ .jne, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x85, 0x00, 0, .none },
|
||||
.{ .jng, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8e, 0x00, 0, .none },
|
||||
.{ .jnge, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8c, 0x00, 0, .none },
|
||||
.{ .jnl, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8d, 0x00, 0, .none },
|
||||
.{ .jnle, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8f, 0x00, 0, .none },
|
||||
.{ .jno, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x81, 0x00, 0, .none },
|
||||
.{ .jnp, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8b, 0x00, 0, .none },
|
||||
.{ .jns, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x89, 0x00, 0, .none },
|
||||
.{ .jnz, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x85, 0x00, 0, .none },
|
||||
.{ .jo, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x80, 0x00, 0, .none },
|
||||
.{ .jp, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8a, 0x00, 0, .none },
|
||||
.{ .jpe, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8a, 0x00, 0, .none },
|
||||
.{ .jpo, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8b, 0x00, 0, .none },
|
||||
.{ .js, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x88, 0x00, 0, .none },
|
||||
.{ .jz, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x84, 0x00, 0, .none },
|
||||
|
||||
.{ .jmp, .d, .rel32, .none, .none, .none, 1, 0xe9, 0x00, 0x00, 0, .none },
|
||||
.{ .jmp, .m, .rm64, .none, .none, .none, 1, 0xff, 0x00, 0x00, 4, .none },
|
||||
|
||||
.{ .lea, .rm, .r16, .m, .none, .none, 1, 0x8d, 0x00, 0x00, 0, .none },
|
||||
.{ .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 },
|
||||
|
||||
.{ .movsx, .rm, .r16, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .none },
|
||||
.{ .movsx, .rm, .r32, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .none },
|
||||
.{ .movsx, .rm, .r64, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .long },
|
||||
.{ .movsx, .rm, .r32, .rm16, .none, .none, 2, 0x0f, 0xbf, 0x00, 0, .none },
|
||||
.{ .movsx, .rm, .r64, .rm16, .none, .none, 2, 0x0f, 0xbf, 0x00, 0, .long },
|
||||
|
||||
// This instruction is discouraged.
|
||||
.{ .movsxd, .rm, .r32, .rm32, .none, .none, 1, 0x63, 0x00, 0x00, 0, .none },
|
||||
.{ .movsxd, .rm, .r64, .rm32, .none, .none, 1, 0x63, 0x00, 0x00, 0, .long },
|
||||
|
||||
.{ .movzx, .rm, .r16, .rm8, .none, .none, 2, 0x0f, 0xb6, 0x00, 0, .none },
|
||||
.{ .movzx, .rm, .r32, .rm8, .none, .none, 2, 0x0f, 0xb6, 0x00, 0, .none },
|
||||
.{ .movzx, .rm, .r64, .rm8, .none, .none, 2, 0x0f, 0xb6, 0x00, 0, .long },
|
||||
.{ .movzx, .rm, .r32, .rm16, .none, .none, 2, 0x0f, 0xb7, 0x00, 0, .none },
|
||||
.{ .movzx, .rm, .r64, .rm16, .none, .none, 2, 0x0f, 0xb7, 0x00, 0, .long },
|
||||
|
||||
.{ .mul, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 4, .none },
|
||||
.{ .mul, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 4, .none },
|
||||
.{ .mul, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 4, .none },
|
||||
.{ .mul, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 4, .long },
|
||||
|
||||
.{ .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 },
|
||||
|
||||
.{ .pop, .o, .r16, .none, .none, .none, 1, 0x58, 0x00, 0x00, 0, .none },
|
||||
.{ .pop, .o, .r64, .none, .none, .none, 1, 0x58, 0x00, 0x00, 0, .none },
|
||||
.{ .pop, .m, .rm16, .none, .none, .none, 1, 0x8f, 0x00, 0x00, 0, .none },
|
||||
.{ .pop, .m, .rm64, .none, .none, .none, 1, 0x8f, 0x00, 0x00, 0, .none },
|
||||
|
||||
.{ .push, .o, .r16, .none, .none, .none, 1, 0x50, 0x00, 0x00, 0, .none },
|
||||
.{ .push, .o, .r64, .none, .none, .none, 1, 0x50, 0x00, 0x00, 0, .none },
|
||||
.{ .push, .m, .rm16, .none, .none, .none, 1, 0xff, 0x00, 0x00, 6, .none },
|
||||
.{ .push, .m, .rm64, .none, .none, .none, 1, 0xff, 0x00, 0x00, 6, .none },
|
||||
.{ .push, .i, .imm8, .none, .none, .none, 1, 0x6a, 0x00, 0x00, 0, .none },
|
||||
.{ .push, .i, .imm16, .none, .none, .none, 1, 0x68, 0x00, 0x00, 0, .none },
|
||||
.{ .push, .i, .imm32, .none, .none, .none, 1, 0x68, 0x00, 0x00, 0, .none },
|
||||
|
||||
.{ .ret, .np, .none, .none, .none, .none, 1, 0xc3, 0x00, 0x00, 0, .none },
|
||||
|
||||
.{ .sal, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .long },
|
||||
.{ .sal, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .long },
|
||||
.{ .sal, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .mi, .rm32, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
|
||||
.{ .sal, .mi, .rm64, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .long },
|
||||
|
||||
.{ .sar, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 7, .long },
|
||||
.{ .sar, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 7, .long },
|
||||
.{ .sar, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 7, .none },
|
||||
.{ .sar, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 7, .none },
|
||||
.{ .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 },
|
||||
|
||||
.{ .seta, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .none },
|
||||
.{ .setae, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
|
||||
.{ .setb, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .none },
|
||||
.{ .setbe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x96, 0x00, 0, .none },
|
||||
.{ .setc, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .none },
|
||||
.{ .sete, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x94, 0x00, 0, .none },
|
||||
.{ .setg, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9f, 0x00, 0, .none },
|
||||
.{ .setge, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9d, 0x00, 0, .none },
|
||||
.{ .setl, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9c, 0x00, 0, .none },
|
||||
.{ .setle, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9e, 0x00, 0, .none },
|
||||
.{ .setna, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x96, 0x00, 0, .none },
|
||||
.{ .setnae, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .none },
|
||||
.{ .setnb, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
|
||||
.{ .setnbe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .none },
|
||||
.{ .setnc, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
|
||||
.{ .setne, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x95, 0x00, 0, .none },
|
||||
.{ .setng, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9e, 0x00, 0, .none },
|
||||
.{ .setnge, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9c, 0x00, 0, .none },
|
||||
.{ .setnl, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9d, 0x00, 0, .none },
|
||||
.{ .setnle, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9f, 0x00, 0, .none },
|
||||
.{ .setno, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x91, 0x00, 0, .none },
|
||||
.{ .setnp, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9b, 0x00, 0, .none },
|
||||
.{ .setns, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x99, 0x00, 0, .none },
|
||||
.{ .setnz, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x95, 0x00, 0, .none },
|
||||
.{ .seto, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x90, 0x00, 0, .none },
|
||||
.{ .setp, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9a, 0x00, 0, .none },
|
||||
.{ .setpe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9a, 0x00, 0, .none },
|
||||
.{ .setpo, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9b, 0x00, 0, .none },
|
||||
.{ .sets, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x98, 0x00, 0, .none },
|
||||
.{ .setz, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x94, 0x00, 0, .none },
|
||||
|
||||
.{ .shl, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .long },
|
||||
.{ .shl, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .long },
|
||||
.{ .shl, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .mi, .rm32, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
|
||||
.{ .shl, .mi, .rm64, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .long },
|
||||
|
||||
.{ .shr, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 5, .long },
|
||||
.{ .shr, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 5, .long },
|
||||
.{ .shr, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 5, .none },
|
||||
.{ .shr, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 5, .none },
|
||||
.{ .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 },
|
||||
|
||||
.{ .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 },
|
||||
|
||||
// SSE
|
||||
.{ .addss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x58, 0, .sse },
|
||||
|
||||
.{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, 3, 0xf3, 0x0f, 0xc2, 0, .sse },
|
||||
|
||||
.{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },
|
||||
.{ .movss, .mr, .xmm_m32, .xmm, .none, .none, 3, 0xf3, 0x0f, 0x11, 0, .sse },
|
||||
|
||||
.{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },
|
||||
|
||||
// SSE2
|
||||
.{ .addsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x58, 0, .sse2 },
|
||||
|
||||
.{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, 3, 0xf2, 0x0f, 0xc2, 0, .sse2 },
|
||||
|
||||
.{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },
|
||||
.{ .movq, .mr, .xmm_m64, .xmm, .none, .none, 3, 0x66, 0x0f, 0xd6, 0, .sse2 },
|
||||
|
||||
.{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },
|
||||
.{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, 3, 0xf2, 0x0f, 0x11, 0, .sse2 },
|
||||
|
||||
.{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0x66, 0x0f, 0x2e, 0, .sse2 },
|
||||
};
|
||||
// zig fmt: on
|
||||
Loading…
x
Reference in New Issue
Block a user