authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-09 18:38:54+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-11 20:05:49+01:00
log9658ab676643ef5c2457ac4908c180e05dc7f729
tree518fbcc79bcb6886586e2dadf7cac3aa0b1a56d0
parent1bde522c2c6cae52c581458774ad1dfa479d8426

x86_64: handle all instructions without introducing Memory operand


2 files changed, 257 insertions(+), 319 deletions(-)

src/arch/x86_64/CodeGen.zig+149-316
......@@ -400,7 +400,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
400400 return result;
401401}
402402
403fn asmSetCCRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
403fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
404404 _ = try self.addInst(.{
405405 .tag = .setcc,
406406 .ops = .r_c,
......@@ -411,7 +411,7 @@ fn asmSetCCRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
411411 });
412412}
413413
414fn asmCmovCCRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
414fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
415415 _ = try self.addInst(.{
416416 .tag = .cmovcc,
417417 .ops = .rr_c,
......@@ -1369,7 +1369,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
13691369 .unsigned => .b,
13701370 .signed => .l,
13711371 };
1372 try self.asmCmovCCRegisterRegister(dst_mcv.register, lhs_reg, cc);
1372 try self.asmCmovccRegisterRegister(dst_mcv.register, lhs_reg, cc);
13731373
13741374 break :result dst_mcv;
13751375 };
......@@ -1569,7 +1569,7 @@ fn genSetStackTruncatedOverflowCompare(
15691569 .signed => .o,
15701570 .unsigned => .c,
15711571 };
1572 try self.asmSetCCRegister(overflow_reg.to8(), cc);
1572 try self.asmSetccRegister(overflow_reg.to8(), cc);
15731573
15741574 const scratch_reg = temp_regs[1];
15751575 try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg });
......@@ -1582,7 +1582,7 @@ fn genSetStackTruncatedOverflowCompare(
15821582 );
15831583
15841584 const eq_reg = temp_regs[2];
1585 try self.asmSetCCRegister(eq_reg.to8(), .ne);
1585 try self.asmSetccRegister(eq_reg.to8(), .ne);
15861586 try self.genBinOpMir(
15871587 .@"or",
15881588 Type.u8,
......@@ -1725,26 +1725,10 @@ fn genIntMulDivOpMir(
17251725 try self.genSetReg(ty, .rax, lhs);
17261726 }
17271727
1728 _ = signedness;
1729 // switch (signedness) {
1730 // .signed => {
1731 // _ = try self.addInst(.{
1732 // .tag = .cwd,
1733 // .ops = Mir.Inst.Ops.encode(.{ .flags = 0b11 }),
1734 // .data = undefined,
1735 // });
1736 // },
1737 // .unsigned => {
1738 // _ = try self.addInst(.{
1739 // .tag = .xor,
1740 // .ops = Mir.Inst.Ops.encode(.{
1741 // .reg1 = .rdx,
1742 // .reg2 = .rdx,
1743 // }),
1744 // .data = undefined,
1745 // });
1746 // },
1747 // }
1728 switch (signedness) {
1729 .signed => try self.asmNone(.cqo),
1730 .unsigned => try self.asmRegisterRegister(.xor, .rdx, .rdx),
1731 }
17481732
17491733 const factor = switch (rhs) {
17501734 .register => rhs,
......@@ -1754,35 +1738,28 @@ fn genIntMulDivOpMir(
17541738 break :blk MCValue{ .register = reg };
17551739 },
17561740 };
1757 _ = factor;
1758 _ = tag;
1759
1760 // switch (factor) {
1761 // .register => |reg| {
1762 // _ = try self.addInst(.{
1763 // .tag = tag,
1764 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
1765 // .data = undefined,
1766 // });
1767 // },
1768 // .stack_offset => |off| {
1769 // _ = try self.addInst(.{
1770 // .tag = tag,
1771 // .ops = Mir.Inst.Ops.encode(.{
1772 // .reg2 = .rbp,
1773 // .flags = switch (abi_size) {
1774 // 1 => 0b00,
1775 // 2 => 0b01,
1776 // 4 => 0b10,
1777 // 8 => 0b11,
1778 // else => unreachable,
1779 // },
1780 // }),
1781 // .data = .{ .disp = -off },
1782 // });
1783 // },
1784 // else => unreachable,
1785 // }
1741
1742 switch (factor) {
1743 .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 },
1761 else => unreachable,
1762 }
17861763}
17871764
17881765/// Always returns a register.
......@@ -1808,31 +1785,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
18081785 .unsigned => .div,
18091786 }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });
18101787
1811 // _ = try self.addInst(.{
1812 // .tag = .xor,
1813 // .ops = Mir.Inst.Ops.encode(.{
1814 // .reg1 = divisor.to64(),
1815 // .reg2 = dividend.to64(),
1816 // }),
1817 // .data = undefined,
1818 // });
1819 // _ = try self.addInst(.{
1820 // .tag = .sar,
1821 // .ops = Mir.Inst.Ops.encode(.{
1822 // .reg1 = divisor.to64(),
1823 // .flags = 0b10,
1824 // }),
1825 // .data = .{ .imm = 63 },
1826 // });
1827 // _ = try self.addInst(.{
1828 // .tag = .@"test",
1829 // .ops = Mir.Inst.Ops.encode(.{
1830 // .reg1 = .rdx,
1831 // .reg2 = .rdx,
1832 // }),
1833 // .data = undefined,
1834 // });
1835 try self.asmCmovCCRegisterRegister(divisor.to64(), .rdx, .e);
1788 try self.asmRegisterRegister(.xor, divisor.to64(), dividend.to64());
1789 try self.asmRegisterImmediate(.sar, divisor.to64(), Immediate.u(63));
1790 try self.asmRegisterRegister(.@"test", .rdx, .rdx);
1791 try self.asmCmovccRegisterRegister(divisor.to64(), .rdx, .e);
18361792 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
18371793 return MCValue{ .register = divisor };
18381794}
......@@ -2877,7 +2833,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28772833 const overflow_bit_ty = value_ty.structFieldType(1);
28782834 const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);
28792835 const tmp_reg = try self.register_manager.allocReg(null, gp);
2880 try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
2836 try self.asmSetccRegister(tmp_reg.to8(), ro.eflags);
28812837 try self.genInlineMemcpyRegisterRegister(
28822838 overflow_bit_ty,
28832839 reg,
......@@ -3151,14 +3107,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
31513107 };
31523108 const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
31533109 if (signedness == .signed and field_size < 8) {
3154 // _ = try self.addInst(.{
3155 // .tag = .mov_sign_extend,
3156 // .ops = Mir.Inst.Ops.encode(.{
3157 // .reg1 = dst_mcv.register,
3158 // .reg2 = registerAlias(dst_mcv.register, field_size),
3159 // }),
3160 // .data = undefined,
3161 // });
3110 try self.asmRegisterRegister(
3111 .movsx,
3112 dst_mcv.register,
3113 registerAlias(dst_mcv.register, field_size),
3114 );
31623115 }
31633116
31643117 break :result dst_mcv;
......@@ -3175,7 +3128,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
31753128 defer self.register_manager.unlockReg(reg_lock);
31763129
31773130 const dst_reg = try self.register_manager.allocReg(inst, gp);
3178 try self.asmSetCCRegister(dst_reg.to8(), ro.eflags);
3131 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
31793132 break :result MCValue{ .register = dst_reg.to8() };
31803133 },
31813134 else => unreachable,
......@@ -3211,25 +3164,7 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
32113164 switch (shift) {
32123165 .immediate => |imm| switch (imm) {
32133166 0 => return,
3214 1 => {
3215 // _ = try self.addInst(.{
3216 // .tag = tag,
3217 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }),
3218 // .data = undefined,
3219 // });
3220 return;
3221 },
3222 else => {
3223 // _ = try self.addInst(.{
3224 // .tag = tag,
3225 // .ops = Mir.Inst.Ops.encode(.{
3226 // .reg1 = registerAlias(reg, abi_size),
3227 // .flags = 0b10,
3228 // }),
3229 // .data = .{ .imm = @intCast(u8, imm) },
3230 // });
3231 return;
3232 },
3167 else => return self.asmRegisterImmediate(tag, registerAlias(reg, abi_size), Immediate.u(imm)),
32333168 },
32343169 .register => |shift_reg| {
32353170 if (shift_reg == .rcx) break :blk;
......@@ -3240,16 +3175,8 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
32403175 try self.register_manager.getReg(.rcx, null);
32413176 try self.genSetReg(Type.u8, .rcx, shift);
32423177 }
3243 _ = abi_size;
32443178
3245 // _ = try self.addInst(.{
3246 // .tag = tag,
3247 // .ops = Mir.Inst.Ops.encode(.{
3248 // .reg1 = registerAlias(reg, abi_size),
3249 // .flags = 0b01,
3250 // }),
3251 // .data = undefined,
3252 // });
3179 try self.asmRegisterRegister(tag, registerAlias(reg, abi_size), .cl);
32533180}
32543181
32553182/// Result is always a register.
......@@ -3620,43 +3547,38 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36203547 .register => |src_reg| switch (dst_ty.zigTypeTag()) {
36213548 .Float => {
36223549 if (intrinsicsAllowed(self.target.*, dst_ty)) {
3623 // const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
3624 // .f32 => switch (mir_tag) {
3625 // .add => Mir.Inst.Tag.add_f32,
3626 // .cmp => Mir.Inst.Tag.cmp_f32,
3627 // else => return self.fail("TODO genBinOpMir for f32 register-register with MIR tag {}", .{mir_tag}),
3628 // },
3629 // .f64 => switch (mir_tag) {
3630 // .add => Mir.Inst.Tag.add_f64,
3631 // .cmp => Mir.Inst.Tag.cmp_f64,
3632 // else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}),
3633 // },
3634 // else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}),
3635 // };
3636 // _ = try self.addInst(.{
3637 // .tag = actual_tag,
3638 // .ops = Mir.Inst.Ops.encode(.{
3639 // .reg1 = dst_reg.to128(),
3640 // .reg2 = src_reg.to128(),
3641 // }),
3642 // .data = undefined,
3643 // });
3644 return;
3550 const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
3551 .f32 => switch (mir_tag) {
3552 .add => .addss,
3553 .cmp => .cmpss,
3554 else => return self.fail(
3555 "TODO genBinOpMir for f32 register-register with MIR tag {}",
3556 .{mir_tag},
3557 ),
3558 },
3559 .f64 => switch (mir_tag) {
3560 .add => .addsd,
3561 .cmp => .cmpsd,
3562 else => return self.fail(
3563 "TODO genBinOpMir for f64 register-register with MIR tag {}",
3564 .{mir_tag},
3565 ),
3566 },
3567 else => return self.fail(
3568 "TODO genBinOpMir for float register-register and type {}",
3569 .{dst_ty.fmtDebug()},
3570 ),
3571 };
3572 try self.asmRegisterRegister(actual_tag, dst_reg.to128(), src_reg.to128());
36453573 }
36463574
36473575 return self.fail("TODO genBinOpMir for float register-register and no intrinsics", .{});
36483576 },
3649 else => {
3650 _ = src_reg;
3651 // _ = try self.addInst(.{
3652 // .tag = mir_tag,
3653 // .ops = Mir.Inst.Ops.encode(.{
3654 // .reg1 = registerAlias(dst_reg, abi_size),
3655 // .reg2 = registerAlias(src_reg, abi_size),
3656 // }),
3657 // .data = undefined,
3658 // });
3659 },
3577 else => try self.asmRegisterRegister(
3578 mir_tag,
3579 registerAlias(dst_reg, abi_size),
3580 registerAlias(src_reg, abi_size),
3581 ),
36603582 },
36613583 .immediate => |imm| {
36623584 _ = imm;
......@@ -3777,7 +3699,6 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
37773699/// Does not support byte-size operands.
37783700fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
37793701 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
3780 _ = abi_size;
37813702 switch (dst_mcv) {
37823703 .none => unreachable,
37833704 .undef => unreachable,
......@@ -3792,18 +3713,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
37923713 .dead, .unreach => unreachable,
37933714 .ptr_stack_offset => unreachable,
37943715 .register_overflow => unreachable,
3795 .register => |src_reg| {
3796 _ = src_reg;
3797 // register, register
3798 // _ = try self.addInst(.{
3799 // .tag = .imul_complex,
3800 // .ops = Mir.Inst.Ops.encode(.{
3801 // .reg1 = registerAlias(dst_reg, abi_size),
3802 // .reg2 = registerAlias(src_reg, abi_size),
3803 // }),
3804 // .data = undefined,
3805 // });
3806 },
3716 .register => |src_reg| try self.asmRegisterRegister(
3717 .imul,
3718 registerAlias(dst_reg, abi_size),
3719 registerAlias(src_reg, abi_size),
3720 ),
38073721 .immediate => |imm| {
38083722 // TODO take into account the type's ABI size when selecting the register alias
38093723 // register, immediate
......@@ -3992,20 +3906,12 @@ fn genVarDbgInfo(
39923906}
39933907
39943908fn airTrap(self: *Self) !void {
3995 // _ = try self.addInst(.{
3996 // .tag = .ud,
3997 // .ops = Mir.Inst.Ops.encode(.{}),
3998 // .data = undefined,
3999 // });
3909 try self.asmNone(.ud2);
40003910 return self.finishAirBookkeeping();
40013911}
40023912
40033913fn airBreakpoint(self: *Self) !void {
4004 // _ = try self.addInst(.{
4005 // .tag = .interrupt,
4006 // .ops = Mir.Inst.Ops.encode(.{}),
4007 // .data = undefined,
4008 // });
3914 try self.asmNone(.int3);
40093915 return self.finishAirBookkeeping();
40103916}
40113917
......@@ -4117,13 +4023,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
41174023 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
41184024 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
41194025 const atom = elf_file.getAtom(atom_index);
4120 const got_addr = @intCast(i32, atom.getOffsetTableAddress(elf_file));
4121 _ = got_addr;
4122 // _ = try self.addInst(.{
4123 // .tag = .call,
4124 // .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4125 // .data = .{ .disp = got_addr },
4126 // });
4026 const got_addr = atom.getOffsetTableAddress(elf_file);
4027 try self.asmImmediate(.call, Immediate.s(@intCast(i32, got_addr)));
41274028 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
41284029 const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
41294030 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
......@@ -4133,14 +4034,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
41334034 .sym_index = sym_index,
41344035 },
41354036 });
4136 // _ = try self.addInst(.{
4137 // .tag = .call,
4138 // .ops = Mir.Inst.Ops.encode(.{
4139 // .reg1 = .rax,
4140 // .flags = 0b01,
4141 // }),
4142 // .data = undefined,
4143 // });
4037 try self.asmRegister(.call, .rax);
41444038 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
41454039 const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
41464040 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
......@@ -4150,14 +4044,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
41504044 .sym_index = sym_index,
41514045 },
41524046 });
4153 // _ = try self.addInst(.{
4154 // .tag = .call,
4155 // .ops = Mir.Inst.Ops.encode(.{
4156 // .reg1 = .rax,
4157 // .flags = 0b01,
4158 // }),
4159 // .data = undefined,
4160 // });
4047 try self.asmRegister(.call, .rax);
41614048 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
41624049 const decl_block_index = try p9.seeDecl(func.owner_decl);
41634050 const decl_block = p9.getDeclBlock(decl_block_index);
......@@ -4166,12 +4053,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
41664053 const got_addr = p9.bases.data;
41674054 const got_index = decl_block.got_index.?;
41684055 const fn_got_addr = got_addr + got_index * ptr_bytes;
4169 _ = fn_got_addr;
4170 // _ = try self.addInst(.{
4171 // .tag = .call,
4172 // .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4173 // .data = .{ .disp = @intCast(i32, fn_got_addr) },
4174 // });
4056 try self.asmImmediate(.call, Immediate.s(@intCast(i32, fn_got_addr)));
41754057 } else unreachable;
41764058 } else if (func_value.castTag(.extern_fn)) |func_payload| {
41774059 const extern_fn = func_payload.data;
......@@ -4191,14 +4073,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
41914073 .sym_index = sym_index,
41924074 },
41934075 });
4194 // _ = try self.addInst(.{
4195 // .tag = .call,
4196 // .ops = Mir.Inst.Ops.encode(.{
4197 // .reg1 = .rax,
4198 // .flags = 0b01,
4199 // }),
4200 // .data = undefined,
4201 // });
4076 try self.asmRegister(.call, .rax);
42024077 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
42034078 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
42044079 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
......@@ -4223,23 +4098,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42234098 assert(ty.zigTypeTag() == .Pointer);
42244099 const mcv = try self.resolveInst(callee);
42254100 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4226 // _ = try self.addInst(.{
4227 // .tag = .call,
4228 // .ops = Mir.Inst.Ops.encode(.{
4229 // .reg1 = .rax,
4230 // .flags = 0b01,
4231 // }),
4232 // .data = undefined,
4233 // });
4101 try self.asmRegister(.call, .rax);
42344102 }
42354103
42364104 if (info.stack_byte_count > 0) {
42374105 // Readjust the stack
4238 // _ = try self.addInst(.{
4239 // .tag = .add,
4240 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
4241 // .data = .{ .imm = info.stack_byte_count },
4242 // });
4106 try self.asmRegisterImmediate(.add, .rsp, Immediate.u(info.stack_byte_count));
42434107 }
42444108
42454109 const result: MCValue = result: {
......@@ -4296,12 +4160,12 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
42964160 // TODO when implementing defer, this will need to jump to the appropriate defer expression.
42974161 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
42984162 // which is available if the jump is 127 bytes or less forward.
4299 // const jmp_reloc = try self.addInst(.{
4300 // .tag = .jmp,
4301 // .ops = Mir.Inst.Ops.encode(.{}),
4302 // .data = .{ .inst = undefined },
4303 // });
4304 // try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
4163 const jmp_reloc = try self.addInst(.{
4164 .tag = .jmp,
4165 .ops = .inst,
4166 .data = .{ .inst = undefined },
4167 });
4168 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
43054169 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
43064170}
43074171
......@@ -4332,12 +4196,12 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
43324196 // TODO when implementing defer, this will need to jump to the appropriate defer expression.
43334197 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
43344198 // which is available if the jump is 127 bytes or less forward.
4335 // const jmp_reloc = try self.addInst(.{
4336 // .tag = .jmp,
4337 // .ops = Mir.Inst.Ops.encode(.{}),
4338 // .data = .{ .inst = undefined },
4339 // });
4340 // try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
4199 const jmp_reloc = try self.addInst(.{
4200 .tag = .jmp,
4201 .ops = .inst,
4202 .data = .{ .inst = undefined },
4203 });
4204 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
43414205 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
43424206}
43434207
......@@ -4872,13 +4736,12 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
48724736 const loop = self.air.extraData(Air.Block, ty_pl.payload);
48734737 const body = self.air.extra[loop.end..][0..loop.data.body_len];
48744738 const jmp_target = @intCast(u32, self.mir_instructions.len);
4875 _ = jmp_target;
48764739 try self.genBody(body);
4877 // _ = try self.addInst(.{
4878 // .tag = .jmp,
4879 // .ops = Mir.Inst.Ops.encode(.{}),
4880 // .data = .{ .inst = jmp_target },
4881 // });
4740 _ = try self.addInst(.{
4741 .tag = .jmp,
4742 .ops = .inst,
4743 .data = .{ .inst = jmp_target },
4744 });
48824745 return self.finishAirBookkeeping();
48834746}
48844747
......@@ -4923,25 +4786,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
49234786 .none => unreachable,
49244787 .undef => unreachable,
49254788 .dead, .unreach => unreachable,
4926 .immediate => |imm| {
4927 _ = imm;
4928 // _ = try self.addInst(.{
4929 // .tag = .xor,
4930 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size) }),
4931 // .data = .{ .imm = @intCast(u32, imm) },
4932 // });
4933 },
4934 .register => |reg| {
4935 _ = reg;
4936 // _ = try self.addInst(.{
4937 // .tag = .xor,
4938 // .ops = Mir.Inst.Ops.encode(.{
4939 // .reg1 = registerAlias(cond_reg, abi_size),
4940 // .reg2 = registerAlias(reg, abi_size),
4941 // }),
4942 // .data = undefined,
4943 // });
4944 },
4789 .immediate => |imm| try self.asmRegisterImmediate(
4790 .xor,
4791 registerAlias(cond_reg, abi_size),
4792 Immediate.u(imm),
4793 ),
4794 .register => |reg| try self.asmRegisterRegister(
4795 .xor,
4796 registerAlias(cond_reg, abi_size),
4797 registerAlias(reg, abi_size),
4798 ),
49454799 .stack_offset => {
49464800 if (abi_size <= 8) {
49474801 const reg = try self.copyToTmpRegister(ty, case);
......@@ -5223,12 +5077,12 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
52235077 // Emit a jump with a relocation. It will be patched up after the block ends.
52245078 try block_data.relocs.ensureUnusedCapacity(self.gpa, 1);
52255079 // Leave the jump offset undefined
5226 // const jmp_reloc = try self.addInst(.{
5227 // .tag = .jmp,
5228 // .ops = Mir.Inst.Ops.encode(.{}),
5229 // .data = .{ .inst = undefined },
5230 // });
5231 // block_data.relocs.appendAssumeCapacity(jmp_reloc);
5080 const jmp_reloc = try self.addInst(.{
5081 .tag = .jmp,
5082 .ops = .inst,
5083 .data = .{ .inst = undefined },
5084 });
5085 block_data.relocs.appendAssumeCapacity(jmp_reloc);
52325086}
52335087
52345088fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
......@@ -5463,11 +5317,15 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
54635317 switch (ty.zigTypeTag()) {
54645318 .Float => {
54655319 if (intrinsicsAllowed(self.target.*, ty)) {
5466 // const tag: Mir.Inst.Tag = switch (ty.tag()) {
5467 // .f32 => Mir.Inst.Tag.mov_f32,
5468 // .f64 => Mir.Inst.Tag.mov_f64,
5469 // else => return self.fail("TODO genSetStackArg for register for type {}", .{ty.fmtDebug()}),
5470 // };
5320 const tag: Mir.Inst.Tag = switch (ty.tag()) {
5321 .f32 => .movss,
5322 .f64 => .movsd,
5323 else => return self.fail(
5324 "TODO genSetStackArg for register for type {}",
5325 .{ty.fmtDebug()},
5326 ),
5327 };
5328 _ = tag;
54715329 _ = reg;
54725330 // _ = try self.addInst(.{
54735331 // .tag = tag,
......@@ -5550,7 +5408,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
55505408 const overflow_bit_ty = ty.structFieldType(1);
55515409 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
55525410 const tmp_reg = try self.register_manager.allocReg(null, gp);
5553 try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
5411 try self.asmSetccRegister(tmp_reg.to8(), ro.eflags);
55545412
55555413 return self.genSetStack(
55565414 overflow_bit_ty,
......@@ -6039,7 +5897,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
60395897 }
60405898 },
60415899 .eflags => |cc| {
6042 return self.asmSetCCRegister(reg.to8(), cc);
5900 return self.asmSetccRegister(reg.to8(), cc);
60435901 },
60445902 .immediate => |x| {
60455903 if (x == 0) {
......@@ -6069,63 +5927,38 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
60695927 .Int => switch (ty.intInfo(self.target.*).signedness) {
60705928 .signed => {
60715929 if (abi_size <= 4) {
6072 // _ = try self.addInst(.{
6073 // .tag = .mov_sign_extend,
6074 // .ops = Mir.Inst.Ops.encode(.{
6075 // .reg1 = reg.to64(),
6076 // .reg2 = registerAlias(src_reg, abi_size),
6077 // }),
6078 // .data = undefined,
6079 // });
6080 return;
5930 return self.asmRegisterRegister(
5931 .movsx,
5932 reg.to64(),
5933 registerAlias(src_reg, abi_size),
5934 );
60815935 }
60825936 },
60835937 .unsigned => {
60845938 if (abi_size <= 2) {
6085 // _ = try self.addInst(.{
6086 // .tag = .mov_zero_extend,
6087 // .ops = Mir.Inst.Ops.encode(.{
6088 // .reg1 = reg.to64(),
6089 // .reg2 = registerAlias(src_reg, abi_size),
6090 // }),
6091 // .data = undefined,
6092 // });
6093 return;
5939 return self.asmRegisterRegister(
5940 .movzx,
5941 reg.to64(),
5942 registerAlias(src_reg, abi_size),
5943 );
60945944 }
60955945 },
60965946 },
60975947 .Float => {
60985948 if (intrinsicsAllowed(self.target.*, ty)) {
6099 // const tag: Mir.Inst.Tag = switch (ty.tag()) {
6100 // .f32 => Mir.Inst.Tag.mov_f32,
6101 // .f64 => Mir.Inst.Tag.mov_f64,
6102 // else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}),
6103 // };
6104 // _ = try self.addInst(.{
6105 // .tag = tag,
6106 // .ops = Mir.Inst.Ops.encode(.{
6107 // .reg1 = reg.to128(),
6108 // .reg2 = src_reg.to128(),
6109 // .flags = 0b10,
6110 // }),
6111 // .data = undefined,
6112 // });
6113 return;
5949 const tag: Mir.Inst.Tag = switch (ty.tag()) {
5950 .f32 => .movss,
5951 .f64 => .movsd,
5952 else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}),
5953 };
5954 return self.asmRegisterRegister(tag, reg.to128(), src_reg.to128());
61145955 }
6115
61165956 return self.fail("TODO genSetReg from register for float with no intrinsics", .{});
61175957 },
61185958 else => {},
61195959 }
61205960
6121 // _ = try self.addInst(.{
6122 // .tag = .mov,
6123 // .ops = Mir.Inst.Ops.encode(.{
6124 // .reg1 = registerAlias(reg, abi_size),
6125 // .reg2 = registerAlias(src_reg, abi_size),
6126 // }),
6127 // .data = undefined,
6128 // });
5961 try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size));
61295962 },
61305963 .linker_load => {
61315964 switch (ty.zigTypeTag()) {
......@@ -6214,7 +6047,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
62146047 } else {
62156048 // If this is RAX, we can use a direct load.
62166049 // Otherwise, we need to load the address, then indirectly load the value.
6217 if (reg.id() == 0) {
6050 if (reg.to64() == .rax) {
62186051 // movabs rax, ds:moffs64
62196052 // const payload = try self.addExtra(Mir.Imm64.encode(x));
62206053 // _ = try self.addInst(.{
src/arch/x86_64/Emit.zig+108-3
......@@ -87,7 +87,6 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
8787 .imul,
8888 .int3,
8989 .mov,
90 .movsx,
9190 .movzx,
9291 .mul,
9392 .nop,
......@@ -116,7 +115,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
116115 .ucomisd,
117116 => try emit.mirEncodeGeneric(tag, inst),
118117
119 // Pseudo-instructions
118 .call,
119 .jmp,
120 => try emit.mirCallJmp(inst),
121
122 .movsx => try emit.mirMovsx(inst),
120123 .cmovcc => try emit.mirCmovcc(inst),
121124 .setcc => try emit.mirSetcc(inst),
122125 .jcc => try emit.mirJcc(inst),
......@@ -209,7 +212,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
209212 .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
210213 };
211214 },
212 else => unreachable,
215 else => unreachable, // TODO
213216 }
214217
215218 return emit.encode(mnemonic, .{
......@@ -220,6 +223,28 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
220223 });
221224}
222225
226fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
227 const ops = emit.mir.instructions.items(.ops)[inst];
228 const data = emit.mir.instructions.items(.data)[inst];
229
230 var op1: Instruction.Operand = .none;
231 var op2: Instruction.Operand = .none;
232 switch (ops) {
233 .rr => {
234 op1 = .{ .reg = data.rr.r1 };
235 op2 = .{ .reg = data.rr.r2 };
236 },
237 else => unreachable, // TODO
238 }
239
240 const mnemonic: Instruction.Mnemonic = if (op1.bitSize() == 64 and op2.bitSize() == 32) .movsxd else .movsx;
241
242 return emit.encode(mnemonic, .{
243 .op1 = op1,
244 .op2 = op2,
245 });
246}
247
223248fn mnemonicFromConditionCode(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
224249 inline for (@typeInfo(bits.Condition).Enum.fields) |field| {
225250 if (mem.eql(u8, field.name, @tagName(cc)))
......@@ -277,6 +302,86 @@ fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
277302 }
278303}
279304
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 };
312 const ops = emit.mir.instructions.items(.ops)[inst];
313 switch (ops) {
314 .inst => {
315 const target = emit.mir.instructions.items(.data)[inst].inst;
316 const source = emit.code.items.len;
317 try emit.encode(mnemonic, .{
318 .op1 = .{ .imm = Immediate.s(0) },
319 });
320 try emit.relocs.append(emit.bin_file.allocator, .{
321 .source = source,
322 .target = target,
323 .offset = emit.code.items.len - 4,
324 .length = 5,
325 });
326 },
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
340 }
341}
342
343// fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
344// const tag = emit.mir.instructions.items(.tag)[inst];
345// assert(tag == .call_extern);
346// const relocation = emit.mir.instructions.items(.data)[inst].relocation;
347
348// const offset = blk: {
349// // callq
350// try emit.encode(.call, .{
351// .op1 = .{ .imm = Immediate.s(0) },
352// });
353// break :blk @intCast(u32, emit.code.items.len) - 4;
354// };
355
356// if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
357// // Add relocation to the decl.
358// const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
359// const target = macho_file.getGlobalByIndex(relocation.sym_index);
360// try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
361// .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
362// .target = target,
363// .offset = offset,
364// .addend = 0,
365// .pcrel = true,
366// .length = 2,
367// });
368// } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
369// // Add relocation to the decl.
370// const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
371// const target = coff_file.getGlobalByIndex(relocation.sym_index);
372// try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
373// .type = .direct,
374// .target = target,
375// .offset = offset,
376// .addend = 0,
377// .pcrel = true,
378// .length = 2,
379// });
380// } else {
381// return emit.fail("TODO implement call_extern for linking backends different than MachO and COFF", .{});
382// }
383// }
384
280385fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
281386 const payload = emit.mir.instructions.items(.data)[inst].payload;
282387 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;