authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-06-16 12:43:18-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-06-16 14:59:56-04:00
log96501d338550f47671692c669cb76eb99513a8da
tree61385f8edbd3e94c32befb476e4340a17b205ec0
parent17f14e1d65b59ebb1a8b5b617cc31fb2614f0c6a

x86_64: get encoder tests passing again


4 files changed, 148 insertions(+), 133 deletions(-)

src/arch/x86_64/CodeGen.zig+18-7
...@@ -14529,6 +14529,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo...@@ -14529,6 +14529,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo
14529 else => {},14529 else => {},
14530 },14530 },
14531 },14531 },
14532 .ip => {},
14532 }14533 }
14533 return self.fail("TODO moveStrategy for {}", .{ty.fmt(mod)});14534 return self.fail("TODO moveStrategy for {}", .{ty.fmt(mod)});
14534}14535}
...@@ -14685,6 +14686,7 @@ fn genSetReg(...@@ -14685,6 +14686,7 @@ fn genSetReg(
14685 else => unreachable,14686 else => unreachable,
14686 },14687 },
14687 .segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(try mod.undefValue(ty)), opts),14688 .segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(try mod.undefValue(ty)), opts),
14689 .ip => unreachable,
14688 },14690 },
14689 .eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()),14691 .eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()),
14690 .immediate => |imm| {14692 .immediate => |imm| {
...@@ -14722,7 +14724,7 @@ fn genSetReg(...@@ -14722,7 +14724,7 @@ fn genSetReg(
14722 registerAlias(dst_reg, abi_size),14724 registerAlias(dst_reg, abi_size),
14723 src_reg,14725 src_reg,
14724 ),14726 ),
14725 .x87, .mmx => unreachable,14727 .x87, .mmx, .ip => unreachable,
14726 .sse => try self.asmRegisterRegister(14728 .sse => try self.asmRegisterRegister(
14727 switch (abi_size) {14729 switch (abi_size) {
14728 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },14730 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
...@@ -14738,7 +14740,7 @@ fn genSetReg(...@@ -14738,7 +14740,7 @@ fn genSetReg(
14738 dst_reg,14740 dst_reg,
14739 switch (src_reg.class()) {14741 switch (src_reg.class()) {
14740 .general_purpose, .segment => registerAlias(src_reg, abi_size),14742 .general_purpose, .segment => registerAlias(src_reg, abi_size),
14741 .x87, .mmx => unreachable,14743 .x87, .mmx, .ip => unreachable,
14742 .sse => try self.copyToTmpRegister(ty, src_mcv),14744 .sse => try self.copyToTmpRegister(ty, src_mcv),
14743 },14745 },
14744 ),14746 ),
...@@ -14753,7 +14755,7 @@ fn genSetReg(...@@ -14753,7 +14755,7 @@ fn genSetReg(
14753 },14755 },
14754 else => unreachable,14756 else => unreachable,
14755 },14757 },
14756 .mmx, .sse => unreachable,14758 .mmx, .sse, .ip => unreachable,
14757 },14759 },
14758 .mmx => unreachable,14760 .mmx => unreachable,
14759 .sse => switch (src_reg.class()) {14761 .sse => switch (src_reg.class()) {
...@@ -14772,7 +14774,7 @@ fn genSetReg(...@@ -14772,7 +14774,7 @@ fn genSetReg(
14772 .{ .register = try self.copyToTmpRegister(ty, src_mcv) },14774 .{ .register = try self.copyToTmpRegister(ty, src_mcv) },
14773 opts,14775 opts,
14774 ),14776 ),
14775 .x87, .mmx => unreachable,14777 .x87, .mmx, .ip => unreachable,
14776 .sse => try self.asmRegisterRegister(14778 .sse => try self.asmRegisterRegister(
14777 @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) {14779 @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) {
14778 else => switch (abi_size) {14780 else => switch (abi_size) {
...@@ -14799,6 +14801,7 @@ fn genSetReg(...@@ -14799,6 +14801,7 @@ fn genSetReg(
14799 registerAlias(src_reg, abi_size),14801 registerAlias(src_reg, abi_size),
14800 ),14802 ),
14801 },14803 },
14804 .ip => unreachable,
14802 },14805 },
14803 .register_pair => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts),14806 .register_pair => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts),
14804 .register_offset,14807 .register_offset,
...@@ -14866,7 +14869,7 @@ fn genSetReg(...@@ -14866,7 +14869,7 @@ fn genSetReg(
14866 });14869 });
14867 return;14870 return;
14868 },14871 },
14869 .segment, .mmx => unreachable,14872 .segment, .mmx, .ip => unreachable,
14870 .x87, .sse => {},14873 .x87, .sse => {},
14871 },14874 },
14872 .load_direct => |sym_index| switch (dst_reg.class()) {14875 .load_direct => |sym_index| switch (dst_reg.class()) {
...@@ -14884,7 +14887,7 @@ fn genSetReg(...@@ -14884,7 +14887,7 @@ fn genSetReg(
14884 });14887 });
14885 return;14888 return;
14886 },14889 },
14887 .segment, .mmx => unreachable,14890 .segment, .mmx, .ip => unreachable,
14888 .x87, .sse => {},14891 .x87, .sse => {},
14889 },14892 },
14890 .load_got, .load_tlv => {},14893 .load_got, .load_tlv => {},
...@@ -15047,7 +15050,7 @@ fn genSetMem(...@@ -15047,7 +15050,7 @@ fn genSetMem(
15047 };15050 };
15048 const src_alias = registerAlias(src_reg, abi_size);15051 const src_alias = registerAlias(src_reg, abi_size);
15049 const src_size: u32 = @intCast(switch (src_alias.class()) {15052 const src_size: u32 = @intCast(switch (src_alias.class()) {
15050 .general_purpose, .segment, .x87 => @divExact(src_alias.bitSize(), 8),15053 .general_purpose, .segment, .x87, .ip => @divExact(src_alias.bitSize(), 8),
15051 .mmx, .sse => abi_size,15054 .mmx, .sse => abi_size,
15052 });15055 });
15053 const src_align = Alignment.fromNonzeroByteUnits(math.ceilPowerOfTwoAssert(u32, src_size));15056 const src_align = Alignment.fromNonzeroByteUnits(math.ceilPowerOfTwoAssert(u32, src_size));
...@@ -19077,6 +19080,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -19077,6 +19080,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
19077 reg.to256()19080 reg.to256()
19078 else19081 else
19079 unreachable,19082 unreachable,
19083 .ip => if (size_bytes <= 2)
19084 .ip
19085 else if (size_bytes <= 4)
19086 .eip
19087 else if (size_bytes <= 8)
19088 .rip
19089 else
19090 unreachable,
19080 };19091 };
19081}19092}
1908219093
src/arch/x86_64/Encoding.zig+1
...@@ -487,6 +487,7 @@ pub const Op = enum {...@@ -487,6 +487,7 @@ pub const Op = enum {
487 256 => .ymm,487 256 => .ymm,
488 else => unreachable,488 else => unreachable,
489 },489 },
490 .ip => unreachable,
490 },491 },
491492
492 .mem => |mem| switch (mem) {493 .mem => |mem| switch (mem) {
src/arch/x86_64/bits.zig+5-1
...@@ -192,6 +192,7 @@ pub const Register = enum(u7) {...@@ -192,6 +192,7 @@ pub const Register = enum(u7) {
192 x87,192 x87,
193 mmx,193 mmx,
194 sse,194 sse,
195 ip,
195 };196 };
196197
197 pub fn class(reg: Register) Class {198 pub fn class(reg: Register) Class {
...@@ -209,6 +210,7 @@ pub const Register = enum(u7) {...@@ -209,6 +210,7 @@ pub const Register = enum(u7) {
209 @intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => .x87,210 @intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => .x87,
210211
211 @intFromEnum(Register.es) ... @intFromEnum(Register.gs) => .segment,212 @intFromEnum(Register.es) ... @intFromEnum(Register.gs) => .segment,
213 @intFromEnum(Register.rip) ... @intFromEnum(Register.ip) => .ip,
212214
213 else => unreachable,215 else => unreachable,
214 // zig fmt: on216 // zig fmt: on
...@@ -370,13 +372,14 @@ pub const Register = enum(u7) {...@@ -370,13 +372,14 @@ pub const Register = enum(u7) {
370 .x87 => 33 + @as(u6, reg.enc()),372 .x87 => 33 + @as(u6, reg.enc()),
371 .mmx => 41 + @as(u6, reg.enc()),373 .mmx => 41 + @as(u6, reg.enc()),
372 .segment => 50 + @as(u6, reg.enc()),374 .segment => 50 + @as(u6, reg.enc()),
375 .ip => unreachable,
373 };376 };
374 }377 }
375};378};
376379
377test "Register id - different classes" {380test "Register id - different classes" {
378 try expect(Register.al.id() == Register.ax.id());381 try expect(Register.al.id() == Register.ax.id());
379 try expect(Register.ah.id() == Register.spl.id());382 try expect(Register.ah.id() != Register.spl.id());
380 try expect(Register.ax.id() == Register.eax.id());383 try expect(Register.ax.id() == Register.eax.id());
381 try expect(Register.eax.id() == Register.rax.id());384 try expect(Register.eax.id() == Register.rax.id());
382385
...@@ -391,6 +394,7 @@ test "Register id - different classes" {...@@ -391,6 +394,7 @@ test "Register id - different classes" {
391394
392test "Register enc - different classes" {395test "Register enc - different classes" {
393 try expect(Register.al.enc() == Register.ax.enc());396 try expect(Register.al.enc() == Register.ax.enc());
397 try expect(Register.ah.enc() == Register.spl.enc());
394 try expect(Register.ax.enc() == Register.eax.enc());398 try expect(Register.ax.enc() == Register.eax.enc());
395 try expect(Register.eax.enc() == Register.rax.enc());399 try expect(Register.eax.enc() == Register.rax.enc());
396 try expect(Register.ymm0.enc() == Register.rax.enc());400 try expect(Register.ymm0.enc() == Register.rax.enc());
src/arch/x86_64/encoder.zig+124-125
...@@ -536,59 +536,62 @@ pub const Instruction = struct {...@@ -536,59 +536,62 @@ pub const Instruction = struct {
536 }536 }
537 try encoder.disp32(sib.disp);537 try encoder.disp32(sib.disp);
538 },538 },
539 .reg => |base| if (base.class() == .segment) {539 .reg => |base| switch (base.class()) {
540 // TODO audit this wrt SIB540 .segment => {
541 try encoder.modRm_SIBDisp0(operand_enc);541 // TODO audit this wrt SIB
542 if (mem.scaleIndex()) |si| {542 try encoder.modRm_SIBDisp0(operand_enc);
543 const scale = math.log2_int(u4, si.scale);543 if (mem.scaleIndex()) |si| {
544 try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());544 const scale = math.log2_int(u4, si.scale);
545 } else {545 try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
546 try encoder.sib_disp32();546 } else {
547 }547 try encoder.sib_disp32();
548 try encoder.disp32(sib.disp);548 }
549 } else {549 try encoder.disp32(sib.disp);
550 assert(base.class() == .general_purpose);550 },
551 const dst = base.lowEnc();551 .general_purpose => {
552 const src = operand_enc;552 const dst = base.lowEnc();
553 if (dst == 4 or mem.scaleIndex() != null) {553 const src = operand_enc;
554 if (sib.disp == 0 and dst != 5) {554 if (dst == 4 or mem.scaleIndex() != null) {
555 try encoder.modRm_SIBDisp0(src);555 if (sib.disp == 0 and dst != 5) {
556 if (mem.scaleIndex()) |si| {556 try encoder.modRm_SIBDisp0(src);
557 const scale = math.log2_int(u4, si.scale);557 if (mem.scaleIndex()) |si| {
558 try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst);558 const scale = math.log2_int(u4, si.scale);
559 } else {559 try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst);
560 try encoder.sib_base(dst);560 } else {
561 }561 try encoder.sib_base(dst);
562 } else if (math.cast(i8, sib.disp)) |_| {562 }
563 try encoder.modRm_SIBDisp8(src);563 } else if (math.cast(i8, sib.disp)) |_| {
564 if (mem.scaleIndex()) |si| {564 try encoder.modRm_SIBDisp8(src);
565 const scale = math.log2_int(u4, si.scale);565 if (mem.scaleIndex()) |si| {
566 try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst);566 const scale = math.log2_int(u4, si.scale);
567 try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst);
568 } else {
569 try encoder.sib_baseDisp8(dst);
570 }
571 try encoder.disp8(@as(i8, @truncate(sib.disp)));
567 } else {572 } else {
568 try encoder.sib_baseDisp8(dst);573 try encoder.modRm_SIBDisp32(src);
574 if (mem.scaleIndex()) |si| {
575 const scale = math.log2_int(u4, si.scale);
576 try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst);
577 } else {
578 try encoder.sib_baseDisp32(dst);
579 }
580 try encoder.disp32(sib.disp);
569 }581 }
570 try encoder.disp8(@as(i8, @truncate(sib.disp)));
571 } else {582 } else {
572 try encoder.modRm_SIBDisp32(src);583 if (sib.disp == 0 and dst != 5) {
573 if (mem.scaleIndex()) |si| {584 try encoder.modRm_indirectDisp0(src, dst);
574 const scale = math.log2_int(u4, si.scale);585 } else if (math.cast(i8, sib.disp)) |_| {
575 try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst);586 try encoder.modRm_indirectDisp8(src, dst);
587 try encoder.disp8(@as(i8, @truncate(sib.disp)));
576 } else {588 } else {
577 try encoder.sib_baseDisp32(dst);589 try encoder.modRm_indirectDisp32(src, dst);
590 try encoder.disp32(sib.disp);
578 }591 }
579 try encoder.disp32(sib.disp);
580 }
581 } else {
582 if (sib.disp == 0 and dst != 5) {
583 try encoder.modRm_indirectDisp0(src, dst);
584 } else if (math.cast(i8, sib.disp)) |_| {
585 try encoder.modRm_indirectDisp8(src, dst);
586 try encoder.disp8(@as(i8, @truncate(sib.disp)));
587 } else {
588 try encoder.modRm_indirectDisp32(src, dst);
589 try encoder.disp32(sib.disp);
590 }592 }
591 }593 },
594 else => unreachable,
592 },595 },
593 .frame => if (@TypeOf(encoder).options.allow_frame_locs) {596 .frame => if (@TypeOf(encoder).options.allow_frame_locs) {
594 try encoder.modRm_indirectDisp32(operand_enc, undefined);597 try encoder.modRm_indirectDisp32(operand_enc, undefined);
...@@ -1101,7 +1104,7 @@ const TestEncode = struct {...@@ -1101,7 +1104,7 @@ const TestEncode = struct {
1101 var stream = std.io.fixedBufferStream(&enc.buffer);1104 var stream = std.io.fixedBufferStream(&enc.buffer);
1102 var count_writer = std.io.countingWriter(stream.writer());1105 var count_writer = std.io.countingWriter(stream.writer());
1103 const inst = try Instruction.new(.none, mnemonic, ops);1106 const inst = try Instruction.new(.none, mnemonic, ops);
1104 try inst.encode(count_writer.writer());1107 try inst.encode(count_writer.writer(), .{});
1105 enc.index = count_writer.bytes_written;1108 enc.index = count_writer.bytes_written;
1106 }1109 }
11071110
...@@ -1118,7 +1121,7 @@ test "encode" {...@@ -1118,7 +1121,7 @@ test "encode" {
1118 .{ .reg = .rbx },1121 .{ .reg = .rbx },
1119 .{ .imm = Immediate.u(4) },1122 .{ .imm = Immediate.u(4) },
1120 });1123 });
1121 try inst.encode(buf.writer());1124 try inst.encode(buf.writer(), .{});
1122 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);1125 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
1123}1126}
11241127
...@@ -1181,7 +1184,7 @@ test "lower MI encoding" {...@@ -1181,7 +1184,7 @@ test "lower MI encoding" {
1181 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");1184 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
11821185
1183 try enc.encode(.mov, &.{1186 try enc.encode(.mov, &.{
1184 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },1187 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
1185 .{ .imm = Immediate.u(0x10) },1188 .{ .imm = Immediate.u(0x10) },
1186 });1189 });
1187 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");1190 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
...@@ -1205,7 +1208,7 @@ test "lower MI encoding" {...@@ -1205,7 +1208,7 @@ test "lower MI encoding" {
1205 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");1208 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
12061209
1207 try enc.encode(.mov, &.{1210 try enc.encode(.mov, &.{
1208 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11 }) },1211 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },
1209 .{ .imm = Immediate.u(0x10) },1212 .{ .imm = Immediate.u(0x10) },
1210 });1213 });
1211 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");1214 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
...@@ -1221,26 +1224,26 @@ test "lower MI encoding" {...@@ -1221,26 +1224,26 @@ test "lower MI encoding" {
1221 );1224 );
12221225
1223 try enc.encode(.mov, &.{1226 try enc.encode(.mov, &.{
1224 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },1227 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
1225 .{ .imm = Immediate.u(0x10) },1228 .{ .imm = Immediate.u(0x10) },
1226 });1229 });
1227 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");1230 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
12281231
1229 try enc.encode(.mov, &.{1232 try enc.encode(.mov, &.{
1230 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },1233 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
1231 .{ .imm = Immediate.s(-16) },1234 .{ .imm = Immediate.s(-16) },
1232 });1235 });
1233 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");1236 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
12341237
1235 try enc.encode(.mov, &.{1238 try enc.encode(.mov, &.{
1236 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },1239 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
1237 .{ .imm = Immediate.u(0x10) },1240 .{ .imm = Immediate.u(0x10) },
1238 });1241 });
1239 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");1242 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
12401243
1241 try enc.encode(.mov, &.{1244 try enc.encode(.mov, &.{
1242 .{ .mem = Instruction.Memory.sib(.qword, .{1245 .{ .mem = Instruction.Memory.sib(.qword, .{
1243 .base = .ds,1246 .base = .{ .reg = .ds },
1244 .disp = 0x10000000,1247 .disp = 0x10000000,
1245 .scale_index = .{ .scale = 2, .index = .rcx },1248 .scale_index = .{ .scale = 2, .index = .rcx },
1246 }) },1249 }) },
...@@ -1253,7 +1256,7 @@ test "lower MI encoding" {...@@ -1253,7 +1256,7 @@ test "lower MI encoding" {
1253 );1256 );
12541257
1255 try enc.encode(.adc, &.{1258 try enc.encode(.adc, &.{
1256 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },1259 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
1257 .{ .imm = Immediate.u(0x10) },1260 .{ .imm = Immediate.u(0x10) },
1258 });1261 });
1259 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");1262 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
...@@ -1271,7 +1274,7 @@ test "lower MI encoding" {...@@ -1271,7 +1274,7 @@ test "lower MI encoding" {
1271 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");1274 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
12721275
1273 try enc.encode(.add, &.{1276 try enc.encode(.add, &.{
1274 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },1277 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
1275 .{ .imm = Immediate.u(0x10) },1278 .{ .imm = Immediate.u(0x10) },
1276 });1279 });
1277 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");1280 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
...@@ -1283,13 +1286,13 @@ test "lower MI encoding" {...@@ -1283,13 +1286,13 @@ test "lower MI encoding" {
1283 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");1286 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
12841287
1285 try enc.encode(.add, &.{1288 try enc.encode(.add, &.{
1286 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },1289 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
1287 .{ .imm = Immediate.s(-0x10) },1290 .{ .imm = Immediate.s(-0x10) },
1288 });1291 });
1289 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");1292 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
12901293
1291 try enc.encode(.@"and", &.{1294 try enc.encode(.@"and", &.{
1292 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },1295 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1293 .{ .imm = Immediate.u(0x10) },1296 .{ .imm = Immediate.u(0x10) },
1294 });1297 });
1295 try expectEqualHexStrings(1298 try expectEqualHexStrings(
...@@ -1299,7 +1302,7 @@ test "lower MI encoding" {...@@ -1299,7 +1302,7 @@ test "lower MI encoding" {
1299 );1302 );
13001303
1301 try enc.encode(.@"and", &.{1304 try enc.encode(.@"and", &.{
1302 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },1305 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
1303 .{ .imm = Immediate.u(0x10) },1306 .{ .imm = Immediate.u(0x10) },
1304 });1307 });
1305 try expectEqualHexStrings(1308 try expectEqualHexStrings(
...@@ -1309,7 +1312,7 @@ test "lower MI encoding" {...@@ -1309,7 +1312,7 @@ test "lower MI encoding" {
1309 );1312 );
13101313
1311 try enc.encode(.@"and", &.{1314 try enc.encode(.@"and", &.{
1312 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },1315 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
1313 .{ .imm = Immediate.u(0x10) },1316 .{ .imm = Immediate.u(0x10) },
1314 });1317 });
1315 try expectEqualHexStrings(1318 try expectEqualHexStrings(
...@@ -1319,7 +1322,7 @@ test "lower MI encoding" {...@@ -1319,7 +1322,7 @@ test "lower MI encoding" {
1319 );1322 );
13201323
1321 try enc.encode(.sub, &.{1324 try enc.encode(.sub, &.{
1322 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },1325 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
1323 .{ .imm = Immediate.u(0x10) },1326 .{ .imm = Immediate.u(0x10) },
1324 });1327 });
1325 try expectEqualHexStrings(1328 try expectEqualHexStrings(
...@@ -1334,26 +1337,26 @@ test "lower RM encoding" {...@@ -1334,26 +1337,26 @@ test "lower RM encoding" {
13341337
1335 try enc.encode(.mov, &.{1338 try enc.encode(.mov, &.{
1336 .{ .reg = .rax },1339 .{ .reg = .rax },
1337 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11 }) },1340 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 } }) },
1338 });1341 });
1339 try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");1342 try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
13401343
1341 try enc.encode(.mov, &.{1344 try enc.encode(.mov, &.{
1342 .{ .reg = .rbx },1345 .{ .reg = .rbx },
1343 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },1346 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) },
1344 });1347 });
1345 try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");1348 try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");
13461349
1347 try enc.encode(.mov, &.{1350 try enc.encode(.mov, &.{
1348 .{ .reg = .rax },1351 .{ .reg = .rax },
1349 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },1352 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },
1350 });1353 });
1351 try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");1354 try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");
13521355
1353 try enc.encode(.mov, &.{1356 try enc.encode(.mov, &.{
1354 .{ .reg = .rax },1357 .{ .reg = .rax },
1355 .{ .mem = Instruction.Memory.sib(.qword, .{1358 .{ .mem = Instruction.Memory.sib(.qword, .{
1356 .base = .rbp,1359 .base = .{ .reg = .rbp },
1357 .scale_index = .{ .scale = 1, .index = .rcx },1360 .scale_index = .{ .scale = 1, .index = .rcx },
1358 .disp = -8,1361 .disp = -8,
1359 }) },1362 }) },
...@@ -1363,7 +1366,7 @@ test "lower RM encoding" {...@@ -1363,7 +1366,7 @@ test "lower RM encoding" {
1363 try enc.encode(.mov, &.{1366 try enc.encode(.mov, &.{
1364 .{ .reg = .eax },1367 .{ .reg = .eax },
1365 .{ .mem = Instruction.Memory.sib(.dword, .{1368 .{ .mem = Instruction.Memory.sib(.dword, .{
1366 .base = .rbp,1369 .base = .{ .reg = .rbp },
1367 .scale_index = .{ .scale = 4, .index = .rdx },1370 .scale_index = .{ .scale = 4, .index = .rdx },
1368 .disp = -4,1371 .disp = -4,
1369 }) },1372 }) },
...@@ -1373,7 +1376,7 @@ test "lower RM encoding" {...@@ -1373,7 +1376,7 @@ test "lower RM encoding" {
1373 try enc.encode(.mov, &.{1376 try enc.encode(.mov, &.{
1374 .{ .reg = .rax },1377 .{ .reg = .rax },
1375 .{ .mem = Instruction.Memory.sib(.qword, .{1378 .{ .mem = Instruction.Memory.sib(.qword, .{
1376 .base = .rbp,1379 .base = .{ .reg = .rbp },
1377 .scale_index = .{ .scale = 8, .index = .rcx },1380 .scale_index = .{ .scale = 8, .index = .rcx },
1378 .disp = -8,1381 .disp = -8,
1379 }) },1382 }) },
...@@ -1383,7 +1386,7 @@ test "lower RM encoding" {...@@ -1383,7 +1386,7 @@ test "lower RM encoding" {
1383 try enc.encode(.mov, &.{1386 try enc.encode(.mov, &.{
1384 .{ .reg = .r8b },1387 .{ .reg = .r8b },
1385 .{ .mem = Instruction.Memory.sib(.byte, .{1388 .{ .mem = Instruction.Memory.sib(.byte, .{
1386 .base = .rsi,1389 .base = .{ .reg = .rsi },
1387 .scale_index = .{ .scale = 1, .index = .rcx },1390 .scale_index = .{ .scale = 1, .index = .rcx },
1388 .disp = -24,1391 .disp = -24,
1389 }) },1392 }) },
...@@ -1398,10 +1401,10 @@ test "lower RM encoding" {...@@ -1398,10 +1401,10 @@ test "lower RM encoding" {
1398 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");1401 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
13991402
1400 try enc.encode(.mov, &.{1403 try enc.encode(.mov, &.{
1401 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },1404 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1402 .{ .reg = .fs },1405 .{ .reg = .fs },
1403 });1406 });
1404 try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs");1407 try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
14051408
1406 try enc.encode(.mov, &.{1409 try enc.encode(.mov, &.{
1407 .{ .reg = .r12w },1410 .{ .reg = .r12w },
...@@ -1409,12 +1412,6 @@ test "lower RM encoding" {...@@ -1409,12 +1412,6 @@ test "lower RM encoding" {
1409 });1412 });
1410 try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");1413 try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");
14111414
1412 try enc.encode(.mov, &.{
1413 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
1414 .{ .reg = .fs },
1415 });
1416 try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
1417
1418 try enc.encode(.movsx, &.{1415 try enc.encode(.movsx, &.{
1419 .{ .reg = .eax },1416 .{ .reg = .eax },
1420 .{ .reg = .bx },1417 .{ .reg = .bx },
...@@ -1435,7 +1432,7 @@ test "lower RM encoding" {...@@ -1435,7 +1432,7 @@ test "lower RM encoding" {
14351432
1436 try enc.encode(.movsx, &.{1433 try enc.encode(.movsx, &.{
1437 .{ .reg = .eax },1434 .{ .reg = .eax },
1438 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },1435 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) },
1439 });1436 });
1440 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");1437 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
14411438
...@@ -1496,7 +1493,7 @@ test "lower RM encoding" {...@@ -1496,7 +1493,7 @@ test "lower RM encoding" {
1496 try enc.encode(.lea, &.{1493 try enc.encode(.lea, &.{
1497 .{ .reg = .rsi },1494 .{ .reg = .rsi },
1498 .{ .mem = Instruction.Memory.sib(.qword, .{1495 .{ .mem = Instruction.Memory.sib(.qword, .{
1499 .base = .rbp,1496 .base = .{ .reg = .rbp },
1500 .scale_index = .{ .scale = 1, .index = .rcx },1497 .scale_index = .{ .scale = 1, .index = .rcx },
1501 }) },1498 }) },
1502 });1499 });
...@@ -1504,31 +1501,31 @@ test "lower RM encoding" {...@@ -1504,31 +1501,31 @@ test "lower RM encoding" {
15041501
1505 try enc.encode(.add, &.{1502 try enc.encode(.add, &.{
1506 .{ .reg = .r11 },1503 .{ .reg = .r11 },
1507 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },1504 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1508 });1505 });
1509 try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");1506 try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");
15101507
1511 try enc.encode(.add, &.{1508 try enc.encode(.add, &.{
1512 .{ .reg = .r12b },1509 .{ .reg = .r12b },
1513 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },1510 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1514 });1511 });
1515 try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");1512 try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");
15161513
1517 try enc.encode(.add, &.{1514 try enc.encode(.add, &.{
1518 .{ .reg = .r12b },1515 .{ .reg = .r12b },
1519 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },1516 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) },
1520 });1517 });
1521 try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");1518 try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");
15221519
1523 try enc.encode(.sub, &.{1520 try enc.encode(.sub, &.{
1524 .{ .reg = .r11 },1521 .{ .reg = .r11 },
1525 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },1522 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) },
1526 });1523 });
1527 try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");1524 try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");
15281525
1529 try enc.encode(.sub, &.{1526 try enc.encode(.sub, &.{
1530 .{ .reg = .r11 },1527 .{ .reg = .r11 },
1531 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },1528 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
1532 });1529 });
1533 try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");1530 try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");
15341531
...@@ -1562,7 +1559,7 @@ test "lower RMI encoding" {...@@ -1562,7 +1559,7 @@ test "lower RMI encoding" {
15621559
1563 try enc.encode(.imul, &.{1560 try enc.encode(.imul, &.{
1564 .{ .reg = .bx },1561 .{ .reg = .bx },
1565 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },1562 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1566 .{ .imm = Immediate.s(-1024) },1563 .{ .imm = Immediate.s(-1024) },
1567 });1564 });
1568 try expectEqualHexStrings(1565 try expectEqualHexStrings(
...@@ -1573,7 +1570,7 @@ test "lower RMI encoding" {...@@ -1573,7 +1570,7 @@ test "lower RMI encoding" {
15731570
1574 try enc.encode(.imul, &.{1571 try enc.encode(.imul, &.{
1575 .{ .reg = .bx },1572 .{ .reg = .bx },
1576 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },1573 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1577 .{ .imm = Immediate.u(1024) },1574 .{ .imm = Immediate.u(1024) },
1578 });1575 });
1579 try expectEqualHexStrings(1576 try expectEqualHexStrings(
...@@ -1593,7 +1590,7 @@ test "lower MR encoding" {...@@ -1593,7 +1590,7 @@ test "lower MR encoding" {
1593 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");1590 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
15941591
1595 try enc.encode(.mov, &.{1592 try enc.encode(.mov, &.{
1596 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },1593 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },
1597 .{ .reg = .r11 },1594 .{ .reg = .r11 },
1598 });1595 });
1599 try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");1596 try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");
...@@ -1606,7 +1603,7 @@ test "lower MR encoding" {...@@ -1606,7 +1603,7 @@ test "lower MR encoding" {
16061603
1607 try enc.encode(.mov, &.{1604 try enc.encode(.mov, &.{
1608 .{ .mem = Instruction.Memory.sib(.qword, .{1605 .{ .mem = Instruction.Memory.sib(.qword, .{
1609 .base = .r11,1606 .base = .{ .reg = .r11 },
1610 .scale_index = .{ .scale = 2, .index = .r12 },1607 .scale_index = .{ .scale = 2, .index = .r12 },
1611 .disp = 0x10,1608 .disp = 0x10,
1612 }) },1609 }) },
...@@ -1622,7 +1619,7 @@ test "lower MR encoding" {...@@ -1622,7 +1619,7 @@ test "lower MR encoding" {
16221619
1623 try enc.encode(.mov, &.{1620 try enc.encode(.mov, &.{
1624 .{ .mem = Instruction.Memory.sib(.byte, .{1621 .{ .mem = Instruction.Memory.sib(.byte, .{
1625 .base = .r11,1622 .base = .{ .reg = .r11 },
1626 .scale_index = .{ .scale = 2, .index = .r12 },1623 .scale_index = .{ .scale = 2, .index = .r12 },
1627 .disp = 0x10,1624 .disp = 0x10,
1628 }) },1625 }) },
...@@ -1631,25 +1628,25 @@ test "lower MR encoding" {...@@ -1631,25 +1628,25 @@ test "lower MR encoding" {
1631 try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");1628 try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");
16321629
1633 try enc.encode(.add, &.{1630 try enc.encode(.add, &.{
1634 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },1631 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1635 .{ .reg = .r12b },1632 .{ .reg = .r12b },
1636 });1633 });
1637 try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");1634 try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");
16381635
1639 try enc.encode(.add, &.{1636 try enc.encode(.add, &.{
1640 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },1637 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1641 .{ .reg = .r12d },1638 .{ .reg = .r12d },
1642 });1639 });
1643 try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");1640 try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");
16441641
1645 try enc.encode(.add, &.{1642 try enc.encode(.add, &.{
1646 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },1643 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) },
1647 .{ .reg = .r12d },1644 .{ .reg = .r12d },
1648 });1645 });
1649 try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");1646 try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");
16501647
1651 try enc.encode(.sub, &.{1648 try enc.encode(.sub, &.{
1652 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },1649 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
1653 .{ .reg = .r12 },1650 .{ .reg = .r12 },
1654 });1651 });
1655 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");1652 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
...@@ -1664,13 +1661,13 @@ test "lower M encoding" {...@@ -1664,13 +1661,13 @@ test "lower M encoding" {
1664 try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");1661 try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
16651662
1666 try enc.encode(.call, &.{1663 try enc.encode(.call, &.{
1667 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12 }) },1664 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 } }) },
1668 });1665 });
1669 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");1666 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
16701667
1671 try enc.encode(.call, &.{1668 try enc.encode(.call, &.{
1672 .{ .mem = Instruction.Memory.sib(.qword, .{1669 .{ .mem = Instruction.Memory.sib(.qword, .{
1673 .base = null,1670 .base = .none,
1674 .scale_index = .{ .index = .r11, .scale = 2 },1671 .scale_index = .{ .index = .r11, .scale = 2 },
1675 }) },1672 }) },
1676 });1673 });
...@@ -1678,14 +1675,14 @@ test "lower M encoding" {...@@ -1678,14 +1675,14 @@ test "lower M encoding" {
16781675
1679 try enc.encode(.call, &.{1676 try enc.encode(.call, &.{
1680 .{ .mem = Instruction.Memory.sib(.qword, .{1677 .{ .mem = Instruction.Memory.sib(.qword, .{
1681 .base = null,1678 .base = .none,
1682 .scale_index = .{ .index = .r12, .scale = 2 },1679 .scale_index = .{ .index = .r12, .scale = 2 },
1683 }) },1680 }) },
1684 });1681 });
1685 try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");1682 try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
16861683
1687 try enc.encode(.call, &.{1684 try enc.encode(.call, &.{
1688 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .gs }) },1685 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .gs } }) },
1689 });1686 });
1690 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");1687 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
16911688
...@@ -1695,12 +1692,12 @@ test "lower M encoding" {...@@ -1695,12 +1692,12 @@ test "lower M encoding" {
1695 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");1692 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
16961693
1697 try enc.encode(.push, &.{1694 try enc.encode(.push, &.{
1698 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp }) },1695 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp } }) },
1699 });1696 });
1700 try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");1697 try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
17011698
1702 try enc.encode(.push, &.{1699 try enc.encode(.push, &.{
1703 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },1700 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) },
1704 });1701 });
1705 try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");1702 try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
17061703
...@@ -1913,7 +1910,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand...@@ -1913,7 +1910,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand
19131910
1914test "cannot encode" {1911test "cannot encode" {
1915 try cannotEncode(.@"test", &.{1912 try cannotEncode(.@"test", &.{
1916 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },1913 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
1917 .{ .reg = .ah },1914 .{ .reg = .ah },
1918 });1915 });
1919 try cannotEncode(.@"test", &.{1916 try cannotEncode(.@"test", &.{
...@@ -2093,7 +2090,7 @@ const Assembler = struct {...@@ -2093,7 +2090,7 @@ const Assembler = struct {
2093 pub fn assemble(as: *Assembler, writer: anytype) !void {2090 pub fn assemble(as: *Assembler, writer: anytype) !void {
2094 while (try as.next()) |parsed_inst| {2091 while (try as.next()) |parsed_inst| {
2095 const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);2092 const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
2096 try inst.encode(writer);2093 try inst.encode(writer, .{});
2097 }2094 }
2098 }2095 }
20992096
...@@ -2262,26 +2259,26 @@ const Assembler = struct {...@@ -2262,26 +2259,26 @@ const Assembler = struct {
22622259
2263 // Supported rules and orderings.2260 // Supported rules and orderings.
2264 const rules = .{2261 const rules = .{
2265 .{ .open_br, .base, .close_br }, // [ base ]2262 .{ .open_br, .general_purpose, .close_br }, // [ general_purpose ]
2266 .{ .open_br, .base, .plus, .disp, .close_br }, // [ base + disp ]2263 .{ .open_br, .general_purpose, .plus, .disp, .close_br }, // [ general_purpose + disp ]
2267 .{ .open_br, .base, .minus, .disp, .close_br }, // [ base - disp ]2264 .{ .open_br, .general_purpose, .minus, .disp, .close_br }, // [ general_purpose - disp ]
2268 .{ .open_br, .disp, .plus, .base, .close_br }, // [ disp + base ]2265 .{ .open_br, .disp, .plus, .general_purpose, .close_br }, // [ disp + general_purpose ]
2269 .{ .open_br, .base, .plus, .index, .close_br }, // [ base + index ]2266 .{ .open_br, .general_purpose, .plus, .index, .close_br }, // [ general_purpose + index ]
2270 .{ .open_br, .base, .plus, .index, .star, .scale, .close_br }, // [ base + index * scale ]2267 .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .close_br }, // [ general_purpose + index * scale ]
2271 .{ .open_br, .index, .star, .scale, .plus, .base, .close_br }, // [ index * scale + base ]2268 .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .close_br }, // [ index * scale + general_purpose ]
2272 .{ .open_br, .base, .plus, .index, .star, .scale, .plus, .disp, .close_br }, // [ base + index * scale + disp ]2269 .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .plus, .disp, .close_br }, // [ general_purpose + index * scale + disp ]
2273 .{ .open_br, .base, .plus, .index, .star, .scale, .minus, .disp, .close_br }, // [ base + index * scale - disp ]2270 .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .minus, .disp, .close_br }, // [ general_purpose + index * scale - disp ]
2274 .{ .open_br, .index, .star, .scale, .plus, .base, .plus, .disp, .close_br }, // [ index * scale + base + disp ]2271 .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .plus, .disp, .close_br }, // [ index * scale + general_purpose + disp ]
2275 .{ .open_br, .index, .star, .scale, .plus, .base, .minus, .disp, .close_br }, // [ index * scale + base - disp ]2272 .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .minus, .disp, .close_br }, // [ index * scale + general_purpose - disp ]
2276 .{ .open_br, .disp, .plus, .index, .star, .scale, .plus, .base, .close_br }, // [ disp + index * scale + base ]2273 .{ .open_br, .disp, .plus, .index, .star, .scale, .plus, .general_purpose, .close_br }, // [ disp + index * scale + general_purpose ]
2277 .{ .open_br, .disp, .plus, .base, .plus, .index, .star, .scale, .close_br }, // [ disp + base + index * scale ]2274 .{ .open_br, .disp, .plus, .general_purpose, .plus, .index, .star, .scale, .close_br }, // [ disp + general_purpose + index * scale ]
2278 .{ .open_br, .base, .plus, .disp, .plus, .index, .star, .scale, .close_br }, // [ base + disp + index * scale ]2275 .{ .open_br, .general_purpose, .plus, .disp, .plus, .index, .star, .scale, .close_br }, // [ general_purpose + disp + index * scale ]
2279 .{ .open_br, .base, .minus, .disp, .plus, .index, .star, .scale, .close_br }, // [ base - disp + index * scale ]2276 .{ .open_br, .general_purpose, .minus, .disp, .plus, .index, .star, .scale, .close_br }, // [ general_purpose - disp + index * scale ]
2280 .{ .open_br, .base, .plus, .disp, .plus, .scale, .star, .index, .close_br }, // [ base + disp + scale * index ]2277 .{ .open_br, .general_purpose, .plus, .disp, .plus, .scale, .star, .index, .close_br }, // [ general_purpose + disp + scale * index ]
2281 .{ .open_br, .base, .minus, .disp, .plus, .scale, .star, .index, .close_br }, // [ base - disp + scale * index ]2278 .{ .open_br, .general_purpose, .minus, .disp, .plus, .scale, .star, .index, .close_br }, // [ general_purpose - disp + scale * index ]
2282 .{ .open_br, .rip, .plus, .disp, .close_br }, // [ rip + disp ]2279 .{ .open_br, .rip, .plus, .disp, .close_br }, // [ rip + disp ]
2283 .{ .open_br, .rip, .minus, .disp, .close_br }, // [ rig - disp ]2280 .{ .open_br, .rip, .minus, .disp, .close_br }, // [ rig - disp ]
2284 .{ .base, .colon, .disp }, // seg:disp2281 .{ .segment, .colon, .disp }, // seg:disp
2285 };2282 };
22862283
2287 const pos = as.it.pos;2284 const pos = as.it.pos;
...@@ -2301,7 +2298,7 @@ const Assembler = struct {...@@ -2301,7 +2298,7 @@ const Assembler = struct {
2301 return Instruction.Memory.moffs(base, offset);2298 return Instruction.Memory.moffs(base, offset);
2302 }2299 }
2303 return Instruction.Memory.sib(ptr_size orelse .qword, .{2300 return Instruction.Memory.sib(ptr_size orelse .qword, .{
2304 .base = base,2301 .base = .{ .reg = base },
2305 .scale_index = res.scale_index,2302 .scale_index = res.scale_index,
2306 .disp = res.disp orelse 0,2303 .disp = res.disp orelse 0,
2307 });2304 });
...@@ -2323,7 +2320,7 @@ const Assembler = struct {...@@ -2323,7 +2320,7 @@ const Assembler = struct {
2323 offset: ?u64 = null,2320 offset: ?u64 = null,
2324 };2321 };
23252322
2326 fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!Instruction.MemoryParseResult {2323 fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!MemoryParseResult {
2327 var res: MemoryParseResult = .{};2324 var res: MemoryParseResult = .{};
2328 inline for (rule, 0..) |cond, i| {2325 inline for (rule, 0..) |cond, i| {
2329 if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) {2326 if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) {
...@@ -2333,9 +2330,11 @@ const Assembler = struct {...@@ -2333,9 +2330,11 @@ const Assembler = struct {
2333 .open_br, .close_br, .plus, .minus, .star, .colon => {2330 .open_br, .close_br, .plus, .minus, .star, .colon => {
2334 _ = try as.expect(cond);2331 _ = try as.expect(cond);
2335 },2332 },
2336 .base => {2333 .general_purpose, .segment => {
2337 const tok = try as.expect(.string);2334 const tok = try as.expect(.string);
2338 res.base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand;2335 const base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand;
2336 if (base.class() != cond) return error.InvalidMemoryOperand;
2337 res.base = base;
2339 },2338 },
2340 .rip => {2339 .rip => {
2341 const tok = try as.expect(.string);2340 const tok = try as.expect(.string);
...@@ -2529,8 +2528,8 @@ test "assemble" {...@@ -2529,8 +2528,8 @@ test "assemble" {
2529 0xF3, 0x45, 0x0F, 0x10, 0xF9,2528 0xF3, 0x45, 0x0F, 0x10, 0xF9,
2530 0xF2, 0x44, 0x0F, 0x10, 0x45, 0xF0,2529 0xF2, 0x44, 0x0F, 0x10, 0x45, 0xF0,
2531 0xF2, 0x0F, 0x11, 0x45, 0xF8,2530 0xF2, 0x0F, 0x11, 0x45, 0xF8,
2532 0xF3, 0x44, 0x0F, 0x7E, 0x45, 0xF0,2531 0x66, 0x4C, 0x0F, 0x6E, 0x45, 0xF0,
2533 0x66, 0x44, 0x0F, 0xD6, 0x45, 0xF0,2532 0x66, 0x4C, 0x0F, 0x7E, 0x45, 0xF0,
2534 0x66, 0x0F, 0x2E, 0x45, 0xF0,2533 0x66, 0x0F, 0x2E, 0x45, 0xF0,
2535 0xDD, 0x4D, 0xF0,2534 0xDD, 0x4D, 0xF0,
2536 0xDF, 0x0D, 0x20, 0x00, 0x00, 0x00,2535 0xDF, 0x0D, 0x20, 0x00, 0x00, 0x00,