authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-31 20:31:39-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 04:49:53-04:00
logac68d72d244fafb601725d22631f7834fb14212c
treec0ec37dfc4246c4e03cef1c8b89b1328853840d6
parent43a6384e9c6ee6f3e250172f6f655782e808afed

x86_64: implement aggregate init of a packed struct


3 files changed, 74 insertions(+), 11 deletions(-)

src/arch/x86_64/CodeGen.zig+74-8
...@@ -7853,19 +7853,85 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -7853,19 +7853,85 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
7853 if (self.liveness.isUnused(inst)) break :res MCValue.dead;7853 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
7854 switch (result_ty.zigTypeTag()) {7854 switch (result_ty.zigTypeTag()) {
7855 .Struct => {7855 .Struct => {
7856 if (result_ty.containerLayout() == .Packed) {
7857 return self.fail("TODO airAggregateInit implement packed structs", .{});
7858 }
7859 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));7856 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
7860 for (elements, 0..) |elem, elem_i| {7857 const dst_mcv = MCValue{ .stack_offset = stack_offset };
7861 if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem7858 if (result_ty.containerLayout() == .Packed) {
7859 const struct_obj = result_ty.castTag(.@"struct").?.data;
7860 try self.genInlineMemset(
7861 dst_mcv,
7862 .{ .immediate = 0 },
7863 .{ .immediate = abi_size },
7864 .{},
7865 );
7866 for (elements, 0..) |elem, elem_i| {
7867 if (result_ty.structFieldValueComptime(elem_i) != null) continue;
7868
7869 const elem_ty = result_ty.structFieldType(elem_i);
7870 const elem_bit_size = @intCast(u32, elem_ty.bitSize(self.target.*));
7871 if (elem_bit_size > 64) {
7872 return self.fail("TODO airAggregateInit implement packed structs with large fields", .{});
7873 }
7874 const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
7875 const elem_abi_bits = elem_abi_size * 8;
7876 const elem_off = struct_obj.packedFieldBitOffset(self.target.*, elem_i);
7877 const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size);
7878 const elem_bit_off = elem_off % elem_abi_bits;
7879 const elem_mcv = try self.resolveInst(elem);
7880 const elem_lock = switch (elem_mcv) {
7881 .register => |reg| self.register_manager.lockReg(reg),
7882 .immediate => |imm| lock: {
7883 if (imm == 0) continue;
7884 break :lock null;
7885 },
7886 else => null,
7887 };
7888 defer if (elem_lock) |lock| self.register_manager.unlockReg(lock);
7889 const elem_reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
7890 const elem_extra_bits = self.regExtraBits(elem_ty);
7891 if (elem_bit_off < elem_extra_bits) {
7892 try self.truncateRegister(elem_ty, registerAlias(elem_reg, elem_abi_size));
7893 }
7894 if (elem_bit_off > 0) try self.genShiftBinOpMir(
7895 .sal,
7896 elem_ty,
7897 .{ .register = elem_reg },
7898 .{ .immediate = elem_bit_off },
7899 );
7900 try self.genBinOpMir(
7901 .@"or",
7902 elem_ty,
7903 .{ .stack_offset = stack_offset - elem_byte_off },
7904 .{ .register = elem_reg },
7905 );
7906 if (elem_bit_off > elem_extra_bits) {
7907 const reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
7908 if (elem_extra_bits > 0) {
7909 try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));
7910 }
7911 try self.genShiftBinOpMir(
7912 .sar,
7913 elem_ty,
7914 .{ .register = reg },
7915 .{ .immediate = elem_abi_bits - elem_bit_off },
7916 );
7917 try self.genBinOpMir(
7918 .@"or",
7919 elem_ty,
7920 .{ .stack_offset = stack_offset - elem_byte_off -
7921 @intCast(i32, elem_abi_size) },
7922 .{ .register = reg },
7923 );
7924 }
7925 }
7926 } else for (elements, 0..) |elem, elem_i| {
7927 if (result_ty.structFieldValueComptime(elem_i) != null) continue;
78627928
7863 const elem_ty = result_ty.structFieldType(elem_i);7929 const elem_ty = result_ty.structFieldType(elem_i);
7864 const elem_off = result_ty.structFieldOffset(elem_i, self.target.*);7930 const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, self.target.*));
7865 const elem_mcv = try self.resolveInst(elem);7931 const elem_mcv = try self.resolveInst(elem);
7866 try self.genSetStack(elem_ty, stack_offset - @intCast(i32, elem_off), elem_mcv, .{});7932 try self.genSetStack(elem_ty, stack_offset - elem_off, elem_mcv, .{});
7867 }7933 }
7868 break :res MCValue{ .stack_offset = stack_offset };7934 break :res dst_mcv;
7869 },7935 },
7870 .Array => {7936 .Array => {
7871 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));7937 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
test/behavior/packed-struct.zig-2
...@@ -352,7 +352,6 @@ test "byte-aligned field pointer offsets" {...@@ -352,7 +352,6 @@ test "byte-aligned field pointer offsets" {
352}352}
353353
354test "load pointer from packed struct" {354test "load pointer from packed struct" {
355 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
357 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
358 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -585,7 +584,6 @@ test "overaligned pointer to packed struct" {...@@ -585,7 +584,6 @@ test "overaligned pointer to packed struct" {
585test "packed struct initialized in bitcast" {584test "packed struct initialized in bitcast" {
586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
587 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO586 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
588 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
589587
590 const T = packed struct { val: u8 };588 const T = packed struct { val: u8 };
591 var val: u8 = 123;589 var val: u8 = 123;
test/behavior/struct.zig-1
...@@ -1244,7 +1244,6 @@ test "loading a struct pointer perfoms a copy" {...@@ -1244,7 +1244,6 @@ test "loading a struct pointer perfoms a copy" {
1244}1244}
12451245
1246test "packed struct aggregate init" {1246test "packed struct aggregate init" {
1247 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO