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
38183818fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
38193819 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
38203820 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 };
38233837
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 }
38273854
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 }
38383858
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 };
38453897 },
38463898 .register => |reg| {
38473899 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
38483900 defer self.register_manager.unlockReg(reg_lock);
38493901
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 );
38603910 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
38613911 .register => |a_reg| self.register_manager.lockReg(a_reg),
38623912 else => null,
......@@ -3864,7 +3914,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
38643914 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
38653915
38663916 // 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
38693919 // Mask to field_bit_size bits
38703920 const field_bit_size = field_ty.bitSize(self.target.*);
......@@ -3883,31 +3933,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
38833933 registerAlias(dst_mcv.register, field_byte_size),
38843934 );
38853935 }
3886
38873936 break :result dst_mcv;
38883937 },
38893938 .register_overflow => |ro| {
38903939 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 {
39003954 const dst_reg = try self.register_manager.allocReg(inst, gp);
39013955 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
3902 break :result MCValue{ .register = dst_reg.to8() };
3956 break :result .{ .register = dst_reg.to8() };
39033957 },
39043958 else => unreachable,
39053959 }
39063960 },
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}),
39083962 }
39093963 };
3910
39113964 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
39123965}
39133966
......@@ -7908,13 +7961,16 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
79087961 else => null,
79097962 };
79107963 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 );
79127968 const elem_extra_bits = self.regExtraBits(elem_ty);
79137969 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);
79157971 }
79167972 if (elem_bit_off > 0) try self.genShiftBinOpMir(
7917 .sal,
7973 .shl,
79187974 elem_ty,
79197975 .{ .register = elem_reg },
79207976 .{ .immediate = elem_bit_off },
......@@ -7931,7 +7987,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
79317987 try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));
79327988 }
79337989 try self.genShiftBinOpMir(
7934 .sar,
7990 .shr,
79357991 elem_ty,
79367992 .{ .register = reg },
79377993 .{ .immediate = elem_abi_bits - elem_bit_off },
test/behavior/bugs/9584.zig-1
......@@ -47,7 +47,6 @@ test {
4747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4848 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4949 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5150
5251 var flags = A{
5352 .a = false,