authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 17:53:53+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 17:53:53+02:00
log6a4e445f5aaadf8e87ec08499c84f1d5f279e8b3
tree3dc56856cd683ccbcb72c432676ce4ec4bb1ebff
parentaef3c149e64746dac01f4d48a2835abd4204e625

x64: pull shl and shr into one helper fn


1 files changed, 121 insertions(+), 132 deletions(-)

src/arch/x86_64/CodeGen.zig+121-132
...@@ -597,7 +597,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -597,7 +597,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
597 .mul_sat => try self.airMulSat(inst),597 .mul_sat => try self.airMulSat(inst),
598 .rem => try self.airMulDivBinOp(inst),598 .rem => try self.airMulDivBinOp(inst),
599 .mod => try self.airMulDivBinOp(inst),599 .mod => try self.airMulDivBinOp(inst),
600 .shl, .shl_exact => try self.airShl(inst),600 .shl, .shl_exact => try self.airShlShrBinOp(inst),
601 .shl_sat => try self.airShlSat(inst),601 .shl_sat => try self.airShlSat(inst),
602 .min => try self.airMin(inst),602 .min => try self.airMin(inst),
603 .max => try self.airMax(inst),603 .max => try self.airMax(inst),
...@@ -643,7 +643,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -643,7 +643,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
643 .bit_and => try self.airBinOp(inst),643 .bit_and => try self.airBinOp(inst),
644 .bit_or => try self.airBinOp(inst),644 .bit_or => try self.airBinOp(inst),
645 .xor => try self.airBinOp(inst),645 .xor => try self.airBinOp(inst),
646 .shr, .shr_exact => try self.airShr(inst),646 .shr, .shr_exact => try self.airShlShrBinOp(inst),
647647
648 .alloc => try self.airAlloc(inst),648 .alloc => try self.airAlloc(inst),
649 .ret_ptr => try self.airRetPtr(inst),649 .ret_ptr => try self.airRetPtr(inst),
...@@ -1652,64 +1652,22 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -1652,64 +1652,22 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
1652 return MCValue{ .register = divisor };1652 return MCValue{ .register = divisor };
1653}1653}
16541654
1655fn airShl(self: *Self, inst: Air.Inst.Index) !void {1655fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
1656 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1656 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1657
1657 if (self.liveness.isUnused(inst)) {1658 if (self.liveness.isUnused(inst)) {
1658 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1659 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1659 }1660 }
16601661
1661 const ty = self.air.typeOfIndex(inst);
1662
1663 const tag = self.air.instructions.items(.tag)[inst];1662 const tag = self.air.instructions.items(.tag)[inst];
1664 switch (tag) {1663 const lhs = try self.resolveInst(bin_op.lhs);
1665 .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty.fmtDebug() }),1664 const rhs = try self.resolveInst(bin_op.rhs);
1666 .shl => {},1665 const lhs_ty = self.air.typeOf(bin_op.lhs);
1667 else => unreachable,1666 const rhs_ty = self.air.typeOf(bin_op.rhs);
1668 }
1669
1670 if (ty.zigTypeTag() != .Int) {
1671 return self.fail("TODO implement .shl for type {}", .{ty.fmtDebug()});
1672 }
1673 if (ty.abiSize(self.target.*) > 8) {
1674 return self.fail("TODO implement .shl for integers larger than 8 bytes", .{});
1675 }
1676
1677 // TODO look into reusing the operands
1678 // TODO audit register allocation mechanics
1679 const shift = try self.resolveInst(bin_op.rhs);
1680 const shift_ty = self.air.typeOf(bin_op.rhs);
1681
1682 blk: {
1683 switch (shift) {
1684 .register => |reg| {
1685 if (reg.to64() == .rcx) break :blk;
1686 },
1687 else => {},
1688 }
1689 try self.register_manager.getReg(.rcx, null);
1690 try self.genSetReg(shift_ty, .rcx, shift);
1691 }
1692 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
1693 defer self.register_manager.unlockReg(rcx_lock);
1694
1695 const value = try self.resolveInst(bin_op.lhs);
1696 const value_lock: ?RegisterLock = switch (value) {
1697 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1698 else => null,
1699 };
1700 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
17011667
1702 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value);1668 const result = try self.genShiftBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1703 _ = try self.addInst(.{
1704 .tag = .sal,
1705 .ops = (Mir.Ops{
1706 .reg1 = dst_mcv.register,
1707 .flags = 0b01,
1708 }).encode(),
1709 .data = undefined,
1710 });
17111669
1712 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });1670 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1713}1671}
17141672
1715fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {1673fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1721,80 +1679,6 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1721,80 +1679,6 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
1721 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1679 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1722}1680}
17231681
1724fn airShr(self: *Self, inst: Air.Inst.Index) !void {
1725 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1726
1727 if (self.liveness.isUnused(inst)) {
1728 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1729 }
1730
1731 const ty = self.air.typeOfIndex(inst);
1732 const tag = self.air.instructions.items(.tag)[inst];
1733 switch (tag) {
1734 .shr_exact => return self.fail("TODO implement shr_exact for type {}", .{ty.fmtDebug()}),
1735 .shr => {},
1736 else => unreachable,
1737 }
1738
1739 if (ty.zigTypeTag() != .Int) {
1740 return self.fail("TODO implement shr for type {}", .{ty.fmtDebug()});
1741 }
1742 if (ty.abiSize(self.target.*) > 8) {
1743 return self.fail("TODO implement shr for integers larger than 8 bytes", .{});
1744 }
1745
1746 // TODO look into reusing the operands
1747 // TODO audit register allocation mechanics
1748 const shift = try self.resolveInst(bin_op.rhs);
1749 const shift_ty = self.air.typeOf(bin_op.rhs);
1750
1751 blk: {
1752 switch (shift) {
1753 .register => |reg| {
1754 if (reg.to64() == .rcx) break :blk;
1755 },
1756 else => {},
1757 }
1758 try self.register_manager.getReg(.rcx, null);
1759 try self.genSetReg(shift_ty, .rcx, shift);
1760 }
1761 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
1762 defer self.register_manager.unlockReg(rcx_lock);
1763
1764 const value = try self.resolveInst(bin_op.lhs);
1765 const value_lock: ?RegisterLock = switch (value) {
1766 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1767 else => null,
1768 };
1769 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
1770
1771 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value);
1772 switch (ty.intInfo(self.target.*).signedness) {
1773 .signed => {
1774 _ = try self.addInst(.{
1775 .tag = .sar,
1776 .ops = (Mir.Ops{
1777 .reg1 = dst_mcv.register,
1778 .flags = 0b01,
1779 }).encode(),
1780 .data = undefined,
1781 });
1782 },
1783 .unsigned => {
1784 _ = try self.addInst(.{
1785 .tag = .shr,
1786 .ops = (Mir.Ops{
1787 .reg1 = dst_mcv.register,
1788 .flags = 0b01,
1789 }).encode(),
1790 .data = undefined,
1791 });
1792 },
1793 }
1794
1795 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
1796}
1797
1798fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {1682fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1799 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1683 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1800 if (self.liveness.isUnused(inst)) {1684 if (self.liveness.isUnused(inst)) {
...@@ -1822,7 +1706,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1822,7 +1706,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1822 // TODO reuse the operand1706 // TODO reuse the operand
1823 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);1707 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);
1824 const shift = @intCast(u8, offset * @sizeOf(usize));1708 const shift = @intCast(u8, offset * @sizeOf(usize));
1825 try self.shiftRegister(result.register, @intCast(u8, shift));1709 try self.shiftRegisterRightUnsigned(result.register, @intCast(u8, shift));
1826 break :result result;1710 break :result result;
1827 },1711 },
1828 else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),1712 else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),
...@@ -1909,7 +1793,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1909,7 +1793,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1909 // TODO reuse operand1793 // TODO reuse operand
1910 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));1794 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));
1911 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);1795 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1912 try self.shiftRegister(result.register.to64(), shift);1796 try self.shiftRegisterRightUnsigned(result.register.to64(), shift);
1913 break :result MCValue{1797 break :result MCValue{
1914 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),1798 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
1915 };1799 };
...@@ -2421,7 +2305,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -2421,7 +2305,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
2421 else2305 else
2422 0;2306 0;
2423 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);2307 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
2424 try self.shiftRegister(result.register.to64(), shift);2308 try self.shiftRegisterRightUnsigned(result.register.to64(), shift);
2425 break :blk MCValue{2309 break :blk MCValue{
2426 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),2310 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
2427 };2311 };
...@@ -3020,7 +2904,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3020,7 +2904,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30202904
3021 // Shift by struct_field_offset.2905 // Shift by struct_field_offset.
3022 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));2906 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
3023 try self.shiftRegister(dst_mcv.register, shift);2907 try self.shiftRegisterRightUnsigned(dst_mcv.register, shift);
30242908
3025 // Mask with reg.size() - struct_field_size2909 // Mask with reg.size() - struct_field_size
3026 const max_reg_bit_width = Register.rax.size();2910 const max_reg_bit_width = Register.rax.size();
...@@ -3097,7 +2981,111 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3097,7 +2981,111 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
3097}2981}
30982982
3099/// Result is always a register.2983/// Result is always a register.
3100/// Clobbers .rax and .rdx therefore care needs to be taken to spill operands upfront.2984/// Clobbers .rcx therefore care is needed to spill .rcx upfront.
2985/// Asserts .rcx is free.
2986fn genShiftBinOp(
2987 self: *Self,
2988 tag: Air.Inst.Tag,
2989 maybe_inst: ?Air.Inst.Index,
2990 lhs: MCValue,
2991 rhs: MCValue,
2992 lhs_ty: Type,
2993 rhs_ty: Type,
2994) !MCValue {
2995 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
2996 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
2997 }
2998 if (lhs_ty.abiSize(self.target.*) > 8) {
2999 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
3000 }
3001
3002 assert(self.register_manager.isRegFree(.rcx));
3003
3004 try self.register_manager.getReg(.rcx, null);
3005 try self.genSetReg(rhs_ty, .rcx, rhs);
3006 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3007 defer self.register_manager.unlockReg(rcx_lock);
3008
3009 const int_info = lhs_ty.intInfo(self.target.*);
3010 const signedness = int_info.signedness;
3011
3012 const lhs_lock: ?RegisterLock = switch (lhs) {
3013 .register => |reg| self.register_manager.lockReg(reg),
3014 else => null,
3015 };
3016 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
3017
3018 const rhs_lock: ?RegisterLock = switch (rhs) {
3019 .register => |reg| self.register_manager.lockReg(reg),
3020 else => null,
3021 };
3022 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
3023
3024 const dst: MCValue = blk: {
3025 if (maybe_inst) |inst| {
3026 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3027 // TODO dst can also be a memory location
3028 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
3029 break :blk lhs;
3030 }
3031 break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
3032 }
3033 break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
3034 };
3035
3036 switch (tag) {
3037 .shl => switch (signedness) {
3038 .signed => {
3039 _ = try self.addInst(.{
3040 .tag = .sal,
3041 .ops = (Mir.Ops{
3042 .reg1 = dst.register,
3043 .flags = 0b01,
3044 }).encode(),
3045 .data = undefined,
3046 });
3047 },
3048 .unsigned => {
3049 _ = try self.addInst(.{
3050 .tag = .shl,
3051 .ops = (Mir.Ops{
3052 .reg1 = dst.register,
3053 .flags = 0b01,
3054 }).encode(),
3055 .data = undefined,
3056 });
3057 },
3058 },
3059 .shr => switch (signedness) {
3060 .signed => {
3061 _ = try self.addInst(.{
3062 .tag = .sar,
3063 .ops = (Mir.Ops{
3064 .reg1 = dst.register,
3065 .flags = 0b01,
3066 }).encode(),
3067 .data = undefined,
3068 });
3069 },
3070 .unsigned => {
3071 _ = try self.addInst(.{
3072 .tag = .shr,
3073 .ops = (Mir.Ops{
3074 .reg1 = dst.register,
3075 .flags = 0b01,
3076 }).encode(),
3077 .data = undefined,
3078 });
3079 },
3080 },
3081 else => unreachable,
3082 }
3083
3084 return dst;
3085}
3086
3087/// Result is always a register.
3088/// Clobbers .rax and .rdx therefore care is needed to spill .rax and .rdx upfront.
3101/// Asserts .rax and .rdx are free.3089/// Asserts .rax and .rdx are free.
3102fn genMulDivBinOp(3090fn genMulDivBinOp(
3103 self: *Self,3091 self: *Self,
...@@ -6790,7 +6778,8 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -6790,7 +6778,8 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
6790 }6778 }
6791}6779}
67926780
6793fn shiftRegister(self: *Self, reg: Register, shift: u8) !void {6781/// Shifts register right without sign-extension.
6782fn shiftRegisterRightUnsigned(self: *Self, reg: Register, shift: u8) !void {
6794 if (shift == 0) return;6783 if (shift == 0) return;
6795 if (shift == 1) {6784 if (shift == 1) {
6796 _ = try self.addInst(.{6785 _ = try self.addInst(.{