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
491491 });
492492}
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
494560fn gen(self: *Self) InnerError!void {
495561 const cc = self.fn_type.fnCallingConvention();
496562 if (cc != .Naked) {
......@@ -1741,23 +1807,10 @@ fn genIntMulDivOpMir(
17411807
17421808 switch (factor) {
17431809 .register => |reg| try self.asmRegister(tag, reg),
1744 .stack_offset => |off| {
1745 _ = off;
1746 // _ = try self.addInst(.{
1747 // .tag = tag,
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 },
1810 .stack_offset => |off| try self.asmMemory(tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
1811 .base = .rbp,
1812 .disp = -off,
1813 })),
17611814 else => unreachable,
17621815 }
17631816}
......@@ -2222,19 +2275,10 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
22222275
22232276 const addr_reg = try self.register_manager.allocReg(null, gp);
22242277 switch (slice_mcv) {
2225 .stack_offset => |off| {
2226 _ = off;
2227 // mov reg, [rbp - 8]
2228 // _ = try self.addInst(.{
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 },
2278 .stack_offset => |off| try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
2279 .base = .rbp,
2280 .disp = -off,
2281 })),
22382282 else => return self.fail("TODO implement slice_elem_ptr when slice is {}", .{slice_mcv}),
22392283 }
22402284 // 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 {
23092353 array_ty.abiAlignment(self.target.*),
23102354 ));
23112355 try self.genSetStack(array_ty, off, array, .{});
2312 // lea reg, [rbp]
2313 // _ = try self.addInst(.{
2314 // .tag = .lea,
2315 // .ops = Mir.Inst.Ops.encode(.{
2316 // .reg1 = addr_reg.to64(),
2317 // .reg2 = .rbp,
2318 // }),
2319 // .data = .{ .disp = -off },
2320 // });
2356 try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{
2357 .base = .rbp,
2358 .disp = -off,
2359 }));
23212360 },
23222361 .stack_offset => |off| {
2323 _ = off;
2324 // lea reg, [rbp]
2325 // _ = try self.addInst(.{
2326 // .tag = .lea,
2327 // .ops = Mir.Inst.Ops.encode(.{
2328 // .reg1 = addr_reg.to64(),
2329 // .reg2 = .rbp,
2330 // }),
2331 // .data = .{ .disp = -off },
2332 // });
2362 try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{
2363 .base = .rbp,
2364 .disp = -off,
2365 }));
23332366 },
23342367 .memory, .linker_load => {
23352368 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
......@@ -2366,7 +2399,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
23662399 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
23672400
23682401 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.*));
23702403 const index_ty = self.air.typeOf(bin_op.rhs);
23712404 const index = try self.resolveInst(bin_op.rhs);
23722405 const index_lock: ?RegisterLock = switch (index) {
......@@ -2386,16 +2419,14 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
23862419 if (elem_abi_size > 8) {
23872420 return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});
23882421 } else {
2389 // mov dst_mcv, [dst_mcv]
2390 // _ = try self.addInst(.{
2391 // .tag = .mov,
2392 // .ops = Mir.Inst.Ops.encode(.{
2393 // .reg1 = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)),
2394 // .reg2 = dst_mcv.register,
2395 // .flags = 0b01,
2396 // }),
2397 // .data = .{ .disp = 0 },
2398 // });
2422 try self.asmRegisterMemory(
2423 .mov,
2424 registerAlias(dst_mcv.register, elem_abi_size),
2425 Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{
2426 .base = dst_mcv.register,
2427 .disp = 0,
2428 }),
2429 );
23992430 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
24002431 }
24012432 };
......@@ -2622,7 +2653,7 @@ fn reuseOperand(
26222653
26232654fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {
26242655 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.*));
26262657 switch (ptr) {
26272658 .none => unreachable,
26282659 .undef => unreachable,
......@@ -2649,17 +2680,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26492680 .undef => unreachable,
26502681 .eflags => unreachable,
26512682 .register => |dst_reg| {
2652 _ = dst_reg;
2653 // mov dst_reg, [reg]
2654 // _ = try self.addInst(.{
2655 // .tag = .mov,
2656 // .ops = Mir.Inst.Ops.encode(.{
2657 // .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
2658 // .reg2 = reg,
2659 // .flags = 0b01,
2660 // }),
2661 // .data = .{ .disp = 0 },
2662 // });
2683 try self.asmRegisterMemory(
2684 .mov,
2685 registerAlias(dst_reg, abi_size),
2686 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg, .disp = 0 }),
2687 );
26632688 },
26642689 .stack_offset => |off| {
26652690 if (abi_size <= 8) {
......@@ -2874,17 +2899,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28742899
28752900 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 GOT
2878 // mov reg, [reg]
2879 // _ = try self.addInst(.{
2880 // .tag = .mov,
2881 // .ops = Mir.Inst.Ops.encode(.{
2882 // .reg1 = addr_reg.to64(),
2883 // .reg2 = addr_reg.to64(),
2884 // .flags = 0b01,
2885 // }),
2886 // .data = .{ .disp = 0 },
2887 // });
2902 // To get the actual address of the value we want to modify we have to go through the GOT
2903 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
2904 .base = addr_reg.to64(),
2905 .disp = 0,
2906 }));
28882907
28892908 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
29362955 defer self.register_manager.unlockReg(tmp_reg_lock);
29372956
29382957 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 // });
29492963 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
29502964 }
29512965
......@@ -3603,15 +3617,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36033617 if (off > math.maxInt(i32)) {
36043618 return self.fail("stack offset too large", .{});
36053619 }
3606 // _ = try self.addInst(.{
3607 // .tag = mir_tag,
3608 // .ops = Mir.Inst.Ops.encode(.{
3609 // .reg1 = registerAlias(dst_reg, abi_size),
3610 // .reg2 = .rbp,
3611 // .flags = 0b01,
3612 // }),
3613 // .data = .{ .disp = -off },
3614 // });
3620 try self.asmRegisterMemory(
3621 mir_tag,
3622 registerAlias(dst_reg, abi_size),
3623 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
3624 );
36153625 },
36163626 }
36173627 },
......@@ -3629,16 +3639,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36293639 .dead, .unreach => unreachable,
36303640 .register_overflow => unreachable,
36313641 .register => |src_reg| {
3632 _ = src_reg;
3633 // _ = try self.addInst(.{
3634 // .tag = mir_tag,
3635 // .ops = Mir.Inst.Ops.encode(.{
3636 // .reg1 = .rbp,
3637 // .reg2 = registerAlias(src_reg, abi_size),
3638 // .flags = 0b10,
3639 // }),
3640 // .data = .{ .disp = -off },
3641 // });
3642 try self.asmMemoryRegister(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
3643 .base = .rbp,
3644 .disp = -off,
3645 }), registerAlias(src_reg, abi_size));
36423646 },
36433647 .immediate => |imm| {
36443648 _ = imm;
......@@ -3738,16 +3742,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
37383742 }
37393743 },
37403744 .stack_offset => |off| {
3741 _ = off;
3742 // _ = try self.addInst(.{
3743 // .tag = .imul_complex,
3744 // .ops = Mir.Inst.Ops.encode(.{
3745 // .reg1 = registerAlias(dst_reg, abi_size),
3746 // .reg2 = .rbp,
3747 // .flags = 0b01,
3748 // }),
3749 // .data = .{ .disp = -off },
3750 // });
3745 try self.asmRegisterMemory(
3746 .imul,
3747 registerAlias(dst_reg, abi_size),
3748 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
3749 );
37513750 },
37523751 .memory => {
37533752 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
37703769 .register => |src_reg| {
37713770 // copy dst to a register
37723771 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
3773 _ = src_reg;
3774 // multiply into dst_reg
3775 // register, register
3776 // _ = try self.addInst(.{
3777 // .tag = .imul_complex,
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 // });
3772 try self.asmRegisterRegister(
3773 .imul,
3774 registerAlias(dst_reg, abi_size),
3775 registerAlias(src_reg, abi_size),
3776 );
37843777 // copy dst_reg back out
37853778 return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{});
37863779 },
......@@ -4006,11 +3999,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40063999
40074000 if (info.stack_byte_count > 0) {
40084001 // Adjust the stack
4009 // _ = try self.addInst(.{
4010 // .tag = .sub,
4011 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
4012 // .data = .{ .imm = info.stack_byte_count },
4013 // });
4002 try self.asmRegisterImmediate(.sub, .rsp, Immediate.u(info.stack_byte_count));
40144003 }
40154004
40164005 // Due to incremental compilation, how function calls are generated depends
......@@ -4161,7 +4150,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
41614150 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
41624151 // which is available if the jump is 127 bytes or less forward.
41634152 const jmp_reloc = try self.addInst(.{
4164 .tag = .jmp,
4153 .tag = .jmp_reloc,
41654154 .ops = .inst,
41664155 .data = .{ .inst = undefined },
41674156 });
......@@ -4197,7 +4186,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
41974186 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
41984187 // which is available if the jump is 127 bytes or less forward.
41994188 const jmp_reloc = try self.addInst(.{
4200 .tag = .jmp,
4189 .tag = .jmp_reloc,
42014190 .ops = .inst,
42024191 .data = .{ .inst = undefined },
42034192 });
......@@ -4738,7 +4727,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
47384727 const jmp_target = @intCast(u32, self.mir_instructions.len);
47394728 try self.genBody(body);
47404729 _ = try self.addInst(.{
4741 .tag = .jmp,
4730 .tag = .jmp_reloc,
47424731 .ops = .inst,
47434732 .data = .{ .inst = jmp_target },
47444733 });
......@@ -5035,7 +5024,7 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
50355024 .jcc => {
50365025 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
50375026 },
5038 .jmp => {
5027 .jmp_reloc => {
50395028 self.mir_instructions.items(.data)[reloc].inst = next_inst;
50405029 },
50415030 else => unreachable,
......@@ -5078,7 +5067,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
50785067 try block_data.relocs.ensureUnusedCapacity(self.gpa, 1);
50795068 // Leave the jump offset undefined
50805069 const jmp_reloc = try self.addInst(.{
5081 .tag = .jmp,
5070 .tag = .jmp_reloc,
50825071 .ops = .inst,
50835072 .data = .{ .inst = undefined },
50845073 });
......@@ -5247,7 +5236,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
52475236}
52485237
52495238fn 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.*));
52515240 switch (mcv) {
52525241 .dead => unreachable,
52535242 .unreach, .none => return,
......@@ -5325,36 +5314,25 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
53255314 .{ty.fmtDebug()},
53265315 ),
53275316 };
5328 _ = tag;
5329 _ = reg;
5330 // _ = try self.addInst(.{
5331 // .tag = tag,
5332 // .ops = Mir.Inst.Ops.encode(.{
5333 // .reg1 = switch (ty.tag()) {
5334 // .f32 => .esp,
5335 // .f64 => .rsp,
5336 // else => unreachable,
5337 // },
5338 // .reg2 = reg.to128(),
5339 // .flags = 0b01,
5340 // }),
5341 // .data = .{ .disp = -stack_offset },
5342 // });
5343 return;
5317 // TODO verify this
5318 const ptr_size: Memory.PtrSize = switch (ty.tag()) {
5319 .f32 => .dword,
5320 .f64 => .qword,
5321 else => unreachable,
5322 };
5323 return self.asmMemoryRegister(tag, Memory.sib(ptr_size, .{
5324 .base = .rsp,
5325 .disp = -stack_offset,
5326 }), reg.to128());
53445327 }
53455328
53465329 return self.fail("TODO genSetStackArg for register with no intrinsics", .{});
53475330 },
53485331 else => {
5349 // _ = try self.addInst(.{
5350 // .tag = .mov,
5351 // .ops = Mir.Inst.Ops.encode(.{
5352 // .reg1 = .rsp,
5353 // .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
5354 // .flags = 0b10,
5355 // }),
5356 // .data = .{ .disp = -stack_offset },
5357 // });
5332 try self.asmMemoryRegister(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5333 .base = .rsp,
5334 .disp = -stack_offset,
5335 }), registerAlias(reg, abi_size));
53585336 },
53595337 }
53605338 },
......@@ -5507,25 +5485,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
55075485 switch (ty.zigTypeTag()) {
55085486 .Float => {
55095487 if (intrinsicsAllowed(self.target.*, ty)) {
5510 // const tag: Mir.Inst.Tag = switch (ty.tag()) {
5511 // .f32 => Mir.Inst.Tag.mov_f32,
5512 // .f64 => Mir.Inst.Tag.mov_f64,
5513 // else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}),
5514 // };
5515 // _ = try self.addInst(.{
5516 // .tag = tag,
5517 // .ops = Mir.Inst.Ops.encode(.{
5518 // .reg1 = switch (ty.tag()) {
5519 // .f32 => base_reg.to32(),
5520 // .f64 => base_reg.to64(),
5521 // else => unreachable,
5522 // },
5523 // .reg2 = reg.to128(),
5524 // .flags = 0b01,
5525 // }),
5526 // .data = .{ .disp = -stack_offset },
5527 // });
5528 return;
5488 const tag: Mir.Inst.Tag = switch (ty.tag()) {
5489 .f32 => .movss,
5490 .f64 => .movsd,
5491 else => return self.fail(
5492 "TODO genSetStack for register for type {}",
5493 .{ty.fmtDebug()},
5494 ),
5495 };
5496 const ptr_size: Memory.PtrSize = switch (ty.tag()) {
5497 .f32 => .dword,
5498 .f64 => .qword,
5499 else => unreachable,
5500 };
5501 return self.asmMemoryRegister(tag, Memory.sib(ptr_size, .{
5502 .base = base_reg.to64(),
5503 .disp = -stack_offset,
5504 }), reg.to128());
55295505 }
55305506
55315507 return self.fail("TODO genSetStack for register for type float with no intrinsics", .{});
......@@ -5590,16 +5566,10 @@ fn genInlineMemcpyRegisterRegister(
55905566 var remainder = abi_size;
55915567 while (remainder > 0) {
55925568 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));
5593
5594 // _ = try self.addInst(.{
5595 // .tag = .mov,
5596 // .ops = Mir.Inst.Ops.encode(.{
5597 // .reg1 = dst_reg,
5598 // .reg2 = registerAlias(tmp_reg, nearest_power_of_two),
5599 // .flags = 0b10,
5600 // }),
5601 // .data = .{ .disp = -next_offset },
5602 // });
5569 try self.asmMemoryRegister(.mov, Memory.sib(Memory.PtrSize.fromSize(nearest_power_of_two), .{
5570 .base = dst_reg,
5571 .disp = -next_offset,
5572 }), registerAlias(tmp_reg, nearest_power_of_two));
56035573
56045574 if (nearest_power_of_two > 1) {
56055575 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{
......@@ -5611,15 +5581,10 @@ fn genInlineMemcpyRegisterRegister(
56115581 next_offset -= nearest_power_of_two;
56125582 }
56135583 } else {
5614 // _ = try self.addInst(.{
5615 // .tag = .mov,
5616 // .ops = Mir.Inst.Ops.encode(.{
5617 // .reg1 = dst_reg,
5618 // .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
5619 // .flags = 0b10,
5620 // }),
5621 // .data = .{ .disp = -offset },
5622 // });
5584 try self.asmMemoryRegister(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5585 .base = dst_reg,
5586 .disp = -offset,
5587 }), registerAlias(src_reg, abi_size));
56235588 }
56245589}
56255590
......@@ -5660,15 +5625,10 @@ fn genInlineMemcpy(
56605625 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);
56615626 },
56625627 .ptr_stack_offset, .stack_offset => |off| {
5663 _ = off;
5664 // _ = try self.addInst(.{
5665 // .tag = .lea,
5666 // .ops = Mir.Inst.Ops.encode(.{
5667 // .reg1 = dst_addr_reg.to64(),
5668 // .reg2 = opts.dest_stack_base orelse .rbp,
5669 // }),
5670 // .data = .{ .disp = -off },
5671 // });
5628 try self.asmRegisterMemory(.lea, dst_addr_reg.to64(), Memory.sib(.qword, .{
5629 .base = opts.dest_stack_base orelse .rbp,
5630 .disp = -off,
5631 }));
56725632 },
56735633 .register => |reg| {
56745634 try self.asmRegisterRegister(
......@@ -5754,7 +5714,7 @@ fn genInlineMemcpy(
57545714 try self.asmRegisterImmediate(.sub, count_reg, Immediate.u(1));
57555715
57565716 _ = try self.addInst(.{
5757 .tag = .jmp,
5717 .tag = .jmp_reloc,
57585718 .ops = .inst,
57595719 .data = .{ .inst = loop_start },
57605720 });
......@@ -5857,7 +5817,7 @@ fn genInlineMemset(
58575817 try self.asmRegisterImmediate(.sub, index_reg, Immediate.u(1));
58585818
58595819 _ = try self.addInst(.{
5860 .tag = .jmp,
5820 .tag = .jmp_reloc,
58615821 .ops = .inst,
58625822 .data = .{ .inst = loop_start },
58635823 });
......@@ -6045,19 +6005,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
60456005 // .data = .{ .disp = @intCast(i32, x) },
60466006 // });
60476007 } 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.
60506008 if (reg.to64() == .rax) {
6051 // movabs rax, ds:moffs64
6052 // const payload = try self.addExtra(Mir.Imm64.encode(x));
6053 // _ = try self.addInst(.{
6054 // .tag = .movabs,
6055 // .ops = Mir.Inst.Ops.encode(.{
6056 // .reg1 = .rax,
6057 // .flags = 0b01, // imm64 will become moffs64
6058 // }),
6059 // .data = .{ .payload = payload },
6060 // });
6009 // If this is RAX, we can use a direct load.
6010 // Otherwise, we need to load the address, then indirectly load the value.
6011 var moffs: Mir.MemoryMoffs = .{
6012 .seg = @enumToInt(Register.ds),
6013 .msb = undefined,
6014 .lsb = undefined,
6015 };
6016 moffs.encodeOffset(x);
6017 _ = try self.addInst(.{
6018 .tag = .mov_moffs,
6019 .ops = .rax_moffs,
6020 .data = .{ .payload = try self.addExtra(moffs) },
6021 });
60616022 } else {
60626023 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
60636024 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 {
7373 .adc,
7474 .add,
7575 .@"and",
76 .call,
7677 .cbw,
7778 .cwde,
7879 .cdqe,
......@@ -86,6 +87,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
8687 .idiv,
8788 .imul,
8889 .int3,
90 .jmp,
91 .lea,
8992 .mov,
9093 .movzx,
9194 .mul,
......@@ -115,9 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
115118 .ucomisd,
116119 => try emit.mirEncodeGeneric(tag, inst),
117120
118 .call,
119 .jmp,
120 => try emit.mirCallJmp(inst),
121 .jmp_reloc => try emit.mirJmpReloc(inst),
122
123 .mov_moffs => try emit.mirMovMoffs(inst),
121124
122125 .movsx => try emit.mirMovsx(inst),
123126 .cmovcc => try emit.mirCmovcc(inst),
......@@ -130,8 +133,6 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
130133
131134 .push_regs => try emit.mirPushPopRegisterList(.push, inst),
132135 .pop_regs => try emit.mirPushPopRegisterList(.pop, inst),
133
134 else => return emit.fail("Implement MIR->Emit lowering for x86_64 for pseudo-inst: {}", .{tag}),
135136 }
136137 }
137138
......@@ -212,6 +213,34 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
212213 .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
213214 };
214215 },
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 },
215244 else => unreachable, // TODO
216245 }
217246
......@@ -223,6 +252,29 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
223252 });
224253}
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
226278fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
227279 const ops = emit.mir.instructions.items(.ops)[inst];
228280 const data = emit.mir.instructions.items(.data)[inst];
......@@ -302,19 +354,13 @@ fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
302354 }
303355}
304356
305fn mirCallJmp(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 };
357fn mirJmpReloc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
312358 const ops = emit.mir.instructions.items(.ops)[inst];
313359 switch (ops) {
314360 .inst => {
315361 const target = emit.mir.instructions.items(.data)[inst].inst;
316362 const source = emit.code.items.len;
317 try emit.encode(mnemonic, .{
363 try emit.encode(.jmp, .{
318364 .op1 = .{ .imm = Immediate.s(0) },
319365 });
320366 try emit.relocs.append(emit.bin_file.allocator, .{
......@@ -324,19 +370,7 @@ fn mirCallJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
324370 .length = 5,
325371 });
326372 },
327 .r => {
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
373 else => unreachable,
340374 }
341375}
342376
src/arch/x86_64/Mir.zig+136-11
......@@ -17,6 +17,7 @@ const encoder = @import("encoder.zig");
1717const Air = @import("../../Air.zig");
1818const CodeGen = @import("CodeGen.zig");
1919const IntegerBitSet = std.bit_set.IntegerBitSet;
20const Memory = bits.Memory;
2021const Register = bits.Register;
2122
2223instructions: std.MultiArrayList(Inst).Slice,
......@@ -135,6 +136,12 @@ pub const Inst = struct {
135136 /// Conditional move
136137 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
138145 /// End of prologue
139146 dbg_prologue_end,
140147 /// Start of epilogue
......@@ -186,24 +193,48 @@ pub const Inst = struct {
186193 /// Relative displacement operand.
187194 /// Uses `rel` payload.
188195 rel,
189 /// Register, memory operands.
196 /// Register, memory (SIB) operands.
197 /// Uses `rx` payload.
198 rm_sib,
199 /// Register, memory (RIP) operands.
190200 /// Uses `rx` payload.
191 rm,
201 rm_rip,
192202 /// Register, memory, immediate (unsigned) operands
193203 /// Uses `rx` payload.
194204 rmi_u,
195205 /// Register, memory, immediate (sign-extended) operands
196206 /// Uses `rx` payload.
197207 rmi_s,
198 /// Memory, immediate (unsigned) operands.
199 /// Uses `payload` payload.
200 mi_u,
201 /// Memory, immediate (sign-extend) operands.
202 /// Uses `payload` payload.
203 mi_s,
204 /// Memory, register operands.
205 /// Uses `payload` payload.
206 mr,
208 /// Single memory (SIB) operand.
209 /// Uses `payload` with extra data of type `MemorySib`.
210 m_sib,
211 /// Single memory (RIP) operand.
212 /// Uses `payload` with extra data of type `MemoryRip`.
213 m_rip,
214 /// Memory (SIB), immediate (unsigned) operands.
215 /// Uses `xi_u` payload with extra data of type `MemorySib`.
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,
207238 /// Lea into register with linker relocation.
208239 /// Uses `payload` payload with data of type `LeaRegisterReloc`.
209240 lea_r_reloc,
......@@ -274,6 +305,16 @@ pub const Inst = struct {
274305 r1: Register,
275306 payload: u32,
276307 },
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 },
277318 /// Relocation for the linker where:
278319 /// * `atom_index` is the index of the source
279320 /// * `sym_index` is the index of the target
......@@ -378,6 +419,90 @@ pub const Imm64 = struct {
378419 }
379420};
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
381506pub const DbgLineColumn = struct {
382507 line: u32,
383508 column: u32,
src/arch/x86_64/bits.zig+11
......@@ -417,6 +417,17 @@ pub const Memory = union(enum) {
417417 qword,
418418 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
420431 pub fn fromBitSize(bit_size: u64) PtrSize {
421432 return switch (bit_size) {
422433 8 => .byte,