authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-05 18:03:09+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-05 19:58:42+00:00
log8f849684f46ad0835bd9591f420e49e212880cb2
treeebf5d639609a744108f4e9a356d0074c25a640d9
parent7f3211a101d8763ec5f0009b219f6819dba2cd35
signaturelock-open Commit is signed but in an unrecognized format.

std.zig.Zir: improve instruction tracking

The main change here is to partition tracked instructions found within a declaration. It's very unlikely that, for instance, a `struct { ... }` type declaration was intentionally turned into a reification or an anonymous initialization, so it makes sense to track things in a few different arrays. In particular, this fixes an issue where a `func` instruction could wrongly be mapped to something else if the types of function parameters changed. This would cause huge problems further down the pipeline; we expect that if a `declaration` is tracked, and it previously contained a `func`/`func_inferred`/`func_fancy`, then this instruction is either tracked to another `func`/`func_inferred`/`func_fancy` instruction, or is lost. Also, this commit takes the opportunity to rename the functions actually doing this logic. `Zir.findDecls` was a name that might have made sense at some point, but nowadays, it's definitely not finding declarations, and it's not *exclusively* finding type declarations. Instead, the point is to find instructions which we want to track; hence the new name, `Zir.findTrackable`. Lastly, a nice side effect of partitioning the output of `findTrackable` is that `Zir.declIterator` no longer needs to accept input instructions which aren't type declarations (e.g. `reify`, `func`).

2 files changed, 249 insertions(+), 197 deletions(-)

lib/std/zig/Zir.zig+188-176
...@@ -3615,145 +3615,155 @@ pub const DeclIterator = struct {...@@ -3615,145 +3615,155 @@ pub const DeclIterator = struct {
3615};3615};
36163616
3617pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {3617pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3618 const tags = zir.instructions.items(.tag);3618 const inst = zir.instructions.get(@intFromEnum(decl_inst));
3619 const datas = zir.instructions.items(.data);3619 assert(inst.tag == .extended);
3620 switch (tags[@intFromEnum(decl_inst)]) {3620 const extended = inst.data.extended;
3621 // Functions are allowed and yield no iterations.3621 switch (extended.opcode) {
3622 // This is because they are returned by `findDecls`.3622 .struct_decl => {
3623 .func, .func_inferred, .func_fancy => return .{3623 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3624 .extra_index = undefined,3624 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
3625 .decls_remaining = 0,3625 const captures_len = if (small.has_captures_len) captures_len: {
3626 .zir = zir,3626 const captures_len = zir.extra[extra_index];
3627 },3627 extra_index += 1;
36283628 break :captures_len captures_len;
3629 .extended => {3629 } else 0;
3630 const extended = datas[@intFromEnum(decl_inst)].extended;3630 extra_index += @intFromBool(small.has_fields_len);
3631 switch (extended.opcode) {3631 const decls_len = if (small.has_decls_len) decls_len: {
3632 // Reifications are allowed and yield no iterations.3632 const decls_len = zir.extra[extra_index];
3633 // This is because they are returned by `findDecls`.3633 extra_index += 1;
3634 .reify => return .{3634 break :decls_len decls_len;
3635 .extra_index = undefined,3635 } else 0;
3636 .decls_remaining = 0,3636
3637 .zir = zir,3637 extra_index += captures_len;
3638 },3638
3639 .struct_decl => {3639 if (small.has_backing_int) {
3640 const small: Inst.StructDecl.Small = @bitCast(extended.small);3640 const backing_int_body_len = zir.extra[extra_index];
3641 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);3641 extra_index += 1; // backing_int_body_len
3642 const captures_len = if (small.has_captures_len) captures_len: {3642 if (backing_int_body_len == 0) {
3643 const captures_len = zir.extra[extra_index];3643 extra_index += 1; // backing_int_ref
3644 extra_index += 1;3644 } else {
3645 break :captures_len captures_len;3645 extra_index += backing_int_body_len; // backing_int_body_inst
3646 } else 0;3646 }
3647 extra_index += @intFromBool(small.has_fields_len);3647 }
3648 const decls_len = if (small.has_decls_len) decls_len: {
3649 const decls_len = zir.extra[extra_index];
3650 extra_index += 1;
3651 break :decls_len decls_len;
3652 } else 0;
3653
3654 extra_index += captures_len;
3655
3656 if (small.has_backing_int) {
3657 const backing_int_body_len = zir.extra[extra_index];
3658 extra_index += 1; // backing_int_body_len
3659 if (backing_int_body_len == 0) {
3660 extra_index += 1; // backing_int_ref
3661 } else {
3662 extra_index += backing_int_body_len; // backing_int_body_inst
3663 }
3664 }
36653648
3666 return .{3649 return .{
3667 .extra_index = extra_index,3650 .extra_index = extra_index,
3668 .decls_remaining = decls_len,3651 .decls_remaining = decls_len,
3669 .zir = zir,3652 .zir = zir,
3670 };3653 };
3671 },3654 },
3672 .enum_decl => {3655 .enum_decl => {
3673 const small: Inst.EnumDecl.Small = @bitCast(extended.small);3656 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3674 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);3657 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
3675 extra_index += @intFromBool(small.has_tag_type);3658 extra_index += @intFromBool(small.has_tag_type);
3676 const captures_len = if (small.has_captures_len) captures_len: {3659 const captures_len = if (small.has_captures_len) captures_len: {
3677 const captures_len = zir.extra[extra_index];3660 const captures_len = zir.extra[extra_index];
3678 extra_index += 1;3661 extra_index += 1;
3679 break :captures_len captures_len;3662 break :captures_len captures_len;
3680 } else 0;3663 } else 0;
3681 extra_index += @intFromBool(small.has_body_len);3664 extra_index += @intFromBool(small.has_body_len);
3682 extra_index += @intFromBool(small.has_fields_len);3665 extra_index += @intFromBool(small.has_fields_len);
3683 const decls_len = if (small.has_decls_len) decls_len: {3666 const decls_len = if (small.has_decls_len) decls_len: {
3684 const decls_len = zir.extra[extra_index];3667 const decls_len = zir.extra[extra_index];
3685 extra_index += 1;3668 extra_index += 1;
3686 break :decls_len decls_len;3669 break :decls_len decls_len;
3687 } else 0;3670 } else 0;
36883671
3689 extra_index += captures_len;3672 extra_index += captures_len;
36903673
3691 return .{3674 return .{
3692 .extra_index = extra_index,3675 .extra_index = extra_index,
3693 .decls_remaining = decls_len,3676 .decls_remaining = decls_len,
3694 .zir = zir,3677 .zir = zir,
3695 };3678 };
3696 },3679 },
3697 .union_decl => {3680 .union_decl => {
3698 const small: Inst.UnionDecl.Small = @bitCast(extended.small);3681 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3699 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);3682 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
3700 extra_index += @intFromBool(small.has_tag_type);3683 extra_index += @intFromBool(small.has_tag_type);
3701 const captures_len = if (small.has_captures_len) captures_len: {3684 const captures_len = if (small.has_captures_len) captures_len: {
3702 const captures_len = zir.extra[extra_index];3685 const captures_len = zir.extra[extra_index];
3703 extra_index += 1;3686 extra_index += 1;
3704 break :captures_len captures_len;3687 break :captures_len captures_len;
3705 } else 0;3688 } else 0;
3706 extra_index += @intFromBool(small.has_body_len);3689 extra_index += @intFromBool(small.has_body_len);
3707 extra_index += @intFromBool(small.has_fields_len);3690 extra_index += @intFromBool(small.has_fields_len);
3708 const decls_len = if (small.has_decls_len) decls_len: {3691 const decls_len = if (small.has_decls_len) decls_len: {
3709 const decls_len = zir.extra[extra_index];3692 const decls_len = zir.extra[extra_index];
3710 extra_index += 1;3693 extra_index += 1;
3711 break :decls_len decls_len;3694 break :decls_len decls_len;
3712 } else 0;3695 } else 0;
37133696
3714 extra_index += captures_len;3697 extra_index += captures_len;
37153698
3716 return .{3699 return .{
3717 .extra_index = extra_index,3700 .extra_index = extra_index,
3718 .decls_remaining = decls_len,3701 .decls_remaining = decls_len,
3719 .zir = zir,3702 .zir = zir,
3720 };3703 };
3721 },3704 },
3722 .opaque_decl => {3705 .opaque_decl => {
3723 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);3706 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3724 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);3707 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
3725 const decls_len = if (small.has_decls_len) decls_len: {3708 const decls_len = if (small.has_decls_len) decls_len: {
3726 const decls_len = zir.extra[extra_index];3709 const decls_len = zir.extra[extra_index];
3727 extra_index += 1;3710 extra_index += 1;
3728 break :decls_len decls_len;3711 break :decls_len decls_len;
3729 } else 0;3712 } else 0;
3730 const captures_len = if (small.has_captures_len) captures_len: {3713 const captures_len = if (small.has_captures_len) captures_len: {
3731 const captures_len = zir.extra[extra_index];3714 const captures_len = zir.extra[extra_index];
3732 extra_index += 1;3715 extra_index += 1;
3733 break :captures_len captures_len;3716 break :captures_len captures_len;
3734 } else 0;3717 } else 0;
37353718
3736 extra_index += captures_len;3719 extra_index += captures_len;
37373720
3738 return .{3721 return .{
3739 .extra_index = extra_index,3722 .extra_index = extra_index,
3740 .decls_remaining = decls_len,3723 .decls_remaining = decls_len,
3741 .zir = zir,3724 .zir = zir,
3742 };3725 };
3743 },
3744 else => unreachable,
3745 }
3746 },3726 },
3747 else => unreachable,3727 else => unreachable,
3748 }3728 }
3749}3729}
37503730
3751/// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through3731/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
3752/// said type declarations' declarations; to find all declarations, call this function on the declarations3732/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping
3753/// of the discovered types recursively.3733/// more effective.
3754/// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result.3734pub const DeclContents = struct {
3755pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void {3735 /// This is a simple optional because ZIR guarantees that a `func`/`func_inferred`/`func_fancy` instruction
3756 list.clearRetainingCapacity();3736 /// can only occur once per `declaration`.
3737 func_decl: ?Inst.Index,
3738 explicit_types: std.ArrayListUnmanaged(Inst.Index),
3739 other: std.ArrayListUnmanaged(Inst.Index),
3740
3741 pub const init: DeclContents = .{
3742 .func_decl = null,
3743 .explicit_types = .empty,
3744 .other = .empty,
3745 };
3746
3747 pub fn clear(contents: *DeclContents) void {
3748 contents.func_decl = null;
3749 contents.explicit_types.clearRetainingCapacity();
3750 contents.other.clearRetainingCapacity();
3751 }
3752
3753 pub fn deinit(contents: *DeclContents, gpa: Allocator) void {
3754 contents.explicit_types.deinit(gpa);
3755 contents.other.deinit(gpa);
3756 }
3757};
3758
3759/// Find all tracked ZIR instructions, recursively, within a `declaration` instruction. Does not recurse through
3760/// nested declarations; to find all declarations, call this function recursively on the type declarations discovered
3761/// in `contents.explicit_types`.
3762///
3763/// This populates an `ArrayListUnmanaged` because an iterator would need to allocate memory anyway.
3764pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void {
3765 contents.clear();
3766
3757 const declaration, const extra_end = zir.getDeclaration(decl_inst);3767 const declaration, const extra_end = zir.getDeclaration(decl_inst);
3758 const bodies = declaration.getBodies(extra_end, zir);3768 const bodies = declaration.getBodies(extra_end, zir);
37593769
...@@ -3762,27 +3772,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In...@@ -3762,27 +3772,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In
3762 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;3772 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
3763 defer found_defers.deinit(gpa);3773 defer found_defers.deinit(gpa);
37643774
3765 try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body);3775 try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
3766 if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);3776 if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3767 if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);3777 if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3768 if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);3778 if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3769}3779}
37703780
3771/// Like `findDecls`, but only considers the `main_struct_inst` instruction. This may return more than3781/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
3772/// just that instruction because it will also traverse fields.3782/// just that instruction because it will also traverse fields.
3773pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void {3783pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void {
3774 list.clearRetainingCapacity();3784 contents.clear();
37753785
3776 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;3786 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
3777 defer found_defers.deinit(gpa);3787 defer found_defers.deinit(gpa);
37783788
3779 try zir.findDeclsInner(gpa, list, &found_defers, .main_struct_inst);3789 try zir.findTrackableInner(gpa, contents, &found_defers, .main_struct_inst);
3780}3790}
37813791
3782fn findDeclsInner(3792fn findTrackableInner(
3783 zir: Zir,3793 zir: Zir,
3784 gpa: Allocator,3794 gpa: Allocator,
3785 list: *std.ArrayListUnmanaged(Inst.Index),3795 contents: *DeclContents,
3786 defers: *std.AutoHashMapUnmanaged(u32, void),3796 defers: *std.AutoHashMapUnmanaged(u32, void),
3787 inst: Inst.Index,3797 inst: Inst.Index,
3788) Allocator.Error!void {3798) Allocator.Error!void {
...@@ -4026,7 +4036,7 @@ fn findDeclsInner(...@@ -4026,7 +4036,7 @@ fn findDeclsInner(
4026 .struct_init,4036 .struct_init,
4027 .struct_init_ref,4037 .struct_init_ref,
4028 .struct_init_anon,4038 .struct_init_anon,
4029 => return list.append(gpa, inst),4039 => return contents.other.append(gpa, inst),
40304040
4031 .extended => {4041 .extended => {
4032 const extended = datas[@intFromEnum(inst)].extended;4042 const extended = datas[@intFromEnum(inst)].extended;
...@@ -4093,15 +4103,15 @@ fn findDeclsInner(...@@ -4093,15 +4103,15 @@ fn findDeclsInner(
4093 .typeof_peer => {4103 .typeof_peer => {
4094 const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);4104 const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
4095 const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);4105 const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);
4096 try zir.findDeclsBody(gpa, list, defers, body);4106 try zir.findTrackableBody(gpa, contents, defers, body);
4097 },4107 },
40984108
4099 // Reifications and opaque declarations need tracking, but have no body.4109 // Reifications and opaque declarations need tracking, but have no body.
4100 .reify, .opaque_decl => return list.append(gpa, inst),4110 .reify, .opaque_decl => return contents.other.append(gpa, inst),
41014111
4102 // Struct declarations need tracking and have bodies.4112 // Struct declarations need tracking and have bodies.
4103 .struct_decl => {4113 .struct_decl => {
4104 try list.append(gpa, inst);4114 try contents.explicit_types.append(gpa, inst);
41054115
4106 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);4116 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
4107 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);4117 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
...@@ -4130,7 +4140,7 @@ fn findDeclsInner(...@@ -4130,7 +4140,7 @@ fn findDeclsInner(
4130 } else {4140 } else {
4131 const body = zir.bodySlice(extra_index, backing_int_body_len);4141 const body = zir.bodySlice(extra_index, backing_int_body_len);
4132 extra_index += backing_int_body_len;4142 extra_index += backing_int_body_len;
4133 try zir.findDeclsBody(gpa, list, defers, body);4143 try zir.findTrackableBody(gpa, contents, defers, body);
4134 }4144 }
4135 }4145 }
4136 extra_index += decls_len;4146 extra_index += decls_len;
...@@ -4186,12 +4196,12 @@ fn findDeclsInner(...@@ -4186,12 +4196,12 @@ fn findDeclsInner(
41864196
4187 // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.4197 // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
4188 const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);4198 const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);
4189 try zir.findDeclsBody(gpa, list, defers, merged_bodies);4199 try zir.findTrackableBody(gpa, contents, defers, merged_bodies);
4190 },4200 },
41914201
4192 // Union declarations need tracking and have a body.4202 // Union declarations need tracking and have a body.
4193 .union_decl => {4203 .union_decl => {
4194 try list.append(gpa, inst);4204 try contents.explicit_types.append(gpa, inst);
41954205
4196 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);4206 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
4197 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);4207 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
...@@ -4216,12 +4226,12 @@ fn findDeclsInner(...@@ -4216,12 +4226,12 @@ fn findDeclsInner(
4216 extra_index += captures_len;4226 extra_index += captures_len;
4217 extra_index += decls_len;4227 extra_index += decls_len;
4218 const body = zir.bodySlice(extra_index, body_len);4228 const body = zir.bodySlice(extra_index, body_len);
4219 try zir.findDeclsBody(gpa, list, defers, body);4229 try zir.findTrackableBody(gpa, contents, defers, body);
4220 },4230 },
42214231
4222 // Enum declarations need tracking and have a body.4232 // Enum declarations need tracking and have a body.
4223 .enum_decl => {4233 .enum_decl => {
4224 try list.append(gpa, inst);4234 try contents.explicit_types.append(gpa, inst);
42254235
4226 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);4236 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
4227 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);4237 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
...@@ -4246,7 +4256,7 @@ fn findDeclsInner(...@@ -4246,7 +4256,7 @@ fn findDeclsInner(
4246 extra_index += captures_len;4256 extra_index += captures_len;
4247 extra_index += decls_len;4257 extra_index += decls_len;
4248 const body = zir.bodySlice(extra_index, body_len);4258 const body = zir.bodySlice(extra_index, body_len);
4249 try zir.findDeclsBody(gpa, list, defers, body);4259 try zir.findTrackableBody(gpa, contents, defers, body);
4250 },4260 },
4251 }4261 }
4252 },4262 },
...@@ -4255,7 +4265,8 @@ fn findDeclsInner(...@@ -4255,7 +4265,8 @@ fn findDeclsInner(
4255 .func,4265 .func,
4256 .func_inferred,4266 .func_inferred,
4257 => {4267 => {
4258 try list.append(gpa, inst);4268 assert(contents.func_decl == null);
4269 contents.func_decl = inst;
42594270
4260 const inst_data = datas[@intFromEnum(inst)].pl_node;4271 const inst_data = datas[@intFromEnum(inst)].pl_node;
4261 const extra = zir.extraData(Inst.Func, inst_data.payload_index);4272 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
...@@ -4266,14 +4277,15 @@ fn findDeclsInner(...@@ -4266,14 +4277,15 @@ fn findDeclsInner(
4266 else => {4277 else => {
4267 const body = zir.bodySlice(extra_index, extra.data.ret_body_len);4278 const body = zir.bodySlice(extra_index, extra.data.ret_body_len);
4268 extra_index += body.len;4279 extra_index += body.len;
4269 try zir.findDeclsBody(gpa, list, defers, body);4280 try zir.findTrackableBody(gpa, contents, defers, body);
4270 },4281 },
4271 }4282 }
4272 const body = zir.bodySlice(extra_index, extra.data.body_len);4283 const body = zir.bodySlice(extra_index, extra.data.body_len);
4273 return zir.findDeclsBody(gpa, list, defers, body);4284 return zir.findTrackableBody(gpa, contents, defers, body);
4274 },4285 },
4275 .func_fancy => {4286 .func_fancy => {
4276 try list.append(gpa, inst);4287 assert(contents.func_decl == null);
4288 contents.func_decl = inst;
42774289
4278 const inst_data = datas[@intFromEnum(inst)].pl_node;4290 const inst_data = datas[@intFromEnum(inst)].pl_node;
4279 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);4291 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
...@@ -4284,7 +4296,7 @@ fn findDeclsInner(...@@ -4284,7 +4296,7 @@ fn findDeclsInner(
4284 const body_len = zir.extra[extra_index];4296 const body_len = zir.extra[extra_index];
4285 extra_index += 1;4297 extra_index += 1;
4286 const body = zir.bodySlice(extra_index, body_len);4298 const body = zir.bodySlice(extra_index, body_len);
4287 try zir.findDeclsBody(gpa, list, defers, body);4299 try zir.findTrackableBody(gpa, contents, defers, body);
4288 extra_index += body.len;4300 extra_index += body.len;
4289 } else if (extra.data.bits.has_align_ref) {4301 } else if (extra.data.bits.has_align_ref) {
4290 extra_index += 1;4302 extra_index += 1;
...@@ -4294,7 +4306,7 @@ fn findDeclsInner(...@@ -4294,7 +4306,7 @@ fn findDeclsInner(
4294 const body_len = zir.extra[extra_index];4306 const body_len = zir.extra[extra_index];
4295 extra_index += 1;4307 extra_index += 1;
4296 const body = zir.bodySlice(extra_index, body_len);4308 const body = zir.bodySlice(extra_index, body_len);
4297 try zir.findDeclsBody(gpa, list, defers, body);4309 try zir.findTrackableBody(gpa, contents, defers, body);
4298 extra_index += body.len;4310 extra_index += body.len;
4299 } else if (extra.data.bits.has_addrspace_ref) {4311 } else if (extra.data.bits.has_addrspace_ref) {
4300 extra_index += 1;4312 extra_index += 1;
...@@ -4304,7 +4316,7 @@ fn findDeclsInner(...@@ -4304,7 +4316,7 @@ fn findDeclsInner(
4304 const body_len = zir.extra[extra_index];4316 const body_len = zir.extra[extra_index];
4305 extra_index += 1;4317 extra_index += 1;
4306 const body = zir.bodySlice(extra_index, body_len);4318 const body = zir.bodySlice(extra_index, body_len);
4307 try zir.findDeclsBody(gpa, list, defers, body);4319 try zir.findTrackableBody(gpa, contents, defers, body);
4308 extra_index += body.len;4320 extra_index += body.len;
4309 } else if (extra.data.bits.has_section_ref) {4321 } else if (extra.data.bits.has_section_ref) {
4310 extra_index += 1;4322 extra_index += 1;
...@@ -4314,7 +4326,7 @@ fn findDeclsInner(...@@ -4314,7 +4326,7 @@ fn findDeclsInner(
4314 const body_len = zir.extra[extra_index];4326 const body_len = zir.extra[extra_index];
4315 extra_index += 1;4327 extra_index += 1;
4316 const body = zir.bodySlice(extra_index, body_len);4328 const body = zir.bodySlice(extra_index, body_len);
4317 try zir.findDeclsBody(gpa, list, defers, body);4329 try zir.findTrackableBody(gpa, contents, defers, body);
4318 extra_index += body.len;4330 extra_index += body.len;
4319 } else if (extra.data.bits.has_cc_ref) {4331 } else if (extra.data.bits.has_cc_ref) {
4320 extra_index += 1;4332 extra_index += 1;
...@@ -4324,7 +4336,7 @@ fn findDeclsInner(...@@ -4324,7 +4336,7 @@ fn findDeclsInner(
4324 const body_len = zir.extra[extra_index];4336 const body_len = zir.extra[extra_index];
4325 extra_index += 1;4337 extra_index += 1;
4326 const body = zir.bodySlice(extra_index, body_len);4338 const body = zir.bodySlice(extra_index, body_len);
4327 try zir.findDeclsBody(gpa, list, defers, body);4339 try zir.findTrackableBody(gpa, contents, defers, body);
4328 extra_index += body.len;4340 extra_index += body.len;
4329 } else if (extra.data.bits.has_ret_ty_ref) {4341 } else if (extra.data.bits.has_ret_ty_ref) {
4330 extra_index += 1;4342 extra_index += 1;
...@@ -4333,7 +4345,7 @@ fn findDeclsInner(...@@ -4333,7 +4345,7 @@ fn findDeclsInner(
4333 extra_index += @intFromBool(extra.data.bits.has_any_noalias);4345 extra_index += @intFromBool(extra.data.bits.has_any_noalias);
43344346
4335 const body = zir.bodySlice(extra_index, extra.data.body_len);4347 const body = zir.bodySlice(extra_index, extra.data.body_len);
4336 return zir.findDeclsBody(gpa, list, defers, body);4348 return zir.findTrackableBody(gpa, contents, defers, body);
4337 },4349 },
43384350
4339 // Block instructions, recurse over the bodies.4351 // Block instructions, recurse over the bodies.
...@@ -4348,24 +4360,24 @@ fn findDeclsInner(...@@ -4348,24 +4360,24 @@ fn findDeclsInner(
4348 const inst_data = datas[@intFromEnum(inst)].pl_node;4360 const inst_data = datas[@intFromEnum(inst)].pl_node;
4349 const extra = zir.extraData(Inst.Block, inst_data.payload_index);4361 const extra = zir.extraData(Inst.Block, inst_data.payload_index);
4350 const body = zir.bodySlice(extra.end, extra.data.body_len);4362 const body = zir.bodySlice(extra.end, extra.data.body_len);
4351 return zir.findDeclsBody(gpa, list, defers, body);4363 return zir.findTrackableBody(gpa, contents, defers, body);
4352 },4364 },
4353 .condbr, .condbr_inline => {4365 .condbr, .condbr_inline => {
4354 const inst_data = datas[@intFromEnum(inst)].pl_node;4366 const inst_data = datas[@intFromEnum(inst)].pl_node;
4355 const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);4367 const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);
4356 const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);4368 const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);
4357 const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);4369 const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
4358 try zir.findDeclsBody(gpa, list, defers, then_body);4370 try zir.findTrackableBody(gpa, contents, defers, then_body);
4359 try zir.findDeclsBody(gpa, list, defers, else_body);4371 try zir.findTrackableBody(gpa, contents, defers, else_body);
4360 },4372 },
4361 .@"try", .try_ptr => {4373 .@"try", .try_ptr => {
4362 const inst_data = datas[@intFromEnum(inst)].pl_node;4374 const inst_data = datas[@intFromEnum(inst)].pl_node;
4363 const extra = zir.extraData(Inst.Try, inst_data.payload_index);4375 const extra = zir.extraData(Inst.Try, inst_data.payload_index);
4364 const body = zir.bodySlice(extra.end, extra.data.body_len);4376 const body = zir.bodySlice(extra.end, extra.data.body_len);
4365 try zir.findDeclsBody(gpa, list, defers, body);4377 try zir.findTrackableBody(gpa, contents, defers, body);
4366 },4378 },
4367 .switch_block, .switch_block_ref => return zir.findDeclsSwitch(gpa, list, defers, inst, .normal),4379 .switch_block, .switch_block_ref => return zir.findTrackableSwitch(gpa, contents, defers, inst, .normal),
4368 .switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union),4380 .switch_block_err_union => return zir.findTrackableSwitch(gpa, contents, defers, inst, .err_union),
43694381
4370 .suspend_block => @panic("TODO iterate suspend block"),4382 .suspend_block => @panic("TODO iterate suspend block"),
43714383
...@@ -4373,7 +4385,7 @@ fn findDeclsInner(...@@ -4373,7 +4385,7 @@ fn findDeclsInner(
4373 const inst_data = datas[@intFromEnum(inst)].pl_tok;4385 const inst_data = datas[@intFromEnum(inst)].pl_tok;
4374 const extra = zir.extraData(Inst.Param, inst_data.payload_index);4386 const extra = zir.extraData(Inst.Param, inst_data.payload_index);
4375 const body = zir.bodySlice(extra.end, extra.data.body_len);4387 const body = zir.bodySlice(extra.end, extra.data.body_len);
4376 try zir.findDeclsBody(gpa, list, defers, body);4388 try zir.findTrackableBody(gpa, contents, defers, body);
4377 },4389 },
43784390
4379 inline .call, .field_call => |tag| {4391 inline .call, .field_call => |tag| {
...@@ -4389,7 +4401,7 @@ fn findDeclsInner(...@@ -4389,7 +4401,7 @@ fn findDeclsInner(
4389 const first_arg_start_off = args_len;4401 const first_arg_start_off = args_len;
4390 const final_arg_end_off = zir.extra[extra.end + args_len - 1];4402 const final_arg_end_off = zir.extra[extra.end + args_len - 1];
4391 const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);4403 const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);
4392 try zir.findDeclsBody(gpa, list, defers, args_body);4404 try zir.findTrackableBody(gpa, contents, defers, args_body);
4393 }4405 }
4394 },4406 },
4395 .@"defer" => {4407 .@"defer" => {
...@@ -4397,7 +4409,7 @@ fn findDeclsInner(...@@ -4397,7 +4409,7 @@ fn findDeclsInner(
4397 const gop = try defers.getOrPut(gpa, inst_data.index);4409 const gop = try defers.getOrPut(gpa, inst_data.index);
4398 if (!gop.found_existing) {4410 if (!gop.found_existing) {
4399 const body = zir.bodySlice(inst_data.index, inst_data.len);4411 const body = zir.bodySlice(inst_data.index, inst_data.len);
4400 try zir.findDeclsBody(gpa, list, defers, body);4412 try zir.findTrackableBody(gpa, contents, defers, body);
4401 }4413 }
4402 },4414 },
4403 .defer_err_code => {4415 .defer_err_code => {
...@@ -4406,16 +4418,16 @@ fn findDeclsInner(...@@ -4406,16 +4418,16 @@ fn findDeclsInner(
4406 const gop = try defers.getOrPut(gpa, extra.index);4418 const gop = try defers.getOrPut(gpa, extra.index);
4407 if (!gop.found_existing) {4419 if (!gop.found_existing) {
4408 const body = zir.bodySlice(extra.index, extra.len);4420 const body = zir.bodySlice(extra.index, extra.len);
4409 try zir.findDeclsBody(gpa, list, defers, body);4421 try zir.findTrackableBody(gpa, contents, defers, body);
4410 }4422 }
4411 },4423 },
4412 }4424 }
4413}4425}
44144426
4415fn findDeclsSwitch(4427fn findTrackableSwitch(
4416 zir: Zir,4428 zir: Zir,
4417 gpa: Allocator,4429 gpa: Allocator,
4418 list: *std.ArrayListUnmanaged(Inst.Index),4430 contents: *DeclContents,
4419 defers: *std.AutoHashMapUnmanaged(u32, void),4431 defers: *std.AutoHashMapUnmanaged(u32, void),
4420 inst: Inst.Index,4432 inst: Inst.Index,
4421 /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.4433 /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.
...@@ -4451,7 +4463,7 @@ fn findDeclsSwitch(...@@ -4451,7 +4463,7 @@ fn findDeclsSwitch(
4451 const body = zir.bodySlice(extra_index, prong_info.body_len);4463 const body = zir.bodySlice(extra_index, prong_info.body_len);
4452 extra_index += body.len;4464 extra_index += body.len;
44534465
4454 try zir.findDeclsBody(gpa, list, defers, body);4466 try zir.findTrackableBody(gpa, contents, defers, body);
44554467
4456 break :has_special extra.data.bits.has_else;4468 break :has_special extra.data.bits.has_else;
4457 },4469 },
...@@ -4463,7 +4475,7 @@ fn findDeclsSwitch(...@@ -4463,7 +4475,7 @@ fn findDeclsSwitch(
4463 const body = zir.bodySlice(extra_index, prong_info.body_len);4475 const body = zir.bodySlice(extra_index, prong_info.body_len);
4464 extra_index += body.len;4476 extra_index += body.len;
44654477
4466 try zir.findDeclsBody(gpa, list, defers, body);4478 try zir.findTrackableBody(gpa, contents, defers, body);
4467 }4479 }
44684480
4469 {4481 {
...@@ -4475,7 +4487,7 @@ fn findDeclsSwitch(...@@ -4475,7 +4487,7 @@ fn findDeclsSwitch(
4475 const body = zir.bodySlice(extra_index, prong_info.body_len);4487 const body = zir.bodySlice(extra_index, prong_info.body_len);
4476 extra_index += body.len;4488 extra_index += body.len;
44774489
4478 try zir.findDeclsBody(gpa, list, defers, body);4490 try zir.findTrackableBody(gpa, contents, defers, body);
4479 }4491 }
4480 }4492 }
4481 {4493 {
...@@ -4492,20 +4504,20 @@ fn findDeclsSwitch(...@@ -4492,20 +4504,20 @@ fn findDeclsSwitch(
4492 const body = zir.bodySlice(extra_index, prong_info.body_len);4504 const body = zir.bodySlice(extra_index, prong_info.body_len);
4493 extra_index += body.len;4505 extra_index += body.len;
44944506
4495 try zir.findDeclsBody(gpa, list, defers, body);4507 try zir.findTrackableBody(gpa, contents, defers, body);
4496 }4508 }
4497 }4509 }
4498}4510}
44994511
4500fn findDeclsBody(4512fn findTrackableBody(
4501 zir: Zir,4513 zir: Zir,
4502 gpa: Allocator,4514 gpa: Allocator,
4503 list: *std.ArrayListUnmanaged(Inst.Index),4515 contents: *DeclContents,
4504 defers: *std.AutoHashMapUnmanaged(u32, void),4516 defers: *std.AutoHashMapUnmanaged(u32, void),
4505 body: []const Inst.Index,4517 body: []const Inst.Index,
4506) Allocator.Error!void {4518) Allocator.Error!void {
4507 for (body) |member| {4519 for (body) |member| {
4508 try zir.findDeclsInner(gpa, list, defers, member);4520 try zir.findTrackableInner(gpa, contents, defers, member);
4509 }4521 }
4510}4522}
45114523
src/Zcu.zig+61-21
...@@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(...@@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(
2593 defer match_stack.deinit(gpa);2593 defer match_stack.deinit(gpa);
25942594
2595 // Used as temporary buffers for namespace declaration instructions2595 // Used as temporary buffers for namespace declaration instructions
2596 var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;2596 var old_contents: Zir.DeclContents = .init;
2597 defer old_decls.deinit(gpa);2597 defer old_contents.deinit(gpa);
2598 var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;2598 var new_contents: Zir.DeclContents = .init;
2599 defer new_decls.deinit(gpa);2599 defer new_contents.deinit(gpa);
26002600
2601 // Map the main struct inst (and anything in its fields)2601 // Map the main struct inst (and anything in its fields)
2602 {2602 {
2603 try old_zir.findDeclsRoot(gpa, &old_decls);2603 try old_zir.findTrackableRoot(gpa, &old_contents);
2604 try new_zir.findDeclsRoot(gpa, &new_decls);2604 try new_zir.findTrackableRoot(gpa, &new_contents);
26052605
2606 assert(old_decls.items[0] == .main_struct_inst);2606 assert(old_contents.explicit_types.items[0] == .main_struct_inst);
2607 assert(new_decls.items[0] == .main_struct_inst);2607 assert(new_contents.explicit_types.items[0] == .main_struct_inst);
26082608
2609 // We don't have any smart way of matching up these type declarations, so we always2609 assert(old_contents.func_decl == null);
2610 // correlate them based on source order.2610 assert(new_contents.func_decl == null);
2611 const n = @min(old_decls.items.len, new_decls.items.len);2611
2612 try match_stack.ensureUnusedCapacity(gpa, n);2612 // We don't have any smart way of matching up these instructions, so we correlate them based on source order
2613 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {2613 // in their respective arrays.
2614
2615 const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
2616 try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
2617 for (
2618 old_contents.explicit_types.items[0..num_explicit_types],
2619 new_contents.explicit_types.items[0..num_explicit_types],
2620 ) |old_inst, new_inst| {
2621 // Here we use `match_stack`, so that we will recursively consider declarations on these types.
2614 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });2622 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
2615 }2623 }
2624
2625 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
2626 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
2627 for (
2628 old_contents.other.items[0..num_other],
2629 new_contents.other.items[0..num_other],
2630 ) |old_inst, new_inst| {
2631 // These instructions don't have declarations, so we just modify `inst_map` directly.
2632 inst_map.putAssumeCapacity(old_inst, new_inst);
2633 }
2616 }2634 }
26172635
2618 while (match_stack.popOrNull()) |match_item| {2636 while (match_stack.popOrNull()) |match_item| {
...@@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(...@@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(
2700 // Match the `declaration` instruction2718 // Match the `declaration` instruction
2701 try inst_map.put(gpa, old_decl_inst, new_decl_inst);2719 try inst_map.put(gpa, old_decl_inst, new_decl_inst);
27022720
2703 // Find container type declarations within this declaration2721 // Find trackable instructions within this declaration
2704 try old_zir.findDecls(gpa, &old_decls, old_decl_inst);2722 try old_zir.findTrackable(gpa, &old_contents, old_decl_inst);
2705 try new_zir.findDecls(gpa, &new_decls, new_decl_inst);2723 try new_zir.findTrackable(gpa, &new_contents, new_decl_inst);
2724
2725 // We don't have any smart way of matching up these instructions, so we correlate them based on source order
2726 // in their respective arrays.
27062727
2707 // We don't have any smart way of matching up these type declarations, so we always2728 const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
2708 // correlate them based on source order.2729 try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
2709 const n = @min(old_decls.items.len, new_decls.items.len);2730 for (
2710 try match_stack.ensureUnusedCapacity(gpa, n);2731 old_contents.explicit_types.items[0..num_explicit_types],
2711 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {2732 new_contents.explicit_types.items[0..num_explicit_types],
2733 ) |old_inst, new_inst| {
2734 // Here we use `match_stack`, so that we will recursively consider declarations on these types.
2712 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });2735 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
2713 }2736 }
2737
2738 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
2739 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
2740 for (
2741 old_contents.other.items[0..num_other],
2742 new_contents.other.items[0..num_other],
2743 ) |old_inst, new_inst| {
2744 // These instructions don't have declarations, so we just modify `inst_map` directly.
2745 inst_map.putAssumeCapacity(old_inst, new_inst);
2746 }
2747
2748 if (old_contents.func_decl) |old_func_inst| {
2749 if (new_contents.func_decl) |new_func_inst| {
2750 // There are no declarations on a function either, so again, we just directly add it to `inst_map`.
2751 try inst_map.put(gpa, old_func_inst, new_func_inst);
2752 }
2753 }
2714 }2754 }
2715 }2755 }
2716}2756}