authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-27 16:20:27+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-27 16:20:27+02:00
log28d6dd75ac151449ddc29f3937a9e333f0a608c1
tree518b954519c6b26aab9aea84f10fa49bfec82fac
parent1de64dba236d9496ae5f31b59b7a4947ff4d90be
parentfd13e44e0c69465cf9ea9ef4fd17dfebf5cffd45
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15087 from jacobly0/x86-debug-mir

x86_64: misc fixes

11 files changed, 2609 insertions(+), 2429 deletions(-)

lib/std/multi_array_list.zig+16-10
......@@ -49,6 +49,20 @@ pub fn MultiArrayList(comptime S: type) type {
4949 return casted_ptr[0..self.len];
5050 }
5151
52 pub fn set(self: Slice, index: usize, elem: S) void {
53 inline for (fields) |field_info| {
54 self.items(@field(Field, field_info.name))[index] = @field(elem, field_info.name);
55 }
56 }
57
58 pub fn get(self: Slice, index: usize) S {
59 var elem: S = undefined;
60 inline for (fields) |field_info| {
61 @field(elem, field_info.name) = self.items(@field(Field, field_info.name))[index];
62 }
63 return elem;
64 }
65
5266 pub fn toMultiArrayList(self: Slice) Self {
5367 if (self.ptrs.len == 0) {
5468 return .{};
......@@ -156,20 +170,12 @@ pub fn MultiArrayList(comptime S: type) type {
156170
157171 /// Overwrite one array element with new data.
158172 pub fn set(self: *Self, index: usize, elem: S) void {
159 const slices = self.slice();
160 inline for (fields, 0..) |field_info, i| {
161 slices.items(@intToEnum(Field, i))[index] = @field(elem, field_info.name);
162 }
173 return self.slice().set(index, elem);
163174 }
164175
165176 /// Obtain all the data for one array element.
166177 pub fn get(self: Self, index: usize) S {
167 const slices = self.slice();
168 var result: S = undefined;
169 inline for (fields, 0..) |field_info, i| {
170 @field(result, field_info.name) = slices.items(@intToEnum(Field, i))[index];
171 }
172 return result;
178 return self.slice().get(index);
173179 }
174180
175181 /// Extend the list by 1 element. Allocates more memory as necessary.
src/arch/x86_64/CodeGen.zig+365-249
......@@ -20,6 +20,7 @@ const ErrorMsg = Module.ErrorMsg;
2020const Result = codegen.Result;
2121const Emit = @import("Emit.zig");
2222const Liveness = @import("../../Liveness.zig");
23const Lower = @import("Lower.zig");
2324const Mir = @import("Mir.zig");
2425const Module = @import("../../Module.zig");
2526const Target = std.Target;
......@@ -44,6 +45,8 @@ const sse = abi.RegisterClass.sse;
4445
4546const InnerError = CodeGenError || error{OutOfRegisters};
4647
48const debug_wip_mir = false;
49
4750gpa: Allocator,
4851air: Air,
4952liveness: Liveness,
......@@ -267,6 +270,12 @@ pub fn generate(
267270 assert(fn_owner_decl.has_tv);
268271 const fn_type = fn_owner_decl.ty;
269272
273 if (debug_wip_mir) {
274 const stderr = std.io.getStdErr().writer();
275 fn_owner_decl.renderFullyQualifiedName(mod, stderr) catch {};
276 stderr.writeAll(":\n") catch {};
277 }
278
270279 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
271280 try branch_stack.ensureUnusedCapacity(2);
272281 // The outermost branch is used for constants only.
......@@ -341,19 +350,22 @@ pub fn generate(
341350 defer mir.deinit(bin_file.allocator);
342351
343352 var emit = Emit{
344 .mir = mir,
353 .lower = .{
354 .allocator = bin_file.allocator,
355 .mir = mir,
356 .target = &bin_file.options.target,
357 .src_loc = src_loc,
358 },
345359 .bin_file = bin_file,
346360 .debug_output = debug_output,
347 .target = &bin_file.options.target,
348 .src_loc = src_loc,
349361 .code = code,
350362 .prev_di_pc = 0,
351363 .prev_di_line = module_fn.lbrace_line,
352364 .prev_di_column = module_fn.lbrace_column,
353365 };
354366 defer emit.deinit();
355 emit.lowerMir() catch |err| switch (err) {
356 error.EmitFail => return Result{ .fail = emit.err_msg.? },
367 emit.emitMir() catch |err| switch (err) {
368 error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? },
357369 error.InvalidInstruction, error.CannotEncode => |e| {
358370 const msg = switch (e) {
359371 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
......@@ -378,11 +390,49 @@ pub fn generate(
378390 }
379391}
380392
393fn dumpWipMir(self: *Self, inst: Mir.Inst) !void {
394 if (!debug_wip_mir) return;
395 const stderr = std.io.getStdErr().writer();
396
397 var lower = Lower{
398 .allocator = self.gpa,
399 .mir = .{
400 .instructions = self.mir_instructions.slice(),
401 .extra = self.mir_extra.items,
402 },
403 .target = self.target,
404 .src_loc = self.src_loc,
405 };
406 for (lower.lowerMir(inst) catch |err| switch (err) {
407 error.LowerFail => {
408 defer {
409 lower.err_msg.?.deinit(self.gpa);
410 lower.err_msg = null;
411 }
412 try stderr.print("{s}\n", .{lower.err_msg.?.msg});
413 return;
414 },
415 error.InvalidInstruction, error.CannotEncode => |e| {
416 try stderr.writeAll(switch (e) {
417 error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n",
418 error.CannotEncode => "CodeGen failed to encode the instruction.\n",
419 });
420 return;
421 },
422 else => |e| return e,
423 }) |lower_inst| {
424 try stderr.writeAll(" | ");
425 try lower_inst.fmtPrint(stderr);
426 try stderr.writeByte('\n');
427 }
428}
429
381430fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
382431 const gpa = self.gpa;
383432 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
384433 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
385434 self.mir_instructions.appendAssumeCapacity(inst);
435 self.dumpWipMir(inst) catch {};
386436 return result_index;
387437}
388438
......@@ -842,8 +892,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
842892 const old_air_bookkeeping = self.air_bookkeeping;
843893 try self.ensureProcessDeathCapacity(Liveness.bpi);
844894 if (builtin.mode == .Debug) {
845 try self.mir_to_air_map.put(@intCast(u32, self.mir_instructions.len), inst);
895 try self.mir_to_air_map.put(@intCast(Mir.Inst.Index, self.mir_instructions.len), inst);
846896 }
897 if (debug_wip_mir) @import("../../print_air.zig").dumpInst(
898 inst,
899 self.bin_file.options.module.?,
900 self.air,
901 self.liveness,
902 );
847903
848904 switch (air_tags[inst]) {
849905 // zig fmt: off
......@@ -1479,43 +1535,31 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
14791535
14801536fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
14811537 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1482 if (self.liveness.isUnused(inst))
1483 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1484
1485 const src_ty = self.air.typeOf(ty_op.operand);
1486 const dst_ty = self.air.typeOfIndex(inst);
1487 const operand = try self.resolveInst(ty_op.operand);
1488
1489 const src_ty_size = src_ty.abiSize(self.target.*);
1490 const dst_ty_size = dst_ty.abiSize(self.target.*);
1538 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1539 const dst_ty = self.air.typeOfIndex(inst);
1540 const dst_abi_size = dst_ty.abiSize(self.target.*);
1541 if (dst_abi_size > 8) {
1542 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});
1543 }
14911544
1492 if (src_ty_size > 8 or dst_ty_size > 8) {
1493 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});
1494 }
1545 const src_mcv = try self.resolveInst(ty_op.operand);
1546 const src_lock = switch (src_mcv) {
1547 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1548 else => null,
1549 };
1550 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
14951551
1496 const operand_lock: ?RegisterLock = switch (operand) {
1497 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1498 else => null,
1499 };
1500 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
1552 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
1553 src_mcv
1554 else
1555 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
15011556
1502 const reg: Register = blk: {
1503 if (operand.isRegister()) {
1504 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1505 break :blk operand.register.to64();
1506 }
1507 }
1508 const mcv = try self.copyToRegisterWithInstTracking(inst, src_ty, operand);
1509 break :blk mcv.register.to64();
1557 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
1558 // have to be removed. this only happens if the dst if not a power-of-two size.
1559 if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64());
1560 break :result dst_mcv;
15101561 };
1511
1512 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
1513 // have to be removed. this only happens if the dst if not a power-of-two size.
1514 if (self.regExtraBits(dst_ty) > 0) {
1515 try self.truncateRegister(dst_ty, reg);
1516 }
1517
1518 return self.finishAir(inst, .{ .register = reg }, .{ ty_op.operand, .none, .none });
1562 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
15191563}
15201564
15211565fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1628,7 +1672,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
16281672 const reg_bits = self.regBitSize(ty);
16291673 const cc: Condition = if (ty.isSignedInt()) cc: {
16301674 try self.genSetReg(ty, limit_reg, dst_mcv);
1631 try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
1675 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
16321676 try self.genBinOpMir(.xor, ty, limit_mcv, .{
16331677 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
16341678 });
......@@ -1681,7 +1725,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
16811725 const reg_bits = self.regBitSize(ty);
16821726 const cc: Condition = if (ty.isSignedInt()) cc: {
16831727 try self.genSetReg(ty, limit_reg, dst_mcv);
1684 try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
1728 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
16851729 try self.genBinOpMir(.xor, ty, limit_mcv, .{
16861730 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
16871731 });
......@@ -1735,7 +1779,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
17351779 const cc: Condition = if (ty.isSignedInt()) cc: {
17361780 try self.genSetReg(ty, limit_reg, lhs_mcv);
17371781 try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv);
1738 try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
1782 try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
17391783 try self.genBinOpMir(.xor, ty, limit_mcv, .{
17401784 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
17411785 });
......@@ -2509,16 +2553,13 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
25092553
25102554fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
25112555 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2512 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2513 const operand = try self.resolveInst(ty_op.operand);
2514 const dst_mcv: MCValue = blk: {
2515 switch (operand) {
2516 .stack_offset => |off| {
2517 break :blk MCValue{ .stack_offset = off };
2518 },
2519 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),
2520 }
2521 };
2556 const result = if (self.liveness.isUnused(inst)) .dead else result: {
2557 const src_mcv = try self.resolveInst(ty_op.operand);
2558 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
2559
2560 const dst_mcv = try self.allocRegOrMem(inst, true);
2561 const dst_ty = self.air.typeOfIndex(inst);
2562 try self.setRegOrMem(dst_ty, dst_mcv, src_mcv);
25222563 break :result dst_mcv;
25232564 };
25242565 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -3040,7 +3081,8 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
30403081 };
30413082 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
30423083
3043 const dst_mcv: MCValue = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
3084 const dst_mcv: MCValue =
3085 if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
30443086 src_mcv
30453087 else
30463088 .{ .register = try self.register_manager.allocReg(inst, gp) };
......@@ -3432,23 +3474,21 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
34323474 const elem_ty = self.air.typeOfIndex(inst);
34333475 const elem_size = elem_ty.abiSize(self.target.*);
34343476 const result: MCValue = result: {
3435 if (!elem_ty.hasRuntimeBitsIgnoreComptime())
3436 break :result MCValue.none;
3477 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
3478
3479 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
3480 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
3481 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
34373482
34383483 const ptr = try self.resolveInst(ty_op.operand);
34393484 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();
3440 if (self.liveness.isUnused(inst) and !is_volatile)
3441 break :result MCValue.dead;
3485 if (self.liveness.isUnused(inst) and !is_volatile) break :result .dead;
34423486
3443 const dst_mcv: MCValue = blk: {
3444 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
3445 // The MCValue that holds the pointer can be re-used as the value.
3446 break :blk ptr;
3447 } else {
3448 break :blk try self.allocRegOrMem(inst, true);
3449 }
3450 };
3451 log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr });
3487 const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr))
3488 // The MCValue that holds the pointer can be re-used as the value.
3489 ptr
3490 else
3491 try self.allocRegOrMem(inst, true);
34523492 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
34533493 break :result dst_mcv;
34543494 };
......@@ -3943,9 +3983,6 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
39433983 .register_overflow => unreachable,
39443984 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
39453985 .ptr_stack_offset, .stack_offset => |off| {
3946 if (off > math.maxInt(i32)) {
3947 return self.fail("stack offset too large", .{});
3948 }
39493986 if (abi_size > 8) {
39503987 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
39513988 }
......@@ -4387,9 +4424,6 @@ fn genBinOp(
43874424 if (lhs_ty.zigTypeTag() == .Vector) {
43884425 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
43894426 }
4390 if (lhs_ty.abiSize(self.target.*) > 8) {
4391 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
4392 }
43934427
43944428 switch (lhs) {
43954429 .immediate => |imm| switch (imm) {
......@@ -4402,7 +4436,7 @@ fn genBinOp(
44024436 else => {},
44034437 }
44044438
4405 const is_commutative: bool = switch (tag) {
4439 const is_commutative = switch (tag) {
44064440 .add,
44074441 .addwrap,
44084442 .bool_or,
......@@ -4416,6 +4450,20 @@ fn genBinOp(
44164450
44174451 else => false,
44184452 };
4453 const needs_reg_dst = switch (tag) {
4454 .add,
4455 .addwrap,
4456 .sub,
4457 .subwrap,
4458 .mul,
4459 .div_float,
4460 .div_exact,
4461 .div_trunc,
4462 .div_floor,
4463 => lhs_ty.isRuntimeFloat(),
4464
4465 else => false,
4466 };
44194467
44204468 const lhs_lock: ?RegisterLock = switch (lhs) {
44214469 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
......@@ -4432,10 +4480,10 @@ fn genBinOp(
44324480 var flipped: bool = false;
44334481 const dst_mcv: MCValue = blk: {
44344482 if (maybe_inst) |inst| {
4435 if (lhs.isRegister() and self.reuseOperand(inst, lhs_air, 0, lhs)) {
4483 if ((!needs_reg_dst or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) {
44364484 break :blk lhs;
44374485 }
4438 if (is_commutative and rhs.isRegister() and self.reuseOperand(inst, rhs_air, 1, rhs)) {
4486 if (is_commutative and (!needs_reg_dst or rhs.isRegister()) and self.reuseOperand(inst, rhs_air, 1, rhs)) {
44394487 flipped = true;
44404488 break :blk rhs;
44414489 }
......@@ -4485,33 +4533,37 @@ fn genBinOp(
44854533
44864534 .div_float,
44874535 .div_exact,
4488 => try self.genBinOpMir(switch (lhs_ty.tag()) {
4489 .f32 => .divss,
4490 .f64 => .divsd,
4491 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
4492 }, lhs_ty, dst_mcv, src_mcv),
4493
44944536 .div_trunc,
44954537 .div_floor,
44964538 => {
44974539 try self.genBinOpMir(switch (lhs_ty.tag()) {
44984540 .f32 => .divss,
44994541 .f64 => .divsd,
4500 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
4542 else => return self.fail("TODO implement genBinOp for {s} {}", .{
4543 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
4544 }),
45014545 }, lhs_ty, dst_mcv, src_mcv);
4502 if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
4503 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
4504 const dst_alias = registerAlias(dst_mcv.register, abi_size);
4505 try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {
4506 .f32 => .roundss,
4507 .f64 => .roundsd,
4508 else => unreachable,
4509 }, dst_alias, dst_alias, Immediate.u(switch (tag) {
4510 .div_trunc => 0b1_0_11,
4511 .div_floor => 0b1_0_01,
4512 else => unreachable,
4513 }));
4514 } else return self.fail("TODO implement round without sse4_1", .{});
4546 switch (tag) {
4547 .div_float,
4548 .div_exact,
4549 => {},
4550 .div_trunc,
4551 .div_floor,
4552 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
4553 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
4554 const dst_alias = registerAlias(dst_mcv.register, abi_size);
4555 try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {
4556 .f32 => .roundss,
4557 .f64 => .roundsd,
4558 else => unreachable,
4559 }, dst_alias, dst_alias, Immediate.u(switch (tag) {
4560 .div_trunc => 0b1_0_11,
4561 .div_floor => 0b1_0_01,
4562 else => unreachable,
4563 }));
4564 } else return self.fail("TODO implement round without sse4_1", .{}),
4565 else => unreachable,
4566 }
45154567 },
45164568
45174569 .ptr_add,
......@@ -4568,7 +4620,13 @@ fn genBinOp(
45684620 };
45694621
45704622 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
4571 switch (dst_mcv) {
4623 const tmp_reg = switch (dst_mcv) {
4624 .register => |reg| reg,
4625 else => try self.copyToTmpRegister(lhs_ty, dst_mcv),
4626 };
4627 const tmp_lock = self.register_manager.lockReg(tmp_reg);
4628 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
4629 switch (mat_src_mcv) {
45724630 .none,
45734631 .undef,
45744632 .dead,
......@@ -4576,57 +4634,43 @@ fn genBinOp(
45764634 .immediate,
45774635 .eflags,
45784636 .register_overflow,
4579 .stack_offset,
45804637 .ptr_stack_offset,
4581 .memory,
4582 .linker_load,
45834638 => unreachable,
4584 .register => |dst_reg| switch (mat_src_mcv) {
4585 .none,
4586 .undef,
4587 .dead,
4588 .unreach,
4589 .immediate,
4590 .eflags,
4591 .register_overflow,
4592 .ptr_stack_offset,
4593 => unreachable,
4594 .register => |src_reg| try self.asmCmovccRegisterRegister(
4595 registerAlias(dst_reg, abi_size),
4596 registerAlias(src_reg, abi_size),
4597 cc,
4598 ),
4599 .stack_offset => |off| try self.asmCmovccRegisterMemory(
4600 registerAlias(dst_reg, abi_size),
4601 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4602 .base = .rbp,
4603 .disp = -off,
4604 }),
4605 cc,
4606 ),
4607 .memory, .linker_load => {
4608 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4609 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
4610 defer self.register_manager.unlockReg(addr_reg_lock);
4611
4612 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);
4613
4614 // To get the actual address of the value we want to modify we
4615 // we have to go through the GOT
4616 try self.asmRegisterMemory(
4617 .mov,
4618 addr_reg,
4619 Memory.sib(.qword, .{ .base = addr_reg }),
4620 );
4639 .register => |src_reg| try self.asmCmovccRegisterRegister(
4640 registerAlias(tmp_reg, abi_size),
4641 registerAlias(src_reg, abi_size),
4642 cc,
4643 ),
4644 .stack_offset => |off| try self.asmCmovccRegisterMemory(
4645 registerAlias(tmp_reg, abi_size),
4646 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4647 .base = .rbp,
4648 .disp = -off,
4649 }),
4650 cc,
4651 ),
4652 .memory, .linker_load => {
4653 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4654 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
4655 defer self.register_manager.unlockReg(addr_reg_lock);
4656 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv);
4657
4658 // To get the actual address of the value we want to modify we
4659 // we have to go through the GOT
4660 try self.asmRegisterMemory(
4661 .mov,
4662 addr_reg,
4663 Memory.sib(.qword, .{ .base = addr_reg }),
4664 );
46214665
4622 try self.asmCmovccRegisterMemory(
4623 registerAlias(dst_reg, abi_size),
4624 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
4625 cc,
4626 );
4627 },
4666 try self.asmCmovccRegisterMemory(
4667 registerAlias(tmp_reg, abi_size),
4668 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
4669 cc,
4670 );
46284671 },
46294672 }
4673 try self.setRegOrMem(lhs_ty, dst_mcv, .{ .register = tmp_reg });
46304674 },
46314675 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
46324676 .f32 => switch (tag) {
......@@ -4649,8 +4693,8 @@ fn genBinOp(
46494693 return dst_mcv;
46504694}
46514695
4652fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4653 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
4696fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4697 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
46544698 switch (dst_mcv) {
46554699 .none => unreachable,
46564700 .undef => unreachable,
......@@ -4667,12 +4711,12 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
46674711 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
46684712 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
46694713
4670 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
4671 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
4714 const reg = try self.copyToTmpRegister(ty, src_mcv);
4715 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
46724716 },
4673 .register => |src_reg| switch (dst_ty.zigTypeTag()) {
4717 .register => |src_reg| switch (ty.zigTypeTag()) {
46744718 .Float => {
4675 if (intrinsicsAllowed(self.target.*, dst_ty)) {
4719 if (intrinsicsAllowed(self.target.*, ty)) {
46764720 return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
46774721 }
46784722
......@@ -4685,7 +4729,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
46854729 ),
46864730 },
46874731 .immediate => |imm| {
4688 switch (self.regBitSize(dst_ty)) {
4732 switch (self.regBitSize(ty)) {
46894733 8, 16, 32 => {
46904734 try self.asmRegisterImmediate(
46914735 mir_tag,
......@@ -4704,7 +4748,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
47044748 try self.asmRegisterRegister(
47054749 mir_tag,
47064750 registerAlias(dst_reg, abi_size),
4707 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
4751 registerAlias(try self.copyToTmpRegister(ty, src_mcv), abi_size),
47084752 );
47094753 }
47104754 },
......@@ -4719,13 +4763,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
47194763 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
47204764 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
47214765
4722 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
4723 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
4766 const reg = try self.copyToTmpRegister(ty, src_mcv);
4767 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
47244768 },
47254769 .stack_offset => |off| {
4726 if (off > math.maxInt(i32)) {
4727 return self.fail("stack offset too large", .{});
4728 }
47294770 try self.asmRegisterMemory(
47304771 mir_tag,
47314772 registerAlias(dst_reg, abi_size),
......@@ -4734,76 +4775,155 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
47344775 },
47354776 }
47364777 },
4737 .ptr_stack_offset, .stack_offset => |off| {
4738 if (off > math.maxInt(i32)) {
4739 return self.fail("stack offset too large", .{});
4740 }
4741 if (abi_size > 8) {
4742 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
4743 }
4778 .ptr_stack_offset, .stack_offset => |dst_off| {
4779 const src: ?struct {
4780 limb_reg: Register,
4781 limb_lock: RegisterLock,
4782 addr_reg: Register,
4783 addr_lock: RegisterLock,
4784 } = switch (src_mcv) {
4785 else => null,
4786 .memory, .linker_load => addr: {
4787 const src_limb_reg = try self.register_manager.allocReg(null, gp);
4788 const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg);
4789 errdefer self.register_manager.unlockReg(src_limb_lock);
4790
4791 const src_addr_reg = try self.register_manager.allocReg(null, gp);
4792 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
4793 errdefer self.register_manager.unlockReg(src_addr_lock);
4794
4795 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv);
4796 // To get the actual address of the value we want to modify we
4797 // we have to go through the GOT
4798 try self.asmRegisterMemory(
4799 .mov,
4800 src_addr_reg,
4801 Memory.sib(.qword, .{ .base = src_addr_reg }),
4802 );
47444803
4745 switch (src_mcv) {
4746 .none => unreachable,
4747 .undef => unreachable,
4748 .dead, .unreach => unreachable,
4749 .register_overflow => unreachable,
4750 .register => |src_reg| {
4751 try self.asmMemoryRegister(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4752 .base = .rbp,
4753 .disp = -off,
4754 }), registerAlias(src_reg, abi_size));
4804 break :addr .{
4805 .addr_reg = src_addr_reg,
4806 .addr_lock = src_addr_lock,
4807 .limb_reg = src_limb_reg,
4808 .limb_lock = src_limb_lock,
4809 };
47554810 },
4756 .immediate => |imm| {
4757 switch (self.regBitSize(dst_ty)) {
4758 8, 16, 32 => {
4759 try self.asmMemoryImmediate(
4760 mir_tag,
4761 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4762 .base = .rbp,
4763 .disp = -off,
4764 }),
4765 if (math.cast(i32, @bitCast(i64, imm))) |small|
4766 Immediate.s(small)
4767 else
4768 Immediate.u(@intCast(u32, imm)),
4769 );
4770 },
4771 64 => {
4772 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4811 };
4812 defer if (src) |locks| {
4813 self.register_manager.unlockReg(locks.limb_lock);
4814 self.register_manager.unlockReg(locks.addr_lock);
4815 };
4816
4817 const ty_signedness =
4818 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
4819 const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) {
4820 .signed => Type.usize,
4821 .unsigned => Type.isize,
4822 };
4823 const limb_abi_size = @min(abi_size, 8);
4824 var off: i32 = 0;
4825 while (off < abi_size) : (off += 8) {
4826 const mir_limb_tag = switch (off) {
4827 0 => mir_tag,
4828 else => switch (mir_tag) {
4829 .add => .adc,
4830 .sub => .sbb,
4831 .@"or", .@"and", .xor => mir_tag,
4832 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
4833 @tagName(mir_tag),
4834 }),
4835 },
4836 };
4837 const dst_limb_mem = Memory.sib(
4838 Memory.PtrSize.fromSize(limb_abi_size),
4839 .{ .base = .rbp, .disp = off - dst_off },
4840 );
4841 switch (src_mcv) {
4842 .none => unreachable,
4843 .undef => unreachable,
4844 .dead, .unreach => unreachable,
4845 .register_overflow => unreachable,
4846 .register => |src_reg| {
4847 assert(off == 0);
4848 try self.asmMemoryRegister(
4849 mir_limb_tag,
4850 dst_limb_mem,
4851 registerAlias(src_reg, limb_abi_size),
4852 );
4853 },
4854 .immediate => |src_imm| {
4855 const imm = if (off == 0) src_imm else switch (ty_signedness) {
4856 .signed => @bitCast(u64, @bitCast(i64, src_imm) >> 63),
4857 .unsigned => 0,
4858 };
4859 switch (self.regBitSize(limb_ty)) {
4860 8, 16, 32 => {
47734861 try self.asmMemoryImmediate(
4774 mir_tag,
4775 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4776 .base = .rbp,
4777 .disp = -off,
4778 }),
4779 Immediate.s(small),
4780 );
4781 } else {
4782 try self.asmMemoryRegister(
4783 mir_tag,
4784 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4785 .base = .rbp,
4786 .disp = -off,
4787 }),
4788 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
4862 mir_limb_tag,
4863 dst_limb_mem,
4864 if (math.cast(i32, @bitCast(i64, imm))) |small|
4865 Immediate.s(small)
4866 else
4867 Immediate.u(@intCast(u32, imm)),
47894868 );
4790 }
4791 },
4792 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
4793 }
4794 },
4795 .memory,
4796 .stack_offset,
4797 .ptr_stack_offset,
4798 => {
4799 return self.fail("TODO implement x86 genBinOpMir source memory", .{});
4800 },
4801 .linker_load => {
4802 return self.fail("TODO implement x86 genBinOpMir source symbol at index in linker", .{});
4803 },
4804 .eflags => {
4805 return self.fail("TODO implement x86 genBinOpMir source eflags", .{});
4806 },
4869 },
4870 64 => {
4871 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4872 try self.asmMemoryImmediate(
4873 mir_limb_tag,
4874 dst_limb_mem,
4875 Immediate.s(small),
4876 );
4877 } else {
4878 try self.asmMemoryRegister(
4879 mir_limb_tag,
4880 dst_limb_mem,
4881 registerAlias(
4882 try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }),
4883 limb_abi_size,
4884 ),
4885 );
4886 }
4887 },
4888 else => unreachable,
4889 }
4890 },
4891 .memory, .linker_load => {
4892 try self.asmRegisterMemory(
4893 .mov,
4894 registerAlias(src.?.limb_reg, limb_abi_size),
4895 Memory.sib(
4896 Memory.PtrSize.fromSize(limb_abi_size),
4897 .{ .base = src.?.addr_reg, .disp = off },
4898 ),
4899 );
4900 try self.asmMemoryRegister(
4901 mir_limb_tag,
4902 dst_limb_mem,
4903 registerAlias(src.?.limb_reg, limb_abi_size),
4904 );
4905 },
4906 .stack_offset, .ptr_stack_offset, .eflags => {
4907 const src_limb_reg = try self.copyToTmpRegister(limb_ty, switch (src_mcv) {
4908 .stack_offset => |src_off| .{ .stack_offset = src_off - off },
4909 .ptr_stack_offset,
4910 .eflags,
4911 => off: {
4912 assert(off == 0);
4913 break :off src_mcv;
4914 },
4915 else => unreachable,
4916 });
4917 const src_limb_lock = self.register_manager.lockReg(src_limb_reg);
4918 defer if (src_limb_lock) |lock| self.register_manager.unlockReg(lock);
4919
4920 try self.asmMemoryRegister(
4921 mir_limb_tag,
4922 dst_limb_mem,
4923 registerAlias(src_limb_reg, limb_abi_size),
4924 );
4925 },
4926 }
48074927 }
48084928 },
48094929 .memory => {
......@@ -4827,6 +4947,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
48274947 .ptr_stack_offset => unreachable,
48284948 .register_overflow => unreachable,
48294949 .register => |dst_reg| {
4950 const dst_alias = registerAlias(dst_reg, abi_size);
4951 const dst_lock = self.register_manager.lockReg(dst_reg);
4952 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
4953
48304954 switch (src_mcv) {
48314955 .none => unreachable,
48324956 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
......@@ -4835,21 +4959,18 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
48354959 .register_overflow => unreachable,
48364960 .register => |src_reg| try self.asmRegisterRegister(
48374961 .imul,
4838 registerAlias(dst_reg, abi_size),
4962 dst_alias,
48394963 registerAlias(src_reg, abi_size),
48404964 ),
48414965 .immediate => |imm| {
4842 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
4843 // TODO take into account the type's ABI size when selecting the register alias
4844 // register, immediate
4966 if (std.math.cast(i32, imm)) |small| {
48454967 try self.asmRegisterRegisterImmediate(
48464968 .imul,
4847 dst_reg.to32(),
4848 dst_reg.to32(),
4849 Immediate.u(@intCast(u32, imm)),
4969 dst_alias,
4970 dst_alias,
4971 Immediate.s(small),
48504972 );
48514973 } else {
4852 // TODO verify we don't spill and assign to the same register as dst_mcv
48534974 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
48544975 return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
48554976 }
......@@ -4857,7 +4978,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
48574978 .stack_offset => |off| {
48584979 try self.asmRegisterMemory(
48594980 .imul,
4860 registerAlias(dst_reg, abi_size),
4981 dst_alias,
48614982 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
48624983 );
48634984 },
......@@ -5344,6 +5465,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
53445465 }
53455466
53465467 const ty = self.air.typeOf(bin_op.lhs);
5468 const abi_size = ty.abiSize(self.target.*);
5469 if (abi_size > 8) return self.fail("TODO implement cmp for large values", .{});
5470
53475471 const signedness: std.builtin.Signedness = blk: {
53485472 // For non-int types, we treat the values as unsigned
53495473 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
......@@ -6655,10 +6779,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
66556779 }
66566780 },
66576781 .register => |reg| {
6658 if (stack_offset > math.maxInt(i32)) {
6659 return self.fail("stack offset too large", .{});
6660 }
6661
66626782 const base_reg = opts.dest_stack_base orelse .rbp;
66636783
66646784 switch (ty.zigTypeTag()) {
......@@ -6893,13 +7013,11 @@ fn genInlineMemset(
68937013
68947014fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
68957015 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
7016 if (abi_size > 8) return self.fail("genSetReg called with a value larger than one register", .{});
68967017 switch (mcv) {
68977018 .dead => unreachable,
68987019 .register_overflow => unreachable,
68997020 .ptr_stack_offset => |off| {
6900 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
6901 return self.fail("stack offset too large", .{});
6902 }
69037021 try self.asmRegisterMemory(
69047022 .lea,
69057023 registerAlias(reg, abi_size),
......@@ -7060,16 +7178,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
70607178 if (reg.to64() == .rax) {
70617179 // If this is RAX, we can use a direct load.
70627180 // Otherwise, we need to load the address, then indirectly load the value.
7063 var moffs: Mir.MemoryMoffs = .{
7064 .seg = @enumToInt(Register.ds),
7065 .msb = undefined,
7066 .lsb = undefined,
7067 };
7068 moffs.encodeOffset(x);
70697181 _ = try self.addInst(.{
70707182 .tag = .mov_moffs,
70717183 .ops = .rax_moffs,
7072 .data = .{ .payload = try self.addExtra(moffs) },
7184 .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, x)) },
70737185 });
70747186 } else {
70757187 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
......@@ -7084,10 +7196,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
70847196 },
70857197 },
70867198 .stack_offset => |off| {
7087 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
7088 return self.fail("stack offset too large", .{});
7089 }
7090
70917199 switch (ty.zigTypeTag()) {
70927200 .Int => switch (ty.intInfo(self.target.*).signedness) {
70937201 .signed => {
......@@ -7151,7 +7259,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
71517259
71527260fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
71537261 const un_op = self.air.instructions.items(.data)[inst].un_op;
7154 const result = try self.resolveInst(un_op);
7262 const result = if (self.liveness.isUnused(inst)) .dead else result: {
7263 const src_mcv = try self.resolveInst(un_op);
7264 if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
7265
7266 const dst_mcv = try self.allocRegOrMem(inst, true);
7267 const dst_ty = self.air.typeOfIndex(inst);
7268 try self.setRegOrMem(dst_ty, dst_mcv, src_mcv);
7269 break :result dst_mcv;
7270 };
71557271 return self.finishAir(inst, result, .{ un_op, .none, .none });
71567272}
71577273
src/arch/x86_64/Emit.zig+168-737
......@@ -1,40 +1,8 @@
1//! This file contains the functionality for lowering x86_64 MIR into
2//! machine code
1//! This file contains the functionality for emitting x86_64 MIR as machine code
32
4const Emit = @This();
5
6const std = @import("std");
7const assert = std.debug.assert;
8const bits = @import("bits.zig");
9const abi = @import("abi.zig");
10const encoder = @import("encoder.zig");
11const link = @import("../../link.zig");
12const log = std.log.scoped(.codegen);
13const math = std.math;
14const mem = std.mem;
15const testing = std.testing;
16
17const Air = @import("../../Air.zig");
18const Allocator = mem.Allocator;
19const CodeGen = @import("CodeGen.zig");
20const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
21const Encoder = bits.Encoder;
22const ErrorMsg = Module.ErrorMsg;
23const Immediate = bits.Immediate;
24const Instruction = encoder.Instruction;
25const MCValue = @import("CodeGen.zig").MCValue;
26const Memory = bits.Memory;
27const Mir = @import("Mir.zig");
28const Module = @import("../../Module.zig");
29const Register = bits.Register;
30const Type = @import("../../type.zig").Type;
31
32mir: Mir,
3lower: Lower,
334bin_file: *link.File,
345debug_output: DebugInfoOutput,
35target: *const std.Target,
36err_msg: ?*ErrorMsg = null,
37src_loc: Module.SrcLoc,
386code: *std.ArrayList(u8),
397
408prev_di_line: u32,
......@@ -45,166 +13,176 @@ prev_di_pc: usize,
4513code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{},
4614relocs: std.ArrayListUnmanaged(Reloc) = .{},
4715
48const InnerError = error{
49 OutOfMemory,
50 EmitFail,
51 InvalidInstruction,
52 CannotEncode,
53};
54
55const Reloc = struct {
56 /// Offset of the instruction.
57 source: usize,
58 /// Target of the relocation.
59 target: Mir.Inst.Index,
60 /// Offset of the relocation within the instruction.
61 offset: usize,
62 /// Length of the instruction.
63 length: u5,
64};
65
66pub fn lowerMir(emit: *Emit) InnerError!void {
67 const mir_tags = emit.mir.instructions.items(.tag);
68
69 for (mir_tags, 0..) |tag, index| {
70 const inst = @intCast(u32, index);
71 try emit.code_offset_mapping.putNoClobber(emit.bin_file.allocator, inst, emit.code.items.len);
72 switch (tag) {
73 .adc,
74 .add,
75 .@"and",
76 .bsf,
77 .bsr,
78 .bswap,
79 .bt,
80 .btc,
81 .btr,
82 .bts,
83 .call,
84 .cbw,
85 .cwde,
86 .cdqe,
87 .cwd,
88 .cdq,
89 .cqo,
90 .cmp,
91 .cmpxchg,
92 .div,
93 .fisttp,
94 .fld,
95 .idiv,
96 .imul,
97 .int3,
98 .jmp,
99 .lea,
100 .lfence,
101 .lzcnt,
102 .mfence,
103 .mov,
104 .movbe,
105 .movzx,
106 .mul,
107 .neg,
108 .nop,
109 .not,
110 .@"or",
111 .pop,
112 .popcnt,
113 .push,
114 .rcl,
115 .rcr,
116 .ret,
117 .rol,
118 .ror,
119 .sal,
120 .sar,
121 .sbb,
122 .sfence,
123 .shl,
124 .shld,
125 .shr,
126 .shrd,
127 .sub,
128 .syscall,
129 .@"test",
130 .tzcnt,
131 .ud2,
132 .xadd,
133 .xchg,
134 .xor,
135
136 .addss,
137 .cmpss,
138 .divss,
139 .maxss,
140 .minss,
141 .movss,
142 .mulss,
143 .roundss,
144 .subss,
145 .ucomiss,
146 .addsd,
147 .cmpsd,
148 .divsd,
149 .maxsd,
150 .minsd,
151 .movsd,
152 .mulsd,
153 .roundsd,
154 .subsd,
155 .ucomisd,
156 => try emit.mirEncodeGeneric(tag, inst),
157
158 .cmps,
159 .lods,
160 .movs,
161 .scas,
162 .stos,
163 => try emit.mirString(tag, inst),
164
165 .cmpxchgb => try emit.mirCmpxchgBytes(inst),
166
167 .jmp_reloc => try emit.mirJmpReloc(inst),
168
169 .call_extern => try emit.mirCallExtern(inst),
170
171 .lea_linker => try emit.mirLeaLinker(inst),
172
173 .mov_moffs => try emit.mirMovMoffs(inst),
174
175 .movsx => try emit.mirMovsx(inst),
176 .cmovcc => try emit.mirCmovcc(inst),
177 .setcc => try emit.mirSetcc(inst),
178 .jcc => try emit.mirJcc(inst),
16pub const Error = Lower.Error || error{EmitFail};
17
18pub fn emitMir(emit: *Emit) Error!void {
19 for (0..emit.lower.mir.instructions.len) |i| {
20 const index = @intCast(Mir.Inst.Index, i);
21 const inst = emit.lower.mir.instructions.get(index);
22
23 const start_offset = @intCast(u32, emit.code.items.len);
24 try emit.code_offset_mapping.putNoClobber(emit.lower.allocator, index, start_offset);
25 for (try emit.lower.lowerMir(inst)) |lower_inst| try lower_inst.encode(emit.code.writer());
26 const end_offset = @intCast(u32, emit.code.items.len);
27
28 switch (inst.tag) {
29 else => {},
30
31 .jmp_reloc => try emit.relocs.append(emit.lower.allocator, .{
32 .source = start_offset,
33 .target = inst.data.inst,
34 .offset = end_offset - 4,
35 .length = 5,
36 }),
37
38 .call_extern => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
39 // Add relocation to the decl.
40 const atom_index = macho_file.getAtomIndexForSymbol(
41 .{ .sym_index = inst.data.relocation.atom_index, .file = null },
42 ).?;
43 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);
44 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
45 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
46 .target = target,
47 .offset = end_offset - 4,
48 .addend = 0,
49 .pcrel = true,
50 .length = 2,
51 });
52 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
53 // Add relocation to the decl.
54 const atom_index = coff_file.getAtomIndexForSymbol(
55 .{ .sym_index = inst.data.relocation.atom_index, .file = null },
56 ).?;
57 const target = coff_file.getGlobalByIndex(inst.data.relocation.sym_index);
58 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
59 .type = .direct,
60 .target = target,
61 .offset = end_offset - 4,
62 .addend = 0,
63 .pcrel = true,
64 .length = 2,
65 });
66 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
67
68 .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
69 const metadata =
70 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
71 const reloc_type = switch (inst.ops) {
72 .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
73 .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
74 else => unreachable,
75 };
76 const atom_index = macho_file.getAtomIndexForSymbol(.{
77 .sym_index = metadata.atom_index,
78 .file = null,
79 }).?;
80 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
81 .type = reloc_type,
82 .target = .{ .sym_index = metadata.sym_index, .file = null },
83 .offset = @intCast(u32, end_offset - 4),
84 .addend = 0,
85 .pcrel = true,
86 .length = 2,
87 });
88 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
89 const metadata =
90 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
91 const atom_index = coff_file.getAtomIndexForSymbol(.{
92 .sym_index = metadata.atom_index,
93 .file = null,
94 }).?;
95 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
96 .type = switch (inst.ops) {
97 .got_reloc => .got,
98 .direct_reloc => .direct,
99 .import_reloc => .import,
100 else => unreachable,
101 },
102 .target = switch (inst.ops) {
103 .got_reloc,
104 .direct_reloc,
105 => .{ .sym_index = metadata.sym_index, .file = null },
106 .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index),
107 else => unreachable,
108 },
109 .offset = @intCast(u32, end_offset - 4),
110 .addend = 0,
111 .pcrel = true,
112 .length = 2,
113 });
114 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
115
116 .jcc => try emit.relocs.append(emit.lower.allocator, .{
117 .source = start_offset,
118 .target = inst.data.inst_cc.inst,
119 .offset = end_offset - 4,
120 .length = 6,
121 }),
179122
180 .dbg_line => try emit.mirDbgLine(inst),
181 .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
182 .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
123 .dbg_line => {
124 const dbg_line_column =
125 emit.lower.mir.extraData(Mir.DbgLineColumn, inst.data.payload).data;
126 try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column);
127 },
183128
184 .push_regs => try emit.mirPushPopRegisterList(.push, inst),
185 .pop_regs => try emit.mirPushPopRegisterList(.pop, inst),
129 .dbg_prologue_end => {
130 switch (emit.debug_output) {
131 .dwarf => |dw| {
132 try dw.setPrologueEnd();
133 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
134 emit.prev_di_line, emit.prev_di_column,
135 });
136 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
137 },
138 .plan9 => {},
139 .none => {},
140 }
141 },
186142
187 .dead => {},
143 .dbg_epilogue_begin => {
144 switch (emit.debug_output) {
145 .dwarf => |dw| {
146 try dw.setEpilogueBegin();
147 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
148 emit.prev_di_line, emit.prev_di_column,
149 });
150 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
151 },
152 .plan9 => {},
153 .none => {},
154 }
155 },
188156 }
189157 }
190
191158 try emit.fixupRelocs();
192159}
193160
194161pub fn deinit(emit: *Emit) void {
195 emit.relocs.deinit(emit.bin_file.allocator);
196 emit.code_offset_mapping.deinit(emit.bin_file.allocator);
162 emit.relocs.deinit(emit.lower.allocator);
163 emit.code_offset_mapping.deinit(emit.lower.allocator);
197164 emit.* = undefined;
198165}
199166
200fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
201 @setCold(true);
202 assert(emit.err_msg == null);
203 emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args);
204 return error.EmitFail;
167fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
168 return switch (emit.lower.fail(format, args)) {
169 error.LowerFail => error.EmitFail,
170 else => |e| e,
171 };
205172}
206173
207fn fixupRelocs(emit: *Emit) InnerError!void {
174const Reloc = struct {
175 /// Offset of the instruction.
176 source: usize,
177 /// Target of the relocation.
178 target: Mir.Inst.Index,
179 /// Offset of the relocation within the instruction.
180 offset: usize,
181 /// Length of the instruction.
182 length: u5,
183};
184
185fn fixupRelocs(emit: *Emit) Error!void {
208186 // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
209187 // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
210188 // possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
......@@ -217,532 +195,7 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
217195 }
218196}
219197
220fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: Instruction.Init) InnerError!void {
221 const inst = try Instruction.new(mnemonic, ops);
222 return inst.encode(emit.code.writer());
223}
224
225fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
226 const mnemonic = inline for (@typeInfo(Instruction.Mnemonic).Enum.fields) |field| {
227 if (mem.eql(u8, field.name, @tagName(tag))) break @field(Instruction.Mnemonic, field.name);
228 } else unreachable;
229
230 const ops = emit.mir.instructions.items(.ops)[inst];
231 const data = emit.mir.instructions.items(.data)[inst];
232
233 const prefix: Instruction.Prefix = switch (ops) {
234 .lock_m_sib,
235 .lock_m_rip,
236 .lock_mi_sib_u,
237 .lock_mi_rip_u,
238 .lock_mi_sib_s,
239 .lock_mi_rip_s,
240 .lock_mr_sib,
241 .lock_mr_rip,
242 .lock_moffs_rax,
243 => .lock,
244 else => .none,
245 };
246
247 var op1: Instruction.Operand = .none;
248 var op2: Instruction.Operand = .none;
249 var op3: Instruction.Operand = .none;
250 var op4: Instruction.Operand = .none;
251
252 switch (ops) {
253 .none => {},
254 .i_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.i)) },
255 .i_u => op1 = .{ .imm = Immediate.u(data.i) },
256 .r => op1 = .{ .reg = data.r },
257 .rr => {
258 op1 = .{ .reg = data.rr.r1 };
259 op2 = .{ .reg = data.rr.r2 };
260 },
261 .rrr => {
262 op1 = .{ .reg = data.rrr.r1 };
263 op2 = .{ .reg = data.rrr.r2 };
264 op3 = .{ .reg = data.rrr.r3 };
265 },
266 .ri_s, .ri_u => {
267 const imm = switch (ops) {
268 .ri_s => Immediate.s(@bitCast(i32, data.ri.i)),
269 .ri_u => Immediate.u(data.ri.i),
270 else => unreachable,
271 };
272 op1 = .{ .reg = data.ri.r };
273 op2 = .{ .imm = imm };
274 },
275 .ri64 => {
276 const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
277 op1 = .{ .reg = data.rx.r };
278 op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
279 },
280 .rri_s, .rri_u => {
281 const imm = switch (ops) {
282 .rri_s => Immediate.s(@bitCast(i32, data.rri.i)),
283 .rri_u => Immediate.u(data.rri.i),
284 else => unreachable,
285 };
286 op1 = .{ .reg = data.rri.r1 };
287 op2 = .{ .reg = data.rri.r2 };
288 op3 = .{ .imm = imm };
289 },
290 .m_sib, .lock_m_sib => {
291 const msib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
292 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
293 },
294 .m_rip, .lock_m_rip => {
295 const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
296 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
297 },
298 .mi_sib_s, .mi_sib_u, .lock_mi_sib_s, .lock_mi_sib_u => {
299 const msib = emit.mir.extraData(Mir.MemorySib, data.ix.payload).data;
300 const imm = switch (ops) {
301 .mi_sib_s, .lock_mi_sib_s => Immediate.s(@bitCast(i32, data.ix.i)),
302 .mi_sib_u, .lock_mi_sib_u => Immediate.u(data.ix.i),
303 else => unreachable,
304 };
305 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
306 op2 = .{ .imm = imm };
307 },
308 .mi_rip_u, .mi_rip_s, .lock_mi_rip_u, .lock_mi_rip_s => {
309 const mrip = emit.mir.extraData(Mir.MemoryRip, data.ix.payload).data;
310 const imm = switch (ops) {
311 .mi_rip_s, .lock_mi_rip_s => Immediate.s(@bitCast(i32, data.ix.i)),
312 .mi_rip_u, .lock_mi_rip_u => Immediate.u(data.ix.i),
313 else => unreachable,
314 };
315 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
316 op2 = .{ .imm = imm };
317 },
318 .rm_sib, .mr_sib, .lock_mr_sib => {
319 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
320 const op_r = .{ .reg = data.rx.r };
321 const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
322 switch (ops) {
323 .rm_sib => {
324 op1 = op_r;
325 op2 = op_m;
326 },
327 .mr_sib, .lock_mr_sib => {
328 op1 = op_m;
329 op2 = op_r;
330 },
331 else => unreachable,
332 }
333 },
334 .rm_rip, .mr_rip, .lock_mr_rip => {
335 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
336 const op_r = .{ .reg = data.rx.r };
337 const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
338 switch (ops) {
339 .rm_rip => {
340 op1 = op_r;
341 op2 = op_m;
342 },
343 .mr_rip, .lock_mr_rip => {
344 op1 = op_m;
345 op2 = op_r;
346 },
347 else => unreachable,
348 }
349 },
350 .mrr_sib => {
351 const msib = emit.mir.extraData(Mir.MemorySib, data.rrx.payload).data;
352 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
353 op2 = .{ .reg = data.rrx.r1 };
354 op2 = .{ .reg = data.rrx.r2 };
355 },
356 .mrr_rip => {
357 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rrx.payload).data;
358 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
359 op2 = .{ .reg = data.rrx.r1 };
360 op2 = .{ .reg = data.rrx.r2 };
361 },
362 .mri_sib => {
363 const msib = emit.mir.extraData(Mir.MemorySib, data.rix.payload).data;
364 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
365 op2 = .{ .reg = data.rix.r };
366 op3 = .{ .imm = Immediate.u(data.rix.i) };
367 },
368 .mri_rip => {
369 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rix.payload).data;
370 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
371 op2 = .{ .reg = data.rix.r };
372 op3 = .{ .imm = Immediate.u(data.rix.i) };
373 },
374 else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{
375 @tagName(mnemonic),
376 @tagName(ops),
377 }),
378 }
379
380 return emit.encode(mnemonic, .{
381 .prefix = prefix,
382 .op1 = op1,
383 .op2 = op2,
384 .op3 = op3,
385 .op4 = op4,
386 });
387}
388
389fn mirString(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
390 const ops = emit.mir.instructions.items(.ops)[inst];
391 switch (ops) {
392 .string => {
393 const data = emit.mir.instructions.items(.data)[inst].string;
394 const mnemonic = switch (tag) {
395 inline .cmps, .lods, .movs, .scas, .stos => |comptime_tag| switch (data.width) {
396 inline else => |comptime_width| @field(
397 Instruction.Mnemonic,
398 @tagName(comptime_tag) ++ @tagName(comptime_width),
399 ),
400 },
401 else => unreachable,
402 };
403 return emit.encode(mnemonic, .{ .prefix = switch (data.repeat) {
404 inline else => |comptime_repeat| @field(Instruction.Prefix, @tagName(comptime_repeat)),
405 } });
406 },
407 else => unreachable,
408 }
409}
410
411fn mirCmpxchgBytes(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
412 const ops = emit.mir.instructions.items(.ops)[inst];
413 const data = emit.mir.instructions.items(.data)[inst];
414
415 var op1: Instruction.Operand = .none;
416 switch (ops) {
417 .m_sib, .lock_m_sib => {
418 const sib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
419 op1 = .{ .mem = Mir.MemorySib.decode(sib) };
420 },
421 .m_rip, .lock_m_rip => {
422 const rip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
423 op1 = .{ .mem = Mir.MemoryRip.decode(rip) };
424 },
425 else => unreachable,
426 }
427
428 const mnemonic: Instruction.Mnemonic = switch (op1.mem.bitSize()) {
429 64 => .cmpxchg8b,
430 128 => .cmpxchg16b,
431 else => unreachable,
432 };
433
434 return emit.encode(mnemonic, .{
435 .prefix = switch (ops) {
436 .m_sib, .m_rip => .none,
437 .lock_m_sib, .lock_m_rip => .lock,
438 else => unreachable,
439 },
440 .op1 = op1,
441 });
442}
443
444fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
445 const ops = emit.mir.instructions.items(.ops)[inst];
446 const payload = emit.mir.instructions.items(.data)[inst].payload;
447 const moffs = emit.mir.extraData(Mir.MemoryMoffs, payload).data;
448 const seg = @intToEnum(Register, moffs.seg);
449 const offset = moffs.decodeOffset();
450 switch (ops) {
451 .rax_moffs => {
452 try emit.encode(.mov, .{
453 .op1 = .{ .reg = .rax },
454 .op2 = .{ .mem = Memory.moffs(seg, offset) },
455 });
456 },
457 .moffs_rax, .lock_moffs_rax => {
458 try emit.encode(.mov, .{
459 .prefix = switch (ops) {
460 .moffs_rax => .none,
461 .lock_moffs_rax => .lock,
462 else => unreachable,
463 },
464 .op1 = .{ .mem = Memory.moffs(seg, offset) },
465 .op2 = .{ .reg = .rax },
466 });
467 },
468 else => unreachable,
469 }
470}
471
472fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
473 const ops = emit.mir.instructions.items(.ops)[inst];
474 const data = emit.mir.instructions.items(.data)[inst];
475
476 var op1: Instruction.Operand = .none;
477 var op2: Instruction.Operand = .none;
478 switch (ops) {
479 .rr => {
480 op1 = .{ .reg = data.rr.r1 };
481 op2 = .{ .reg = data.rr.r2 };
482 },
483 .rm_sib => {
484 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
485 op1 = .{ .reg = data.rx.r };
486 op2 = .{ .mem = Mir.MemorySib.decode(msib) };
487 },
488 .rm_rip => {
489 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
490 op1 = .{ .reg = data.rx.r };
491 op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };
492 },
493 else => unreachable, // TODO
494 }
495
496 const mnemonic: Instruction.Mnemonic = switch (op1.bitSize()) {
497 32, 64 => if (op2.bitSize() == 32) .movsxd else .movsx,
498 else => .movsx,
499 };
500
501 return emit.encode(mnemonic, .{
502 .op1 = op1,
503 .op2 = op2,
504 });
505}
506
507fn mnemonicFromConditionCode(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
508 return switch (cc) {
509 inline else => |comptime_cc| @field(Instruction.Mnemonic, basename ++ @tagName(comptime_cc)),
510 };
511}
512
513fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
514 const ops = emit.mir.instructions.items(.ops)[inst];
515 switch (ops) {
516 .rr_cc => {
517 const data = emit.mir.instructions.items(.data)[inst].rr_cc;
518 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
519 return emit.encode(mnemonic, .{
520 .op1 = .{ .reg = data.r1 },
521 .op2 = .{ .reg = data.r2 },
522 });
523 },
524 .rm_sib_cc => {
525 const data = emit.mir.instructions.items(.data)[inst].rx_cc;
526 const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
527 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
528 return emit.encode(mnemonic, .{
529 .op1 = .{ .reg = data.r },
530 .op2 = .{ .mem = Mir.MemorySib.decode(extra) },
531 });
532 },
533 .rm_rip_cc => {
534 const data = emit.mir.instructions.items(.data)[inst].rx_cc;
535 const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
536 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
537 return emit.encode(mnemonic, .{
538 .op1 = .{ .reg = data.r },
539 .op2 = .{ .mem = Mir.MemoryRip.decode(extra) },
540 });
541 },
542 else => unreachable,
543 }
544}
545
546fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
547 const ops = emit.mir.instructions.items(.ops)[inst];
548 switch (ops) {
549 .r_cc => {
550 const data = emit.mir.instructions.items(.data)[inst].r_cc;
551 const mnemonic = mnemonicFromConditionCode("set", data.cc);
552 return emit.encode(mnemonic, .{
553 .op1 = .{ .reg = data.r },
554 });
555 },
556 .m_sib_cc => {
557 const data = emit.mir.instructions.items(.data)[inst].x_cc;
558 const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
559 const mnemonic = mnemonicFromConditionCode("set", data.cc);
560 return emit.encode(mnemonic, .{
561 .op1 = .{ .mem = Mir.MemorySib.decode(extra) },
562 });
563 },
564 .m_rip_cc => {
565 const data = emit.mir.instructions.items(.data)[inst].x_cc;
566 const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
567 const mnemonic = mnemonicFromConditionCode("set", data.cc);
568 return emit.encode(mnemonic, .{
569 .op1 = .{ .mem = Mir.MemoryRip.decode(extra) },
570 });
571 },
572 else => unreachable, // TODO
573 }
574}
575
576fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
577 const ops = emit.mir.instructions.items(.ops)[inst];
578 switch (ops) {
579 .inst_cc => {
580 const data = emit.mir.instructions.items(.data)[inst].inst_cc;
581 const mnemonic = mnemonicFromConditionCode("j", data.cc);
582 const source = emit.code.items.len;
583 try emit.encode(mnemonic, .{
584 .op1 = .{ .imm = Immediate.s(0) },
585 });
586 try emit.relocs.append(emit.bin_file.allocator, .{
587 .source = source,
588 .target = data.inst,
589 .offset = emit.code.items.len - 4,
590 .length = 6,
591 });
592 },
593 else => unreachable, // TODO
594 }
595}
596
597fn mirJmpReloc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
598 const target = emit.mir.instructions.items(.data)[inst].inst;
599 const source = emit.code.items.len;
600 try emit.encode(.jmp, .{
601 .op1 = .{ .imm = Immediate.s(0) },
602 });
603 try emit.relocs.append(emit.bin_file.allocator, .{
604 .source = source,
605 .target = target,
606 .offset = emit.code.items.len - 4,
607 .length = 5,
608 });
609}
610
611fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
612 const relocation = emit.mir.instructions.items(.data)[inst].relocation;
613
614 const offset = blk: {
615 try emit.encode(.call, .{
616 .op1 = .{ .imm = Immediate.s(0) },
617 });
618 break :blk @intCast(u32, emit.code.items.len) - 4;
619 };
620
621 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
622 // Add relocation to the decl.
623 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
624 const target = macho_file.getGlobalByIndex(relocation.sym_index);
625 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
626 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
627 .target = target,
628 .offset = offset,
629 .addend = 0,
630 .pcrel = true,
631 .length = 2,
632 });
633 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
634 // Add relocation to the decl.
635 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
636 const target = coff_file.getGlobalByIndex(relocation.sym_index);
637 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
638 .type = .direct,
639 .target = target,
640 .offset = offset,
641 .addend = 0,
642 .pcrel = true,
643 .length = 2,
644 });
645 } else {
646 return emit.fail("TODO implement call_extern for linking backends different than MachO and COFF", .{});
647 }
648}
649
650fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
651 const payload = emit.mir.instructions.items(.data)[inst].payload;
652 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;
653 const base = @intToEnum(Register, save_reg_list.base_reg);
654 var disp: i32 = -@intCast(i32, save_reg_list.stack_end);
655 const reg_list = Mir.RegisterList.fromInt(save_reg_list.register_list);
656 const callee_preserved_regs = abi.getCalleePreservedRegs(emit.target.*);
657 for (callee_preserved_regs) |reg| {
658 if (reg_list.isSet(callee_preserved_regs, reg)) {
659 const op1: Instruction.Operand = .{ .mem = Memory.sib(.qword, .{
660 .base = base,
661 .disp = disp,
662 }) };
663 const op2: Instruction.Operand = .{ .reg = reg };
664 switch (tag) {
665 .push => try emit.encode(.mov, .{
666 .op1 = op1,
667 .op2 = op2,
668 }),
669 .pop => try emit.encode(.mov, .{
670 .op1 = op2,
671 .op2 = op1,
672 }),
673 else => unreachable,
674 }
675 disp += 8;
676 }
677 }
678}
679
680fn mirLeaLinker(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
681 const ops = emit.mir.instructions.items(.ops)[inst];
682 const payload = emit.mir.instructions.items(.data)[inst].payload;
683 const metadata = emit.mir.extraData(Mir.LeaRegisterReloc, payload).data;
684 const reg = @intToEnum(Register, metadata.reg);
685
686 try emit.encode(.lea, .{
687 .op1 = .{ .reg = reg },
688 .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
689 });
690
691 const end_offset = emit.code.items.len;
692
693 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
694 const reloc_type = switch (ops) {
695 .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
696 .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
697 else => unreachable,
698 };
699 const atom_index = macho_file.getAtomIndexForSymbol(.{
700 .sym_index = metadata.atom_index,
701 .file = null,
702 }).?;
703 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
704 .type = reloc_type,
705 .target = .{ .sym_index = metadata.sym_index, .file = null },
706 .offset = @intCast(u32, end_offset - 4),
707 .addend = 0,
708 .pcrel = true,
709 .length = 2,
710 });
711 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
712 const atom_index = coff_file.getAtomIndexForSymbol(.{
713 .sym_index = metadata.atom_index,
714 .file = null,
715 }).?;
716 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
717 .type = switch (ops) {
718 .got_reloc => .got,
719 .direct_reloc => .direct,
720 .import_reloc => .import,
721 else => unreachable,
722 },
723 .target = switch (ops) {
724 .got_reloc, .direct_reloc => .{ .sym_index = metadata.sym_index, .file = null },
725 .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index),
726 else => unreachable,
727 },
728 .offset = @intCast(u32, end_offset - 4),
729 .addend = 0,
730 .pcrel = true,
731 .length = 2,
732 });
733 } else {
734 return emit.fail("TODO implement lea reg, [rip + reloc] for linking backends different than MachO", .{});
735 }
736}
737
738fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
739 const payload = emit.mir.instructions.items(.data)[inst].payload;
740 const dbg_line_column = emit.mir.extraData(Mir.DbgLineColumn, payload).data;
741 log.debug("mirDbgLine", .{});
742 try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column);
743}
744
745fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
198fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
746199 const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line);
747200 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
748201 log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
......@@ -756,7 +209,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
756209 .plan9 => |dbg_out| {
757210 if (delta_pc <= 0) return; // only do this when the pc changes
758211 // we have already checked the target in the linker to make sure it is compatable
759 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.target.cpu.arch) catch unreachable;
212 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.lower.target.cpu.arch) catch unreachable;
760213
761214 // increasing the line number
762215 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
......@@ -792,34 +245,12 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
792245 }
793246}
794247
795fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
796 _ = inst;
797 switch (emit.debug_output) {
798 .dwarf => |dw| {
799 try dw.setPrologueEnd();
800 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
801 emit.prev_di_line,
802 emit.prev_di_column,
803 });
804 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
805 },
806 .plan9 => {},
807 .none => {},
808 }
809}
248const link = @import("../../link.zig");
249const log = std.log.scoped(.emit);
250const mem = std.mem;
251const std = @import("std");
810252
811fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
812 _ = inst;
813 switch (emit.debug_output) {
814 .dwarf => |dw| {
815 try dw.setEpilogueBegin();
816 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
817 emit.prev_di_line,
818 emit.prev_di_column,
819 });
820 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
821 },
822 .plan9 => {},
823 .none => {},
824 }
825}
253const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
254const Emit = @This();
255const Lower = @import("Lower.zig");
256const Mir = @import("Mir.zig");
src/arch/x86_64/Encoding.zig+137-157
......@@ -7,30 +7,32 @@ const math = std.math;
77const bits = @import("bits.zig");
88const encoder = @import("encoder.zig");
99const Instruction = encoder.Instruction;
10const Operand = Instruction.Operand;
11const Prefix = Instruction.Prefix;
1012const Register = bits.Register;
1113const Rex = encoder.Rex;
1214const LegacyPrefixes = encoder.LegacyPrefixes;
1315
14const table = @import("encodings.zig").table;
15
1616mnemonic: Mnemonic,
17op_en: OpEn,
18op1: Op,
19op2: Op,
20op3: Op,
21op4: Op,
22opc_len: u3,
23opc: [7]u8,
24modrm_ext: u3,
25mode: Mode,
26
27pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding {
28 const input_op1 = Op.fromOperand(args.op1);
29 const input_op2 = Op.fromOperand(args.op2);
30 const input_op3 = Op.fromOperand(args.op3);
31 const input_op4 = Op.fromOperand(args.op4);
32
33 const ops = &[_]Instruction.Operand{ args.op1, args.op2, args.op3, args.op4 };
17data: Data,
18
19const Data = struct {
20 op_en: OpEn,
21 ops: [4]Op,
22 opc_len: u3,
23 opc: [7]u8,
24 modrm_ext: u3,
25 mode: Mode,
26};
27
28pub fn findByMnemonic(
29 prefix: Instruction.Prefix,
30 mnemonic: Mnemonic,
31 ops: []const Instruction.Operand,
32) !?Encoding {
33 var input_ops = [1]Op{.none} ** 4;
34 for (input_ops[0..ops.len], ops) |*input_op, op| input_op.* = Op.fromOperand(op);
35
3436 const rex_required = for (ops) |op| switch (op) {
3537 .reg => |r| switch (r) {
3638 .spl, .bpl, .sil, .dil => break true,
......@@ -60,88 +62,29 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding {
6062
6163 if ((rex_required or rex_extended) and rex_invalid) return error.CannotEncode;
6264
63 // TODO work out what is the maximum number of variants we can actually find in one swoop.
64 var candidates: [10]Encoding = undefined;
65 var count: usize = 0;
66 for (table) |entry| {
67 var enc = Encoding{
68 .mnemonic = entry[0],
69 .op_en = entry[1],
70 .op1 = entry[2],
71 .op2 = entry[3],
72 .op3 = entry[4],
73 .op4 = entry[5],
74 .opc_len = @intCast(u3, entry[6].len),
75 .opc = undefined,
76 .modrm_ext = entry[7],
77 .mode = entry[8],
78 };
79 std.mem.copy(u8, &enc.opc, entry[6]);
80 if (enc.mnemonic == mnemonic and
81 input_op1.isSubset(enc.op1, enc.mode) and
82 input_op2.isSubset(enc.op2, enc.mode) and
83 input_op3.isSubset(enc.op3, enc.mode) and
84 input_op4.isSubset(enc.op4, enc.mode))
85 {
86 if (rex_required) {
87 switch (enc.mode) {
88 .rex, .long => {
89 candidates[count] = enc;
90 count += 1;
91 },
92 else => {},
93 }
94 } else {
95 if (enc.mode != .rex) {
96 candidates[count] = enc;
97 count += 1;
98 }
99 }
65 var shortest_enc: ?Encoding = null;
66 var shortest_len: ?usize = null;
67 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
68 switch (data.mode) {
69 .rex => if (!rex_required) continue,
70 .long => {},
71 else => if (rex_required) continue,
10072 }
73 for (input_ops, data.ops) |input_op, data_op|
74 if (!input_op.isSubset(data_op, data.mode)) continue :next;
75
76 const enc = Encoding{ .mnemonic = mnemonic, .data = data };
77 if (shortest_enc) |previous_shortest_enc| {
78 const len = estimateInstructionLength(prefix, enc, ops);
79 const previous_shortest_len = shortest_len orelse
80 estimateInstructionLength(prefix, previous_shortest_enc, ops);
81 if (len < previous_shortest_len) {
82 shortest_enc = enc;
83 shortest_len = len;
84 } else shortest_len = previous_shortest_len;
85 } else shortest_enc = enc;
10186 }
102
103 if (count == 0) return null;
104 if (count == 1) return candidates[0];
105
106 const EncodingLength = struct {
107 fn estimate(encoding: Encoding, params: Instruction.Init) usize {
108 var inst = Instruction{
109 .op1 = params.op1,
110 .op2 = params.op2,
111 .op3 = params.op3,
112 .op4 = params.op4,
113 .prefix = params.prefix,
114 .encoding = encoding,
115 };
116 var cwriter = std.io.countingWriter(std.io.null_writer);
117 inst.encode(cwriter.writer()) catch unreachable; // Not allowed to fail here unless OOM.
118 return @intCast(usize, cwriter.bytes_written);
119 }
120 };
121
122 var shortest_encoding: ?struct {
123 index: usize,
124 len: usize,
125 } = null;
126 var i: usize = 0;
127 while (i < count) : (i += 1) {
128 const candidate = candidates[i];
129 switch (candidate.mode) {
130 .long, .rex => if (rex_invalid) return error.CannotEncode,
131 else => {},
132 }
133
134 const len = EncodingLength.estimate(candidate, args);
135 const current = shortest_encoding orelse {
136 shortest_encoding = .{ .index = i, .len = len };
137 continue;
138 };
139 if (len < current.len) {
140 shortest_encoding = .{ .index = i, .len = len };
141 }
142 }
143
144 return candidates[shortest_encoding.?.index];
87 return shortest_enc;
14588}
14689
14790/// Returns first matching encoding by opcode.
......@@ -149,57 +92,45 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
14992 legacy: LegacyPrefixes,
15093 rex: Rex,
15194}, modrm_ext: ?u3) ?Encoding {
152 for (table) |entry| {
153 const enc = Encoding{
154 .mnemonic = entry[0],
155 .op_en = entry[1],
156 .op1 = entry[2],
157 .op2 = entry[3],
158 .op3 = entry[4],
159 .op4 = entry[5],
160 .opc_len = entry[6],
161 .opc = .{ entry[7], entry[8], entry[9] },
162 .modrm_ext = entry[10],
163 .mode = entry[11],
164 };
165 const match = match: {
166 if (modrm_ext) |ext| {
167 break :match ext == enc.modrm_ext and std.mem.eql(u8, enc.opcode(), opc);
95 for (mnemonic_to_encodings_map, 0..) |encs, mnemonic_int| for (encs) |data| {
96 const enc = Encoding{ .mnemonic = @intToEnum(Mnemonic, mnemonic_int), .data = data };
97 if (modrm_ext) |ext| if (ext != data.modrm_ext) continue;
98 if (!std.mem.eql(u8, opc, enc.opcode())) continue;
99 if (prefixes.rex.w) {
100 switch (data.mode) {
101 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
102 .long, .rex => {},
168103 }
169 break :match std.mem.eql(u8, enc.opcode(), opc);
170 };
171 if (match) {
172 if (prefixes.rex.w) {
173 switch (enc.mode) {
174 .fpu, .sse, .sse2, .sse4_1, .none => {},
175 .long, .rex => return enc,
176 }
177 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
178 if (enc.mode == .rex) return enc;
179 } else if (prefixes.legacy.prefix_66) {
180 switch (enc.operandBitSize()) {
181 16 => return enc,
104 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
105 switch (data.mode) {
106 .rex => {},
107 else => continue,
108 }
109 } else if (prefixes.legacy.prefix_66) {
110 switch (enc.operandBitSize()) {
111 16 => {},
112 else => continue,
113 }
114 } else {
115 switch (data.mode) {
116 .none => switch (enc.operandBitSize()) {
117 16 => continue,
182118 else => {},
183 }
184 } else {
185 if (enc.mode == .none) {
186 switch (enc.operandBitSize()) {
187 16 => {},
188 else => return enc,
189 }
190 }
119 },
120 else => continue,
191121 }
192122 }
193 }
123 return enc;
124 };
194125 return null;
195126}
196127
197128pub fn opcode(encoding: *const Encoding) []const u8 {
198 return encoding.opc[0..encoding.opc_len];
129 return encoding.data.opc[0..encoding.data.opc_len];
199130}
200131
201132pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
202 const prefix = encoding.opc[0];
133 const prefix = encoding.data.opc[0];
203134 return switch (prefix) {
204135 0x66, 0xf2, 0xf3 => prefix,
205136 else => null,
......@@ -207,27 +138,27 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
207138}
208139
209140pub fn modRmExt(encoding: Encoding) u3 {
210 return switch (encoding.op_en) {
211 .m, .mi, .m1, .mc => encoding.modrm_ext,
141 return switch (encoding.data.op_en) {
142 .m, .mi, .m1, .mc => encoding.data.modrm_ext,
212143 else => unreachable,
213144 };
214145}
215146
216147pub fn operandBitSize(encoding: Encoding) u64 {
217 switch (encoding.mode) {
148 switch (encoding.data.mode) {
218149 .short => return 16,
219150 .long => return 64,
220151 else => {},
221152 }
222 const bit_size: u64 = switch (encoding.op_en) {
223 .np => switch (encoding.op1) {
153 const bit_size: u64 = switch (encoding.data.op_en) {
154 .np => switch (encoding.data.ops[0]) {
224155 .o16 => 16,
225156 .o32 => 32,
226157 .o64 => 64,
227158 else => 32,
228159 },
229 .td => encoding.op2.bitSize(),
230 else => encoding.op1.bitSize(),
160 .td => encoding.data.ops[1].bitSize(),
161 else => encoding.data.ops[0].bitSize(),
231162 };
232163 return bit_size;
233164}
......@@ -240,7 +171,7 @@ pub fn format(
240171) !void {
241172 _ = options;
242173 _ = fmt;
243 switch (encoding.mode) {
174 switch (encoding.data.mode) {
244175 .long => try writer.writeAll("REX.W + "),
245176 else => {},
246177 }
......@@ -249,10 +180,10 @@ pub fn format(
249180 try writer.print("{x:0>2} ", .{byte});
250181 }
251182
252 switch (encoding.op_en) {
183 switch (encoding.data.op_en) {
253184 .np, .fd, .td, .i, .zi, .d => {},
254185 .o, .oi => {
255 const tag = switch (encoding.op1) {
186 const tag = switch (encoding.data.ops[0]) {
256187 .r8 => "rb",
257188 .r16 => "rw",
258189 .r32 => "rd",
......@@ -265,12 +196,12 @@ pub fn format(
265196 .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),
266197 }
267198
268 switch (encoding.op_en) {
199 switch (encoding.data.op_en) {
269200 .i, .d, .zi, .oi, .mi, .rmi, .mri => {
270 const op = switch (encoding.op_en) {
271 .i, .d => encoding.op1,
272 .zi, .oi, .mi => encoding.op2,
273 .rmi, .mri => encoding.op3,
201 const op = switch (encoding.data.op_en) {
202 .i, .d => encoding.data.ops[0],
203 .zi, .oi, .mi => encoding.data.ops[1],
204 .rmi, .mri => encoding.data.ops[2],
274205 else => unreachable,
275206 };
276207 const tag = switch (op) {
......@@ -290,13 +221,12 @@ pub fn format(
290221
291222 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
292223
293 const ops = &[_]Op{ encoding.op1, encoding.op2, encoding.op3, encoding.op4 };
294 for (ops) |op| switch (op) {
224 for (encoding.data.ops) |op| switch (op) {
295225 .none, .o16, .o32, .o64 => break,
296226 else => try writer.print("{s} ", .{@tagName(op)}),
297227 };
298228
299 const op_en = switch (encoding.op_en) {
229 const op_en = switch (encoding.data.op_en) {
300230 .zi => .i,
301231 else => |op_en| op_en,
302232 };
......@@ -604,3 +534,53 @@ pub const Mode = enum {
604534 sse2,
605535 sse4_1,
606536};
537
538fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize {
539 var inst = Instruction{
540 .prefix = prefix,
541 .encoding = encoding,
542 .ops = [1]Operand{.none} ** 4,
543 };
544 std.mem.copy(Operand, &inst.ops, ops);
545
546 var cwriter = std.io.countingWriter(std.io.null_writer);
547 inst.encode(cwriter.writer()) catch unreachable; // Not allowed to fail here unless OOM.
548 return @intCast(usize, cwriter.bytes_written);
549}
550
551const mnemonic_to_encodings_map = init: {
552 @setEvalBranchQuota(100_000);
553 const encodings = @import("encodings.zig");
554 var entries = encodings.table;
555 std.sort.sort(encodings.Entry, &entries, {}, struct {
556 fn lessThan(_: void, lhs: encodings.Entry, rhs: encodings.Entry) bool {
557 return @enumToInt(lhs[0]) < @enumToInt(rhs[0]);
558 }
559 }.lessThan);
560 var data_storage: [entries.len]Data = undefined;
561 var mnemonic_map: [@typeInfo(Mnemonic).Enum.fields.len][]const Data = undefined;
562 var mnemonic_int = 0;
563 var mnemonic_start = 0;
564 for (&data_storage, entries, 0..) |*data, entry, data_index| {
565 data.* = .{
566 .op_en = entry[1],
567 .ops = undefined,
568 .opc_len = entry[3].len,
569 .opc = undefined,
570 .modrm_ext = entry[4],
571 .mode = entry[5],
572 };
573 std.mem.copy(Op, &data.ops, entry[2]);
574 std.mem.copy(u8, &data.opc, entry[3]);
575
576 while (mnemonic_int < @enumToInt(entry[0])) : (mnemonic_int += 1) {
577 mnemonic_map[mnemonic_int] = data_storage[mnemonic_start..data_index];
578 mnemonic_start = data_index;
579 }
580 }
581 while (mnemonic_int < mnemonic_map.len) : (mnemonic_int += 1) {
582 mnemonic_map[mnemonic_int] = data_storage[mnemonic_start..];
583 mnemonic_start = data_storage.len;
584 }
585 break :init mnemonic_map;
586};
src/arch/x86_64/Lower.zig created+465
......@@ -0,0 +1,465 @@
1//! This file contains the functionality for lowering x86_64 MIR to Instructions
2
3allocator: Allocator,
4mir: Mir,
5target: *const std.Target,
6err_msg: ?*ErrorMsg = null,
7src_loc: Module.SrcLoc,
8result: [
9 std.mem.max(usize, &.{
10 abi.Win64.callee_preserved_regs.len,
11 abi.SysV.callee_preserved_regs.len,
12 })
13]Instruction = undefined,
14result_len: usize = undefined,
15
16pub const Error = error{
17 OutOfMemory,
18 LowerFail,
19 InvalidInstruction,
20 CannotEncode,
21};
22
23/// The returned slice is overwritten by the next call to lowerMir.
24pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
25 lower.result = undefined;
26 errdefer lower.result = undefined;
27 lower.result_len = 0;
28 defer lower.result_len = undefined;
29
30 switch (inst.tag) {
31 .adc,
32 .add,
33 .@"and",
34 .bsf,
35 .bsr,
36 .bswap,
37 .bt,
38 .btc,
39 .btr,
40 .bts,
41 .call,
42 .cbw,
43 .cwde,
44 .cdqe,
45 .cwd,
46 .cdq,
47 .cqo,
48 .cmp,
49 .cmpxchg,
50 .div,
51 .fisttp,
52 .fld,
53 .idiv,
54 .imul,
55 .int3,
56 .jmp,
57 .lea,
58 .lfence,
59 .lzcnt,
60 .mfence,
61 .mov,
62 .movbe,
63 .movzx,
64 .mul,
65 .neg,
66 .nop,
67 .not,
68 .@"or",
69 .pop,
70 .popcnt,
71 .push,
72 .rcl,
73 .rcr,
74 .ret,
75 .rol,
76 .ror,
77 .sal,
78 .sar,
79 .sbb,
80 .sfence,
81 .shl,
82 .shld,
83 .shr,
84 .shrd,
85 .sub,
86 .syscall,
87 .@"test",
88 .tzcnt,
89 .ud2,
90 .xadd,
91 .xchg,
92 .xor,
93
94 .addss,
95 .cmpss,
96 .divss,
97 .maxss,
98 .minss,
99 .movss,
100 .mulss,
101 .roundss,
102 .subss,
103 .ucomiss,
104 .addsd,
105 .cmpsd,
106 .divsd,
107 .maxsd,
108 .minsd,
109 .movsd,
110 .mulsd,
111 .roundsd,
112 .subsd,
113 .ucomisd,
114 => try lower.mirGeneric(inst),
115
116 .cmps,
117 .lods,
118 .movs,
119 .scas,
120 .stos,
121 => try lower.mirString(inst),
122
123 .cmpxchgb => try lower.mirCmpxchgBytes(inst),
124
125 .jmp_reloc => try lower.emit(.none, .jmp, &.{.{ .imm = Immediate.s(0) }}),
126
127 .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}),
128
129 .lea_linker => try lower.mirLeaLinker(inst),
130
131 .mov_moffs => try lower.mirMovMoffs(inst),
132
133 .movsx => try lower.mirMovsx(inst),
134 .cmovcc => try lower.mirCmovcc(inst),
135 .setcc => try lower.mirSetcc(inst),
136 .jcc => try lower.emit(.none, mnem_cc(.j, inst.data.inst_cc.cc), &.{.{ .imm = Immediate.s(0) }}),
137
138 .push_regs, .pop_regs => try lower.mirPushPopRegisterList(inst),
139
140 .dbg_line,
141 .dbg_prologue_end,
142 .dbg_epilogue_begin,
143 .dead,
144 => {},
145 }
146
147 return lower.result[0..lower.result_len];
148}
149
150pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
151 @setCold(true);
152 assert(lower.err_msg == null);
153 lower.err_msg = try ErrorMsg.create(lower.allocator, lower.src_loc, format, args);
154 return error.LowerFail;
155}
156
157fn mnem_cc(comptime base: @Type(.EnumLiteral), cc: bits.Condition) Mnemonic {
158 return switch (cc) {
159 inline else => |c| @field(Mnemonic, @tagName(base) ++ @tagName(c)),
160 };
161}
162
163fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
164 return switch (ops) {
165 .rri_s,
166 .ri_s,
167 .i_s,
168 .mi_sib_s,
169 .mi_rip_s,
170 .lock_mi_sib_s,
171 .lock_mi_rip_s,
172 => Immediate.s(@bitCast(i32, i)),
173
174 .rri_u,
175 .ri_u,
176 .i_u,
177 .mi_sib_u,
178 .mi_rip_u,
179 .lock_mi_sib_u,
180 .lock_mi_rip_u,
181 .mri_sib,
182 .mri_rip,
183 => Immediate.u(i),
184
185 .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
186
187 else => unreachable,
188 };
189}
190
191fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
192 return switch (ops) {
193 .rm_sib,
194 .rm_sib_cc,
195 .m_sib,
196 .m_sib_cc,
197 .mi_sib_u,
198 .mi_sib_s,
199 .mr_sib,
200 .mrr_sib,
201 .mri_sib,
202 .lock_m_sib,
203 .lock_mi_sib_u,
204 .lock_mi_sib_s,
205 .lock_mr_sib,
206 => lower.mir.extraData(Mir.MemorySib, payload).data.decode(),
207
208 .rm_rip,
209 .rm_rip_cc,
210 .m_rip,
211 .m_rip_cc,
212 .mi_rip_u,
213 .mi_rip_s,
214 .mr_rip,
215 .mrr_rip,
216 .mri_rip,
217 .lock_m_rip,
218 .lock_mi_rip_u,
219 .lock_mi_rip_s,
220 .lock_mr_rip,
221 => lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),
222
223 .rax_moffs,
224 .moffs_rax,
225 .lock_moffs_rax,
226 => lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),
227
228 else => unreachable,
229 };
230}
231
232fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
233 lower.result[lower.result_len] = try Instruction.new(prefix, mnemonic, ops);
234 lower.result_len += 1;
235}
236
237fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
238 try lower.emit(switch (inst.ops) {
239 else => .none,
240 .lock_m_sib,
241 .lock_m_rip,
242 .lock_mi_sib_u,
243 .lock_mi_rip_u,
244 .lock_mi_sib_s,
245 .lock_mi_rip_s,
246 .lock_mr_sib,
247 .lock_mr_rip,
248 .lock_moffs_rax,
249 => .lock,
250 }, switch (inst.tag) {
251 inline else => |tag| if (@hasField(Mnemonic, @tagName(tag)))
252 @field(Mnemonic, @tagName(tag))
253 else
254 unreachable,
255 }, switch (inst.ops) {
256 .none => &.{},
257 .i_s, .i_u => &.{
258 .{ .imm = lower.imm(inst.ops, inst.data.i) },
259 },
260 .r => &.{
261 .{ .reg = inst.data.r },
262 },
263 .rr => &.{
264 .{ .reg = inst.data.rr.r1 },
265 .{ .reg = inst.data.rr.r2 },
266 },
267 .rrr => &.{
268 .{ .reg = inst.data.rrr.r1 },
269 .{ .reg = inst.data.rrr.r2 },
270 .{ .reg = inst.data.rrr.r3 },
271 },
272 .ri_s, .ri_u => &.{
273 .{ .reg = inst.data.ri.r },
274 .{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
275 },
276 .ri64 => &.{
277 .{ .reg = inst.data.rx.r },
278 .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },
279 },
280 .rri_s, .rri_u => &.{
281 .{ .reg = inst.data.rri.r1 },
282 .{ .reg = inst.data.rri.r2 },
283 .{ .imm = lower.imm(inst.ops, inst.data.rri.i) },
284 },
285 .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => &.{
286 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
287 },
288 .mi_sib_s,
289 .lock_mi_sib_s,
290 .mi_sib_u,
291 .lock_mi_sib_u,
292 .mi_rip_u,
293 .lock_mi_rip_u,
294 .mi_rip_s,
295 .lock_mi_rip_s,
296 => &.{
297 .{ .mem = lower.mem(inst.ops, inst.data.ix.payload) },
298 .{ .imm = lower.imm(inst.ops, inst.data.ix.i) },
299 },
300 .rm_sib, .rm_rip => &.{
301 .{ .reg = inst.data.rx.r },
302 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
303 },
304 .mr_sib, .lock_mr_sib, .mr_rip, .lock_mr_rip => &.{
305 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
306 .{ .reg = inst.data.rx.r },
307 },
308 .mrr_sib, .mrr_rip => &.{
309 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
310 .{ .reg = inst.data.rrx.r1 },
311 .{ .reg = inst.data.rrx.r2 },
312 },
313 .mri_sib, .mri_rip => &.{
314 .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
315 .{ .reg = inst.data.rix.r },
316 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
317 },
318 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
319 });
320}
321
322fn mirString(lower: *Lower, inst: Mir.Inst) Error!void {
323 switch (inst.ops) {
324 .string => try lower.emit(switch (inst.data.string.repeat) {
325 inline else => |repeat| @field(Prefix, @tagName(repeat)),
326 }, switch (inst.tag) {
327 inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) {
328 inline else => |width| @field(Mnemonic, @tagName(tag) ++ @tagName(width)),
329 },
330 else => unreachable,
331 }, &.{}),
332 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
333 }
334}
335
336fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {
337 const ops: [1]Operand = switch (inst.ops) {
338 .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => .{
339 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
340 },
341 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
342 };
343 try lower.emit(switch (inst.ops) {
344 .m_sib, .m_rip => .none,
345 .lock_m_sib, .lock_m_rip => .lock,
346 else => unreachable,
347 }, switch (@divExact(ops[0].bitSize(), 8)) {
348 8 => .cmpxchg8b,
349 16 => .cmpxchg16b,
350 else => return lower.fail("invalid operand for {s}", .{@tagName(inst.tag)}),
351 }, &ops);
352}
353
354fn mirMovMoffs(lower: *Lower, inst: Mir.Inst) Error!void {
355 try lower.emit(switch (inst.ops) {
356 .rax_moffs, .moffs_rax => .none,
357 .lock_moffs_rax => .lock,
358 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
359 }, .mov, switch (inst.ops) {
360 .rax_moffs => &.{
361 .{ .reg = .rax },
362 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
363 },
364 .moffs_rax, .lock_moffs_rax => &.{
365 .{ .mem = lower.mem(inst.ops, inst.data.payload) },
366 .{ .reg = .rax },
367 },
368 else => unreachable,
369 });
370}
371
372fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {
373 const ops: [2]Operand = switch (inst.ops) {
374 .rr => .{
375 .{ .reg = inst.data.rr.r1 },
376 .{ .reg = inst.data.rr.r2 },
377 },
378 .rm_sib, .rm_rip => .{
379 .{ .reg = inst.data.rx.r },
380 .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
381 },
382 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
383 };
384 try lower.emit(.none, switch (ops[0].bitSize()) {
385 32, 64 => switch (ops[1].bitSize()) {
386 32 => .movsxd,
387 else => .movsx,
388 },
389 else => .movsx,
390 }, &ops);
391}
392
393fn mirCmovcc(lower: *Lower, inst: Mir.Inst) Error!void {
394 switch (inst.ops) {
395 .rr_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rr_cc.cc), &.{
396 .{ .reg = inst.data.rr_cc.r1 },
397 .{ .reg = inst.data.rr_cc.r2 },
398 }),
399 .rm_sib_cc, .rm_rip_cc => try lower.emit(.none, mnem_cc(.cmov, inst.data.rx_cc.cc), &.{
400 .{ .reg = inst.data.rx_cc.r },
401 .{ .mem = lower.mem(inst.ops, inst.data.rx_cc.payload) },
402 }),
403 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
404 }
405}
406
407fn mirSetcc(lower: *Lower, inst: Mir.Inst) Error!void {
408 switch (inst.ops) {
409 .r_cc => try lower.emit(.none, mnem_cc(.set, inst.data.r_cc.cc), &.{
410 .{ .reg = inst.data.r_cc.r },
411 }),
412 .m_sib_cc, .m_rip_cc => try lower.emit(.none, mnem_cc(.set, inst.data.x_cc.cc), &.{
413 .{ .mem = lower.mem(inst.ops, inst.data.x_cc.payload) },
414 }),
415 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
416 }
417}
418
419fn mirPushPopRegisterList(lower: *Lower, inst: Mir.Inst) Error!void {
420 const save_reg_list = lower.mir.extraData(Mir.SaveRegisterList, inst.data.payload).data;
421 const base = @intToEnum(Register, save_reg_list.base_reg);
422 var disp: i32 = -@intCast(i32, save_reg_list.stack_end);
423 const reg_list = Mir.RegisterList.fromInt(save_reg_list.register_list);
424 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);
425 for (callee_preserved_regs) |callee_preserved_reg| {
426 if (!reg_list.isSet(callee_preserved_regs, callee_preserved_reg)) continue;
427 const reg_op = Operand{ .reg = callee_preserved_reg };
428 const mem_op = Operand{ .mem = Memory.sib(.qword, .{ .base = base, .disp = disp }) };
429 try lower.emit(.none, .mov, switch (inst.tag) {
430 .push_regs => &.{ mem_op, reg_op },
431 .pop_regs => &.{ reg_op, mem_op },
432 else => unreachable,
433 });
434 disp += 8;
435 }
436}
437
438fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void {
439 const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
440 const reg = @intToEnum(Register, metadata.reg);
441 try lower.emit(.none, .lea, &.{
442 .{ .reg = reg },
443 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
444 });
445}
446
447const abi = @import("abi.zig");
448const assert = std.debug.assert;
449const bits = @import("bits.zig");
450const encoder = @import("encoder.zig");
451const std = @import("std");
452
453const Air = @import("../../Air.zig");
454const Allocator = std.mem.Allocator;
455const ErrorMsg = Module.ErrorMsg;
456const Immediate = bits.Immediate;
457const Instruction = encoder.Instruction;
458const Lower = @This();
459const Memory = bits.Memory;
460const Mir = @import("Mir.zig");
461const Mnemonic = Instruction.Mnemonic;
462const Module = @import("../../Module.zig");
463const Operand = Instruction.Operand;
464const Prefix = Instruction.Prefix;
465const Register = bits.Register;
src/arch/x86_64/Mir.zig+11-8
......@@ -655,16 +655,19 @@ pub const MemoryMoffs = struct {
655655 msb: u32,
656656 lsb: u32,
657657
658 pub fn encodeOffset(moffs: *MemoryMoffs, v: u64) void {
659 moffs.msb = @truncate(u32, v >> 32);
660 moffs.lsb = @truncate(u32, v);
658 pub fn encode(seg: Register, offset: u64) MemoryMoffs {
659 return .{
660 .seg = @enumToInt(seg),
661 .msb = @truncate(u32, offset >> 32),
662 .lsb = @truncate(u32, offset >> 0),
663 };
661664 }
662665
663 pub fn decodeOffset(moffs: *const MemoryMoffs) u64 {
664 var res: u64 = 0;
665 res |= (@intCast(u64, moffs.msb) << 32);
666 res |= @intCast(u64, moffs.lsb);
667 return res;
666 pub fn decode(moffs: MemoryMoffs) Memory {
667 return .{ .moffs = .{
668 .seg = @intToEnum(Register, moffs.seg),
669 .offset = @as(u64, moffs.msb) << 32 | @as(u64, moffs.lsb) << 0,
670 } };
668671 }
669672};
670673
src/arch/x86_64/bits.zig+1-1
......@@ -515,7 +515,7 @@ pub const Memory = union(enum) {
515515 return switch (mem) {
516516 .rip => |r| r.ptr_size.bitSize(),
517517 .sib => |s| s.ptr_size.bitSize(),
518 .moffs => unreachable,
518 .moffs => 64,
519519 };
520520 }
521521};
src/arch/x86_64/encoder.zig+560-402
......@@ -11,12 +11,9 @@ const Memory = bits.Memory;
1111const Register = bits.Register;
1212
1313pub const Instruction = struct {
14 op1: Operand = .none,
15 op2: Operand = .none,
16 op3: Operand = .none,
17 op4: Operand = .none,
1814 prefix: Prefix = .none,
1915 encoding: Encoding,
16 ops: [4]Operand = .{.none} ** 4,
2017
2118 pub const Mnemonic = Encoding.Mnemonic;
2219
......@@ -57,18 +54,17 @@ pub const Instruction = struct {
5754 };
5855 }
5956
60 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) !void {
57 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) @TypeOf(writer).Error!void {
6158 switch (op) {
6259 .none => {},
6360 .reg => |reg| try writer.writeAll(@tagName(reg)),
6461 .mem => |mem| switch (mem) {
6562 .rip => |rip| {
6663 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
67 if (rip.disp != 0) {
68 const sign_bit = if (sign(rip.disp) < 0) "-" else "+";
69 const disp_abs = try std.math.absInt(rip.disp);
70 try writer.print(" {s} 0x{x}", .{ sign_bit, disp_abs });
71 }
64 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
65 @as(u8, if (rip.disp < 0) '-' else '+'),
66 std.math.absCast(rip.disp),
67 });
7268 try writer.writeByte(']');
7369 },
7470 .sib => |sib| {
......@@ -80,129 +76,118 @@ pub const Instruction = struct {
8076
8177 try writer.writeByte('[');
8278
79 var any = false;
8380 if (sib.base) |base| {
8481 try writer.print("{s}", .{@tagName(base)});
82 any = true;
8583 }
8684 if (sib.scale_index) |si| {
87 if (sib.base != null) {
88 try writer.writeAll(" + ");
89 }
85 if (any) try writer.writeAll(" + ");
9086 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
87 any = true;
9188 }
92 if (sib.disp != 0) {
93 if (sib.base != null or sib.scale_index != null) {
94 try writer.writeByte(' ');
95 }
96 try writer.writeByte(if (sign(sib.disp) < 0) '-' else '+');
97 const disp_abs = try std.math.absInt(sib.disp);
98 try writer.print(" 0x{x}", .{disp_abs});
89 if (sib.disp != 0 or !any) {
90 if (any)
91 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
92 else if (sib.disp < 0)
93 try writer.writeByte('-');
94 try writer.print("0x{x}", .{std.math.absCast(sib.disp)});
95 any = true;
9996 }
10097
10198 try writer.writeByte(']');
10299 },
103 .moffs => |moffs| try writer.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset }),
100 .moffs => |moffs| try writer.print("{s}:0x{x}", .{
101 @tagName(moffs.seg),
102 moffs.offset,
103 }),
104104 },
105105 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
106106 }
107107 }
108108 };
109109
110 pub const Init = struct {
111 prefix: Prefix = .none,
112 op1: Operand = .none,
113 op2: Operand = .none,
114 op3: Operand = .none,
115 op4: Operand = .none,
116 };
117
118 pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
119 const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {
110 pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {
111 const encoding = (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
120112 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
121 @tagName(args.prefix),
113 @tagName(prefix),
122114 @tagName(mnemonic),
123 @tagName(Encoding.Op.fromOperand(args.op1)),
124 @tagName(Encoding.Op.fromOperand(args.op2)),
125 @tagName(Encoding.Op.fromOperand(args.op3)),
126 @tagName(Encoding.Op.fromOperand(args.op4)),
115 @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
116 @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
117 @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
118 @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
127119 });
128120 return error.InvalidInstruction;
129121 };
130122 log.debug("selected encoding: {}", .{encoding});
131 return .{
132 .prefix = args.prefix,
133 .op1 = args.op1,
134 .op2 = args.op2,
135 .op3 = args.op3,
136 .op4 = args.op4,
123
124 var inst = Instruction{
125 .prefix = prefix,
137126 .encoding = encoding,
127 .ops = [1]Operand{.none} ** 4,
138128 };
129 std.mem.copy(Operand, &inst.ops, ops);
130 return inst;
139131 }
140132
141 pub fn fmtPrint(inst: Instruction, writer: anytype) !void {
133 pub fn fmtPrint(inst: Instruction, writer: anytype) @TypeOf(writer).Error!void {
142134 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
143135 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
144 const ops = [_]struct { Operand, Encoding.Op }{
145 .{ inst.op1, inst.encoding.op1 },
146 .{ inst.op2, inst.encoding.op2 },
147 .{ inst.op3, inst.encoding.op3 },
148 .{ inst.op4, inst.encoding.op4 },
149 };
150 for (&ops, 0..) |op, i| {
151 if (op[0] == .none) break;
152 if (i > 0) {
153 try writer.writeByte(',');
154 }
136 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
137 if (op == .none) break;
138 if (i > 0) try writer.writeByte(',');
155139 try writer.writeByte(' ');
156 try op[0].fmtPrint(op[1], writer);
140 try op.fmtPrint(enc, writer);
157141 }
158142 }
159143
160144 pub fn encode(inst: Instruction, writer: anytype) !void {
161145 const encoder = Encoder(@TypeOf(writer)){ .writer = writer };
162 const encoding = inst.encoding;
146 const enc = inst.encoding;
147 const data = enc.data;
163148
164149 try inst.encodeLegacyPrefixes(encoder);
165150 try inst.encodeMandatoryPrefix(encoder);
166151 try inst.encodeRexPrefix(encoder);
167152 try inst.encodeOpcode(encoder);
168153
169 switch (encoding.op_en) {
154 switch (data.op_en) {
170155 .np, .o => {},
171 .i, .d => try encodeImm(inst.op1.imm, encoding.op1, encoder),
172 .zi, .oi => try encodeImm(inst.op2.imm, encoding.op2, encoder),
173 .fd => try encoder.imm64(inst.op2.mem.moffs.offset),
174 .td => try encoder.imm64(inst.op1.mem.moffs.offset),
156 .i, .d => try encodeImm(inst.ops[0].imm, data.ops[0], encoder),
157 .zi, .oi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
158 .fd => try encoder.imm64(inst.ops[1].mem.moffs.offset),
159 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
175160 else => {
176 const mem_op = switch (encoding.op_en) {
177 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
178 .rm, .rmi => inst.op2,
161 const mem_op = switch (data.op_en) {
162 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
163 .rm, .rmi => inst.ops[1],
179164 else => unreachable,
180165 };
181166 switch (mem_op) {
182167 .reg => |reg| {
183 const rm = switch (encoding.op_en) {
184 .m, .mi, .m1, .mc => encoding.modRmExt(),
185 .mr, .mri, .mrc => inst.op2.reg.lowEnc(),
186 .rm, .rmi => inst.op1.reg.lowEnc(),
168 const rm = switch (data.op_en) {
169 .m, .mi, .m1, .mc => enc.modRmExt(),
170 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
171 .rm, .rmi => inst.ops[0].reg.lowEnc(),
187172 else => unreachable,
188173 };
189174 try encoder.modRm_direct(rm, reg.lowEnc());
190175 },
191176 .mem => |mem| {
192 const op = switch (encoding.op_en) {
177 const op = switch (data.op_en) {
193178 .m, .mi, .m1, .mc => .none,
194 .mr, .mri, .mrc => inst.op2,
195 .rm, .rmi => inst.op1,
179 .mr, .mri, .mrc => inst.ops[1],
180 .rm, .rmi => inst.ops[0],
196181 else => unreachable,
197182 };
198 try encodeMemory(encoding, mem, op, encoder);
183 try encodeMemory(enc, mem, op, encoder);
199184 },
200185 else => unreachable,
201186 }
202187
203 switch (encoding.op_en) {
204 .mi => try encodeImm(inst.op2.imm, encoding.op2, encoder),
205 .rmi, .mri => try encodeImm(inst.op3.imm, encoding.op3, encoder),
188 switch (data.op_en) {
189 .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
190 .rmi, .mri => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
206191 else => {},
207192 }
208193 },
......@@ -214,15 +199,16 @@ pub const Instruction = struct {
214199 const first = @boolToInt(inst.encoding.mandatoryPrefix() != null);
215200 const final = opcode.len - 1;
216201 for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);
217 switch (inst.encoding.op_en) {
218 .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()),
202 switch (inst.encoding.data.op_en) {
203 .o, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()),
219204 else => try encoder.opcode_1byte(opcode[final]),
220205 }
221206 }
222207
223208 fn encodeLegacyPrefixes(inst: Instruction, encoder: anytype) !void {
224209 const enc = inst.encoding;
225 const op_en = enc.op_en;
210 const data = enc.data;
211 const op_en = data.op_en;
226212
227213 var legacy = LegacyPrefixes{};
228214
......@@ -233,7 +219,7 @@ pub const Instruction = struct {
233219 .rep, .repe, .repz => legacy.prefix_f3 = true,
234220 }
235221
236 if (enc.mode == .none) {
222 if (data.mode == .none) {
237223 const bit_size = enc.operandBitSize();
238224 if (bit_size == 16) {
239225 legacy.set16BitOverride();
......@@ -242,17 +228,17 @@ pub const Instruction = struct {
242228
243229 const segment_override: ?Register = switch (op_en) {
244230 .i, .zi, .o, .oi, .d, .np => null,
245 .fd => inst.op2.mem.base().?,
246 .td => inst.op1.mem.base().?,
247 .rm, .rmi => if (inst.op2.isSegmentRegister()) blk: {
248 break :blk switch (inst.op2) {
231 .fd => inst.ops[1].mem.base().?,
232 .td => inst.ops[0].mem.base().?,
233 .rm, .rmi => if (inst.ops[1].isSegmentRegister()) blk: {
234 break :blk switch (inst.ops[1]) {
249235 .reg => |r| r,
250236 .mem => |m| m.base().?,
251237 else => unreachable,
252238 };
253239 } else null,
254 .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.op1.isSegmentRegister()) blk: {
255 break :blk switch (inst.op1) {
240 .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.ops[0].isSegmentRegister()) blk: {
241 break :blk switch (inst.ops[0]) {
256242 .reg => |r| r,
257243 .mem => |m| m.base().?,
258244 else => unreachable,
......@@ -267,19 +253,19 @@ pub const Instruction = struct {
267253 }
268254
269255 fn encodeRexPrefix(inst: Instruction, encoder: anytype) !void {
270 const op_en = inst.encoding.op_en;
256 const op_en = inst.encoding.data.op_en;
271257
272258 var rex = Rex{};
273 rex.present = inst.encoding.mode == .rex;
274 rex.w = inst.encoding.mode == .long;
259 rex.present = inst.encoding.data.mode == .rex;
260 rex.w = inst.encoding.data.mode == .long;
275261
276262 switch (op_en) {
277263 .np, .i, .zi, .fd, .td, .d => {},
278 .o, .oi => rex.b = inst.op1.reg.isExtended(),
264 .o, .oi => rex.b = inst.ops[0].reg.isExtended(),
279265 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {
280266 const r_op = switch (op_en) {
281 .rm, .rmi => inst.op1,
282 .mr, .mri, .mrc => inst.op2,
267 .rm, .rmi => inst.ops[0],
268 .mr, .mri, .mrc => inst.ops[1],
283269 else => null,
284270 };
285271 if (r_op) |op| {
......@@ -287,8 +273,8 @@ pub const Instruction = struct {
287273 }
288274
289275 const b_x_op = switch (op_en) {
290 .rm, .rmi => inst.op2,
291 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
276 .rm, .rmi => inst.ops[1],
277 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
292278 else => unreachable,
293279 };
294280 switch (b_x_op) {
......@@ -407,10 +393,6 @@ pub const Instruction = struct {
407393 }
408394};
409395
410inline fn sign(i: anytype) @TypeOf(i) {
411 return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0);
412}
413
414396pub const LegacyPrefixes = packed struct {
415397 /// LOCK
416398 prefix_f0: bool = false,
......@@ -827,16 +809,14 @@ const TestEncode = struct {
827809 buffer: [32]u8 = undefined,
828810 index: usize = 0,
829811
830 fn encode(enc: *TestEncode, mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
812 fn encode(
813 enc: *TestEncode,
814 mnemonic: Instruction.Mnemonic,
815 ops: []const Instruction.Operand,
816 ) !void {
831817 var stream = std.io.fixedBufferStream(&enc.buffer);
832818 var count_writer = std.io.countingWriter(stream.writer());
833 const inst = try Instruction.new(mnemonic, .{
834 .prefix = args.prefix,
835 .op1 = args.op1,
836 .op2 = args.op2,
837 .op3 = args.op3,
838 .op4 = args.op4,
839 });
819 const inst = try Instruction.new(.none, mnemonic, ops);
840820 try inst.encode(count_writer.writer());
841821 enc.index = count_writer.bytes_written;
842822 }
......@@ -850,9 +830,9 @@ test "encode" {
850830 var buf = std.ArrayList(u8).init(testing.allocator);
851831 defer buf.deinit();
852832
853 const inst = try Instruction.new(.mov, .{
854 .op1 = .{ .reg = .rbx },
855 .op2 = .{ .imm = Immediate.u(4) },
833 const inst = try Instruction.new(.none, .mov, &.{
834 .{ .reg = .rbx },
835 .{ .imm = Immediate.u(4) },
856836 });
857837 try inst.encode(buf.writer());
858838 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
......@@ -861,61 +841,94 @@ test "encode" {
861841test "lower I encoding" {
862842 var enc = TestEncode{};
863843
864 try enc.encode(.push, .{ .op1 = .{ .imm = Immediate.u(0x10) } });
844 try enc.encode(.push, &.{
845 .{ .imm = Immediate.u(0x10) },
846 });
865847 try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
866848
867 try enc.encode(.push, .{ .op1 = .{ .imm = Immediate.u(0x1000) } });
849 try enc.encode(.push, &.{
850 .{ .imm = Immediate.u(0x1000) },
851 });
868852 try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
869853
870 try enc.encode(.push, .{ .op1 = .{ .imm = Immediate.u(0x10000000) } });
854 try enc.encode(.push, &.{
855 .{ .imm = Immediate.u(0x10000000) },
856 });
871857 try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");
872858
873 try enc.encode(.adc, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10000000) } });
859 try enc.encode(.adc, &.{
860 .{ .reg = .rax },
861 .{ .imm = Immediate.u(0x10000000) },
862 });
874863 try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");
875864
876 try enc.encode(.add, .{ .op1 = .{ .reg = .al }, .op2 = .{ .imm = Immediate.u(0x10) } });
865 try enc.encode(.add, &.{
866 .{ .reg = .al },
867 .{ .imm = Immediate.u(0x10) },
868 });
877869 try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
878870
879 try enc.encode(.add, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } });
871 try enc.encode(.add, &.{
872 .{ .reg = .rax },
873 .{ .imm = Immediate.u(0x10) },
874 });
880875 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
881876
882 try enc.encode(.sbb, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .imm = Immediate.u(0x10) } });
877 try enc.encode(.sbb, &.{
878 .{ .reg = .ax },
879 .{ .imm = Immediate.u(0x10) },
880 });
883881 try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
884882
885 try enc.encode(.xor, .{ .op1 = .{ .reg = .al }, .op2 = .{ .imm = Immediate.u(0x10) } });
883 try enc.encode(.xor, &.{
884 .{ .reg = .al },
885 .{ .imm = Immediate.u(0x10) },
886 });
886887 try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
887888}
888889
889890test "lower MI encoding" {
890891 var enc = TestEncode{};
891892
892 try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
893 try enc.encode(.mov, &.{
894 .{ .reg = .r12 },
895 .{ .imm = Immediate.u(0x1000) },
896 });
893897 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
894898
895 try enc.encode(.mov, .{
896 .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
897 .op2 = .{ .imm = Immediate.u(0x10) },
899 try enc.encode(.mov, &.{
900 .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
901 .{ .imm = Immediate.u(0x10) },
898902 });
899903 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
900904
901 try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
905 try enc.encode(.mov, &.{
906 .{ .reg = .r12 },
907 .{ .imm = Immediate.u(0x1000) },
908 });
902909 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
903910
904 try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
911 try enc.encode(.mov, &.{
912 .{ .reg = .r12 },
913 .{ .imm = Immediate.u(0x1000) },
914 });
905915 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
906916
907 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } });
917 try enc.encode(.mov, &.{
918 .{ .reg = .rax },
919 .{ .imm = Immediate.u(0x10) },
920 });
908921 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
909922
910 try enc.encode(.mov, .{
911 .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
912 .op2 = .{ .imm = Immediate.u(0x10) },
923 try enc.encode(.mov, &.{
924 .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
925 .{ .imm = Immediate.u(0x10) },
913926 });
914927 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
915928
916 try enc.encode(.mov, .{
917 .op1 = .{ .mem = Memory.rip(.qword, 0x10) },
918 .op2 = .{ .imm = Immediate.u(0x10) },
929 try enc.encode(.mov, &.{
930 .{ .mem = Memory.rip(.qword, 0x10) },
931 .{ .imm = Immediate.u(0x10) },
919932 });
920933 try expectEqualHexStrings(
921934 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
......@@ -923,99 +936,108 @@ test "lower MI encoding" {
923936 "mov QWORD PTR [rip + 0x10], 0x10",
924937 );
925938
926 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
927 .base = .rbp,
928 .disp = -8,
929 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
939 try enc.encode(.mov, &.{
940 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
941 .{ .imm = Immediate.u(0x10) },
942 });
930943 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
931944
932 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.word, .{
933 .base = .rbp,
934 .disp = -2,
935 }) }, .op2 = .{ .imm = Immediate.s(-16) } });
945 try enc.encode(.mov, &.{
946 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },
947 .{ .imm = Immediate.s(-16) },
948 });
936949 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
937950
938 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{
939 .base = .rbp,
940 .disp = -1,
941 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
951 try enc.encode(.mov, &.{
952 .{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },
953 .{ .imm = Immediate.u(0x10) },
954 });
942955 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
943956
944 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
945 .base = .ds,
946 .disp = 0x10000000,
947 .scale_index = .{
948 .scale = 2,
949 .index = .rcx,
950 },
951 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
957 try enc.encode(.mov, &.{
958 .{ .mem = Memory.sib(.qword, .{
959 .base = .ds,
960 .disp = 0x10000000,
961 .scale_index = .{ .scale = 2, .index = .rcx },
962 }) },
963 .{ .imm = Immediate.u(0x10) },
964 });
952965 try expectEqualHexStrings(
953966 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
954967 enc.code(),
955968 "mov QWORD PTR [rcx*2 + 0x10000000], 0x10",
956969 );
957970
958 try enc.encode(.adc, .{ .op1 = .{ .mem = Memory.sib(.byte, .{
959 .base = .rbp,
960 .disp = -0x10,
961 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
971 try enc.encode(.adc, &.{
972 .{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
973 .{ .imm = Immediate.u(0x10) },
974 });
962975 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
963976
964 try enc.encode(.adc, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) }, .op2 = .{ .imm = Immediate.u(0x10) } });
977 try enc.encode(.adc, &.{
978 .{ .mem = Memory.rip(.qword, 0) },
979 .{ .imm = Immediate.u(0x10) },
980 });
965981 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
966982
967 try enc.encode(.adc, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } });
983 try enc.encode(.adc, &.{
984 .{ .reg = .rax },
985 .{ .imm = Immediate.u(0x10) },
986 });
968987 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
969988
970 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{
971 .base = .rdx,
972 .disp = -8,
973 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
989 try enc.encode(.add, &.{
990 .{ .mem = Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
991 .{ .imm = Immediate.u(0x10) },
992 });
974993 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
975994
976 try enc.encode(.add, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } });
995 try enc.encode(.add, &.{
996 .{ .reg = .rax },
997 .{ .imm = Immediate.u(0x10) },
998 });
977999 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
9781000
979 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
980 .base = .rbp,
981 .disp = -0x10,
982 }) }, .op2 = .{ .imm = Immediate.s(-0x10) } });
1001 try enc.encode(.add, &.{
1002 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
1003 .{ .imm = Immediate.s(-0x10) },
1004 });
9831005 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
9841006
985 try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{
986 .base = .ds,
987 .disp = 0x10000000,
988 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
1007 try enc.encode(.@"and", &.{
1008 .{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
1009 .{ .imm = Immediate.u(0x10) },
1010 });
9891011 try expectEqualHexStrings(
9901012 "\x83\x24\x25\x00\x00\x00\x10\x10",
9911013 enc.code(),
9921014 "and DWORD PTR ds:0x10000000, 0x10",
9931015 );
9941016
995 try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{
996 .base = .es,
997 .disp = 0x10000000,
998 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
1017 try enc.encode(.@"and", &.{
1018 .{ .mem = Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
1019 .{ .imm = Immediate.u(0x10) },
1020 });
9991021 try expectEqualHexStrings(
10001022 "\x26\x83\x24\x25\x00\x00\x00\x10\x10",
10011023 enc.code(),
10021024 "and DWORD PTR es:0x10000000, 0x10",
10031025 );
10041026
1005 try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{
1006 .base = .r12,
1007 .disp = 0x10000000,
1008 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
1027 try enc.encode(.@"and", &.{
1028 .{ .mem = Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
1029 .{ .imm = Immediate.u(0x10) },
1030 });
10091031 try expectEqualHexStrings(
10101032 "\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
10111033 enc.code(),
10121034 "and DWORD PTR [r12 + 0x10000000], 0x10",
10131035 );
10141036
1015 try enc.encode(.sub, .{ .op1 = .{ .mem = Memory.sib(.dword, .{
1016 .base = .r11,
1017 .disp = 0x10000000,
1018 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
1037 try enc.encode(.sub, &.{
1038 .{ .mem = Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
1039 .{ .imm = Immediate.u(0x10) },
1040 });
10191041 try expectEqualHexStrings(
10201042 "\x41\x83\xAB\x00\x00\x00\x10\x10",
10211043 enc.code(),
......@@ -1026,185 +1048,227 @@ test "lower MI encoding" {
10261048test "lower RM encoding" {
10271049 var enc = TestEncode{};
10281050
1029 try enc.encode(.mov, .{
1030 .op1 = .{ .reg = .rax },
1031 .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
1051 try enc.encode(.mov, &.{
1052 .{ .reg = .rax },
1053 .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
10321054 });
10331055 try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
10341056
1035 try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{
1036 .base = .ds,
1037 .disp = 0x10,
1038 }) } });
1057 try enc.encode(.mov, &.{
1058 .{ .reg = .rbx },
1059 .{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
1060 });
10391061 try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");
10401062
1041 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{
1042 .base = .rbp,
1043 .disp = -4,
1044 }) } });
1063 try enc.encode(.mov, &.{
1064 .{ .reg = .rax },
1065 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
1066 });
10451067 try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");
10461068
1047 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{
1048 .base = .rbp,
1049 .scale_index = .{
1050 .scale = 1,
1051 .index = .rcx,
1052 },
1053 .disp = -8,
1054 }) } });
1069 try enc.encode(.mov, &.{
1070 .{ .reg = .rax },
1071 .{ .mem = Memory.sib(.qword, .{
1072 .base = .rbp,
1073 .scale_index = .{ .scale = 1, .index = .rcx },
1074 .disp = -8,
1075 }) },
1076 });
10551077 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", enc.code(), "mov rax, QWORD PTR [rbp + rcx*1 - 8]");
10561078
1057 try enc.encode(.mov, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.dword, .{
1058 .base = .rbp,
1059 .scale_index = .{
1060 .scale = 4,
1061 .index = .rdx,
1062 },
1063 .disp = -4,
1064 }) } });
1079 try enc.encode(.mov, &.{
1080 .{ .reg = .eax },
1081 .{ .mem = Memory.sib(.dword, .{
1082 .base = .rbp,
1083 .scale_index = .{ .scale = 4, .index = .rdx },
1084 .disp = -4,
1085 }) },
1086 });
10651087 try expectEqualHexStrings("\x8B\x44\x95\xFC", enc.code(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
10661088
1067 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{
1068 .base = .rbp,
1069 .scale_index = .{
1070 .scale = 8,
1071 .index = .rcx,
1072 },
1073 .disp = -8,
1074 }) } });
1089 try enc.encode(.mov, &.{
1090 .{ .reg = .rax },
1091 .{ .mem = Memory.sib(.qword, .{
1092 .base = .rbp,
1093 .scale_index = .{ .scale = 8, .index = .rcx },
1094 .disp = -8,
1095 }) },
1096 });
10751097 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", enc.code(), "mov rax, QWORD PTR [rbp + rcx*8 - 8]");
10761098
1077 try enc.encode(.mov, .{ .op1 = .{ .reg = .r8b }, .op2 = .{ .mem = Memory.sib(.byte, .{
1078 .base = .rsi,
1079 .scale_index = .{
1080 .scale = 1,
1081 .index = .rcx,
1082 },
1083 .disp = -24,
1084 }) } });
1099 try enc.encode(.mov, &.{
1100 .{ .reg = .r8b },
1101 .{ .mem = Memory.sib(.byte, .{
1102 .base = .rsi,
1103 .scale_index = .{ .scale = 1, .index = .rcx },
1104 .disp = -24,
1105 }) },
1106 });
10851107 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", enc.code(), "mov r8b, BYTE PTR [rsi + rcx*1 - 24]");
10861108
10871109 // TODO this mnemonic needs cleanup as some prefixes are obsolete.
1088 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .cs } });
1110 try enc.encode(.mov, &.{
1111 .{ .reg = .rax },
1112 .{ .reg = .cs },
1113 });
10891114 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
10901115
1091 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
1092 .base = .rbp,
1093 .disp = -16,
1094 }) }, .op2 = .{ .reg = .fs } });
1116 try enc.encode(.mov, &.{
1117 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
1118 .{ .reg = .fs },
1119 });
10951120 try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs");
10961121
1097 try enc.encode(.mov, .{ .op1 = .{ .reg = .r12w }, .op2 = .{ .reg = .cs } });
1122 try enc.encode(.mov, &.{
1123 .{ .reg = .r12w },
1124 .{ .reg = .cs },
1125 });
10981126 try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");
10991127
1100 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.word, .{
1101 .base = .rbp,
1102 .disp = -16,
1103 }) }, .op2 = .{ .reg = .fs } });
1128 try enc.encode(.mov, &.{
1129 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1130 .{ .reg = .fs },
1131 });
11041132 try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
11051133
1106 try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .reg = .bx } });
1134 try enc.encode(.movsx, &.{
1135 .{ .reg = .eax },
1136 .{ .reg = .bx },
1137 });
11071138 try expectEqualHexStrings("\x0F\xBF\xC3", enc.code(), "movsx eax, bx");
11081139
1109 try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .reg = .bl } });
1140 try enc.encode(.movsx, &.{
1141 .{ .reg = .eax },
1142 .{ .reg = .bl },
1143 });
11101144 try expectEqualHexStrings("\x0F\xBE\xC3", enc.code(), "movsx eax, bl");
11111145
1112 try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } });
1146 try enc.encode(.movsx, &.{
1147 .{ .reg = .ax },
1148 .{ .reg = .bl },
1149 });
11131150 try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl");
11141151
1115 try enc.encode(.movsx, .{
1116 .op1 = .{ .reg = .eax },
1117 .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
1152 try enc.encode(.movsx, &.{
1153 .{ .reg = .eax },
1154 .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
11181155 });
11191156 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
11201157
1121 try enc.encode(.movsx, .{
1122 .op1 = .{ .reg = .eax },
1123 .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
1158 try enc.encode(.movsx, &.{
1159 .{ .reg = .eax },
1160 .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
11241161 });
11251162 try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");
11261163
1127 try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } });
1164 try enc.encode(.movsx, &.{
1165 .{ .reg = .ax },
1166 .{ .mem = Memory.rip(.byte, 0x10) },
1167 });
11281168 try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]");
11291169
1130 try enc.encode(.movsx, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .bx } });
1170 try enc.encode(.movsx, &.{
1171 .{ .reg = .rax },
1172 .{ .reg = .bx },
1173 });
11311174 try expectEqualHexStrings("\x48\x0F\xBF\xC3", enc.code(), "movsx rax, bx");
11321175
1133 try enc.encode(.movsxd, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .ebx } });
1176 try enc.encode(.movsxd, &.{
1177 .{ .reg = .rax },
1178 .{ .reg = .ebx },
1179 });
11341180 try expectEqualHexStrings("\x48\x63\xC3", enc.code(), "movsxd rax, ebx");
11351181
1136 try enc.encode(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.rip(.qword, 0x10) } });
1182 try enc.encode(.lea, &.{
1183 .{ .reg = .rax },
1184 .{ .mem = Memory.rip(.qword, 0x10) },
1185 });
11371186 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]");
11381187
1139 try enc.encode(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.rip(.dword, 0x10) } });
1188 try enc.encode(.lea, &.{
1189 .{ .reg = .rax },
1190 .{ .mem = Memory.rip(.dword, 0x10) },
1191 });
11401192 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]");
11411193
1142 try enc.encode(.lea, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.rip(.dword, 0x10) } });
1194 try enc.encode(.lea, &.{
1195 .{ .reg = .eax },
1196 .{ .mem = Memory.rip(.dword, 0x10) },
1197 });
11431198 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]");
11441199
1145 try enc.encode(.lea, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.rip(.word, 0x10) } });
1200 try enc.encode(.lea, &.{
1201 .{ .reg = .eax },
1202 .{ .mem = Memory.rip(.word, 0x10) },
1203 });
11461204 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]");
11471205
1148 try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } });
1206 try enc.encode(.lea, &.{
1207 .{ .reg = .ax },
1208 .{ .mem = Memory.rip(.byte, 0x10) },
1209 });
11491210 try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");
11501211
1151 try enc.encode(.lea, .{
1152 .op1 = .{ .reg = .rsi },
1153 .op2 = .{ .mem = Memory.sib(.qword, .{
1212 try enc.encode(.lea, &.{
1213 .{ .reg = .rsi },
1214 .{ .mem = Memory.sib(.qword, .{
11541215 .base = .rbp,
11551216 .scale_index = .{ .scale = 1, .index = .rcx },
11561217 }) },
11571218 });
11581219 try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]");
11591220
1160 try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{
1161 .base = .ds,
1162 .disp = 0x10000000,
1163 }) } });
1221 try enc.encode(.add, &.{
1222 .{ .reg = .r11 },
1223 .{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
1224 });
11641225 try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");
11651226
1166 try enc.encode(.add, .{ .op1 = .{ .reg = .r12b }, .op2 = .{ .mem = Memory.sib(.byte, .{
1167 .base = .ds,
1168 .disp = 0x10000000,
1169 }) } });
1227 try enc.encode(.add, &.{
1228 .{ .reg = .r12b },
1229 .{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
1230 });
11701231 try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");
11711232
1172 try enc.encode(.add, .{ .op1 = .{ .reg = .r12b }, .op2 = .{ .mem = Memory.sib(.byte, .{
1173 .base = .fs,
1174 .disp = 0x10000000,
1175 }) } });
1233 try enc.encode(.add, &.{
1234 .{ .reg = .r12b },
1235 .{ .mem = Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
1236 });
11761237 try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");
11771238
1178 try enc.encode(.sub, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{
1179 .base = .r13,
1180 .disp = 0x10000000,
1181 }) } });
1239 try enc.encode(.sub, &.{
1240 .{ .reg = .r11 },
1241 .{ .mem = Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
1242 });
11821243 try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");
11831244
1184 try enc.encode(.sub, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{
1185 .base = .r12,
1186 .disp = 0x10000000,
1187 }) } });
1245 try enc.encode(.sub, &.{
1246 .{ .reg = .r11 },
1247 .{ .mem = Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
1248 });
11881249 try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");
11891250
1190 try enc.encode(.imul, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .reg = .r12 } });
1251 try enc.encode(.imul, &.{
1252 .{ .reg = .r11 },
1253 .{ .reg = .r12 },
1254 });
11911255 try expectEqualHexStrings("\x4D\x0F\xAF\xDC", enc.code(), "mov r11, r12");
11921256}
11931257
11941258test "lower RMI encoding" {
11951259 var enc = TestEncode{};
11961260
1197 try enc.encode(.imul, .{
1198 .op1 = .{ .reg = .r11 },
1199 .op2 = .{ .reg = .r12 },
1200 .op3 = .{ .imm = Immediate.s(-2) },
1261 try enc.encode(.imul, &.{
1262 .{ .reg = .r11 },
1263 .{ .reg = .r12 },
1264 .{ .imm = Immediate.s(-2) },
12011265 });
12021266 try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
12031267
1204 try enc.encode(.imul, .{
1205 .op1 = .{ .reg = .r11 },
1206 .op2 = .{ .mem = Memory.rip(.qword, -16) },
1207 .op3 = .{ .imm = Immediate.s(-1024) },
1268 try enc.encode(.imul, &.{
1269 .{ .reg = .r11 },
1270 .{ .mem = Memory.rip(.qword, -16) },
1271 .{ .imm = Immediate.s(-1024) },
12081272 });
12091273 try expectEqualHexStrings(
12101274 "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
......@@ -1212,13 +1276,10 @@ test "lower RMI encoding" {
12121276 "imul r11, QWORD PTR [rip - 16], -1024",
12131277 );
12141278
1215 try enc.encode(.imul, .{
1216 .op1 = .{ .reg = .bx },
1217 .op2 = .{ .mem = Memory.sib(.word, .{
1218 .base = .rbp,
1219 .disp = -16,
1220 }) },
1221 .op3 = .{ .imm = Immediate.s(-1024) },
1279 try enc.encode(.imul, &.{
1280 .{ .reg = .bx },
1281 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1282 .{ .imm = Immediate.s(-1024) },
12221283 });
12231284 try expectEqualHexStrings(
12241285 "\x66\x69\x5D\xF0\x00\xFC",
......@@ -1226,13 +1287,10 @@ test "lower RMI encoding" {
12261287 "imul bx, WORD PTR [rbp - 16], -1024",
12271288 );
12281289
1229 try enc.encode(.imul, .{
1230 .op1 = .{ .reg = .bx },
1231 .op2 = .{ .mem = Memory.sib(.word, .{
1232 .base = .rbp,
1233 .disp = -16,
1234 }) },
1235 .op3 = .{ .imm = Immediate.u(1024) },
1290 try enc.encode(.imul, &.{
1291 .{ .reg = .bx },
1292 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1293 .{ .imm = Immediate.u(1024) },
12361294 });
12371295 try expectEqualHexStrings(
12381296 "\x66\x69\x5D\xF0\x00\x04",
......@@ -1244,238 +1302,343 @@ test "lower RMI encoding" {
12441302test "lower MR encoding" {
12451303 var enc = TestEncode{};
12461304
1247 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .rbx } });
1305 try enc.encode(.mov, &.{
1306 .{ .reg = .rax },
1307 .{ .reg = .rbx },
1308 });
12481309 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
12491310
1250 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
1251 .base = .rbp,
1252 .disp = -4,
1253 }) }, .op2 = .{ .reg = .r11 } });
1311 try enc.encode(.mov, &.{
1312 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
1313 .{ .reg = .r11 },
1314 });
12541315 try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");
12551316
1256 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.rip(.qword, 0x10) }, .op2 = .{ .reg = .r12 } });
1317 try enc.encode(.mov, &.{
1318 .{ .mem = Memory.rip(.qword, 0x10) },
1319 .{ .reg = .r12 },
1320 });
12571321 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12");
12581322
1259 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
1260 .base = .r11,
1261 .scale_index = .{
1262 .scale = 2,
1263 .index = .r12,
1264 },
1265 .disp = 0x10,
1266 }) }, .op2 = .{ .reg = .r13 } });
1323 try enc.encode(.mov, &.{
1324 .{ .mem = Memory.sib(.qword, .{
1325 .base = .r11,
1326 .scale_index = .{ .scale = 2, .index = .r12 },
1327 .disp = 0x10,
1328 }) },
1329 .{ .reg = .r13 },
1330 });
12671331 try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13");
12681332
1269 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.rip(.word, -0x10) }, .op2 = .{ .reg = .r12w } });
1333 try enc.encode(.mov, &.{
1334 .{ .mem = Memory.rip(.word, -0x10) },
1335 .{ .reg = .r12w },
1336 });
12701337 try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w");
12711338
1272 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{
1273 .base = .r11,
1274 .scale_index = .{
1275 .scale = 2,
1276 .index = .r12,
1277 },
1278 .disp = 0x10,
1279 }) }, .op2 = .{ .reg = .r13b } });
1339 try enc.encode(.mov, &.{
1340 .{ .mem = Memory.sib(.byte, .{
1341 .base = .r11,
1342 .scale_index = .{ .scale = 2, .index = .r12 },
1343 .disp = 0x10,
1344 }) },
1345 .{ .reg = .r13b },
1346 });
12801347 try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");
12811348
1282 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.byte, .{
1283 .base = .ds,
1284 .disp = 0x10000000,
1285 }) }, .op2 = .{ .reg = .r12b } });
1349 try enc.encode(.add, &.{
1350 .{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
1351 .{ .reg = .r12b },
1352 });
12861353 try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");
12871354
1288 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{
1289 .base = .ds,
1290 .disp = 0x10000000,
1291 }) }, .op2 = .{ .reg = .r12d } });
1355 try enc.encode(.add, &.{
1356 .{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
1357 .{ .reg = .r12d },
1358 });
12921359 try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");
12931360
1294 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{
1295 .base = .gs,
1296 .disp = 0x10000000,
1297 }) }, .op2 = .{ .reg = .r12d } });
1361 try enc.encode(.add, &.{
1362 .{ .mem = Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
1363 .{ .reg = .r12d },
1364 });
12981365 try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");
12991366
1300 try enc.encode(.sub, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
1301 .base = .r11,
1302 .disp = 0x10000000,
1303 }) }, .op2 = .{ .reg = .r12 } });
1367 try enc.encode(.sub, &.{
1368 .{ .mem = Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
1369 .{ .reg = .r12 },
1370 });
13041371 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
13051372}
13061373
13071374test "lower M encoding" {
13081375 var enc = TestEncode{};
13091376
1310 try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } });
1377 try enc.encode(.call, &.{
1378 .{ .reg = .r12 },
1379 });
13111380 try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
13121381
1313 try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) } });
1382 try enc.encode(.call, &.{
1383 .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) },
1384 });
13141385 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
13151386
1316 try enc.encode(.call, .{
1317 .op1 = .{ .mem = Memory.sib(.qword, .{
1387 try enc.encode(.call, &.{
1388 .{ .mem = Memory.sib(.qword, .{
13181389 .base = null,
13191390 .scale_index = .{ .index = .r11, .scale = 2 },
13201391 }) },
13211392 });
13221393 try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
13231394
1324 try enc.encode(.call, .{
1325 .op1 = .{ .mem = Memory.sib(.qword, .{
1395 try enc.encode(.call, &.{
1396 .{ .mem = Memory.sib(.qword, .{
13261397 .base = null,
13271398 .scale_index = .{ .index = .r12, .scale = 2 },
13281399 }) },
13291400 });
13301401 try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
13311402
1332 try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .gs }) } });
1403 try enc.encode(.call, &.{
1404 .{ .mem = Memory.sib(.qword, .{ .base = .gs }) },
1405 });
13331406 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
13341407
1335 try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } });
1408 try enc.encode(.call, &.{
1409 .{ .imm = Immediate.s(0) },
1410 });
13361411 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
13371412
1338 try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) } });
1413 try enc.encode(.push, &.{
1414 .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) },
1415 });
13391416 try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
13401417
1341 try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) } });
1418 try enc.encode(.push, &.{
1419 .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
1420 });
13421421 try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
13431422
1344 try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) } });
1423 try enc.encode(.pop, &.{
1424 .{ .mem = Memory.rip(.qword, 0) },
1425 });
13451426 try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]");
13461427
1347 try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.word, 0) } });
1428 try enc.encode(.pop, &.{
1429 .{ .mem = Memory.rip(.word, 0) },
1430 });
13481431 try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]");
13491432
1350 try enc.encode(.imul, .{ .op1 = .{ .reg = .rax } });
1433 try enc.encode(.imul, &.{
1434 .{ .reg = .rax },
1435 });
13511436 try expectEqualHexStrings("\x48\xF7\xE8", enc.code(), "imul rax");
13521437
1353 try enc.encode(.imul, .{ .op1 = .{ .reg = .r12 } });
1438 try enc.encode(.imul, &.{
1439 .{ .reg = .r12 },
1440 });
13541441 try expectEqualHexStrings("\x49\xF7\xEC", enc.code(), "imul r12");
13551442}
13561443
13571444test "lower O encoding" {
13581445 var enc = TestEncode{};
13591446
1360 try enc.encode(.push, .{ .op1 = .{ .reg = .rax } });
1447 try enc.encode(.push, &.{
1448 .{ .reg = .rax },
1449 });
13611450 try expectEqualHexStrings("\x50", enc.code(), "push rax");
13621451
1363 try enc.encode(.push, .{ .op1 = .{ .reg = .r12w } });
1452 try enc.encode(.push, &.{
1453 .{ .reg = .r12w },
1454 });
13641455 try expectEqualHexStrings("\x66\x41\x54", enc.code(), "push r12w");
13651456
1366 try enc.encode(.pop, .{ .op1 = .{ .reg = .r12 } });
1457 try enc.encode(.pop, &.{
1458 .{ .reg = .r12 },
1459 });
13671460 try expectEqualHexStrings("\x41\x5c", enc.code(), "pop r12");
13681461}
13691462
13701463test "lower OI encoding" {
13711464 var enc = TestEncode{};
13721465
1373 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x1000000000000000) } });
1466 try enc.encode(.mov, &.{
1467 .{ .reg = .rax },
1468 .{ .imm = Immediate.u(0x1000000000000000) },
1469 });
13741470 try expectEqualHexStrings(
13751471 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
13761472 enc.code(),
13771473 "movabs rax, 0x1000000000000000",
13781474 );
13791475
1380 try enc.encode(.mov, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .imm = Immediate.u(0x1000000000000000) } });
1476 try enc.encode(.mov, &.{
1477 .{ .reg = .r11 },
1478 .{ .imm = Immediate.u(0x1000000000000000) },
1479 });
13811480 try expectEqualHexStrings(
13821481 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
13831482 enc.code(),
13841483 "movabs r11, 0x1000000000000000",
13851484 );
13861485
1387 try enc.encode(.mov, .{ .op1 = .{ .reg = .r11d }, .op2 = .{ .imm = Immediate.u(0x10000000) } });
1486 try enc.encode(.mov, &.{
1487 .{ .reg = .r11d },
1488 .{ .imm = Immediate.u(0x10000000) },
1489 });
13881490 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");
13891491
1390 try enc.encode(.mov, .{ .op1 = .{ .reg = .r11w }, .op2 = .{ .imm = Immediate.u(0x1000) } });
1492 try enc.encode(.mov, &.{
1493 .{ .reg = .r11w },
1494 .{ .imm = Immediate.u(0x1000) },
1495 });
13911496 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
13921497
1393 try enc.encode(.mov, .{ .op1 = .{ .reg = .r11b }, .op2 = .{ .imm = Immediate.u(0x10) } });
1498 try enc.encode(.mov, &.{
1499 .{ .reg = .r11b },
1500 .{ .imm = Immediate.u(0x10) },
1501 });
13941502 try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
13951503}
13961504
13971505test "lower FD/TD encoding" {
13981506 var enc = TestEncode{};
13991507
1400 try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.moffs(.cs, 0x10) } });
1508 try enc.encode(.mov, &.{
1509 .{ .reg = .rax },
1510 .{ .mem = Memory.moffs(.cs, 0x10) },
1511 });
14011512 try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10");
14021513
1403 try enc.encode(.mov, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.moffs(.fs, 0x10) } });
1514 try enc.encode(.mov, &.{
1515 .{ .reg = .eax },
1516 .{ .mem = Memory.moffs(.fs, 0x10) },
1517 });
14041518 try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10");
14051519
1406 try enc.encode(.mov, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.moffs(.gs, 0x10) } });
1520 try enc.encode(.mov, &.{
1521 .{ .reg = .ax },
1522 .{ .mem = Memory.moffs(.gs, 0x10) },
1523 });
14071524 try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10");
14081525
1409 try enc.encode(.mov, .{ .op1 = .{ .reg = .al }, .op2 = .{ .mem = Memory.moffs(.ds, 0x10) } });
1526 try enc.encode(.mov, &.{
1527 .{ .reg = .al },
1528 .{ .mem = Memory.moffs(.ds, 0x10) },
1529 });
14101530 try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10");
14111531
1412 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.cs, 0x10) }, .op2 = .{ .reg = .rax } });
1532 try enc.encode(.mov, &.{
1533 .{ .mem = Memory.moffs(.cs, 0x10) },
1534 .{ .reg = .rax },
1535 });
14131536 try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax");
14141537
1415 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.fs, 0x10) }, .op2 = .{ .reg = .eax } });
1538 try enc.encode(.mov, &.{
1539 .{ .mem = Memory.moffs(.fs, 0x10) },
1540 .{ .reg = .eax },
1541 });
14161542 try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax");
14171543
1418 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.gs, 0x10) }, .op2 = .{ .reg = .ax } });
1544 try enc.encode(.mov, &.{
1545 .{ .mem = Memory.moffs(.gs, 0x10) },
1546 .{ .reg = .ax },
1547 });
14191548 try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax");
14201549
1421 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.moffs(.ds, 0x10) }, .op2 = .{ .reg = .al } });
1550 try enc.encode(.mov, &.{
1551 .{ .mem = Memory.moffs(.ds, 0x10) },
1552 .{ .reg = .al },
1553 });
14221554 try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");
14231555}
14241556
14251557test "lower NP encoding" {
14261558 var enc = TestEncode{};
14271559
1428 try enc.encode(.int3, .{});
1560 try enc.encode(.int3, &.{});
14291561 try expectEqualHexStrings("\xCC", enc.code(), "int3");
14301562
1431 try enc.encode(.nop, .{});
1563 try enc.encode(.nop, &.{});
14321564 try expectEqualHexStrings("\x90", enc.code(), "nop");
14331565
1434 try enc.encode(.ret, .{});
1566 try enc.encode(.ret, &.{});
14351567 try expectEqualHexStrings("\xC3", enc.code(), "ret");
14361568
1437 try enc.encode(.syscall, .{});
1569 try enc.encode(.syscall, &.{});
14381570 try expectEqualHexStrings("\x0f\x05", enc.code(), "syscall");
14391571}
14401572
1441fn invalidInstruction(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
1442 const err = Instruction.new(mnemonic, args);
1573fn invalidInstruction(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
1574 const err = Instruction.new(.none, mnemonic, ops);
14431575 try testing.expectError(error.InvalidInstruction, err);
14441576}
14451577
14461578test "invalid instruction" {
1447 try invalidInstruction(.call, .{ .op1 = .{ .reg = .eax } });
1448 try invalidInstruction(.call, .{ .op1 = .{ .reg = .ax } });
1449 try invalidInstruction(.call, .{ .op1 = .{ .reg = .al } });
1450 try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.dword, 0) } });
1451 try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.word, 0) } });
1452 try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.byte, 0) } });
1453 try invalidInstruction(.mov, .{ .op1 = .{ .mem = Memory.rip(.word, 0x10) }, .op2 = .{ .reg = .r12 } });
1454 try invalidInstruction(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .rbx } });
1455 try invalidInstruction(.lea, .{ .op1 = .{ .reg = .al }, .op2 = .{ .mem = Memory.rip(.byte, 0) } });
1456 try invalidInstruction(.pop, .{ .op1 = .{ .reg = .r12b } });
1457 try invalidInstruction(.pop, .{ .op1 = .{ .reg = .r12d } });
1458 try invalidInstruction(.push, .{ .op1 = .{ .reg = .r12b } });
1459 try invalidInstruction(.push, .{ .op1 = .{ .reg = .r12d } });
1460 try invalidInstruction(.push, .{ .op1 = .{ .imm = Immediate.u(0x1000000000000000) } });
1579 try invalidInstruction(.call, &.{
1580 .{ .reg = .eax },
1581 });
1582 try invalidInstruction(.call, &.{
1583 .{ .reg = .ax },
1584 });
1585 try invalidInstruction(.call, &.{
1586 .{ .reg = .al },
1587 });
1588 try invalidInstruction(.call, &.{
1589 .{ .mem = Memory.rip(.dword, 0) },
1590 });
1591 try invalidInstruction(.call, &.{
1592 .{ .mem = Memory.rip(.word, 0) },
1593 });
1594 try invalidInstruction(.call, &.{
1595 .{ .mem = Memory.rip(.byte, 0) },
1596 });
1597 try invalidInstruction(.mov, &.{
1598 .{ .mem = Memory.rip(.word, 0x10) },
1599 .{ .reg = .r12 },
1600 });
1601 try invalidInstruction(.lea, &.{
1602 .{ .reg = .rax },
1603 .{ .reg = .rbx },
1604 });
1605 try invalidInstruction(.lea, &.{
1606 .{ .reg = .al },
1607 .{ .mem = Memory.rip(.byte, 0) },
1608 });
1609 try invalidInstruction(.pop, &.{
1610 .{ .reg = .r12b },
1611 });
1612 try invalidInstruction(.pop, &.{
1613 .{ .reg = .r12d },
1614 });
1615 try invalidInstruction(.push, &.{
1616 .{ .reg = .r12b },
1617 });
1618 try invalidInstruction(.push, &.{
1619 .{ .reg = .r12d },
1620 });
1621 try invalidInstruction(.push, &.{
1622 .{ .imm = Immediate.u(0x1000000000000000) },
1623 });
14611624}
14621625
1463fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
1464 try testing.expectError(error.CannotEncode, Instruction.new(mnemonic, args));
1626fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
1627 try testing.expectError(error.CannotEncode, Instruction.new(.none, mnemonic, ops));
14651628}
14661629
14671630test "cannot encode" {
1468 try cannotEncode(.@"test", .{
1469 .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
1470 .op2 = .{ .reg = .ah },
1631 try cannotEncode(.@"test", &.{
1632 .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
1633 .{ .reg = .ah },
14711634 });
1472 try cannotEncode(.@"test", .{
1473 .op1 = .{ .reg = .r11b },
1474 .op2 = .{ .reg = .bh },
1635 try cannotEncode(.@"test", &.{
1636 .{ .reg = .r11b },
1637 .{ .reg = .bh },
14751638 });
1476 try cannotEncode(.mov, .{
1477 .op1 = .{ .reg = .sil },
1478 .op2 = .{ .reg = .ah },
1639 try cannotEncode(.mov, &.{
1640 .{ .reg = .sil },
1641 .{ .reg = .ah },
14791642 });
14801643}
14811644
......@@ -1645,12 +1808,7 @@ const Assembler = struct {
16451808
16461809 pub fn assemble(as: *Assembler, writer: anytype) !void {
16471810 while (try as.next()) |parsed_inst| {
1648 const inst = try Instruction.new(parsed_inst.mnemonic, .{
1649 .op1 = parsed_inst.ops[0],
1650 .op2 = parsed_inst.ops[1],
1651 .op3 = parsed_inst.ops[2],
1652 .op4 = parsed_inst.ops[3],
1653 });
1811 const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
16541812 try inst.encode(writer);
16551813 }
16561814 }
src/arch/x86_64/encodings.zig+837-832
......@@ -6,869 +6,874 @@ const Mode = Encoding.Mode;
66
77const modrm_ext = u3;
88
9const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, []const u8, modrm_ext, Mode };
9pub const Entry = struct { Mnemonic, OpEn, []const Op, []const u8, modrm_ext, Mode };
1010
1111// TODO move this into a .zon file when Zig is capable of importing .zon files
1212// zig fmt: off
13pub const table = &[_]Entry{
13pub const table = [_]Entry{
1414 // General-purpose
15 .{ .adc, .zi, .al, .imm8, .none, .none, &.{ 0x14 }, 0, .none },
16 .{ .adc, .zi, .ax, .imm16, .none, .none, &.{ 0x15 }, 0, .none },
17 .{ .adc, .zi, .eax, .imm32, .none, .none, &.{ 0x15 }, 0, .none },
18 .{ .adc, .zi, .rax, .imm32s, .none, .none, &.{ 0x15 }, 0, .long },
19 .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .none },
20 .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .rex },
21 .{ .adc, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 2, .none },
22 .{ .adc, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 2, .none },
23 .{ .adc, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 2, .long },
24 .{ .adc, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 2, .none },
25 .{ .adc, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 2, .none },
26 .{ .adc, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 2, .long },
27 .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .none },
28 .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .rex },
29 .{ .adc, .mr, .rm16, .r16, .none, .none, &.{ 0x11 }, 0, .none },
30 .{ .adc, .mr, .rm32, .r32, .none, .none, &.{ 0x11 }, 0, .none },
31 .{ .adc, .mr, .rm64, .r64, .none, .none, &.{ 0x11 }, 0, .long },
32 .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .none },
33 .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .rex },
34 .{ .adc, .rm, .r16, .rm16, .none, .none, &.{ 0x13 }, 0, .none },
35 .{ .adc, .rm, .r32, .rm32, .none, .none, &.{ 0x13 }, 0, .none },
36 .{ .adc, .rm, .r64, .rm64, .none, .none, &.{ 0x13 }, 0, .long },
37
38 .{ .add, .zi, .al, .imm8, .none, .none, &.{ 0x04 }, 0, .none },
39 .{ .add, .zi, .ax, .imm16, .none, .none, &.{ 0x05 }, 0, .none },
40 .{ .add, .zi, .eax, .imm32, .none, .none, &.{ 0x05 }, 0, .none },
41 .{ .add, .zi, .rax, .imm32s, .none, .none, &.{ 0x05 }, 0, .long },
42 .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .none },
43 .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .rex },
44 .{ .add, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 0, .none },
45 .{ .add, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 0, .none },
46 .{ .add, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 0, .long },
47 .{ .add, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 0, .none },
48 .{ .add, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 0, .none },
49 .{ .add, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 0, .long },
50 .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .none },
51 .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .rex },
52 .{ .add, .mr, .rm16, .r16, .none, .none, &.{ 0x01 }, 0, .none },
53 .{ .add, .mr, .rm32, .r32, .none, .none, &.{ 0x01 }, 0, .none },
54 .{ .add, .mr, .rm64, .r64, .none, .none, &.{ 0x01 }, 0, .long },
55 .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .none },
56 .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .rex },
57 .{ .add, .rm, .r16, .rm16, .none, .none, &.{ 0x03 }, 0, .none },
58 .{ .add, .rm, .r32, .rm32, .none, .none, &.{ 0x03 }, 0, .none },
59 .{ .add, .rm, .r64, .rm64, .none, .none, &.{ 0x03 }, 0, .long },
60
61 .{ .@"and", .zi, .al, .imm8, .none, .none, &.{ 0x24 }, 0, .none },
62 .{ .@"and", .zi, .ax, .imm16, .none, .none, &.{ 0x25 }, 0, .none },
63 .{ .@"and", .zi, .eax, .imm32, .none, .none, &.{ 0x25 }, 0, .none },
64 .{ .@"and", .zi, .rax, .imm32s, .none, .none, &.{ 0x25 }, 0, .long },
65 .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .none },
66 .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .rex },
67 .{ .@"and", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 4, .none },
68 .{ .@"and", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 4, .none },
69 .{ .@"and", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 4, .long },
70 .{ .@"and", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 4, .none },
71 .{ .@"and", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 4, .none },
72 .{ .@"and", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 4, .long },
73 .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .none },
74 .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .rex },
75 .{ .@"and", .mr, .rm16, .r16, .none, .none, &.{ 0x21 }, 0, .none },
76 .{ .@"and", .mr, .rm32, .r32, .none, .none, &.{ 0x21 }, 0, .none },
77 .{ .@"and", .mr, .rm64, .r64, .none, .none, &.{ 0x21 }, 0, .long },
78 .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .none },
79 .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .rex },
80 .{ .@"and", .rm, .r16, .rm16, .none, .none, &.{ 0x23 }, 0, .none },
81 .{ .@"and", .rm, .r32, .rm32, .none, .none, &.{ 0x23 }, 0, .none },
82 .{ .@"and", .rm, .r64, .rm64, .none, .none, &.{ 0x23 }, 0, .long },
83
84 .{ .bsf, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbc }, 0, .none },
85 .{ .bsf, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbc }, 0, .none },
86 .{ .bsf, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbc }, 0, .long },
87
88 .{ .bsr, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },
89 .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },
90 .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long },
91
92 .{ .bswap, .o, .r32, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .none },
93 .{ .bswap, .o, .r64, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .long },
94
95 .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },
96 .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },
97 .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long },
98 .{ .bt, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none },
99 .{ .bt, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none },
100 .{ .bt, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .long },
101
102 .{ .btc, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xbb }, 0, .none },
103 .{ .btc, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xbb }, 0, .none },
104 .{ .btc, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xbb }, 0, .long },
105 .{ .btc, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none },
106 .{ .btc, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none },
107 .{ .btc, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .long },
108
109 .{ .btr, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none },
110 .{ .btr, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none },
111 .{ .btr, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb3 }, 0, .long },
112 .{ .btr, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none },
113 .{ .btr, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none },
114 .{ .btr, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .long },
115
116 .{ .bts, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xab }, 0, .none },
117 .{ .bts, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xab }, 0, .none },
118 .{ .bts, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xab }, 0, .long },
119 .{ .bts, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none },
120 .{ .bts, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none },
121 .{ .bts, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .long },
15 .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none },
16 .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .none },
17 .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none },
18 .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long },
19 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none },
20 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex },
21 .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .none },
22 .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none },
23 .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long },
24 .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .none },
25 .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none },
26 .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long },
27 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none },
28 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex },
29 .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .none },
30 .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none },
31 .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long },
32 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none },
33 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex },
34 .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .none },
35 .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none },
36 .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long },
37
38 .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none },
39 .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .none },
40 .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none },
41 .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long },
42 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none },
43 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex },
44 .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .none },
45 .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none },
46 .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long },
47 .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .none },
48 .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none },
49 .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long },
50 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none },
51 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex },
52 .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .none },
53 .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none },
54 .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long },
55 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none },
56 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex },
57 .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .none },
58 .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none },
59 .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long },
60
61 .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none },
62 .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .none },
63 .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none },
64 .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long },
65 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none },
66 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex },
67 .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .none },
68 .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none },
69 .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long },
70 .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .none },
71 .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none },
72 .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long },
73 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none },
74 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex },
75 .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .none },
76 .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none },
77 .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long },
78 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none },
79 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex },
80 .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .none },
81 .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none },
82 .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long },
83
84 .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .none },
85 .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none },
86 .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long },
87
88 .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .none },
89 .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none },
90 .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long },
91
92 .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none },
93 .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long },
94
95 .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .none },
96 .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none },
97 .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long },
98 .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },
99 .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },
100 .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long },
101
102 .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .none },
103 .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none },
104 .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long },
105 .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },
106 .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },
107 .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long },
108
109 .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .none },
110 .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none },
111 .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long },
112 .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },
113 .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },
114 .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long },
115
116 .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .none },
117 .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none },
118 .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long },
119 .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },
120 .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },
121 .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long },
122122
123123 // This is M encoding according to Intel, but D makes more sense here.
124 .{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none },
125 .{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none },
126
127 .{ .cbw, .np, .o16, .none, .none, .none, &.{ 0x98 }, 0, .none },
128 .{ .cwde, .np, .o32, .none, .none, .none, &.{ 0x98 }, 0, .none },
129 .{ .cdqe, .np, .o64, .none, .none, .none, &.{ 0x98 }, 0, .long },
130
131 .{ .cwd, .np, .o16, .none, .none, .none, &.{ 0x99 }, 0, .none },
132 .{ .cdq, .np, .o32, .none, .none, .none, &.{ 0x99 }, 0, .none },
133 .{ .cqo, .np, .o64, .none, .none, .none, &.{ 0x99 }, 0, .long },
134
135 .{ .cmova, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
136 .{ .cmova, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
137 .{ .cmova, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long },
138 .{ .cmovae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
139 .{ .cmovae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
140 .{ .cmovae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },
141 .{ .cmovb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
142 .{ .cmovb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
143 .{ .cmovb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },
144 .{ .cmovbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
145 .{ .cmovbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
146 .{ .cmovbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long },
147 .{ .cmovc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
148 .{ .cmovc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
149 .{ .cmovc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },
150 .{ .cmove, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
151 .{ .cmove, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
152 .{ .cmove, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long },
153 .{ .cmovg, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
154 .{ .cmovg, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
155 .{ .cmovg, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long },
156 .{ .cmovge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
157 .{ .cmovge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
158 .{ .cmovge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long },
159 .{ .cmovl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
160 .{ .cmovl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
161 .{ .cmovl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long },
162 .{ .cmovle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
163 .{ .cmovle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
164 .{ .cmovle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long },
165 .{ .cmovna, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
166 .{ .cmovna, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
167 .{ .cmovna, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long },
168 .{ .cmovnae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
169 .{ .cmovnae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
170 .{ .cmovnae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },
171 .{ .cmovnb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
172 .{ .cmovnb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
173 .{ .cmovnb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },
174 .{ .cmovnbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
175 .{ .cmovnbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
176 .{ .cmovnbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long },
177 .{ .cmovnc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
178 .{ .cmovnc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
179 .{ .cmovnc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },
180 .{ .cmovne, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
181 .{ .cmovne, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
182 .{ .cmovne, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long },
183 .{ .cmovng, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
184 .{ .cmovng, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
185 .{ .cmovng, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long },
186 .{ .cmovnge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
187 .{ .cmovnge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
188 .{ .cmovnge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long },
189 .{ .cmovnl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
190 .{ .cmovnl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
191 .{ .cmovnl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long },
192 .{ .cmovnle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
193 .{ .cmovnle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
194 .{ .cmovnle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long },
195 .{ .cmovno, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x41 }, 0, .none },
196 .{ .cmovno, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x41 }, 0, .none },
197 .{ .cmovno, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x41 }, 0, .long },
198 .{ .cmovnp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
199 .{ .cmovnp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
200 .{ .cmovnp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long },
201 .{ .cmovns, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x49 }, 0, .none },
202 .{ .cmovns, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x49 }, 0, .none },
203 .{ .cmovns, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x49 }, 0, .long },
204 .{ .cmovnz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
205 .{ .cmovnz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
206 .{ .cmovnz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long },
207 .{ .cmovo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x40 }, 0, .none },
208 .{ .cmovo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x40 }, 0, .none },
209 .{ .cmovo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x40 }, 0, .long },
210 .{ .cmovp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
211 .{ .cmovp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
212 .{ .cmovp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long },
213 .{ .cmovpe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
214 .{ .cmovpe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
215 .{ .cmovpe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long },
216 .{ .cmovpo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
217 .{ .cmovpo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
218 .{ .cmovpo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long },
219 .{ .cmovs, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x48 }, 0, .none },
220 .{ .cmovs, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x48 }, 0, .none },
221 .{ .cmovs, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x48 }, 0, .long },
222 .{ .cmovz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
223 .{ .cmovz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
224 .{ .cmovz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long },
225
226 .{ .cmp, .zi, .al, .imm8, .none, .none, &.{ 0x3c }, 0, .none },
227 .{ .cmp, .zi, .ax, .imm16, .none, .none, &.{ 0x3d }, 0, .none },
228 .{ .cmp, .zi, .eax, .imm32, .none, .none, &.{ 0x3d }, 0, .none },
229 .{ .cmp, .zi, .rax, .imm32s, .none, .none, &.{ 0x3d }, 0, .long },
230 .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .none },
231 .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .rex },
232 .{ .cmp, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 7, .none },
233 .{ .cmp, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 7, .none },
234 .{ .cmp, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 7, .long },
235 .{ .cmp, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 7, .none },
236 .{ .cmp, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 7, .none },
237 .{ .cmp, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 7, .long },
238 .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .none },
239 .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .rex },
240 .{ .cmp, .mr, .rm16, .r16, .none, .none, &.{ 0x39 }, 0, .none },
241 .{ .cmp, .mr, .rm32, .r32, .none, .none, &.{ 0x39 }, 0, .none },
242 .{ .cmp, .mr, .rm64, .r64, .none, .none, &.{ 0x39 }, 0, .long },
243 .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .none },
244 .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .rex },
245 .{ .cmp, .rm, .r16, .rm16, .none, .none, &.{ 0x3b }, 0, .none },
246 .{ .cmp, .rm, .r32, .rm32, .none, .none, &.{ 0x3b }, 0, .none },
247 .{ .cmp, .rm, .r64, .rm64, .none, .none, &.{ 0x3b }, 0, .long },
248
249 .{ .cmps, .np, .m8, .m8, .none, .none, &.{ 0xa6 }, 0, .none },
250 .{ .cmps, .np, .m16, .m16, .none, .none, &.{ 0xa7 }, 0, .none },
251 .{ .cmps, .np, .m32, .m32, .none, .none, &.{ 0xa7 }, 0, .none },
252 .{ .cmps, .np, .m64, .m64, .none, .none, &.{ 0xa7 }, 0, .long },
253 .{ .cmpsb, .np, .none, .none, .none, .none, &.{ 0xa6 }, 0, .none },
254 .{ .cmpsw, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .short },
255 .{ .cmpsd, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .none },
256 .{ .cmpsq, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .long },
257
258 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },
259 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },
260 .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },
261 .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },
262 .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },
263
264 .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },
265 .{ .cmpxchg16b, .m, .m128, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .long },
266
267 .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none },
268 .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex },
269 .{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none },
270 .{ .div, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 6, .none },
271 .{ .div, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 6, .long },
272
273 .{ .fisttp, .m, .m16, .none, .none, .none, &.{ 0xdf }, 1, .fpu },
274 .{ .fisttp, .m, .m32, .none, .none, .none, &.{ 0xdb }, 1, .fpu },
275 .{ .fisttp, .m, .m64, .none, .none, .none, &.{ 0xdd }, 1, .fpu },
276
277 .{ .fld, .m, .m32, .none, .none, .none, &.{ 0xd9 }, 0, .fpu },
278 .{ .fld, .m, .m64, .none, .none, .none, &.{ 0xdd }, 0, .fpu },
279 .{ .fld, .m, .m80, .none, .none, .none, &.{ 0xdb }, 5, .fpu },
280
281 .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .none },
282 .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .rex },
283 .{ .idiv, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 7, .none },
284 .{ .idiv, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 7, .none },
285 .{ .idiv, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 7, .long },
286
287 .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .none },
288 .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .rex },
289 .{ .imul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 5, .none },
290 .{ .imul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 5, .none },
291 .{ .imul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 5, .long },
292 .{ .imul, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xaf }, 0, .none },
293 .{ .imul, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xaf }, 0, .none },
294 .{ .imul, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xaf }, 0, .long },
295 .{ .imul, .rmi, .r16, .rm16, .imm8s, .none, &.{ 0x6b }, 0, .none },
296 .{ .imul, .rmi, .r32, .rm32, .imm8s, .none, &.{ 0x6b }, 0, .none },
297 .{ .imul, .rmi, .r64, .rm64, .imm8s, .none, &.{ 0x6b }, 0, .long },
298 .{ .imul, .rmi, .r16, .rm16, .imm16, .none, &.{ 0x69 }, 0, .none },
299 .{ .imul, .rmi, .r32, .rm32, .imm32, .none, &.{ 0x69 }, 0, .none },
300 .{ .imul, .rmi, .r64, .rm64, .imm32, .none, &.{ 0x69 }, 0, .long },
301
302 .{ .int3, .np, .none, .none, .none, .none, &.{ 0xcc }, 0, .none },
303
304 .{ .ja, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none },
305 .{ .jae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },
306 .{ .jb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },
307 .{ .jbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none },
308 .{ .jc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },
309 .{ .jrcxz, .d, .rel32, .none, .none, .none, &.{ 0xe3 }, 0, .none },
310 .{ .je, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none },
311 .{ .jg, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none },
312 .{ .jge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none },
313 .{ .jl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none },
314 .{ .jle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none },
315 .{ .jna, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none },
316 .{ .jnae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },
317 .{ .jnb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },
318 .{ .jnbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none },
319 .{ .jnc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },
320 .{ .jne, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none },
321 .{ .jng, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none },
322 .{ .jnge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none },
323 .{ .jnl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none },
324 .{ .jnle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none },
325 .{ .jno, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x81 }, 0, .none },
326 .{ .jnp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none },
327 .{ .jns, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x89 }, 0, .none },
328 .{ .jnz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none },
329 .{ .jo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x80 }, 0, .none },
330 .{ .jp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none },
331 .{ .jpe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none },
332 .{ .jpo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none },
333 .{ .js, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x88 }, 0, .none },
334 .{ .jz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none },
335
336 .{ .jmp, .d, .rel32, .none, .none, .none, &.{ 0xe9 }, 0, .none },
337 .{ .jmp, .m, .rm64, .none, .none, .none, &.{ 0xff }, 4, .none },
338
339 .{ .lea, .rm, .r16, .m, .none, .none, &.{ 0x8d }, 0, .none },
340 .{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none },
341 .{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long },
342
343 .{ .lfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },
344
345 .{ .lods, .np, .m8, .none, .none, .none, &.{ 0xac }, 0, .none },
346 .{ .lods, .np, .m16, .none, .none, .none, &.{ 0xad }, 0, .none },
347 .{ .lods, .np, .m32, .none, .none, .none, &.{ 0xad }, 0, .none },
348 .{ .lods, .np, .m64, .none, .none, .none, &.{ 0xad }, 0, .long },
349 .{ .lodsb, .np, .none, .none, .none, .none, &.{ 0xac }, 0, .none },
350 .{ .lodsw, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .short },
351 .{ .lodsd, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .none },
352 .{ .lodsq, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .long },
353
354 .{ .lzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
355 .{ .lzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
356 .{ .lzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
357
358 .{ .mfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },
359
360 .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },
361 .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },
362 .{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },
363 .{ .mov, .mr, .rm32, .r32, .none, .none, &.{ 0x89 }, 0, .none },
364 .{ .mov, .mr, .rm64, .r64, .none, .none, &.{ 0x89 }, 0, .long },
365 .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .none },
366 .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .rex },
367 .{ .mov, .rm, .r16, .rm16, .none, .none, &.{ 0x8b }, 0, .none },
368 .{ .mov, .rm, .r32, .rm32, .none, .none, &.{ 0x8b }, 0, .none },
369 .{ .mov, .rm, .r64, .rm64, .none, .none, &.{ 0x8b }, 0, .long },
370 .{ .mov, .mr, .rm16, .sreg, .none, .none, &.{ 0x8c }, 0, .none },
371 .{ .mov, .mr, .rm64, .sreg, .none, .none, &.{ 0x8c }, 0, .long },
372 .{ .mov, .rm, .sreg, .rm16, .none, .none, &.{ 0x8e }, 0, .none },
373 .{ .mov, .rm, .sreg, .rm64, .none, .none, &.{ 0x8e }, 0, .long },
374 .{ .mov, .fd, .al, .moffs, .none, .none, &.{ 0xa0 }, 0, .none },
375 .{ .mov, .fd, .ax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none },
376 .{ .mov, .fd, .eax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none },
377 .{ .mov, .fd, .rax, .moffs, .none, .none, &.{ 0xa1 }, 0, .long },
378 .{ .mov, .td, .moffs, .al, .none, .none, &.{ 0xa2 }, 0, .none },
379 .{ .mov, .td, .moffs, .ax, .none, .none, &.{ 0xa3 }, 0, .none },
380 .{ .mov, .td, .moffs, .eax, .none, .none, &.{ 0xa3 }, 0, .none },
381 .{ .mov, .td, .moffs, .rax, .none, .none, &.{ 0xa3 }, 0, .long },
382 .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .none },
383 .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .rex },
384 .{ .mov, .oi, .r16, .imm16, .none, .none, &.{ 0xb8 }, 0, .none },
385 .{ .mov, .oi, .r32, .imm32, .none, .none, &.{ 0xb8 }, 0, .none },
386 .{ .mov, .oi, .r64, .imm64, .none, .none, &.{ 0xb8 }, 0, .long },
387 .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .none },
388 .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .rex },
389 .{ .mov, .mi, .rm16, .imm16, .none, .none, &.{ 0xc7 }, 0, .none },
390 .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none },
391 .{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long },
392
393 .{ .movbe, .rm, .r16, .m16, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
394 .{ .movbe, .rm, .r32, .m32, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
395 .{ .movbe, .rm, .r64, .m64, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },
396 .{ .movbe, .mr, .m16, .r16, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
397 .{ .movbe, .mr, .m32, .r32, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
398 .{ .movbe, .mr, .m64, .r64, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },
399
400 .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none },
401 .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none },
402 .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none },
403 .{ .movs, .np, .m64, .m64, .none, .none, &.{ 0xa5 }, 0, .long },
404 .{ .movsb, .np, .none, .none, .none, .none, &.{ 0xa4 }, 0, .none },
405 .{ .movsw, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .short },
406 .{ .movsd, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .none },
407 .{ .movsq, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .long },
408
409 .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },
410 .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },
411 .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },
412 .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },
413 .{ .movsx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .long },
414 .{ .movsx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .none },
415 .{ .movsx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .long },
124 .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none },
125 .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none },
126
127 .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .none },
128 .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none },
129 .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long },
130
131 .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .none },
132 .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none },
133 .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long },
134
135 .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },
136 .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },
137 .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },
138 .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
139 .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
140 .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
141 .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
142 .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
143 .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
144 .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },
145 .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },
146 .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },
147 .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
148 .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
149 .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
150 .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },
151 .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },
152 .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },
153 .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },
154 .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },
155 .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },
156 .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },
157 .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },
158 .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },
159 .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },
160 .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },
161 .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },
162 .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },
163 .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },
164 .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },
165 .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },
166 .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },
167 .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },
168 .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
169 .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
170 .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
171 .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
172 .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
173 .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
174 .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },
175 .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },
176 .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },
177 .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
178 .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
179 .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
180 .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },
181 .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },
182 .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },
183 .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },
184 .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },
185 .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },
186 .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },
187 .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },
188 .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },
189 .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },
190 .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },
191 .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },
192 .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },
193 .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },
194 .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },
195 .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .none },
196 .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none },
197 .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long },
198 .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },
199 .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },
200 .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },
201 .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .none },
202 .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none },
203 .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long },
204 .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },
205 .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },
206 .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },
207 .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .none },
208 .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none },
209 .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long },
210 .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },
211 .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },
212 .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },
213 .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },
214 .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },
215 .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },
216 .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },
217 .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },
218 .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },
219 .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .none },
220 .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none },
221 .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long },
222 .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },
223 .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },
224 .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },
225
226 .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none },
227 .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .none },
228 .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none },
229 .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long },
230 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none },
231 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex },
232 .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .none },
233 .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none },
234 .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long },
235 .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .none },
236 .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none },
237 .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long },
238 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none },
239 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex },
240 .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .none },
241 .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none },
242 .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long },
243 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none },
244 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex },
245 .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .none },
246 .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none },
247 .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long },
248
249 .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none },
250 .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .none },
251 .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none },
252 .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long },
253
254 .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none },
255 .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short },
256 .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none },
257 .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long },
258
259 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none },
260 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex },
261 .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .none },
262 .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none },
263 .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long },
264
265 .{ .cmpxchg8b , .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none },
266 .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long },
267
268 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none },
269 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex },
270 .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .none },
271 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none },
272 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long },
273
274 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .fpu },
275 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .fpu },
276 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .fpu },
277
278 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .fpu },
279 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .fpu },
280 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .fpu },
281
282 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none },
283 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex },
284 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .none },
285 .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none },
286 .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long },
287
288 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none },
289 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex },
290 .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .none },
291 .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none },
292 .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long },
293 .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .none },
294 .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none },
295 .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long },
296 .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .none },
297 .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none },
298 .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long },
299 .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .none },
300 .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none },
301 .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long },
302
303 .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none },
304
305 .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },
306 .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
307 .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
308 .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },
309 .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
310 .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none },
311 .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },
312 .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },
313 .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },
314 .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },
315 .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },
316 .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },
317 .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
318 .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
319 .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },
320 .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
321 .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },
322 .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },
323 .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },
324 .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },
325 .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },
326 .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none },
327 .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },
328 .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none },
329 .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },
330 .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none },
331 .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },
332 .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },
333 .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },
334 .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none },
335 .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },
336
337 .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none },
338 .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none },
339
340 .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .none },
341 .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none },
342 .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long },
343
344 .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },
345
346 .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none },
347 .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .none },
348 .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none },
349 .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long },
350
351 .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none },
352 .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short },
353 .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none },
354 .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long },
355
356 .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
357 .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
358 .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
359
360 .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },
361
362 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none },
363 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex },
364 .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .none },
365 .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none },
366 .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long },
367 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none },
368 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex },
369 .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .none },
370 .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none },
371 .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long },
372 .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .none },
373 .{ .mov, .mr, &.{ .rm64, .sreg }, &.{ 0x8c }, 0, .long },
374 .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .none },
375 .{ .mov, .rm, &.{ .sreg, .rm64 }, &.{ 0x8e }, 0, .long },
376 .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none },
377 .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none },
378 .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none },
379 .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long },
380 .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none },
381 .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none },
382 .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none },
383 .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long },
384 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none },
385 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex },
386 .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .none },
387 .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none },
388 .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long },
389 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none },
390 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex },
391 .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .none },
392 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none },
393 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long },
394
395 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
396 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
397 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },
398 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
399 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
400 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },
401
402 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none },
403 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .none },
404 .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none },
405 .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long },
406
407 .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none },
408 .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short },
409 .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none },
410 .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long },
411
412 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },
413 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },
414 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },
415 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },
416 .{ .movsx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xbe }, 0, .long },
417 .{ .movsx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xbf }, 0, .none },
418 .{ .movsx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xbf }, 0, .long },
416419
417420 // This instruction is discouraged.
418 .{ .movsxd, .rm, .r32, .rm32, .none, .none, &.{ 0x63 }, 0, .none },
419 .{ .movsxd, .rm, .r64, .rm32, .none, .none, &.{ 0x63 }, 0, .long },
420
421 .{ .movzx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none },
422 .{ .movzx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none },
423 .{ .movzx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .long },
424 .{ .movzx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .none },
425 .{ .movzx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .long },
426
427 .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .none },
428 .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .rex },
429 .{ .mul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 4, .none },
430 .{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none },
431 .{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long },
432
433 .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .none },
434 .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .rex },
435 .{ .neg, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 3, .none },
436 .{ .neg, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 3, .none },
437 .{ .neg, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 3, .long },
438
439 .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none },
440
441 .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .none },
442 .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .rex },
443 .{ .not, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 2, .none },
444 .{ .not, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 2, .none },
445 .{ .not, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 2, .long },
446
447 .{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none },
448 .{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none },
449 .{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none },
450 .{ .@"or", .zi, .rax, .imm32s, .none, .none, &.{ 0x0d }, 0, .long },
451 .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .none },
452 .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .rex },
453 .{ .@"or", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 1, .none },
454 .{ .@"or", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 1, .none },
455 .{ .@"or", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 1, .long },
456 .{ .@"or", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 1, .none },
457 .{ .@"or", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 1, .none },
458 .{ .@"or", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 1, .long },
459 .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .none },
460 .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .rex },
461 .{ .@"or", .mr, .rm16, .r16, .none, .none, &.{ 0x09 }, 0, .none },
462 .{ .@"or", .mr, .rm32, .r32, .none, .none, &.{ 0x09 }, 0, .none },
463 .{ .@"or", .mr, .rm64, .r64, .none, .none, &.{ 0x09 }, 0, .long },
464 .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .none },
465 .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .rex },
466 .{ .@"or", .rm, .r16, .rm16, .none, .none, &.{ 0x0b }, 0, .none },
467 .{ .@"or", .rm, .r32, .rm32, .none, .none, &.{ 0x0b }, 0, .none },
468 .{ .@"or", .rm, .r64, .rm64, .none, .none, &.{ 0x0b }, 0, .long },
469
470 .{ .pop, .o, .r16, .none, .none, .none, &.{ 0x58 }, 0, .none },
471 .{ .pop, .o, .r64, .none, .none, .none, &.{ 0x58 }, 0, .none },
472 .{ .pop, .m, .rm16, .none, .none, .none, &.{ 0x8f }, 0, .none },
473 .{ .pop, .m, .rm64, .none, .none, .none, &.{ 0x8f }, 0, .none },
474
475 .{ .popcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
476 .{ .popcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
477 .{ .popcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },
478
479 .{ .push, .o, .r16, .none, .none, .none, &.{ 0x50 }, 0, .none },
480 .{ .push, .o, .r64, .none, .none, .none, &.{ 0x50 }, 0, .none },
481 .{ .push, .m, .rm16, .none, .none, .none, &.{ 0xff }, 6, .none },
482 .{ .push, .m, .rm64, .none, .none, .none, &.{ 0xff }, 6, .none },
483 .{ .push, .i, .imm8, .none, .none, .none, &.{ 0x6a }, 0, .none },
484 .{ .push, .i, .imm16, .none, .none, .none, &.{ 0x68 }, 0, .none },
485 .{ .push, .i, .imm32, .none, .none, .none, &.{ 0x68 }, 0, .none },
486
487 .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none },
488
489 .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .none },
490 .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .rex },
491 .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .none },
492 .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .rex },
493 .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .none },
494 .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .rex },
495 .{ .rcl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 2, .none },
496 .{ .rcl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 2, .none },
497 .{ .rcl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 2, .none },
498 .{ .rcl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 2, .none },
499 .{ .rcl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 2, .long },
500 .{ .rcl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 2, .none },
501 .{ .rcl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 2, .long },
502 .{ .rcl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 2, .none },
503 .{ .rcl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 2, .long },
504
505 .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .none },
506 .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .rex },
507 .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .none },
508 .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .rex },
509 .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .none },
510 .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .rex },
511 .{ .rcr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 3, .none },
512 .{ .rcr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 3, .none },
513 .{ .rcr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 3, .none },
514 .{ .rcr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 3, .none },
515 .{ .rcr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 3, .long },
516 .{ .rcr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 3, .none },
517 .{ .rcr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 3, .long },
518 .{ .rcr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 3, .none },
519 .{ .rcr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 3, .long },
520
521 .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .none },
522 .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .rex },
523 .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .none },
524 .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .rex },
525 .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .none },
526 .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .rex },
527 .{ .rol, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 0, .none },
528 .{ .rol, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 0, .none },
529 .{ .rol, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 0, .none },
530 .{ .rol, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 0, .none },
531 .{ .rol, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 0, .long },
532 .{ .rol, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 0, .none },
533 .{ .rol, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 0, .long },
534 .{ .rol, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 0, .none },
535 .{ .rol, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 0, .long },
536
537 .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .none },
538 .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .rex },
539 .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .none },
540 .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .rex },
541 .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .none },
542 .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .rex },
543 .{ .ror, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 1, .none },
544 .{ .ror, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 1, .none },
545 .{ .ror, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 1, .none },
546 .{ .ror, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 1, .none },
547 .{ .ror, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 1, .long },
548 .{ .ror, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 1, .none },
549 .{ .ror, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 1, .long },
550 .{ .ror, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 1, .none },
551 .{ .ror, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 1, .long },
552
553 .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
554 .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
555 .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
556 .{ .sal, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
557 .{ .sal, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long },
558 .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none },
559 .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex },
560 .{ .sal, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
561 .{ .sal, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
562 .{ .sal, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long },
563 .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none },
564 .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex },
565 .{ .sal, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
566 .{ .sal, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
567 .{ .sal, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },
568
569 .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .none },
570 .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .rex },
571 .{ .sar, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 7, .none },
572 .{ .sar, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 7, .none },
573 .{ .sar, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 7, .long },
574 .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .none },
575 .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .rex },
576 .{ .sar, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 7, .none },
577 .{ .sar, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 7, .none },
578 .{ .sar, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 7, .long },
579 .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .none },
580 .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .rex },
581 .{ .sar, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 7, .none },
582 .{ .sar, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 7, .none },
583 .{ .sar, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 7, .long },
584
585 .{ .sbb, .zi, .al, .imm8, .none, .none, &.{ 0x1c }, 0, .none },
586 .{ .sbb, .zi, .ax, .imm16, .none, .none, &.{ 0x1d }, 0, .none },
587 .{ .sbb, .zi, .eax, .imm32, .none, .none, &.{ 0x1d }, 0, .none },
588 .{ .sbb, .zi, .rax, .imm32s, .none, .none, &.{ 0x1d }, 0, .long },
589 .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .none },
590 .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .rex },
591 .{ .sbb, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 3, .none },
592 .{ .sbb, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 3, .none },
593 .{ .sbb, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 3, .long },
594 .{ .sbb, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 3, .none },
595 .{ .sbb, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 3, .none },
596 .{ .sbb, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 3, .long },
597 .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .none },
598 .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .rex },
599 .{ .sbb, .mr, .rm16, .r16, .none, .none, &.{ 0x19 }, 0, .none },
600 .{ .sbb, .mr, .rm32, .r32, .none, .none, &.{ 0x19 }, 0, .none },
601 .{ .sbb, .mr, .rm64, .r64, .none, .none, &.{ 0x19 }, 0, .long },
602 .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .none },
603 .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .rex },
604 .{ .sbb, .rm, .r16, .rm16, .none, .none, &.{ 0x1b }, 0, .none },
605 .{ .sbb, .rm, .r32, .rm32, .none, .none, &.{ 0x1b }, 0, .none },
606 .{ .sbb, .rm, .r64, .rm64, .none, .none, &.{ 0x1b }, 0, .long },
607
608 .{ .scas, .np, .m8, .none, .none, .none, &.{ 0xae }, 0, .none },
609 .{ .scas, .np, .m16, .none, .none, .none, &.{ 0xaf }, 0, .none },
610 .{ .scas, .np, .m32, .none, .none, .none, &.{ 0xaf }, 0, .none },
611 .{ .scas, .np, .m64, .none, .none, .none, &.{ 0xaf }, 0, .long },
612 .{ .scasb, .np, .none, .none, .none, .none, &.{ 0xae }, 0, .none },
613 .{ .scasw, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .short },
614 .{ .scasd, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .none },
615 .{ .scasq, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .long },
616
617 .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },
618 .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },
619 .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
620 .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },
621 .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },
622 .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },
623 .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none },
624 .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex },
625 .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },
626 .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },
627 .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },
628 .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },
629 .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none },
630 .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex },
631 .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none },
632 .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex },
633 .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none },
634 .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex },
635 .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none },
636 .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex },
637 .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none },
638 .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex },
639 .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },
640 .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },
641 .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
642 .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },
643 .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },
644 .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },
645 .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
646 .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },
647 .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none },
648 .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex },
649 .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none },
650 .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex },
651 .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none },
652 .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex },
653 .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none },
654 .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex },
655 .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none },
656 .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex },
657 .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .none },
658 .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .rex },
659 .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none },
660 .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex },
661 .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .none },
662 .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .rex },
663 .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none },
664 .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex },
665 .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .none },
666 .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .rex },
667 .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none },
668 .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex },
669 .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none },
670 .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex },
671 .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none },
672 .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex },
673 .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .none },
674 .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .rex },
675 .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },
676 .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },
677
678 .{ .sfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },
679
680 .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
681 .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
682 .{ .shl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
683 .{ .shl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
684 .{ .shl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long },
685 .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none },
686 .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex },
687 .{ .shl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
688 .{ .shl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
689 .{ .shl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long },
690 .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none },
691 .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex },
692 .{ .shl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
693 .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
694 .{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },
695
696 .{ .shld, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },
697 .{ .shld, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },
698 .{ .shld, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },
699 .{ .shld, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .long },
700 .{ .shld, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },
701 .{ .shld, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .long },
702
703 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },
704 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },
705 .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
706 .{ .shr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
707 .{ .shr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 5, .long },
708 .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .none },
709 .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .rex },
710 .{ .shr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 5, .none },
711 .{ .shr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 5, .none },
712 .{ .shr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 5, .long },
713 .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .none },
714 .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .rex },
715 .{ .shr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
716 .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
717 .{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },
718
719 .{ .shrd, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },
720 .{ .shrd, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },
721 .{ .shrd, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },
722 .{ .shrd, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xac }, 0, .long },
723 .{ .shrd, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },
724 .{ .shrd, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xad }, 0, .long },
725
726 .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },
727 .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },
728 .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },
729 .{ .stos, .np, .m64, .none, .none, .none, &.{ 0xab }, 0, .long },
730 .{ .stosb, .np, .none, .none, .none, .none, &.{ 0xaa }, 0, .none },
731 .{ .stosw, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .short },
732 .{ .stosd, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .none },
733 .{ .stosq, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .long },
734
735 .{ .sub, .zi, .al, .imm8, .none, .none, &.{ 0x2c }, 0, .none },
736 .{ .sub, .zi, .ax, .imm16, .none, .none, &.{ 0x2d }, 0, .none },
737 .{ .sub, .zi, .eax, .imm32, .none, .none, &.{ 0x2d }, 0, .none },
738 .{ .sub, .zi, .rax, .imm32s, .none, .none, &.{ 0x2d }, 0, .long },
739 .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .none },
740 .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .rex },
741 .{ .sub, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 5, .none },
742 .{ .sub, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 5, .none },
743 .{ .sub, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 5, .long },
744 .{ .sub, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 5, .none },
745 .{ .sub, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 5, .none },
746 .{ .sub, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 5, .long },
747 .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .none },
748 .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .rex },
749 .{ .sub, .mr, .rm16, .r16, .none, .none, &.{ 0x29 }, 0, .none },
750 .{ .sub, .mr, .rm32, .r32, .none, .none, &.{ 0x29 }, 0, .none },
751 .{ .sub, .mr, .rm64, .r64, .none, .none, &.{ 0x29 }, 0, .long },
752 .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .none },
753 .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .rex },
754 .{ .sub, .rm, .r16, .rm16, .none, .none, &.{ 0x2b }, 0, .none },
755 .{ .sub, .rm, .r32, .rm32, .none, .none, &.{ 0x2b }, 0, .none },
756 .{ .sub, .rm, .r64, .rm64, .none, .none, &.{ 0x2b }, 0, .long },
757
758 .{ .syscall, .np, .none, .none, .none, .none, &.{ 0x0f, 0x05 }, 0, .none }
421 .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none },
422 .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long },
423
424 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },
425 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },
426 .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long },
427 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none },
428 .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long },
429
430 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none },
431 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex },
432 .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .none },
433 .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none },
434 .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long },
435
436 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none },
437 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex },
438 .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .none },
439 .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none },
440 .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long },
441
442 .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none },
443
444 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none },
445 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex },
446 .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .none },
447 .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none },
448 .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long },
449
450 .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none },
451 .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .none },
452 .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none },
453 .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long },
454 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none },
455 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex },
456 .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .none },
457 .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none },
458 .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long },
459 .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .none },
460 .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none },
461 .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long },
462 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none },
463 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex },
464 .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .none },
465 .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none },
466 .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long },
467 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none },
468 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex },
469 .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .none },
470 .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none },
471 .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long },
472
473 .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .none },
474 .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none },
475 .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .none },
476 .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none },
477
478 .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
479 .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
480 .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },
481
482 .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .none },
483 .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none },
484 .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .none },
485 .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none },
486 .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none },
487 .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .none },
488 .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none },
489
490 .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none },
491
492 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none },
493 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex },
494 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none },
495 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex },
496 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none },
497 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex },
498 .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .none },
499 .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .none },
500 .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .none },
501 .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none },
502 .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long },
503 .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none },
504 .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long },
505 .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none },
506 .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long },
507
508 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none },
509 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex },
510 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none },
511 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex },
512 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none },
513 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex },
514 .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .none },
515 .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .none },
516 .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .none },
517 .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none },
518 .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long },
519 .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none },
520 .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long },
521 .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none },
522 .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long },
523
524 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none },
525 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex },
526 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none },
527 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex },
528 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none },
529 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex },
530 .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .none },
531 .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .none },
532 .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .none },
533 .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none },
534 .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long },
535 .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none },
536 .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long },
537 .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none },
538 .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long },
539
540 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none },
541 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex },
542 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none },
543 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex },
544 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none },
545 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex },
546 .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .none },
547 .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .none },
548 .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .none },
549 .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none },
550 .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long },
551 .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none },
552 .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long },
553 .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none },
554 .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long },
555
556 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },
557 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },
558 .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },
559 .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },
560 .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },
561 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },
562 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },
563 .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },
564 .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },
565 .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },
566 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },
567 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },
568 .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },
569 .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },
570 .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },
571
572 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none },
573 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex },
574 .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .none },
575 .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none },
576 .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long },
577 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none },
578 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex },
579 .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .none },
580 .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none },
581 .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long },
582 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none },
583 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex },
584 .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .none },
585 .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none },
586 .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long },
587
588 .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none },
589 .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .none },
590 .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none },
591 .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long },
592 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none },
593 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex },
594 .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .none },
595 .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none },
596 .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long },
597 .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .none },
598 .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none },
599 .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long },
600 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none },
601 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex },
602 .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .none },
603 .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none },
604 .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long },
605 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none },
606 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex },
607 .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .none },
608 .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none },
609 .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long },
610
611 .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none },
612 .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .none },
613 .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none },
614 .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long },
615
616 .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none },
617 .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short },
618 .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none },
619 .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long },
620
621 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },
622 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },
623 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
624 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
625 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
626 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
627 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },
628 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },
629 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
630 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
631 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },
632 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },
633 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },
634 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },
635 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },
636 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },
637 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },
638 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },
639 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },
640 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },
641 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },
642 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },
643 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
644 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
645 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
646 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
647 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },
648 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },
649 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
650 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
651 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },
652 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },
653 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },
654 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },
655 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },
656 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },
657 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },
658 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },
659 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },
660 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },
661 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none },
662 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex },
663 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },
664 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },
665 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none },
666 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex },
667 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },
668 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },
669 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none },
670 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex },
671 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },
672 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },
673 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },
674 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },
675 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },
676 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },
677 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none },
678 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex },
679 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },
680 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },
681
682 .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },
683
684 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },
685 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },
686 .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },
687 .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },
688 .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },
689 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },
690 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },
691 .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },
692 .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },
693 .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },
694 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },
695 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },
696 .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },
697 .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },
698 .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },
699
700 .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },
701 .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },
702 .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },
703 .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long },
704 .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },
705 .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long },
706
707 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none },
708 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex },
709 .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .none },
710 .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none },
711 .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long },
712 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none },
713 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex },
714 .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .none },
715 .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none },
716 .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long },
717 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none },
718 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex },
719 .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .none },
720 .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none },
721 .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long },
722
723 .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },
724 .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .none },
725 .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },
726 .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long },
727 .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none },
728 .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long },
729
730 .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none },
731 .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .none },
732 .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none },
733 .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long },
734
735 .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none },
736 .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short },
737 .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none },
738 .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long },
739
740 .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none },
741 .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .none },
742 .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none },
743 .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long },
744 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none },
745 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex },
746 .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .none },
747 .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none },
748 .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long },
749 .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .none },
750 .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none },
751 .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long },
752 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none },
753 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex },
754 .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .none },
755 .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none },
756 .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long },
757 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none },
758 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex },
759 .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .none },
760 .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none },
761 .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long },
762
763 .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none }
759764,
760 .{ .@"test", .zi, .al, .imm8, .none, .none, &.{ 0xa8 }, 0, .none },
761 .{ .@"test", .zi, .ax, .imm16, .none, .none, &.{ 0xa9 }, 0, .none },
762 .{ .@"test", .zi, .eax, .imm32, .none, .none, &.{ 0xa9 }, 0, .none },
763 .{ .@"test", .zi, .rax, .imm32s, .none, .none, &.{ 0xa9 }, 0, .long },
764 .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .none },
765 .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .rex },
766 .{ .@"test", .mi, .rm16, .imm16, .none, .none, &.{ 0xf7 }, 0, .none },
767 .{ .@"test", .mi, .rm32, .imm32, .none, .none, &.{ 0xf7 }, 0, .none },
768 .{ .@"test", .mi, .rm64, .imm32s, .none, .none, &.{ 0xf7 }, 0, .long },
769 .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .none },
770 .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .rex },
771 .{ .@"test", .mr, .rm16, .r16, .none, .none, &.{ 0x85 }, 0, .none },
772 .{ .@"test", .mr, .rm32, .r32, .none, .none, &.{ 0x85 }, 0, .none },
773 .{ .@"test", .mr, .rm64, .r64, .none, .none, &.{ 0x85 }, 0, .long },
774
775 .{ .tzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
776 .{ .tzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
777 .{ .tzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },
778
779 .{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none },
780
781 .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .none },
782 .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .rex },
783 .{ .xadd, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },
784 .{ .xadd, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },
785 .{ .xadd, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xc1 }, 0, .long },
786
787 .{ .xchg, .o, .ax, .r16, .none, .none, &.{ 0x90 }, 0, .none },
788 .{ .xchg, .o, .r16, .ax, .none, .none, &.{ 0x90 }, 0, .none },
789 .{ .xchg, .o, .eax, .r32, .none, .none, &.{ 0x90 }, 0, .none },
790 .{ .xchg, .o, .rax, .r64, .none, .none, &.{ 0x90 }, 0, .long },
791 .{ .xchg, .o, .r32, .eax, .none, .none, &.{ 0x90 }, 0, .none },
792 .{ .xchg, .o, .r64, .rax, .none, .none, &.{ 0x90 }, 0, .long },
793 .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .none },
794 .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .rex },
795 .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .none },
796 .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .rex },
797 .{ .xchg, .mr, .rm16, .r16, .none, .none, &.{ 0x87 }, 0, .none },
798 .{ .xchg, .rm, .r16, .rm16, .none, .none, &.{ 0x87 }, 0, .none },
799 .{ .xchg, .mr, .rm32, .r32, .none, .none, &.{ 0x87 }, 0, .none },
800 .{ .xchg, .mr, .rm64, .r64, .none, .none, &.{ 0x87 }, 0, .long },
801 .{ .xchg, .rm, .r32, .rm32, .none, .none, &.{ 0x87 }, 0, .none },
802 .{ .xchg, .rm, .r64, .rm64, .none, .none, &.{ 0x87 }, 0, .long },
803
804 .{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none },
805 .{ .xor, .zi, .ax, .imm16, .none, .none, &.{ 0x35 }, 0, .none },
806 .{ .xor, .zi, .eax, .imm32, .none, .none, &.{ 0x35 }, 0, .none },
807 .{ .xor, .zi, .rax, .imm32s, .none, .none, &.{ 0x35 }, 0, .long },
808 .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .none },
809 .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .rex },
810 .{ .xor, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 6, .none },
811 .{ .xor, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 6, .none },
812 .{ .xor, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 6, .long },
813 .{ .xor, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 6, .none },
814 .{ .xor, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 6, .none },
815 .{ .xor, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 6, .long },
816 .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .none },
817 .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .rex },
818 .{ .xor, .mr, .rm16, .r16, .none, .none, &.{ 0x31 }, 0, .none },
819 .{ .xor, .mr, .rm32, .r32, .none, .none, &.{ 0x31 }, 0, .none },
820 .{ .xor, .mr, .rm64, .r64, .none, .none, &.{ 0x31 }, 0, .long },
821 .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .none },
822 .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .rex },
823 .{ .xor, .rm, .r16, .rm16, .none, .none, &.{ 0x33 }, 0, .none },
824 .{ .xor, .rm, .r32, .rm32, .none, .none, &.{ 0x33 }, 0, .none },
825 .{ .xor, .rm, .r64, .rm64, .none, .none, &.{ 0x33 }, 0, .long },
765 .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none },
766 .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .none },
767 .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none },
768 .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long },
769 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none },
770 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex },
771 .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .none },
772 .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none },
773 .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long },
774 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none },
775 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex },
776 .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .none },
777 .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none },
778 .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long },
779
780 .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
781 .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
782 .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },
783
784 .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none },
785
786 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none },
787 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex },
788 .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .none },
789 .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none },
790 .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long },
791
792 .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .none },
793 .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .none },
794 .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none },
795 .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long },
796 .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none },
797 .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long },
798 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none },
799 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex },
800 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none },
801 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex },
802 .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .none },
803 .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .none },
804 .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none },
805 .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long },
806 .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none },
807 .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long },
808
809 .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none },
810 .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .none },
811 .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none },
812 .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long },
813 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none },
814 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex },
815 .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .none },
816 .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none },
817 .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long },
818 .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .none },
819 .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none },
820 .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long },
821 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none },
822 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex },
823 .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .none },
824 .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none },
825 .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long },
826 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none },
827 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .rex },
828 .{ .xor, .rm, &.{ .r16, .rm16 }, &.{ 0x33 }, 0, .none },
829 .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none },
830 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long },
826831
827832 // SSE
828 .{ .addss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x58 }, 0, .sse },
833 .{ .addss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x58 }, 0, .sse },
829834
830 .{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse },
835 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse },
831836
832 .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },
837 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },
833838
834 .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },
839 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },
835840
836 .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse },
841 .{ .minss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse },
837842
838 .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse },
839 .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse },
843 .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse },
844 .{ .movss, .mr, &.{ .xmm_m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse },
840845
841 .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse },
846 .{ .mulss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse },
842847
843 .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse },
848 .{ .subss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse },
844849
845 .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0x0f, 0x2e }, 0, .sse },
850 .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse },
846851
847852 // SSE2
848 .{ .addsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },
853 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },
849854
850 .{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 },
855 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 },
851856
852 .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },
857 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },
853858
854 .{ .maxsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },
859 .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },
855860
856 .{ .minsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },
861 .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },
857862
858 .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
859 .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },
863 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
864 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },
860865
861 .{ .mulsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 },
866 .{ .mulsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 },
862867
863 .{ .subsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 },
868 .{ .subsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 },
864869
865 .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 },
866 .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 },
870 .{ .movsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 },
871 .{ .movsd, .mr, &.{ .xmm_m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 },
867872
868 .{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },
873 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },
869874
870875 // SSE4.1
871 .{ .roundss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
872 .{ .roundsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },
876 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
877 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },
873878};
874879// zig fmt: on
src/print_air.zig+48-33
......@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;
88const Air = @import("Air.zig");
99const Liveness = @import("Liveness.zig");
1010
11pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
11pub fn write(stream: anytype, module: *Module, air: Air, liveness: Liveness) void {
1212 const instruction_bytes = air.instructions.len *
1313 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
1414 // the debug safety tag but we want to measure release size.
......@@ -23,7 +23,7 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
2323 liveness_special_bytes + tomb_bytes;
2424
2525 // zig fmt: off
26 std.debug.print(
26 stream.print(
2727 \\# Total AIR+Liveness bytes: {}
2828 \\# AIR Instructions: {d} ({})
2929 \\# AIR Extra Data: {d} ({})
......@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
4040 fmtIntSizeBin(tomb_bytes),
4141 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
4242 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
43 });
43 }) catch return;
4444 // zig fmt: on
45 var arena = std.heap.ArenaAllocator.init(module.gpa);
46 defer arena.deinit();
4745
4846 var writer: Writer = .{
4947 .module = module,
5048 .gpa = module.gpa,
51 .arena = arena.allocator(),
5249 .air = air,
5350 .liveness = liveness,
5451 .indent = 2,
52 .skip_body = false,
5553 };
56 const stream = std.io.getStdErr().writer();
5754 writer.writeAllConstants(stream) catch return;
5855 stream.writeByte('\n') catch return;
5956 writer.writeBody(stream, air.getMainBody()) catch return;
6057}
6158
59pub fn writeInst(
60 stream: anytype,
61 inst: Air.Inst.Index,
62 module: *Module,
63 air: Air,
64 liveness: Liveness,
65) void {
66 var writer: Writer = .{
67 .module = module,
68 .gpa = module.gpa,
69 .air = air,
70 .liveness = liveness,
71 .indent = 2,
72 .skip_body = true,
73 };
74 writer.writeInst(stream, inst) catch return;
75}
76
77pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
78 write(std.io.getStdErr().writer(), module, air, liveness);
79}
80
81pub fn dumpInst(inst: Air.Inst.Index, module: *Module, air: Air, liveness: Liveness) void {
82 writeInst(std.io.getStdErr().writer(), inst, module, air, liveness);
83}
84
6285const Writer = struct {
6386 module: *Module,
6487 gpa: Allocator,
65 arena: Allocator,
6688 air: Air,
6789 liveness: Liveness,
6890 indent: usize,
91 skip_body: bool,
6992
7093 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
7194 for (w.air.instructions.items(.tag), 0..) |tag, i| {
72 const inst = @intCast(u32, i);
95 const inst = @intCast(Air.Inst.Index, i);
7396 switch (tag) {
74 .constant, .const_ty => {
75 try s.writeByteNTimes(' ', w.indent);
76 try s.print("%{d} ", .{inst});
77 try w.writeInst(s, inst);
78 try s.writeAll(")\n");
79 },
97 .constant, .const_ty => try w.writeInst(s, inst),
8098 else => continue,
8199 }
82100 }
83101 }
84102
85103 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
86 for (body) |inst| {
87 try s.writeByteNTimes(' ', w.indent);
88 if (w.liveness.isUnused(inst)) {
89 try s.print("%{d}!", .{inst});
90 } else {
91 try s.print("%{d} ", .{inst});
92 }
93 try w.writeInst(s, inst);
94 try s.writeAll(")\n");
95 }
104 for (body) |inst| try w.writeInst(s, inst);
96105 }
97106
98107 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
99 const tags = w.air.instructions.items(.tag);
100 const tag = tags[inst];
101 try s.print("= {s}(", .{@tagName(tags[inst])});
108 const tag = w.air.instructions.items(.tag)[inst];
109 try s.writeByteNTimes(' ', w.indent);
110 try s.print("%{d}{c}= {s}(", .{
111 inst,
112 @as(u8, if (w.liveness.isUnused(inst)) '!' else ' '),
113 @tagName(tag),
114 });
102115 switch (tag) {
103116 .add,
104117 .addwrap,
......@@ -316,6 +329,7 @@ const Writer = struct {
316329
317330 .dbg_block_begin, .dbg_block_end => {},
318331 }
332 try s.writeAll(")\n");
319333 }
320334
321335 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
......@@ -372,6 +386,7 @@ const Writer = struct {
372386 const body = w.air.extra[extra.end..][0..extra.data.body_len];
373387
374388 try w.writeType(s, w.air.getRefType(ty_pl.ty));
389 if (w.skip_body) return s.writeAll(", ...");
375390 try s.writeAll(", {\n");
376391 const old_indent = w.indent;
377392 w.indent += 2;
......@@ -703,6 +718,7 @@ const Writer = struct {
703718 const body = w.air.extra[extra.end..][0..extra.data.body_len];
704719
705720 try w.writeOperand(s, inst, 0, pl_op.operand);
721 if (w.skip_body) return s.writeAll(", ...");
706722 try s.writeAll(", {\n");
707723 const old_indent = w.indent;
708724 w.indent += 2;
......@@ -721,6 +737,7 @@ const Writer = struct {
721737
722738 try s.writeAll(", ");
723739 try w.writeType(s, w.air.getRefType(ty_pl.ty));
740 if (w.skip_body) return s.writeAll(", ...");
724741 try s.writeAll(", {\n");
725742 const old_indent = w.indent;
726743 w.indent += 2;
......@@ -738,6 +755,7 @@ const Writer = struct {
738755 const liveness_condbr = w.liveness.getCondBr(inst);
739756
740757 try w.writeOperand(s, inst, 0, pl_op.operand);
758 if (w.skip_body) return s.writeAll(", ...");
741759 try s.writeAll(", {\n");
742760 const old_indent = w.indent;
743761 w.indent += 2;
......@@ -900,10 +918,7 @@ const Writer = struct {
900918 dies: bool,
901919 ) @TypeOf(s).Error!void {
902920 _ = w;
903 if (dies) {
904 try s.print("%{d}!", .{inst});
905 } else {
906 try s.print("%{d}", .{inst});
907 }
921 try s.print("%{d}", .{inst});
922 if (dies) try s.writeByte('!');
908923 }
909924};
test/behavior/bugs/9584.zig+1
......@@ -47,6 +47,7 @@ test {
4747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4848 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4949 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5051
5152 var flags = A{
5253 .a = false,