authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-09 20:32:07+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-11 20:05:49+01:00
log32708dd6e2f16b4b688b2deed22253ea36233c91
treea2c1eaa13120f9f01c685f8e562241e3a053f2d4
parent9658ab676643ef5c2457ac4908c180e05dc7f729

x86_64: add RM and MR helpers to codegen


4 files changed, 397 insertions(+), 266 deletions(-)

src/arch/x86_64/CodeGen.zig+190-229
...@@ -491,6 +491,72 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme...@@ -491,6 +491,72 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
491 });491 });
492}492}
493493
494fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
495 const ops: Mir.Inst.Ops = switch (m) {
496 .sib => .m_sib,
497 .rip => .m_rip,
498 else => unreachable,
499 };
500 const data: Mir.Inst.Data = switch (ops) {
501 .m_sib => .{ .payload = try self.addExtra(Mir.MemorySib.encode(m)) },
502 .m_rip => .{ .payload = try self.addExtra(Mir.MemoryRip.encode(m)) },
503 else => unreachable,
504 };
505 _ = try self.addInst(.{
506 .tag = tag,
507 .ops = ops,
508 .data = data,
509 });
510}
511
512fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {
513 const ops: Mir.Inst.Ops = switch (m) {
514 .sib => .rm_sib,
515 .rip => .rm_rip,
516 else => unreachable,
517 };
518 const data: Mir.Inst.Data = switch (ops) {
519 .rm_sib => .{ .rx = .{
520 .r1 = reg,
521 .payload = try self.addExtra(Mir.MemorySib.encode(m)),
522 } },
523 .rm_rip => .{ .rx = .{
524 .r1 = reg,
525 .payload = try self.addExtra(Mir.MemoryRip.encode(m)),
526 } },
527 else => unreachable,
528 };
529 _ = try self.addInst(.{
530 .tag = tag,
531 .ops = ops,
532 .data = data,
533 });
534}
535
536fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {
537 const ops: Mir.Inst.Ops = switch (m) {
538 .sib => .mr_sib,
539 .rip => .mr_rip,
540 else => unreachable,
541 };
542 const data: Mir.Inst.Data = switch (ops) {
543 .mr_sib => .{ .rx = .{
544 .r1 = reg,
545 .payload = try self.addExtra(Mir.MemorySib.encode(m)),
546 } },
547 .mr_rip => .{ .rx = .{
548 .r1 = reg,
549 .payload = try self.addExtra(Mir.MemoryRip.encode(m)),
550 } },
551 else => unreachable,
552 };
553 _ = try self.addInst(.{
554 .tag = tag,
555 .ops = ops,
556 .data = data,
557 });
558}
559
494fn gen(self: *Self) InnerError!void {560fn gen(self: *Self) InnerError!void {
495 const cc = self.fn_type.fnCallingConvention();561 const cc = self.fn_type.fnCallingConvention();
496 if (cc != .Naked) {562 if (cc != .Naked) {
...@@ -1741,23 +1807,10 @@ fn genIntMulDivOpMir(...@@ -1741,23 +1807,10 @@ fn genIntMulDivOpMir(
17411807
1742 switch (factor) {1808 switch (factor) {
1743 .register => |reg| try self.asmRegister(tag, reg),1809 .register => |reg| try self.asmRegister(tag, reg),
1744 .stack_offset => |off| {1810 .stack_offset => |off| try self.asmMemory(tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
1745 _ = off;1811 .base = .rbp,
1746 // _ = try self.addInst(.{1812 .disp = -off,
1747 // .tag = tag,1813 })),
1748 // .ops = Mir.Inst.Ops.encode(.{
1749 // .reg2 = .rbp,
1750 // .flags = switch (abi_size) {
1751 // 1 => 0b00,
1752 // 2 => 0b01,
1753 // 4 => 0b10,
1754 // 8 => 0b11,
1755 // else => unreachable,
1756 // },
1757 // }),
1758 // .data = .{ .disp = -off },
1759 // });
1760 },
1761 else => unreachable,1814 else => unreachable,
1762 }1815 }
1763}1816}
...@@ -2222,19 +2275,10 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -2222,19 +2275,10 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
22222275
2223 const addr_reg = try self.register_manager.allocReg(null, gp);2276 const addr_reg = try self.register_manager.allocReg(null, gp);
2224 switch (slice_mcv) {2277 switch (slice_mcv) {
2225 .stack_offset => |off| {2278 .stack_offset => |off| try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
2226 _ = off;2279 .base = .rbp,
2227 // mov reg, [rbp - 8]2280 .disp = -off,
2228 // _ = try self.addInst(.{2281 })),
2229 // .tag = .mov,
2230 // .ops = Mir.Inst.Ops.encode(.{
2231 // .reg1 = addr_reg.to64(),
2232 // .reg2 = .rbp,
2233 // .flags = 0b01,
2234 // }),
2235 // .data = .{ .disp = -@intCast(i32, off) },
2236 // });
2237 },
2238 else => return self.fail("TODO implement slice_elem_ptr when slice is {}", .{slice_mcv}),2282 else => return self.fail("TODO implement slice_elem_ptr when slice is {}", .{slice_mcv}),
2239 }2283 }
2240 // TODO we could allocate register here, but need to expect addr register and potentially2284 // TODO we could allocate register here, but need to expect addr register and potentially
...@@ -2309,27 +2353,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2309,27 +2353,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2309 array_ty.abiAlignment(self.target.*),2353 array_ty.abiAlignment(self.target.*),
2310 ));2354 ));
2311 try self.genSetStack(array_ty, off, array, .{});2355 try self.genSetStack(array_ty, off, array, .{});
2312 // lea reg, [rbp]2356 try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{
2313 // _ = try self.addInst(.{2357 .base = .rbp,
2314 // .tag = .lea,2358 .disp = -off,
2315 // .ops = Mir.Inst.Ops.encode(.{2359 }));
2316 // .reg1 = addr_reg.to64(),
2317 // .reg2 = .rbp,
2318 // }),
2319 // .data = .{ .disp = -off },
2320 // });
2321 },2360 },
2322 .stack_offset => |off| {2361 .stack_offset => |off| {
2323 _ = off;2362 try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{
2324 // lea reg, [rbp]2363 .base = .rbp,
2325 // _ = try self.addInst(.{2364 .disp = -off,
2326 // .tag = .lea,2365 }));
2327 // .ops = Mir.Inst.Ops.encode(.{
2328 // .reg1 = addr_reg.to64(),
2329 // .reg2 = .rbp,
2330 // }),
2331 // .data = .{ .disp = -off },
2332 // });
2333 },2366 },
2334 .memory, .linker_load => {2367 .memory, .linker_load => {
2335 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);2368 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
...@@ -2366,7 +2399,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2366,7 +2399,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2366 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);2399 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
23672400
2368 const elem_ty = ptr_ty.elemType2();2401 const elem_ty = ptr_ty.elemType2();
2369 const elem_abi_size = elem_ty.abiSize(self.target.*);2402 const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
2370 const index_ty = self.air.typeOf(bin_op.rhs);2403 const index_ty = self.air.typeOf(bin_op.rhs);
2371 const index = try self.resolveInst(bin_op.rhs);2404 const index = try self.resolveInst(bin_op.rhs);
2372 const index_lock: ?RegisterLock = switch (index) {2405 const index_lock: ?RegisterLock = switch (index) {
...@@ -2386,16 +2419,14 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2386,16 +2419,14 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2386 if (elem_abi_size > 8) {2419 if (elem_abi_size > 8) {
2387 return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});2420 return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});
2388 } else {2421 } else {
2389 // mov dst_mcv, [dst_mcv]2422 try self.asmRegisterMemory(
2390 // _ = try self.addInst(.{2423 .mov,
2391 // .tag = .mov,2424 registerAlias(dst_mcv.register, elem_abi_size),
2392 // .ops = Mir.Inst.Ops.encode(.{2425 Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{
2393 // .reg1 = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)),2426 .base = dst_mcv.register,
2394 // .reg2 = dst_mcv.register,2427 .disp = 0,
2395 // .flags = 0b01,2428 }),
2396 // }),2429 );
2397 // .data = .{ .disp = 0 },
2398 // });
2399 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };2430 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
2400 }2431 }
2401 };2432 };
...@@ -2622,7 +2653,7 @@ fn reuseOperand(...@@ -2622,7 +2653,7 @@ fn reuseOperand(
26222653
2623fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {2654fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {
2624 const elem_ty = ptr_ty.elemType();2655 const elem_ty = ptr_ty.elemType();
2625 const abi_size = elem_ty.abiSize(self.target.*);2656 const abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
2626 switch (ptr) {2657 switch (ptr) {
2627 .none => unreachable,2658 .none => unreachable,
2628 .undef => unreachable,2659 .undef => unreachable,
...@@ -2649,17 +2680,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2649,17 +2680,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2649 .undef => unreachable,2680 .undef => unreachable,
2650 .eflags => unreachable,2681 .eflags => unreachable,
2651 .register => |dst_reg| {2682 .register => |dst_reg| {
2652 _ = dst_reg;2683 try self.asmRegisterMemory(
2653 // mov dst_reg, [reg]2684 .mov,
2654 // _ = try self.addInst(.{2685 registerAlias(dst_reg, abi_size),
2655 // .tag = .mov,2686 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg, .disp = 0 }),
2656 // .ops = Mir.Inst.Ops.encode(.{2687 );
2657 // .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
2658 // .reg2 = reg,
2659 // .flags = 0b01,
2660 // }),
2661 // .data = .{ .disp = 0 },
2662 // });
2663 },2688 },
2664 .stack_offset => |off| {2689 .stack_offset => |off| {
2665 if (abi_size <= 8) {2690 if (abi_size <= 8) {
...@@ -2874,17 +2899,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2874,17 +2899,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28742899
2875 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);2900 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);
28762901
2877 // to get the actual address of the value we want to modify we have to go through the GOT2902 // To get the actual address of the value we want to modify we have to go through the GOT
2878 // mov reg, [reg]2903 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
2879 // _ = try self.addInst(.{2904 .base = addr_reg.to64(),
2880 // .tag = .mov,2905 .disp = 0,
2881 // .ops = Mir.Inst.Ops.encode(.{2906 }));
2882 // .reg1 = addr_reg.to64(),
2883 // .reg2 = addr_reg.to64(),
2884 // .flags = 0b01,
2885 // }),
2886 // .data = .{ .disp = 0 },
2887 // });
28882907
2889 const new_ptr = MCValue{ .register = addr_reg.to64() };2908 const new_ptr = MCValue{ .register = addr_reg.to64() };
28902909
...@@ -2936,16 +2955,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2936,16 +2955,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2936 defer self.register_manager.unlockReg(tmp_reg_lock);2955 defer self.register_manager.unlockReg(tmp_reg_lock);
29372956
2938 try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value);2957 try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value);
2958 try self.asmRegisterMemory(.mov, tmp_reg, Memory.sib(.qword, .{
2959 .base = tmp_reg,
2960 .disp = 0,
2961 }));
29392962
2940 // _ = try self.addInst(.{
2941 // .tag = .mov,
2942 // .ops = Mir.Inst.Ops.encode(.{
2943 // .reg1 = tmp_reg,
2944 // .reg2 = tmp_reg,
2945 // .flags = 0b01,
2946 // }),
2947 // .data = .{ .disp = 0 },
2948 // });
2949 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);2963 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
2950 }2964 }
29512965
...@@ -3603,15 +3617,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3603,15 +3617,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3603 if (off > math.maxInt(i32)) {3617 if (off > math.maxInt(i32)) {
3604 return self.fail("stack offset too large", .{});3618 return self.fail("stack offset too large", .{});
3605 }3619 }
3606 // _ = try self.addInst(.{3620 try self.asmRegisterMemory(
3607 // .tag = mir_tag,3621 mir_tag,
3608 // .ops = Mir.Inst.Ops.encode(.{3622 registerAlias(dst_reg, abi_size),
3609 // .reg1 = registerAlias(dst_reg, abi_size),3623 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
3610 // .reg2 = .rbp,3624 );
3611 // .flags = 0b01,
3612 // }),
3613 // .data = .{ .disp = -off },
3614 // });
3615 },3625 },
3616 }3626 }
3617 },3627 },
...@@ -3629,16 +3639,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3629,16 +3639,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3629 .dead, .unreach => unreachable,3639 .dead, .unreach => unreachable,
3630 .register_overflow => unreachable,3640 .register_overflow => unreachable,
3631 .register => |src_reg| {3641 .register => |src_reg| {
3632 _ = src_reg;3642 try self.asmMemoryRegister(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
3633 // _ = try self.addInst(.{3643 .base = .rbp,
3634 // .tag = mir_tag,3644 .disp = -off,
3635 // .ops = Mir.Inst.Ops.encode(.{3645 }), registerAlias(src_reg, abi_size));
3636 // .reg1 = .rbp,
3637 // .reg2 = registerAlias(src_reg, abi_size),
3638 // .flags = 0b10,
3639 // }),
3640 // .data = .{ .disp = -off },
3641 // });
3642 },3646 },
3643 .immediate => |imm| {3647 .immediate => |imm| {
3644 _ = imm;3648 _ = imm;
...@@ -3738,16 +3742,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3738,16 +3742,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3738 }3742 }
3739 },3743 },
3740 .stack_offset => |off| {3744 .stack_offset => |off| {
3741 _ = off;3745 try self.asmRegisterMemory(
3742 // _ = try self.addInst(.{3746 .imul,
3743 // .tag = .imul_complex,3747 registerAlias(dst_reg, abi_size),
3744 // .ops = Mir.Inst.Ops.encode(.{3748 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
3745 // .reg1 = registerAlias(dst_reg, abi_size),3749 );
3746 // .reg2 = .rbp,
3747 // .flags = 0b01,
3748 // }),
3749 // .data = .{ .disp = -off },
3750 // });
3751 },3750 },
3752 .memory => {3751 .memory => {
3753 return self.fail("TODO implement x86 multiply source memory", .{});3752 return self.fail("TODO implement x86 multiply source memory", .{});
...@@ -3770,17 +3769,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3770,17 +3769,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3770 .register => |src_reg| {3769 .register => |src_reg| {
3771 // copy dst to a register3770 // copy dst to a register
3772 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);3771 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
3773 _ = src_reg;3772 try self.asmRegisterRegister(
3774 // multiply into dst_reg3773 .imul,
3775 // register, register3774 registerAlias(dst_reg, abi_size),
3776 // _ = try self.addInst(.{3775 registerAlias(src_reg, abi_size),
3777 // .tag = .imul_complex,3776 );
3778 // .ops = Mir.Inst.Ops.encode(.{
3779 // .reg1 = registerAlias(dst_reg, abi_size),
3780 // .reg2 = registerAlias(src_reg, abi_size),
3781 // }),
3782 // .data = undefined,
3783 // });
3784 // copy dst_reg back out3777 // copy dst_reg back out
3785 return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{});3778 return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{});
3786 },3779 },
...@@ -4006,11 +3999,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4006,11 +3999,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40063999
4007 if (info.stack_byte_count > 0) {4000 if (info.stack_byte_count > 0) {
4008 // Adjust the stack4001 // Adjust the stack
4009 // _ = try self.addInst(.{4002 try self.asmRegisterImmediate(.sub, .rsp, Immediate.u(info.stack_byte_count));
4010 // .tag = .sub,
4011 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
4012 // .data = .{ .imm = info.stack_byte_count },
4013 // });
4014 }4003 }
40154004
4016 // Due to incremental compilation, how function calls are generated depends4005 // Due to incremental compilation, how function calls are generated depends
...@@ -4161,7 +4150,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -4161,7 +4150,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
4161 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction4150 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
4162 // which is available if the jump is 127 bytes or less forward.4151 // which is available if the jump is 127 bytes or less forward.
4163 const jmp_reloc = try self.addInst(.{4152 const jmp_reloc = try self.addInst(.{
4164 .tag = .jmp,4153 .tag = .jmp_reloc,
4165 .ops = .inst,4154 .ops = .inst,
4166 .data = .{ .inst = undefined },4155 .data = .{ .inst = undefined },
4167 });4156 });
...@@ -4197,7 +4186,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -4197,7 +4186,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
4197 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction4186 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
4198 // which is available if the jump is 127 bytes or less forward.4187 // which is available if the jump is 127 bytes or less forward.
4199 const jmp_reloc = try self.addInst(.{4188 const jmp_reloc = try self.addInst(.{
4200 .tag = .jmp,4189 .tag = .jmp_reloc,
4201 .ops = .inst,4190 .ops = .inst,
4202 .data = .{ .inst = undefined },4191 .data = .{ .inst = undefined },
4203 });4192 });
...@@ -4738,7 +4727,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -4738,7 +4727,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
4738 const jmp_target = @intCast(u32, self.mir_instructions.len);4727 const jmp_target = @intCast(u32, self.mir_instructions.len);
4739 try self.genBody(body);4728 try self.genBody(body);
4740 _ = try self.addInst(.{4729 _ = try self.addInst(.{
4741 .tag = .jmp,4730 .tag = .jmp_reloc,
4742 .ops = .inst,4731 .ops = .inst,
4743 .data = .{ .inst = jmp_target },4732 .data = .{ .inst = jmp_target },
4744 });4733 });
...@@ -5035,7 +5024,7 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {...@@ -5035,7 +5024,7 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
5035 .jcc => {5024 .jcc => {
5036 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;5025 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
5037 },5026 },
5038 .jmp => {5027 .jmp_reloc => {
5039 self.mir_instructions.items(.data)[reloc].inst = next_inst;5028 self.mir_instructions.items(.data)[reloc].inst = next_inst;
5040 },5029 },
5041 else => unreachable,5030 else => unreachable,
...@@ -5078,7 +5067,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {...@@ -5078,7 +5067,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
5078 try block_data.relocs.ensureUnusedCapacity(self.gpa, 1);5067 try block_data.relocs.ensureUnusedCapacity(self.gpa, 1);
5079 // Leave the jump offset undefined5068 // Leave the jump offset undefined
5080 const jmp_reloc = try self.addInst(.{5069 const jmp_reloc = try self.addInst(.{
5081 .tag = .jmp,5070 .tag = .jmp_reloc,
5082 .ops = .inst,5071 .ops = .inst,
5083 .data = .{ .inst = undefined },5072 .data = .{ .inst = undefined },
5084 });5073 });
...@@ -5247,7 +5236,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {...@@ -5247,7 +5236,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
5247}5236}
52485237
5249fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {5238fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {
5250 const abi_size = ty.abiSize(self.target.*);5239 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
5251 switch (mcv) {5240 switch (mcv) {
5252 .dead => unreachable,5241 .dead => unreachable,
5253 .unreach, .none => return,5242 .unreach, .none => return,
...@@ -5325,36 +5314,25 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5325,36 +5314,25 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5325 .{ty.fmtDebug()},5314 .{ty.fmtDebug()},
5326 ),5315 ),
5327 };5316 };
5328 _ = tag;5317 // TODO verify this
5329 _ = reg;5318 const ptr_size: Memory.PtrSize = switch (ty.tag()) {
5330 // _ = try self.addInst(.{5319 .f32 => .dword,
5331 // .tag = tag,5320 .f64 => .qword,
5332 // .ops = Mir.Inst.Ops.encode(.{5321 else => unreachable,
5333 // .reg1 = switch (ty.tag()) {5322 };
5334 // .f32 => .esp,5323 return self.asmMemoryRegister(tag, Memory.sib(ptr_size, .{
5335 // .f64 => .rsp,5324 .base = .rsp,
5336 // else => unreachable,5325 .disp = -stack_offset,
5337 // },5326 }), reg.to128());
5338 // .reg2 = reg.to128(),
5339 // .flags = 0b01,
5340 // }),
5341 // .data = .{ .disp = -stack_offset },
5342 // });
5343 return;
5344 }5327 }
53455328
5346 return self.fail("TODO genSetStackArg for register with no intrinsics", .{});5329 return self.fail("TODO genSetStackArg for register with no intrinsics", .{});
5347 },5330 },
5348 else => {5331 else => {
5349 // _ = try self.addInst(.{5332 try self.asmMemoryRegister(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5350 // .tag = .mov,5333 .base = .rsp,
5351 // .ops = Mir.Inst.Ops.encode(.{5334 .disp = -stack_offset,
5352 // .reg1 = .rsp,5335 }), registerAlias(reg, abi_size));
5353 // .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
5354 // .flags = 0b10,
5355 // }),
5356 // .data = .{ .disp = -stack_offset },
5357 // });
5358 },5336 },
5359 }5337 }
5360 },5338 },
...@@ -5507,25 +5485,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5507,25 +5485,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5507 switch (ty.zigTypeTag()) {5485 switch (ty.zigTypeTag()) {
5508 .Float => {5486 .Float => {
5509 if (intrinsicsAllowed(self.target.*, ty)) {5487 if (intrinsicsAllowed(self.target.*, ty)) {
5510 // const tag: Mir.Inst.Tag = switch (ty.tag()) {5488 const tag: Mir.Inst.Tag = switch (ty.tag()) {
5511 // .f32 => Mir.Inst.Tag.mov_f32,5489 .f32 => .movss,
5512 // .f64 => Mir.Inst.Tag.mov_f64,5490 .f64 => .movsd,
5513 // else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}),5491 else => return self.fail(
5514 // };5492 "TODO genSetStack for register for type {}",
5515 // _ = try self.addInst(.{5493 .{ty.fmtDebug()},
5516 // .tag = tag,5494 ),
5517 // .ops = Mir.Inst.Ops.encode(.{5495 };
5518 // .reg1 = switch (ty.tag()) {5496 const ptr_size: Memory.PtrSize = switch (ty.tag()) {
5519 // .f32 => base_reg.to32(),5497 .f32 => .dword,
5520 // .f64 => base_reg.to64(),5498 .f64 => .qword,
5521 // else => unreachable,5499 else => unreachable,
5522 // },5500 };
5523 // .reg2 = reg.to128(),5501 return self.asmMemoryRegister(tag, Memory.sib(ptr_size, .{
5524 // .flags = 0b01,5502 .base = base_reg.to64(),
5525 // }),5503 .disp = -stack_offset,
5526 // .data = .{ .disp = -stack_offset },5504 }), reg.to128());
5527 // });
5528 return;
5529 }5505 }
55305506
5531 return self.fail("TODO genSetStack for register for type float with no intrinsics", .{});5507 return self.fail("TODO genSetStack for register for type float with no intrinsics", .{});
...@@ -5590,16 +5566,10 @@ fn genInlineMemcpyRegisterRegister(...@@ -5590,16 +5566,10 @@ fn genInlineMemcpyRegisterRegister(
5590 var remainder = abi_size;5566 var remainder = abi_size;
5591 while (remainder > 0) {5567 while (remainder > 0) {
5592 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));5568 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));
55935569 try self.asmMemoryRegister(.mov, Memory.sib(Memory.PtrSize.fromSize(nearest_power_of_two), .{
5594 // _ = try self.addInst(.{5570 .base = dst_reg,
5595 // .tag = .mov,5571 .disp = -next_offset,
5596 // .ops = Mir.Inst.Ops.encode(.{5572 }), registerAlias(tmp_reg, nearest_power_of_two));
5597 // .reg1 = dst_reg,
5598 // .reg2 = registerAlias(tmp_reg, nearest_power_of_two),
5599 // .flags = 0b10,
5600 // }),
5601 // .data = .{ .disp = -next_offset },
5602 // });
56035573
5604 if (nearest_power_of_two > 1) {5574 if (nearest_power_of_two > 1) {
5605 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{5575 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{
...@@ -5611,15 +5581,10 @@ fn genInlineMemcpyRegisterRegister(...@@ -5611,15 +5581,10 @@ fn genInlineMemcpyRegisterRegister(
5611 next_offset -= nearest_power_of_two;5581 next_offset -= nearest_power_of_two;
5612 }5582 }
5613 } else {5583 } else {
5614 // _ = try self.addInst(.{5584 try self.asmMemoryRegister(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5615 // .tag = .mov,5585 .base = dst_reg,
5616 // .ops = Mir.Inst.Ops.encode(.{5586 .disp = -offset,
5617 // .reg1 = dst_reg,5587 }), registerAlias(src_reg, abi_size));
5618 // .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
5619 // .flags = 0b10,
5620 // }),
5621 // .data = .{ .disp = -offset },
5622 // });
5623 }5588 }
5624}5589}
56255590
...@@ -5660,15 +5625,10 @@ fn genInlineMemcpy(...@@ -5660,15 +5625,10 @@ fn genInlineMemcpy(
5660 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);5625 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);
5661 },5626 },
5662 .ptr_stack_offset, .stack_offset => |off| {5627 .ptr_stack_offset, .stack_offset => |off| {
5663 _ = off;5628 try self.asmRegisterMemory(.lea, dst_addr_reg.to64(), Memory.sib(.qword, .{
5664 // _ = try self.addInst(.{5629 .base = opts.dest_stack_base orelse .rbp,
5665 // .tag = .lea,5630 .disp = -off,
5666 // .ops = Mir.Inst.Ops.encode(.{5631 }));
5667 // .reg1 = dst_addr_reg.to64(),
5668 // .reg2 = opts.dest_stack_base orelse .rbp,
5669 // }),
5670 // .data = .{ .disp = -off },
5671 // });
5672 },5632 },
5673 .register => |reg| {5633 .register => |reg| {
5674 try self.asmRegisterRegister(5634 try self.asmRegisterRegister(
...@@ -5754,7 +5714,7 @@ fn genInlineMemcpy(...@@ -5754,7 +5714,7 @@ fn genInlineMemcpy(
5754 try self.asmRegisterImmediate(.sub, count_reg, Immediate.u(1));5714 try self.asmRegisterImmediate(.sub, count_reg, Immediate.u(1));
57555715
5756 _ = try self.addInst(.{5716 _ = try self.addInst(.{
5757 .tag = .jmp,5717 .tag = .jmp_reloc,
5758 .ops = .inst,5718 .ops = .inst,
5759 .data = .{ .inst = loop_start },5719 .data = .{ .inst = loop_start },
5760 });5720 });
...@@ -5857,7 +5817,7 @@ fn genInlineMemset(...@@ -5857,7 +5817,7 @@ fn genInlineMemset(
5857 try self.asmRegisterImmediate(.sub, index_reg, Immediate.u(1));5817 try self.asmRegisterImmediate(.sub, index_reg, Immediate.u(1));
58585818
5859 _ = try self.addInst(.{5819 _ = try self.addInst(.{
5860 .tag = .jmp,5820 .tag = .jmp_reloc,
5861 .ops = .inst,5821 .ops = .inst,
5862 .data = .{ .inst = loop_start },5822 .data = .{ .inst = loop_start },
5863 });5823 });
...@@ -6045,19 +6005,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6045,19 +6005,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6045 // .data = .{ .disp = @intCast(i32, x) },6005 // .data = .{ .disp = @intCast(i32, x) },
6046 // });6006 // });
6047 } else {6007 } else {
6048 // If this is RAX, we can use a direct load.
6049 // Otherwise, we need to load the address, then indirectly load the value.
6050 if (reg.to64() == .rax) {6008 if (reg.to64() == .rax) {
6051 // movabs rax, ds:moffs646009 // If this is RAX, we can use a direct load.
6052 // const payload = try self.addExtra(Mir.Imm64.encode(x));6010 // Otherwise, we need to load the address, then indirectly load the value.
6053 // _ = try self.addInst(.{6011 var moffs: Mir.MemoryMoffs = .{
6054 // .tag = .movabs,6012 .seg = @enumToInt(Register.ds),
6055 // .ops = Mir.Inst.Ops.encode(.{6013 .msb = undefined,
6056 // .reg1 = .rax,6014 .lsb = undefined,
6057 // .flags = 0b01, // imm64 will become moffs646015 };
6058 // }),6016 moffs.encodeOffset(x);
6059 // .data = .{ .payload = payload },6017 _ = try self.addInst(.{
6060 // });6018 .tag = .mov_moffs,
6019 .ops = .rax_moffs,
6020 .data = .{ .payload = try self.addExtra(moffs) },
6021 });
6061 } else {6022 } else {
6062 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.6023 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
6063 try self.genSetReg(ty, reg, MCValue{ .immediate = x });6024 try self.genSetReg(ty, reg, MCValue{ .immediate = x });
src/arch/x86_64/Emit.zig+60-26
...@@ -73,6 +73,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -73,6 +73,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
73 .adc,73 .adc,
74 .add,74 .add,
75 .@"and",75 .@"and",
76 .call,
76 .cbw,77 .cbw,
77 .cwde,78 .cwde,
78 .cdqe,79 .cdqe,
...@@ -86,6 +87,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -86,6 +87,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
86 .idiv,87 .idiv,
87 .imul,88 .imul,
88 .int3,89 .int3,
90 .jmp,
91 .lea,
89 .mov,92 .mov,
90 .movzx,93 .movzx,
91 .mul,94 .mul,
...@@ -115,9 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -115,9 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
115 .ucomisd,118 .ucomisd,
116 => try emit.mirEncodeGeneric(tag, inst),119 => try emit.mirEncodeGeneric(tag, inst),
117120
118 .call,121 .jmp_reloc => try emit.mirJmpReloc(inst),
119 .jmp,122
120 => try emit.mirCallJmp(inst),123 .mov_moffs => try emit.mirMovMoffs(inst),
121124
122 .movsx => try emit.mirMovsx(inst),125 .movsx => try emit.mirMovsx(inst),
123 .cmovcc => try emit.mirCmovcc(inst),126 .cmovcc => try emit.mirCmovcc(inst),
...@@ -130,8 +133,6 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -130,8 +133,6 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
130133
131 .push_regs => try emit.mirPushPopRegisterList(.push, inst),134 .push_regs => try emit.mirPushPopRegisterList(.push, inst),
132 .pop_regs => try emit.mirPushPopRegisterList(.pop, inst),135 .pop_regs => try emit.mirPushPopRegisterList(.pop, inst),
133
134 else => return emit.fail("Implement MIR->Emit lowering for x86_64 for pseudo-inst: {}", .{tag}),
135 }136 }
136 }137 }
137138
...@@ -212,6 +213,34 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -212,6 +213,34 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
212 .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },213 .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
213 };214 };
214 },215 },
216 .m_sib => {
217 const msib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
218 operands[0] = .{ .mem = Mir.MemorySib.decode(msib) };
219 },
220 .m_rip => {
221 const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
222 operands[0] = .{ .mem = Mir.MemoryRip.decode(mrip) };
223 },
224 .rm_sib, .mr_sib => {
225 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
226 const op1 = .{ .reg = data.rx.r1 };
227 const op2 = .{ .mem = Mir.MemorySib.decode(msib) };
228 switch (ops) {
229 .rm_sib => operands[0..2].* = .{ op1, op2 },
230 .mr_sib => operands[0..2].* = .{ op2, op1 },
231 else => unreachable,
232 }
233 },
234 .rm_rip, .mr_rip => {
235 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
236 const op1 = .{ .reg = data.rx.r1 };
237 const op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };
238 switch (ops) {
239 .rm_rip => operands[0..2].* = .{ op1, op2 },
240 .mr_rip => operands[0..2].* = .{ op2, op1 },
241 else => unreachable,
242 }
243 },
215 else => unreachable, // TODO244 else => unreachable, // TODO
216 }245 }
217246
...@@ -223,6 +252,29 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -223,6 +252,29 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
223 });252 });
224}253}
225254
255fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
256 const ops = emit.mir.instructions.items(.ops)[inst];
257 const payload = emit.mir.instructions.items(.data)[inst].payload;
258 const moffs = emit.mir.extraData(Mir.MemoryMoffs, payload).data;
259 const seg = @intToEnum(Register, moffs.seg);
260 const offset = moffs.decodeOffset();
261 switch (ops) {
262 .rax_moffs => {
263 try emit.encode(.mov, .{
264 .op1 = .{ .reg = .rax },
265 .op2 = .{ .mem = Memory.moffs(seg, offset) },
266 });
267 },
268 .moffs_rax => {
269 try emit.encode(.mov, .{
270 .op1 = .{ .mem = Memory.moffs(seg, offset) },
271 .op2 = .{ .reg = .rax },
272 });
273 },
274 else => unreachable,
275 }
276}
277
226fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {278fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
227 const ops = emit.mir.instructions.items(.ops)[inst];279 const ops = emit.mir.instructions.items(.ops)[inst];
228 const data = emit.mir.instructions.items(.data)[inst];280 const data = emit.mir.instructions.items(.data)[inst];
...@@ -302,19 +354,13 @@ fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -302,19 +354,13 @@ fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
302 }354 }
303}355}
304356
305fn mirCallJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {357fn mirJmpReloc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
306 const tag = emit.mir.instructions.items(.tag)[inst];
307 const mnemonic: Instruction.Mnemonic = switch (tag) {
308 .call => .call,
309 .jmp => .jmp,
310 else => unreachable,
311 };
312 const ops = emit.mir.instructions.items(.ops)[inst];358 const ops = emit.mir.instructions.items(.ops)[inst];
313 switch (ops) {359 switch (ops) {
314 .inst => {360 .inst => {
315 const target = emit.mir.instructions.items(.data)[inst].inst;361 const target = emit.mir.instructions.items(.data)[inst].inst;
316 const source = emit.code.items.len;362 const source = emit.code.items.len;
317 try emit.encode(mnemonic, .{363 try emit.encode(.jmp, .{
318 .op1 = .{ .imm = Immediate.s(0) },364 .op1 = .{ .imm = Immediate.s(0) },
319 });365 });
320 try emit.relocs.append(emit.bin_file.allocator, .{366 try emit.relocs.append(emit.bin_file.allocator, .{
...@@ -324,19 +370,7 @@ fn mirCallJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -324,19 +370,7 @@ fn mirCallJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
324 .length = 5,370 .length = 5,
325 });371 });
326 },372 },
327 .r => {373 else => unreachable,
328 const reg = emit.mir.instructions.items(.data)[inst].r;
329 try emit.encode(mnemonic, .{
330 .op1 = .{ .reg = reg },
331 });
332 },
333 .imm_s => {
334 const imm = emit.mir.instructions.items(.data)[inst].imm_s;
335 try emit.encode(mnemonic, .{
336 .op1 = .{ .imm = Immediate.s(imm) },
337 });
338 },
339 else => unreachable, // TODO
340 }374 }
341}375}
342376
src/arch/x86_64/Mir.zig+136-11
...@@ -17,6 +17,7 @@ const encoder = @import("encoder.zig");...@@ -17,6 +17,7 @@ const encoder = @import("encoder.zig");
17const Air = @import("../../Air.zig");17const Air = @import("../../Air.zig");
18const CodeGen = @import("CodeGen.zig");18const CodeGen = @import("CodeGen.zig");
19const IntegerBitSet = std.bit_set.IntegerBitSet;19const IntegerBitSet = std.bit_set.IntegerBitSet;
20const Memory = bits.Memory;
20const Register = bits.Register;21const Register = bits.Register;
2122
22instructions: std.MultiArrayList(Inst).Slice,23instructions: std.MultiArrayList(Inst).Slice,
...@@ -135,6 +136,12 @@ pub const Inst = struct {...@@ -135,6 +136,12 @@ pub const Inst = struct {
135 /// Conditional move136 /// Conditional move
136 cmovcc,137 cmovcc,
137138
139 /// Mov absolute to/from memory wrt segment register to/from rax
140 mov_moffs,
141
142 /// Jump with relocation to another local MIR instruction
143 jmp_reloc,
144
138 /// End of prologue145 /// End of prologue
139 dbg_prologue_end,146 dbg_prologue_end,
140 /// Start of epilogue147 /// Start of epilogue
...@@ -186,24 +193,48 @@ pub const Inst = struct {...@@ -186,24 +193,48 @@ pub const Inst = struct {
186 /// Relative displacement operand.193 /// Relative displacement operand.
187 /// Uses `rel` payload.194 /// Uses `rel` payload.
188 rel,195 rel,
189 /// Register, memory operands.196 /// Register, memory (SIB) operands.
197 /// Uses `rx` payload.
198 rm_sib,
199 /// Register, memory (RIP) operands.
190 /// Uses `rx` payload.200 /// Uses `rx` payload.
191 rm,201 rm_rip,
192 /// Register, memory, immediate (unsigned) operands202 /// Register, memory, immediate (unsigned) operands
193 /// Uses `rx` payload.203 /// Uses `rx` payload.
194 rmi_u,204 rmi_u,
195 /// Register, memory, immediate (sign-extended) operands205 /// Register, memory, immediate (sign-extended) operands
196 /// Uses `rx` payload.206 /// Uses `rx` payload.
197 rmi_s,207 rmi_s,
198 /// Memory, immediate (unsigned) operands.208 /// Single memory (SIB) operand.
199 /// Uses `payload` payload.209 /// Uses `payload` with extra data of type `MemorySib`.
200 mi_u,210 m_sib,
201 /// Memory, immediate (sign-extend) operands.211 /// Single memory (RIP) operand.
202 /// Uses `payload` payload.212 /// Uses `payload` with extra data of type `MemoryRip`.
203 mi_s,213 m_rip,
204 /// Memory, register operands.214 /// Memory (SIB), immediate (unsigned) operands.
205 /// Uses `payload` payload.215 /// Uses `xi_u` payload with extra data of type `MemorySib`.
206 mr,216 mi_u_sib,
217 /// Memory (RIP), immediate (unsigned) operands.
218 /// Uses `xi_u` payload with extra data of type `MemoryRip`.
219 mi_u_rip,
220 /// Memory (SIB), immediate (sign-extend) operands.
221 /// Uses `xi_s` payload with extra data of type `MemorySib`.
222 mi_s_sib,
223 /// Memory (RIP), immediate (sign-extend) operands.
224 /// Uses `xi_s` payload with extra data of type `MemoryRip`.
225 mi_s_rip,
226 /// Memory (SIB), register operands.
227 /// Uses `rx` payload with extra data of type `MemorySib`.
228 mr_sib,
229 /// Memory (RIP), register operands.
230 /// Uses `rx` payload with extra data of type `MemoryRip`.
231 mr_rip,
232 /// Rax, Memory moffs.
233 /// Uses `payload` with extra data of type `MemoryMoffs`.
234 rax_moffs,
235 /// Memory moffs, rax.
236 /// Uses `payload` with extra data of type `MemoryMoffs`.
237 moffs_rax,
207 /// Lea into register with linker relocation.238 /// Lea into register with linker relocation.
208 /// Uses `payload` payload with data of type `LeaRegisterReloc`.239 /// Uses `payload` payload with data of type `LeaRegisterReloc`.
209 lea_r_reloc,240 lea_r_reloc,
...@@ -274,6 +305,16 @@ pub const Inst = struct {...@@ -274,6 +305,16 @@ pub const Inst = struct {
274 r1: Register,305 r1: Register,
275 payload: u32,306 payload: u32,
276 },307 },
308 /// Custom payload followed by an unsigned immediate.
309 xi_u: struct {
310 payload: u32,
311 imm: u32,
312 },
313 /// Custom payload followed by a signed immediate.
314 xi_s: struct {
315 payload: u32,
316 imm: i32,
317 },
277 /// Relocation for the linker where:318 /// Relocation for the linker where:
278 /// * `atom_index` is the index of the source319 /// * `atom_index` is the index of the source
279 /// * `sym_index` is the index of the target320 /// * `sym_index` is the index of the target
...@@ -378,6 +419,90 @@ pub const Imm64 = struct {...@@ -378,6 +419,90 @@ pub const Imm64 = struct {
378 }419 }
379};420};
380421
422// TODO this can be further compacted using packed struct
423pub const MemorySib = struct {
424 /// Size of the pointer.
425 ptr_size: u32,
426 /// Base register. -1 means null, or no base register.
427 base: i32,
428 /// Scale for index register. -1 means null, or no scale.
429 /// This has to be in sync with `index` field.
430 scale: i32,
431 /// Index register. -1 means null, or no index register.
432 /// This has to be in sync with `scale` field.
433 index: i32,
434 /// Displacement value.
435 disp: i32,
436
437 pub fn encode(mem: Memory) MemorySib {
438 const sib = mem.sib;
439 return .{
440 .ptr_size = @enumToInt(sib.ptr_size),
441 .base = if (sib.base) |r| @enumToInt(r) else -1,
442 .scale = if (sib.scale_index) |si| si.scale else -1,
443 .index = if (sib.scale_index) |si| @enumToInt(si.index) else -1,
444 .disp = sib.disp,
445 };
446 }
447
448 pub fn decode(msib: MemorySib) Memory {
449 const base: ?Register = if (msib.base == -1) null else @intToEnum(Register, msib.base);
450 const scale_index: ?Memory.ScaleIndex = if (msib.index == -1) null else .{
451 .scale = @intCast(u4, msib.scale),
452 .index = @intToEnum(Register, msib.index),
453 };
454 const mem: Memory = .{ .sib = .{
455 .ptr_size = @intToEnum(Memory.PtrSize, msib.ptr_size),
456 .base = base,
457 .scale_index = scale_index,
458 .disp = msib.disp,
459 } };
460 return mem;
461 }
462};
463
464pub const MemoryRip = struct {
465 /// Size of the pointer.
466 ptr_size: u32,
467 /// Displacement value.
468 disp: i32,
469
470 pub fn encode(mem: Memory) MemoryRip {
471 return .{
472 .ptr_size = @enumToInt(mem.rip.ptr_size),
473 .disp = mem.rip.disp,
474 };
475 }
476
477 pub fn decode(mrip: MemoryRip) Memory {
478 return .{ .rip = .{
479 .ptr_size = @intToEnum(Memory.PtrSize, mrip.ptr_size),
480 .disp = mrip.disp,
481 } };
482 }
483};
484
485pub const MemoryMoffs = struct {
486 /// Segment register.
487 seg: u32,
488 /// Absolute offset wrt to the segment register split between MSB and LSB parts much like
489 /// `Imm64` payload.
490 msb: u32,
491 lsb: u32,
492
493 pub fn encodeOffset(moffs: *MemoryMoffs, v: u64) void {
494 moffs.msb = @truncate(u32, v >> 32);
495 moffs.lsb = @truncate(u32, v);
496 }
497
498 pub fn decodeOffset(moffs: *const MemoryMoffs) u64 {
499 var res: u64 = 0;
500 res |= (@intCast(u64, moffs.msb) << 32);
501 res |= @intCast(u64, moffs.lsb);
502 return res;
503 }
504};
505
381pub const DbgLineColumn = struct {506pub const DbgLineColumn = struct {
382 line: u32,507 line: u32,
383 column: u32,508 column: u32,
src/arch/x86_64/bits.zig+11
...@@ -417,6 +417,17 @@ pub const Memory = union(enum) {...@@ -417,6 +417,17 @@ pub const Memory = union(enum) {
417 qword,417 qword,
418 tbyte,418 tbyte,
419419
420 pub fn fromSize(size: u32) PtrSize {
421 return switch (size) {
422 1 => .byte,
423 2 => .word,
424 4 => .dword,
425 8 => .qword,
426 10 => .tbyte,
427 else => unreachable,
428 };
429 }
430
420 pub fn fromBitSize(bit_size: u64) PtrSize {431 pub fn fromBitSize(bit_size: u64) PtrSize {
421 return switch (bit_size) {432 return switch (bit_size) {
422 8 => .byte,433 8 => .byte,