| ... | ... | @@ -3818,45 +3818,95 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 3818 | 3818 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3819 | 3819 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3820 | 3820 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3821 | | const operand = extra.struct_operand; |
| 3822 | | const index = extra.field_index; |
| 3821 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 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)) { |
| 3825 | | return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none }); |
| 3826 | | } |
| 3838 | switch (src_mcv) { |
| 3839 | .stack_offset => |src_off| { |
| 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); |
| 3829 | | const container_ty = self.air.typeOf(operand); |
| 3830 | | const field_ty = container_ty.structFieldType(index); |
| 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 | | }; |
| 3855 | if (field_abi_size > 8) { |
| 3856 | return self.fail("TODO implement struct_field_val with large packed field", .{}); |
| 3857 | } |
| 3838 | 3858 | |
| 3839 | | const result: MCValue = result: { |
| 3840 | | switch (mcv) { |
| 3841 | | .stack_offset => |off| { |
| 3842 | | const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch |
| 3843 | | return self.fail("TODO implement struct_field_val for a packed struct", .{}); |
| 3844 | | break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) }; |
| 3859 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3860 | const field_extra_bits = self.regExtraBits(field_ty); |
| 3861 | const load_abi_size = |
| 3862 | if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2; |
| 3863 | if (load_abi_size <= 8) { |
| 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 | 3898 | .register => |reg| { |
| 3847 | 3899 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3848 | 3900 | defer self.register_manager.unlockReg(reg_lock); |
| 3849 | 3901 | |
| 3850 | | const dst_mcv: MCValue = blk: { |
| 3851 | | if (self.reuseOperand(inst, operand, 0, mcv)) { |
| 3852 | | break :blk mcv; |
| 3853 | | } else { |
| 3854 | | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, Type.usize, .{ |
| 3855 | | .register = reg.to64(), |
| 3856 | | }); |
| 3857 | | break :blk dst_mcv; |
| 3858 | | } |
| 3859 | | }; |
| 3902 | const dst_mcv = if (self.reuseOperand(inst, operand, 0, src_mcv)) |
| 3903 | src_mcv |
| 3904 | else |
| 3905 | try self.copyToRegisterWithInstTracking( |
| 3906 | inst, |
| 3907 | Type.usize, |
| 3908 | .{ .register = reg.to64() }, |
| 3909 | ); |
| 3860 | 3910 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3861 | 3911 | .register => |a_reg| self.register_manager.lockReg(a_reg), |
| 3862 | 3912 | else => null, |
| ... | ... | @@ -3864,7 +3914,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3864 | 3914 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3865 | 3915 | |
| 3866 | 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 | 3919 | // Mask to field_bit_size bits |
| 3870 | 3920 | const field_bit_size = field_ty.bitSize(self.target.*); |
| ... | ... | @@ -3883,31 +3933,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3883 | 3933 | registerAlias(dst_mcv.register, field_byte_size), |
| 3884 | 3934 | ); |
| 3885 | 3935 | } |
| 3886 | | |
| 3887 | 3936 | break :result dst_mcv; |
| 3888 | 3937 | }, |
| 3889 | 3938 | .register_overflow => |ro| { |
| 3890 | 3939 | switch (index) { |
| 3891 | | 0 => { |
| 3892 | | // Get wrapped value for overflow operation. |
| 3893 | | break :result MCValue{ .register = ro.reg }; |
| 3894 | | }, |
| 3895 | | 1 => { |
| 3896 | | // Get overflow bit. |
| 3897 | | const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg); |
| 3898 | | defer self.register_manager.unlockReg(reg_lock); |
| 3899 | | |
| 3940 | // Get wrapped value for overflow operation. |
| 3941 | 0 => if (self.liveness.operandDies(inst, 0)) { |
| 3942 | self.eflags_inst = null; |
| 3943 | break :result .{ .register = ro.reg }; |
| 3944 | } else break :result try self.copyToRegisterWithInstTracking( |
| 3945 | inst, |
| 3946 | Type.usize, |
| 3947 | .{ .register = ro.reg }, |
| 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 | 3954 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3901 | 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 | 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 | 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 | 7961 | else => null, |
| 7909 | 7962 | }; |
| 7910 | 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 | 7968 | const elem_extra_bits = self.regExtraBits(elem_ty); |
| 7913 | 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 | 7972 | if (elem_bit_off > 0) try self.genShiftBinOpMir( |
| 7917 | | .sal, |
| 7973 | .shl, |
| 7918 | 7974 | elem_ty, |
| 7919 | 7975 | .{ .register = elem_reg }, |
| 7920 | 7976 | .{ .immediate = elem_bit_off }, |
| ... | ... | @@ -7931,7 +7987,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 7931 | 7987 | try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size)); |
| 7932 | 7988 | } |
| 7933 | 7989 | try self.genShiftBinOpMir( |
| 7934 | | .sar, |
| 7990 | .shr, |
| 7935 | 7991 | elem_ty, |
| 7936 | 7992 | .{ .register = reg }, |
| 7937 | 7993 | .{ .immediate = elem_abi_bits - elem_bit_off }, |