aboutsummaryrefslogtreecommitdiff
path: root/src/arch/x86_64/encoder.zig
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-03-20 23:02:31 -0400
committerJakub Konka <kubkon@jakubkonka.com>2023-03-21 08:49:54 +0100
commitc58b5732f381fe4f145537501e29347be01e2a44 (patch)
tree10dbb755d5323d9ca4fd3ddfb88c78a8bd980ce7 /src/arch/x86_64/encoder.zig
parentf316cb29cc094c37be191f1eb72ee70eb0dc99ee (diff)
downloadzig-c58b5732f381fe4f145537501e29347be01e2a44.tar.gz
zig-c58b5732f381fe4f145537501e29347be01e2a44.zip
x86_64: implement @byteSwap and @bitReverse
Diffstat (limited to 'src/arch/x86_64/encoder.zig')
-rw-r--r--src/arch/x86_64/encoder.zig121
1 files changed, 49 insertions, 72 deletions
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index 519158d012..b3de7ec1bd 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -211,14 +211,12 @@ pub const Instruction = struct {
fn encodeOpcode(inst: Instruction, encoder: anytype) !void {
const opcode = inst.encoding.opcode();
+ const first = @boolToInt(inst.encoding.mandatoryPrefix() != null);
+ const final = opcode.len - 1;
+ for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);
switch (inst.encoding.op_en) {
- .o, .oi => try encoder.opcode_withReg(opcode[0], inst.op1.reg.lowEnc()),
- else => {
- const index: usize = if (inst.encoding.mandatoryPrefix()) |_| 1 else 0;
- for (opcode[index..]) |byte| {
- try encoder.opcode_1byte(byte);
- }
- },
+ .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()),
+ else => try encoder.opcode_1byte(opcode[final]),
}
}
@@ -896,10 +894,10 @@ test "lower MI encoding" {
try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
- try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{
- .base = .r12,
- .disp = 0,
- }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
+ try enc.encode(.mov, .{
+ .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
+ .op2 = .{ .imm = Immediate.u(0x10) },
+ });
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
@@ -911,10 +909,10 @@ test "lower MI encoding" {
try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } });
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
- try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.dword, .{
- .base = .r11,
- .disp = 0,
- }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
+ try enc.encode(.mov, .{
+ .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
+ .op2 = .{ .imm = Immediate.u(0x10) },
+ });
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
try enc.encode(.mov, .{
@@ -1030,10 +1028,10 @@ test "lower MI encoding" {
test "lower RM encoding" {
var enc = TestEncode{};
- try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{
- .base = .r11,
- .disp = 0,
- }) } });
+ try enc.encode(.mov, .{
+ .op1 = .{ .reg = .rax },
+ .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
+ });
try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{
@@ -1116,20 +1114,16 @@ test "lower RM encoding" {
try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } });
try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl");
- try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.word, .{
- .base = .rbp,
- .disp = 0,
- }) } });
+ try enc.encode(.movsx, .{
+ .op1 = .{ .reg = .eax },
+ .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
+ });
try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
- try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.byte, .{
- .base = null,
- .scale_index = .{
- .index = .rax,
- .scale = 2,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.movsx, .{
+ .op1 = .{ .reg = .eax },
+ .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
+ });
try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");
try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } });
@@ -1156,14 +1150,13 @@ test "lower RM encoding" {
try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } });
try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");
- try enc.encode(.lea, .{ .op1 = .{ .reg = .rsi }, .op2 = .{ .mem = Memory.sib(.qword, .{
- .base = .rbp,
- .scale_index = .{
- .scale = 1,
- .index = .rcx,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.lea, .{
+ .op1 = .{ .reg = .rsi },
+ .op2 = .{ .mem = Memory.sib(.qword, .{
+ .base = .rbp,
+ .scale_index = .{ .scale = 1, .index = .rcx },
+ }) },
+ });
try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]");
try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{
@@ -1319,51 +1312,35 @@ test "lower M encoding" {
try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } });
try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = .r12,
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) } });
try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = null,
- .scale_index = .{
- .index = .r11,
- .scale = 2,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{
+ .op1 = .{ .mem = Memory.sib(.qword, .{
+ .base = null,
+ .scale_index = .{ .index = .r11, .scale = 2 },
+ }) },
+ });
try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = null,
- .scale_index = .{
- .index = .r12,
- .scale = 2,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{
+ .op1 = .{ .mem = Memory.sib(.qword, .{
+ .base = null,
+ .scale_index = .{ .index = .r12, .scale = 2 },
+ }) },
+ });
try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = .gs,
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .gs }) } });
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } });
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
- try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = .rbp,
- .disp = 0,
- }) } });
+ try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) } });
try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
- try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{
- .base = .rbp,
- .disp = 0,
- }) } });
+ try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) } });
try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) } });
@@ -1491,7 +1468,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
test "cannot encode" {
try cannotEncode(.@"test", .{
- .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12, .disp = 0 }) },
+ .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
.op2 = .{ .reg = .ah },
});
try cannotEncode(.@"test", .{