| ... | @@ -48,9 +48,31 @@ const InnerError = error{ | ... | @@ -48,9 +48,31 @@ const InnerError = error{ |
| 48 | EmitFail, | 48 | EmitFail, |
| 49 | }; | 49 | }; |
| 50 | | 50 | |
| 51 | const EmitError = error{ | 51 | const EmitResult = union(enum) { |
| 52 | OutOfMemory, | 52 | ok: void, |
| 53 | OperandSizeMismatch, | 53 | err: *ErrorMsg, |
| | 54 | |
| | 55 | fn ok() EmitResult { |
| | 56 | return EmitResult{ .ok = .{} }; |
| | 57 | } |
| | 58 | |
| | 59 | fn err( |
| | 60 | allocator: Allocator, |
| | 61 | src_loc: Module.SrcLoc, |
| | 62 | comptime format: []const u8, |
| | 63 | args: anytype, |
| | 64 | ) error{OutOfMemory}!EmitResult { |
| | 65 | return EmitResult{ |
| | 66 | .err = try ErrorMsg.create(allocator, src_loc, format, args), |
| | 67 | }; |
| | 68 | } |
| | 69 | |
| | 70 | fn deinit(res: EmitResult, allocator: Allocator) void { |
| | 71 | switch (res) { |
| | 72 | .ok => {}, |
| | 73 | .err => |err_msg| err_msg.destroy(allocator), |
| | 74 | } |
| | 75 | } |
| 54 | }; | 76 | }; |
| 55 | | 77 | |
| 56 | const Reloc = struct { | 78 | const Reloc = struct { |
| ... | @@ -167,9 +189,15 @@ pub fn deinit(emit: *Emit) void { | ... | @@ -167,9 +189,15 @@ pub fn deinit(emit: *Emit) void { |
| 167 | } | 189 | } |
| 168 | | 190 | |
| 169 | fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { | 191 | fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| | 192 | @setCold(true); |
| | 193 | const err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); |
| | 194 | return emit.failWithErrorMsg(err_msg); |
| | 195 | } |
| | 196 | |
| | 197 | fn failWithErrorMsg(emit: *Emit, err_msg: *ErrorMsg) InnerError { |
| 170 | @setCold(true); | 198 | @setCold(true); |
| 171 | assert(emit.err_msg == null); | 199 | assert(emit.err_msg == null); |
| 172 | emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); | 200 | emit.err_msg = err_msg; |
| 173 | return error.EmitFail; | 201 | return error.EmitFail; |
| 174 | } | 202 | } |
| 175 | | 203 | |
| ... | @@ -858,24 +886,28 @@ fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE | ... | @@ -858,24 +886,28 @@ fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE |
| 858 | } | 886 | } |
| 859 | | 887 | |
| 860 | fn mirMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 888 | fn mirMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 861 | return mirMovImpl( | 889 | const res = try mirMovImpl( |
| | 890 | emit.bin_file.allocator, |
| 862 | emit.mir.instructions, | 891 | emit.mir.instructions, |
| 863 | emit.mir.extra, | 892 | emit.mir.extra, |
| 864 | inst, | 893 | inst, |
| | 894 | emit.src_loc, |
| 865 | emit.code, | 895 | emit.code, |
| 866 | ) catch |err| switch (err) { | 896 | ); |
| 867 | // TODO better formating of operands in case of an error | 897 | switch (res) { |
| 868 | error.OperandSizeMismatch => emit.fail("operand size mismatch", .{}), | 898 | .ok => {}, |
| 869 | else => emit.fail("emit failed with error: {}", .{err}), | 899 | .err => |err_msg| return emit.failWithErrorMsg(err_msg), |
| 870 | }; | 900 | } |
| 871 | } | 901 | } |
| 872 | | 902 | |
| 873 | fn mirMovImpl( | 903 | fn mirMovImpl( |
| | 904 | allocator: Allocator, |
| 874 | mir_instructions: std.MultiArrayList(Mir.Inst).Slice, | 905 | mir_instructions: std.MultiArrayList(Mir.Inst).Slice, |
| 875 | mir_extra: []const u32, | 906 | mir_extra: []const u32, |
| 876 | inst: Mir.Inst.Index, | 907 | inst: Mir.Inst.Index, |
| | 908 | src_loc: Module.SrcLoc, |
| 877 | code: *std.ArrayList(u8), | 909 | code: *std.ArrayList(u8), |
| 878 | ) EmitError!void { | 910 | ) error{OutOfMemory}!EmitResult { |
| 879 | const ops = Mir.Ops.decode(mir_instructions.items(.ops)[inst]); | 911 | const ops = Mir.Ops.decode(mir_instructions.items(.ops)[inst]); |
| 880 | switch (ops.flags) { | 912 | switch (ops.flags) { |
| 881 | 0b00 => blk: { | 913 | 0b00 => blk: { |
| ... | @@ -900,11 +932,31 @@ fn mirMovImpl( | ... | @@ -900,11 +932,31 @@ fn mirMovImpl( |
| 900 | encoder.modRm_direct(modrm_ext, ops.reg1.lowId()); | 932 | encoder.modRm_direct(modrm_ext, ops.reg1.lowId()); |
| 901 | switch (ops.reg1.size()) { | 933 | switch (ops.reg1.size()) { |
| 902 | 8 => { | 934 | 8 => { |
| 903 | const imm8 = math.cast(i8, imm) catch return error.OperandSizeMismatch; | 935 | const imm8 = math.cast(i8, imm) catch { |
| | 936 | return EmitResult.err( |
| | 937 | allocator, |
| | 938 | src_loc, |
| | 939 | "size mismatch: sizeof {} != sizeof 0x{x}", |
| | 940 | .{ |
| | 941 | ops.reg1, |
| | 942 | imm, |
| | 943 | }, |
| | 944 | ); |
| | 945 | }; |
| 904 | encoder.imm8(imm8); | 946 | encoder.imm8(imm8); |
| 905 | }, | 947 | }, |
| 906 | 16 => { | 948 | 16 => { |
| 907 | const imm16 = math.cast(i16, imm) catch return error.OperandSizeMismatch; | 949 | const imm16 = math.cast(i16, imm) catch { |
| | 950 | return EmitResult.err( |
| | 951 | allocator, |
| | 952 | src_loc, |
| | 953 | "size mismatch: sizeof {} != sizeof 0x{x}", |
| | 954 | .{ |
| | 955 | ops.reg1, |
| | 956 | imm, |
| | 957 | }, |
| | 958 | ); |
| | 959 | }; |
| 908 | encoder.imm16(imm16); | 960 | encoder.imm16(imm16); |
| 909 | }, | 961 | }, |
| 910 | 32, 64 => { | 962 | 32, 64 => { |
| ... | @@ -917,7 +969,10 @@ fn mirMovImpl( | ... | @@ -917,7 +969,10 @@ fn mirMovImpl( |
| 917 | // mov reg1, reg2 | 969 | // mov reg1, reg2 |
| 918 | // MR | 970 | // MR |
| 919 | if (ops.reg1.size() != ops.reg2.size()) { | 971 | if (ops.reg1.size() != ops.reg2.size()) { |
| 920 | return error.OperandSizeMismatch; | 972 | return EmitResult.err(allocator, src_loc, "size mismatch: sizeof {} != sizeof {}", .{ |
| | 973 | ops.reg1, |
| | 974 | ops.reg2, |
| | 975 | }); |
| 921 | } | 976 | } |
| 922 | const opc: u8 = if (ops.reg1.size() == 8) 0x88 else 0x89; | 977 | const opc: u8 = if (ops.reg1.size() == 8) 0x88 else 0x89; |
| 923 | const encoder = try Encoder.init(code, 3); | 978 | const encoder = try Encoder.init(code, 3); |
| ... | @@ -954,7 +1009,7 @@ fn mirMovImpl( | ... | @@ -954,7 +1009,7 @@ fn mirMovImpl( |
| 954 | // TODO handle 32-bit base register - requires prefix 0x67 | 1009 | // TODO handle 32-bit base register - requires prefix 0x67 |
| 955 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 | 1010 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 |
| 956 | if (ops.reg2.size() != 64) { | 1011 | if (ops.reg2.size() != 64) { |
| 957 | return error.OperandSizeMismatch; | 1012 | return EmitResult.err(allocator, src_loc, "size mismatch: sizeof {} != 8", .{ops.reg2}); |
| 958 | } | 1013 | } |
| 959 | const encoder = try Encoder.init(code, 8); | 1014 | const encoder = try Encoder.init(code, 8); |
| 960 | if (ops.reg1.size() == 16) { | 1015 | if (ops.reg1.size() == 16) { |
| ... | @@ -978,7 +1033,7 @@ fn mirMovImpl( | ... | @@ -978,7 +1033,7 @@ fn mirMovImpl( |
| 978 | // TODO handle 32-bit base register - requires prefix 0x67 | 1033 | // TODO handle 32-bit base register - requires prefix 0x67 |
| 979 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 | 1034 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 |
| 980 | if (ops.reg1.size() != 64) { | 1035 | if (ops.reg1.size() != 64) { |
| 981 | return error.OperandSizeMismatch; | 1036 | return EmitResult.err(allocator, src_loc, "size mismatch: sizeof {} != 8", .{ops.reg1}); |
| 982 | } | 1037 | } |
| 983 | if (ops.reg2 == .none) { | 1038 | if (ops.reg2 == .none) { |
| 984 | // mov [reg1 + 0], imm32 | 1039 | // mov [reg1 + 0], imm32 |
| ... | @@ -1041,7 +1096,7 @@ fn mirMovImpl( | ... | @@ -1041,7 +1096,7 @@ fn mirMovImpl( |
| 1041 | // a byte, word or dword ptr. | 1096 | // a byte, word or dword ptr. |
| 1042 | // TODO we currently don't have a way to flag imm32 64bit sign extended | 1097 | // TODO we currently don't have a way to flag imm32 64bit sign extended |
| 1043 | if (ops.reg1.size() != 64) { | 1098 | if (ops.reg1.size() != 64) { |
| 1044 | return error.OperandSizeMismatch; | 1099 | return EmitResult.err(allocator, src_loc, "size mismatch: sizeof {} != 8", .{ops.reg1}); |
| 1045 | } | 1100 | } |
| 1046 | const payload = mir_instructions.items(.data)[inst].payload; | 1101 | const payload = mir_instructions.items(.data)[inst].payload; |
| 1047 | const imm_pair = Mir.extraData(mir_extra, Mir.ImmPair, payload).data; | 1102 | const imm_pair = Mir.extraData(mir_extra, Mir.ImmPair, payload).data; |
| ... | @@ -1077,6 +1132,7 @@ fn mirMovImpl( | ... | @@ -1077,6 +1132,7 @@ fn mirMovImpl( |
| 1077 | encoder.modRm_direct(ops.reg1.lowId(), ops.reg2.lowId()); | 1132 | encoder.modRm_direct(ops.reg1.lowId(), ops.reg2.lowId()); |
| 1078 | }, | 1133 | }, |
| 1079 | } | 1134 | } |
| | 1135 | return EmitResult.ok(); |
| 1080 | } | 1136 | } |
| 1081 | | 1137 | |
| 1082 | fn immOpSize(imm: i32) u8 { | 1138 | fn immOpSize(imm: i32) u8 { |
| ... | @@ -1488,23 +1544,36 @@ const Mock = struct { | ... | @@ -1488,23 +1544,36 @@ const Mock = struct { |
| 1488 | return result; | 1544 | return result; |
| 1489 | } | 1545 | } |
| 1490 | | 1546 | |
| | 1547 | fn dummySrcLoc() Module.SrcLoc { |
| | 1548 | return .{ |
| | 1549 | .file_scope = undefined, |
| | 1550 | .parent_decl_node = 0, |
| | 1551 | .lazy = .unneeded, |
| | 1552 | }; |
| | 1553 | } |
| | 1554 | |
| 1491 | fn testEmitSingleSuccess( | 1555 | fn testEmitSingleSuccess( |
| 1492 | self: *Mock, | 1556 | self: *Mock, |
| 1493 | mir_inst: Mir.Inst, | 1557 | mir_inst: Mir.Inst, |
| 1494 | expected_enc: []const u8, | 1558 | expected_enc: []const u8, |
| 1495 | assembly: []const u8, | 1559 | assembly: []const u8, |
| 1496 | ) !void { | 1560 | ) !void { |
| | 1561 | const dummy_src_loc = Mock.dummySrcLoc(); |
| 1497 | const code_index = self.code.items.len; | 1562 | const code_index = self.code.items.len; |
| 1498 | const mir_index = try self.addInst(mir_inst); | 1563 | const mir_index = try self.addInst(mir_inst); |
| 1499 | switch (mir_inst.tag) { | 1564 | const res = switch (mir_inst.tag) { |
| 1500 | .mov => try mirMovImpl( | 1565 | .mov => try mirMovImpl( |
| | 1566 | testing.allocator, |
| 1501 | self.mir_instructions.slice(), | 1567 | self.mir_instructions.slice(), |
| 1502 | self.mir_extra.items, | 1568 | self.mir_extra.items, |
| 1503 | mir_index, | 1569 | mir_index, |
| | 1570 | dummy_src_loc, |
| 1504 | &self.code, | 1571 | &self.code, |
| 1505 | ), | 1572 | ), |
| 1506 | else => unreachable, | 1573 | else => unreachable, |
| 1507 | } | 1574 | }; |
| | 1575 | defer res.deinit(testing.allocator); |
| | 1576 | try testing.expect(res == .ok); |
| 1508 | const code_len = if (self.code.items[code_index..].len >= expected_enc.len) | 1577 | const code_len = if (self.code.items[code_index..].len >= expected_enc.len) |
| 1509 | expected_enc.len | 1578 | expected_enc.len |
| 1510 | else | 1579 | else |
| ... | @@ -1512,18 +1581,23 @@ const Mock = struct { | ... | @@ -1512,18 +1581,23 @@ const Mock = struct { |
| 1512 | try expectEqualHexStrings(expected_enc, self.code.items[code_index..][0..code_len], assembly); | 1581 | try expectEqualHexStrings(expected_enc, self.code.items[code_index..][0..code_len], assembly); |
| 1513 | } | 1582 | } |
| 1514 | | 1583 | |
| 1515 | fn testEmitSingleError(self: *Mock, mir_inst: Mir.Inst, err: EmitError) !void { | 1584 | fn testEmitSingleFail(self: *Mock, mir_inst: Mir.Inst, msg: []const u8) !void { |
| | 1585 | const dummy_src_loc = Mock.dummySrcLoc(); |
| 1516 | const index = try self.addInst(mir_inst); | 1586 | const index = try self.addInst(mir_inst); |
| 1517 | const res = switch (mir_inst.tag) { | 1587 | const res = switch (mir_inst.tag) { |
| 1518 | .mov => mirMovImpl( | 1588 | .mov => try mirMovImpl( |
| | 1589 | testing.allocator, |
| 1519 | self.mir_instructions.slice(), | 1590 | self.mir_instructions.slice(), |
| 1520 | self.mir_extra.items, | 1591 | self.mir_extra.items, |
| 1521 | index, | 1592 | index, |
| | 1593 | dummy_src_loc, |
| 1522 | &self.code, | 1594 | &self.code, |
| 1523 | ), | 1595 | ), |
| 1524 | else => unreachable, | 1596 | else => unreachable, |
| 1525 | }; | 1597 | }; |
| 1526 | try testing.expectError(err, res); | 1598 | defer res.deinit(testing.allocator); |
| | 1599 | try testing.expect(res == .err); |
| | 1600 | try testing.expectEqualStrings(msg, res.err.msg); |
| 1527 | } | 1601 | } |
| 1528 | }; | 1602 | }; |
| 1529 | | 1603 | |
| ... | @@ -1560,16 +1634,16 @@ test "mov dst_reg, src_reg" { | ... | @@ -1560,16 +1634,16 @@ test "mov dst_reg, src_reg" { |
| 1560 | .ops = (Mir.Ops{ .reg1 = .r12, .reg2 = .rax }).encode(), | 1634 | .ops = (Mir.Ops{ .reg1 = .r12, .reg2 = .rax }).encode(), |
| 1561 | .data = undefined, | 1635 | .data = undefined, |
| 1562 | }, "\x49\x89\xc4", "mov r12, rax"); | 1636 | }, "\x49\x89\xc4", "mov r12, rax"); |
| 1563 | try mock.testEmitSingleError(.{ | 1637 | try mock.testEmitSingleFail(.{ |
| 1564 | .tag = .mov, | 1638 | .tag = .mov, |
| 1565 | .ops = (Mir.Ops{ .reg1 = .r12, .reg2 = .eax }).encode(), | 1639 | .ops = (Mir.Ops{ .reg1 = .r12, .reg2 = .eax }).encode(), |
| 1566 | .data = undefined, | 1640 | .data = undefined, |
| 1567 | }, error.OperandSizeMismatch); | 1641 | }, "size mismatch: sizeof Register.r12 != sizeof Register.eax"); |
| 1568 | try mock.testEmitSingleError(.{ | 1642 | try mock.testEmitSingleFail(.{ |
| 1569 | .tag = .mov, | 1643 | .tag = .mov, |
| 1570 | .ops = (Mir.Ops{ .reg1 = .r12d, .reg2 = .rax }).encode(), | 1644 | .ops = (Mir.Ops{ .reg1 = .r12d, .reg2 = .rax }).encode(), |
| 1571 | .data = undefined, | 1645 | .data = undefined, |
| 1572 | }, error.OperandSizeMismatch); | 1646 | }, "size mismatch: sizeof Register.r12d != sizeof Register.rax"); |
| 1573 | try mock.testEmitSingleSuccess(.{ | 1647 | try mock.testEmitSingleSuccess(.{ |
| 1574 | .tag = .mov, | 1648 | .tag = .mov, |
| 1575 | .ops = (Mir.Ops{ .reg1 = .r12d, .reg2 = .eax }).encode(), | 1649 | .ops = (Mir.Ops{ .reg1 = .r12d, .reg2 = .eax }).encode(), |
| ... | @@ -1615,16 +1689,16 @@ test "mov dst_reg, imm" { | ... | @@ -1615,16 +1689,16 @@ test "mov dst_reg, imm" { |
| 1615 | .ops = (Mir.Ops{ .reg1 = .cl }).encode(), | 1689 | .ops = (Mir.Ops{ .reg1 = .cl }).encode(), |
| 1616 | .data = .{ .imm = 0x10 }, | 1690 | .data = .{ .imm = 0x10 }, |
| 1617 | }, "\xc6\xc1\x10", "mov cl, 0x10"); | 1691 | }, "\xc6\xc1\x10", "mov cl, 0x10"); |
| 1618 | try mock.testEmitSingleError(.{ | 1692 | try mock.testEmitSingleFail(.{ |
| 1619 | .tag = .mov, | 1693 | .tag = .mov, |
| 1620 | .ops = (Mir.Ops{ .reg1 = .cx }).encode(), | 1694 | .ops = (Mir.Ops{ .reg1 = .cx }).encode(), |
| 1621 | .data = .{ .imm = 0x10000000 }, | 1695 | .data = .{ .imm = 0x10000000 }, |
| 1622 | }, error.OperandSizeMismatch); | 1696 | }, "size mismatch: sizeof Register.cx != sizeof 0x10000000"); |
| 1623 | try mock.testEmitSingleError(.{ | 1697 | try mock.testEmitSingleFail(.{ |
| 1624 | .tag = .mov, | 1698 | .tag = .mov, |
| 1625 | .ops = (Mir.Ops{ .reg1 = .cl }).encode(), | 1699 | .ops = (Mir.Ops{ .reg1 = .cl }).encode(), |
| 1626 | .data = .{ .imm = 0x1000 }, | 1700 | .data = .{ .imm = 0x1000 }, |
| 1627 | }, error.OperandSizeMismatch); | 1701 | }, "size mismatch: sizeof Register.cl != sizeof 0x1000"); |
| 1628 | } | 1702 | } |
| 1629 | | 1703 | |
| 1630 | test "mov dst_reg, [imm32]" { | 1704 | test "mov dst_reg, [imm32]" { |
| ... | @@ -1705,11 +1779,11 @@ test "mov [dst_reg + 0], imm" { | ... | @@ -1705,11 +1779,11 @@ test "mov [dst_reg + 0], imm" { |
| 1705 | .ops = (Mir.Ops{ .reg1 = .rax, .flags = 0b10 }).encode(), | 1779 | .ops = (Mir.Ops{ .reg1 = .rax, .flags = 0b10 }).encode(), |
| 1706 | .data = .{ .imm = 0x10 }, | 1780 | .data = .{ .imm = 0x10 }, |
| 1707 | }, "\xC7\x00\x10\x00\x00\x00", "mov dword ptr [rax + 0], 0x10"); | 1781 | }, "\xC7\x00\x10\x00\x00\x00", "mov dword ptr [rax + 0], 0x10"); |
| 1708 | try mock.testEmitSingleError(.{ | 1782 | try mock.testEmitSingleFail(.{ |
| 1709 | .tag = .mov, | 1783 | .tag = .mov, |
| 1710 | .ops = (Mir.Ops{ .reg1 = .eax, .flags = 0b10 }).encode(), | 1784 | .ops = (Mir.Ops{ .reg1 = .eax, .flags = 0b10 }).encode(), |
| 1711 | .data = .{ .imm = 0x10 }, | 1785 | .data = .{ .imm = 0x10 }, |
| 1712 | }, error.OperandSizeMismatch); | 1786 | }, "size mismatch: sizeof Register.eax != 8"); |
| 1713 | } | 1787 | } |
| 1714 | | 1788 | |
| 1715 | test "mov [dst_reg + imm32], src_reg" { | 1789 | test "mov [dst_reg + imm32], src_reg" { |
| ... | @@ -1745,11 +1819,11 @@ test "mov [dst_reg + imm32], src_reg" { | ... | @@ -1745,11 +1819,11 @@ test "mov [dst_reg + imm32], src_reg" { |
| 1745 | .ops = (Mir.Ops{ .reg1 = .r11, .reg2 = .eax, .flags = 0b10 }).encode(), | 1819 | .ops = (Mir.Ops{ .reg1 = .r11, .reg2 = .eax, .flags = 0b10 }).encode(), |
| 1746 | .data = .{ .imm = 0x10 }, | 1820 | .data = .{ .imm = 0x10 }, |
| 1747 | }, "\x41\x89\x43\x10", "mov dword ptr [r11 + 0x10], eax"); | 1821 | }, "\x41\x89\x43\x10", "mov dword ptr [r11 + 0x10], eax"); |
| 1748 | try mock.testEmitSingleError(.{ | 1822 | try mock.testEmitSingleFail(.{ |
| 1749 | .tag = .mov, | 1823 | .tag = .mov, |
| 1750 | .ops = (Mir.Ops{ .reg1 = .r11w, .reg2 = .ax, .flags = 0b10 }).encode(), | 1824 | .ops = (Mir.Ops{ .reg1 = .r11w, .reg2 = .ax, .flags = 0b10 }).encode(), |
| 1751 | .data = .{ .imm = 0x10 }, | 1825 | .data = .{ .imm = 0x10 }, |
| 1752 | }, error.OperandSizeMismatch); | 1826 | }, "size mismatch: sizeof Register.r11w != 8"); |
| 1753 | } | 1827 | } |
| 1754 | | 1828 | |
| 1755 | test "mov [dst_reg + imm32], imm32" { | 1829 | test "mov [dst_reg + imm32], imm32" { |
| ... | @@ -1815,10 +1889,10 @@ test "mov [dst_reg + imm32], imm32" { | ... | @@ -1815,10 +1889,10 @@ test "mov [dst_reg + imm32], imm32" { |
| 1815 | .dest_off = 0x10, | 1889 | .dest_off = 0x10, |
| 1816 | .operand = 0x20, | 1890 | .operand = 0x20, |
| 1817 | }); | 1891 | }); |
| 1818 | try mock.testEmitSingleError(.{ | 1892 | try mock.testEmitSingleFail(.{ |
| 1819 | .tag = .mov, | 1893 | .tag = .mov, |
| 1820 | .ops = (Mir.Ops{ .reg1 = .r11d, .flags = 0b11 }).encode(), | 1894 | .ops = (Mir.Ops{ .reg1 = .r11d, .flags = 0b11 }).encode(), |
| 1821 | .data = .{ .payload = payload }, | 1895 | .data = .{ .payload = payload }, |
| 1822 | }, error.OperandSizeMismatch); | 1896 | }, "size mismatch: sizeof Register.r11d != 8"); |
| 1823 | } | 1897 | } |
| 1824 | } | 1898 | } |