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 {
597597 .mul_sat => try self.airMulSat(inst),
598598 .rem => try self.airMulDivBinOp(inst),
599599 .mod => try self.airMulDivBinOp(inst),
600 .shl, .shl_exact => try self.airShl(inst),
600 .shl, .shl_exact => try self.airShlShrBinOp(inst),
601601 .shl_sat => try self.airShlSat(inst),
602602 .min => try self.airMin(inst),
603603 .max => try self.airMax(inst),
......@@ -643,7 +643,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
643643 .bit_and => try self.airBinOp(inst),
644644 .bit_or => try self.airBinOp(inst),
645645 .xor => try self.airBinOp(inst),
646 .shr, .shr_exact => try self.airShr(inst),
646 .shr, .shr_exact => try self.airShlShrBinOp(inst),
647647
648648 .alloc => try self.airAlloc(inst),
649649 .ret_ptr => try self.airRetPtr(inst),
......@@ -1652,64 +1652,22 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
16521652 return MCValue{ .register = divisor };
16531653}
16541654
1655fn airShl(self: *Self, inst: Air.Inst.Index) !void {
1655fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
16561656 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1657
16571658 if (self.liveness.isUnused(inst)) {
16581659 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
16591660 }
16601661
1661 const ty = self.air.typeOfIndex(inst);
1662
16631662 const tag = self.air.instructions.items(.tag)[inst];
1664 switch (tag) {
1665 .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty.fmtDebug() }),
1666 .shl => {},
1667 else => unreachable,
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);
1663 const lhs = try self.resolveInst(bin_op.lhs);
1664 const rhs = try self.resolveInst(bin_op.rhs);
1665 const lhs_ty = self.air.typeOf(bin_op.lhs);
1666 const rhs_ty = self.air.typeOf(bin_op.rhs);
17011667
1702 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value);
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 });
1668 const result = try self.genShiftBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
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 });
17131671}
17141672
17151673fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1721,80 +1679,6 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
17211679 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
17221680}
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
17981682fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
17991683 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
18001684 if (self.liveness.isUnused(inst)) {
......@@ -1822,7 +1706,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
18221706 // TODO reuse the operand
18231707 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);
18241708 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));
18261710 break :result result;
18271711 },
18281712 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 {
19091793 // TODO reuse operand
19101794 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));
19111795 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);
19131797 break :result MCValue{
19141798 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
19151799 };
......@@ -2421,7 +2305,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
24212305 else
24222306 0;
24232307 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);
24252309 break :blk MCValue{
24262310 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
24272311 };
......@@ -3020,7 +2904,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30202904
30212905 // Shift by struct_field_offset.
30222906 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
30252909 // Mask with reg.size() - struct_field_size
30262910 const max_reg_bit_width = Register.rax.size();
......@@ -3097,7 +2981,111 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
30972981}
30982982
30992983/// 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.
31013089/// Asserts .rax and .rdx are free.
31023090fn genMulDivBinOp(
31033091 self: *Self,
......@@ -6790,7 +6778,8 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
67906778 }
67916779}
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 {
67946783 if (shift == 0) return;
67956784 if (shift == 1) {
67966785 _ = try self.addInst(.{