commit 20cc560c2dba4834e683692dabd43162a5ce8d22 (tree)
parent b09280b48452be8b57b87bbf4eaacd430e6e3537
Author: Jakub Konka <kubkon@jakubkonka.com>
Date: Thu, 24 Mar 2022 22:29:20 +0100
Merge pull request #11286 from ziglang/stage2-aggregate-init
stage2: add debug info for tuples (and anon structs), and implement aggregate_init for structs and arrays
Diffstat:
5 files changed, 103 insertions(+), 41 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
@@ -2884,6 +2884,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
break :blk dst_mcv;
}
};
+ dst_mcv.freezeIfRegister(&self.register_manager);
+ defer dst_mcv.unfreezeIfRegister(&self.register_manager);
// Shift by struct_field_offset.
const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
@@ -2893,7 +2895,25 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
const max_reg_bit_width = Register.rax.size();
const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*)));
const mask = (~@as(u64, 0)) >> mask_shift;
- try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .immediate = mask });
+
+ const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
+ try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
+
+ const signedness: std.builtin.Signedness = blk: {
+ if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned;
+ break :blk struct_field_ty.intInfo(self.target.*).signedness;
+ };
+ const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
+ if (signedness == .signed and field_size < 8) {
+ _ = try self.addInst(.{
+ .tag = .mov_sign_extend,
+ .ops = (Mir.Ops{
+ .reg1 = dst_mcv.register,
+ .reg2 = registerAlias(dst_mcv.register, field_size),
+ }).encode(),
+ .data = undefined,
+ });
+ }
break :result dst_mcv;
},
@@ -5671,13 +5691,42 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void {
}
fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
- const vector_ty = self.air.typeOfIndex(inst);
- const len = vector_ty.vectorLen();
+ const result_ty = self.air.typeOfIndex(inst);
+ const len = @intCast(usize, result_ty.arrayLen());
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const abi_size = @intCast(u32, result_ty.abiSize(self.target.*));
+ const abi_align = result_ty.abiAlignment(self.target.*);
const result: MCValue = res: {
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
- return self.fail("TODO implement airAggregateInit for x86_64", .{});
+ switch (result_ty.zigTypeTag()) {
+ .Struct => {
+ const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
+ for (elements) |elem, elem_i| {
+ if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem
+
+ const elem_ty = result_ty.structFieldType(elem_i);
+ const elem_off = 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, .{});
+ }
+ break :res MCValue{ .stack_offset = stack_offset };
+ },
+ .Array => {
+ const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
+ const elem_ty = result_ty.childType();
+ const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
+
+ for (elements) |elem, elem_i| {
+ const elem_mcv = try self.resolveInst(elem);
+ const elem_off = @intCast(i32, elem_size * elem_i);
+ try self.genSetStack(elem_ty, stack_offset - elem_off, elem_mcv, .{});
+ }
+ break :res MCValue{ .stack_offset = stack_offset };
+ },
+ .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}),
+ else => unreachable,
+ }
};
if (elements.len <= Liveness.bpi - 1) {
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
@@ -881,45 +881,63 @@ fn addDbgInfoType(
}
},
.Struct => blk: {
- if (ty.tag() == .tuple) {
- log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});
- try dbg_info_buffer.append(abbrev_pad1);
- break :blk;
- }
- // try dbg_info_buffer.ensureUnusedCapacity(23);
// DW.AT.structure_type
try dbg_info_buffer.append(abbrev_struct_type);
// DW.AT.byte_size, DW.FORM.sdata
const abi_size = ty.abiSize(target);
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
- // DW.AT.name, DW.FORM.string
- const struct_name = try ty.nameAllocArena(arena, target);
- try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1);
- dbg_info_buffer.appendSliceAssumeCapacity(struct_name);
- dbg_info_buffer.appendAssumeCapacity(0);
- const struct_obj = ty.castTag(.@"struct").?.data;
- if (struct_obj.layout == .Packed) {
- log.debug("TODO implement .debug_info for packed structs", .{});
- break :blk;
- }
+ switch (ty.tag()) {
+ .tuple, .anon_struct => {
+ // DW.AT.name, DW.FORM.string
+ try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)});
+
+ const fields = ty.tupleFields();
+ for (fields.types) |field, field_index| {
+ // DW.AT.member
+ try dbg_info_buffer.append(abbrev_struct_member);
+ // DW.AT.name, DW.FORM.string
+ try dbg_info_buffer.writer().print("{d}\x00", .{field_index});
+ // DW.AT.type, DW.FORM.ref4
+ var index = dbg_info_buffer.items.len;
+ try dbg_info_buffer.resize(index + 4);
+ try relocs.append(.{ .ty = field, .reloc = @intCast(u32, index) });
+ // DW.AT.data_member_location, DW.FORM.sdata
+ const field_off = ty.structFieldOffset(field_index, target);
+ try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
+ }
+ },
+ else => {
+ // DW.AT.name, DW.FORM.string
+ const struct_name = try ty.nameAllocArena(arena, target);
+ try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1);
+ dbg_info_buffer.appendSliceAssumeCapacity(struct_name);
+ dbg_info_buffer.appendAssumeCapacity(0);
+
+ const struct_obj = ty.castTag(.@"struct").?.data;
+ if (struct_obj.layout == .Packed) {
+ log.debug("TODO implement .debug_info for packed structs", .{});
+ break :blk;
+ }
- const fields = ty.structFields();
- for (fields.keys()) |field_name, field_index| {
- const field = fields.get(field_name).?;
- // DW.AT.member
- try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
- // DW.AT.name, DW.FORM.string
- dbg_info_buffer.appendSliceAssumeCapacity(field_name);
- dbg_info_buffer.appendAssumeCapacity(0);
- // DW.AT.type, DW.FORM.ref4
- var index = dbg_info_buffer.items.len;
- try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });
- // DW.AT.data_member_location, DW.FORM.sdata
- const field_off = ty.structFieldOffset(field_index, target);
- try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
+ const fields = ty.structFields();
+ for (fields.keys()) |field_name, field_index| {
+ const field = fields.get(field_name).?;
+ // DW.AT.member
+ try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
+ dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ // DW.AT.name, DW.FORM.string
+ dbg_info_buffer.appendSliceAssumeCapacity(field_name);
+ dbg_info_buffer.appendAssumeCapacity(0);
+ // DW.AT.type, DW.FORM.ref4
+ var index = dbg_info_buffer.items.len;
+ try dbg_info_buffer.resize(index + 4);
+ try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });
+ // DW.AT.data_member_location, DW.FORM.sdata
+ const field_off = ty.structFieldOffset(field_index, target);
+ try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
+ }
+ },
}
// DW.AT.structure_type delimit children
diff --git a/test/behavior/array.zig b/test/behavior/array.zig
@@ -501,7 +501,6 @@ test "type coercion of anon struct literal to array" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const S = struct {
const U = union {
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
@@ -301,7 +301,6 @@ test "void struct fields" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const foo = VoidStructFieldsFoo{
.a = void{},
@@ -1019,7 +1018,6 @@ test "struct with union field" {
}
test "type coercion of anon struct literal to struct" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig
@@ -4,7 +4,6 @@ const testing = std.testing;
const expect = testing.expect;
test "tuple concatenation" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@@ -47,7 +46,6 @@ test "tuple multiplication" {
}
test "more tuple concatenation" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO