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 {...@@ -49,6 +49,20 @@ pub fn MultiArrayList(comptime S: type) type {
49 return casted_ptr[0..self.len];49 return casted_ptr[0..self.len];
50 }50 }
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
52 pub fn toMultiArrayList(self: Slice) Self {66 pub fn toMultiArrayList(self: Slice) Self {
53 if (self.ptrs.len == 0) {67 if (self.ptrs.len == 0) {
54 return .{};68 return .{};
...@@ -156,20 +170,12 @@ pub fn MultiArrayList(comptime S: type) type {...@@ -156,20 +170,12 @@ pub fn MultiArrayList(comptime S: type) type {
156170
157 /// Overwrite one array element with new data.171 /// Overwrite one array element with new data.
158 pub fn set(self: *Self, index: usize, elem: S) void {172 pub fn set(self: *Self, index: usize, elem: S) void {
159 const slices = self.slice();173 return self.slice().set(index, elem);
160 inline for (fields, 0..) |field_info, i| {
161 slices.items(@intToEnum(Field, i))[index] = @field(elem, field_info.name);
162 }
163 }174 }
164175
165 /// Obtain all the data for one array element.176 /// Obtain all the data for one array element.
166 pub fn get(self: Self, index: usize) S {177 pub fn get(self: Self, index: usize) S {
167 const slices = self.slice();178 return self.slice().get(index);
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;
173 }179 }
174180
175 /// Extend the list by 1 element. Allocates more memory as necessary.181 /// 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;...@@ -20,6 +20,7 @@ const ErrorMsg = Module.ErrorMsg;
20const Result = codegen.Result;20const Result = codegen.Result;
21const Emit = @import("Emit.zig");21const Emit = @import("Emit.zig");
22const Liveness = @import("../../Liveness.zig");22const Liveness = @import("../../Liveness.zig");
23const Lower = @import("Lower.zig");
23const Mir = @import("Mir.zig");24const Mir = @import("Mir.zig");
24const Module = @import("../../Module.zig");25const Module = @import("../../Module.zig");
25const Target = std.Target;26const Target = std.Target;
...@@ -44,6 +45,8 @@ const sse = abi.RegisterClass.sse;...@@ -44,6 +45,8 @@ const sse = abi.RegisterClass.sse;
4445
45const InnerError = CodeGenError || error{OutOfRegisters};46const InnerError = CodeGenError || error{OutOfRegisters};
4647
48const debug_wip_mir = false;
49
47gpa: Allocator,50gpa: Allocator,
48air: Air,51air: Air,
49liveness: Liveness,52liveness: Liveness,
...@@ -267,6 +270,12 @@ pub fn generate(...@@ -267,6 +270,12 @@ pub fn generate(
267 assert(fn_owner_decl.has_tv);270 assert(fn_owner_decl.has_tv);
268 const fn_type = fn_owner_decl.ty;271 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
270 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);279 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
271 try branch_stack.ensureUnusedCapacity(2);280 try branch_stack.ensureUnusedCapacity(2);
272 // The outermost branch is used for constants only.281 // The outermost branch is used for constants only.
...@@ -341,19 +350,22 @@ pub fn generate(...@@ -341,19 +350,22 @@ pub fn generate(
341 defer mir.deinit(bin_file.allocator);350 defer mir.deinit(bin_file.allocator);
342351
343 var emit = Emit{352 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 },
345 .bin_file = bin_file,359 .bin_file = bin_file,
346 .debug_output = debug_output,360 .debug_output = debug_output,
347 .target = &bin_file.options.target,
348 .src_loc = src_loc,
349 .code = code,361 .code = code,
350 .prev_di_pc = 0,362 .prev_di_pc = 0,
351 .prev_di_line = module_fn.lbrace_line,363 .prev_di_line = module_fn.lbrace_line,
352 .prev_di_column = module_fn.lbrace_column,364 .prev_di_column = module_fn.lbrace_column,
353 };365 };
354 defer emit.deinit();366 defer emit.deinit();
355 emit.lowerMir() catch |err| switch (err) {367 emit.emitMir() catch |err| switch (err) {
356 error.EmitFail => return Result{ .fail = emit.err_msg.? },368 error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? },
357 error.InvalidInstruction, error.CannotEncode => |e| {369 error.InvalidInstruction, error.CannotEncode => |e| {
358 const msg = switch (e) {370 const msg = switch (e) {
359 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",371 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
...@@ -378,11 +390,49 @@ pub fn generate(...@@ -378,11 +390,49 @@ pub fn generate(
378 }390 }
379}391}
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
381fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {430fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
382 const gpa = self.gpa;431 const gpa = self.gpa;
383 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);432 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
384 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);433 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
385 self.mir_instructions.appendAssumeCapacity(inst);434 self.mir_instructions.appendAssumeCapacity(inst);
435 self.dumpWipMir(inst) catch {};
386 return result_index;436 return result_index;
387}437}
388438
...@@ -842,8 +892,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -842,8 +892,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
842 const old_air_bookkeeping = self.air_bookkeeping;892 const old_air_bookkeeping = self.air_bookkeeping;
843 try self.ensureProcessDeathCapacity(Liveness.bpi);893 try self.ensureProcessDeathCapacity(Liveness.bpi);
844 if (builtin.mode == .Debug) {894 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);
846 }896 }
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
848 switch (air_tags[inst]) {904 switch (air_tags[inst]) {
849 // zig fmt: off905 // zig fmt: off
...@@ -1479,43 +1535,31 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1479,43 +1535,31 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
14791535
1480fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1536fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1481 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1537 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1482 if (self.liveness.isUnused(inst))1538 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1483 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1539 const dst_ty = self.air.typeOfIndex(inst);
14841540 const dst_abi_size = dst_ty.abiSize(self.target.*);
1485 const src_ty = self.air.typeOf(ty_op.operand);1541 if (dst_abi_size > 8) {
1486 const dst_ty = self.air.typeOfIndex(inst);1542 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});
1487 const operand = try self.resolveInst(ty_op.operand);1543 }
1488
1489 const src_ty_size = src_ty.abiSize(self.target.*);
1490 const dst_ty_size = dst_ty.abiSize(self.target.*);
14911544
1492 if (src_ty_size > 8 or dst_ty_size > 8) {1545 const src_mcv = try self.resolveInst(ty_op.operand);
1493 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});1546 const src_lock = switch (src_mcv) {
1494 }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) {1552 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
1497 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),1553 src_mcv
1498 else => null,1554 else
1499 };1555 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
1500 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
15011556
1502 const reg: Register = blk: {1557 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
1503 if (operand.isRegister()) {1558 // have to be removed. this only happens if the dst if not a power-of-two size.
1504 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {1559 if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64());
1505 break :blk operand.register.to64();1560 break :result dst_mcv;
1506 }
1507 }
1508 const mcv = try self.copyToRegisterWithInstTracking(inst, src_ty, operand);
1509 break :blk mcv.register.to64();
1510 };1561 };
15111562 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
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 });
1519}1563}
15201564
1521fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {1565fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1628,7 +1672,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1628,7 +1672,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
1628 const reg_bits = self.regBitSize(ty);1672 const reg_bits = self.regBitSize(ty);
1629 const cc: Condition = if (ty.isSignedInt()) cc: {1673 const cc: Condition = if (ty.isSignedInt()) cc: {
1630 try self.genSetReg(ty, limit_reg, dst_mcv);1674 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 });
1632 try self.genBinOpMir(.xor, ty, limit_mcv, .{1676 try self.genBinOpMir(.xor, ty, limit_mcv, .{
1633 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,1677 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
1634 });1678 });
...@@ -1681,7 +1725,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1681,7 +1725,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
1681 const reg_bits = self.regBitSize(ty);1725 const reg_bits = self.regBitSize(ty);
1682 const cc: Condition = if (ty.isSignedInt()) cc: {1726 const cc: Condition = if (ty.isSignedInt()) cc: {
1683 try self.genSetReg(ty, limit_reg, dst_mcv);1727 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 });
1685 try self.genBinOpMir(.xor, ty, limit_mcv, .{1729 try self.genBinOpMir(.xor, ty, limit_mcv, .{
1686 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,1730 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
1687 });1731 });
...@@ -1735,7 +1779,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1735,7 +1779,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1735 const cc: Condition = if (ty.isSignedInt()) cc: {1779 const cc: Condition = if (ty.isSignedInt()) cc: {
1736 try self.genSetReg(ty, limit_reg, lhs_mcv);1780 try self.genSetReg(ty, limit_reg, lhs_mcv);
1737 try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv);1781 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 });
1739 try self.genBinOpMir(.xor, ty, limit_mcv, .{1783 try self.genBinOpMir(.xor, ty, limit_mcv, .{
1740 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,1784 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
1741 });1785 });
...@@ -2509,16 +2553,13 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2509,16 +2553,13 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
25092553
2510fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {2554fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
2511 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2555 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2512 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2556 const result = if (self.liveness.isUnused(inst)) .dead else result: {
2513 const operand = try self.resolveInst(ty_op.operand);2557 const src_mcv = try self.resolveInst(ty_op.operand);
2514 const dst_mcv: MCValue = blk: {2558 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
2515 switch (operand) {2559
2516 .stack_offset => |off| {2560 const dst_mcv = try self.allocRegOrMem(inst, true);
2517 break :blk MCValue{ .stack_offset = off };2561 const dst_ty = self.air.typeOfIndex(inst);
2518 },2562 try self.setRegOrMem(dst_ty, dst_mcv, src_mcv);
2519 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),
2520 }
2521 };
2522 break :result dst_mcv;2563 break :result dst_mcv;
2523 };2564 };
2524 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2565 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -3040,7 +3081,8 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -3040,7 +3081,8 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
3040 };3081 };
3041 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);3082 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))
3044 src_mcv3086 src_mcv
3045 else3087 else
3046 .{ .register = try self.register_manager.allocReg(inst, gp) };3088 .{ .register = try self.register_manager.allocReg(inst, gp) };
...@@ -3432,23 +3474,21 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3432,23 +3474,21 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
3432 const elem_ty = self.air.typeOfIndex(inst);3474 const elem_ty = self.air.typeOfIndex(inst);
3433 const elem_size = elem_ty.abiSize(self.target.*);3475 const elem_size = elem_ty.abiSize(self.target.*);
3434 const result: MCValue = result: {3476 const result: MCValue = result: {
3435 if (!elem_ty.hasRuntimeBitsIgnoreComptime())3477 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
3436 break :result MCValue.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
3438 const ptr = try self.resolveInst(ty_op.operand);3483 const ptr = try self.resolveInst(ty_op.operand);
3439 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();3484 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();
3440 if (self.liveness.isUnused(inst) and !is_volatile)3485 if (self.liveness.isUnused(inst) and !is_volatile) break :result .dead;
3441 break :result MCValue.dead;
34423486
3443 const dst_mcv: MCValue = blk: {3487 const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr))
3444 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.
3445 // The MCValue that holds the pointer can be re-used as the value.3489 ptr
3446 break :blk ptr;3490 else
3447 } else {3491 try self.allocRegOrMem(inst, true);
3448 break :blk try self.allocRegOrMem(inst, true);
3449 }
3450 };
3451 log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr });
3452 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));3492 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
3453 break :result dst_mcv;3493 break :result dst_mcv;
3454 };3494 };
...@@ -3943,9 +3983,6 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue...@@ -3943,9 +3983,6 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
3943 .register_overflow => unreachable,3983 .register_overflow => unreachable,
3944 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),3984 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
3945 .ptr_stack_offset, .stack_offset => |off| {3985 .ptr_stack_offset, .stack_offset => |off| {
3946 if (off > math.maxInt(i32)) {
3947 return self.fail("stack offset too large", .{});
3948 }
3949 if (abi_size > 8) {3986 if (abi_size > 8) {
3950 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});3987 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
3951 }3988 }
...@@ -4387,9 +4424,6 @@ fn genBinOp(...@@ -4387,9 +4424,6 @@ fn genBinOp(
4387 if (lhs_ty.zigTypeTag() == .Vector) {4424 if (lhs_ty.zigTypeTag() == .Vector) {
4388 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});4425 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
4389 }4426 }
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
4394 switch (lhs) {4428 switch (lhs) {
4395 .immediate => |imm| switch (imm) {4429 .immediate => |imm| switch (imm) {
...@@ -4402,7 +4436,7 @@ fn genBinOp(...@@ -4402,7 +4436,7 @@ fn genBinOp(
4402 else => {},4436 else => {},
4403 }4437 }
44044438
4405 const is_commutative: bool = switch (tag) {4439 const is_commutative = switch (tag) {
4406 .add,4440 .add,
4407 .addwrap,4441 .addwrap,
4408 .bool_or,4442 .bool_or,
...@@ -4416,6 +4450,20 @@ fn genBinOp(...@@ -4416,6 +4450,20 @@ fn genBinOp(
44164450
4417 else => false,4451 else => false,
4418 };4452 };
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
4420 const lhs_lock: ?RegisterLock = switch (lhs) {4468 const lhs_lock: ?RegisterLock = switch (lhs) {
4421 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),4469 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
...@@ -4432,10 +4480,10 @@ fn genBinOp(...@@ -4432,10 +4480,10 @@ fn genBinOp(
4432 var flipped: bool = false;4480 var flipped: bool = false;
4433 const dst_mcv: MCValue = blk: {4481 const dst_mcv: MCValue = blk: {
4434 if (maybe_inst) |inst| {4482 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)) {
4436 break :blk lhs;4484 break :blk lhs;
4437 }4485 }
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)) {
4439 flipped = true;4487 flipped = true;
4440 break :blk rhs;4488 break :blk rhs;
4441 }4489 }
...@@ -4485,33 +4533,37 @@ fn genBinOp(...@@ -4485,33 +4533,37 @@ fn genBinOp(
44854533
4486 .div_float,4534 .div_float,
4487 .div_exact,4535 .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
4494 .div_trunc,4536 .div_trunc,
4495 .div_floor,4537 .div_floor,
4496 => {4538 => {
4497 try self.genBinOpMir(switch (lhs_ty.tag()) {4539 try self.genBinOpMir(switch (lhs_ty.tag()) {
4498 .f32 => .divss,4540 .f32 => .divss,
4499 .f64 => .divsd,4541 .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 }),
4501 }, lhs_ty, dst_mcv, src_mcv);4545 }, lhs_ty, dst_mcv, src_mcv);
4502 if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {4546 switch (tag) {
4503 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));4547 .div_float,
4504 const dst_alias = registerAlias(dst_mcv.register, abi_size);4548 .div_exact,
4505 try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {4549 => {},
4506 .f32 => .roundss,4550 .div_trunc,
4507 .f64 => .roundsd,4551 .div_floor,
4508 else => unreachable,4552 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
4509 }, dst_alias, dst_alias, Immediate.u(switch (tag) {4553 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
4510 .div_trunc => 0b1_0_11,4554 const dst_alias = registerAlias(dst_mcv.register, abi_size);
4511 .div_floor => 0b1_0_01,4555 try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {
4512 else => unreachable,4556 .f32 => .roundss,
4513 }));4557 .f64 => .roundsd,
4514 } else return self.fail("TODO implement round without sse4_1", .{});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 }
4515 },4567 },
45164568
4517 .ptr_add,4569 .ptr_add,
...@@ -4568,7 +4620,13 @@ fn genBinOp(...@@ -4568,7 +4620,13 @@ fn genBinOp(
4568 };4620 };
45694621
4570 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));4622 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) {
4572 .none,4630 .none,
4573 .undef,4631 .undef,
4574 .dead,4632 .dead,
...@@ -4576,57 +4634,43 @@ fn genBinOp(...@@ -4576,57 +4634,43 @@ fn genBinOp(
4576 .immediate,4634 .immediate,
4577 .eflags,4635 .eflags,
4578 .register_overflow,4636 .register_overflow,
4579 .stack_offset,
4580 .ptr_stack_offset,4637 .ptr_stack_offset,
4581 .memory,
4582 .linker_load,
4583 => unreachable,4638 => unreachable,
4584 .register => |dst_reg| switch (mat_src_mcv) {4639 .register => |src_reg| try self.asmCmovccRegisterRegister(
4585 .none,4640 registerAlias(tmp_reg, abi_size),
4586 .undef,4641 registerAlias(src_reg, abi_size),
4587 .dead,4642 cc,
4588 .unreach,4643 ),
4589 .immediate,4644 .stack_offset => |off| try self.asmCmovccRegisterMemory(
4590 .eflags,4645 registerAlias(tmp_reg, abi_size),
4591 .register_overflow,4646 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4592 .ptr_stack_offset,4647 .base = .rbp,
4593 => unreachable,4648 .disp = -off,
4594 .register => |src_reg| try self.asmCmovccRegisterRegister(4649 }),
4595 registerAlias(dst_reg, abi_size),4650 cc,
4596 registerAlias(src_reg, abi_size),4651 ),
4597 cc,4652 .memory, .linker_load => {
4598 ),4653 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4599 .stack_offset => |off| try self.asmCmovccRegisterMemory(4654 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
4600 registerAlias(dst_reg, abi_size),4655 defer self.register_manager.unlockReg(addr_reg_lock);
4601 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{4656 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv);
4602 .base = .rbp,4657
4603 .disp = -off,4658 // To get the actual address of the value we want to modify we
4604 }),4659 // we have to go through the GOT
4605 cc,4660 try self.asmRegisterMemory(
4606 ),4661 .mov,
4607 .memory, .linker_load => {4662 addr_reg,
4608 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();4663 Memory.sib(.qword, .{ .base = addr_reg }),
4609 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);4664 );
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 );
46214665
4622 try self.asmCmovccRegisterMemory(4666 try self.asmCmovccRegisterMemory(
4623 registerAlias(dst_reg, abi_size),4667 registerAlias(tmp_reg, abi_size),
4624 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),4668 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
4625 cc,4669 cc,
4626 );4670 );
4627 },
4628 },4671 },
4629 }4672 }
4673 try self.setRegOrMem(lhs_ty, dst_mcv, .{ .register = tmp_reg });
4630 },4674 },
4631 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {4675 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
4632 .f32 => switch (tag) {4676 .f32 => switch (tag) {
...@@ -4649,8 +4693,8 @@ fn genBinOp(...@@ -4649,8 +4693,8 @@ fn genBinOp(
4649 return dst_mcv;4693 return dst_mcv;
4650}4694}
46514695
4652fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {4696fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4653 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));4697 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4654 switch (dst_mcv) {4698 switch (dst_mcv) {
4655 .none => unreachable,4699 .none => unreachable,
4656 .undef => unreachable,4700 .undef => unreachable,
...@@ -4667,12 +4711,12 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4667,12 +4711,12 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4667 const dst_reg_lock = self.register_manager.lockReg(dst_reg);4711 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
4668 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);4712 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
46694713
4670 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);4714 const reg = try self.copyToTmpRegister(ty, src_mcv);
4671 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });4715 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
4672 },4716 },
4673 .register => |src_reg| switch (dst_ty.zigTypeTag()) {4717 .register => |src_reg| switch (ty.zigTypeTag()) {
4674 .Float => {4718 .Float => {
4675 if (intrinsicsAllowed(self.target.*, dst_ty)) {4719 if (intrinsicsAllowed(self.target.*, ty)) {
4676 return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());4720 return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
4677 }4721 }
46784722
...@@ -4685,7 +4729,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4685,7 +4729,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4685 ),4729 ),
4686 },4730 },
4687 .immediate => |imm| {4731 .immediate => |imm| {
4688 switch (self.regBitSize(dst_ty)) {4732 switch (self.regBitSize(ty)) {
4689 8, 16, 32 => {4733 8, 16, 32 => {
4690 try self.asmRegisterImmediate(4734 try self.asmRegisterImmediate(
4691 mir_tag,4735 mir_tag,
...@@ -4704,7 +4748,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4704,7 +4748,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4704 try self.asmRegisterRegister(4748 try self.asmRegisterRegister(
4705 mir_tag,4749 mir_tag,
4706 registerAlias(dst_reg, abi_size),4750 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),
4708 );4752 );
4709 }4753 }
4710 },4754 },
...@@ -4719,13 +4763,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4719,13 +4763,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4719 const dst_reg_lock = self.register_manager.lockReg(dst_reg);4763 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
4720 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);4764 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
47214765
4722 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);4766 const reg = try self.copyToTmpRegister(ty, src_mcv);
4723 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });4767 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
4724 },4768 },
4725 .stack_offset => |off| {4769 .stack_offset => |off| {
4726 if (off > math.maxInt(i32)) {
4727 return self.fail("stack offset too large", .{});
4728 }
4729 try self.asmRegisterMemory(4770 try self.asmRegisterMemory(
4730 mir_tag,4771 mir_tag,
4731 registerAlias(dst_reg, abi_size),4772 registerAlias(dst_reg, abi_size),
...@@ -4734,76 +4775,155 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4734,76 +4775,155 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4734 },4775 },
4735 }4776 }
4736 },4777 },
4737 .ptr_stack_offset, .stack_offset => |off| {4778 .ptr_stack_offset, .stack_offset => |dst_off| {
4738 if (off > math.maxInt(i32)) {4779 const src: ?struct {
4739 return self.fail("stack offset too large", .{});4780 limb_reg: Register,
4740 }4781 limb_lock: RegisterLock,
4741 if (abi_size > 8) {4782 addr_reg: Register,
4742 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});4783 addr_lock: RegisterLock,
4743 }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) {4804 break :addr .{
4746 .none => unreachable,4805 .addr_reg = src_addr_reg,
4747 .undef => unreachable,4806 .addr_lock = src_addr_lock,
4748 .dead, .unreach => unreachable,4807 .limb_reg = src_limb_reg,
4749 .register_overflow => unreachable,4808 .limb_lock = src_limb_lock,
4750 .register => |src_reg| {4809 };
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));
4755 },4810 },
4756 .immediate => |imm| {4811 };
4757 switch (self.regBitSize(dst_ty)) {4812 defer if (src) |locks| {
4758 8, 16, 32 => {4813 self.register_manager.unlockReg(locks.limb_lock);
4759 try self.asmMemoryImmediate(4814 self.register_manager.unlockReg(locks.addr_lock);
4760 mir_tag,4815 };
4761 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{4816
4762 .base = .rbp,4817 const ty_signedness =
4763 .disp = -off,4818 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
4764 }),4819 const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) {
4765 if (math.cast(i32, @bitCast(i64, imm))) |small|4820 .signed => Type.usize,
4766 Immediate.s(small)4821 .unsigned => Type.isize,
4767 else4822 };
4768 Immediate.u(@intCast(u32, imm)),4823 const limb_abi_size = @min(abi_size, 8);
4769 );4824 var off: i32 = 0;
4770 },4825 while (off < abi_size) : (off += 8) {
4771 64 => {4826 const mir_limb_tag = switch (off) {
4772 if (math.cast(i32, @bitCast(i64, imm))) |small| {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 => {
4773 try self.asmMemoryImmediate(4861 try self.asmMemoryImmediate(
4774 mir_tag,4862 mir_limb_tag,
4775 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{4863 dst_limb_mem,
4776 .base = .rbp,4864 if (math.cast(i32, @bitCast(i64, imm))) |small|
4777 .disp = -off,4865 Immediate.s(small)
4778 }),4866 else
4779 Immediate.s(small),4867 Immediate.u(@intCast(u32, imm)),
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),
4789 );4868 );
4790 }4869 },
4791 },4870 64 => {
4792 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),4871 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4793 }4872 try self.asmMemoryImmediate(
4794 },4873 mir_limb_tag,
4795 .memory,4874 dst_limb_mem,
4796 .stack_offset,4875 Immediate.s(small),
4797 .ptr_stack_offset,4876 );
4798 => {4877 } else {
4799 return self.fail("TODO implement x86 genBinOpMir source memory", .{});4878 try self.asmMemoryRegister(
4800 },4879 mir_limb_tag,
4801 .linker_load => {4880 dst_limb_mem,
4802 return self.fail("TODO implement x86 genBinOpMir source symbol at index in linker", .{});4881 registerAlias(
4803 },4882 try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }),
4804 .eflags => {4883 limb_abi_size,
4805 return self.fail("TODO implement x86 genBinOpMir source eflags", .{});4884 ),
4806 },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 }
4807 }4927 }
4808 },4928 },
4809 .memory => {4929 .memory => {
...@@ -4827,6 +4947,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -4827,6 +4947,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
4827 .ptr_stack_offset => unreachable,4947 .ptr_stack_offset => unreachable,
4828 .register_overflow => unreachable,4948 .register_overflow => unreachable,
4829 .register => |dst_reg| {4949 .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
4830 switch (src_mcv) {4954 switch (src_mcv) {
4831 .none => unreachable,4955 .none => unreachable,
4832 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),4956 .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...@@ -4835,21 +4959,18 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
4835 .register_overflow => unreachable,4959 .register_overflow => unreachable,
4836 .register => |src_reg| try self.asmRegisterRegister(4960 .register => |src_reg| try self.asmRegisterRegister(
4837 .imul,4961 .imul,
4838 registerAlias(dst_reg, abi_size),4962 dst_alias,
4839 registerAlias(src_reg, abi_size),4963 registerAlias(src_reg, abi_size),
4840 ),4964 ),
4841 .immediate => |imm| {4965 .immediate => |imm| {
4842 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {4966 if (std.math.cast(i32, imm)) |small| {
4843 // TODO take into account the type's ABI size when selecting the register alias
4844 // register, immediate
4845 try self.asmRegisterRegisterImmediate(4967 try self.asmRegisterRegisterImmediate(
4846 .imul,4968 .imul,
4847 dst_reg.to32(),4969 dst_alias,
4848 dst_reg.to32(),4970 dst_alias,
4849 Immediate.u(@intCast(u32, imm)),4971 Immediate.s(small),
4850 );4972 );
4851 } else {4973 } else {
4852 // TODO verify we don't spill and assign to the same register as dst_mcv
4853 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);4974 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
4854 return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });4975 return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
4855 }4976 }
...@@ -4857,7 +4978,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -4857,7 +4978,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
4857 .stack_offset => |off| {4978 .stack_offset => |off| {
4858 try self.asmRegisterMemory(4979 try self.asmRegisterMemory(
4859 .imul,4980 .imul,
4860 registerAlias(dst_reg, abi_size),4981 dst_alias,
4861 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),4982 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
4862 );4983 );
4863 },4984 },
...@@ -5344,6 +5465,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -5344,6 +5465,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
5344 }5465 }
53455466
5346 const ty = self.air.typeOf(bin_op.lhs);5467 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
5347 const signedness: std.builtin.Signedness = blk: {5471 const signedness: std.builtin.Signedness = blk: {
5348 // For non-int types, we treat the values as unsigned5472 // For non-int types, we treat the values as unsigned
5349 if (ty.zigTypeTag() != .Int) break :blk .unsigned;5473 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
...@@ -6655,10 +6779,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -6655,10 +6779,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
6655 }6779 }
6656 },6780 },
6657 .register => |reg| {6781 .register => |reg| {
6658 if (stack_offset > math.maxInt(i32)) {
6659 return self.fail("stack offset too large", .{});
6660 }
6661
6662 const base_reg = opts.dest_stack_base orelse .rbp;6782 const base_reg = opts.dest_stack_base orelse .rbp;
66636783
6664 switch (ty.zigTypeTag()) {6784 switch (ty.zigTypeTag()) {
...@@ -6893,13 +7013,11 @@ fn genInlineMemset(...@@ -6893,13 +7013,11 @@ fn genInlineMemset(
68937013
6894fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {7014fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
6895 const abi_size = @intCast(u32, ty.abiSize(self.target.*));7015 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", .{});
6896 switch (mcv) {7017 switch (mcv) {
6897 .dead => unreachable,7018 .dead => unreachable,
6898 .register_overflow => unreachable,7019 .register_overflow => unreachable,
6899 .ptr_stack_offset => |off| {7020 .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 }
6903 try self.asmRegisterMemory(7021 try self.asmRegisterMemory(
6904 .lea,7022 .lea,
6905 registerAlias(reg, abi_size),7023 registerAlias(reg, abi_size),
...@@ -7060,16 +7178,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7060,16 +7178,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
7060 if (reg.to64() == .rax) {7178 if (reg.to64() == .rax) {
7061 // If this is RAX, we can use a direct load.7179 // If this is RAX, we can use a direct load.
7062 // Otherwise, we need to load the address, then indirectly load the value.7180 // 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);
7069 _ = try self.addInst(.{7181 _ = try self.addInst(.{
7070 .tag = .mov_moffs,7182 .tag = .mov_moffs,
7071 .ops = .rax_moffs,7183 .ops = .rax_moffs,
7072 .data = .{ .payload = try self.addExtra(moffs) },7184 .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, x)) },
7073 });7185 });
7074 } else {7186 } else {
7075 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.7187 // 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...@@ -7084,10 +7196,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
7084 },7196 },
7085 },7197 },
7086 .stack_offset => |off| {7198 .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
7091 switch (ty.zigTypeTag()) {7199 switch (ty.zigTypeTag()) {
7092 .Int => switch (ty.intInfo(self.target.*).signedness) {7200 .Int => switch (ty.intInfo(self.target.*).signedness) {
7093 .signed => {7201 .signed => {
...@@ -7151,7 +7259,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7151,7 +7259,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
71517259
7152fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {7260fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
7153 const un_op = self.air.instructions.items(.data)[inst].un_op;7261 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 };
7155 return self.finishAir(inst, result, .{ un_op, .none, .none });7271 return self.finishAir(inst, result, .{ un_op, .none, .none });
7156}7272}
71577273
src/arch/x86_64/Emit.zig+168-737
...@@ -1,40 +1,8 @@...@@ -1,40 +1,8 @@
1//! This file contains the functionality for lowering x86_64 MIR into1//! This file contains the functionality for emitting x86_64 MIR as machine code
2//! machine code
32
4const Emit = @This();3lower: Lower,
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,
33bin_file: *link.File,4bin_file: *link.File,
34debug_output: DebugInfoOutput,5debug_output: DebugInfoOutput,
35target: *const std.Target,
36err_msg: ?*ErrorMsg = null,
37src_loc: Module.SrcLoc,
38code: *std.ArrayList(u8),6code: *std.ArrayList(u8),
397
40prev_di_line: u32,8prev_di_line: u32,
...@@ -45,166 +13,176 @@ prev_di_pc: usize,...@@ -45,166 +13,176 @@ prev_di_pc: usize,
45code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{},13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{},
46relocs: std.ArrayListUnmanaged(Reloc) = .{},14relocs: std.ArrayListUnmanaged(Reloc) = .{},
4715
48const InnerError = error{16pub const Error = Lower.Error || error{EmitFail};
49 OutOfMemory,17
50 EmitFail,18pub fn emitMir(emit: *Emit) Error!void {
51 InvalidInstruction,19 for (0..emit.lower.mir.instructions.len) |i| {
52 CannotEncode,20 const index = @intCast(Mir.Inst.Index, i);
53};21 const inst = emit.lower.mir.instructions.get(index);
5422
55const Reloc = struct {23 const start_offset = @intCast(u32, emit.code.items.len);
56 /// Offset of the instruction.24 try emit.code_offset_mapping.putNoClobber(emit.lower.allocator, index, start_offset);
57 source: usize,25 for (try emit.lower.lowerMir(inst)) |lower_inst| try lower_inst.encode(emit.code.writer());
58 /// Target of the relocation.26 const end_offset = @intCast(u32, emit.code.items.len);
59 target: Mir.Inst.Index,27
60 /// Offset of the relocation within the instruction.28 switch (inst.tag) {
61 offset: usize,29 else => {},
62 /// Length of the instruction.30
63 length: u5,31 .jmp_reloc => try emit.relocs.append(emit.lower.allocator, .{
64};32 .source = start_offset,
6533 .target = inst.data.inst,
66pub fn lowerMir(emit: *Emit) InnerError!void {34 .offset = end_offset - 4,
67 const mir_tags = emit.mir.instructions.items(.tag);35 .length = 5,
6836 }),
69 for (mir_tags, 0..) |tag, index| {37
70 const inst = @intCast(u32, index);38 .call_extern => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
71 try emit.code_offset_mapping.putNoClobber(emit.bin_file.allocator, inst, emit.code.items.len);39 // Add relocation to the decl.
72 switch (tag) {40 const atom_index = macho_file.getAtomIndexForSymbol(
73 .adc,41 .{ .sym_index = inst.data.relocation.atom_index, .file = null },
74 .add,42 ).?;
75 .@"and",43 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);
76 .bsf,44 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
77 .bsr,45 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
78 .bswap,46 .target = target,
79 .bt,47 .offset = end_offset - 4,
80 .btc,48 .addend = 0,
81 .btr,49 .pcrel = true,
82 .bts,50 .length = 2,
83 .call,51 });
84 .cbw,52 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
85 .cwde,53 // Add relocation to the decl.
86 .cdqe,54 const atom_index = coff_file.getAtomIndexForSymbol(
87 .cwd,55 .{ .sym_index = inst.data.relocation.atom_index, .file = null },
88 .cdq,56 ).?;
89 .cqo,57 const target = coff_file.getGlobalByIndex(inst.data.relocation.sym_index);
90 .cmp,58 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
91 .cmpxchg,59 .type = .direct,
92 .div,60 .target = target,
93 .fisttp,61 .offset = end_offset - 4,
94 .fld,62 .addend = 0,
95 .idiv,63 .pcrel = true,
96 .imul,64 .length = 2,
97 .int3,65 });
98 .jmp,66 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
99 .lea,67
100 .lfence,68 .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
101 .lzcnt,69 const metadata =
102 .mfence,70 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
103 .mov,71 const reloc_type = switch (inst.ops) {
104 .movbe,72 .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
105 .movzx,73 .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
106 .mul,74 else => unreachable,
107 .neg,75 };
108 .nop,76 const atom_index = macho_file.getAtomIndexForSymbol(.{
109 .not,77 .sym_index = metadata.atom_index,
110 .@"or",78 .file = null,
111 .pop,79 }).?;
112 .popcnt,80 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
113 .push,81 .type = reloc_type,
114 .rcl,82 .target = .{ .sym_index = metadata.sym_index, .file = null },
115 .rcr,83 .offset = @intCast(u32, end_offset - 4),
116 .ret,84 .addend = 0,
117 .rol,85 .pcrel = true,
118 .ror,86 .length = 2,
119 .sal,87 });
120 .sar,88 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
121 .sbb,89 const metadata =
122 .sfence,90 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
123 .shl,91 const atom_index = coff_file.getAtomIndexForSymbol(.{
124 .shld,92 .sym_index = metadata.atom_index,
125 .shr,93 .file = null,
126 .shrd,94 }).?;
127 .sub,95 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
128 .syscall,96 .type = switch (inst.ops) {
129 .@"test",97 .got_reloc => .got,
130 .tzcnt,98 .direct_reloc => .direct,
131 .ud2,99 .import_reloc => .import,
132 .xadd,100 else => unreachable,
133 .xchg,101 },
134 .xor,102 .target = switch (inst.ops) {
135103 .got_reloc,
136 .addss,104 .direct_reloc,
137 .cmpss,105 => .{ .sym_index = metadata.sym_index, .file = null },
138 .divss,106 .import_reloc => coff_file.getGlobalByIndex(metadata.sym_index),
139 .maxss,107 else => unreachable,
140 .minss,108 },
141 .movss,109 .offset = @intCast(u32, end_offset - 4),
142 .mulss,110 .addend = 0,
143 .roundss,111 .pcrel = true,
144 .subss,112 .length = 2,
145 .ucomiss,113 });
146 .addsd,114 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
147 .cmpsd,115
148 .divsd,116 .jcc => try emit.relocs.append(emit.lower.allocator, .{
149 .maxsd,117 .source = start_offset,
150 .minsd,118 .target = inst.data.inst_cc.inst,
151 .movsd,119 .offset = end_offset - 4,
152 .mulsd,120 .length = 6,
153 .roundsd,121 }),
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),
179122
180 .dbg_line => try emit.mirDbgLine(inst),123 .dbg_line => {
181 .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),124 const dbg_line_column =
182 .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),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),129 .dbg_prologue_end => {
185 .pop_regs => try emit.mirPushPopRegisterList(.pop, inst),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 },
188 }156 }
189 }157 }
190
191 try emit.fixupRelocs();158 try emit.fixupRelocs();
192}159}
193160
194pub fn deinit(emit: *Emit) void {161pub fn deinit(emit: *Emit) void {
195 emit.relocs.deinit(emit.bin_file.allocator);162 emit.relocs.deinit(emit.lower.allocator);
196 emit.code_offset_mapping.deinit(emit.bin_file.allocator);163 emit.code_offset_mapping.deinit(emit.lower.allocator);
197 emit.* = undefined;164 emit.* = undefined;
198}165}
199166
200fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {167fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
201 @setCold(true);168 return switch (emit.lower.fail(format, args)) {
202 assert(emit.err_msg == null);169 error.LowerFail => error.EmitFail,
203 emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args);170 else => |e| e,
204 return error.EmitFail;171 };
205}172}
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 {
208 // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.186 // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
209 // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest187 // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
210 // possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution188 // possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
...@@ -217,532 +195,7 @@ fn fixupRelocs(emit: *Emit) InnerError!void {...@@ -217,532 +195,7 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
217 }195 }
218}196}
219197
220fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: Instruction.Init) InnerError!void {198fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!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 {
746 const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line);199 const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line);
747 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;200 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
748 log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });201 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 {...@@ -756,7 +209,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
756 .plan9 => |dbg_out| {209 .plan9 => |dbg_out| {
757 if (delta_pc <= 0) return; // only do this when the pc changes210 if (delta_pc <= 0) return; // only do this when the pc changes
758 // we have already checked the target in the linker to make sure it is compatable211 // 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
761 // increasing the line number214 // increasing the line number
762 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);215 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 {...@@ -792,34 +245,12 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
792 }245 }
793}246}
794247
795fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {248const link = @import("../../link.zig");
796 _ = inst;249const log = std.log.scoped(.emit);
797 switch (emit.debug_output) {250const mem = std.mem;
798 .dwarf => |dw| {251const std = @import("std");
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}
810252
811fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {253const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
812 _ = inst;254const Emit = @This();
813 switch (emit.debug_output) {255const Lower = @import("Lower.zig");
814 .dwarf => |dw| {256const Mir = @import("Mir.zig");
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}
src/arch/x86_64/Encoding.zig+137-157
...@@ -7,30 +7,32 @@ const math = std.math;...@@ -7,30 +7,32 @@ const math = std.math;
7const bits = @import("bits.zig");7const bits = @import("bits.zig");
8const encoder = @import("encoder.zig");8const encoder = @import("encoder.zig");
9const Instruction = encoder.Instruction;9const Instruction = encoder.Instruction;
10const Operand = Instruction.Operand;
11const Prefix = Instruction.Prefix;
10const Register = bits.Register;12const Register = bits.Register;
11const Rex = encoder.Rex;13const Rex = encoder.Rex;
12const LegacyPrefixes = encoder.LegacyPrefixes;14const LegacyPrefixes = encoder.LegacyPrefixes;
1315
14const table = @import("encodings.zig").table;
15
16mnemonic: Mnemonic,16mnemonic: Mnemonic,
17op_en: OpEn,17data: Data,
18op1: Op,18
19op2: Op,19const Data = struct {
20op3: Op,20 op_en: OpEn,
21op4: Op,21 ops: [4]Op,
22opc_len: u3,22 opc_len: u3,
23opc: [7]u8,23 opc: [7]u8,
24modrm_ext: u3,24 modrm_ext: u3,
25mode: Mode,25 mode: Mode,
2626};
27pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding {27
28 const input_op1 = Op.fromOperand(args.op1);28pub fn findByMnemonic(
29 const input_op2 = Op.fromOperand(args.op2);29 prefix: Instruction.Prefix,
30 const input_op3 = Op.fromOperand(args.op3);30 mnemonic: Mnemonic,
31 const input_op4 = Op.fromOperand(args.op4);31 ops: []const Instruction.Operand,
3232) !?Encoding {
33 const ops = &[_]Instruction.Operand{ args.op1, args.op2, args.op3, args.op4 };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
34 const rex_required = for (ops) |op| switch (op) {36 const rex_required = for (ops) |op| switch (op) {
35 .reg => |r| switch (r) {37 .reg => |r| switch (r) {
36 .spl, .bpl, .sil, .dil => break true,38 .spl, .bpl, .sil, .dil => break true,
...@@ -60,88 +62,29 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding {...@@ -60,88 +62,29 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding {
6062
61 if ((rex_required or rex_extended) and rex_invalid) return error.CannotEncode;63 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.65 var shortest_enc: ?Encoding = null;
64 var candidates: [10]Encoding = undefined;66 var shortest_len: ?usize = null;
65 var count: usize = 0;67 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
66 for (table) |entry| {68 switch (data.mode) {
67 var enc = Encoding{69 .rex => if (!rex_required) continue,
68 .mnemonic = entry[0],70 .long => {},
69 .op_en = entry[1],71 else => if (rex_required) continue,
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 }
100 }72 }
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;
101 }86 }
10287 return shortest_enc;
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];
145}88}
14689
147/// Returns first matching encoding by opcode.90/// Returns first matching encoding by opcode.
...@@ -149,57 +92,45 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {...@@ -149,57 +92,45 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
149 legacy: LegacyPrefixes,92 legacy: LegacyPrefixes,
150 rex: Rex,93 rex: Rex,
151}, modrm_ext: ?u3) ?Encoding {94}, modrm_ext: ?u3) ?Encoding {
152 for (table) |entry| {95 for (mnemonic_to_encodings_map, 0..) |encs, mnemonic_int| for (encs) |data| {
153 const enc = Encoding{96 const enc = Encoding{ .mnemonic = @intToEnum(Mnemonic, mnemonic_int), .data = data };
154 .mnemonic = entry[0],97 if (modrm_ext) |ext| if (ext != data.modrm_ext) continue;
155 .op_en = entry[1],98 if (!std.mem.eql(u8, opc, enc.opcode())) continue;
156 .op1 = entry[2],99 if (prefixes.rex.w) {
157 .op2 = entry[3],100 switch (data.mode) {
158 .op3 = entry[4],101 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
159 .op4 = entry[5],102 .long, .rex => {},
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);
168 }103 }
169 break :match std.mem.eql(u8, enc.opcode(), opc);104 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
170 };105 switch (data.mode) {
171 if (match) {106 .rex => {},
172 if (prefixes.rex.w) {107 else => continue,
173 switch (enc.mode) {108 }
174 .fpu, .sse, .sse2, .sse4_1, .none => {},109 } else if (prefixes.legacy.prefix_66) {
175 .long, .rex => return enc,110 switch (enc.operandBitSize()) {
176 }111 16 => {},
177 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {112 else => continue,
178 if (enc.mode == .rex) return enc;113 }
179 } else if (prefixes.legacy.prefix_66) {114 } else {
180 switch (enc.operandBitSize()) {115 switch (data.mode) {
181 16 => return enc,116 .none => switch (enc.operandBitSize()) {
117 16 => continue,
182 else => {},118 else => {},
183 }119 },
184 } else {120 else => continue,
185 if (enc.mode == .none) {
186 switch (enc.operandBitSize()) {
187 16 => {},
188 else => return enc,
189 }
190 }
191 }121 }
192 }122 }
193 }123 return enc;
124 };
194 return null;125 return null;
195}126}
196127
197pub fn opcode(encoding: *const Encoding) []const u8 {128pub 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];
199}130}
200131
201pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {132pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
202 const prefix = encoding.opc[0];133 const prefix = encoding.data.opc[0];
203 return switch (prefix) {134 return switch (prefix) {
204 0x66, 0xf2, 0xf3 => prefix,135 0x66, 0xf2, 0xf3 => prefix,
205 else => null,136 else => null,
...@@ -207,27 +138,27 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {...@@ -207,27 +138,27 @@ pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 {
207}138}
208139
209pub fn modRmExt(encoding: Encoding) u3 {140pub fn modRmExt(encoding: Encoding) u3 {
210 return switch (encoding.op_en) {141 return switch (encoding.data.op_en) {
211 .m, .mi, .m1, .mc => encoding.modrm_ext,142 .m, .mi, .m1, .mc => encoding.data.modrm_ext,
212 else => unreachable,143 else => unreachable,
213 };144 };
214}145}
215146
216pub fn operandBitSize(encoding: Encoding) u64 {147pub fn operandBitSize(encoding: Encoding) u64 {
217 switch (encoding.mode) {148 switch (encoding.data.mode) {
218 .short => return 16,149 .short => return 16,
219 .long => return 64,150 .long => return 64,
220 else => {},151 else => {},
221 }152 }
222 const bit_size: u64 = switch (encoding.op_en) {153 const bit_size: u64 = switch (encoding.data.op_en) {
223 .np => switch (encoding.op1) {154 .np => switch (encoding.data.ops[0]) {
224 .o16 => 16,155 .o16 => 16,
225 .o32 => 32,156 .o32 => 32,
226 .o64 => 64,157 .o64 => 64,
227 else => 32,158 else => 32,
228 },159 },
229 .td => encoding.op2.bitSize(),160 .td => encoding.data.ops[1].bitSize(),
230 else => encoding.op1.bitSize(),161 else => encoding.data.ops[0].bitSize(),
231 };162 };
232 return bit_size;163 return bit_size;
233}164}
...@@ -240,7 +171,7 @@ pub fn format(...@@ -240,7 +171,7 @@ pub fn format(
240) !void {171) !void {
241 _ = options;172 _ = options;
242 _ = fmt;173 _ = fmt;
243 switch (encoding.mode) {174 switch (encoding.data.mode) {
244 .long => try writer.writeAll("REX.W + "),175 .long => try writer.writeAll("REX.W + "),
245 else => {},176 else => {},
246 }177 }
...@@ -249,10 +180,10 @@ pub fn format(...@@ -249,10 +180,10 @@ pub fn format(
249 try writer.print("{x:0>2} ", .{byte});180 try writer.print("{x:0>2} ", .{byte});
250 }181 }
251182
252 switch (encoding.op_en) {183 switch (encoding.data.op_en) {
253 .np, .fd, .td, .i, .zi, .d => {},184 .np, .fd, .td, .i, .zi, .d => {},
254 .o, .oi => {185 .o, .oi => {
255 const tag = switch (encoding.op1) {186 const tag = switch (encoding.data.ops[0]) {
256 .r8 => "rb",187 .r8 => "rb",
257 .r16 => "rw",188 .r16 => "rw",
258 .r32 => "rd",189 .r32 => "rd",
...@@ -265,12 +196,12 @@ pub fn format(...@@ -265,12 +196,12 @@ pub fn format(
265 .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),196 .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),
266 }197 }
267198
268 switch (encoding.op_en) {199 switch (encoding.data.op_en) {
269 .i, .d, .zi, .oi, .mi, .rmi, .mri => {200 .i, .d, .zi, .oi, .mi, .rmi, .mri => {
270 const op = switch (encoding.op_en) {201 const op = switch (encoding.data.op_en) {
271 .i, .d => encoding.op1,202 .i, .d => encoding.data.ops[0],
272 .zi, .oi, .mi => encoding.op2,203 .zi, .oi, .mi => encoding.data.ops[1],
273 .rmi, .mri => encoding.op3,204 .rmi, .mri => encoding.data.ops[2],
274 else => unreachable,205 else => unreachable,
275 };206 };
276 const tag = switch (op) {207 const tag = switch (op) {
...@@ -290,13 +221,12 @@ pub fn format(...@@ -290,13 +221,12 @@ pub fn format(
290221
291 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});222 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
292223
293 const ops = &[_]Op{ encoding.op1, encoding.op2, encoding.op3, encoding.op4 };224 for (encoding.data.ops) |op| switch (op) {
294 for (ops) |op| switch (op) {
295 .none, .o16, .o32, .o64 => break,225 .none, .o16, .o32, .o64 => break,
296 else => try writer.print("{s} ", .{@tagName(op)}),226 else => try writer.print("{s} ", .{@tagName(op)}),
297 };227 };
298228
299 const op_en = switch (encoding.op_en) {229 const op_en = switch (encoding.data.op_en) {
300 .zi => .i,230 .zi => .i,
301 else => |op_en| op_en,231 else => |op_en| op_en,
302 };232 };
...@@ -604,3 +534,53 @@ pub const Mode = enum {...@@ -604,3 +534,53 @@ pub const Mode = enum {
604 sse2,534 sse2,
605 sse4_1,535 sse4_1,
606};536};
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 {...@@ -655,16 +655,19 @@ pub const MemoryMoffs = struct {
655 msb: u32,655 msb: u32,
656 lsb: u32,656 lsb: u32,
657657
658 pub fn encodeOffset(moffs: *MemoryMoffs, v: u64) void {658 pub fn encode(seg: Register, offset: u64) MemoryMoffs {
659 moffs.msb = @truncate(u32, v >> 32);659 return .{
660 moffs.lsb = @truncate(u32, v);660 .seg = @enumToInt(seg),
661 .msb = @truncate(u32, offset >> 32),
662 .lsb = @truncate(u32, offset >> 0),
663 };
661 }664 }
662665
663 pub fn decodeOffset(moffs: *const MemoryMoffs) u64 {666 pub fn decode(moffs: MemoryMoffs) Memory {
664 var res: u64 = 0;667 return .{ .moffs = .{
665 res |= (@intCast(u64, moffs.msb) << 32);668 .seg = @intToEnum(Register, moffs.seg),
666 res |= @intCast(u64, moffs.lsb);669 .offset = @as(u64, moffs.msb) << 32 | @as(u64, moffs.lsb) << 0,
667 return res;670 } };
668 }671 }
669};672};
670673
src/arch/x86_64/bits.zig+1-1
...@@ -515,7 +515,7 @@ pub const Memory = union(enum) {...@@ -515,7 +515,7 @@ pub const Memory = union(enum) {
515 return switch (mem) {515 return switch (mem) {
516 .rip => |r| r.ptr_size.bitSize(),516 .rip => |r| r.ptr_size.bitSize(),
517 .sib => |s| s.ptr_size.bitSize(),517 .sib => |s| s.ptr_size.bitSize(),
518 .moffs => unreachable,518 .moffs => 64,
519 };519 };
520 }520 }
521};521};
src/arch/x86_64/encoder.zig+560-402
...@@ -11,12 +11,9 @@ const Memory = bits.Memory;...@@ -11,12 +11,9 @@ const Memory = bits.Memory;
11const Register = bits.Register;11const Register = bits.Register;
1212
13pub const Instruction = struct {13pub const Instruction = struct {
14 op1: Operand = .none,
15 op2: Operand = .none,
16 op3: Operand = .none,
17 op4: Operand = .none,
18 prefix: Prefix = .none,14 prefix: Prefix = .none,
19 encoding: Encoding,15 encoding: Encoding,
16 ops: [4]Operand = .{.none} ** 4,
2017
21 pub const Mnemonic = Encoding.Mnemonic;18 pub const Mnemonic = Encoding.Mnemonic;
2219
...@@ -57,18 +54,17 @@ pub const Instruction = struct {...@@ -57,18 +54,17 @@ pub const Instruction = struct {
57 };54 };
58 }55 }
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 {
61 switch (op) {58 switch (op) {
62 .none => {},59 .none => {},
63 .reg => |reg| try writer.writeAll(@tagName(reg)),60 .reg => |reg| try writer.writeAll(@tagName(reg)),
64 .mem => |mem| switch (mem) {61 .mem => |mem| switch (mem) {
65 .rip => |rip| {62 .rip => |rip| {
66 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});63 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
67 if (rip.disp != 0) {64 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
68 const sign_bit = if (sign(rip.disp) < 0) "-" else "+";65 @as(u8, if (rip.disp < 0) '-' else '+'),
69 const disp_abs = try std.math.absInt(rip.disp);66 std.math.absCast(rip.disp),
70 try writer.print(" {s} 0x{x}", .{ sign_bit, disp_abs });67 });
71 }
72 try writer.writeByte(']');68 try writer.writeByte(']');
73 },69 },
74 .sib => |sib| {70 .sib => |sib| {
...@@ -80,129 +76,118 @@ pub const Instruction = struct {...@@ -80,129 +76,118 @@ pub const Instruction = struct {
8076
81 try writer.writeByte('[');77 try writer.writeByte('[');
8278
79 var any = false;
83 if (sib.base) |base| {80 if (sib.base) |base| {
84 try writer.print("{s}", .{@tagName(base)});81 try writer.print("{s}", .{@tagName(base)});
82 any = true;
85 }83 }
86 if (sib.scale_index) |si| {84 if (sib.scale_index) |si| {
87 if (sib.base != null) {85 if (any) try writer.writeAll(" + ");
88 try writer.writeAll(" + ");
89 }
90 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });86 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
87 any = true;
91 }88 }
92 if (sib.disp != 0) {89 if (sib.disp != 0 or !any) {
93 if (sib.base != null or sib.scale_index != null) {90 if (any)
94 try writer.writeByte(' ');91 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
95 }92 else if (sib.disp < 0)
96 try writer.writeByte(if (sign(sib.disp) < 0) '-' else '+');93 try writer.writeByte('-');
97 const disp_abs = try std.math.absInt(sib.disp);94 try writer.print("0x{x}", .{std.math.absCast(sib.disp)});
98 try writer.print(" 0x{x}", .{disp_abs});95 any = true;
99 }96 }
10097
101 try writer.writeByte(']');98 try writer.writeByte(']');
102 },99 },
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 }),
104 },104 },
105 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),105 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
106 }106 }
107 }107 }
108 };108 };
109109
110 pub const Init = struct {110 pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {
111 prefix: Prefix = .none,111 const encoding = (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
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 {
120 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{112 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
121 @tagName(args.prefix),113 @tagName(prefix),
122 @tagName(mnemonic),114 @tagName(mnemonic),
123 @tagName(Encoding.Op.fromOperand(args.op1)),115 @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
124 @tagName(Encoding.Op.fromOperand(args.op2)),116 @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
125 @tagName(Encoding.Op.fromOperand(args.op3)),117 @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
126 @tagName(Encoding.Op.fromOperand(args.op4)),118 @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
127 });119 });
128 return error.InvalidInstruction;120 return error.InvalidInstruction;
129 };121 };
130 log.debug("selected encoding: {}", .{encoding});122 log.debug("selected encoding: {}", .{encoding});
131 return .{123
132 .prefix = args.prefix,124 var inst = Instruction{
133 .op1 = args.op1,125 .prefix = prefix,
134 .op2 = args.op2,
135 .op3 = args.op3,
136 .op4 = args.op4,
137 .encoding = encoding,126 .encoding = encoding,
127 .ops = [1]Operand{.none} ** 4,
138 };128 };
129 std.mem.copy(Operand, &inst.ops, ops);
130 return inst;
139 }131 }
140132
141 pub fn fmtPrint(inst: Instruction, writer: anytype) !void {133 pub fn fmtPrint(inst: Instruction, writer: anytype) @TypeOf(writer).Error!void {
142 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});134 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
143 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});135 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
144 const ops = [_]struct { Operand, Encoding.Op }{136 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
145 .{ inst.op1, inst.encoding.op1 },137 if (op == .none) break;
146 .{ inst.op2, inst.encoding.op2 },138 if (i > 0) try writer.writeByte(',');
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 }
155 try writer.writeByte(' ');139 try writer.writeByte(' ');
156 try op[0].fmtPrint(op[1], writer);140 try op.fmtPrint(enc, writer);
157 }141 }
158 }142 }
159143
160 pub fn encode(inst: Instruction, writer: anytype) !void {144 pub fn encode(inst: Instruction, writer: anytype) !void {
161 const encoder = Encoder(@TypeOf(writer)){ .writer = writer };145 const encoder = Encoder(@TypeOf(writer)){ .writer = writer };
162 const encoding = inst.encoding;146 const enc = inst.encoding;
147 const data = enc.data;
163148
164 try inst.encodeLegacyPrefixes(encoder);149 try inst.encodeLegacyPrefixes(encoder);
165 try inst.encodeMandatoryPrefix(encoder);150 try inst.encodeMandatoryPrefix(encoder);
166 try inst.encodeRexPrefix(encoder);151 try inst.encodeRexPrefix(encoder);
167 try inst.encodeOpcode(encoder);152 try inst.encodeOpcode(encoder);
168153
169 switch (encoding.op_en) {154 switch (data.op_en) {
170 .np, .o => {},155 .np, .o => {},
171 .i, .d => try encodeImm(inst.op1.imm, encoding.op1, encoder),156 .i, .d => try encodeImm(inst.ops[0].imm, data.ops[0], encoder),
172 .zi, .oi => try encodeImm(inst.op2.imm, encoding.op2, encoder),157 .zi, .oi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
173 .fd => try encoder.imm64(inst.op2.mem.moffs.offset),158 .fd => try encoder.imm64(inst.ops[1].mem.moffs.offset),
174 .td => try encoder.imm64(inst.op1.mem.moffs.offset),159 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
175 else => {160 else => {
176 const mem_op = switch (encoding.op_en) {161 const mem_op = switch (data.op_en) {
177 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,162 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
178 .rm, .rmi => inst.op2,163 .rm, .rmi => inst.ops[1],
179 else => unreachable,164 else => unreachable,
180 };165 };
181 switch (mem_op) {166 switch (mem_op) {
182 .reg => |reg| {167 .reg => |reg| {
183 const rm = switch (encoding.op_en) {168 const rm = switch (data.op_en) {
184 .m, .mi, .m1, .mc => encoding.modRmExt(),169 .m, .mi, .m1, .mc => enc.modRmExt(),
185 .mr, .mri, .mrc => inst.op2.reg.lowEnc(),170 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
186 .rm, .rmi => inst.op1.reg.lowEnc(),171 .rm, .rmi => inst.ops[0].reg.lowEnc(),
187 else => unreachable,172 else => unreachable,
188 };173 };
189 try encoder.modRm_direct(rm, reg.lowEnc());174 try encoder.modRm_direct(rm, reg.lowEnc());
190 },175 },
191 .mem => |mem| {176 .mem => |mem| {
192 const op = switch (encoding.op_en) {177 const op = switch (data.op_en) {
193 .m, .mi, .m1, .mc => .none,178 .m, .mi, .m1, .mc => .none,
194 .mr, .mri, .mrc => inst.op2,179 .mr, .mri, .mrc => inst.ops[1],
195 .rm, .rmi => inst.op1,180 .rm, .rmi => inst.ops[0],
196 else => unreachable,181 else => unreachable,
197 };182 };
198 try encodeMemory(encoding, mem, op, encoder);183 try encodeMemory(enc, mem, op, encoder);
199 },184 },
200 else => unreachable,185 else => unreachable,
201 }186 }
202187
203 switch (encoding.op_en) {188 switch (data.op_en) {
204 .mi => try encodeImm(inst.op2.imm, encoding.op2, encoder),189 .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
205 .rmi, .mri => try encodeImm(inst.op3.imm, encoding.op3, encoder),190 .rmi, .mri => try encodeImm(inst.ops[2].imm, data.ops[2], encoder),
206 else => {},191 else => {},
207 }192 }
208 },193 },
...@@ -214,15 +199,16 @@ pub const Instruction = struct {...@@ -214,15 +199,16 @@ pub const Instruction = struct {
214 const first = @boolToInt(inst.encoding.mandatoryPrefix() != null);199 const first = @boolToInt(inst.encoding.mandatoryPrefix() != null);
215 const final = opcode.len - 1;200 const final = opcode.len - 1;
216 for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);201 for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);
217 switch (inst.encoding.op_en) {202 switch (inst.encoding.data.op_en) {
218 .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()),203 .o, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()),
219 else => try encoder.opcode_1byte(opcode[final]),204 else => try encoder.opcode_1byte(opcode[final]),
220 }205 }
221 }206 }
222207
223 fn encodeLegacyPrefixes(inst: Instruction, encoder: anytype) !void {208 fn encodeLegacyPrefixes(inst: Instruction, encoder: anytype) !void {
224 const enc = inst.encoding;209 const enc = inst.encoding;
225 const op_en = enc.op_en;210 const data = enc.data;
211 const op_en = data.op_en;
226212
227 var legacy = LegacyPrefixes{};213 var legacy = LegacyPrefixes{};
228214
...@@ -233,7 +219,7 @@ pub const Instruction = struct {...@@ -233,7 +219,7 @@ pub const Instruction = struct {
233 .rep, .repe, .repz => legacy.prefix_f3 = true,219 .rep, .repe, .repz => legacy.prefix_f3 = true,
234 }220 }
235221
236 if (enc.mode == .none) {222 if (data.mode == .none) {
237 const bit_size = enc.operandBitSize();223 const bit_size = enc.operandBitSize();
238 if (bit_size == 16) {224 if (bit_size == 16) {
239 legacy.set16BitOverride();225 legacy.set16BitOverride();
...@@ -242,17 +228,17 @@ pub const Instruction = struct {...@@ -242,17 +228,17 @@ pub const Instruction = struct {
242228
243 const segment_override: ?Register = switch (op_en) {229 const segment_override: ?Register = switch (op_en) {
244 .i, .zi, .o, .oi, .d, .np => null,230 .i, .zi, .o, .oi, .d, .np => null,
245 .fd => inst.op2.mem.base().?,231 .fd => inst.ops[1].mem.base().?,
246 .td => inst.op1.mem.base().?,232 .td => inst.ops[0].mem.base().?,
247 .rm, .rmi => if (inst.op2.isSegmentRegister()) blk: {233 .rm, .rmi => if (inst.ops[1].isSegmentRegister()) blk: {
248 break :blk switch (inst.op2) {234 break :blk switch (inst.ops[1]) {
249 .reg => |r| r,235 .reg => |r| r,
250 .mem => |m| m.base().?,236 .mem => |m| m.base().?,
251 else => unreachable,237 else => unreachable,
252 };238 };
253 } else null,239 } else null,
254 .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.op1.isSegmentRegister()) blk: {240 .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.ops[0].isSegmentRegister()) blk: {
255 break :blk switch (inst.op1) {241 break :blk switch (inst.ops[0]) {
256 .reg => |r| r,242 .reg => |r| r,
257 .mem => |m| m.base().?,243 .mem => |m| m.base().?,
258 else => unreachable,244 else => unreachable,
...@@ -267,19 +253,19 @@ pub const Instruction = struct {...@@ -267,19 +253,19 @@ pub const Instruction = struct {
267 }253 }
268254
269 fn encodeRexPrefix(inst: Instruction, encoder: anytype) !void {255 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
272 var rex = Rex{};258 var rex = Rex{};
273 rex.present = inst.encoding.mode == .rex;259 rex.present = inst.encoding.data.mode == .rex;
274 rex.w = inst.encoding.mode == .long;260 rex.w = inst.encoding.data.mode == .long;
275261
276 switch (op_en) {262 switch (op_en) {
277 .np, .i, .zi, .fd, .td, .d => {},263 .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(),
279 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {265 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {
280 const r_op = switch (op_en) {266 const r_op = switch (op_en) {
281 .rm, .rmi => inst.op1,267 .rm, .rmi => inst.ops[0],
282 .mr, .mri, .mrc => inst.op2,268 .mr, .mri, .mrc => inst.ops[1],
283 else => null,269 else => null,
284 };270 };
285 if (r_op) |op| {271 if (r_op) |op| {
...@@ -287,8 +273,8 @@ pub const Instruction = struct {...@@ -287,8 +273,8 @@ pub const Instruction = struct {
287 }273 }
288274
289 const b_x_op = switch (op_en) {275 const b_x_op = switch (op_en) {
290 .rm, .rmi => inst.op2,276 .rm, .rmi => inst.ops[1],
291 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,277 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
292 else => unreachable,278 else => unreachable,
293 };279 };
294 switch (b_x_op) {280 switch (b_x_op) {
...@@ -407,10 +393,6 @@ pub const Instruction = struct {...@@ -407,10 +393,6 @@ pub const Instruction = struct {
407 }393 }
408};394};
409395
410inline fn sign(i: anytype) @TypeOf(i) {
411 return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0);
412}
413
414pub const LegacyPrefixes = packed struct {396pub const LegacyPrefixes = packed struct {
415 /// LOCK397 /// LOCK
416 prefix_f0: bool = false,398 prefix_f0: bool = false,
...@@ -827,16 +809,14 @@ const TestEncode = struct {...@@ -827,16 +809,14 @@ const TestEncode = struct {
827 buffer: [32]u8 = undefined,809 buffer: [32]u8 = undefined,
828 index: usize = 0,810 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 {
831 var stream = std.io.fixedBufferStream(&enc.buffer);817 var stream = std.io.fixedBufferStream(&enc.buffer);
832 var count_writer = std.io.countingWriter(stream.writer());818 var count_writer = std.io.countingWriter(stream.writer());
833 const inst = try Instruction.new(mnemonic, .{819 const inst = try Instruction.new(.none, mnemonic, ops);
834 .prefix = args.prefix,
835 .op1 = args.op1,
836 .op2 = args.op2,
837 .op3 = args.op3,
838 .op4 = args.op4,
839 });
840 try inst.encode(count_writer.writer());820 try inst.encode(count_writer.writer());
841 enc.index = count_writer.bytes_written;821 enc.index = count_writer.bytes_written;
842 }822 }
...@@ -850,9 +830,9 @@ test "encode" {...@@ -850,9 +830,9 @@ test "encode" {
850 var buf = std.ArrayList(u8).init(testing.allocator);830 var buf = std.ArrayList(u8).init(testing.allocator);
851 defer buf.deinit();831 defer buf.deinit();
852832
853 const inst = try Instruction.new(.mov, .{833 const inst = try Instruction.new(.none, .mov, &.{
854 .op1 = .{ .reg = .rbx },834 .{ .reg = .rbx },
855 .op2 = .{ .imm = Immediate.u(4) },835 .{ .imm = Immediate.u(4) },
856 });836 });
857 try inst.encode(buf.writer());837 try inst.encode(buf.writer());
858 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);838 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
...@@ -861,61 +841,94 @@ test "encode" {...@@ -861,61 +841,94 @@ test "encode" {
861test "lower I encoding" {841test "lower I encoding" {
862 var enc = TestEncode{};842 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 });
865 try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");847 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 });
868 try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");852 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 });
871 try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");857 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 });
874 try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");863 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 });
877 try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");869 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 });
880 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");875 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 });
883 try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");881 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 });
886 try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");887 try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
887}888}
888889
889test "lower MI encoding" {890test "lower MI encoding" {
890 var enc = TestEncode{};891 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 });
893 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");897 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
894898
895 try enc.encode(.mov, .{899 try enc.encode(.mov, &.{
896 .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },900 .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
897 .op2 = .{ .imm = Immediate.u(0x10) },901 .{ .imm = Immediate.u(0x10) },
898 });902 });
899 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");903 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 });
902 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");909 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 });
905 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");915 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 });
908 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");921 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
909922
910 try enc.encode(.mov, .{923 try enc.encode(.mov, &.{
911 .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },924 .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
912 .op2 = .{ .imm = Immediate.u(0x10) },925 .{ .imm = Immediate.u(0x10) },
913 });926 });
914 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");927 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
915928
916 try enc.encode(.mov, .{929 try enc.encode(.mov, &.{
917 .op1 = .{ .mem = Memory.rip(.qword, 0x10) },930 .{ .mem = Memory.rip(.qword, 0x10) },
918 .op2 = .{ .imm = Immediate.u(0x10) },931 .{ .imm = Immediate.u(0x10) },
919 });932 });
920 try expectEqualHexStrings(933 try expectEqualHexStrings(
921 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",934 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
...@@ -923,99 +936,108 @@ test "lower MI encoding" {...@@ -923,99 +936,108 @@ test "lower MI encoding" {
923 "mov QWORD PTR [rip + 0x10], 0x10",936 "mov QWORD PTR [rip + 0x10], 0x10",
924 );937 );
925938
926 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{939 try enc.encode(.mov, &.{
927 .base = .rbp,940 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
928 .disp = -8,941 .{ .imm = Immediate.u(0x10) },
929 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });942 });
930 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");943 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, .{945 try enc.encode(.mov, &.{
933 .base = .rbp,946 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },
934 .disp = -2,947 .{ .imm = Immediate.s(-16) },
935 }) }, .op2 = .{ .imm = Immediate.s(-16) } });948 });
936 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");949 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, .{951 try enc.encode(.mov, &.{
939 .base = .rbp,952 .{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },
940 .disp = -1,953 .{ .imm = Immediate.u(0x10) },
941 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });954 });
942 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");955 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, .{957 try enc.encode(.mov, &.{
945 .base = .ds,958 .{ .mem = Memory.sib(.qword, .{
946 .disp = 0x10000000,959 .base = .ds,
947 .scale_index = .{960 .disp = 0x10000000,
948 .scale = 2,961 .scale_index = .{ .scale = 2, .index = .rcx },
949 .index = .rcx,962 }) },
950 },963 .{ .imm = Immediate.u(0x10) },
951 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });964 });
952 try expectEqualHexStrings(965 try expectEqualHexStrings(
953 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",966 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
954 enc.code(),967 enc.code(),
955 "mov QWORD PTR [rcx*2 + 0x10000000], 0x10",968 "mov QWORD PTR [rcx*2 + 0x10000000], 0x10",
956 );969 );
957970
958 try enc.encode(.adc, .{ .op1 = .{ .mem = Memory.sib(.byte, .{971 try enc.encode(.adc, &.{
959 .base = .rbp,972 .{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
960 .disp = -0x10,973 .{ .imm = Immediate.u(0x10) },
961 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });974 });
962 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");975 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 });
965 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");981 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 });
968 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");987 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
969988
970 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.dword, .{989 try enc.encode(.add, &.{
971 .base = .rdx,990 .{ .mem = Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
972 .disp = -8,991 .{ .imm = Immediate.u(0x10) },
973 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });992 });
974 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");993 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 });
977 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");999 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
9781000
979 try enc.encode(.add, .{ .op1 = .{ .mem = Memory.sib(.qword, .{1001 try enc.encode(.add, &.{
980 .base = .rbp,1002 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
981 .disp = -0x10,1003 .{ .imm = Immediate.s(-0x10) },
982 }) }, .op2 = .{ .imm = Immediate.s(-0x10) } });1004 });
983 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");1005 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, .{1007 try enc.encode(.@"and", &.{
986 .base = .ds,1008 .{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
987 .disp = 0x10000000,1009 .{ .imm = Immediate.u(0x10) },
988 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });1010 });
989 try expectEqualHexStrings(1011 try expectEqualHexStrings(
990 "\x83\x24\x25\x00\x00\x00\x10\x10",1012 "\x83\x24\x25\x00\x00\x00\x10\x10",
991 enc.code(),1013 enc.code(),
992 "and DWORD PTR ds:0x10000000, 0x10",1014 "and DWORD PTR ds:0x10000000, 0x10",
993 );1015 );
9941016
995 try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{1017 try enc.encode(.@"and", &.{
996 .base = .es,1018 .{ .mem = Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
997 .disp = 0x10000000,1019 .{ .imm = Immediate.u(0x10) },
998 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });1020 });
999 try expectEqualHexStrings(1021 try expectEqualHexStrings(
1000 "\x26\x83\x24\x25\x00\x00\x00\x10\x10",1022 "\x26\x83\x24\x25\x00\x00\x00\x10\x10",
1001 enc.code(),1023 enc.code(),
1002 "and DWORD PTR es:0x10000000, 0x10",1024 "and DWORD PTR es:0x10000000, 0x10",
1003 );1025 );
10041026
1005 try enc.encode(.@"and", .{ .op1 = .{ .mem = Memory.sib(.dword, .{1027 try enc.encode(.@"and", &.{
1006 .base = .r12,1028 .{ .mem = Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
1007 .disp = 0x10000000,1029 .{ .imm = Immediate.u(0x10) },
1008 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });1030 });
1009 try expectEqualHexStrings(1031 try expectEqualHexStrings(
1010 "\x41\x83\xA4\x24\x00\x00\x00\x10\x10",1032 "\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
1011 enc.code(),1033 enc.code(),
1012 "and DWORD PTR [r12 + 0x10000000], 0x10",1034 "and DWORD PTR [r12 + 0x10000000], 0x10",
1013 );1035 );
10141036
1015 try enc.encode(.sub, .{ .op1 = .{ .mem = Memory.sib(.dword, .{1037 try enc.encode(.sub, &.{
1016 .base = .r11,1038 .{ .mem = Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
1017 .disp = 0x10000000,1039 .{ .imm = Immediate.u(0x10) },
1018 }) }, .op2 = .{ .imm = Immediate.u(0x10) } });1040 });
1019 try expectEqualHexStrings(1041 try expectEqualHexStrings(
1020 "\x41\x83\xAB\x00\x00\x00\x10\x10",1042 "\x41\x83\xAB\x00\x00\x00\x10\x10",
1021 enc.code(),1043 enc.code(),
...@@ -1026,185 +1048,227 @@ test "lower MI encoding" {...@@ -1026,185 +1048,227 @@ test "lower MI encoding" {
1026test "lower RM encoding" {1048test "lower RM encoding" {
1027 var enc = TestEncode{};1049 var enc = TestEncode{};
10281050
1029 try enc.encode(.mov, .{1051 try enc.encode(.mov, &.{
1030 .op1 = .{ .reg = .rax },1052 .{ .reg = .rax },
1031 .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },1053 .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
1032 });1054 });
1033 try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");1055 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, .{1057 try enc.encode(.mov, &.{
1036 .base = .ds,1058 .{ .reg = .rbx },
1037 .disp = 0x10,1059 .{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
1038 }) } });1060 });
1039 try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");1061 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, .{1063 try enc.encode(.mov, &.{
1042 .base = .rbp,1064 .{ .reg = .rax },
1043 .disp = -4,1065 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
1044 }) } });1066 });
1045 try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");1067 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, .{1069 try enc.encode(.mov, &.{
1048 .base = .rbp,1070 .{ .reg = .rax },
1049 .scale_index = .{1071 .{ .mem = Memory.sib(.qword, .{
1050 .scale = 1,1072 .base = .rbp,
1051 .index = .rcx,1073 .scale_index = .{ .scale = 1, .index = .rcx },
1052 },1074 .disp = -8,
1053 .disp = -8,1075 }) },
1054 }) } });1076 });
1055 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", enc.code(), "mov rax, QWORD PTR [rbp + rcx*1 - 8]");1077 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, .{1079 try enc.encode(.mov, &.{
1058 .base = .rbp,1080 .{ .reg = .eax },
1059 .scale_index = .{1081 .{ .mem = Memory.sib(.dword, .{
1060 .scale = 4,1082 .base = .rbp,
1061 .index = .rdx,1083 .scale_index = .{ .scale = 4, .index = .rdx },
1062 },1084 .disp = -4,
1063 .disp = -4,1085 }) },
1064 }) } });1086 });
1065 try expectEqualHexStrings("\x8B\x44\x95\xFC", enc.code(), "mov eax, dword ptr [rbp + rdx*4 - 4]");1087 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, .{1089 try enc.encode(.mov, &.{
1068 .base = .rbp,1090 .{ .reg = .rax },
1069 .scale_index = .{1091 .{ .mem = Memory.sib(.qword, .{
1070 .scale = 8,1092 .base = .rbp,
1071 .index = .rcx,1093 .scale_index = .{ .scale = 8, .index = .rcx },
1072 },1094 .disp = -8,
1073 .disp = -8,1095 }) },
1074 }) } });1096 });
1075 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", enc.code(), "mov rax, QWORD PTR [rbp + rcx*8 - 8]");1097 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, .{1099 try enc.encode(.mov, &.{
1078 .base = .rsi,1100 .{ .reg = .r8b },
1079 .scale_index = .{1101 .{ .mem = Memory.sib(.byte, .{
1080 .scale = 1,1102 .base = .rsi,
1081 .index = .rcx,1103 .scale_index = .{ .scale = 1, .index = .rcx },
1082 },1104 .disp = -24,
1083 .disp = -24,1105 }) },
1084 }) } });1106 });
1085 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", enc.code(), "mov r8b, BYTE PTR [rsi + rcx*1 - 24]");1107 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", enc.code(), "mov r8b, BYTE PTR [rsi + rcx*1 - 24]");
10861108
1087 // TODO this mnemonic needs cleanup as some prefixes are obsolete.1109 // 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 });
1089 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");1114 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
10901115
1091 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{1116 try enc.encode(.mov, &.{
1092 .base = .rbp,1117 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
1093 .disp = -16,1118 .{ .reg = .fs },
1094 }) }, .op2 = .{ .reg = .fs } });1119 });
1095 try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs");1120 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 });
1098 try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");1126 try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");
10991127
1100 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.word, .{1128 try enc.encode(.mov, &.{
1101 .base = .rbp,1129 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1102 .disp = -16,1130 .{ .reg = .fs },
1103 }) }, .op2 = .{ .reg = .fs } });1131 });
1104 try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");1132 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 });
1107 try expectEqualHexStrings("\x0F\xBF\xC3", enc.code(), "movsx eax, bx");1138 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 });
1110 try expectEqualHexStrings("\x0F\xBE\xC3", enc.code(), "movsx eax, bl");1144 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 });
1113 try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl");1150 try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl");
11141151
1115 try enc.encode(.movsx, .{1152 try enc.encode(.movsx, &.{
1116 .op1 = .{ .reg = .eax },1153 .{ .reg = .eax },
1117 .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },1154 .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
1118 });1155 });
1119 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");1156 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
11201157
1121 try enc.encode(.movsx, .{1158 try enc.encode(.movsx, &.{
1122 .op1 = .{ .reg = .eax },1159 .{ .reg = .eax },
1123 .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },1160 .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
1124 });1161 });
1125 try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");1162 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 });
1128 try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]");1168 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 });
1131 try expectEqualHexStrings("\x48\x0F\xBF\xC3", enc.code(), "movsx rax, bx");1174 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 });
1134 try expectEqualHexStrings("\x48\x63\xC3", enc.code(), "movsxd rax, ebx");1180 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 });
1137 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]");1186 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 });
1140 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]");1192 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 });
1143 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]");1198 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 });
1146 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]");1204 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 });
1149 try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");1210 try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");
11501211
1151 try enc.encode(.lea, .{1212 try enc.encode(.lea, &.{
1152 .op1 = .{ .reg = .rsi },1213 .{ .reg = .rsi },
1153 .op2 = .{ .mem = Memory.sib(.qword, .{1214 .{ .mem = Memory.sib(.qword, .{
1154 .base = .rbp,1215 .base = .rbp,
1155 .scale_index = .{ .scale = 1, .index = .rcx },1216 .scale_index = .{ .scale = 1, .index = .rcx },
1156 }) },1217 }) },
1157 });1218 });
1158 try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]");1219 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, .{1221 try enc.encode(.add, &.{
1161 .base = .ds,1222 .{ .reg = .r11 },
1162 .disp = 0x10000000,1223 .{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
1163 }) } });1224 });
1164 try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");1225 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, .{1227 try enc.encode(.add, &.{
1167 .base = .ds,1228 .{ .reg = .r12b },
1168 .disp = 0x10000000,1229 .{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
1169 }) } });1230 });
1170 try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");1231 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, .{1233 try enc.encode(.add, &.{
1173 .base = .fs,1234 .{ .reg = .r12b },
1174 .disp = 0x10000000,1235 .{ .mem = Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
1175 }) } });1236 });
1176 try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");1237 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, .{1239 try enc.encode(.sub, &.{
1179 .base = .r13,1240 .{ .reg = .r11 },
1180 .disp = 0x10000000,1241 .{ .mem = Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
1181 }) } });1242 });
1182 try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");1243 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, .{1245 try enc.encode(.sub, &.{
1185 .base = .r12,1246 .{ .reg = .r11 },
1186 .disp = 0x10000000,1247 .{ .mem = Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
1187 }) } });1248 });
1188 try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");1249 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 });
1191 try expectEqualHexStrings("\x4D\x0F\xAF\xDC", enc.code(), "mov r11, r12");1255 try expectEqualHexStrings("\x4D\x0F\xAF\xDC", enc.code(), "mov r11, r12");
1192}1256}
11931257
1194test "lower RMI encoding" {1258test "lower RMI encoding" {
1195 var enc = TestEncode{};1259 var enc = TestEncode{};
11961260
1197 try enc.encode(.imul, .{1261 try enc.encode(.imul, &.{
1198 .op1 = .{ .reg = .r11 },1262 .{ .reg = .r11 },
1199 .op2 = .{ .reg = .r12 },1263 .{ .reg = .r12 },
1200 .op3 = .{ .imm = Immediate.s(-2) },1264 .{ .imm = Immediate.s(-2) },
1201 });1265 });
1202 try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");1266 try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
12031267
1204 try enc.encode(.imul, .{1268 try enc.encode(.imul, &.{
1205 .op1 = .{ .reg = .r11 },1269 .{ .reg = .r11 },
1206 .op2 = .{ .mem = Memory.rip(.qword, -16) },1270 .{ .mem = Memory.rip(.qword, -16) },
1207 .op3 = .{ .imm = Immediate.s(-1024) },1271 .{ .imm = Immediate.s(-1024) },
1208 });1272 });
1209 try expectEqualHexStrings(1273 try expectEqualHexStrings(
1210 "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",1274 "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
...@@ -1212,13 +1276,10 @@ test "lower RMI encoding" {...@@ -1212,13 +1276,10 @@ test "lower RMI encoding" {
1212 "imul r11, QWORD PTR [rip - 16], -1024",1276 "imul r11, QWORD PTR [rip - 16], -1024",
1213 );1277 );
12141278
1215 try enc.encode(.imul, .{1279 try enc.encode(.imul, &.{
1216 .op1 = .{ .reg = .bx },1280 .{ .reg = .bx },
1217 .op2 = .{ .mem = Memory.sib(.word, .{1281 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1218 .base = .rbp,1282 .{ .imm = Immediate.s(-1024) },
1219 .disp = -16,
1220 }) },
1221 .op3 = .{ .imm = Immediate.s(-1024) },
1222 });1283 });
1223 try expectEqualHexStrings(1284 try expectEqualHexStrings(
1224 "\x66\x69\x5D\xF0\x00\xFC",1285 "\x66\x69\x5D\xF0\x00\xFC",
...@@ -1226,13 +1287,10 @@ test "lower RMI encoding" {...@@ -1226,13 +1287,10 @@ test "lower RMI encoding" {
1226 "imul bx, WORD PTR [rbp - 16], -1024",1287 "imul bx, WORD PTR [rbp - 16], -1024",
1227 );1288 );
12281289
1229 try enc.encode(.imul, .{1290 try enc.encode(.imul, &.{
1230 .op1 = .{ .reg = .bx },1291 .{ .reg = .bx },
1231 .op2 = .{ .mem = Memory.sib(.word, .{1292 .{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1232 .base = .rbp,1293 .{ .imm = Immediate.u(1024) },
1233 .disp = -16,
1234 }) },
1235 .op3 = .{ .imm = Immediate.u(1024) },
1236 });1294 });
1237 try expectEqualHexStrings(1295 try expectEqualHexStrings(
1238 "\x66\x69\x5D\xF0\x00\x04",1296 "\x66\x69\x5D\xF0\x00\x04",
...@@ -1244,238 +1302,343 @@ test "lower RMI encoding" {...@@ -1244,238 +1302,343 @@ test "lower RMI encoding" {
1244test "lower MR encoding" {1302test "lower MR encoding" {
1245 var enc = TestEncode{};1303 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 });
1248 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");1309 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
12491310
1250 try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.qword, .{1311 try enc.encode(.mov, &.{
1251 .base = .rbp,1312 .{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
1252 .disp = -4,1313 .{ .reg = .r11 },
1253 }) }, .op2 = .{ .reg = .r11 } });1314 });
1254 try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");1315 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 });
1257 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12");1321 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, .{1323 try enc.encode(.mov, &.{
1260 .base = .r11,1324 .{ .mem = Memory.sib(.qword, .{
1261 .scale_index = .{1325 .base = .r11,
1262 .scale = 2,1326 .scale_index = .{ .scale = 2, .index = .r12 },
1263 .index = .r12,1327 .disp = 0x10,
1264 },1328 }) },
1265 .disp = 0x10,1329 .{ .reg = .r13 },
1266 }) }, .op2 = .{ .reg = .r13 } });1330 });
1267 try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13");1331 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 });
1270 try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w");1337 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, .{1339 try enc.encode(.mov, &.{
1273 .base = .r11,1340 .{ .mem = Memory.sib(.byte, .{
1274 .scale_index = .{1341 .base = .r11,
1275 .scale = 2,1342 .scale_index = .{ .scale = 2, .index = .r12 },
1276 .index = .r12,1343 .disp = 0x10,
1277 },1344 }) },
1278 .disp = 0x10,1345 .{ .reg = .r13b },
1279 }) }, .op2 = .{ .reg = .r13b } });1346 });
1280 try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");1347 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, .{1349 try enc.encode(.add, &.{
1283 .base = .ds,1350 .{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
1284 .disp = 0x10000000,1351 .{ .reg = .r12b },
1285 }) }, .op2 = .{ .reg = .r12b } });1352 });
1286 try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");1353 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, .{1355 try enc.encode(.add, &.{
1289 .base = .ds,1356 .{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
1290 .disp = 0x10000000,1357 .{ .reg = .r12d },
1291 }) }, .op2 = .{ .reg = .r12d } });1358 });
1292 try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");1359 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, .{1361 try enc.encode(.add, &.{
1295 .base = .gs,1362 .{ .mem = Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
1296 .disp = 0x10000000,1363 .{ .reg = .r12d },
1297 }) }, .op2 = .{ .reg = .r12d } });1364 });
1298 try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");1365 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, .{1367 try enc.encode(.sub, &.{
1301 .base = .r11,1368 .{ .mem = Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
1302 .disp = 0x10000000,1369 .{ .reg = .r12 },
1303 }) }, .op2 = .{ .reg = .r12 } });1370 });
1304 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");1371 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
1305}1372}
13061373
1307test "lower M encoding" {1374test "lower M encoding" {
1308 var enc = TestEncode{};1375 var enc = TestEncode{};
13091376
1310 try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } });1377 try enc.encode(.call, &.{
1378 .{ .reg = .r12 },
1379 });
1311 try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");1380 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 });
1314 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");1385 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
13151386
1316 try enc.encode(.call, .{1387 try enc.encode(.call, &.{
1317 .op1 = .{ .mem = Memory.sib(.qword, .{1388 .{ .mem = Memory.sib(.qword, .{
1318 .base = null,1389 .base = null,
1319 .scale_index = .{ .index = .r11, .scale = 2 },1390 .scale_index = .{ .index = .r11, .scale = 2 },
1320 }) },1391 }) },
1321 });1392 });
1322 try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");1393 try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
13231394
1324 try enc.encode(.call, .{1395 try enc.encode(.call, &.{
1325 .op1 = .{ .mem = Memory.sib(.qword, .{1396 .{ .mem = Memory.sib(.qword, .{
1326 .base = null,1397 .base = null,
1327 .scale_index = .{ .index = .r12, .scale = 2 },1398 .scale_index = .{ .index = .r12, .scale = 2 },
1328 }) },1399 }) },
1329 });1400 });
1330 try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");1401 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 });
1333 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");1406 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 });
1336 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");1411 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 });
1339 try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");1416 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 });
1342 try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");1421 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 });
1345 try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]");1426 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 });
1348 try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]");1431 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 });
1351 try expectEqualHexStrings("\x48\xF7\xE8", enc.code(), "imul rax");1436 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 });
1354 try expectEqualHexStrings("\x49\xF7\xEC", enc.code(), "imul r12");1441 try expectEqualHexStrings("\x49\xF7\xEC", enc.code(), "imul r12");
1355}1442}
13561443
1357test "lower O encoding" {1444test "lower O encoding" {
1358 var enc = TestEncode{};1445 var enc = TestEncode{};
13591446
1360 try enc.encode(.push, .{ .op1 = .{ .reg = .rax } });1447 try enc.encode(.push, &.{
1448 .{ .reg = .rax },
1449 });
1361 try expectEqualHexStrings("\x50", enc.code(), "push rax");1450 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 });
1364 try expectEqualHexStrings("\x66\x41\x54", enc.code(), "push r12w");1455 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 });
1367 try expectEqualHexStrings("\x41\x5c", enc.code(), "pop r12");1460 try expectEqualHexStrings("\x41\x5c", enc.code(), "pop r12");
1368}1461}
13691462
1370test "lower OI encoding" {1463test "lower OI encoding" {
1371 var enc = TestEncode{};1464 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 });
1374 try expectEqualHexStrings(1470 try expectEqualHexStrings(
1375 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",1471 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
1376 enc.code(),1472 enc.code(),
1377 "movabs rax, 0x1000000000000000",1473 "movabs rax, 0x1000000000000000",
1378 );1474 );
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 });
1381 try expectEqualHexStrings(1480 try expectEqualHexStrings(
1382 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",1481 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
1383 enc.code(),1482 enc.code(),
1384 "movabs r11, 0x1000000000000000",1483 "movabs r11, 0x1000000000000000",
1385 );1484 );
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 });
1388 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");1490 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 });
1391 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");1496 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 });
1394 try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");1502 try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
1395}1503}
13961504
1397test "lower FD/TD encoding" {1505test "lower FD/TD encoding" {
1398 var enc = TestEncode{};1506 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 });
1401 try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10");1512 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 });
1404 try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10");1518 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 });
1407 try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10");1524 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 });
1410 try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10");1530 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 });
1413 try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax");1536 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 });
1416 try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax");1542 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 });
1419 try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax");1548 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 });
1422 try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");1554 try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");
1423}1555}
14241556
1425test "lower NP encoding" {1557test "lower NP encoding" {
1426 var enc = TestEncode{};1558 var enc = TestEncode{};
14271559
1428 try enc.encode(.int3, .{});1560 try enc.encode(.int3, &.{});
1429 try expectEqualHexStrings("\xCC", enc.code(), "int3");1561 try expectEqualHexStrings("\xCC", enc.code(), "int3");
14301562
1431 try enc.encode(.nop, .{});1563 try enc.encode(.nop, &.{});
1432 try expectEqualHexStrings("\x90", enc.code(), "nop");1564 try expectEqualHexStrings("\x90", enc.code(), "nop");
14331565
1434 try enc.encode(.ret, .{});1566 try enc.encode(.ret, &.{});
1435 try expectEqualHexStrings("\xC3", enc.code(), "ret");1567 try expectEqualHexStrings("\xC3", enc.code(), "ret");
14361568
1437 try enc.encode(.syscall, .{});1569 try enc.encode(.syscall, &.{});
1438 try expectEqualHexStrings("\x0f\x05", enc.code(), "syscall");1570 try expectEqualHexStrings("\x0f\x05", enc.code(), "syscall");
1439}1571}
14401572
1441fn invalidInstruction(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {1573fn invalidInstruction(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
1442 const err = Instruction.new(mnemonic, args);1574 const err = Instruction.new(.none, mnemonic, ops);
1443 try testing.expectError(error.InvalidInstruction, err);1575 try testing.expectError(error.InvalidInstruction, err);
1444}1576}
14451577
1446test "invalid instruction" {1578test "invalid instruction" {
1447 try invalidInstruction(.call, .{ .op1 = .{ .reg = .eax } });1579 try invalidInstruction(.call, &.{
1448 try invalidInstruction(.call, .{ .op1 = .{ .reg = .ax } });1580 .{ .reg = .eax },
1449 try invalidInstruction(.call, .{ .op1 = .{ .reg = .al } });1581 });
1450 try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.dword, 0) } });1582 try invalidInstruction(.call, &.{
1451 try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.word, 0) } });1583 .{ .reg = .ax },
1452 try invalidInstruction(.call, .{ .op1 = .{ .mem = Memory.rip(.byte, 0) } });1584 });
1453 try invalidInstruction(.mov, .{ .op1 = .{ .mem = Memory.rip(.word, 0x10) }, .op2 = .{ .reg = .r12 } });1585 try invalidInstruction(.call, &.{
1454 try invalidInstruction(.lea, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .reg = .rbx } });1586 .{ .reg = .al },
1455 try invalidInstruction(.lea, .{ .op1 = .{ .reg = .al }, .op2 = .{ .mem = Memory.rip(.byte, 0) } });1587 });
1456 try invalidInstruction(.pop, .{ .op1 = .{ .reg = .r12b } });1588 try invalidInstruction(.call, &.{
1457 try invalidInstruction(.pop, .{ .op1 = .{ .reg = .r12d } });1589 .{ .mem = Memory.rip(.dword, 0) },
1458 try invalidInstruction(.push, .{ .op1 = .{ .reg = .r12b } });1590 });
1459 try invalidInstruction(.push, .{ .op1 = .{ .reg = .r12d } });1591 try invalidInstruction(.call, &.{
1460 try invalidInstruction(.push, .{ .op1 = .{ .imm = Immediate.u(0x1000000000000000) } });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 });
1461}1624}
14621625
1463fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {1626fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
1464 try testing.expectError(error.CannotEncode, Instruction.new(mnemonic, args));1627 try testing.expectError(error.CannotEncode, Instruction.new(.none, mnemonic, ops));
1465}1628}
14661629
1467test "cannot encode" {1630test "cannot encode" {
1468 try cannotEncode(.@"test", .{1631 try cannotEncode(.@"test", &.{
1469 .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },1632 .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
1470 .op2 = .{ .reg = .ah },1633 .{ .reg = .ah },
1471 });1634 });
1472 try cannotEncode(.@"test", .{1635 try cannotEncode(.@"test", &.{
1473 .op1 = .{ .reg = .r11b },1636 .{ .reg = .r11b },
1474 .op2 = .{ .reg = .bh },1637 .{ .reg = .bh },
1475 });1638 });
1476 try cannotEncode(.mov, .{1639 try cannotEncode(.mov, &.{
1477 .op1 = .{ .reg = .sil },1640 .{ .reg = .sil },
1478 .op2 = .{ .reg = .ah },1641 .{ .reg = .ah },
1479 });1642 });
1480}1643}
14811644
...@@ -1645,12 +1808,7 @@ const Assembler = struct {...@@ -1645,12 +1808,7 @@ const Assembler = struct {
16451808
1646 pub fn assemble(as: *Assembler, writer: anytype) !void {1809 pub fn assemble(as: *Assembler, writer: anytype) !void {
1647 while (try as.next()) |parsed_inst| {1810 while (try as.next()) |parsed_inst| {
1648 const inst = try Instruction.new(parsed_inst.mnemonic, .{1811 const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
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 });
1654 try inst.encode(writer);1812 try inst.encode(writer);
1655 }1813 }
1656 }1814 }
src/arch/x86_64/encodings.zig+837-832
...@@ -6,869 +6,874 @@ const Mode = Encoding.Mode;...@@ -6,869 +6,874 @@ const Mode = Encoding.Mode;
66
7const modrm_ext = u3;7const 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
11// TODO move this into a .zon file when Zig is capable of importing .zon files11// TODO move this into a .zon file when Zig is capable of importing .zon files
12// zig fmt: off12// zig fmt: off
13pub const table = &[_]Entry{13pub const table = [_]Entry{
14 // General-purpose14 // General-purpose
15 .{ .adc, .zi, .al, .imm8, .none, .none, &.{ 0x14 }, 0, .none },15 .{ .adc, .zi, &.{ .al, .imm8 }, &.{ 0x14 }, 0, .none },
16 .{ .adc, .zi, .ax, .imm16, .none, .none, &.{ 0x15 }, 0, .none },16 .{ .adc, .zi, &.{ .ax, .imm16 }, &.{ 0x15 }, 0, .none },
17 .{ .adc, .zi, .eax, .imm32, .none, .none, &.{ 0x15 }, 0, .none },17 .{ .adc, .zi, &.{ .eax, .imm32 }, &.{ 0x15 }, 0, .none },
18 .{ .adc, .zi, .rax, .imm32s, .none, .none, &.{ 0x15 }, 0, .long },18 .{ .adc, .zi, &.{ .rax, .imm32s }, &.{ 0x15 }, 0, .long },
19 .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .none },19 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .none },
20 .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .rex },20 .{ .adc, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 2, .rex },
21 .{ .adc, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 2, .none },21 .{ .adc, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 2, .none },
22 .{ .adc, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 2, .none },22 .{ .adc, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 2, .none },
23 .{ .adc, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 2, .long },23 .{ .adc, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 2, .long },
24 .{ .adc, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 2, .none },24 .{ .adc, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 2, .none },
25 .{ .adc, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 2, .none },25 .{ .adc, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 2, .none },
26 .{ .adc, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 2, .long },26 .{ .adc, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 2, .long },
27 .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .none },27 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .none },
28 .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .rex },28 .{ .adc, .mr, &.{ .rm8, .r8 }, &.{ 0x10 }, 0, .rex },
29 .{ .adc, .mr, .rm16, .r16, .none, .none, &.{ 0x11 }, 0, .none },29 .{ .adc, .mr, &.{ .rm16, .r16 }, &.{ 0x11 }, 0, .none },
30 .{ .adc, .mr, .rm32, .r32, .none, .none, &.{ 0x11 }, 0, .none },30 .{ .adc, .mr, &.{ .rm32, .r32 }, &.{ 0x11 }, 0, .none },
31 .{ .adc, .mr, .rm64, .r64, .none, .none, &.{ 0x11 }, 0, .long },31 .{ .adc, .mr, &.{ .rm64, .r64 }, &.{ 0x11 }, 0, .long },
32 .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .none },32 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .none },
33 .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .rex },33 .{ .adc, .rm, &.{ .r8, .rm8 }, &.{ 0x12 }, 0, .rex },
34 .{ .adc, .rm, .r16, .rm16, .none, .none, &.{ 0x13 }, 0, .none },34 .{ .adc, .rm, &.{ .r16, .rm16 }, &.{ 0x13 }, 0, .none },
35 .{ .adc, .rm, .r32, .rm32, .none, .none, &.{ 0x13 }, 0, .none },35 .{ .adc, .rm, &.{ .r32, .rm32 }, &.{ 0x13 }, 0, .none },
36 .{ .adc, .rm, .r64, .rm64, .none, .none, &.{ 0x13 }, 0, .long },36 .{ .adc, .rm, &.{ .r64, .rm64 }, &.{ 0x13 }, 0, .long },
3737
38 .{ .add, .zi, .al, .imm8, .none, .none, &.{ 0x04 }, 0, .none },38 .{ .add, .zi, &.{ .al, .imm8 }, &.{ 0x04 }, 0, .none },
39 .{ .add, .zi, .ax, .imm16, .none, .none, &.{ 0x05 }, 0, .none },39 .{ .add, .zi, &.{ .ax, .imm16 }, &.{ 0x05 }, 0, .none },
40 .{ .add, .zi, .eax, .imm32, .none, .none, &.{ 0x05 }, 0, .none },40 .{ .add, .zi, &.{ .eax, .imm32 }, &.{ 0x05 }, 0, .none },
41 .{ .add, .zi, .rax, .imm32s, .none, .none, &.{ 0x05 }, 0, .long },41 .{ .add, .zi, &.{ .rax, .imm32s }, &.{ 0x05 }, 0, .long },
42 .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .none },42 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .none },
43 .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .rex },43 .{ .add, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 0, .rex },
44 .{ .add, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 0, .none },44 .{ .add, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 0, .none },
45 .{ .add, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 0, .none },45 .{ .add, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 0, .none },
46 .{ .add, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 0, .long },46 .{ .add, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 0, .long },
47 .{ .add, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 0, .none },47 .{ .add, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 0, .none },
48 .{ .add, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 0, .none },48 .{ .add, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 0, .none },
49 .{ .add, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 0, .long },49 .{ .add, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 0, .long },
50 .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .none },50 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .none },
51 .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .rex },51 .{ .add, .mr, &.{ .rm8, .r8 }, &.{ 0x00 }, 0, .rex },
52 .{ .add, .mr, .rm16, .r16, .none, .none, &.{ 0x01 }, 0, .none },52 .{ .add, .mr, &.{ .rm16, .r16 }, &.{ 0x01 }, 0, .none },
53 .{ .add, .mr, .rm32, .r32, .none, .none, &.{ 0x01 }, 0, .none },53 .{ .add, .mr, &.{ .rm32, .r32 }, &.{ 0x01 }, 0, .none },
54 .{ .add, .mr, .rm64, .r64, .none, .none, &.{ 0x01 }, 0, .long },54 .{ .add, .mr, &.{ .rm64, .r64 }, &.{ 0x01 }, 0, .long },
55 .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .none },55 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .none },
56 .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .rex },56 .{ .add, .rm, &.{ .r8, .rm8 }, &.{ 0x02 }, 0, .rex },
57 .{ .add, .rm, .r16, .rm16, .none, .none, &.{ 0x03 }, 0, .none },57 .{ .add, .rm, &.{ .r16, .rm16 }, &.{ 0x03 }, 0, .none },
58 .{ .add, .rm, .r32, .rm32, .none, .none, &.{ 0x03 }, 0, .none },58 .{ .add, .rm, &.{ .r32, .rm32 }, &.{ 0x03 }, 0, .none },
59 .{ .add, .rm, .r64, .rm64, .none, .none, &.{ 0x03 }, 0, .long },59 .{ .add, .rm, &.{ .r64, .rm64 }, &.{ 0x03 }, 0, .long },
6060
61 .{ .@"and", .zi, .al, .imm8, .none, .none, &.{ 0x24 }, 0, .none },61 .{ .@"and", .zi, &.{ .al, .imm8 }, &.{ 0x24 }, 0, .none },
62 .{ .@"and", .zi, .ax, .imm16, .none, .none, &.{ 0x25 }, 0, .none },62 .{ .@"and", .zi, &.{ .ax, .imm16 }, &.{ 0x25 }, 0, .none },
63 .{ .@"and", .zi, .eax, .imm32, .none, .none, &.{ 0x25 }, 0, .none },63 .{ .@"and", .zi, &.{ .eax, .imm32 }, &.{ 0x25 }, 0, .none },
64 .{ .@"and", .zi, .rax, .imm32s, .none, .none, &.{ 0x25 }, 0, .long },64 .{ .@"and", .zi, &.{ .rax, .imm32s }, &.{ 0x25 }, 0, .long },
65 .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .none },65 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .none },
66 .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .rex },66 .{ .@"and", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 4, .rex },
67 .{ .@"and", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 4, .none },67 .{ .@"and", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 4, .none },
68 .{ .@"and", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 4, .none },68 .{ .@"and", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 4, .none },
69 .{ .@"and", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 4, .long },69 .{ .@"and", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 4, .long },
70 .{ .@"and", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 4, .none },70 .{ .@"and", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 4, .none },
71 .{ .@"and", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 4, .none },71 .{ .@"and", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 4, .none },
72 .{ .@"and", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 4, .long },72 .{ .@"and", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 4, .long },
73 .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .none },73 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .none },
74 .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .rex },74 .{ .@"and", .mr, &.{ .rm8, .r8 }, &.{ 0x20 }, 0, .rex },
75 .{ .@"and", .mr, .rm16, .r16, .none, .none, &.{ 0x21 }, 0, .none },75 .{ .@"and", .mr, &.{ .rm16, .r16 }, &.{ 0x21 }, 0, .none },
76 .{ .@"and", .mr, .rm32, .r32, .none, .none, &.{ 0x21 }, 0, .none },76 .{ .@"and", .mr, &.{ .rm32, .r32 }, &.{ 0x21 }, 0, .none },
77 .{ .@"and", .mr, .rm64, .r64, .none, .none, &.{ 0x21 }, 0, .long },77 .{ .@"and", .mr, &.{ .rm64, .r64 }, &.{ 0x21 }, 0, .long },
78 .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .none },78 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .none },
79 .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .rex },79 .{ .@"and", .rm, &.{ .r8, .rm8 }, &.{ 0x22 }, 0, .rex },
80 .{ .@"and", .rm, .r16, .rm16, .none, .none, &.{ 0x23 }, 0, .none },80 .{ .@"and", .rm, &.{ .r16, .rm16 }, &.{ 0x23 }, 0, .none },
81 .{ .@"and", .rm, .r32, .rm32, .none, .none, &.{ 0x23 }, 0, .none },81 .{ .@"and", .rm, &.{ .r32, .rm32 }, &.{ 0x23 }, 0, .none },
82 .{ .@"and", .rm, .r64, .rm64, .none, .none, &.{ 0x23 }, 0, .long },82 .{ .@"and", .rm, &.{ .r64, .rm64 }, &.{ 0x23 }, 0, .long },
8383
84 .{ .bsf, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbc }, 0, .none },84 .{ .bsf, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbc }, 0, .none },
85 .{ .bsf, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbc }, 0, .none },85 .{ .bsf, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbc }, 0, .none },
86 .{ .bsf, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbc }, 0, .long },86 .{ .bsf, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbc }, 0, .long },
8787
88 .{ .bsr, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },88 .{ .bsr, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0xbd }, 0, .none },
89 .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },89 .{ .bsr, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0xbd }, 0, .none },
90 .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long },90 .{ .bsr, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0xbd }, 0, .long },
9191
92 .{ .bswap, .o, .r32, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .none },92 .{ .bswap, .o, &.{ .r32 }, &.{ 0x0f, 0xc8 }, 0, .none },
93 .{ .bswap, .o, .r64, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .long },93 .{ .bswap, .o, &.{ .r64 }, &.{ 0x0f, 0xc8 }, 0, .long },
9494
95 .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },95 .{ .bt, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xa3 }, 0, .none },
96 .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },96 .{ .bt, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xa3 }, 0, .none },
97 .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long },97 .{ .bt, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xa3 }, 0, .long },
98 .{ .bt, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none },98 .{ .bt, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },
99 .{ .bt, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none },99 .{ .bt, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 4, .none },
100 .{ .bt, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .long },100 .{ .bt, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 4, .long },
101101
102 .{ .btc, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xbb }, 0, .none },102 .{ .btc, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xbb }, 0, .none },
103 .{ .btc, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xbb }, 0, .none },103 .{ .btc, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xbb }, 0, .none },
104 .{ .btc, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xbb }, 0, .long },104 .{ .btc, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xbb }, 0, .long },
105 .{ .btc, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none },105 .{ .btc, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },
106 .{ .btc, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none },106 .{ .btc, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 7, .none },
107 .{ .btc, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .long },107 .{ .btc, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 7, .long },
108108
109 .{ .btr, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none },109 .{ .btr, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb3 }, 0, .none },
110 .{ .btr, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none },110 .{ .btr, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb3 }, 0, .none },
111 .{ .btr, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb3 }, 0, .long },111 .{ .btr, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb3 }, 0, .long },
112 .{ .btr, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none },112 .{ .btr, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },
113 .{ .btr, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none },113 .{ .btr, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 6, .none },
114 .{ .btr, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .long },114 .{ .btr, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 6, .long },
115115
116 .{ .bts, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xab }, 0, .none },116 .{ .bts, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xab }, 0, .none },
117 .{ .bts, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xab }, 0, .none },117 .{ .bts, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xab }, 0, .none },
118 .{ .bts, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xab }, 0, .long },118 .{ .bts, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xab }, 0, .long },
119 .{ .bts, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none },119 .{ .bts, .mi, &.{ .rm16, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },
120 .{ .bts, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none },120 .{ .bts, .mi, &.{ .rm32, .imm8 }, &.{ 0x0f, 0xba }, 5, .none },
121 .{ .bts, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .long },121 .{ .bts, .mi, &.{ .rm64, .imm8 }, &.{ 0x0f, 0xba }, 5, .long },
122122
123 // This is M encoding according to Intel, but D makes more sense here.123 // This is M encoding according to Intel, but D makes more sense here.
124 .{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none },124 .{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none },
125 .{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none },125 .{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none },
126126
127 .{ .cbw, .np, .o16, .none, .none, .none, &.{ 0x98 }, 0, .none },127 .{ .cbw, .np, &.{ .o16 }, &.{ 0x98 }, 0, .none },
128 .{ .cwde, .np, .o32, .none, .none, .none, &.{ 0x98 }, 0, .none },128 .{ .cwde, .np, &.{ .o32 }, &.{ 0x98 }, 0, .none },
129 .{ .cdqe, .np, .o64, .none, .none, .none, &.{ 0x98 }, 0, .long },129 .{ .cdqe, .np, &.{ .o64 }, &.{ 0x98 }, 0, .long },
130130
131 .{ .cwd, .np, .o16, .none, .none, .none, &.{ 0x99 }, 0, .none },131 .{ .cwd, .np, &.{ .o16 }, &.{ 0x99 }, 0, .none },
132 .{ .cdq, .np, .o32, .none, .none, .none, &.{ 0x99 }, 0, .none },132 .{ .cdq, .np, &.{ .o32 }, &.{ 0x99 }, 0, .none },
133 .{ .cqo, .np, .o64, .none, .none, .none, &.{ 0x99 }, 0, .long },133 .{ .cqo, .np, &.{ .o64 }, &.{ 0x99 }, 0, .long },
134134
135 .{ .cmova, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },135 .{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },
136 .{ .cmova, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },136 .{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },
137 .{ .cmova, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long },137 .{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },
138 .{ .cmovae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },138 .{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
139 .{ .cmovae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },139 .{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
140 .{ .cmovae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },140 .{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
141 .{ .cmovb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },141 .{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
142 .{ .cmovb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },142 .{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
143 .{ .cmovb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },143 .{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
144 .{ .cmovbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },144 .{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },
145 .{ .cmovbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },145 .{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },
146 .{ .cmovbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long },146 .{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },
147 .{ .cmovc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },147 .{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
148 .{ .cmovc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },148 .{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
149 .{ .cmovc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },149 .{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
150 .{ .cmove, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },150 .{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },
151 .{ .cmove, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },151 .{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },
152 .{ .cmove, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long },152 .{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },
153 .{ .cmovg, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },153 .{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },
154 .{ .cmovg, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },154 .{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },
155 .{ .cmovg, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long },155 .{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },
156 .{ .cmovge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },156 .{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },
157 .{ .cmovge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },157 .{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },
158 .{ .cmovge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long },158 .{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },
159 .{ .cmovl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },159 .{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },
160 .{ .cmovl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },160 .{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },
161 .{ .cmovl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long },161 .{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },
162 .{ .cmovle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },162 .{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },
163 .{ .cmovle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },163 .{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },
164 .{ .cmovle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long },164 .{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },
165 .{ .cmovna, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },165 .{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .none },
166 .{ .cmovna, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },166 .{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none },
167 .{ .cmovna, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long },167 .{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long },
168 .{ .cmovnae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },168 .{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .none },
169 .{ .cmovnae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },169 .{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none },
170 .{ .cmovnae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },170 .{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long },
171 .{ .cmovnb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },171 .{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
172 .{ .cmovnb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },172 .{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
173 .{ .cmovnb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },173 .{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
174 .{ .cmovnbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },174 .{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .none },
175 .{ .cmovnbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },175 .{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none },
176 .{ .cmovnbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long },176 .{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long },
177 .{ .cmovnc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },177 .{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .none },
178 .{ .cmovnc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },178 .{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none },
179 .{ .cmovnc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },179 .{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long },
180 .{ .cmovne, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },180 .{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },
181 .{ .cmovne, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },181 .{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },
182 .{ .cmovne, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long },182 .{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },
183 .{ .cmovng, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },183 .{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .none },
184 .{ .cmovng, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },184 .{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none },
185 .{ .cmovng, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long },185 .{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long },
186 .{ .cmovnge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },186 .{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .none },
187 .{ .cmovnge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },187 .{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none },
188 .{ .cmovnge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long },188 .{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long },
189 .{ .cmovnl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },189 .{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .none },
190 .{ .cmovnl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },190 .{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none },
191 .{ .cmovnl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long },191 .{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long },
192 .{ .cmovnle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },192 .{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .none },
193 .{ .cmovnle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },193 .{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none },
194 .{ .cmovnle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long },194 .{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long },
195 .{ .cmovno, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x41 }, 0, .none },195 .{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .none },
196 .{ .cmovno, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x41 }, 0, .none },196 .{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none },
197 .{ .cmovno, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x41 }, 0, .long },197 .{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long },
198 .{ .cmovnp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },198 .{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },
199 .{ .cmovnp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },199 .{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },
200 .{ .cmovnp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long },200 .{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },
201 .{ .cmovns, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x49 }, 0, .none },201 .{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .none },
202 .{ .cmovns, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x49 }, 0, .none },202 .{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none },
203 .{ .cmovns, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x49 }, 0, .long },203 .{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long },
204 .{ .cmovnz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },204 .{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .none },
205 .{ .cmovnz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },205 .{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none },
206 .{ .cmovnz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long },206 .{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long },
207 .{ .cmovo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x40 }, 0, .none },207 .{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .none },
208 .{ .cmovo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x40 }, 0, .none },208 .{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none },
209 .{ .cmovo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x40 }, 0, .long },209 .{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long },
210 .{ .cmovp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },210 .{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },
211 .{ .cmovp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },211 .{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },
212 .{ .cmovp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long },212 .{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },
213 .{ .cmovpe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },213 .{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .none },
214 .{ .cmovpe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },214 .{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none },
215 .{ .cmovpe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long },215 .{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long },
216 .{ .cmovpo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },216 .{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .none },
217 .{ .cmovpo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },217 .{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none },
218 .{ .cmovpo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long },218 .{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long },
219 .{ .cmovs, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x48 }, 0, .none },219 .{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .none },
220 .{ .cmovs, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x48 }, 0, .none },220 .{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none },
221 .{ .cmovs, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x48 }, 0, .long },221 .{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long },
222 .{ .cmovz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },222 .{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .none },
223 .{ .cmovz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },223 .{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none },
224 .{ .cmovz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long },224 .{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long },
225225
226 .{ .cmp, .zi, .al, .imm8, .none, .none, &.{ 0x3c }, 0, .none },226 .{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none },
227 .{ .cmp, .zi, .ax, .imm16, .none, .none, &.{ 0x3d }, 0, .none },227 .{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .none },
228 .{ .cmp, .zi, .eax, .imm32, .none, .none, &.{ 0x3d }, 0, .none },228 .{ .cmp, .zi, &.{ .eax, .imm32 }, &.{ 0x3d }, 0, .none },
229 .{ .cmp, .zi, .rax, .imm32s, .none, .none, &.{ 0x3d }, 0, .long },229 .{ .cmp, .zi, &.{ .rax, .imm32s }, &.{ 0x3d }, 0, .long },
230 .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .none },230 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .none },
231 .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .rex },231 .{ .cmp, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 7, .rex },
232 .{ .cmp, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 7, .none },232 .{ .cmp, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 7, .none },
233 .{ .cmp, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 7, .none },233 .{ .cmp, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 7, .none },
234 .{ .cmp, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 7, .long },234 .{ .cmp, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 7, .long },
235 .{ .cmp, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 7, .none },235 .{ .cmp, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 7, .none },
236 .{ .cmp, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 7, .none },236 .{ .cmp, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 7, .none },
237 .{ .cmp, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 7, .long },237 .{ .cmp, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 7, .long },
238 .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .none },238 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .none },
239 .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .rex },239 .{ .cmp, .mr, &.{ .rm8, .r8 }, &.{ 0x38 }, 0, .rex },
240 .{ .cmp, .mr, .rm16, .r16, .none, .none, &.{ 0x39 }, 0, .none },240 .{ .cmp, .mr, &.{ .rm16, .r16 }, &.{ 0x39 }, 0, .none },
241 .{ .cmp, .mr, .rm32, .r32, .none, .none, &.{ 0x39 }, 0, .none },241 .{ .cmp, .mr, &.{ .rm32, .r32 }, &.{ 0x39 }, 0, .none },
242 .{ .cmp, .mr, .rm64, .r64, .none, .none, &.{ 0x39 }, 0, .long },242 .{ .cmp, .mr, &.{ .rm64, .r64 }, &.{ 0x39 }, 0, .long },
243 .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .none },243 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .none },
244 .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .rex },244 .{ .cmp, .rm, &.{ .r8, .rm8 }, &.{ 0x3a }, 0, .rex },
245 .{ .cmp, .rm, .r16, .rm16, .none, .none, &.{ 0x3b }, 0, .none },245 .{ .cmp, .rm, &.{ .r16, .rm16 }, &.{ 0x3b }, 0, .none },
246 .{ .cmp, .rm, .r32, .rm32, .none, .none, &.{ 0x3b }, 0, .none },246 .{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none },
247 .{ .cmp, .rm, .r64, .rm64, .none, .none, &.{ 0x3b }, 0, .long },247 .{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long },
248248
249 .{ .cmps, .np, .m8, .m8, .none, .none, &.{ 0xa6 }, 0, .none },249 .{ .cmps, .np, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none },
250 .{ .cmps, .np, .m16, .m16, .none, .none, &.{ 0xa7 }, 0, .none },250 .{ .cmps, .np, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .none },
251 .{ .cmps, .np, .m32, .m32, .none, .none, &.{ 0xa7 }, 0, .none },251 .{ .cmps, .np, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none },
252 .{ .cmps, .np, .m64, .m64, .none, .none, &.{ 0xa7 }, 0, .long },252 .{ .cmps, .np, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long },
253 .{ .cmpsb, .np, .none, .none, .none, .none, &.{ 0xa6 }, 0, .none },253
254 .{ .cmpsw, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .short },254 .{ .cmpsb, .np, &.{}, &.{ 0xa6 }, 0, .none },
255 .{ .cmpsd, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .none },255 .{ .cmpsw, .np, &.{}, &.{ 0xa7 }, 0, .short },
256 .{ .cmpsq, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .long },256 .{ .cmpsd, .np, &.{}, &.{ 0xa7 }, 0, .none },
257257 .{ .cmpsq, .np, &.{}, &.{ 0xa7 }, 0, .long },
258 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },258
259 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },259 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none },
260 .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },260 .{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex },
261 .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },261 .{ .cmpxchg, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xb1 }, 0, .none },
262 .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },262 .{ .cmpxchg, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xb1 }, 0, .none },
263263 .{ .cmpxchg, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xb1 }, 0, .long },
264 .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },264
265 .{ .cmpxchg16b, .m, .m128, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .long },265 .{ .cmpxchg8b , .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none },
266266 .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long },
267 .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none },267
268 .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex },268 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none },
269 .{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none },269 .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex },
270 .{ .div, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 6, .none },270 .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .none },
271 .{ .div, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 6, .long },271 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none },
272272 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long },
273 .{ .fisttp, .m, .m16, .none, .none, .none, &.{ 0xdf }, 1, .fpu },273
274 .{ .fisttp, .m, .m32, .none, .none, .none, &.{ 0xdb }, 1, .fpu },274 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .fpu },
275 .{ .fisttp, .m, .m64, .none, .none, .none, &.{ 0xdd }, 1, .fpu },275 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .fpu },
276276 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .fpu },
277 .{ .fld, .m, .m32, .none, .none, .none, &.{ 0xd9 }, 0, .fpu },277
278 .{ .fld, .m, .m64, .none, .none, .none, &.{ 0xdd }, 0, .fpu },278 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .fpu },
279 .{ .fld, .m, .m80, .none, .none, .none, &.{ 0xdb }, 5, .fpu },279 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .fpu },
280280 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .fpu },
281 .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .none },281
282 .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .rex },282 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none },
283 .{ .idiv, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 7, .none },283 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex },
284 .{ .idiv, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 7, .none },284 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .none },
285 .{ .idiv, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 7, .long },285 .{ .idiv, .m, &.{ .rm32 }, &.{ 0xf7 }, 7, .none },
286286 .{ .idiv, .m, &.{ .rm64 }, &.{ 0xf7 }, 7, .long },
287 .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .none },287
288 .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .rex },288 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .none },
289 .{ .imul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 5, .none },289 .{ .imul, .m, &.{ .rm8 }, &.{ 0xf6 }, 5, .rex },
290 .{ .imul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 5, .none },290 .{ .imul, .m, &.{ .rm16, }, &.{ 0xf7 }, 5, .none },
291 .{ .imul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 5, .long },291 .{ .imul, .m, &.{ .rm32, }, &.{ 0xf7 }, 5, .none },
292 .{ .imul, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xaf }, 0, .none },292 .{ .imul, .m, &.{ .rm64, }, &.{ 0xf7 }, 5, .long },
293 .{ .imul, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xaf }, 0, .none },293 .{ .imul, .rm, &.{ .r16, .rm16, }, &.{ 0x0f, 0xaf }, 0, .none },
294 .{ .imul, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xaf }, 0, .long },294 .{ .imul, .rm, &.{ .r32, .rm32, }, &.{ 0x0f, 0xaf }, 0, .none },
295 .{ .imul, .rmi, .r16, .rm16, .imm8s, .none, &.{ 0x6b }, 0, .none },295 .{ .imul, .rm, &.{ .r64, .rm64, }, &.{ 0x0f, 0xaf }, 0, .long },
296 .{ .imul, .rmi, .r32, .rm32, .imm8s, .none, &.{ 0x6b }, 0, .none },296 .{ .imul, .rmi, &.{ .r16, .rm16, .imm8s }, &.{ 0x6b }, 0, .none },
297 .{ .imul, .rmi, .r64, .rm64, .imm8s, .none, &.{ 0x6b }, 0, .long },297 .{ .imul, .rmi, &.{ .r32, .rm32, .imm8s }, &.{ 0x6b }, 0, .none },
298 .{ .imul, .rmi, .r16, .rm16, .imm16, .none, &.{ 0x69 }, 0, .none },298 .{ .imul, .rmi, &.{ .r64, .rm64, .imm8s }, &.{ 0x6b }, 0, .long },
299 .{ .imul, .rmi, .r32, .rm32, .imm32, .none, &.{ 0x69 }, 0, .none },299 .{ .imul, .rmi, &.{ .r16, .rm16, .imm16 }, &.{ 0x69 }, 0, .none },
300 .{ .imul, .rmi, .r64, .rm64, .imm32, .none, &.{ 0x69 }, 0, .long },300 .{ .imul, .rmi, &.{ .r32, .rm32, .imm32 }, &.{ 0x69 }, 0, .none },
301301 .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long },
302 .{ .int3, .np, .none, .none, .none, .none, &.{ 0xcc }, 0, .none },302
303303 .{ .int3, .np, &.{}, &.{ 0xcc }, 0, .none },
304 .{ .ja, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none },304
305 .{ .jae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },305 .{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },
306 .{ .jb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },306 .{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
307 .{ .jbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none },307 .{ .jb, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
308 .{ .jc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },308 .{ .jbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },
309 .{ .jrcxz, .d, .rel32, .none, .none, .none, &.{ 0xe3 }, 0, .none },309 .{ .jc, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
310 .{ .je, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none },310 .{ .jrcxz, .d, &.{ .rel32 }, &.{ 0xe3 }, 0, .none },
311 .{ .jg, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none },311 .{ .je, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },
312 .{ .jge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none },312 .{ .jg, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },
313 .{ .jl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none },313 .{ .jge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },
314 .{ .jle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none },314 .{ .jl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },
315 .{ .jna, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none },315 .{ .jle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },
316 .{ .jnae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },316 .{ .jna, .d, &.{ .rel32 }, &.{ 0x0f, 0x86 }, 0, .none },
317 .{ .jnb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },317 .{ .jnae, .d, &.{ .rel32 }, &.{ 0x0f, 0x82 }, 0, .none },
318 .{ .jnbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none },318 .{ .jnb, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
319 .{ .jnc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },319 .{ .jnbe, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none },
320 .{ .jne, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none },320 .{ .jnc, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none },
321 .{ .jng, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none },321 .{ .jne, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },
322 .{ .jnge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none },322 .{ .jng, .d, &.{ .rel32 }, &.{ 0x0f, 0x8e }, 0, .none },
323 .{ .jnl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none },323 .{ .jnge, .d, &.{ .rel32 }, &.{ 0x0f, 0x8c }, 0, .none },
324 .{ .jnle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none },324 .{ .jnl, .d, &.{ .rel32 }, &.{ 0x0f, 0x8d }, 0, .none },
325 .{ .jno, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x81 }, 0, .none },325 .{ .jnle, .d, &.{ .rel32 }, &.{ 0x0f, 0x8f }, 0, .none },
326 .{ .jnp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none },326 .{ .jno, .d, &.{ .rel32 }, &.{ 0x0f, 0x81 }, 0, .none },
327 .{ .jns, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x89 }, 0, .none },327 .{ .jnp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },
328 .{ .jnz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none },328 .{ .jns, .d, &.{ .rel32 }, &.{ 0x0f, 0x89 }, 0, .none },
329 .{ .jo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x80 }, 0, .none },329 .{ .jnz, .d, &.{ .rel32 }, &.{ 0x0f, 0x85 }, 0, .none },
330 .{ .jp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none },330 .{ .jo, .d, &.{ .rel32 }, &.{ 0x0f, 0x80 }, 0, .none },
331 .{ .jpe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none },331 .{ .jp, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },
332 .{ .jpo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none },332 .{ .jpe, .d, &.{ .rel32 }, &.{ 0x0f, 0x8a }, 0, .none },
333 .{ .js, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x88 }, 0, .none },333 .{ .jpo, .d, &.{ .rel32 }, &.{ 0x0f, 0x8b }, 0, .none },
334 .{ .jz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none },334 .{ .js, .d, &.{ .rel32 }, &.{ 0x0f, 0x88 }, 0, .none },
335335 .{ .jz, .d, &.{ .rel32 }, &.{ 0x0f, 0x84 }, 0, .none },
336 .{ .jmp, .d, .rel32, .none, .none, .none, &.{ 0xe9 }, 0, .none },336
337 .{ .jmp, .m, .rm64, .none, .none, .none, &.{ 0xff }, 4, .none },337 .{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none },
338338 .{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none },
339 .{ .lea, .rm, .r16, .m, .none, .none, &.{ 0x8d }, 0, .none },339
340 .{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none },340 .{ .lea, .rm, &.{ .r16, .m }, &.{ 0x8d }, 0, .none },
341 .{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long },341 .{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none },
342342 .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long },
343 .{ .lfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },343
344344 .{ .lfence, .np, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },
345 .{ .lods, .np, .m8, .none, .none, .none, &.{ 0xac }, 0, .none },345
346 .{ .lods, .np, .m16, .none, .none, .none, &.{ 0xad }, 0, .none },346 .{ .lods, .np, &.{ .m8 }, &.{ 0xac }, 0, .none },
347 .{ .lods, .np, .m32, .none, .none, .none, &.{ 0xad }, 0, .none },347 .{ .lods, .np, &.{ .m16 }, &.{ 0xad }, 0, .none },
348 .{ .lods, .np, .m64, .none, .none, .none, &.{ 0xad }, 0, .long },348 .{ .lods, .np, &.{ .m32 }, &.{ 0xad }, 0, .none },
349 .{ .lodsb, .np, .none, .none, .none, .none, &.{ 0xac }, 0, .none },349 .{ .lods, .np, &.{ .m64 }, &.{ 0xad }, 0, .long },
350 .{ .lodsw, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .short },350
351 .{ .lodsd, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .none },351 .{ .lodsb, .np, &.{}, &.{ 0xac }, 0, .none },
352 .{ .lodsq, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .long },352 .{ .lodsw, .np, &.{}, &.{ 0xad }, 0, .short },
353353 .{ .lodsd, .np, &.{}, &.{ 0xad }, 0, .none },
354 .{ .lzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },354 .{ .lodsq, .np, &.{}, &.{ 0xad }, 0, .long },
355 .{ .lzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },355
356 .{ .lzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },356 .{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
357357 .{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
358 .{ .mfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },358 .{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
359359
360 .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },360 .{ .mfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },
361 .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },361
362 .{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },362 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none },
363 .{ .mov, .mr, .rm32, .r32, .none, .none, &.{ 0x89 }, 0, .none },363 .{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex },
364 .{ .mov, .mr, .rm64, .r64, .none, .none, &.{ 0x89 }, 0, .long },364 .{ .mov, .mr, &.{ .rm16, .r16 }, &.{ 0x89 }, 0, .none },
365 .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .none },365 .{ .mov, .mr, &.{ .rm32, .r32 }, &.{ 0x89 }, 0, .none },
366 .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .rex },366 .{ .mov, .mr, &.{ .rm64, .r64 }, &.{ 0x89 }, 0, .long },
367 .{ .mov, .rm, .r16, .rm16, .none, .none, &.{ 0x8b }, 0, .none },367 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .none },
368 .{ .mov, .rm, .r32, .rm32, .none, .none, &.{ 0x8b }, 0, .none },368 .{ .mov, .rm, &.{ .r8, .rm8 }, &.{ 0x8a }, 0, .rex },
369 .{ .mov, .rm, .r64, .rm64, .none, .none, &.{ 0x8b }, 0, .long },369 .{ .mov, .rm, &.{ .r16, .rm16 }, &.{ 0x8b }, 0, .none },
370 .{ .mov, .mr, .rm16, .sreg, .none, .none, &.{ 0x8c }, 0, .none },370 .{ .mov, .rm, &.{ .r32, .rm32 }, &.{ 0x8b }, 0, .none },
371 .{ .mov, .mr, .rm64, .sreg, .none, .none, &.{ 0x8c }, 0, .long },371 .{ .mov, .rm, &.{ .r64, .rm64 }, &.{ 0x8b }, 0, .long },
372 .{ .mov, .rm, .sreg, .rm16, .none, .none, &.{ 0x8e }, 0, .none },372 .{ .mov, .mr, &.{ .rm16, .sreg }, &.{ 0x8c }, 0, .none },
373 .{ .mov, .rm, .sreg, .rm64, .none, .none, &.{ 0x8e }, 0, .long },373 .{ .mov, .mr, &.{ .rm64, .sreg }, &.{ 0x8c }, 0, .long },
374 .{ .mov, .fd, .al, .moffs, .none, .none, &.{ 0xa0 }, 0, .none },374 .{ .mov, .rm, &.{ .sreg, .rm16 }, &.{ 0x8e }, 0, .none },
375 .{ .mov, .fd, .ax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none },375 .{ .mov, .rm, &.{ .sreg, .rm64 }, &.{ 0x8e }, 0, .long },
376 .{ .mov, .fd, .eax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none },376 .{ .mov, .fd, &.{ .al, .moffs }, &.{ 0xa0 }, 0, .none },
377 .{ .mov, .fd, .rax, .moffs, .none, .none, &.{ 0xa1 }, 0, .long },377 .{ .mov, .fd, &.{ .ax, .moffs }, &.{ 0xa1 }, 0, .none },
378 .{ .mov, .td, .moffs, .al, .none, .none, &.{ 0xa2 }, 0, .none },378 .{ .mov, .fd, &.{ .eax, .moffs }, &.{ 0xa1 }, 0, .none },
379 .{ .mov, .td, .moffs, .ax, .none, .none, &.{ 0xa3 }, 0, .none },379 .{ .mov, .fd, &.{ .rax, .moffs }, &.{ 0xa1 }, 0, .long },
380 .{ .mov, .td, .moffs, .eax, .none, .none, &.{ 0xa3 }, 0, .none },380 .{ .mov, .td, &.{ .moffs, .al }, &.{ 0xa2 }, 0, .none },
381 .{ .mov, .td, .moffs, .rax, .none, .none, &.{ 0xa3 }, 0, .long },381 .{ .mov, .td, &.{ .moffs, .ax }, &.{ 0xa3 }, 0, .none },
382 .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .none },382 .{ .mov, .td, &.{ .moffs, .eax }, &.{ 0xa3 }, 0, .none },
383 .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .rex },383 .{ .mov, .td, &.{ .moffs, .rax }, &.{ 0xa3 }, 0, .long },
384 .{ .mov, .oi, .r16, .imm16, .none, .none, &.{ 0xb8 }, 0, .none },384 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .none },
385 .{ .mov, .oi, .r32, .imm32, .none, .none, &.{ 0xb8 }, 0, .none },385 .{ .mov, .oi, &.{ .r8, .imm8 }, &.{ 0xb0 }, 0, .rex },
386 .{ .mov, .oi, .r64, .imm64, .none, .none, &.{ 0xb8 }, 0, .long },386 .{ .mov, .oi, &.{ .r16, .imm16 }, &.{ 0xb8 }, 0, .none },
387 .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .none },387 .{ .mov, .oi, &.{ .r32, .imm32 }, &.{ 0xb8 }, 0, .none },
388 .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .rex },388 .{ .mov, .oi, &.{ .r64, .imm64 }, &.{ 0xb8 }, 0, .long },
389 .{ .mov, .mi, .rm16, .imm16, .none, .none, &.{ 0xc7 }, 0, .none },389 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .none },
390 .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none },390 .{ .mov, .mi, &.{ .rm8, .imm8 }, &.{ 0xc6 }, 0, .rex },
391 .{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long },391 .{ .mov, .mi, &.{ .rm16, .imm16 }, &.{ 0xc7 }, 0, .none },
392392 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none },
393 .{ .movbe, .rm, .r16, .m16, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },393 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long },
394 .{ .movbe, .rm, .r32, .m32, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },394
395 .{ .movbe, .rm, .r64, .m64, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },395 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
396 .{ .movbe, .mr, .m16, .r16, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },396 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
397 .{ .movbe, .mr, .m32, .r32, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },397 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },
398 .{ .movbe, .mr, .m64, .r64, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },398 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
399399 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
400 .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none },400 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },
401 .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none },401
402 .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none },402 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none },
403 .{ .movs, .np, .m64, .m64, .none, .none, &.{ 0xa5 }, 0, .long },403 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .none },
404 .{ .movsb, .np, .none, .none, .none, .none, &.{ 0xa4 }, 0, .none },404 .{ .movs, .np, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none },
405 .{ .movsw, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .short },405 .{ .movs, .np, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long },
406 .{ .movsd, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .none },406
407 .{ .movsq, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .long },407 .{ .movsb, .np, &.{}, &.{ 0xa4 }, 0, .none },
408408 .{ .movsw, .np, &.{}, &.{ 0xa5 }, 0, .short },
409 .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },409 .{ .movsd, .np, &.{}, &.{ 0xa5 }, 0, .none },
410 .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },410 .{ .movsq, .np, &.{}, &.{ 0xa5 }, 0, .long },
411 .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },411
412 .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },412 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },
413 .{ .movsx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .long },413 .{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex },
414 .{ .movsx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .none },414 .{ .movsx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xbe }, 0, .none },
415 .{ .movsx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .long },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
417 // This instruction is discouraged.420 // This instruction is discouraged.
418 .{ .movsxd, .rm, .r32, .rm32, .none, .none, &.{ 0x63 }, 0, .none },421 .{ .movsxd, .rm, &.{ .r32, .rm32 }, &.{ 0x63 }, 0, .none },
419 .{ .movsxd, .rm, .r64, .rm32, .none, .none, &.{ 0x63 }, 0, .long },422 .{ .movsxd, .rm, &.{ .r64, .rm32 }, &.{ 0x63 }, 0, .long },
420423
421 .{ .movzx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none },424 .{ .movzx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },
422 .{ .movzx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none },425 .{ .movzx, .rm, &.{ .r32, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .none },
423 .{ .movzx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .long },426 .{ .movzx, .rm, &.{ .r64, .rm8 }, &.{ 0x0f, 0xb6 }, 0, .long },
424 .{ .movzx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .none },427 .{ .movzx, .rm, &.{ .r32, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .none },
425 .{ .movzx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .long },428 .{ .movzx, .rm, &.{ .r64, .rm16 }, &.{ 0x0f, 0xb7 }, 0, .long },
426429
427 .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .none },430 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .none },
428 .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .rex },431 .{ .mul, .m, &.{ .rm8 }, &.{ 0xf6 }, 4, .rex },
429 .{ .mul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 4, .none },432 .{ .mul, .m, &.{ .rm16 }, &.{ 0xf7 }, 4, .none },
430 .{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none },433 .{ .mul, .m, &.{ .rm32 }, &.{ 0xf7 }, 4, .none },
431 .{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long },434 .{ .mul, .m, &.{ .rm64 }, &.{ 0xf7 }, 4, .long },
432435
433 .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .none },436 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .none },
434 .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .rex },437 .{ .neg, .m, &.{ .rm8 }, &.{ 0xf6 }, 3, .rex },
435 .{ .neg, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 3, .none },438 .{ .neg, .m, &.{ .rm16 }, &.{ 0xf7 }, 3, .none },
436 .{ .neg, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 3, .none },439 .{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none },
437 .{ .neg, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 3, .long },440 .{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long },
438441
439 .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none },442 .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none },
440443
441 .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .none },444 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none },
442 .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .rex },445 .{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex },
443 .{ .not, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 2, .none },446 .{ .not, .m, &.{ .rm16 }, &.{ 0xf7 }, 2, .none },
444 .{ .not, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 2, .none },447 .{ .not, .m, &.{ .rm32 }, &.{ 0xf7 }, 2, .none },
445 .{ .not, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 2, .long },448 .{ .not, .m, &.{ .rm64 }, &.{ 0xf7 }, 2, .long },
446449
447 .{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none },450 .{ .@"or", .zi, &.{ .al, .imm8 }, &.{ 0x0c }, 0, .none },
448 .{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none },451 .{ .@"or", .zi, &.{ .ax, .imm16 }, &.{ 0x0d }, 0, .none },
449 .{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none },452 .{ .@"or", .zi, &.{ .eax, .imm32 }, &.{ 0x0d }, 0, .none },
450 .{ .@"or", .zi, .rax, .imm32s, .none, .none, &.{ 0x0d }, 0, .long },453 .{ .@"or", .zi, &.{ .rax, .imm32s }, &.{ 0x0d }, 0, .long },
451 .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .none },454 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .none },
452 .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .rex },455 .{ .@"or", .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 1, .rex },
453 .{ .@"or", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 1, .none },456 .{ .@"or", .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 1, .none },
454 .{ .@"or", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 1, .none },457 .{ .@"or", .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 1, .none },
455 .{ .@"or", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 1, .long },458 .{ .@"or", .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 1, .long },
456 .{ .@"or", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 1, .none },459 .{ .@"or", .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 1, .none },
457 .{ .@"or", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 1, .none },460 .{ .@"or", .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 1, .none },
458 .{ .@"or", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 1, .long },461 .{ .@"or", .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 1, .long },
459 .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .none },462 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .none },
460 .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .rex },463 .{ .@"or", .mr, &.{ .rm8, .r8 }, &.{ 0x08 }, 0, .rex },
461 .{ .@"or", .mr, .rm16, .r16, .none, .none, &.{ 0x09 }, 0, .none },464 .{ .@"or", .mr, &.{ .rm16, .r16 }, &.{ 0x09 }, 0, .none },
462 .{ .@"or", .mr, .rm32, .r32, .none, .none, &.{ 0x09 }, 0, .none },465 .{ .@"or", .mr, &.{ .rm32, .r32 }, &.{ 0x09 }, 0, .none },
463 .{ .@"or", .mr, .rm64, .r64, .none, .none, &.{ 0x09 }, 0, .long },466 .{ .@"or", .mr, &.{ .rm64, .r64 }, &.{ 0x09 }, 0, .long },
464 .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .none },467 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .none },
465 .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .rex },468 .{ .@"or", .rm, &.{ .r8, .rm8 }, &.{ 0x0a }, 0, .rex },
466 .{ .@"or", .rm, .r16, .rm16, .none, .none, &.{ 0x0b }, 0, .none },469 .{ .@"or", .rm, &.{ .r16, .rm16 }, &.{ 0x0b }, 0, .none },
467 .{ .@"or", .rm, .r32, .rm32, .none, .none, &.{ 0x0b }, 0, .none },470 .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none },
468 .{ .@"or", .rm, .r64, .rm64, .none, .none, &.{ 0x0b }, 0, .long },471 .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long },
469472
470 .{ .pop, .o, .r16, .none, .none, .none, &.{ 0x58 }, 0, .none },473 .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .none },
471 .{ .pop, .o, .r64, .none, .none, .none, &.{ 0x58 }, 0, .none },474 .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none },
472 .{ .pop, .m, .rm16, .none, .none, .none, &.{ 0x8f }, 0, .none },475 .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .none },
473 .{ .pop, .m, .rm64, .none, .none, .none, &.{ 0x8f }, 0, .none },476 .{ .pop, .m, &.{ .rm64 }, &.{ 0x8f }, 0, .none },
474477
475 .{ .popcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },478 .{ .popcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
476 .{ .popcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },479 .{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
477 .{ .popcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },480 .{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },
478481
479 .{ .push, .o, .r16, .none, .none, .none, &.{ 0x50 }, 0, .none },482 .{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .none },
480 .{ .push, .o, .r64, .none, .none, .none, &.{ 0x50 }, 0, .none },483 .{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none },
481 .{ .push, .m, .rm16, .none, .none, .none, &.{ 0xff }, 6, .none },484 .{ .push, .m, &.{ .rm16 }, &.{ 0xff }, 6, .none },
482 .{ .push, .m, .rm64, .none, .none, .none, &.{ 0xff }, 6, .none },485 .{ .push, .m, &.{ .rm64 }, &.{ 0xff }, 6, .none },
483 .{ .push, .i, .imm8, .none, .none, .none, &.{ 0x6a }, 0, .none },486 .{ .push, .i, &.{ .imm8 }, &.{ 0x6a }, 0, .none },
484 .{ .push, .i, .imm16, .none, .none, .none, &.{ 0x68 }, 0, .none },487 .{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .none },
485 .{ .push, .i, .imm32, .none, .none, .none, &.{ 0x68 }, 0, .none },488 .{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none },
486489
487 .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none },490 .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none },
488491
489 .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .none },492 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none },
490 .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .rex },493 .{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex },
491 .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .none },494 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .none },
492 .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .rex },495 .{ .rcl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 2, .rex },
493 .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .none },496 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .none },
494 .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .rex },497 .{ .rcl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 2, .rex },
495 .{ .rcl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 2, .none },498 .{ .rcl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 2, .none },
496 .{ .rcl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 2, .none },499 .{ .rcl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 2, .none },
497 .{ .rcl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 2, .none },500 .{ .rcl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 2, .none },
498 .{ .rcl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 2, .none },501 .{ .rcl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 2, .none },
499 .{ .rcl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 2, .long },502 .{ .rcl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 2, .long },
500 .{ .rcl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 2, .none },503 .{ .rcl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 2, .none },
501 .{ .rcl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 2, .long },504 .{ .rcl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 2, .long },
502 .{ .rcl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 2, .none },505 .{ .rcl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 2, .none },
503 .{ .rcl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 2, .long },506 .{ .rcl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 2, .long },
504507
505 .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .none },508 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .none },
506 .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .rex },509 .{ .rcr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 3, .rex },
507 .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .none },510 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .none },
508 .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .rex },511 .{ .rcr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 3, .rex },
509 .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .none },512 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .none },
510 .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .rex },513 .{ .rcr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 3, .rex },
511 .{ .rcr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 3, .none },514 .{ .rcr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 3, .none },
512 .{ .rcr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 3, .none },515 .{ .rcr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 3, .none },
513 .{ .rcr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 3, .none },516 .{ .rcr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 3, .none },
514 .{ .rcr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 3, .none },517 .{ .rcr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 3, .none },
515 .{ .rcr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 3, .long },518 .{ .rcr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 3, .long },
516 .{ .rcr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 3, .none },519 .{ .rcr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 3, .none },
517 .{ .rcr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 3, .long },520 .{ .rcr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 3, .long },
518 .{ .rcr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 3, .none },521 .{ .rcr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 3, .none },
519 .{ .rcr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 3, .long },522 .{ .rcr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 3, .long },
520523
521 .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .none },524 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .none },
522 .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .rex },525 .{ .rol, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 0, .rex },
523 .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .none },526 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .none },
524 .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .rex },527 .{ .rol, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 0, .rex },
525 .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .none },528 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .none },
526 .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .rex },529 .{ .rol, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 0, .rex },
527 .{ .rol, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 0, .none },530 .{ .rol, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 0, .none },
528 .{ .rol, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 0, .none },531 .{ .rol, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 0, .none },
529 .{ .rol, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 0, .none },532 .{ .rol, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 0, .none },
530 .{ .rol, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 0, .none },533 .{ .rol, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 0, .none },
531 .{ .rol, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 0, .long },534 .{ .rol, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 0, .long },
532 .{ .rol, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 0, .none },535 .{ .rol, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 0, .none },
533 .{ .rol, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 0, .long },536 .{ .rol, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 0, .long },
534 .{ .rol, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 0, .none },537 .{ .rol, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 0, .none },
535 .{ .rol, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 0, .long },538 .{ .rol, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 0, .long },
536539
537 .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .none },540 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .none },
538 .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .rex },541 .{ .ror, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 1, .rex },
539 .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .none },542 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .none },
540 .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .rex },543 .{ .ror, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 1, .rex },
541 .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .none },544 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .none },
542 .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .rex },545 .{ .ror, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 1, .rex },
543 .{ .ror, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 1, .none },546 .{ .ror, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 1, .none },
544 .{ .ror, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 1, .none },547 .{ .ror, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 1, .none },
545 .{ .ror, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 1, .none },548 .{ .ror, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 1, .none },
546 .{ .ror, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 1, .none },549 .{ .ror, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 1, .none },
547 .{ .ror, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 1, .long },550 .{ .ror, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 1, .long },
548 .{ .ror, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 1, .none },551 .{ .ror, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 1, .none },
549 .{ .ror, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 1, .long },552 .{ .ror, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 1, .long },
550 .{ .ror, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 1, .none },553 .{ .ror, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 1, .none },
551 .{ .ror, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 1, .long },554 .{ .ror, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 1, .long },
552555
553 .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },556 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },
554 .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },557 .{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },
555 .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },558 .{ .sal, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },
556 .{ .sal, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none },559 .{ .sal, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },
557 .{ .sal, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long },560 .{ .sal, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },
558 .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none },561 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },
559 .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex },562 .{ .sal, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },
560 .{ .sal, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none },563 .{ .sal, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },
561 .{ .sal, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none },564 .{ .sal, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },
562 .{ .sal, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long },565 .{ .sal, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },
563 .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none },566 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },
564 .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex },567 .{ .sal, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },
565 .{ .sal, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },568 .{ .sal, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },
566 .{ .sal, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },569 .{ .sal, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },
567 .{ .sal, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },570 .{ .sal, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },
568571
569 .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .none },572 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .none },
570 .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .rex },573 .{ .sar, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 7, .rex },
571 .{ .sar, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 7, .none },574 .{ .sar, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 7, .none },
572 .{ .sar, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 7, .none },575 .{ .sar, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 7, .none },
573 .{ .sar, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 7, .long },576 .{ .sar, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 7, .long },
574 .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .none },577 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .none },
575 .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .rex },578 .{ .sar, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 7, .rex },
576 .{ .sar, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 7, .none },579 .{ .sar, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 7, .none },
577 .{ .sar, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 7, .none },580 .{ .sar, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 7, .none },
578 .{ .sar, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 7, .long },581 .{ .sar, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 7, .long },
579 .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .none },582 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .none },
580 .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .rex },583 .{ .sar, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 7, .rex },
581 .{ .sar, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 7, .none },584 .{ .sar, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 7, .none },
582 .{ .sar, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 7, .none },585 .{ .sar, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 7, .none },
583 .{ .sar, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 7, .long },586 .{ .sar, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 7, .long },
584587
585 .{ .sbb, .zi, .al, .imm8, .none, .none, &.{ 0x1c }, 0, .none },588 .{ .sbb, .zi, &.{ .al, .imm8 }, &.{ 0x1c }, 0, .none },
586 .{ .sbb, .zi, .ax, .imm16, .none, .none, &.{ 0x1d }, 0, .none },589 .{ .sbb, .zi, &.{ .ax, .imm16 }, &.{ 0x1d }, 0, .none },
587 .{ .sbb, .zi, .eax, .imm32, .none, .none, &.{ 0x1d }, 0, .none },590 .{ .sbb, .zi, &.{ .eax, .imm32 }, &.{ 0x1d }, 0, .none },
588 .{ .sbb, .zi, .rax, .imm32s, .none, .none, &.{ 0x1d }, 0, .long },591 .{ .sbb, .zi, &.{ .rax, .imm32s }, &.{ 0x1d }, 0, .long },
589 .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .none },592 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .none },
590 .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .rex },593 .{ .sbb, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 3, .rex },
591 .{ .sbb, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 3, .none },594 .{ .sbb, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 3, .none },
592 .{ .sbb, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 3, .none },595 .{ .sbb, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 3, .none },
593 .{ .sbb, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 3, .long },596 .{ .sbb, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 3, .long },
594 .{ .sbb, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 3, .none },597 .{ .sbb, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 3, .none },
595 .{ .sbb, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 3, .none },598 .{ .sbb, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 3, .none },
596 .{ .sbb, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 3, .long },599 .{ .sbb, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 3, .long },
597 .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .none },600 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .none },
598 .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .rex },601 .{ .sbb, .mr, &.{ .rm8, .r8 }, &.{ 0x18 }, 0, .rex },
599 .{ .sbb, .mr, .rm16, .r16, .none, .none, &.{ 0x19 }, 0, .none },602 .{ .sbb, .mr, &.{ .rm16, .r16 }, &.{ 0x19 }, 0, .none },
600 .{ .sbb, .mr, .rm32, .r32, .none, .none, &.{ 0x19 }, 0, .none },603 .{ .sbb, .mr, &.{ .rm32, .r32 }, &.{ 0x19 }, 0, .none },
601 .{ .sbb, .mr, .rm64, .r64, .none, .none, &.{ 0x19 }, 0, .long },604 .{ .sbb, .mr, &.{ .rm64, .r64 }, &.{ 0x19 }, 0, .long },
602 .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .none },605 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .none },
603 .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .rex },606 .{ .sbb, .rm, &.{ .r8, .rm8 }, &.{ 0x1a }, 0, .rex },
604 .{ .sbb, .rm, .r16, .rm16, .none, .none, &.{ 0x1b }, 0, .none },607 .{ .sbb, .rm, &.{ .r16, .rm16 }, &.{ 0x1b }, 0, .none },
605 .{ .sbb, .rm, .r32, .rm32, .none, .none, &.{ 0x1b }, 0, .none },608 .{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none },
606 .{ .sbb, .rm, .r64, .rm64, .none, .none, &.{ 0x1b }, 0, .long },609 .{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long },
607610
608 .{ .scas, .np, .m8, .none, .none, .none, &.{ 0xae }, 0, .none },611 .{ .scas, .np, &.{ .m8 }, &.{ 0xae }, 0, .none },
609 .{ .scas, .np, .m16, .none, .none, .none, &.{ 0xaf }, 0, .none },612 .{ .scas, .np, &.{ .m16 }, &.{ 0xaf }, 0, .none },
610 .{ .scas, .np, .m32, .none, .none, .none, &.{ 0xaf }, 0, .none },613 .{ .scas, .np, &.{ .m32 }, &.{ 0xaf }, 0, .none },
611 .{ .scas, .np, .m64, .none, .none, .none, &.{ 0xaf }, 0, .long },614 .{ .scas, .np, &.{ .m64 }, &.{ 0xaf }, 0, .long },
612 .{ .scasb, .np, .none, .none, .none, .none, &.{ 0xae }, 0, .none },615
613 .{ .scasw, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .short },616 .{ .scasb, .np, &.{}, &.{ 0xae }, 0, .none },
614 .{ .scasd, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .none },617 .{ .scasw, .np, &.{}, &.{ 0xaf }, 0, .short },
615 .{ .scasq, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .long },618 .{ .scasd, .np, &.{}, &.{ 0xaf }, 0, .none },
616619 .{ .scasq, .np, &.{}, &.{ 0xaf }, 0, .long },
617 .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },620
618 .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },621 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },
619 .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },622 .{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },
620 .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },623 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
621 .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },624 .{ .setae, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
622 .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },625 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
623 .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none },626 .{ .setb, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
624 .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex },627 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },
625 .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },628 .{ .setbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },
626 .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },629 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
627 .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },630 .{ .setc, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
628 .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },631 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },
629 .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none },632 .{ .sete, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },
630 .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex },633 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },
631 .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none },634 .{ .setg, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },
632 .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex },635 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },
633 .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none },636 .{ .setge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },
634 .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex },637 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },
635 .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none },638 .{ .setl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },
636 .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex },639 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },
637 .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none },640 .{ .setle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },
638 .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex },641 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .none },
639 .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },642 .{ .setna, .m, &.{ .rm8 }, &.{ 0x0f, 0x96 }, 0, .rex },
640 .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },643 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .none },
641 .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },644 .{ .setnae, .m, &.{ .rm8 }, &.{ 0x0f, 0x92 }, 0, .rex },
642 .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },645 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
643 .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },646 .{ .setnb, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
644 .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },647 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none },
645 .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },648 .{ .setnbe, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex },
646 .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },649 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .none },
647 .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none },650 .{ .setnc, .m, &.{ .rm8 }, &.{ 0x0f, 0x93 }, 0, .rex },
648 .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex },651 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },
649 .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none },652 .{ .setne, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },
650 .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex },653 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .none },
651 .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none },654 .{ .setng, .m, &.{ .rm8 }, &.{ 0x0f, 0x9e }, 0, .rex },
652 .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex },655 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .none },
653 .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none },656 .{ .setnge, .m, &.{ .rm8 }, &.{ 0x0f, 0x9c }, 0, .rex },
654 .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex },657 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .none },
655 .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none },658 .{ .setnl, .m, &.{ .rm8 }, &.{ 0x0f, 0x9d }, 0, .rex },
656 .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex },659 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .none },
657 .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .none },660 .{ .setnle, .m, &.{ .rm8 }, &.{ 0x0f, 0x9f }, 0, .rex },
658 .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .rex },661 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .none },
659 .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none },662 .{ .setno, .m, &.{ .rm8 }, &.{ 0x0f, 0x91 }, 0, .rex },
660 .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex },663 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },
661 .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .none },664 .{ .setnp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },
662 .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .rex },665 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .none },
663 .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none },666 .{ .setns, .m, &.{ .rm8 }, &.{ 0x0f, 0x99 }, 0, .rex },
664 .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex },667 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .none },
665 .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .none },668 .{ .setnz, .m, &.{ .rm8 }, &.{ 0x0f, 0x95 }, 0, .rex },
666 .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .rex },669 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .none },
667 .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none },670 .{ .seto, .m, &.{ .rm8 }, &.{ 0x0f, 0x90 }, 0, .rex },
668 .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex },671 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },
669 .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none },672 .{ .setp, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },
670 .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex },673 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .none },
671 .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none },674 .{ .setpe, .m, &.{ .rm8 }, &.{ 0x0f, 0x9a }, 0, .rex },
672 .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex },675 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .none },
673 .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .none },676 .{ .setpo, .m, &.{ .rm8 }, &.{ 0x0f, 0x9b }, 0, .rex },
674 .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .rex },677 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .none },
675 .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },678 .{ .sets, .m, &.{ .rm8 }, &.{ 0x0f, 0x98 }, 0, .rex },
676 .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },679 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none },
677680 .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex },
678 .{ .sfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },681
679682 .{ .sfence, .np, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },
680 .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },683
681 .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },684 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none },
682 .{ .shl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },685 .{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex },
683 .{ .shl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none },686 .{ .shl, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 4, .none },
684 .{ .shl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long },687 .{ .shl, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 4, .none },
685 .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none },688 .{ .shl, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 4, .long },
686 .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex },689 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .none },
687 .{ .shl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none },690 .{ .shl, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 4, .rex },
688 .{ .shl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none },691 .{ .shl, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 4, .none },
689 .{ .shl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long },692 .{ .shl, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 4, .none },
690 .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none },693 .{ .shl, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 4, .long },
691 .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex },694 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .none },
692 .{ .shl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },695 .{ .shl, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 4, .rex },
693 .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },696 .{ .shl, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 4, .none },
694 .{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },697 .{ .shl, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 4, .none },
695698 .{ .shl, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 4, .long },
696 .{ .shld, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },699
697 .{ .shld, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },700 .{ .shld, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },
698 .{ .shld, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },701 .{ .shld, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },
699 .{ .shld, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .long },702 .{ .shld, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .none },
700 .{ .shld, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },703 .{ .shld, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xa4 }, 0, .long },
701 .{ .shld, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .long },704 .{ .shld, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xa5 }, 0, .none },
702705 .{ .shld, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xa5 }, 0, .long },
703 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },706
704 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },707 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .none },
705 .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },708 .{ .shr, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 5, .rex },
706 .{ .shr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 5, .none },709 .{ .shr, .m1, &.{ .rm16, .unity }, &.{ 0xd1 }, 5, .none },
707 .{ .shr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 5, .long },710 .{ .shr, .m1, &.{ .rm32, .unity }, &.{ 0xd1 }, 5, .none },
708 .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .none },711 .{ .shr, .m1, &.{ .rm64, .unity }, &.{ 0xd1 }, 5, .long },
709 .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .rex },712 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .none },
710 .{ .shr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 5, .none },713 .{ .shr, .mc, &.{ .rm8, .cl }, &.{ 0xd2 }, 5, .rex },
711 .{ .shr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 5, .none },714 .{ .shr, .mc, &.{ .rm16, .cl }, &.{ 0xd3 }, 5, .none },
712 .{ .shr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 5, .long },715 .{ .shr, .mc, &.{ .rm32, .cl }, &.{ 0xd3 }, 5, .none },
713 .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .none },716 .{ .shr, .mc, &.{ .rm64, .cl }, &.{ 0xd3 }, 5, .long },
714 .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .rex },717 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .none },
715 .{ .shr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },718 .{ .shr, .mi, &.{ .rm8, .imm8 }, &.{ 0xc0 }, 5, .rex },
716 .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },719 .{ .shr, .mi, &.{ .rm16, .imm8 }, &.{ 0xc1 }, 5, .none },
717 .{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },720 .{ .shr, .mi, &.{ .rm32, .imm8 }, &.{ 0xc1 }, 5, .none },
718721 .{ .shr, .mi, &.{ .rm64, .imm8 }, &.{ 0xc1 }, 5, .long },
719 .{ .shrd, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },722
720 .{ .shrd, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },723 .{ .shrd, .mri, &.{ .rm16, .r16, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },
721 .{ .shrd, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },724 .{ .shrd, .mrc, &.{ .rm16, .r16, .cl }, &.{ 0x0f, 0xad }, 0, .none },
722 .{ .shrd, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xac }, 0, .long },725 .{ .shrd, .mri, &.{ .rm32, .r32, .imm8 }, &.{ 0x0f, 0xac }, 0, .none },
723 .{ .shrd, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },726 .{ .shrd, .mri, &.{ .rm64, .r64, .imm8 }, &.{ 0x0f, 0xac }, 0, .long },
724 .{ .shrd, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xad }, 0, .long },727 .{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none },
725728 .{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long },
726 .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },729
727 .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },730 .{ .stos, .np, &.{ .m8 }, &.{ 0xaa }, 0, .none },
728 .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },731 .{ .stos, .np, &.{ .m16 }, &.{ 0xab }, 0, .none },
729 .{ .stos, .np, .m64, .none, .none, .none, &.{ 0xab }, 0, .long },732 .{ .stos, .np, &.{ .m32 }, &.{ 0xab }, 0, .none },
730 .{ .stosb, .np, .none, .none, .none, .none, &.{ 0xaa }, 0, .none },733 .{ .stos, .np, &.{ .m64 }, &.{ 0xab }, 0, .long },
731 .{ .stosw, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .short },734
732 .{ .stosd, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .none },735 .{ .stosb, .np, &.{}, &.{ 0xaa }, 0, .none },
733 .{ .stosq, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .long },736 .{ .stosw, .np, &.{}, &.{ 0xab }, 0, .short },
734737 .{ .stosd, .np, &.{}, &.{ 0xab }, 0, .none },
735 .{ .sub, .zi, .al, .imm8, .none, .none, &.{ 0x2c }, 0, .none },738 .{ .stosq, .np, &.{}, &.{ 0xab }, 0, .long },
736 .{ .sub, .zi, .ax, .imm16, .none, .none, &.{ 0x2d }, 0, .none },739
737 .{ .sub, .zi, .eax, .imm32, .none, .none, &.{ 0x2d }, 0, .none },740 .{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none },
738 .{ .sub, .zi, .rax, .imm32s, .none, .none, &.{ 0x2d }, 0, .long },741 .{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .none },
739 .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .none },742 .{ .sub, .zi, &.{ .eax, .imm32 }, &.{ 0x2d }, 0, .none },
740 .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .rex },743 .{ .sub, .zi, &.{ .rax, .imm32s }, &.{ 0x2d }, 0, .long },
741 .{ .sub, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 5, .none },744 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .none },
742 .{ .sub, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 5, .none },745 .{ .sub, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 5, .rex },
743 .{ .sub, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 5, .long },746 .{ .sub, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 5, .none },
744 .{ .sub, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 5, .none },747 .{ .sub, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 5, .none },
745 .{ .sub, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 5, .none },748 .{ .sub, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 5, .long },
746 .{ .sub, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 5, .long },749 .{ .sub, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 5, .none },
747 .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .none },750 .{ .sub, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 5, .none },
748 .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .rex },751 .{ .sub, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 5, .long },
749 .{ .sub, .mr, .rm16, .r16, .none, .none, &.{ 0x29 }, 0, .none },752 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .none },
750 .{ .sub, .mr, .rm32, .r32, .none, .none, &.{ 0x29 }, 0, .none },753 .{ .sub, .mr, &.{ .rm8, .r8 }, &.{ 0x28 }, 0, .rex },
751 .{ .sub, .mr, .rm64, .r64, .none, .none, &.{ 0x29 }, 0, .long },754 .{ .sub, .mr, &.{ .rm16, .r16 }, &.{ 0x29 }, 0, .none },
752 .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .none },755 .{ .sub, .mr, &.{ .rm32, .r32 }, &.{ 0x29 }, 0, .none },
753 .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .rex },756 .{ .sub, .mr, &.{ .rm64, .r64 }, &.{ 0x29 }, 0, .long },
754 .{ .sub, .rm, .r16, .rm16, .none, .none, &.{ 0x2b }, 0, .none },757 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .none },
755 .{ .sub, .rm, .r32, .rm32, .none, .none, &.{ 0x2b }, 0, .none },758 .{ .sub, .rm, &.{ .r8, .rm8 }, &.{ 0x2a }, 0, .rex },
756 .{ .sub, .rm, .r64, .rm64, .none, .none, &.{ 0x2b }, 0, .long },759 .{ .sub, .rm, &.{ .r16, .rm16 }, &.{ 0x2b }, 0, .none },
757760 .{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none },
758 .{ .syscall, .np, .none, .none, .none, .none, &.{ 0x0f, 0x05 }, 0, .none }761 .{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long },
762
763 .{ .syscall, .np, &.{}, &.{ 0x0f, 0x05 }, 0, .none }
759,764,
760 .{ .@"test", .zi, .al, .imm8, .none, .none, &.{ 0xa8 }, 0, .none },765 .{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none },
761 .{ .@"test", .zi, .ax, .imm16, .none, .none, &.{ 0xa9 }, 0, .none },766 .{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .none },
762 .{ .@"test", .zi, .eax, .imm32, .none, .none, &.{ 0xa9 }, 0, .none },767 .{ .@"test", .zi, &.{ .eax, .imm32 }, &.{ 0xa9 }, 0, .none },
763 .{ .@"test", .zi, .rax, .imm32s, .none, .none, &.{ 0xa9 }, 0, .long },768 .{ .@"test", .zi, &.{ .rax, .imm32s }, &.{ 0xa9 }, 0, .long },
764 .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .none },769 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .none },
765 .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .rex },770 .{ .@"test", .mi, &.{ .rm8, .imm8 }, &.{ 0xf6 }, 0, .rex },
766 .{ .@"test", .mi, .rm16, .imm16, .none, .none, &.{ 0xf7 }, 0, .none },771 .{ .@"test", .mi, &.{ .rm16, .imm16 }, &.{ 0xf7 }, 0, .none },
767 .{ .@"test", .mi, .rm32, .imm32, .none, .none, &.{ 0xf7 }, 0, .none },772 .{ .@"test", .mi, &.{ .rm32, .imm32 }, &.{ 0xf7 }, 0, .none },
768 .{ .@"test", .mi, .rm64, .imm32s, .none, .none, &.{ 0xf7 }, 0, .long },773 .{ .@"test", .mi, &.{ .rm64, .imm32s }, &.{ 0xf7 }, 0, .long },
769 .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .none },774 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .none },
770 .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .rex },775 .{ .@"test", .mr, &.{ .rm8, .r8 }, &.{ 0x84 }, 0, .rex },
771 .{ .@"test", .mr, .rm16, .r16, .none, .none, &.{ 0x85 }, 0, .none },776 .{ .@"test", .mr, &.{ .rm16, .r16 }, &.{ 0x85 }, 0, .none },
772 .{ .@"test", .mr, .rm32, .r32, .none, .none, &.{ 0x85 }, 0, .none },777 .{ .@"test", .mr, &.{ .rm32, .r32 }, &.{ 0x85 }, 0, .none },
773 .{ .@"test", .mr, .rm64, .r64, .none, .none, &.{ 0x85 }, 0, .long },778 .{ .@"test", .mr, &.{ .rm64, .r64 }, &.{ 0x85 }, 0, .long },
774779
775 .{ .tzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },780 .{ .tzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
776 .{ .tzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },781 .{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
777 .{ .tzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },782 .{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },
778783
779 .{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none },784 .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none },
780785
781 .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .none },786 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none },
782 .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .rex },787 .{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex },
783 .{ .xadd, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },788 .{ .xadd, .mr, &.{ .rm16, .r16 }, &.{ 0x0f, 0xc1 }, 0, .none },
784 .{ .xadd, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },789 .{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none },
785 .{ .xadd, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xc1 }, 0, .long },790 .{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long },
786791
787 .{ .xchg, .o, .ax, .r16, .none, .none, &.{ 0x90 }, 0, .none },792 .{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .none },
788 .{ .xchg, .o, .r16, .ax, .none, .none, &.{ 0x90 }, 0, .none },793 .{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .none },
789 .{ .xchg, .o, .eax, .r32, .none, .none, &.{ 0x90 }, 0, .none },794 .{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none },
790 .{ .xchg, .o, .rax, .r64, .none, .none, &.{ 0x90 }, 0, .long },795 .{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long },
791 .{ .xchg, .o, .r32, .eax, .none, .none, &.{ 0x90 }, 0, .none },796 .{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none },
792 .{ .xchg, .o, .r64, .rax, .none, .none, &.{ 0x90 }, 0, .long },797 .{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long },
793 .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .none },798 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none },
794 .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .rex },799 .{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex },
795 .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .none },800 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none },
796 .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .rex },801 .{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .rex },
797 .{ .xchg, .mr, .rm16, .r16, .none, .none, &.{ 0x87 }, 0, .none },802 .{ .xchg, .mr, &.{ .rm16, .r16 }, &.{ 0x87 }, 0, .none },
798 .{ .xchg, .rm, .r16, .rm16, .none, .none, &.{ 0x87 }, 0, .none },803 .{ .xchg, .rm, &.{ .r16, .rm16 }, &.{ 0x87 }, 0, .none },
799 .{ .xchg, .mr, .rm32, .r32, .none, .none, &.{ 0x87 }, 0, .none },804 .{ .xchg, .mr, &.{ .rm32, .r32 }, &.{ 0x87 }, 0, .none },
800 .{ .xchg, .mr, .rm64, .r64, .none, .none, &.{ 0x87 }, 0, .long },805 .{ .xchg, .mr, &.{ .rm64, .r64 }, &.{ 0x87 }, 0, .long },
801 .{ .xchg, .rm, .r32, .rm32, .none, .none, &.{ 0x87 }, 0, .none },806 .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none },
802 .{ .xchg, .rm, .r64, .rm64, .none, .none, &.{ 0x87 }, 0, .long },807 .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long },
803808
804 .{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none },809 .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none },
805 .{ .xor, .zi, .ax, .imm16, .none, .none, &.{ 0x35 }, 0, .none },810 .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .none },
806 .{ .xor, .zi, .eax, .imm32, .none, .none, &.{ 0x35 }, 0, .none },811 .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none },
807 .{ .xor, .zi, .rax, .imm32s, .none, .none, &.{ 0x35 }, 0, .long },812 .{ .xor, .zi, &.{ .rax, .imm32s }, &.{ 0x35 }, 0, .long },
808 .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .none },813 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .none },
809 .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .rex },814 .{ .xor, .mi, &.{ .rm8, .imm8 }, &.{ 0x80 }, 6, .rex },
810 .{ .xor, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 6, .none },815 .{ .xor, .mi, &.{ .rm16, .imm16 }, &.{ 0x81 }, 6, .none },
811 .{ .xor, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 6, .none },816 .{ .xor, .mi, &.{ .rm32, .imm32 }, &.{ 0x81 }, 6, .none },
812 .{ .xor, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 6, .long },817 .{ .xor, .mi, &.{ .rm64, .imm32s }, &.{ 0x81 }, 6, .long },
813 .{ .xor, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 6, .none },818 .{ .xor, .mi, &.{ .rm16, .imm8s }, &.{ 0x83 }, 6, .none },
814 .{ .xor, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 6, .none },819 .{ .xor, .mi, &.{ .rm32, .imm8s }, &.{ 0x83 }, 6, .none },
815 .{ .xor, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 6, .long },820 .{ .xor, .mi, &.{ .rm64, .imm8s }, &.{ 0x83 }, 6, .long },
816 .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .none },821 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .none },
817 .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .rex },822 .{ .xor, .mr, &.{ .rm8, .r8 }, &.{ 0x30 }, 0, .rex },
818 .{ .xor, .mr, .rm16, .r16, .none, .none, &.{ 0x31 }, 0, .none },823 .{ .xor, .mr, &.{ .rm16, .r16 }, &.{ 0x31 }, 0, .none },
819 .{ .xor, .mr, .rm32, .r32, .none, .none, &.{ 0x31 }, 0, .none },824 .{ .xor, .mr, &.{ .rm32, .r32 }, &.{ 0x31 }, 0, .none },
820 .{ .xor, .mr, .rm64, .r64, .none, .none, &.{ 0x31 }, 0, .long },825 .{ .xor, .mr, &.{ .rm64, .r64 }, &.{ 0x31 }, 0, .long },
821 .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .none },826 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .none },
822 .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .rex },827 .{ .xor, .rm, &.{ .r8, .rm8 }, &.{ 0x32 }, 0, .rex },
823 .{ .xor, .rm, .r16, .rm16, .none, .none, &.{ 0x33 }, 0, .none },828 .{ .xor, .rm, &.{ .r16, .rm16 }, &.{ 0x33 }, 0, .none },
824 .{ .xor, .rm, .r32, .rm32, .none, .none, &.{ 0x33 }, 0, .none },829 .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none },
825 .{ .xor, .rm, .r64, .rm64, .none, .none, &.{ 0x33 }, 0, .long },830 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long },
826831
827 // SSE832 // 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 },843 .{ .movss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse },
839 .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, &.{ 0xf3, 0x0f, 0x11 }, 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
847 // SSE2852 // 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 },863 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
859 .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0x66, 0x0f, 0xd6 }, 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 },870 .{ .movsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 },
866 .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0xf2, 0x0f, 0x11 }, 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
870 // SSE4.1875 // SSE4.1
871 .{ .roundss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },876 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
872 .{ .roundsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },877 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },
873};878};
874// zig fmt: on879// zig fmt: on
src/print_air.zig+48-33
...@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;...@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;
8const Air = @import("Air.zig");8const Air = @import("Air.zig");
9const Liveness = @import("Liveness.zig");9const 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 {
12 const instruction_bytes = air.instructions.len *12 const instruction_bytes = air.instructions.len *
13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
14 // the debug safety tag but we want to measure release size.14 // 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 {...@@ -23,7 +23,7 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
23 liveness_special_bytes + tomb_bytes;23 liveness_special_bytes + tomb_bytes;
2424
25 // zig fmt: off25 // zig fmt: off
26 std.debug.print(26 stream.print(
27 \\# Total AIR+Liveness bytes: {}27 \\# Total AIR+Liveness bytes: {}
28 \\# AIR Instructions: {d} ({})28 \\# AIR Instructions: {d} ({})
29 \\# AIR Extra Data: {d} ({})29 \\# AIR Extra Data: {d} ({})
...@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {...@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
40 fmtIntSizeBin(tomb_bytes),40 fmtIntSizeBin(tomb_bytes),
41 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),41 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
42 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),42 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
43 });43 }) catch return;
44 // zig fmt: on44 // zig fmt: on
45 var arena = std.heap.ArenaAllocator.init(module.gpa);
46 defer arena.deinit();
4745
48 var writer: Writer = .{46 var writer: Writer = .{
49 .module = module,47 .module = module,
50 .gpa = module.gpa,48 .gpa = module.gpa,
51 .arena = arena.allocator(),
52 .air = air,49 .air = air,
53 .liveness = liveness,50 .liveness = liveness,
54 .indent = 2,51 .indent = 2,
52 .skip_body = false,
55 };53 };
56 const stream = std.io.getStdErr().writer();
57 writer.writeAllConstants(stream) catch return;54 writer.writeAllConstants(stream) catch return;
58 stream.writeByte('\n') catch return;55 stream.writeByte('\n') catch return;
59 writer.writeBody(stream, air.getMainBody()) catch return;56 writer.writeBody(stream, air.getMainBody()) catch return;
60}57}
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
62const Writer = struct {85const Writer = struct {
63 module: *Module,86 module: *Module,
64 gpa: Allocator,87 gpa: Allocator,
65 arena: Allocator,
66 air: Air,88 air: Air,
67 liveness: Liveness,89 liveness: Liveness,
68 indent: usize,90 indent: usize,
91 skip_body: bool,
6992
70 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {93 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
71 for (w.air.instructions.items(.tag), 0..) |tag, i| {94 for (w.air.instructions.items(.tag), 0..) |tag, i| {
72 const inst = @intCast(u32, i);95 const inst = @intCast(Air.Inst.Index, i);
73 switch (tag) {96 switch (tag) {
74 .constant, .const_ty => {97 .constant, .const_ty => try w.writeInst(s, inst),
75 try s.writeByteNTimes(' ', w.indent);
76 try s.print("%{d} ", .{inst});
77 try w.writeInst(s, inst);
78 try s.writeAll(")\n");
79 },
80 else => continue,98 else => continue,
81 }99 }
82 }100 }
83 }101 }
84102
85 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {103 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
86 for (body) |inst| {104 for (body) |inst| try w.writeInst(s, 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 }
96 }105 }
97106
98 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {107 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
99 const tags = w.air.instructions.items(.tag);108 const tag = w.air.instructions.items(.tag)[inst];
100 const tag = tags[inst];109 try s.writeByteNTimes(' ', w.indent);
101 try s.print("= {s}(", .{@tagName(tags[inst])});110 try s.print("%{d}{c}= {s}(", .{
111 inst,
112 @as(u8, if (w.liveness.isUnused(inst)) '!' else ' '),
113 @tagName(tag),
114 });
102 switch (tag) {115 switch (tag) {
103 .add,116 .add,
104 .addwrap,117 .addwrap,
...@@ -316,6 +329,7 @@ const Writer = struct {...@@ -316,6 +329,7 @@ const Writer = struct {
316329
317 .dbg_block_begin, .dbg_block_end => {},330 .dbg_block_begin, .dbg_block_end => {},
318 }331 }
332 try s.writeAll(")\n");
319 }333 }
320334
321 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {335 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -372,6 +386,7 @@ const Writer = struct {...@@ -372,6 +386,7 @@ const Writer = struct {
372 const body = w.air.extra[extra.end..][0..extra.data.body_len];386 const body = w.air.extra[extra.end..][0..extra.data.body_len];
373387
374 try w.writeType(s, w.air.getRefType(ty_pl.ty));388 try w.writeType(s, w.air.getRefType(ty_pl.ty));
389 if (w.skip_body) return s.writeAll(", ...");
375 try s.writeAll(", {\n");390 try s.writeAll(", {\n");
376 const old_indent = w.indent;391 const old_indent = w.indent;
377 w.indent += 2;392 w.indent += 2;
...@@ -703,6 +718,7 @@ const Writer = struct {...@@ -703,6 +718,7 @@ const Writer = struct {
703 const body = w.air.extra[extra.end..][0..extra.data.body_len];718 const body = w.air.extra[extra.end..][0..extra.data.body_len];
704719
705 try w.writeOperand(s, inst, 0, pl_op.operand);720 try w.writeOperand(s, inst, 0, pl_op.operand);
721 if (w.skip_body) return s.writeAll(", ...");
706 try s.writeAll(", {\n");722 try s.writeAll(", {\n");
707 const old_indent = w.indent;723 const old_indent = w.indent;
708 w.indent += 2;724 w.indent += 2;
...@@ -721,6 +737,7 @@ const Writer = struct {...@@ -721,6 +737,7 @@ const Writer = struct {
721737
722 try s.writeAll(", ");738 try s.writeAll(", ");
723 try w.writeType(s, w.air.getRefType(ty_pl.ty));739 try w.writeType(s, w.air.getRefType(ty_pl.ty));
740 if (w.skip_body) return s.writeAll(", ...");
724 try s.writeAll(", {\n");741 try s.writeAll(", {\n");
725 const old_indent = w.indent;742 const old_indent = w.indent;
726 w.indent += 2;743 w.indent += 2;
...@@ -738,6 +755,7 @@ const Writer = struct {...@@ -738,6 +755,7 @@ const Writer = struct {
738 const liveness_condbr = w.liveness.getCondBr(inst);755 const liveness_condbr = w.liveness.getCondBr(inst);
739756
740 try w.writeOperand(s, inst, 0, pl_op.operand);757 try w.writeOperand(s, inst, 0, pl_op.operand);
758 if (w.skip_body) return s.writeAll(", ...");
741 try s.writeAll(", {\n");759 try s.writeAll(", {\n");
742 const old_indent = w.indent;760 const old_indent = w.indent;
743 w.indent += 2;761 w.indent += 2;
...@@ -900,10 +918,7 @@ const Writer = struct {...@@ -900,10 +918,7 @@ const Writer = struct {
900 dies: bool,918 dies: bool,
901 ) @TypeOf(s).Error!void {919 ) @TypeOf(s).Error!void {
902 _ = w;920 _ = w;
903 if (dies) {921 try s.print("%{d}", .{inst});
904 try s.print("%{d}!", .{inst});922 if (dies) try s.writeByte('!');
905 } else {
906 try s.print("%{d}", .{inst});
907 }
908 }923 }
909};924};
test/behavior/bugs/9584.zig+1
...@@ -47,6 +47,7 @@ test {...@@ -47,6 +47,7 @@ test {
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5051
51 var flags = A{52 var flags = A{
52 .a = false,53 .a = false,