| ... | @@ -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 operand | 1708 | // 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 operand | 1795 | // 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 | else | 2307 | 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 { |
| 2906 | | 2906 | |
| 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); |
| 2910 | | 2910 | |
| 2911 | // Mask with reg.size() - struct_field_size | 2911 | // 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 | } |
| 2984 | | 2984 | |
| | 2985 | /// Clobbers .rcx for non-immediate shift value. |
| | 2986 | fn 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( |
| 3003 | | 3071 | |
| 3004 | assert(rhs_ty.abiSize(self.target.*) == 1); | 3072 | assert(rhs_ty.abiSize(self.target.*) == 1); |
| 3005 | | 3073 | |
| 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); |
| 3020 | | 3085 | |
| 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; | | |
| 3043 | | 3090 | |
| 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 | }; |
| 3055 | | 3102 | |
| 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 | } |
| 3103 | | 3108 | |
| ... | @@ -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 | }); |
| 5423 | | 5428 | |
| 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 | } |
| 5434 | | 5432 | |
| 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 | } |
| 6800 | | 6798 | |
| 6801 | /// Shifts register right without sign-extension. | | |
| 6802 | fn 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. |
| 6826 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | 6801 | fn 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); |