mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
x86_64: refactor codegen memory repr
Also refactor linker reloc lowering.
This commit is contained in:
parent
20ade4ce7f
commit
1fecf86ebf
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ const Encoding = @import("Encoding.zig");
|
||||
const Immediate = bits.Immediate;
|
||||
const Instruction = encoder.Instruction;
|
||||
const LegacyPrefixes = encoder.LegacyPrefixes;
|
||||
const Memory = bits.Memory;
|
||||
const Memory = Instruction.Memory;
|
||||
const Register = bits.Register;
|
||||
const Rex = encoder.Rex;
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
//! This file contains the functionality for emitting x86_64 MIR as machine code
|
||||
|
||||
lower: Lower,
|
||||
bin_file: *link.File,
|
||||
debug_output: DebugInfoOutput,
|
||||
code: *std.ArrayList(u8),
|
||||
|
||||
@ -41,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.offset = end_offset - 4,
|
||||
.length = @intCast(end_offset - start_offset),
|
||||
}),
|
||||
.linker_extern_fn => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
.linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
// Add relocation to the decl.
|
||||
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
|
||||
try atom_ptr.addReloc(elf_file, .{
|
||||
@ -49,9 +48,10 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | std.elf.R_X86_64_PLT32,
|
||||
.r_addend = -4,
|
||||
});
|
||||
} else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
// Add relocation to the decl.
|
||||
const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
|
||||
const atom_index =
|
||||
macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
|
||||
const target = macho_file.getGlobalByIndex(symbol.sym_index);
|
||||
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
|
||||
.type = .branch,
|
||||
@ -61,7 +61,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.pcrel = true,
|
||||
.length = 2,
|
||||
});
|
||||
} else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
} else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
// Add relocation to the decl.
|
||||
const atom_index = coff_file.getAtomIndexForSymbol(
|
||||
.{ .sym_index = symbol.atom_index, .file = null },
|
||||
@ -76,12 +76,12 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.length = 2,
|
||||
});
|
||||
} else return emit.fail("TODO implement extern reloc for {s}", .{
|
||||
@tagName(emit.bin_file.tag),
|
||||
@tagName(emit.lower.bin_file.tag),
|
||||
}),
|
||||
.linker_reloc => |data| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
.linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
|
||||
const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(data.sym_index));
|
||||
if (emit.bin_file.options.pic) {
|
||||
if (emit.lower.bin_file.options.pic) {
|
||||
const r_type: u32 = if (sym.flags.has_zig_got)
|
||||
link.File.Elf.R_X86_64_ZIG_GOTPCREL
|
||||
else if (sym.flags.needs_got)
|
||||
@ -111,10 +111,11 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.linker_direct,
|
||||
.linker_import,
|
||||
.linker_tlv,
|
||||
=> |symbol| if (emit.bin_file.cast(link.File.Elf)) |_| {
|
||||
=> |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |_| {
|
||||
unreachable;
|
||||
} else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
|
||||
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
const atom_index =
|
||||
macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
|
||||
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
|
||||
.type = switch (lowered_relocs[0].target) {
|
||||
.linker_got => .got,
|
||||
@ -128,7 +129,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.pcrel = true,
|
||||
.length = 2,
|
||||
});
|
||||
} else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
} else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
const atom_index = coff_file.getAtomIndexForSymbol(.{
|
||||
.sym_index = symbol.atom_index,
|
||||
.file = null,
|
||||
@ -152,7 +153,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.pcrel = true,
|
||||
.length = 2,
|
||||
});
|
||||
} else if (emit.bin_file.cast(link.File.Plan9)) |p9_file| {
|
||||
} else if (emit.lower.bin_file.cast(link.File.Plan9)) |p9_file| {
|
||||
const atom_index = symbol.atom_index;
|
||||
try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct
|
||||
.target = symbol.sym_index, // we set sym_index to just be the atom index
|
||||
@ -161,7 +162,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.type = .pcrel,
|
||||
});
|
||||
} else return emit.fail("TODO implement linker reloc for {s}", .{
|
||||
@tagName(emit.bin_file.tag),
|
||||
@tagName(emit.lower.bin_file.tag),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@ -803,7 +803,10 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
|
||||
@memcpy(inst.ops[0..ops.len], ops);
|
||||
|
||||
var cwriter = std.io.countingWriter(std.io.null_writer);
|
||||
inst.encode(cwriter.writer(), .{ .allow_frame_loc = true }) catch unreachable; // Not allowed to fail here unless OOM.
|
||||
inst.encode(cwriter.writer(), .{
|
||||
.allow_frame_locs = true,
|
||||
.allow_symbols = true,
|
||||
}) catch unreachable; // Not allowed to fail here unless OOM.
|
||||
return @as(usize, @intCast(cwriter.bytes_written));
|
||||
}
|
||||
|
||||
|
||||
@ -50,12 +50,12 @@ pub const Reloc = struct {
|
||||
|
||||
const Target = union(enum) {
|
||||
inst: Mir.Inst.Index,
|
||||
linker_reloc: Mir.Reloc,
|
||||
linker_extern_fn: Mir.Reloc,
|
||||
linker_got: Mir.Reloc,
|
||||
linker_direct: Mir.Reloc,
|
||||
linker_import: Mir.Reloc,
|
||||
linker_tlv: Mir.Reloc,
|
||||
linker_reloc: bits.Symbol,
|
||||
linker_extern_fn: bits.Symbol,
|
||||
linker_got: bits.Symbol,
|
||||
linker_direct: bits.Symbol,
|
||||
linker_import: bits.Symbol,
|
||||
linker_tlv: bits.Symbol,
|
||||
};
|
||||
};
|
||||
|
||||
@ -99,17 +99,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
.{ .reg = inst.data.rr.r2 },
|
||||
});
|
||||
},
|
||||
.pseudo_cmov_nz_or_p_rm_sib,
|
||||
.pseudo_cmov_nz_or_p_rm_rip,
|
||||
=> {
|
||||
.pseudo_cmov_nz_or_p_rm => {
|
||||
assert(inst.data.rx.fixes == ._);
|
||||
try lower.emit(.none, .cmovnz, &.{
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
});
|
||||
try lower.emit(.none, .cmovp, &.{
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
});
|
||||
},
|
||||
.pseudo_set_z_and_np_r => {
|
||||
@ -125,18 +123,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
.{ .reg = inst.data.rr.r2 },
|
||||
});
|
||||
},
|
||||
.pseudo_set_z_and_np_m_sib,
|
||||
.pseudo_set_z_and_np_m_rip,
|
||||
=> {
|
||||
.pseudo_set_z_and_np_m => {
|
||||
assert(inst.data.rx.fixes == ._);
|
||||
try lower.emit(.none, .setz, &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
});
|
||||
try lower.emit(.none, .setnp, &.{
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
});
|
||||
try lower.emit(.none, .@"and", &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
});
|
||||
},
|
||||
@ -153,18 +149,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
.{ .reg = inst.data.rr.r2 },
|
||||
});
|
||||
},
|
||||
.pseudo_set_nz_or_p_m_sib,
|
||||
.pseudo_set_nz_or_p_m_rip,
|
||||
=> {
|
||||
.pseudo_set_nz_or_p_m => {
|
||||
assert(inst.data.rx.fixes == ._);
|
||||
try lower.emit(.none, .setnz, &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
});
|
||||
try lower.emit(.none, .setp, &.{
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
});
|
||||
try lower.emit(.none, .@"or", &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
});
|
||||
},
|
||||
@ -289,28 +283,20 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
.rri_s,
|
||||
.ri_s,
|
||||
.i_s,
|
||||
.mi_sib_s,
|
||||
.mi_rip_s,
|
||||
.rmi_sib_s,
|
||||
.rmi_rip_s,
|
||||
.mi_s,
|
||||
.rmi_s,
|
||||
=> Immediate.s(@bitCast(i)),
|
||||
|
||||
.rrri,
|
||||
.rri_u,
|
||||
.ri_u,
|
||||
.i_u,
|
||||
.mi_sib_u,
|
||||
.mi_rip_u,
|
||||
.rmi_sib,
|
||||
.rmi_rip,
|
||||
.rmi_sib_u,
|
||||
.rmi_rip_u,
|
||||
.mri_sib,
|
||||
.mri_rip,
|
||||
.rrm_sib,
|
||||
.rrm_rip,
|
||||
.rrmi_sib,
|
||||
.rrmi_rip,
|
||||
.mi_u,
|
||||
.rmi,
|
||||
.rmi_u,
|
||||
.mri,
|
||||
.rrm,
|
||||
.rrmi,
|
||||
=> Immediate.u(i),
|
||||
|
||||
.ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
|
||||
@ -319,50 +305,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
};
|
||||
}
|
||||
|
||||
fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
|
||||
return lower.mir.resolveFrameLoc(switch (ops) {
|
||||
.rm_sib,
|
||||
.rmi_sib,
|
||||
.rmi_sib_s,
|
||||
.rmi_sib_u,
|
||||
.m_sib,
|
||||
.mi_sib_u,
|
||||
.mi_sib_s,
|
||||
.mr_sib,
|
||||
.mrr_sib,
|
||||
.mri_sib,
|
||||
.rrm_sib,
|
||||
.rrmi_sib,
|
||||
|
||||
.pseudo_cmov_nz_or_p_rm_sib,
|
||||
.pseudo_set_z_and_np_m_sib,
|
||||
.pseudo_set_nz_or_p_m_sib,
|
||||
=> lower.mir.extraData(Mir.MemorySib, payload).data.decode(),
|
||||
|
||||
.rm_rip,
|
||||
.rmi_rip,
|
||||
.rmi_rip_s,
|
||||
.rmi_rip_u,
|
||||
.m_rip,
|
||||
.mi_rip_u,
|
||||
.mi_rip_s,
|
||||
.mr_rip,
|
||||
.mrr_rip,
|
||||
.mri_rip,
|
||||
.rrm_rip,
|
||||
.rrmi_rip,
|
||||
|
||||
.pseudo_cmov_nz_or_p_rm_rip,
|
||||
.pseudo_set_z_and_np_m_rip,
|
||||
.pseudo_set_nz_or_p_m_rip,
|
||||
=> lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),
|
||||
|
||||
.rax_moffs,
|
||||
.moffs_rax,
|
||||
=> lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),
|
||||
|
||||
else => unreachable,
|
||||
});
|
||||
fn mem(lower: Lower, payload: u32) Memory {
|
||||
return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
|
||||
}
|
||||
|
||||
fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
|
||||
@ -375,7 +319,42 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
|
||||
}
|
||||
|
||||
fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
|
||||
lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
|
||||
var emit_prefix = prefix;
|
||||
var emit_mnemonic = mnemonic;
|
||||
var emit_ops_storage: [4]Operand = undefined;
|
||||
const emit_ops = emit_ops_storage[0..ops.len];
|
||||
for (emit_ops, ops) |*emit_op, op| {
|
||||
emit_op.* = switch (op) {
|
||||
else => op,
|
||||
.mem => |mem_op| switch (mem_op.base()) {
|
||||
else => op,
|
||||
.reloc => |sym| op: {
|
||||
assert(prefix == .none);
|
||||
assert(mem_op.sib.disp == 0);
|
||||
assert(mem_op.sib.scale_index.scale == 0);
|
||||
_ = lower.reloc(.{ .linker_reloc = sym });
|
||||
break :op if (lower.bin_file.options.pic) switch (mnemonic) {
|
||||
.mov, .lea => .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },
|
||||
else => unreachable,
|
||||
} else switch (mnemonic) {
|
||||
.call => .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
|
||||
.base = .{ .reg = .ds },
|
||||
}) },
|
||||
.lea => {
|
||||
emit_mnemonic = .mov;
|
||||
break :op .{ .imm = Immediate.s(0) };
|
||||
},
|
||||
.mov => .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
|
||||
.base = .{ .reg = .ds },
|
||||
}) },
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(emit_prefix, emit_mnemonic, emit_ops);
|
||||
lower.result_insts_len += 1;
|
||||
}
|
||||
|
||||
@ -391,74 +370,13 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
.rrri => inst.data.rrri.fixes,
|
||||
.rri_s, .rri_u => inst.data.rri.fixes,
|
||||
.ri_s, .ri_u => inst.data.ri.fixes,
|
||||
.ri64,
|
||||
.rm_sib,
|
||||
.rm_rip,
|
||||
.rmi_sib_s,
|
||||
.rmi_sib_u,
|
||||
.rmi_rip_s,
|
||||
.rmi_rip_u,
|
||||
.mr_sib,
|
||||
.mr_rip,
|
||||
=> inst.data.rx.fixes,
|
||||
.mrr_sib, .mrr_rip, .rrm_sib, .rrm_rip => inst.data.rrx.fixes,
|
||||
.rmi_sib, .rmi_rip, .mri_sib, .mri_rip => inst.data.rix.fixes,
|
||||
.rrmi_sib, .rrmi_rip => inst.data.rrix.fixes,
|
||||
.mi_sib_u, .mi_rip_u, .mi_sib_s, .mi_rip_s => inst.data.x.fixes,
|
||||
.m_sib, .m_rip, .rax_moffs, .moffs_rax => inst.data.x.fixes,
|
||||
.extern_fn_reloc,
|
||||
.got_reloc,
|
||||
.direct_reloc,
|
||||
.import_reloc,
|
||||
.tlv_reloc,
|
||||
=> ._,
|
||||
.linker_reloc => {
|
||||
if (lower.bin_file.options.pic) {
|
||||
assert(inst.data.rx.fixes == ._);
|
||||
const reg = inst.data.rx.r1;
|
||||
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
|
||||
_ = lower.reloc(.{ .linker_reloc = extra });
|
||||
const mnemonic: Mnemonic = switch (inst.tag) {
|
||||
.mov => .mov,
|
||||
.lea => .lea,
|
||||
else => unreachable,
|
||||
};
|
||||
try lower.emit(.none, mnemonic, &.{
|
||||
.{ .reg = reg },
|
||||
.{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
|
||||
});
|
||||
} else {
|
||||
switch (inst.tag) {
|
||||
.call => {
|
||||
_ = lower.reloc(.{ .linker_reloc = inst.data.reloc });
|
||||
try lower.emit(.none, .call, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
|
||||
});
|
||||
},
|
||||
.lea => {
|
||||
assert(inst.data.rx.fixes == ._);
|
||||
const reg = inst.data.rx.r1;
|
||||
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
|
||||
try lower.emit(.none, .mov, &.{
|
||||
.{ .reg = reg },
|
||||
.{ .imm = lower.reloc(.{ .linker_reloc = extra }) },
|
||||
});
|
||||
},
|
||||
.mov => {
|
||||
assert(inst.data.rx.fixes == ._);
|
||||
const reg = inst.data.rx.r1;
|
||||
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
|
||||
_ = lower.reloc(.{ .linker_reloc = extra });
|
||||
try lower.emit(.none, .mov, &.{
|
||||
.{ .reg = reg },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
|
||||
});
|
||||
},
|
||||
else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
|
||||
}
|
||||
}
|
||||
return;
|
||||
},
|
||||
.ri64, .rm, .rmi_s, .mr => inst.data.rx.fixes,
|
||||
.mrr, .rrm => inst.data.rrx.fixes,
|
||||
.rmi, .mri => inst.data.rix.fixes,
|
||||
.rrmi => inst.data.rrix.fixes,
|
||||
.mi_u, .mi_s => inst.data.x.fixes,
|
||||
.m => inst.data.x.fixes,
|
||||
.extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._,
|
||||
else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
|
||||
};
|
||||
try lower.emit(switch (fixes) {
|
||||
@ -527,73 +445,64 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
.{ .reg = inst.data.rri.r2 },
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.rri.i) },
|
||||
},
|
||||
.m_sib, .m_rip => &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
|
||||
.m => &.{
|
||||
.{ .mem = lower.mem(inst.data.x.payload) },
|
||||
},
|
||||
.mi_sib_s, .mi_sib_u, .mi_rip_s, .mi_rip_u => &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.x.payload + 1) },
|
||||
.mi_s, .mi_u => &.{
|
||||
.{ .mem = lower.mem(inst.data.x.payload + 1) },
|
||||
.{ .imm = lower.imm(
|
||||
inst.ops,
|
||||
lower.mir.extraData(Mir.Imm32, inst.data.x.payload).data.imm,
|
||||
) },
|
||||
},
|
||||
.rm_sib, .rm_rip => &.{
|
||||
.rm => &.{
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
},
|
||||
.rmi_sib, .rmi_rip => &.{
|
||||
.rmi => &.{
|
||||
.{ .reg = inst.data.rix.r1 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rix.payload) },
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
|
||||
},
|
||||
.rmi_sib_s, .rmi_sib_u, .rmi_rip_s, .rmi_rip_u => &.{
|
||||
.rmi_s, .rmi_u => &.{
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload + 1) },
|
||||
.{ .mem = lower.mem(inst.data.rx.payload + 1) },
|
||||
.{ .imm = lower.imm(
|
||||
inst.ops,
|
||||
lower.mir.extraData(Mir.Imm32, inst.data.rx.payload).data.imm,
|
||||
) },
|
||||
},
|
||||
.mr_sib, .mr_rip => &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
|
||||
.mr => &.{
|
||||
.{ .mem = lower.mem(inst.data.rx.payload) },
|
||||
.{ .reg = inst.data.rx.r1 },
|
||||
},
|
||||
.mrr_sib, .mrr_rip => &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
|
||||
.mrr => &.{
|
||||
.{ .mem = lower.mem(inst.data.rrx.payload) },
|
||||
.{ .reg = inst.data.rrx.r1 },
|
||||
.{ .reg = inst.data.rrx.r2 },
|
||||
},
|
||||
.mri_sib, .mri_rip => &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
|
||||
.mri => &.{
|
||||
.{ .mem = lower.mem(inst.data.rix.payload) },
|
||||
.{ .reg = inst.data.rix.r1 },
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
|
||||
},
|
||||
.rrm_sib, .rrm_rip => &.{
|
||||
.rrm => &.{
|
||||
.{ .reg = inst.data.rrx.r1 },
|
||||
.{ .reg = inst.data.rrx.r2 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rrx.payload) },
|
||||
},
|
||||
.rrmi_sib, .rrmi_rip => &.{
|
||||
.rrmi => &.{
|
||||
.{ .reg = inst.data.rrix.r1 },
|
||||
.{ .reg = inst.data.rrix.r2 },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.rrix.payload) },
|
||||
.{ .mem = lower.mem(inst.data.rrix.payload) },
|
||||
.{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
|
||||
},
|
||||
.rax_moffs => &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
|
||||
},
|
||||
.moffs_rax => &.{
|
||||
.{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
|
||||
.{ .reg = .rax },
|
||||
},
|
||||
.extern_fn_reloc => &.{
|
||||
.{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
|
||||
},
|
||||
.linker_reloc => unreachable,
|
||||
.got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
|
||||
const reg = inst.data.rx.r1;
|
||||
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
|
||||
const extra = lower.mir.extraData(bits.Symbol, inst.data.rx.payload).data;
|
||||
_ = lower.reloc(switch (inst.ops) {
|
||||
.got_reloc => .{ .linker_got = extra },
|
||||
.direct_reloc => .{ .linker_direct = extra },
|
||||
@ -635,7 +544,7 @@ const ErrorMsg = Module.ErrorMsg;
|
||||
const Immediate = bits.Immediate;
|
||||
const Instruction = encoder.Instruction;
|
||||
const Lower = @This();
|
||||
const Memory = bits.Memory;
|
||||
const Memory = Instruction.Memory;
|
||||
const Mir = @import("Mir.zig");
|
||||
const Mnemonic = Instruction.Mnemonic;
|
||||
const Module = @import("../../Module.zig");
|
||||
|
||||
@ -17,7 +17,6 @@ const encoder = @import("encoder.zig");
|
||||
const Air = @import("../../Air.zig");
|
||||
const CodeGen = @import("CodeGen.zig");
|
||||
const IntegerBitSet = std.bit_set.IntegerBitSet;
|
||||
const Memory = bits.Memory;
|
||||
const Register = bits.Register;
|
||||
|
||||
instructions: std.MultiArrayList(Inst).Slice,
|
||||
@ -767,84 +766,42 @@ pub const Inst = struct {
|
||||
/// Relative displacement operand.
|
||||
/// Uses `imm` payload.
|
||||
rel,
|
||||
/// Register, memory (SIB) operands.
|
||||
/// Register, memory operands.
|
||||
/// Uses `rx` payload.
|
||||
rm_sib,
|
||||
/// Register, memory (RIP) operands.
|
||||
/// Uses `rx` payload.
|
||||
rm_rip,
|
||||
/// Register, memory (SIB), immediate (word) operands.
|
||||
/// Uses `rix` payload with extra data of type `MemorySib`.
|
||||
rmi_sib,
|
||||
/// Register, memory (RIP), immediate (word) operands.
|
||||
/// Uses `rix` payload with extra data of type `MemoryRip`.
|
||||
rmi_rip,
|
||||
/// Register, memory (SIB), immediate (signed) operands.
|
||||
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemorySib`.
|
||||
rmi_sib_s,
|
||||
/// Register, memory (SIB), immediate (unsigned) operands.
|
||||
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemorySib`.
|
||||
rmi_sib_u,
|
||||
/// Register, memory (RIP), immediate (signed) operands.
|
||||
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemoryRip`.
|
||||
rmi_rip_s,
|
||||
/// Register, memory (RIP), immediate (unsigned) operands.
|
||||
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemoryRip`.
|
||||
rmi_rip_u,
|
||||
/// Register, register, memory (RIP).
|
||||
/// Uses `rrix` payload with extra data of type `MemoryRip`.
|
||||
rrm_rip,
|
||||
/// Register, register, memory (SIB).
|
||||
/// Uses `rrix` payload with extra data of type `MemorySib`.
|
||||
rrm_sib,
|
||||
/// Register, register, memory (RIP), immediate (byte) operands.
|
||||
/// Uses `rrix` payload with extra data of type `MemoryRip`.
|
||||
rrmi_rip,
|
||||
/// Register, register, memory (SIB), immediate (byte) operands.
|
||||
/// Uses `rrix` payload with extra data of type `MemorySib`.
|
||||
rrmi_sib,
|
||||
/// Single memory (SIB) operand.
|
||||
/// Uses `x` with extra data of type `MemorySib`.
|
||||
m_sib,
|
||||
/// Single memory (RIP) operand.
|
||||
/// Uses `x` with extra data of type `MemoryRip`.
|
||||
m_rip,
|
||||
/// Memory (SIB), immediate (sign-extend) operands.
|
||||
/// Uses `x` payload with extra data of type `Imm32` followed by `MemorySib`.
|
||||
mi_sib_s,
|
||||
/// Memory (SIB), immediate (unsigned) operands.
|
||||
/// Uses `x` payload with extra data of type `Imm32` followed by `MemorySib`.
|
||||
mi_sib_u,
|
||||
/// Memory (RIP), immediate (sign-extend) operands.
|
||||
/// Uses `x` payload with extra data of type `Imm32` followed by `MemoryRip`.
|
||||
mi_rip_s,
|
||||
/// Memory (RIP), immediate (unsigned) operands.
|
||||
/// Uses `x` payload with extra data of type `Imm32` followed by `MemoryRip`.
|
||||
mi_rip_u,
|
||||
/// Memory (SIB), register operands.
|
||||
/// Uses `rx` payload with extra data of type `MemorySib`.
|
||||
mr_sib,
|
||||
/// Memory (RIP), register operands.
|
||||
/// Uses `rx` payload with extra data of type `MemoryRip`.
|
||||
mr_rip,
|
||||
/// Memory (SIB), register, register operands.
|
||||
/// Uses `rrx` payload with extra data of type `MemorySib`.
|
||||
mrr_sib,
|
||||
/// Memory (RIP), register, register operands.
|
||||
/// Uses `rrx` payload with extra data of type `MemoryRip`.
|
||||
mrr_rip,
|
||||
/// Memory (SIB), register, immediate (word) operands.
|
||||
/// Uses `rix` payload with extra data of type `MemorySib`.
|
||||
mri_sib,
|
||||
/// Memory (RIP), register, immediate (word) operands.
|
||||
/// Uses `rix` payload with extra data of type `MemoryRip`.
|
||||
mri_rip,
|
||||
/// Rax, Memory moffs.
|
||||
/// Uses `x` with extra data of type `MemoryMoffs`.
|
||||
rax_moffs,
|
||||
/// Memory moffs, rax.
|
||||
/// Uses `x` with extra data of type `MemoryMoffs`.
|
||||
moffs_rax,
|
||||
rm,
|
||||
/// Register, memory, immediate (word) operands.
|
||||
/// Uses `rix` payload with extra data of type `Memory`.
|
||||
rmi,
|
||||
/// Register, memory, immediate (signed) operands.
|
||||
/// Uses `rx` payload with extra data of type `Imm32` followed by `Memory`.
|
||||
rmi_s,
|
||||
/// Register, memory, immediate (unsigned) operands.
|
||||
/// Uses `rx` payload with extra data of type `Imm32` followed by `Memory`.
|
||||
rmi_u,
|
||||
/// Register, register, memory.
|
||||
/// Uses `rrix` payload with extra data of type `Memory`.
|
||||
rrm,
|
||||
/// Register, register, memory, immediate (byte) operands.
|
||||
/// Uses `rrix` payload with extra data of type `Memory`.
|
||||
rrmi,
|
||||
/// Single memory operand.
|
||||
/// Uses `x` with extra data of type `Memory`.
|
||||
m,
|
||||
/// Memory, immediate (sign-extend) operands.
|
||||
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
|
||||
mi_s,
|
||||
/// Memory, immediate (unsigned) operands.
|
||||
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
|
||||
mi_u,
|
||||
/// Memory, register operands.
|
||||
/// Uses `rx` payload with extra data of type `Memory`.
|
||||
mr,
|
||||
/// Memory, register, register operands.
|
||||
/// Uses `rrx` payload with extra data of type `Memory`.
|
||||
mrr,
|
||||
/// Memory, register, immediate (word) operands.
|
||||
/// Uses `rix` payload with extra data of type `Memory`.
|
||||
mri,
|
||||
/// References another Mir instruction directly.
|
||||
/// Uses `inst` payload.
|
||||
inst,
|
||||
@ -852,20 +809,17 @@ pub const Inst = struct {
|
||||
/// Uses `reloc` payload.
|
||||
extern_fn_reloc,
|
||||
/// Linker relocation - GOT indirection.
|
||||
/// Uses `rx` payload with extra data of type `Reloc`.
|
||||
/// Uses `rx` payload with extra data of type `bits.Symbol`.
|
||||
got_reloc,
|
||||
/// Linker relocation - direct reference.
|
||||
/// Uses `rx` payload with extra data of type `Reloc`.
|
||||
/// Uses `rx` payload with extra data of type `bits.Symbol`.
|
||||
direct_reloc,
|
||||
/// Linker relocation - imports table indirection (binding).
|
||||
/// Uses `rx` payload with extra data of type `Reloc`.
|
||||
/// Uses `rx` payload with extra data of type `bits.Symbol`.
|
||||
import_reloc,
|
||||
/// Linker relocation - threadlocal variable via GOT indirection.
|
||||
/// Uses `rx` payload with extra data of type `Reloc`.
|
||||
/// Uses `rx` payload with extra data of type `bits.Symbol`.
|
||||
tlv_reloc,
|
||||
/// Linker relocation.
|
||||
/// Uses `rx` payload with extra data of type `Reloc`.
|
||||
linker_reloc,
|
||||
|
||||
// Pseudo instructions:
|
||||
|
||||
@ -878,10 +832,7 @@ pub const Inst = struct {
|
||||
pseudo_cmov_nz_or_p_rr,
|
||||
/// Conditional move if zero flag not set or parity flag set
|
||||
/// Uses `rx` payload.
|
||||
pseudo_cmov_nz_or_p_rm_sib,
|
||||
/// Conditional move if zero flag not set or parity flag set
|
||||
/// Uses `rx` payload.
|
||||
pseudo_cmov_nz_or_p_rm_rip,
|
||||
pseudo_cmov_nz_or_p_rm,
|
||||
/// Set byte if zero flag set and parity flag not set
|
||||
/// Requires a scratch register!
|
||||
/// Uses `rr` payload.
|
||||
@ -889,11 +840,7 @@ pub const Inst = struct {
|
||||
/// Set byte if zero flag set and parity flag not set
|
||||
/// Requires a scratch register!
|
||||
/// Uses `rx` payload.
|
||||
pseudo_set_z_and_np_m_sib,
|
||||
/// Set byte if zero flag set and parity flag not set
|
||||
/// Requires a scratch register!
|
||||
/// Uses `rx` payload.
|
||||
pseudo_set_z_and_np_m_rip,
|
||||
pseudo_set_z_and_np_m,
|
||||
/// Set byte if zero flag not set or parity flag set
|
||||
/// Requires a scratch register!
|
||||
/// Uses `rr` payload.
|
||||
@ -901,11 +848,7 @@ pub const Inst = struct {
|
||||
/// Set byte if zero flag not set or parity flag set
|
||||
/// Requires a scratch register!
|
||||
/// Uses `rx` payload.
|
||||
pseudo_set_nz_or_p_m_sib,
|
||||
/// Set byte if zero flag not set or parity flag set
|
||||
/// Requires a scratch register!
|
||||
/// Uses `rx` payload.
|
||||
pseudo_set_nz_or_p_m_rip,
|
||||
pseudo_set_nz_or_p_m,
|
||||
/// Jump if zero flag set and parity flag not set
|
||||
/// Uses `inst` payload.
|
||||
pseudo_j_z_and_np_inst,
|
||||
@ -1036,7 +979,7 @@ pub const Inst = struct {
|
||||
/// Relocation for the linker where:
|
||||
/// * `atom_index` is the index of the source
|
||||
/// * `sym_index` is the index of the target
|
||||
reloc: Reloc,
|
||||
reloc: bits.Symbol,
|
||||
/// Debug line and column position
|
||||
line_column: struct {
|
||||
line: u32,
|
||||
@ -1055,14 +998,6 @@ pub const Inst = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// A linker symbol not yet allocated in VM.
|
||||
pub const Reloc = struct {
|
||||
/// Index of the containing atom.
|
||||
atom_index: u32,
|
||||
/// Index into the linker's symbol table.
|
||||
sym_index: u32,
|
||||
};
|
||||
|
||||
/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
|
||||
pub const RegisterList = struct {
|
||||
bitset: BitSet = BitSet.initEmpty(),
|
||||
@ -1123,100 +1058,94 @@ pub const Imm64 = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO this can be further compacted using packed struct
|
||||
pub const MemorySib = struct {
|
||||
/// Size of the pointer.
|
||||
ptr_size: u32,
|
||||
/// Base register tag of type Memory.Base.Tag
|
||||
base_tag: u32,
|
||||
/// Base register of type Register or FrameIndex
|
||||
pub const Memory = struct {
|
||||
info: Info,
|
||||
base: u32,
|
||||
/// Scale starting at bit 0 and index register starting at bit 4.
|
||||
scale_index: u32,
|
||||
/// Displacement value.
|
||||
disp: i32,
|
||||
off: u32,
|
||||
extra: u32,
|
||||
|
||||
pub fn encode(mem: Memory) MemorySib {
|
||||
const sib = mem.sib;
|
||||
assert(sib.scale_index.scale == 0 or std.math.isPowerOfTwo(sib.scale_index.scale));
|
||||
pub const Info = packed struct(u32) {
|
||||
base: @typeInfo(bits.Memory.Base).Union.tag_type.?,
|
||||
mod: @typeInfo(bits.Memory.Mod).Union.tag_type.?,
|
||||
size: bits.Memory.Size,
|
||||
index: Register,
|
||||
scale: bits.Memory.Scale,
|
||||
_: u16 = undefined,
|
||||
};
|
||||
|
||||
pub fn encode(mem: bits.Memory) Memory {
|
||||
assert(mem.base != .reloc or mem.mod != .off);
|
||||
return .{
|
||||
.ptr_size = @intFromEnum(sib.ptr_size),
|
||||
.base_tag = @intFromEnum(sib.base),
|
||||
.base = switch (sib.base) {
|
||||
.info = .{
|
||||
.base = mem.base,
|
||||
.mod = mem.mod,
|
||||
.size = switch (mem.mod) {
|
||||
.rm => |rm| rm.size,
|
||||
.off => undefined,
|
||||
},
|
||||
.index = switch (mem.mod) {
|
||||
.rm => |rm| rm.index,
|
||||
.off => undefined,
|
||||
},
|
||||
.scale = switch (mem.mod) {
|
||||
.rm => |rm| rm.scale,
|
||||
.off => undefined,
|
||||
},
|
||||
},
|
||||
.base = switch (mem.base) {
|
||||
.none => undefined,
|
||||
.reg => |r| @intFromEnum(r),
|
||||
.frame => |fi| @intFromEnum(fi),
|
||||
.reg => |reg| @intFromEnum(reg),
|
||||
.frame => |frame_index| @intFromEnum(frame_index),
|
||||
.reloc => |symbol| symbol.sym_index,
|
||||
},
|
||||
.scale_index = @as(u32, sib.scale_index.scale) << 0 |
|
||||
@as(u32, if (sib.scale_index.scale > 0)
|
||||
@intFromEnum(sib.scale_index.index)
|
||||
.off = switch (mem.mod) {
|
||||
.rm => |rm| @bitCast(rm.disp),
|
||||
.off => |off| @truncate(off),
|
||||
},
|
||||
.extra = if (mem.base == .reloc)
|
||||
mem.base.reloc.atom_index
|
||||
else if (mem.mod == .off)
|
||||
@intCast(mem.mod.off >> 32)
|
||||
else
|
||||
undefined) << 4,
|
||||
.disp = sib.disp,
|
||||
undefined,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn decode(msib: MemorySib) Memory {
|
||||
const scale: u4 = @truncate(msib.scale_index);
|
||||
assert(scale == 0 or std.math.isPowerOfTwo(scale));
|
||||
return .{ .sib = .{
|
||||
.ptr_size = @enumFromInt(msib.ptr_size),
|
||||
.base = switch (@as(Memory.Base.Tag, @enumFromInt(msib.base_tag))) {
|
||||
.none => .none,
|
||||
.reg => .{ .reg = @enumFromInt(msib.base) },
|
||||
.frame => .{ .frame = @enumFromInt(msib.base) },
|
||||
pub fn decode(mem: Memory) encoder.Instruction.Memory {
|
||||
switch (mem.info.mod) {
|
||||
.rm => {
|
||||
if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) {
|
||||
assert(mem.info.index == .none and mem.info.scale == .@"1");
|
||||
return encoder.Instruction.Memory.rip(mem.info.size, @bitCast(mem.off));
|
||||
}
|
||||
return encoder.Instruction.Memory.sib(mem.info.size, .{
|
||||
.disp = @bitCast(mem.off),
|
||||
.base = switch (mem.info.base) {
|
||||
.none => .none,
|
||||
.reg => .{ .reg = @enumFromInt(mem.base) },
|
||||
.frame => .{ .frame = @enumFromInt(mem.base) },
|
||||
.reloc => .{ .reloc = .{ .atom_index = mem.extra, .sym_index = mem.base } },
|
||||
},
|
||||
.scale_index = switch (mem.info.index) {
|
||||
.none => null,
|
||||
else => |index| .{ .scale = switch (mem.info.scale) {
|
||||
inline else => |scale| comptime std.fmt.parseInt(
|
||||
u4,
|
||||
@tagName(scale),
|
||||
10,
|
||||
) catch unreachable,
|
||||
}, .index = index },
|
||||
},
|
||||
});
|
||||
},
|
||||
.scale_index = .{
|
||||
.scale = scale,
|
||||
.index = if (scale > 0) @enumFromInt(msib.scale_index >> 4) else undefined,
|
||||
.off => {
|
||||
assert(mem.info.base == .reg);
|
||||
return encoder.Instruction.Memory.moffs(
|
||||
@enumFromInt(mem.base),
|
||||
@as(u64, mem.extra) << 32 | mem.off,
|
||||
);
|
||||
},
|
||||
.disp = msib.disp,
|
||||
} };
|
||||
}
|
||||
};
|
||||
|
||||
pub const MemoryRip = struct {
|
||||
/// Size of the pointer.
|
||||
ptr_size: u32,
|
||||
/// Displacement value.
|
||||
disp: i32,
|
||||
|
||||
pub fn encode(mem: Memory) MemoryRip {
|
||||
return .{
|
||||
.ptr_size = @intFromEnum(mem.rip.ptr_size),
|
||||
.disp = mem.rip.disp,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn decode(mrip: MemoryRip) Memory {
|
||||
return .{ .rip = .{
|
||||
.ptr_size = @enumFromInt(mrip.ptr_size),
|
||||
.disp = mrip.disp,
|
||||
} };
|
||||
}
|
||||
};
|
||||
|
||||
pub const MemoryMoffs = struct {
|
||||
/// Segment register.
|
||||
seg: u32,
|
||||
/// Absolute offset wrt to the segment register split between MSB and LSB parts much like
|
||||
/// `Imm64` payload.
|
||||
msb: u32,
|
||||
lsb: u32,
|
||||
|
||||
pub fn encode(seg: Register, offset: u64) MemoryMoffs {
|
||||
return .{
|
||||
.seg = @intFromEnum(seg),
|
||||
.msb = @truncate(offset >> 32),
|
||||
.lsb = @truncate(offset >> 0),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn decode(moffs: MemoryMoffs) Memory {
|
||||
return .{ .moffs = .{
|
||||
.seg = @enumFromInt(moffs.seg),
|
||||
.offset = @as(u64, moffs.msb) << 32 | @as(u64, moffs.lsb) << 0,
|
||||
} };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1234,8 +1163,8 @@ pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end:
|
||||
inline for (fields) |field| {
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => mir.extra[i],
|
||||
i32 => @bitCast(mir.extra[i]),
|
||||
else => @compileError("bad field type"),
|
||||
i32, Memory.Info => @bitCast(mir.extra[i]),
|
||||
else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
@ -1251,15 +1180,19 @@ pub const FrameLoc = struct {
|
||||
};
|
||||
|
||||
pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
|
||||
return switch (mem) {
|
||||
.sib => |sib| switch (sib.base) {
|
||||
.none, .reg => mem,
|
||||
.frame => |index| if (mir.frame_locs.len > 0) Memory.sib(sib.ptr_size, .{
|
||||
.base = .{ .reg = mir.frame_locs.items(.base)[@intFromEnum(index)] },
|
||||
.disp = mir.frame_locs.items(.disp)[@intFromEnum(index)] + sib.disp,
|
||||
.scale_index = mem.scaleIndex(),
|
||||
}) else mem,
|
||||
},
|
||||
.rip, .moffs => mem,
|
||||
return switch (mem.info.base) {
|
||||
.none, .reg, .reloc => mem,
|
||||
.frame => if (mir.frame_locs.len > 0) Memory{
|
||||
.info = .{
|
||||
.base = .reg,
|
||||
.mod = mem.info.mod,
|
||||
.size = mem.info.size,
|
||||
.index = mem.info.index,
|
||||
.scale = mem.info.scale,
|
||||
},
|
||||
.base = @intFromEnum(mir.frame_locs.items(.base)[mem.base]),
|
||||
.off = @bitCast(mir.frame_locs.items(.disp)[mem.base] + @as(i32, @bitCast(mem.off))),
|
||||
.extra = mem.extra,
|
||||
} else mem,
|
||||
};
|
||||
}
|
||||
|
||||
@ -181,6 +181,8 @@ pub const Register = enum(u7) {
|
||||
|
||||
es, cs, ss, ds, fs, gs,
|
||||
|
||||
rip, eip, ip,
|
||||
|
||||
none,
|
||||
// zig fmt: on
|
||||
|
||||
@ -442,34 +444,58 @@ pub const FrameIndex = enum(u32) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Memory = union(enum) {
|
||||
sib: Sib,
|
||||
rip: Rip,
|
||||
moffs: Moffs,
|
||||
/// A linker symbol not yet allocated in VM.
|
||||
pub const Symbol = struct {
|
||||
/// Index of the containing atom.
|
||||
atom_index: u32,
|
||||
/// Index into the linker's symbol table.
|
||||
sym_index: u32,
|
||||
|
||||
pub const Base = union(enum) {
|
||||
pub fn format(
|
||||
sym: Symbol,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
try writer.writeAll("Symbol(");
|
||||
try std.fmt.formatType(sym.atom_index, fmt, options, writer, 0);
|
||||
try writer.writeAll(", ");
|
||||
try std.fmt.formatType(sym.sym_index, fmt, options, writer, 0);
|
||||
try writer.writeByte(')');
|
||||
}
|
||||
};
|
||||
|
||||
pub const Memory = struct {
|
||||
base: Base,
|
||||
mod: Mod,
|
||||
|
||||
pub const Base = union(enum(u2)) {
|
||||
none,
|
||||
reg: Register,
|
||||
frame: FrameIndex,
|
||||
reloc: Symbol,
|
||||
|
||||
pub const Tag = @typeInfo(Base).Union.tag_type.?;
|
||||
|
||||
pub fn isExtended(self: Base) bool {
|
||||
return switch (self) {
|
||||
.none, .frame => false, // neither rsp nor rbp are extended
|
||||
.none, .frame, .reloc => false, // rsp, rbp, and rip are not extended
|
||||
.reg => |reg| reg.isExtended(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const ScaleIndex = struct {
|
||||
scale: u4,
|
||||
index: Register,
|
||||
|
||||
const none = ScaleIndex{ .scale = 0, .index = undefined };
|
||||
pub const Mod = union(enum(u1)) {
|
||||
rm: struct {
|
||||
size: Size,
|
||||
index: Register = .none,
|
||||
scale: Scale = .@"1",
|
||||
disp: i32 = 0,
|
||||
},
|
||||
off: u64,
|
||||
};
|
||||
|
||||
pub const PtrSize = enum {
|
||||
pub const Size = enum(u4) {
|
||||
none,
|
||||
byte,
|
||||
word,
|
||||
@ -480,7 +506,7 @@ pub const Memory = union(enum) {
|
||||
yword,
|
||||
zword,
|
||||
|
||||
pub fn fromSize(size: u32) PtrSize {
|
||||
pub fn fromSize(size: u32) Size {
|
||||
return switch (size) {
|
||||
1...1 => .byte,
|
||||
2...2 => .word,
|
||||
@ -493,7 +519,7 @@ pub const Memory = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromBitSize(bit_size: u64) PtrSize {
|
||||
pub fn fromBitSize(bit_size: u64) Size {
|
||||
return switch (bit_size) {
|
||||
8 => .byte,
|
||||
16 => .word,
|
||||
@ -507,7 +533,7 @@ pub const Memory = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitSize(s: PtrSize) u64 {
|
||||
pub fn bitSize(s: Size) u64 {
|
||||
return switch (s) {
|
||||
.none => 0,
|
||||
.byte => 8,
|
||||
@ -522,7 +548,7 @@ pub const Memory = union(enum) {
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
s: PtrSize,
|
||||
s: Size,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
@ -533,79 +559,7 @@ pub const Memory = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Sib = struct {
|
||||
ptr_size: PtrSize,
|
||||
base: Base,
|
||||
scale_index: ScaleIndex,
|
||||
disp: i32,
|
||||
};
|
||||
|
||||
pub const Rip = struct {
|
||||
ptr_size: PtrSize,
|
||||
disp: i32,
|
||||
};
|
||||
|
||||
pub const Moffs = struct {
|
||||
seg: Register,
|
||||
offset: u64,
|
||||
};
|
||||
|
||||
pub fn moffs(reg: Register, offset: u64) Memory {
|
||||
assert(reg.class() == .segment);
|
||||
return .{ .moffs = .{ .seg = reg, .offset = offset } };
|
||||
}
|
||||
|
||||
pub fn sib(ptr_size: PtrSize, args: struct {
|
||||
disp: i32 = 0,
|
||||
base: Base = .none,
|
||||
scale_index: ?ScaleIndex = null,
|
||||
}) Memory {
|
||||
if (args.scale_index) |si| assert(std.math.isPowerOfTwo(si.scale));
|
||||
return .{ .sib = .{
|
||||
.base = args.base,
|
||||
.disp = args.disp,
|
||||
.ptr_size = ptr_size,
|
||||
.scale_index = if (args.scale_index) |si| si else ScaleIndex.none,
|
||||
} };
|
||||
}
|
||||
|
||||
pub fn rip(ptr_size: PtrSize, disp: i32) Memory {
|
||||
return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } };
|
||||
}
|
||||
|
||||
pub fn isSegmentRegister(mem: Memory) bool {
|
||||
return switch (mem) {
|
||||
.moffs => true,
|
||||
.rip => false,
|
||||
.sib => |s| switch (s.base) {
|
||||
.none, .frame => false,
|
||||
.reg => |reg| reg.class() == .segment,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn base(mem: Memory) Base {
|
||||
return switch (mem) {
|
||||
.moffs => |m| .{ .reg = m.seg },
|
||||
.sib => |s| s.base,
|
||||
.rip => .none,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn scaleIndex(mem: Memory) ?ScaleIndex {
|
||||
return switch (mem) {
|
||||
.moffs, .rip => null,
|
||||
.sib => |s| if (s.scale_index.scale > 0) s.scale_index else null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitSize(mem: Memory) u64 {
|
||||
return switch (mem) {
|
||||
.rip => |r| r.ptr_size.bitSize(),
|
||||
.sib => |s| s.ptr_size.bitSize(),
|
||||
.moffs => 64,
|
||||
};
|
||||
}
|
||||
pub const Scale = enum(u2) { @"1", @"2", @"4", @"8" };
|
||||
};
|
||||
|
||||
pub const Immediate = union(enum) {
|
||||
|
||||
@ -6,9 +6,10 @@ const testing = std.testing;
|
||||
|
||||
const bits = @import("bits.zig");
|
||||
const Encoding = @import("Encoding.zig");
|
||||
const FrameIndex = bits.FrameIndex;
|
||||
const Immediate = bits.Immediate;
|
||||
const Memory = bits.Memory;
|
||||
const Register = bits.Register;
|
||||
const Symbol = bits.Symbol;
|
||||
|
||||
pub const Instruction = struct {
|
||||
prefix: Prefix = .none,
|
||||
@ -27,6 +28,97 @@ pub const Instruction = struct {
|
||||
repnz,
|
||||
};
|
||||
|
||||
pub const Memory = union(enum) {
|
||||
sib: Sib,
|
||||
rip: Rip,
|
||||
moffs: Moffs,
|
||||
|
||||
pub const Base = bits.Memory.Base;
|
||||
|
||||
pub const ScaleIndex = struct {
|
||||
scale: u4,
|
||||
index: Register,
|
||||
|
||||
const none = ScaleIndex{ .scale = 0, .index = undefined };
|
||||
};
|
||||
|
||||
pub const PtrSize = bits.Memory.Size;
|
||||
|
||||
pub const Sib = struct {
|
||||
ptr_size: PtrSize,
|
||||
base: Base,
|
||||
scale_index: ScaleIndex,
|
||||
disp: i32,
|
||||
};
|
||||
|
||||
pub const Rip = struct {
|
||||
ptr_size: PtrSize,
|
||||
disp: i32,
|
||||
};
|
||||
|
||||
pub const Moffs = struct {
|
||||
seg: Register,
|
||||
offset: u64,
|
||||
};
|
||||
|
||||
pub fn moffs(reg: Register, offset: u64) Memory {
|
||||
assert(reg.class() == .segment);
|
||||
return .{ .moffs = .{ .seg = reg, .offset = offset } };
|
||||
}
|
||||
|
||||
pub fn sib(ptr_size: PtrSize, args: struct {
|
||||
disp: i32 = 0,
|
||||
base: Base = .none,
|
||||
scale_index: ?ScaleIndex = null,
|
||||
}) Memory {
|
||||
if (args.scale_index) |si| assert(std.math.isPowerOfTwo(si.scale));
|
||||
return .{ .sib = .{
|
||||
.base = args.base,
|
||||
.disp = args.disp,
|
||||
.ptr_size = ptr_size,
|
||||
.scale_index = if (args.scale_index) |si| si else ScaleIndex.none,
|
||||
} };
|
||||
}
|
||||
|
||||
pub fn rip(ptr_size: PtrSize, disp: i32) Memory {
|
||||
return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } };
|
||||
}
|
||||
|
||||
pub fn isSegmentRegister(mem: Memory) bool {
|
||||
return switch (mem) {
|
||||
.moffs => true,
|
||||
.rip => false,
|
||||
.sib => |s| switch (s.base) {
|
||||
.none, .frame, .reloc => false,
|
||||
.reg => |reg| reg.class() == .segment,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn base(mem: Memory) Base {
|
||||
return switch (mem) {
|
||||
.moffs => |m| .{ .reg = m.seg },
|
||||
.sib => |s| s.base,
|
||||
.rip => .none,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn scaleIndex(mem: Memory) ?ScaleIndex {
|
||||
return switch (mem) {
|
||||
.moffs, .rip => null,
|
||||
.sib => |s| if (s.scale_index.scale > 0) s.scale_index else null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitSize(mem: Memory) u64 {
|
||||
return switch (mem) {
|
||||
.rip => |r| r.ptr_size.bitSize(),
|
||||
.sib => |s| s.ptr_size.bitSize(),
|
||||
.moffs => 64,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Operand = union(enum) {
|
||||
none,
|
||||
reg: Register,
|
||||
@ -125,8 +217,8 @@ pub const Instruction = struct {
|
||||
try writer.print("{s}", .{@tagName(reg)});
|
||||
any = true;
|
||||
},
|
||||
.frame => |frame| {
|
||||
try writer.print("{}", .{frame});
|
||||
inline .frame, .reloc => |payload| {
|
||||
try writer.print("{}", .{payload});
|
||||
any = true;
|
||||
},
|
||||
}
|
||||
@ -498,7 +590,11 @@ pub const Instruction = struct {
|
||||
}
|
||||
}
|
||||
},
|
||||
.frame => if (@TypeOf(encoder).options.allow_frame_loc) {
|
||||
.frame => if (@TypeOf(encoder).options.allow_frame_locs) {
|
||||
try encoder.modRm_indirectDisp32(operand_enc, undefined);
|
||||
try encoder.disp32(undefined);
|
||||
} else return error.CannotEncode,
|
||||
.reloc => if (@TypeOf(encoder).options.allow_symbols) {
|
||||
try encoder.modRm_indirectDisp32(operand_enc, undefined);
|
||||
try encoder.disp32(undefined);
|
||||
} else return error.CannotEncode,
|
||||
@ -570,7 +666,7 @@ pub const LegacyPrefixes = packed struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Options = struct { allow_frame_loc: bool = false };
|
||||
pub const Options = struct { allow_frame_locs: bool = false, allow_symbols: bool = false };
|
||||
|
||||
fn Encoder(comptime T: type, comptime opts: Options) type {
|
||||
return struct {
|
||||
@ -1085,7 +1181,7 @@ test "lower MI encoding" {
|
||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
|
||||
@ -1109,13 +1205,13 @@ test "lower MI encoding" {
|
||||
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.rip(.qword, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1125,25 +1221,25 @@ test "lower MI encoding" {
|
||||
);
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },
|
||||
.{ .imm = Immediate.s(-16) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = .ds,
|
||||
.disp = 0x10000000,
|
||||
.scale_index = .{ .scale = 2, .index = .rcx },
|
||||
@ -1157,13 +1253,13 @@ test "lower MI encoding" {
|
||||
);
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .mem = Memory.rip(.qword, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, 0) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
|
||||
@ -1175,7 +1271,7 @@ test "lower MI encoding" {
|
||||
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
|
||||
@ -1187,13 +1283,13 @@ test "lower MI encoding" {
|
||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
|
||||
.{ .imm = Immediate.s(-0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1203,7 +1299,7 @@ test "lower MI encoding" {
|
||||
);
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1213,7 +1309,7 @@ test "lower MI encoding" {
|
||||
);
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1223,7 +1319,7 @@ test "lower MI encoding" {
|
||||
);
|
||||
|
||||
try enc.encode(.sub, &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1238,25 +1334,25 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rbx },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = .rbp,
|
||||
.scale_index = .{ .scale = 1, .index = .rcx },
|
||||
.disp = -8,
|
||||
@ -1266,7 +1362,7 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .eax },
|
||||
.{ .mem = Memory.sib(.dword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{
|
||||
.base = .rbp,
|
||||
.scale_index = .{ .scale = 4, .index = .rdx },
|
||||
.disp = -4,
|
||||
@ -1276,7 +1372,7 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = .rbp,
|
||||
.scale_index = .{ .scale = 8, .index = .rcx },
|
||||
.disp = -8,
|
||||
@ -1286,7 +1382,7 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r8b },
|
||||
.{ .mem = Memory.sib(.byte, .{
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{
|
||||
.base = .rsi,
|
||||
.scale_index = .{ .scale = 1, .index = .rcx },
|
||||
.disp = -24,
|
||||
@ -1302,7 +1398,7 @@ test "lower RM encoding" {
|
||||
try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .reg = .fs },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs");
|
||||
@ -1314,7 +1410,7 @@ test "lower RM encoding" {
|
||||
try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .reg = .fs },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
|
||||
@ -1339,19 +1435,19 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.movsx, &.{
|
||||
.{ .reg = .eax },
|
||||
.{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
|
||||
|
||||
try enc.encode(.movsx, &.{
|
||||
.{ .reg = .eax },
|
||||
.{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
|
||||
.{ .mem = Instruction.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, &.{
|
||||
.{ .reg = .ax },
|
||||
.{ .mem = Memory.rip(.byte, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.byte, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]");
|
||||
|
||||
@ -1369,37 +1465,37 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.lea, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.rip(.qword, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]");
|
||||
|
||||
try enc.encode(.lea, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.rip(.dword, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.dword, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]");
|
||||
|
||||
try enc.encode(.lea, &.{
|
||||
.{ .reg = .eax },
|
||||
.{ .mem = Memory.rip(.dword, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.dword, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]");
|
||||
|
||||
try enc.encode(.lea, &.{
|
||||
.{ .reg = .eax },
|
||||
.{ .mem = Memory.rip(.word, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.word, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]");
|
||||
|
||||
try enc.encode(.lea, &.{
|
||||
.{ .reg = .ax },
|
||||
.{ .mem = Memory.rip(.byte, 0x10) },
|
||||
.{ .mem = Instruction.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, &.{
|
||||
.{ .reg = .rsi },
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = .rbp,
|
||||
.scale_index = .{ .scale = 1, .index = .rcx },
|
||||
}) },
|
||||
@ -1408,31 +1504,31 @@ test "lower RM encoding" {
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .r12b },
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .r12b },
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");
|
||||
|
||||
try enc.encode(.sub, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");
|
||||
|
||||
try enc.encode(.sub, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");
|
||||
|
||||
@ -1455,7 +1551,7 @@ test "lower RMI encoding" {
|
||||
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .mem = Memory.rip(.qword, -16) },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, -16) },
|
||||
.{ .imm = Immediate.s(-1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1466,7 +1562,7 @@ test "lower RMI encoding" {
|
||||
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .bx },
|
||||
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .imm = Immediate.s(-1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1477,7 +1573,7 @@ test "lower RMI encoding" {
|
||||
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .bx },
|
||||
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
|
||||
.{ .imm = Immediate.u(1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
@ -1497,19 +1593,19 @@ test "lower MR encoding" {
|
||||
try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
|
||||
.{ .reg = .r11 },
|
||||
});
|
||||
try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.rip(.qword, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
|
||||
.{ .reg = .r12 },
|
||||
});
|
||||
try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = .r11,
|
||||
.scale_index = .{ .scale = 2, .index = .r12 },
|
||||
.disp = 0x10,
|
||||
@ -1519,13 +1615,13 @@ test "lower MR encoding" {
|
||||
try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.rip(.word, -0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.word, -0x10) },
|
||||
.{ .reg = .r12w },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.sib(.byte, .{
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{
|
||||
.base = .r11,
|
||||
.scale_index = .{ .scale = 2, .index = .r12 },
|
||||
.disp = 0x10,
|
||||
@ -1535,25 +1631,25 @@ test "lower MR encoding" {
|
||||
try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .reg = .r12b },
|
||||
});
|
||||
try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
|
||||
.{ .reg = .r12d },
|
||||
});
|
||||
try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
|
||||
.{ .reg = .r12d },
|
||||
});
|
||||
try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");
|
||||
|
||||
try enc.encode(.sub, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
|
||||
.{ .reg = .r12 },
|
||||
});
|
||||
try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
|
||||
@ -1568,12 +1664,12 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
|
||||
|
||||
try enc.encode(.call, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .r12 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12 }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
|
||||
|
||||
try enc.encode(.call, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = null,
|
||||
.scale_index = .{ .index = .r11, .scale = 2 },
|
||||
}) },
|
||||
@ -1581,7 +1677,7 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
|
||||
|
||||
try enc.encode(.call, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{
|
||||
.base = null,
|
||||
.scale_index = .{ .index = .r12, .scale = 2 },
|
||||
}) },
|
||||
@ -1589,7 +1685,7 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
|
||||
|
||||
try enc.encode(.call, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .gs }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .gs }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
|
||||
|
||||
@ -1599,22 +1695,22 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .mem = Memory.sib(.qword, .{ .base = .rbp }) },
|
||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp }) },
|
||||
});
|
||||
try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
|
||||
|
||||
try enc.encode(.pop, &.{
|
||||
.{ .mem = Memory.rip(.qword, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, 0) },
|
||||
});
|
||||
try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]");
|
||||
|
||||
try enc.encode(.pop, &.{
|
||||
.{ .mem = Memory.rip(.word, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.word, 0) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]");
|
||||
|
||||
@ -1695,48 +1791,48 @@ test "lower FD/TD encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.moffs(.cs, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.cs, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .eax },
|
||||
.{ .mem = Memory.moffs(.fs, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.fs, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .ax },
|
||||
.{ .mem = Memory.moffs(.gs, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.gs, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .al },
|
||||
.{ .mem = Memory.moffs(.ds, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.ds, 0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.moffs(.cs, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.cs, 0x10) },
|
||||
.{ .reg = .rax },
|
||||
});
|
||||
try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.moffs(.fs, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.fs, 0x10) },
|
||||
.{ .reg = .eax },
|
||||
});
|
||||
try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.moffs(.gs, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.gs, 0x10) },
|
||||
.{ .reg = .ax },
|
||||
});
|
||||
try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Memory.moffs(.ds, 0x10) },
|
||||
.{ .mem = Instruction.Memory.moffs(.ds, 0x10) },
|
||||
.{ .reg = .al },
|
||||
});
|
||||
try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");
|
||||
@ -1774,16 +1870,16 @@ test "invalid instruction" {
|
||||
.{ .reg = .al },
|
||||
});
|
||||
try invalidInstruction(.call, &.{
|
||||
.{ .mem = Memory.rip(.dword, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.dword, 0) },
|
||||
});
|
||||
try invalidInstruction(.call, &.{
|
||||
.{ .mem = Memory.rip(.word, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.word, 0) },
|
||||
});
|
||||
try invalidInstruction(.call, &.{
|
||||
.{ .mem = Memory.rip(.byte, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.byte, 0) },
|
||||
});
|
||||
try invalidInstruction(.mov, &.{
|
||||
.{ .mem = Memory.rip(.word, 0x10) },
|
||||
.{ .mem = Instruction.Memory.rip(.word, 0x10) },
|
||||
.{ .reg = .r12 },
|
||||
});
|
||||
try invalidInstruction(.lea, &.{
|
||||
@ -1792,7 +1888,7 @@ test "invalid instruction" {
|
||||
});
|
||||
try invalidInstruction(.lea, &.{
|
||||
.{ .reg = .al },
|
||||
.{ .mem = Memory.rip(.byte, 0) },
|
||||
.{ .mem = Instruction.Memory.rip(.byte, 0) },
|
||||
});
|
||||
try invalidInstruction(.pop, &.{
|
||||
.{ .reg = .r12b },
|
||||
@ -1817,7 +1913,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand
|
||||
|
||||
test "cannot encode" {
|
||||
try cannotEncode(.@"test", &.{
|
||||
.{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
|
||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },
|
||||
.{ .reg = .ah },
|
||||
});
|
||||
try cannotEncode(.@"test", &.{
|
||||
@ -2149,8 +2245,8 @@ const Assembler = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn parseMemory(as: *Assembler) ParseError!Memory {
|
||||
const ptr_size: ?Memory.PtrSize = blk: {
|
||||
fn parseMemory(as: *Assembler) ParseError!Instruction.Memory {
|
||||
const ptr_size: ?Instruction.Memory.PtrSize = blk: {
|
||||
const pos = as.it.pos;
|
||||
const ptr_size = as.parsePtrSize() catch |err| switch (err) {
|
||||
error.UnexpectedToken => {
|
||||
@ -2194,7 +2290,7 @@ const Assembler = struct {
|
||||
if (res.rip) {
|
||||
if (res.base != null or res.scale_index != null or res.offset != null)
|
||||
return error.InvalidMemoryOperand;
|
||||
return Memory.rip(ptr_size orelse .qword, res.disp orelse 0);
|
||||
return Instruction.Memory.rip(ptr_size orelse .qword, res.disp orelse 0);
|
||||
}
|
||||
if (res.base) |base| {
|
||||
if (res.rip)
|
||||
@ -2202,9 +2298,9 @@ const Assembler = struct {
|
||||
if (res.offset) |offset| {
|
||||
if (res.scale_index != null or res.disp != null)
|
||||
return error.InvalidMemoryOperand;
|
||||
return Memory.moffs(base, offset);
|
||||
return Instruction.Memory.moffs(base, offset);
|
||||
}
|
||||
return Memory.sib(ptr_size orelse .qword, .{
|
||||
return Instruction.Memory.sib(ptr_size orelse .qword, .{
|
||||
.base = base,
|
||||
.scale_index = res.scale_index,
|
||||
.disp = res.disp orelse 0,
|
||||
@ -2222,12 +2318,12 @@ const Assembler = struct {
|
||||
const MemoryParseResult = struct {
|
||||
rip: bool = false,
|
||||
base: ?Register = null,
|
||||
scale_index: ?Memory.ScaleIndex = null,
|
||||
scale_index: ?Instruction.Memory.ScaleIndex = null,
|
||||
disp: ?i32 = null,
|
||||
offset: ?u64 = null,
|
||||
};
|
||||
|
||||
fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!MemoryParseResult {
|
||||
fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!Instruction.MemoryParseResult {
|
||||
var res: MemoryParseResult = .{};
|
||||
inline for (rule, 0..) |cond, i| {
|
||||
if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) {
|
||||
@ -2294,7 +2390,7 @@ const Assembler = struct {
|
||||
return res;
|
||||
}
|
||||
|
||||
fn parsePtrSize(as: *Assembler) ParseError!Memory.PtrSize {
|
||||
fn parsePtrSize(as: *Assembler) ParseError!Instruction.Memory.PtrSize {
|
||||
const size = try as.expect(.string);
|
||||
try as.skip(1, .{.space});
|
||||
const ptr = try as.expect(.string);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user