authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 00:45:21-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 04:49:53-04:00
logb80cdde4f079181ad4b3ba937771fcfd1de94bdb
treefa81ebfdda330d2a59f9412e0e08a80f0e72dba7
parent83a208c3551ae470f92753592a4c88984d2154d3

x86_64: implement struct_field_val for large packed structs


2 files changed, 105 insertions(+), 50 deletions(-)

src/arch/x86_64/CodeGen.zig+105-49
...@@ -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
3818fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {3818fn 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 };
38233837
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 }
38273854
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 };
38383858
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) catch3862 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);
38493901
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);
38653915
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 });
38683918
3869 // Mask to field_bit_size bits3919 // 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 },
38993948 ),
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}
39133966
...@@ -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 },
test/behavior/bugs/9584.zig-1
...@@ -47,7 +47,6 @@ test {...@@ -47,7 +47,6 @@ test {
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5150
52 var flags = A{51 var flags = A{
53 .a = false,52 .a = false,