| ... | ... | @@ -1708,7 +1708,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1708 | 1708 | // TODO reuse the operand |
| 1709 | 1709 | const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand); |
| 1710 | 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 | 1712 | break :result result; |
| 1713 | 1713 | }, |
| 1714 | 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 | 1795 | // TODO reuse operand |
| 1796 | 1796 | const shift = @intCast(u6, err_abi_size * @sizeOf(usize)); |
| 1797 | 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 | 1799 | break :result MCValue{ |
| 1800 | 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 | 2307 | else |
| 2308 | 2308 | 0; |
| 2309 | 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 | 2311 | break :blk MCValue{ |
| 2312 | 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 | 2906 | |
| 2907 | 2907 | // Shift by struct_field_offset. |
| 2908 | 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 | 2911 | // Mask with reg.size() - struct_field_size |
| 2912 | 2912 | const max_reg_bit_width = Register.rax.size(); |
| ... | ... | @@ -2982,6 +2982,74 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2982 | 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 | 3053 | /// Result is always a register. |
| 2986 | 3054 | /// Clobbers .rcx for non-immediate rhs, therefore care is needed to spill .rcx upfront. |
| 2987 | 3055 | /// Asserts .rcx is free. |
| ... | ... | @@ -3003,9 +3071,6 @@ fn genShiftBinOp( |
| 3003 | 3071 | |
| 3004 | 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 | 3074 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 3010 | 3075 | .register => |reg| self.register_manager.lockReg(reg), |
| 3011 | 3076 | else => null, |
| ... | ... | @@ -3018,28 +3083,10 @@ fn genShiftBinOp( |
| 3018 | 3083 | }; |
| 3019 | 3084 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3020 | 3085 | |
| 3021 | | const flags: u2 = blk: { |
| 3022 | | if (rhs.isImmediate()) { |
| 3023 | | const flags: u2 = switch (rhs.immediate) { |
| 3024 | | 0 => unreachable, // TODO is this valid? |
| 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; |
| 3086 | assert(self.register_manager.isRegFree(.rcx)); |
| 3087 | try self.register_manager.getReg(.rcx, null); |
| 3088 | const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx); |
| 3089 | defer self.register_manager.unlockReg(rcx_lock); |
| 3043 | 3090 | |
| 3044 | 3091 | const dst: MCValue = blk: { |
| 3045 | 3092 | if (maybe_inst) |inst| { |
| ... | ... | @@ -3054,50 +3101,8 @@ fn genShiftBinOp( |
| 3054 | 3101 | }; |
| 3055 | 3102 | |
| 3056 | 3103 | switch (tag) { |
| 3057 | | .shl => switch (signedness) { |
| 3058 | | .signed => { |
| 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 | | }, |
| 3104 | .shl => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .left), |
| 3105 | .shr => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .right), |
| 3101 | 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 | 5427 | }); |
| 5423 | 5428 | |
| 5424 | 5429 | if (nearest_power_of_two > 1) { |
| 5425 | | _ = try self.addInst(.{ |
| 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 | | }); |
| 5430 | try self.genShiftBinOpMir(ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }, .right); |
| 5433 | 5431 | } |
| 5434 | 5432 | |
| 5435 | 5433 | remainder -= nearest_power_of_two; |
| ... | ... | @@ -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 | 6799 | /// Truncates the value in the register in place. |
| 6825 | 6800 | /// Clobbers any remaining bits. |
| 6826 | 6801 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| ... | ... | @@ -6829,22 +6804,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 6829 | 6804 | switch (int_info.signedness) { |
| 6830 | 6805 | .signed => { |
| 6831 | 6806 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); |
| 6832 | | _ = try self.addInst(.{ |
| 6833 | | .tag = .sal, |
| 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 | | }); |
| 6807 | try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .left); |
| 6808 | try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .right); |
| 6848 | 6809 | }, |
| 6849 | 6810 | .unsigned => { |
| 6850 | 6811 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); |