| author | |
| committer | |
| log | 28d6dd75ac151449ddc29f3937a9e333f0a608c1 |
| tree | 518b954519c6b26aab9aea84f10fa49bfec82fac |
| parent | 1de64dba236d9496ae5f31b59b7a4947ff4d90be |
| parent | fd13e44e0c69465cf9ea9ef4fd17dfebf5cffd45 |
| signature |
x86_64: misc fixes11 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 | } |
| 51 | 51 | ||
| 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 { |
| 156 | 170 | ||
| 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 | } |
| 164 | 175 | ||
| 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 | } |
| 174 | 180 | ||
| 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; |
| 20 | const Result = codegen.Result; | 20 | const Result = codegen.Result; |
| 21 | const Emit = @import("Emit.zig"); | 21 | const Emit = @import("Emit.zig"); |
| 22 | const Liveness = @import("../../Liveness.zig"); | 22 | const Liveness = @import("../../Liveness.zig"); |
| 23 | const Lower = @import("Lower.zig"); | ||
| 23 | const Mir = @import("Mir.zig"); | 24 | const Mir = @import("Mir.zig"); |
| 24 | const Module = @import("../../Module.zig"); | 25 | const Module = @import("../../Module.zig"); |
| 25 | const Target = std.Target; | 26 | const Target = std.Target; |
| ... | @@ -44,6 +45,8 @@ const sse = abi.RegisterClass.sse; | ... | @@ -44,6 +45,8 @@ const sse = abi.RegisterClass.sse; |
| 44 | 45 | ||
| 45 | const InnerError = CodeGenError || error{OutOfRegisters}; | 46 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 46 | 47 | ||
| 48 | const debug_wip_mir = false; | ||
| 49 | |||
| 47 | gpa: Allocator, | 50 | gpa: Allocator, |
| 48 | air: Air, | 51 | air: Air, |
| 49 | liveness: Liveness, | 52 | liveness: 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; |
| 269 | 272 | ||
| 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); |
| 342 | 351 | ||
| 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 | } |
| 380 | 392 | ||
| 393 | fn 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 | |||
| 381 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | 430 | fn 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 | } |
| 388 | 438 | ||
| ... | @@ -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 | ); | ||
| 847 | 903 | ||
| 848 | switch (air_tags[inst]) { | 904 | switch (air_tags[inst]) { |
| 849 | // zig fmt: off | 905 | // 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 { |
| 1479 | 1535 | ||
| 1480 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 1536 | fn 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); |
| 1484 | 1540 | 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.*); | ||
| 1491 | 1544 | ||
| 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); | ||
| 1495 | 1551 | ||
| 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); | ||
| 1501 | 1556 | ||
| 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 | }; |
| 1511 | 1562 | 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 | } |
| 1520 | 1564 | ||
| 1521 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 1565 | fn 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 { |
| 2509 | 2553 | ||
| 2510 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 2554 | fn 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); |
| 3042 | 3083 | ||
| 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_mcv | 3086 | src_mcv |
| 3045 | else | 3087 | 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); | ||
| 3437 | 3482 | ||
| 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; | ||
| 3442 | 3486 | ||
| 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 | } | ||
| 4393 | 4427 | ||
| 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 | } |
| 4404 | 4438 | ||
| 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( |
| 4416 | 4450 | ||
| 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 | }; | ||
| 4419 | 4467 | ||
| 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( |
| 4485 | 4533 | ||
| 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 | }, |
| 4516 | 4568 | ||
| 4517 | .ptr_add, | 4569 | .ptr_add, |
| ... | @@ -4568,7 +4620,13 @@ fn genBinOp( | ... | @@ -4568,7 +4620,13 @@ fn genBinOp( |
| 4568 | }; | 4620 | }; |
| 4569 | 4621 | ||
| 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 | ); | ||
| 4621 | 4665 | ||
| 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 | } |
| 4651 | 4695 | ||
| 4652 | fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | 4696 | fn 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); |
| 4669 | 4713 | ||
| 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 | } |
| 4678 | 4722 | ||
| ... | @@ -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); |
| 4721 | 4765 | ||
| 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 | ); | ||
| 4744 | 4803 | ||
| 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 | else | 4822 | }; |
| 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 | } |
| 5345 | 5466 | ||
| 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 unsigned | 5472 | // 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; |
| 6663 | 6783 | ||
| 6664 | switch (ty.zigTypeTag()) { | 6784 | switch (ty.zigTypeTag()) { |
| ... | @@ -6893,13 +7013,11 @@ fn genInlineMemset( | ... | @@ -6893,13 +7013,11 @@ fn genInlineMemset( |
| 6893 | 7013 | ||
| 6894 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 7014 | fn 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 |
| 7151 | 7259 | ||
| 7152 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | 7260 | fn 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 | } |
| 7157 | 7273 |
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 into | 1 | //! This file contains the functionality for emitting x86_64 MIR as machine code |
| 2 | //! machine code | ||
| 3 | 2 | ||
| 4 | const Emit = @This(); | 3 | lower: Lower, |
| 5 | |||
| 6 | const std = @import("std"); | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const bits = @import("bits.zig"); | ||
| 9 | const abi = @import("abi.zig"); | ||
| 10 | const encoder = @import("encoder.zig"); | ||
| 11 | const link = @import("../../link.zig"); | ||
| 12 | const log = std.log.scoped(.codegen); | ||
| 13 | const math = std.math; | ||
| 14 | const mem = std.mem; | ||
| 15 | const testing = std.testing; | ||
| 16 | |||
| 17 | const Air = @import("../../Air.zig"); | ||
| 18 | const Allocator = mem.Allocator; | ||
| 19 | const CodeGen = @import("CodeGen.zig"); | ||
| 20 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | ||
| 21 | const Encoder = bits.Encoder; | ||
| 22 | const ErrorMsg = Module.ErrorMsg; | ||
| 23 | const Immediate = bits.Immediate; | ||
| 24 | const Instruction = encoder.Instruction; | ||
| 25 | const MCValue = @import("CodeGen.zig").MCValue; | ||
| 26 | const Memory = bits.Memory; | ||
| 27 | const Mir = @import("Mir.zig"); | ||
| 28 | const Module = @import("../../Module.zig"); | ||
| 29 | const Register = bits.Register; | ||
| 30 | const Type = @import("../../type.zig").Type; | ||
| 31 | |||
| 32 | mir: Mir, | ||
| 33 | bin_file: *link.File, | 4 | bin_file: *link.File, |
| 34 | debug_output: DebugInfoOutput, | 5 | debug_output: DebugInfoOutput, |
| 35 | target: *const std.Target, | ||
| 36 | err_msg: ?*ErrorMsg = null, | ||
| 37 | src_loc: Module.SrcLoc, | ||
| 38 | code: *std.ArrayList(u8), | 6 | code: *std.ArrayList(u8), |
| 39 | 7 | ||
| 40 | prev_di_line: u32, | 8 | prev_di_line: u32, |
| ... | @@ -45,166 +13,176 @@ prev_di_pc: usize, | ... | @@ -45,166 +13,176 @@ prev_di_pc: usize, |
| 45 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{}, | 13 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{}, |
| 46 | relocs: std.ArrayListUnmanaged(Reloc) = .{}, | 14 | relocs: std.ArrayListUnmanaged(Reloc) = .{}, |
| 47 | 15 | ||
| 48 | const InnerError = error{ | 16 | pub const Error = Lower.Error || error{EmitFail}; |
| 49 | OutOfMemory, | 17 | |
| 50 | EmitFail, | 18 | pub 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); |
| 54 | 22 | ||
| 55 | const 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, |
| 65 | 33 | .target = inst.data.inst, | |
| 66 | pub fn lowerMir(emit: *Emit) InnerError!void { | 34 | .offset = end_offset - 4, |
| 67 | const mir_tags = emit.mir.instructions.items(.tag); | 35 | .length = 5, |
| 68 | 36 | }), | |
| 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) { |
| 135 | 103 | .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), | ||
| 179 | 122 | ||
| 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 | }, | ||
| 183 | 128 | ||
| 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 | }, | ||
| 186 | 142 | ||
| 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 | } |
| 193 | 160 | ||
| 194 | pub fn deinit(emit: *Emit) void { | 161 | pub 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 | } |
| 199 | 166 | ||
| 200 | fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { | 167 | fn 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 | } |
| 206 | 173 | ||
| 207 | fn fixupRelocs(emit: *Emit) InnerError!void { | 174 | const 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 | |||
| 185 | fn 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 smallest | 187 | // 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 resolution | 188 | // 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 | } |
| 219 | 197 | ||
| 220 | fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: Instruction.Init) InnerError!void { | 198 | fn 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 | |||
| 225 | fn 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 | |||
| 389 | fn 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 | |||
| 411 | fn 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 | |||
| 444 | fn 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 | |||
| 472 | fn 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 | |||
| 507 | fn 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 | |||
| 513 | fn 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 | |||
| 546 | fn 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 | |||
| 576 | fn 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 | |||
| 597 | fn 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 | |||
| 611 | fn 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 | |||
| 650 | fn 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 | |||
| 680 | fn 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 | |||
| 738 | fn 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 | |||
| 745 | fn 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 changes | 210 | 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 compatable | 211 | // 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; |
| 760 | 213 | ||
| 761 | // increasing the line number | 214 | // 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 | } |
| 794 | 247 | ||
| 795 | fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 248 | const link = @import("../../link.zig"); |
| 796 | _ = inst; | 249 | const log = std.log.scoped(.emit); |
| 797 | switch (emit.debug_output) { | 250 | const mem = std.mem; |
| 798 | .dwarf => |dw| { | 251 | const 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 | } | ||
| 810 | 252 | ||
| 811 | fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 253 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 812 | _ = inst; | 254 | const Emit = @This(); |
| 813 | switch (emit.debug_output) { | 255 | const Lower = @import("Lower.zig"); |
| 814 | .dwarf => |dw| { | 256 | const 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; |
| 7 | const bits = @import("bits.zig"); | 7 | const bits = @import("bits.zig"); |
| 8 | const encoder = @import("encoder.zig"); | 8 | const encoder = @import("encoder.zig"); |
| 9 | const Instruction = encoder.Instruction; | 9 | const Instruction = encoder.Instruction; |
| 10 | const Operand = Instruction.Operand; | ||
| 11 | const Prefix = Instruction.Prefix; | ||
| 10 | const Register = bits.Register; | 12 | const Register = bits.Register; |
| 11 | const Rex = encoder.Rex; | 13 | const Rex = encoder.Rex; |
| 12 | const LegacyPrefixes = encoder.LegacyPrefixes; | 14 | const LegacyPrefixes = encoder.LegacyPrefixes; |
| 13 | 15 | ||
| 14 | const table = @import("encodings.zig").table; | ||
| 15 | |||
| 16 | mnemonic: Mnemonic, | 16 | mnemonic: Mnemonic, |
| 17 | op_en: OpEn, | 17 | data: Data, |
| 18 | op1: Op, | 18 | |
| 19 | op2: Op, | 19 | const Data = struct { |
| 20 | op3: Op, | 20 | op_en: OpEn, |
| 21 | op4: Op, | 21 | ops: [4]Op, |
| 22 | opc_len: u3, | 22 | opc_len: u3, |
| 23 | opc: [7]u8, | 23 | opc: [7]u8, |
| 24 | modrm_ext: u3, | 24 | modrm_ext: u3, |
| 25 | mode: Mode, | 25 | mode: Mode, |
| 26 | 26 | }; | |
| 27 | pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding { | 27 | |
| 28 | const input_op1 = Op.fromOperand(args.op1); | 28 | pub 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, |
| 32 | 32 | ) !?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 { |
| 60 | 62 | ||
| 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; |
| 62 | 64 | ||
| 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 | } |
| 102 | 87 | 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 | } |
| 146 | 89 | ||
| 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 | } |
| 196 | 127 | ||
| 197 | pub fn opcode(encoding: *const Encoding) []const u8 { | 128 | pub 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 | } |
| 200 | 131 | ||
| 201 | pub fn mandatoryPrefix(encoding: *const Encoding) ?u8 { | 132 | pub 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 | } |
| 208 | 139 | ||
| 209 | pub fn modRmExt(encoding: Encoding) u3 { | 140 | pub 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 | } |
| 215 | 146 | ||
| 216 | pub fn operandBitSize(encoding: Encoding) u64 { | 147 | pub 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 | } |
| 251 | 182 | ||
| 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 | } |
| 267 | 198 | ||
| 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( |
| 290 | 221 | ||
| 291 | try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); | 222 | try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); |
| 292 | 223 | ||
| 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 | }; |
| 298 | 228 | ||
| 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 | |||
| 538 | fn 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 | |||
| 551 | const 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 | |||
| 3 | allocator: Allocator, | ||
| 4 | mir: Mir, | ||
| 5 | target: *const std.Target, | ||
| 6 | err_msg: ?*ErrorMsg = null, | ||
| 7 | src_loc: Module.SrcLoc, | ||
| 8 | result: [ | ||
| 9 | std.mem.max(usize, &.{ | ||
| 10 | abi.Win64.callee_preserved_regs.len, | ||
| 11 | abi.SysV.callee_preserved_regs.len, | ||
| 12 | }) | ||
| 13 | ]Instruction = undefined, | ||
| 14 | result_len: usize = undefined, | ||
| 15 | |||
| 16 | pub 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. | ||
| 24 | pub 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 | |||
| 150 | pub 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 | |||
| 157 | fn 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 | |||
| 163 | fn 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 | |||
| 191 | fn 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 | |||
| 232 | fn 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 | |||
| 237 | fn 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 | |||
| 322 | fn 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 | |||
| 336 | fn 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 | |||
| 354 | fn 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 | |||
| 372 | fn 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 | |||
| 393 | fn 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 | |||
| 407 | fn 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 | |||
| 419 | fn 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 | |||
| 438 | fn 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 | |||
| 447 | const abi = @import("abi.zig"); | ||
| 448 | const assert = std.debug.assert; | ||
| 449 | const bits = @import("bits.zig"); | ||
| 450 | const encoder = @import("encoder.zig"); | ||
| 451 | const std = @import("std"); | ||
| 452 | |||
| 453 | const Air = @import("../../Air.zig"); | ||
| 454 | const Allocator = std.mem.Allocator; | ||
| 455 | const ErrorMsg = Module.ErrorMsg; | ||
| 456 | const Immediate = bits.Immediate; | ||
| 457 | const Instruction = encoder.Instruction; | ||
| 458 | const Lower = @This(); | ||
| 459 | const Memory = bits.Memory; | ||
| 460 | const Mir = @import("Mir.zig"); | ||
| 461 | const Mnemonic = Instruction.Mnemonic; | ||
| 462 | const Module = @import("../../Module.zig"); | ||
| 463 | const Operand = Instruction.Operand; | ||
| 464 | const Prefix = Instruction.Prefix; | ||
| 465 | const 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, |
| 657 | 657 | ||
| 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 | } |
| 662 | 665 | ||
| 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 | }; |
| 670 | 673 |
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; |
| 11 | const Register = bits.Register; | 11 | const Register = bits.Register; |
| 12 | 12 | ||
| 13 | pub const Instruction = struct { | 13 | pub 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, | ||
| 20 | 17 | ||
| 21 | pub const Mnemonic = Encoding.Mnemonic; | 18 | pub const Mnemonic = Encoding.Mnemonic; |
| 22 | 19 | ||
| ... | @@ -57,18 +54,17 @@ pub const Instruction = struct { | ... | @@ -57,18 +54,17 @@ pub const Instruction = struct { |
| 57 | }; | 54 | }; |
| 58 | } | 55 | } |
| 59 | 56 | ||
| 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 { |
| 80 | 76 | ||
| 81 | try writer.writeByte('['); | 77 | try writer.writeByte('['); |
| 82 | 78 | ||
| 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 | } |
| 100 | 97 | ||
| 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 | }; |
| 109 | 109 | ||
| 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 | } |
| 140 | 132 | ||
| 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 | } |
| 159 | 143 | ||
| 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; | ||
| 163 | 148 | ||
| 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); |
| 168 | 153 | ||
| 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 | } |
| 202 | 187 | ||
| 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 | } |
| 222 | 207 | ||
| 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; | ||
| 226 | 212 | ||
| 227 | var legacy = LegacyPrefixes{}; | 213 | var legacy = LegacyPrefixes{}; |
| 228 | 214 | ||
| ... | @@ -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 | } |
| 235 | 221 | ||
| 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 { |
| 242 | 228 | ||
| 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 | } |
| 268 | 254 | ||
| 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; |
| 271 | 257 | ||
| 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; |
| 275 | 261 | ||
| 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 | } |
| 288 | 274 | ||
| 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 | }; |
| 409 | 395 | ||
| 410 | inline fn sign(i: anytype) @TypeOf(i) { | ||
| 411 | return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0); | ||
| 412 | } | ||
| 413 | |||
| 414 | pub const LegacyPrefixes = packed struct { | 396 | pub const LegacyPrefixes = packed struct { |
| 415 | /// LOCK | 397 | /// 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, |
| 829 | 811 | ||
| 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(); |
| 852 | 832 | ||
| 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" { |
| 861 | test "lower I encoding" { | 841 | test "lower I encoding" { |
| 862 | var enc = TestEncode{}; | 842 | var enc = TestEncode{}; |
| 863 | 843 | ||
| 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"); |
| 866 | 848 | ||
| 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"); |
| 869 | 853 | ||
| 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"); |
| 872 | 858 | ||
| 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"); |
| 875 | 864 | ||
| 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"); |
| 878 | 870 | ||
| 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"); |
| 881 | 876 | ||
| 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"); |
| 884 | 882 | ||
| 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 | } |
| 888 | 889 | ||
| 889 | test "lower MI encoding" { | 890 | test "lower MI encoding" { |
| 890 | var enc = TestEncode{}; | 891 | var enc = TestEncode{}; |
| 891 | 892 | ||
| 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"); |
| 894 | 898 | ||
| 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"); |
| 900 | 904 | ||
| 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"); |
| 903 | 910 | ||
| 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"); |
| 906 | 916 | ||
| 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"); |
| 909 | 922 | ||
| 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"); |
| 915 | 928 | ||
| 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 | ); |
| 925 | 938 | ||
| 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"); |
| 931 | 944 | ||
| 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"); |
| 937 | 950 | ||
| 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"); |
| 943 | 956 | ||
| 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 | ); |
| 957 | 970 | ||
| 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"); |
| 963 | 976 | ||
| 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"); |
| 966 | 982 | ||
| 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"); |
| 969 | 988 | ||
| 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"); |
| 975 | 994 | ||
| 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"); |
| 978 | 1000 | ||
| 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"); |
| 984 | 1006 | ||
| 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 | ); |
| 994 | 1016 | ||
| 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 | ); |
| 1004 | 1026 | ||
| 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 | ); |
| 1014 | 1036 | ||
| 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" { |
| 1026 | test "lower RM encoding" { | 1048 | test "lower RM encoding" { |
| 1027 | var enc = TestEncode{}; | 1049 | var enc = TestEncode{}; |
| 1028 | 1050 | ||
| 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]"); |
| 1034 | 1056 | ||
| 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"); |
| 1040 | 1062 | ||
| 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]"); |
| 1046 | 1068 | ||
| 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]"); |
| 1056 | 1078 | ||
| 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]"); |
| 1066 | 1088 | ||
| 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]"); |
| 1076 | 1098 | ||
| 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]"); |
| 1086 | 1108 | ||
| 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"); |
| 1090 | 1115 | ||
| 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"); |
| 1096 | 1121 | ||
| 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"); |
| 1099 | 1127 | ||
| 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"); |
| 1105 | 1133 | ||
| 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"); |
| 1108 | 1139 | ||
| 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"); |
| 1111 | 1145 | ||
| 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"); |
| 1114 | 1151 | ||
| 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]"); |
| 1120 | 1157 | ||
| 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]"); |
| 1126 | 1163 | ||
| 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]"); |
| 1129 | 1169 | ||
| 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"); |
| 1132 | 1175 | ||
| 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"); |
| 1135 | 1181 | ||
| 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]"); |
| 1138 | 1187 | ||
| 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]"); |
| 1141 | 1193 | ||
| 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]"); |
| 1144 | 1199 | ||
| 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]"); |
| 1147 | 1205 | ||
| 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]"); |
| 1150 | 1211 | ||
| 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]"); |
| 1159 | 1220 | ||
| 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"); |
| 1165 | 1226 | ||
| 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"); |
| 1171 | 1232 | ||
| 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"); |
| 1177 | 1238 | ||
| 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]"); |
| 1183 | 1244 | ||
| 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]"); |
| 1189 | 1250 | ||
| 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 | } |
| 1193 | 1257 | ||
| 1194 | test "lower RMI encoding" { | 1258 | test "lower RMI encoding" { |
| 1195 | var enc = TestEncode{}; | 1259 | var enc = TestEncode{}; |
| 1196 | 1260 | ||
| 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"); |
| 1203 | 1267 | ||
| 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 | ); |
| 1214 | 1278 | ||
| 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 | ); |
| 1228 | 1289 | ||
| 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" { |
| 1244 | test "lower MR encoding" { | 1302 | test "lower MR encoding" { |
| 1245 | var enc = TestEncode{}; | 1303 | var enc = TestEncode{}; |
| 1246 | 1304 | ||
| 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"); |
| 1249 | 1310 | ||
| 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"); |
| 1255 | 1316 | ||
| 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"); |
| 1258 | 1322 | ||
| 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"); |
| 1268 | 1332 | ||
| 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"); |
| 1271 | 1338 | ||
| 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"); |
| 1281 | 1348 | ||
| 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"); |
| 1287 | 1354 | ||
| 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"); |
| 1293 | 1360 | ||
| 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"); |
| 1299 | 1366 | ||
| 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 | } |
| 1306 | 1373 | ||
| 1307 | test "lower M encoding" { | 1374 | test "lower M encoding" { |
| 1308 | var enc = TestEncode{}; | 1375 | var enc = TestEncode{}; |
| 1309 | 1376 | ||
| 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"); |
| 1312 | 1381 | ||
| 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]"); |
| 1315 | 1386 | ||
| 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]"); |
| 1323 | 1394 | ||
| 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]"); |
| 1331 | 1402 | ||
| 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"); |
| 1334 | 1407 | ||
| 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"); |
| 1337 | 1412 | ||
| 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]"); |
| 1340 | 1417 | ||
| 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]"); |
| 1343 | 1422 | ||
| 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]"); |
| 1346 | 1427 | ||
| 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]"); |
| 1349 | 1432 | ||
| 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"); |
| 1352 | 1437 | ||
| 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 | } |
| 1356 | 1443 | ||
| 1357 | test "lower O encoding" { | 1444 | test "lower O encoding" { |
| 1358 | var enc = TestEncode{}; | 1445 | var enc = TestEncode{}; |
| 1359 | 1446 | ||
| 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"); |
| 1362 | 1451 | ||
| 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"); |
| 1365 | 1456 | ||
| 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 | } |
| 1369 | 1462 | ||
| 1370 | test "lower OI encoding" { | 1463 | test "lower OI encoding" { |
| 1371 | var enc = TestEncode{}; | 1464 | var enc = TestEncode{}; |
| 1372 | 1465 | ||
| 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 | ); |
| 1379 | 1475 | ||
| 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 | ); |
| 1386 | 1485 | ||
| 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"); |
| 1389 | 1491 | ||
| 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"); |
| 1392 | 1497 | ||
| 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 | } |
| 1396 | 1504 | ||
| 1397 | test "lower FD/TD encoding" { | 1505 | test "lower FD/TD encoding" { |
| 1398 | var enc = TestEncode{}; | 1506 | var enc = TestEncode{}; |
| 1399 | 1507 | ||
| 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"); |
| 1402 | 1513 | ||
| 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"); |
| 1405 | 1519 | ||
| 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"); |
| 1408 | 1525 | ||
| 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"); |
| 1411 | 1531 | ||
| 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"); |
| 1414 | 1537 | ||
| 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"); |
| 1417 | 1543 | ||
| 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"); |
| 1420 | 1549 | ||
| 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 | } |
| 1424 | 1556 | ||
| 1425 | test "lower NP encoding" { | 1557 | test "lower NP encoding" { |
| 1426 | var enc = TestEncode{}; | 1558 | var enc = TestEncode{}; |
| 1427 | 1559 | ||
| 1428 | try enc.encode(.int3, .{}); | 1560 | try enc.encode(.int3, &.{}); |
| 1429 | try expectEqualHexStrings("\xCC", enc.code(), "int3"); | 1561 | try expectEqualHexStrings("\xCC", enc.code(), "int3"); |
| 1430 | 1562 | ||
| 1431 | try enc.encode(.nop, .{}); | 1563 | try enc.encode(.nop, &.{}); |
| 1432 | try expectEqualHexStrings("\x90", enc.code(), "nop"); | 1564 | try expectEqualHexStrings("\x90", enc.code(), "nop"); |
| 1433 | 1565 | ||
| 1434 | try enc.encode(.ret, .{}); | 1566 | try enc.encode(.ret, &.{}); |
| 1435 | try expectEqualHexStrings("\xC3", enc.code(), "ret"); | 1567 | try expectEqualHexStrings("\xC3", enc.code(), "ret"); |
| 1436 | 1568 | ||
| 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 | } |
| 1440 | 1572 | ||
| 1441 | fn invalidInstruction(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { | 1573 | fn 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 | } |
| 1445 | 1577 | ||
| 1446 | test "invalid instruction" { | 1578 | test "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 | } |
| 1462 | 1625 | ||
| 1463 | fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { | 1626 | fn 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 | } |
| 1466 | 1629 | ||
| 1467 | test "cannot encode" { | 1630 | test "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 | } |
| 1481 | 1644 | ||
| ... | @@ -1645,12 +1808,7 @@ const Assembler = struct { | ... | @@ -1645,12 +1808,7 @@ const Assembler = struct { |
| 1645 | 1808 | ||
| 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; |
| 6 | 6 | ||
| 7 | const modrm_ext = u3; | 7 | const modrm_ext = u3; |
| 8 | 8 | ||
| 9 | const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, []const u8, modrm_ext, Mode }; | 9 | pub const Entry = struct { Mnemonic, OpEn, []const Op, []const u8, modrm_ext, Mode }; |
| 10 | 10 | ||
| 11 | // TODO move this into a .zon file when Zig is capable of importing .zon files | 11 | // TODO move this into a .zon file when Zig is capable of importing .zon files |
| 12 | // zig fmt: off | 12 | // zig fmt: off |
| 13 | pub const table = &[_]Entry{ | 13 | pub const table = [_]Entry{ |
| 14 | // General-purpose | 14 | // 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 }, |
| 37 | 37 | ||
| 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 }, |
| 60 | 60 | ||
| 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 }, |
| 83 | 83 | ||
| 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 }, |
| 87 | 87 | ||
| 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 }, |
| 91 | 91 | ||
| 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 }, |
| 94 | 94 | ||
| 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 }, |
| 101 | 101 | ||
| 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 }, |
| 108 | 108 | ||
| 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 }, |
| 115 | 115 | ||
| 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 }, |
| 122 | 122 | ||
| 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 }, |
| 126 | 126 | ||
| 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 }, |
| 130 | 130 | ||
| 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 }, |
| 134 | 134 | ||
| 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 }, |
| 225 | 225 | ||
| 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 }, |
| 248 | 248 | ||
| 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 }, |
| 257 | 257 | .{ .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 }, |
| 263 | 263 | .{ .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 }, |
| 266 | 266 | .{ .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 }, |
| 272 | 272 | .{ .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 }, |
| 276 | 276 | .{ .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 }, |
| 280 | 280 | .{ .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 }, |
| 286 | 286 | .{ .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 }, |
| 301 | 301 | .{ .imul, .rmi, &.{ .r64, .rm64, .imm32 }, &.{ 0x69 }, 0, .long }, | |
| 302 | .{ .int3, .np, .none, .none, .none, .none, &.{ 0xcc }, 0, .none }, | 302 | |
| 303 | 303 | .{ .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 }, |
| 335 | 335 | .{ .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 }, |
| 338 | 338 | .{ .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 }, |
| 342 | 342 | .{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long }, | |
| 343 | .{ .lfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xe8 }, 0, .none }, | 343 | |
| 344 | 344 | .{ .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 }, |
| 353 | 353 | .{ .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 }, |
| 357 | 357 | .{ .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 }, |
| 359 | 359 | ||
| 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 }, |
| 392 | 392 | .{ .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 }, |
| 399 | 399 | .{ .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 }, |
| 408 | 408 | .{ .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 }, | ||
| 416 | 419 | ||
| 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 }, |
| 420 | 423 | ||
| 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 }, |
| 426 | 429 | ||
| 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 }, |
| 432 | 435 | ||
| 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 }, |
| 438 | 441 | ||
| 439 | .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none }, | 442 | .{ .nop, .np, &.{}, &.{ 0x90 }, 0, .none }, |
| 440 | 443 | ||
| 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 }, |
| 446 | 449 | ||
| 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 }, |
| 469 | 472 | ||
| 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 }, |
| 474 | 477 | ||
| 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 }, |
| 478 | 481 | ||
| 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 }, |
| 486 | 489 | ||
| 487 | .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none }, | 490 | .{ .ret, .np, &.{}, &.{ 0xc3 }, 0, .none }, |
| 488 | 491 | ||
| 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 }, |
| 504 | 507 | ||
| 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 }, |
| 520 | 523 | ||
| 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 }, |
| 536 | 539 | ||
| 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 }, |
| 552 | 555 | ||
| 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 }, |
| 568 | 571 | ||
| 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 }, |
| 584 | 587 | ||
| 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 }, |
| 607 | 610 | ||
| 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 }, |
| 616 | 619 | .{ .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 }, |
| 677 | 680 | .{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex }, | |
| 678 | .{ .sfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf8 }, 0, .none }, | 681 | |
| 679 | 682 | .{ .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 }, |
| 695 | 698 | .{ .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 }, |
| 702 | 705 | .{ .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 }, |
| 718 | 721 | .{ .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 }, |
| 725 | 728 | .{ .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 }, |
| 734 | 737 | .{ .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 }, |
| 757 | 760 | .{ .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 }, |
| 774 | 779 | ||
| 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 }, |
| 778 | 783 | ||
| 779 | .{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none }, | 784 | .{ .ud2, .np, &.{}, &.{ 0x0f, 0x0b }, 0, .none }, |
| 780 | 785 | ||
| 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 }, |
| 786 | 791 | ||
| 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 }, |
| 803 | 808 | ||
| 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 }, |
| 826 | 831 | ||
| 827 | // SSE | 832 | // 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 }, |
| 829 | 834 | ||
| 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 }, |
| 831 | 836 | ||
| 832 | .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, | 837 | .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, |
| 833 | 838 | ||
| 834 | .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, | 839 | .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, |
| 835 | 840 | ||
| 836 | .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse }, | 841 | .{ .minss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse }, |
| 837 | 842 | ||
| 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 }, |
| 840 | 845 | ||
| 841 | .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse }, | 846 | .{ .mulss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse }, |
| 842 | 847 | ||
| 843 | .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse }, | 848 | .{ .subss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse }, |
| 844 | 849 | ||
| 845 | .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0x0f, 0x2e }, 0, .sse }, | 850 | .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse }, |
| 846 | 851 | ||
| 847 | // SSE2 | 852 | // 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 }, |
| 849 | 854 | ||
| 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 }, |
| 851 | 856 | ||
| 852 | .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, | 857 | .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, |
| 853 | 858 | ||
| 854 | .{ .maxsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, | 859 | .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, |
| 855 | 860 | ||
| 856 | .{ .minsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 }, | 861 | .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 }, |
| 857 | 862 | ||
| 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 }, |
| 860 | 865 | ||
| 861 | .{ .mulsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 }, | 866 | .{ .mulsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 }, |
| 862 | 867 | ||
| 863 | .{ .subsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 }, | 868 | .{ .subsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 }, |
| 864 | 869 | ||
| 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 }, |
| 867 | 872 | ||
| 868 | .{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, | 873 | .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, |
| 869 | 874 | ||
| 870 | // SSE4.1 | 875 | // 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: on | 879 | // 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; |
| 8 | const Air = @import("Air.zig"); | 8 | const Air = @import("Air.zig"); |
| 9 | const Liveness = @import("Liveness.zig"); | 9 | const Liveness = @import("Liveness.zig"); |
| 10 | 10 | ||
| 11 | pub fn dump(module: *Module, air: Air, liveness: Liveness) void { | 11 | pub 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 include | 13 | // 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; |
| 24 | 24 | ||
| 25 | // zig fmt: off | 25 | // 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: on | 44 | // zig fmt: on |
| 45 | var arena = std.heap.ArenaAllocator.init(module.gpa); | ||
| 46 | defer arena.deinit(); | ||
| 47 | 45 | ||
| 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 | } |
| 61 | 58 | ||
| 59 | pub 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 | |||
| 77 | pub fn dump(module: *Module, air: Air, liveness: Liveness) void { | ||
| 78 | write(std.io.getStdErr().writer(), module, air, liveness); | ||
| 79 | } | ||
| 80 | |||
| 81 | pub 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 | |||
| 62 | const Writer = struct { | 85 | const 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, | ||
| 69 | 92 | ||
| 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 | } |
| 84 | 102 | ||
| 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 | } |
| 97 | 106 | ||
| 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 { |
| 316 | 329 | ||
| 317 | .dbg_block_begin, .dbg_block_end => {}, | 330 | .dbg_block_begin, .dbg_block_end => {}, |
| 318 | } | 331 | } |
| 332 | try s.writeAll(")\n"); | ||
| 319 | } | 333 | } |
| 320 | 334 | ||
| 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]; |
| 373 | 387 | ||
| 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]; |
| 704 | 719 | ||
| 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 { |
| 721 | 737 | ||
| 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); |
| 739 | 756 | ||
| 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; // TODO | 47 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 49 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 49 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 50 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 50 | 51 | ||
| 51 | var flags = A{ | 52 | var flags = A{ |
| 52 | .a = false, | 53 | .a = false, |