| ... | @@ -3818,45 +3818,95 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 | ... | @@ -3818,45 +3818,95 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 3818 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 3818 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3819 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3819 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3820 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 3820 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3821 | const operand = extra.struct_operand; | 3821 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3822 | const index = extra.field_index; | 3822 | const operand = extra.struct_operand; |
| | 3823 | const index = extra.field_index; |
| | 3824 | |
| | 3825 | const container_ty = self.air.typeOf(operand); |
| | 3826 | const field_ty = container_ty.structFieldType(index); |
| | 3827 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; |
| | 3828 | |
| | 3829 | const src_mcv = try self.resolveInst(operand); |
| | 3830 | const field_off = switch (container_ty.containerLayout()) { |
| | 3831 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8), |
| | 3832 | .Packed => if (container_ty.castTag(.@"struct")) |struct_obj| |
| | 3833 | struct_obj.data.packedFieldBitOffset(self.target.*, index) |
| | 3834 | else |
| | 3835 | 0, |
| | 3836 | }; |
| 3823 | | 3837 | |
| 3824 | if (self.liveness.isUnused(inst)) { | 3838 | switch (src_mcv) { |
| 3825 | return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none }); | 3839 | .stack_offset => |src_off| { |
| 3826 | } | 3840 | const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); |
| | 3841 | const limb_abi_size = @min(field_abi_size, 8); |
| | 3842 | const limb_abi_bits = limb_abi_size * 8; |
| | 3843 | const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); |
| | 3844 | const field_bit_off = field_off % limb_abi_bits; |
| | 3845 | |
| | 3846 | if (field_bit_off == 0) { |
| | 3847 | const off_mcv = MCValue{ .stack_offset = src_off - field_byte_off }; |
| | 3848 | if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv; |
| | 3849 | |
| | 3850 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 3851 | try self.setRegOrMem(field_ty, dst_mcv, off_mcv); |
| | 3852 | break :result dst_mcv; |
| | 3853 | } |
| 3827 | | 3854 | |
| 3828 | const mcv = try self.resolveInst(operand); | 3855 | if (field_abi_size > 8) { |
| 3829 | const container_ty = self.air.typeOf(operand); | 3856 | return self.fail("TODO implement struct_field_val with large packed field", .{}); |
| 3830 | const field_ty = container_ty.structFieldType(index); | 3857 | } |
| 3831 | const field_bit_offset = switch (container_ty.containerLayout()) { | | |
| 3832 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8), | | |
| 3833 | .Packed => if (container_ty.castTag(.@"struct")) |struct_obj| | | |
| 3834 | struct_obj.data.packedFieldBitOffset(self.target.*, index) | | |
| 3835 | else | | |
| 3836 | 0, | | |
| 3837 | }; | | |
| 3838 | | 3858 | |
| 3839 | const result: MCValue = result: { | 3859 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3840 | switch (mcv) { | 3860 | const field_extra_bits = self.regExtraBits(field_ty); |
| 3841 | .stack_offset => |off| { | 3861 | const load_abi_size = |
| 3842 | const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch | 3862 | if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2; |
| 3843 | return self.fail("TODO implement struct_field_val for a packed struct", .{}); | 3863 | if (load_abi_size <= 8) { |
| 3844 | break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) }; | 3864 | const load_reg = registerAlias(dst_reg, load_abi_size); |
| | 3865 | try self.asmRegisterMemory(.mov, load_reg, Memory.sib( |
| | 3866 | Memory.PtrSize.fromSize(load_abi_size), |
| | 3867 | .{ .base = .rbp, .disp = field_byte_off - src_off }, |
| | 3868 | )); |
| | 3869 | try self.asmRegisterImmediate(.shr, load_reg, Immediate.u(field_bit_off)); |
| | 3870 | } else { |
| | 3871 | const tmp_reg = registerAlias( |
| | 3872 | try self.register_manager.allocReg(null, gp), |
| | 3873 | field_abi_size, |
| | 3874 | ); |
| | 3875 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| | 3876 | defer self.register_manager.unlockReg(tmp_lock); |
| | 3877 | |
| | 3878 | const dst_alias = registerAlias(dst_reg, field_abi_size); |
| | 3879 | try self.asmRegisterMemory(.mov, dst_alias, Memory.sib( |
| | 3880 | Memory.PtrSize.fromSize(field_abi_size), |
| | 3881 | .{ .base = .rbp, .disp = field_byte_off - src_off }, |
| | 3882 | )); |
| | 3883 | try self.asmRegisterMemory(.mov, tmp_reg, Memory.sib( |
| | 3884 | Memory.PtrSize.fromSize(field_abi_size), |
| | 3885 | .{ .base = .rbp, .disp = field_byte_off + 1 - src_off }, |
| | 3886 | )); |
| | 3887 | try self.asmRegisterRegisterImmediate( |
| | 3888 | .shrd, |
| | 3889 | dst_alias, |
| | 3890 | tmp_reg, |
| | 3891 | Immediate.u(field_bit_off), |
| | 3892 | ); |
| | 3893 | } |
| | 3894 | |
| | 3895 | if (field_extra_bits > 0) try self.truncateRegister(field_ty, dst_reg); |
| | 3896 | break :result .{ .register = dst_reg }; |
| 3845 | }, | 3897 | }, |
| 3846 | .register => |reg| { | 3898 | .register => |reg| { |
| 3847 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); | 3899 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3848 | defer self.register_manager.unlockReg(reg_lock); | 3900 | defer self.register_manager.unlockReg(reg_lock); |
| 3849 | | 3901 | |
| 3850 | const dst_mcv: MCValue = blk: { | 3902 | const dst_mcv = if (self.reuseOperand(inst, operand, 0, src_mcv)) |
| 3851 | if (self.reuseOperand(inst, operand, 0, mcv)) { | 3903 | src_mcv |
| 3852 | break :blk mcv; | 3904 | else |
| 3853 | } else { | 3905 | try self.copyToRegisterWithInstTracking( |
| 3854 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, Type.usize, .{ | 3906 | inst, |
| 3855 | .register = reg.to64(), | 3907 | Type.usize, |
| 3856 | }); | 3908 | .{ .register = reg.to64() }, |
| 3857 | break :blk dst_mcv; | 3909 | ); |
| 3858 | } | | |
| 3859 | }; | | |
| 3860 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | 3910 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3861 | .register => |a_reg| self.register_manager.lockReg(a_reg), | 3911 | .register => |a_reg| self.register_manager.lockReg(a_reg), |
| 3862 | else => null, | 3912 | else => null, |
| ... | @@ -3864,7 +3914,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3864,7 +3914,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3864 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 3914 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3865 | | 3915 | |
| 3866 | // Shift by struct_field_offset. | 3916 | // Shift by struct_field_offset. |
| 3867 | try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_bit_offset }); | 3917 | try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_off }); |
| 3868 | | 3918 | |
| 3869 | // Mask to field_bit_size bits | 3919 | // Mask to field_bit_size bits |
| 3870 | const field_bit_size = field_ty.bitSize(self.target.*); | 3920 | const field_bit_size = field_ty.bitSize(self.target.*); |
| ... | @@ -3883,31 +3933,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3883,31 +3933,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3883 | registerAlias(dst_mcv.register, field_byte_size), | 3933 | registerAlias(dst_mcv.register, field_byte_size), |
| 3884 | ); | 3934 | ); |
| 3885 | } | 3935 | } |
| 3886 | | | |
| 3887 | break :result dst_mcv; | 3936 | break :result dst_mcv; |
| 3888 | }, | 3937 | }, |
| 3889 | .register_overflow => |ro| { | 3938 | .register_overflow => |ro| { |
| 3890 | switch (index) { | 3939 | switch (index) { |
| 3891 | 0 => { | 3940 | // Get wrapped value for overflow operation. |
| 3892 | // Get wrapped value for overflow operation. | 3941 | 0 => if (self.liveness.operandDies(inst, 0)) { |
| 3893 | break :result MCValue{ .register = ro.reg }; | 3942 | self.eflags_inst = null; |
| 3894 | }, | 3943 | break :result .{ .register = ro.reg }; |
| 3895 | 1 => { | 3944 | } else break :result try self.copyToRegisterWithInstTracking( |
| 3896 | // Get overflow bit. | 3945 | inst, |
| 3897 | const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg); | 3946 | Type.usize, |
| 3898 | defer self.register_manager.unlockReg(reg_lock); | 3947 | .{ .register = ro.reg }, |
| 3899 | | 3948 | ), |
| | 3949 | // Get overflow bit. |
| | 3950 | 1 => if (self.liveness.operandDies(inst, 0)) { |
| | 3951 | self.eflags_inst = inst; |
| | 3952 | break :result .{ .eflags = ro.eflags }; |
| | 3953 | } else { |
| 3900 | const dst_reg = try self.register_manager.allocReg(inst, gp); | 3954 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3901 | try self.asmSetccRegister(dst_reg.to8(), ro.eflags); | 3955 | try self.asmSetccRegister(dst_reg.to8(), ro.eflags); |
| 3902 | break :result MCValue{ .register = dst_reg.to8() }; | 3956 | break :result .{ .register = dst_reg.to8() }; |
| 3903 | }, | 3957 | }, |
| 3904 | else => unreachable, | 3958 | else => unreachable, |
| 3905 | } | 3959 | } |
| 3906 | }, | 3960 | }, |
| 3907 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), | 3961 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{src_mcv}), |
| 3908 | } | 3962 | } |
| 3909 | }; | 3963 | }; |
| 3910 | | | |
| 3911 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); | 3964 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 3912 | } | 3965 | } |
| 3913 | | 3966 | |
| ... | @@ -7908,13 +7961,16 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7908,13 +7961,16 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 7908 | else => null, | 7961 | else => null, |
| 7909 | }; | 7962 | }; |
| 7910 | defer if (elem_lock) |lock| self.register_manager.unlockReg(lock); | 7963 | defer if (elem_lock) |lock| self.register_manager.unlockReg(lock); |
| 7911 | const elem_reg = try self.copyToTmpRegister(elem_ty, elem_mcv); | 7964 | const elem_reg = registerAlias( |
| | 7965 | try self.copyToTmpRegister(elem_ty, elem_mcv), |
| | 7966 | elem_abi_size, |
| | 7967 | ); |
| 7912 | const elem_extra_bits = self.regExtraBits(elem_ty); | 7968 | const elem_extra_bits = self.regExtraBits(elem_ty); |
| 7913 | if (elem_bit_off < elem_extra_bits) { | 7969 | if (elem_bit_off < elem_extra_bits) { |
| 7914 | try self.truncateRegister(elem_ty, registerAlias(elem_reg, elem_abi_size)); | 7970 | try self.truncateRegister(elem_ty, elem_reg); |
| 7915 | } | 7971 | } |
| 7916 | if (elem_bit_off > 0) try self.genShiftBinOpMir( | 7972 | if (elem_bit_off > 0) try self.genShiftBinOpMir( |
| 7917 | .sal, | 7973 | .shl, |
| 7918 | elem_ty, | 7974 | elem_ty, |
| 7919 | .{ .register = elem_reg }, | 7975 | .{ .register = elem_reg }, |
| 7920 | .{ .immediate = elem_bit_off }, | 7976 | .{ .immediate = elem_bit_off }, |
| ... | @@ -7931,7 +7987,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7931,7 +7987,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 7931 | try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size)); | 7987 | try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size)); |
| 7932 | } | 7988 | } |
| 7933 | try self.genShiftBinOpMir( | 7989 | try self.genShiftBinOpMir( |
| 7934 | .sar, | 7990 | .shr, |
| 7935 | elem_ty, | 7991 | elem_ty, |
| 7936 | .{ .register = reg }, | 7992 | .{ .register = reg }, |
| 7937 | .{ .immediate = elem_abi_bits - elem_bit_off }, | 7993 | .{ .immediate = elem_abi_bits - elem_bit_off }, |