aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-03-31 20:31:39 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2023-04-02 04:49:53 -0400
commitac68d72d244fafb601725d22631f7834fb14212c (patch)
treec0ec37dfc4246c4e03cef1c8b89b1328853840d6 /src
parent43a6384e9c6ee6f3e250172f6f655782e808afed (diff)
downloadzig-ac68d72d244fafb601725d22631f7834fb14212c.tar.gz
zig-ac68d72d244fafb601725d22631f7834fb14212c.zip
x86_64: implement aggregate init of a packed struct
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig82
1 files changed, 74 insertions, 8 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 604052ee7e..a216ed3c2c 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -7853,19 +7853,85 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
switch (result_ty.zigTypeTag()) {
.Struct => {
- if (result_ty.containerLayout() == .Packed) {
- return self.fail("TODO airAggregateInit implement packed structs", .{});
- }
const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
- for (elements, 0..) |elem, elem_i| {
- if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem
+ const dst_mcv = MCValue{ .stack_offset = stack_offset };
+ if (result_ty.containerLayout() == .Packed) {
+ const struct_obj = result_ty.castTag(.@"struct").?.data;
+ try self.genInlineMemset(
+ dst_mcv,
+ .{ .immediate = 0 },
+ .{ .immediate = abi_size },
+ .{},
+ );
+ for (elements, 0..) |elem, elem_i| {
+ if (result_ty.structFieldValueComptime(elem_i) != null) continue;
+
+ const elem_ty = result_ty.structFieldType(elem_i);
+ const elem_bit_size = @intCast(u32, elem_ty.bitSize(self.target.*));
+ if (elem_bit_size > 64) {
+ return self.fail("TODO airAggregateInit implement packed structs with large fields", .{});
+ }
+ const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
+ const elem_abi_bits = elem_abi_size * 8;
+ const elem_off = struct_obj.packedFieldBitOffset(self.target.*, elem_i);
+ const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size);
+ const elem_bit_off = elem_off % elem_abi_bits;
+ const elem_mcv = try self.resolveInst(elem);
+ const elem_lock = switch (elem_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ .immediate => |imm| lock: {
+ if (imm == 0) continue;
+ break :lock null;
+ },
+ else => null,
+ };
+ defer if (elem_lock) |lock| self.register_manager.unlockReg(lock);
+ const elem_reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
+ const elem_extra_bits = self.regExtraBits(elem_ty);
+ if (elem_bit_off < elem_extra_bits) {
+ try self.truncateRegister(elem_ty, registerAlias(elem_reg, elem_abi_size));
+ }
+ if (elem_bit_off > 0) try self.genShiftBinOpMir(
+ .sal,
+ elem_ty,
+ .{ .register = elem_reg },
+ .{ .immediate = elem_bit_off },
+ );
+ try self.genBinOpMir(
+ .@"or",
+ elem_ty,
+ .{ .stack_offset = stack_offset - elem_byte_off },
+ .{ .register = elem_reg },
+ );
+ if (elem_bit_off > elem_extra_bits) {
+ const reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
+ if (elem_extra_bits > 0) {
+ try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));
+ }
+ try self.genShiftBinOpMir(
+ .sar,
+ elem_ty,
+ .{ .register = reg },
+ .{ .immediate = elem_abi_bits - elem_bit_off },
+ );
+ try self.genBinOpMir(
+ .@"or",
+ elem_ty,
+ .{ .stack_offset = stack_offset - elem_byte_off -
+ @intCast(i32, elem_abi_size) },
+ .{ .register = reg },
+ );
+ }
+ }
+ } else for (elements, 0..) |elem, elem_i| {
+ if (result_ty.structFieldValueComptime(elem_i) != null) continue;
const elem_ty = result_ty.structFieldType(elem_i);
- const elem_off = result_ty.structFieldOffset(elem_i, self.target.*);
+ const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, self.target.*));
const elem_mcv = try self.resolveInst(elem);
- try self.genSetStack(elem_ty, stack_offset - @intCast(i32, elem_off), elem_mcv, .{});
+ try self.genSetStack(elem_ty, stack_offset - elem_off, elem_mcv, .{});
}
- break :res MCValue{ .stack_offset = stack_offset };
+ break :res dst_mcv;
},
.Array => {
const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));