diff --git a/src/arch/x86_64/Isel.zig b/src/arch/x86_64/Isel.zig index 6124d55a10..4bd064ae11 100644 --- a/src/arch/x86_64/Isel.zig +++ b/src/arch/x86_64/Isel.zig @@ -227,8 +227,10 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { 16 => .word_ptr, else => .qword_ptr, }; - return lowerToMEnc(tag, RegisterOrMemory.mem(ops.reg1, imm, ptr_size), isel.code) catch |err| - isel.failWithLoweringError(err); + return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ + .disp = imm, + .base = ops.reg1, + }), isel.code) catch |err| isel.failWithLoweringError(err); }, 0b10 => { // PUSH imm32 @@ -284,7 +286,7 @@ fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { 16 => .word_ptr, else => .qword_ptr, }; - return lowerToMEnc(tag, RegisterOrMemory.mem(null, imm, ptr_size), isel.code) catch |err| + return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err| isel.failWithLoweringError(err); } // JMP/CALL reg @@ -422,12 +424,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { // RM const imm = isel.mir.instructions.items(.data)[inst].imm; const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2; - return lowerToRmEnc( - tag, - ops.reg1, - RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())), - isel.code, - ) catch |err| isel.failWithLoweringError(err); + return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ + .disp = imm, + .base = src_reg, + }), isel.code) catch |err| isel.failWithLoweringError(err); }, 0b10 => { if (ops.reg2 == .none) { @@ -436,12 +436,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { // mov [reg1 + imm32], reg2 // MR const imm = isel.mir.instructions.items(.data)[inst].imm; - return lowerToMrEnc( - tag, - RegisterOrMemory.mem(ops.reg1, imm, Memory.PtrSize.fromBits(ops.reg2.size())), - ops.reg2, - isel.code, - ) catch |err| isel.failWithLoweringError(err); + return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ + .disp = imm, + .base = ops.reg1, + }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err); }, 0b11 => { return isel.fail("TODO unused variant: mov reg1, reg2, 0b11", .{}); @@ -460,12 +458,10 @@ fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { 0b10 => .dword_ptr, 0b11 => .qword_ptr, }; - return lowerToMiEnc( - tag, - RegisterOrMemory.mem(ops.reg1, imm_pair.dest_off, ptr_size), - imm_pair.operand, - isel.code, - ) catch |err| isel.failWithLoweringError(err); + return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{ + .disp = imm_pair.dest_off, + .base = ops.reg1, + }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err); } inline fn setRexWRegister(reg: Register) bool { @@ -492,103 +488,61 @@ inline fn immOpSize(imm: i64) u8 { return 64; } -// TODO fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); const scale = ops.flags; - // OP reg1, [reg2 + scale*rcx + imm32] - const opc = getOpCode(tag, .rm, ops.reg1.size() == 8).?; const imm = isel.mir.instructions.items(.data)[inst].imm; - const encoder = try Encoder.init(isel.code, 8); - encoder.rex(.{ - .w = ops.reg1.size() == 64, - .r = ops.reg1.isExtended(), - .b = ops.reg2.isExtended(), - }); - opc.encode(encoder); - if (imm <= math.maxInt(i8)) { - encoder.modRm_SIBDisp8(ops.reg1.lowId()); - encoder.sib_scaleIndexBaseDisp8(scale, Register.rcx.lowId(), ops.reg2.lowId()); - encoder.disp8(@intCast(i8, imm)); - } else { - encoder.modRm_SIBDisp32(ops.reg1.lowId()); - encoder.sib_scaleIndexBaseDisp32(scale, Register.rcx.lowId(), ops.reg2.lowId()); - encoder.disp32(imm); - } + // OP reg1, [reg2 + scale*rcx + imm32] + return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ + .disp = imm, + .base = ops.reg2, + .scale_index = .{ + .scale = scale, + .index = .rcx, + }, + }), isel.code) catch |err| isel.failWithLoweringError(err); } -// TODO fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); const scale = ops.flags; const imm = isel.mir.instructions.items(.data)[inst].imm; - if (ops.reg2 == .none) { - // OP [reg1 + scale*rax + 0], imm32 - const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?; - const modrm_ext = getModRmExt(tag).?; - const encoder = try Encoder.init(isel.code, 8); - encoder.rex(.{ - .w = ops.reg1.size() == 64, - .b = ops.reg1.isExtended(), - }); - opc.encode(encoder); - encoder.modRm_SIBDisp0(modrm_ext); - encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId()); - if (imm <= math.maxInt(i8)) { - encoder.imm8(@intCast(i8, imm)); - } else if (imm <= math.maxInt(i16)) { - encoder.imm16(@intCast(i16, imm)); - } else { - encoder.imm32(imm); - } - return; + // OP qword ptr [reg1 + scale*rax + 0], imm32 + return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0, + .base = ops.reg1, + .scale_index = .{ + .scale = scale, + .index = .rax, + }, + }), imm, isel.code) catch |err| isel.failWithLoweringError(err); } - // OP [reg1 + scale*rax + imm32], reg2 - const opc = getOpCode(tag, .mr, ops.reg1.size() == 8).?; - const encoder = try Encoder.init(isel.code, 8); - encoder.rex(.{ - .w = ops.reg1.size() == 64, - .r = ops.reg2.isExtended(), - .b = ops.reg1.isExtended(), - }); - opc.encode(encoder); - if (imm <= math.maxInt(i8)) { - encoder.modRm_SIBDisp8(ops.reg2.lowId()); - encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId()); - encoder.disp8(@intCast(i8, imm)); - } else { - encoder.modRm_SIBDisp32(ops.reg2.lowId()); - encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId()); - encoder.disp32(imm); - } + return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ + .disp = imm, + .base = ops.reg1, + .scale_index = .{ + .scale = scale, + .index = .rax, + }, + }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err); } -// TODO fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); const scale = ops.flags; const payload = isel.mir.instructions.items(.data)[inst].payload; const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data; - const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?; - const modrm_ext = getModRmExt(tag).?; - const encoder = try Encoder.init(isel.code, 2); - encoder.rex(.{ - .w = ops.reg1.size() == 64, - .b = ops.reg1.isExtended(), - }); - opc.encode(encoder); - if (imm_pair.dest_off <= math.maxInt(i8)) { - encoder.modRm_SIBDisp8(modrm_ext); - encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId()); - encoder.disp8(@intCast(i8, imm_pair.dest_off)); - } else { - encoder.modRm_SIBDisp32(modrm_ext); - encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId()); - encoder.disp32(imm_pair.dest_off); - } - encoder.imm32(imm_pair.operand); + // OP qword ptr [reg1 + scale*rax + imm32], imm32 + return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = imm_pair.dest_off, + .base = ops.reg1, + .scale_index = .{ + .scale = scale, + .index = .rax, + }, + }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err); } fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { @@ -646,7 +600,10 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { return lowerToRmEnc( .lea, ops.reg1, - RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())), + RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ + .disp = imm, + .base = src_reg, + }), isel.code, ) catch |err| isel.failWithLoweringError(err); }, @@ -657,7 +614,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { lowerToRmEnc( .lea, ops.reg1, - RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())), + RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), isel.code, ) catch |err| return isel.failWithLoweringError(err); const end_offset = isel.code.items.len; @@ -673,7 +630,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { lowerToRmEnc( .lea, ops.reg1, - RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())), + RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), isel.code, ) catch |err| return isel.failWithLoweringError(err); const end_offset = isel.code.items.len; @@ -1273,17 +1230,29 @@ const Memory = struct { if (mem_op.base) |base| { const dst = base.lowId(); const src = operand; - if (dst == 4) { + if (dst == 4 or mem_op.scale_index != null) { if (mem_op.disp == 0) { encoder.modRm_SIBDisp0(src); - encoder.sib_base(dst); + if (mem_op.scale_index) |si| { + encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst); + } else { + encoder.sib_base(dst); + } } else if (immOpSize(mem_op.disp) == 8) { encoder.modRm_SIBDisp8(src); - encoder.sib_baseDisp8(dst); + if (mem_op.scale_index) |si| { + encoder.sib_scaleIndexBaseDisp8(si.scale, si.index.lowId(), dst); + } else { + encoder.sib_baseDisp8(dst); + } encoder.disp8(@intCast(i8, mem_op.disp)); } else { encoder.modRm_SIBDisp32(src); - encoder.sib_baseDisp32(dst); + if (mem_op.scale_index) |si| { + encoder.sib_scaleIndexBaseDisp32(si.scale, si.index.lowId(), dst); + } else { + encoder.sib_baseDisp32(dst); + } encoder.disp32(mem_op.disp); } } else { @@ -1302,7 +1271,11 @@ const Memory = struct { encoder.modRm_RIPDisp32(operand); } else { encoder.modRm_SIBDisp0(operand); - encoder.sib_disp32(); + if (mem_op.scale_index) |si| { + encoder.sib_scaleIndexDisp32(si.scale, si.index.lowId()); + } else { + encoder.sib_disp32(); + } } encoder.disp32(mem_op.disp); } @@ -1326,17 +1299,22 @@ const RegisterOrMemory = union(enum) { return .{ .register = register }; } - fn mem(base: ?Register, disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory { + fn mem(ptr_size: Memory.PtrSize, args: struct { + disp: i32, + base: ?Register = null, + scale_index: ?ScaleIndex = null, + }) RegisterOrMemory { return .{ .memory = .{ - .base = base, - .disp = disp, + .base = args.base, + .disp = args.disp, .ptr_size = ptr_size, + .scale_index = args.scale_index, }, }; } - fn rip(disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory { + fn rip(ptr_size: Memory.PtrSize, disp: i32) RegisterOrMemory { return .{ .memory = .{ .base = null, @@ -1566,6 +1544,10 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr .w = dst_mem.ptr_size == .qword_ptr, .b = base.isExtended(), }); + } else { + encoder.rex(.{ + .w = dst_mem.ptr_size == .qword_ptr, + }); } opc.encode(encoder); dst_mem.encode(encoder, modrm_ext); @@ -1782,44 +1764,62 @@ test "lower MI encoding" { defer isel.deinit(); try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code()); try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10"); - try lowerToMiEnc(.mov, RegisterOrMemory.mem(.r11, 0, .dword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.mov, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0, .base = .r11 }), 0x10, isel.code()); try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10"); - try lowerToMiEnc(.add, RegisterOrMemory.mem(.rdx, -8, .dword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = -8, .base = .rdx }), 0x10, isel.code()); try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10"); - try lowerToMiEnc(.sub, RegisterOrMemory.mem(.r11, 0x10000000, .dword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.sub, RegisterOrMemory.mem(.dword_ptr, .{ + .disp = 0x10000000, + .base = .r11, + }), 0x10, isel.code()); try expectEqualHexStrings( "\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00", isel.lowered(), "sub dword ptr [r11 + 0x10000000], 0x10", ); - try lowerToMiEnc(.@"and", RegisterOrMemory.mem(null, 0x10000000, .dword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), 0x10, isel.code()); try expectEqualHexStrings( "\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00", isel.lowered(), "and dword ptr [ds:0x10000000], 0x10", ); - try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.r12, 0x10000000, .dword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{ + .disp = 0x10000000, + .base = .r12, + }), 0x10, isel.code()); try expectEqualHexStrings( "\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00", isel.lowered(), "and dword ptr [r12 + 0x10000000], 0x10", ); - try lowerToMiEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), 0x10, isel.code()); try expectEqualHexStrings( - "\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", + "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], 0x10", ); - try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -8, .qword_ptr), 0x10, isel.code()); + try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -8, .base = .rbp }), 0x10, isel.code()); try expectEqualHexStrings( "\x48\xc7\x45\xf8\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rbp - 8], 0x10", ); - try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -2, .word_ptr), 0x10, isel.code()); + try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{ .disp = -2, .base = .rbp }), 0x10, isel.code()); try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10"); - try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -1, .byte_ptr), 0x10, isel.code()); + try lowerToMiEnc(.mov, RegisterOrMemory.mem(.byte_ptr, .{ .disp = -1, .base = .rbp }), 0x10, isel.code()); try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10"); + try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0x10000000, + .scale_index = .{ + .scale = 1, + .index = .rcx, + }, + }), 0x10, isel.code()); + try expectEqualHexStrings( + "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00", + isel.lowered(), + "mov qword ptr [rcx*2 + 0x10000000], 0x10", + ); } test "lower RM encoding" { @@ -1827,36 +1827,69 @@ test "lower RM encoding" { defer isel.deinit(); try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code()); try expectEqualHexStrings("\x48\x8b\xc3", isel.lowered(), "mov rax, rbx"); - try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.r11, 0, .qword_ptr), isel.code()); + try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), isel.code()); try expectEqualHexStrings("\x49\x8b\x03", isel.lowered(), "mov rax, qword ptr [r11 + 0]"); - try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(null, 0x10000000, .qword_ptr), isel.code()); + try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), isel.code()); try expectEqualHexStrings( "\x4C\x03\x1C\x25\x00\x00\x00\x10", isel.lowered(), "add r11, qword ptr [ds:0x10000000]", ); - try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(null, 0x10000000, .byte_ptr), isel.code()); + try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), isel.code()); try expectEqualHexStrings( "\x44\x02\x24\x25\x00\x00\x00\x10", isel.lowered(), "add r11b, byte ptr [ds:0x10000000]", ); - try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.r13, 0x10000000, .qword_ptr), isel.code()); + try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0x10000000, + .base = .r13, + }), isel.code()); try expectEqualHexStrings( "\x4D\x2B\x9D\x00\x00\x00\x10", isel.lowered(), "sub r11, qword ptr [r13 + 0x10000000]", ); - try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.r12, 0x10000000, .qword_ptr), isel.code()); + try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0x10000000, + .base = .r12, + }), isel.code()); try expectEqualHexStrings( "\x4D\x2B\x9C\x24\x00\x00\x00\x10", isel.lowered(), "sub r11, qword ptr [r12 + 0x10000000]", ); - try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4, .qword_ptr), isel.code()); + try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), isel.code()); try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]"); - try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code()); + try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code()); try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]"); + try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = -8, + .base = .rbp, + .scale_index = .{ + .scale = 0, + .index = .rcx, + }, + }), isel.code()); + try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]"); + try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{ + .disp = -4, + .base = .rbp, + .scale_index = .{ + .scale = 2, + .index = .rdx, + }, + }), isel.code()); + try expectEqualHexStrings("\x8B\x44\x95\xFC", isel.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]"); + try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = -8, + .base = .rbp, + .scale_index = .{ + .scale = 3, + .index = .rcx, + }, + }), isel.code()); + try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]"); } test "lower MR encoding" { @@ -1864,27 +1897,30 @@ test "lower MR encoding" { defer isel.deinit(); try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code()); try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx"); - try lowerToMrEnc(.mov, RegisterOrMemory.mem(.rbp, -4, .qword_ptr), .r11, isel.code()); + try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), .r11, isel.code()); try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11"); - try lowerToMrEnc(.add, RegisterOrMemory.mem(null, 0x10000000, .byte_ptr), .r12b, isel.code()); + try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, isel.code()); try expectEqualHexStrings( "\x44\x00\x24\x25\x00\x00\x00\x10", isel.lowered(), "add byte ptr [ds:0x10000000], r12b", ); - try lowerToMrEnc(.add, RegisterOrMemory.mem(null, 0x10000000, .dword_ptr), .r12d, isel.code()); + try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, isel.code()); try expectEqualHexStrings( "\x44\x01\x24\x25\x00\x00\x00\x10", isel.lowered(), "add dword ptr [ds:0x10000000], r12d", ); - try lowerToMrEnc(.sub, RegisterOrMemory.mem(.r11, 0x10000000, .qword_ptr), .r12, isel.code()); + try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0x10000000, + .base = .r11, + }), .r12, isel.code()); try expectEqualHexStrings( "\x4D\x29\xA3\x00\x00\x00\x10", isel.lowered(), "sub qword ptr [r11 + 0x10000000], r12", ); - try lowerToMrEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), .r12, isel.code()); + try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, isel.code()); try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12"); } @@ -1935,21 +1971,24 @@ test "lower M encoding" { try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12"); try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code()); try expectEqualHexStrings("\x66\x41\xFF\xE4", isel.lowered(), "jmp r12w"); - try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0, .qword_ptr), isel.code()); + try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r12 }), isel.code()); try expectEqualHexStrings("\x41\xFF\x24\x24", isel.lowered(), "jmp qword ptr [r12]"); - try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0, .word_ptr), isel.code()); + try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.word_ptr, .{ .disp = 0, .base = .r12 }), isel.code()); try expectEqualHexStrings("\x66\x41\xFF\x24\x24", isel.lowered(), "jmp word ptr [r12]"); - try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0x10, .qword_ptr), isel.code()); + try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10, .base = .r12 }), isel.code()); try expectEqualHexStrings("\x41\xFF\x64\x24\x10", isel.lowered(), "jmp qword ptr [r12 + 0x10]"); - try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0x1000, .qword_ptr), isel.code()); + try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0x1000, + .base = .r12, + }), isel.code()); try expectEqualHexStrings( "\x41\xFF\xA4\x24\x00\x10\x00\x00", isel.lowered(), "jmp qword ptr [r12 + 0x1000]", ); - try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code()); + try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code()); try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [rip + 0x10]"); - try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10, .qword_ptr), isel.code()); + try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10 }), isel.code()); try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]"); try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code()); try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b"); @@ -1967,15 +2006,24 @@ test "lower O encoding" { test "lower RMI encoding" { var isel = TestIsel.init(); defer isel.deinit(); - try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.rbp, -8, .qword_ptr), 0x10, isel.code()); + try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = -8, + .base = .rbp, + }), 0x10, isel.code()); try expectEqualHexStrings( "\x48\x69\x45\xF8\x10\x00\x00\x00", isel.lowered(), "imul rax, qword ptr [rbp - 8], 0x10", ); - try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.rbp, -4, .dword_ptr), 0x10, isel.code()); + try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{ + .disp = -4, + .base = .rbp, + }), 0x10, isel.code()); try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10"); - try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.rbp, -2, .word_ptr), 0x10, isel.code()); + try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{ + .disp = -2, + .base = .rbp, + }), 0x10, isel.code()); try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10"); try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code()); try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", isel.lowered(), "imul r12, r12, 0x10");