authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 18:52:49+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 18:52:49+02:00
log9725205859517ce81e201b79b55f7a7c2cb87f20
treeb56d00e0b9eb8280ab5a479d10a60d1088bba7de
parenta9514ae1732df1fdc142b602e62ab0d12f693afa

x64: consolidate shifts into single MIR helper fn


1 files changed, 81 insertions(+), 120 deletions(-)

src/arch/x86_64/CodeGen.zig+81-120
...@@ -1708,7 +1708,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1708,7 +1708,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1708 // TODO reuse the operand1708 // TODO reuse the operand
1709 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);1709 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);
1710 const shift = @intCast(u8, offset * @sizeOf(usize));1710 const shift = @intCast(u8, offset * @sizeOf(usize));
1711 try self.shiftRegisterRightUnsigned(result.register, @intCast(u8, shift));1711 try self.genShiftBinOpMir(optional_ty, result.register, .{ .immediate = @intCast(u8, shift) }, .right);
1712 break :result result;1712 break :result result;
1713 },1713 },
1714 else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),1714 else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),
...@@ -1795,7 +1795,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1795,7 +1795,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1795 // TODO reuse operand1795 // TODO reuse operand
1796 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));1796 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));
1797 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);1797 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1798 try self.shiftRegisterRightUnsigned(result.register.to64(), shift);1798 try self.genShiftBinOpMir(Type.usize, result.register, .{ .immediate = shift }, .right);
1799 break :result MCValue{1799 break :result MCValue{
1800 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),1800 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
1801 };1801 };
...@@ -2307,7 +2307,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -2307,7 +2307,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
2307 else2307 else
2308 0;2308 0;
2309 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);2309 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
2310 try self.shiftRegisterRightUnsigned(result.register.to64(), shift);2310 try self.genShiftBinOpMir(Type.usize, result.register, .{ .immediate = shift }, .right);
2311 break :blk MCValue{2311 break :blk MCValue{
2312 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),2312 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
2313 };2313 };
...@@ -2906,7 +2906,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2906,7 +2906,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
29062906
2907 // Shift by struct_field_offset.2907 // Shift by struct_field_offset.
2908 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));2908 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
2909 try self.shiftRegisterRightUnsigned(dst_mcv.register, shift);2909 try self.genShiftBinOpMir(Type.usize, dst_mcv.register, .{ .immediate = shift }, .right);
29102910
2911 // Mask with reg.size() - struct_field_size2911 // Mask with reg.size() - struct_field_size
2912 const max_reg_bit_width = Register.rax.size();2912 const max_reg_bit_width = Register.rax.size();
...@@ -2982,6 +2982,74 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2982,6 +2982,74 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2982 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2982 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2983}2983}
29842984
2985/// Clobbers .rcx for non-immediate shift value.
2986fn genShiftBinOpMir(self: *Self, ty: Type, reg: Register, shift: MCValue, direction: enum { left, right }) !void {
2987 assert(reg.to64() != .rcx);
2988
2989 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
2990 const signedness: std.builtin.Signedness = blk: {
2991 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
2992 break :blk ty.intInfo(self.target.*).signedness;
2993 };
2994
2995 const tag: Mir.Inst.Tag = switch (signedness) {
2996 .signed => switch (direction) {
2997 .left => Mir.Inst.Tag.sal,
2998 .right => Mir.Inst.Tag.sar,
2999 },
3000 .unsigned => switch (direction) {
3001 .left => Mir.Inst.Tag.shl,
3002 .right => Mir.Inst.Tag.shr,
3003 },
3004 };
3005
3006 blk: {
3007 switch (shift) {
3008 .immediate => |imm| switch (imm) {
3009 0 => return,
3010 1 => {
3011 _ = try self.addInst(.{
3012 .tag = tag,
3013 .ops = (Mir.Ops{
3014 .reg1 = registerAlias(reg, abi_size),
3015 .flags = 0b00,
3016 }).encode(),
3017 .data = undefined,
3018 });
3019 return;
3020 },
3021 else => {
3022 _ = try self.addInst(.{
3023 .tag = tag,
3024 .ops = (Mir.Ops{
3025 .reg1 = registerAlias(reg, abi_size),
3026 .flags = 0b10,
3027 }).encode(),
3028 .data = .{ .imm = @intCast(u8, imm) },
3029 });
3030 return;
3031 },
3032 },
3033 .register => |shift_reg| {
3034 if (shift_reg == .rcx) break :blk;
3035 },
3036 else => {},
3037 }
3038 assert(self.register_manager.isRegFree(.rcx));
3039 try self.register_manager.getReg(.rcx, null);
3040 try self.genSetReg(Type.u8, .rcx, shift);
3041 }
3042
3043 _ = try self.addInst(.{
3044 .tag = tag,
3045 .ops = (Mir.Ops{
3046 .reg1 = registerAlias(reg, abi_size),
3047 .flags = 0b01,
3048 }).encode(),
3049 .data = undefined,
3050 });
3051}
3052
2985/// Result is always a register.3053/// Result is always a register.
2986/// Clobbers .rcx for non-immediate rhs, therefore care is needed to spill .rcx upfront.3054/// Clobbers .rcx for non-immediate rhs, therefore care is needed to spill .rcx upfront.
2987/// Asserts .rcx is free.3055/// Asserts .rcx is free.
...@@ -3003,9 +3071,6 @@ fn genShiftBinOp(...@@ -3003,9 +3071,6 @@ fn genShiftBinOp(
30033071
3004 assert(rhs_ty.abiSize(self.target.*) == 1);3072 assert(rhs_ty.abiSize(self.target.*) == 1);
30053073
3006 const int_info = lhs_ty.intInfo(self.target.*);
3007 const signedness = int_info.signedness;
3008
3009 const lhs_lock: ?RegisterLock = switch (lhs) {3074 const lhs_lock: ?RegisterLock = switch (lhs) {
3010 .register => |reg| self.register_manager.lockReg(reg),3075 .register => |reg| self.register_manager.lockReg(reg),
3011 else => null,3076 else => null,
...@@ -3018,28 +3083,10 @@ fn genShiftBinOp(...@@ -3018,28 +3083,10 @@ fn genShiftBinOp(
3018 };3083 };
3019 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);3084 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
30203085
3021 const flags: u2 = blk: {3086 assert(self.register_manager.isRegFree(.rcx));
3022 if (rhs.isImmediate()) {3087 try self.register_manager.getReg(.rcx, null);
3023 const flags: u2 = switch (rhs.immediate) {3088 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3024 0 => unreachable, // TODO is this valid?3089 defer self.register_manager.unlockReg(rcx_lock);
3025 1 => 0b00,
3026 else => 0b10,
3027 };
3028 break :blk flags;
3029 }
3030
3031 assert(self.register_manager.isRegFree(.rcx));
3032
3033 try self.register_manager.getReg(.rcx, null);
3034 try self.genSetReg(rhs_ty, .rcx, rhs);
3035 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3036 defer self.register_manager.unlockReg(rcx_lock);
3037
3038 break :blk 0b01;
3039 };
3040 const data: Mir.Inst.Data = if (rhs.isImmediate()) .{
3041 .imm = @intCast(u8, rhs.immediate),
3042 } else undefined;
30433090
3044 const dst: MCValue = blk: {3091 const dst: MCValue = blk: {
3045 if (maybe_inst) |inst| {3092 if (maybe_inst) |inst| {
...@@ -3054,50 +3101,8 @@ fn genShiftBinOp(...@@ -3054,50 +3101,8 @@ fn genShiftBinOp(
3054 };3101 };
30553102
3056 switch (tag) {3103 switch (tag) {
3057 .shl => switch (signedness) {3104 .shl => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .left),
3058 .signed => {3105 .shr => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .right),
3059 _ = try self.addInst(.{
3060 .tag = .sal,
3061 .ops = (Mir.Ops{
3062 .reg1 = dst.register,
3063 .flags = flags,
3064 }).encode(),
3065 .data = data,
3066 });
3067 },
3068 .unsigned => {
3069 _ = try self.addInst(.{
3070 .tag = .shl,
3071 .ops = (Mir.Ops{
3072 .reg1 = dst.register,
3073 .flags = flags,
3074 }).encode(),
3075 .data = data,
3076 });
3077 },
3078 },
3079 .shr => switch (signedness) {
3080 .signed => {
3081 _ = try self.addInst(.{
3082 .tag = .sar,
3083 .ops = (Mir.Ops{
3084 .reg1 = dst.register,
3085 .flags = flags,
3086 }).encode(),
3087 .data = data,
3088 });
3089 },
3090 .unsigned => {
3091 _ = try self.addInst(.{
3092 .tag = .shr,
3093 .ops = (Mir.Ops{
3094 .reg1 = dst.register,
3095 .flags = flags,
3096 }).encode(),
3097 .data = data,
3098 });
3099 },
3100 },
3101 else => unreachable,3106 else => unreachable,
3102 }3107 }
31033108
...@@ -5422,14 +5427,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5422,14 +5427,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5422 });5427 });
54235428
5424 if (nearest_power_of_two > 1) {5429 if (nearest_power_of_two > 1) {
5425 _ = try self.addInst(.{5430 try self.genShiftBinOpMir(ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }, .right);
5426 .tag = .shr,
5427 .ops = (Mir.Ops{
5428 .reg1 = tmp_reg,
5429 .flags = 0b10,
5430 }).encode(),
5431 .data = .{ .imm = nearest_power_of_two * 8 },
5432 });
5433 }5431 }
54345432
5435 remainder -= nearest_power_of_two;5433 remainder -= nearest_power_of_two;
...@@ -6798,29 +6796,6 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -6798,29 +6796,6 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
6798 }6796 }
6799}6797}
68006798
6801/// Shifts register right without sign-extension.
6802fn shiftRegisterRightUnsigned(self: *Self, reg: Register, shift: u8) !void {
6803 if (shift == 0) return;
6804 if (shift == 1) {
6805 _ = try self.addInst(.{
6806 .tag = .shr,
6807 .ops = (Mir.Ops{
6808 .reg1 = reg,
6809 }).encode(),
6810 .data = undefined,
6811 });
6812 } else {
6813 _ = try self.addInst(.{
6814 .tag = .shr,
6815 .ops = (Mir.Ops{
6816 .reg1 = reg,
6817 .flags = 0b10,
6818 }).encode(),
6819 .data = .{ .imm = shift },
6820 });
6821 }
6822}
6823
6824/// Truncates the value in the register in place.6799/// Truncates the value in the register in place.
6825/// Clobbers any remaining bits.6800/// Clobbers any remaining bits.
6826fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {6801fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
...@@ -6829,22 +6804,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -6829,22 +6804,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
6829 switch (int_info.signedness) {6804 switch (int_info.signedness) {
6830 .signed => {6805 .signed => {
6831 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);6806 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
6832 _ = try self.addInst(.{6807 try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .left);
6833 .tag = .sal,6808 try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .right);
6834 .ops = (Mir.Ops{
6835 .reg1 = reg.to64(),
6836 .flags = 0b10,
6837 }).encode(),
6838 .data = .{ .imm = shift },
6839 });
6840 _ = try self.addInst(.{
6841 .tag = .sar,
6842 .ops = (Mir.Ops{
6843 .reg1 = reg.to64(),
6844 .flags = 0b10,
6845 }).encode(),
6846 .data = .{ .imm = shift },
6847 });
6848 },6809 },
6849 .unsigned => {6810 .unsigned => {
6850 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);6811 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);