aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2024-12-05 18:03:09 +0000
committermlugg <mlugg@mlugg.co.uk>2024-12-05 19:58:42 +0000
commit8f849684f46ad0835bd9591f420e49e212880cb2 (patch)
treeebf5d639609a744108f4e9a356d0074c25a640d9 /src
parent7f3211a101d8763ec5f0009b219f6819dba2cd35 (diff)
downloadzig-8f849684f46ad0835bd9591f420e49e212880cb2.tar.gz
zig-8f849684f46ad0835bd9591f420e49e212880cb2.zip
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`).
Diffstat (limited to 'src')
-rw-r--r--src/Zcu.zig82
1 files changed, 61 insertions, 21 deletions
diff --git a/src/Zcu.zig b/src/Zcu.zig
index d03eb4cc9a..bb2dc2a8df 100644
--- a/src/Zcu.zig
+++ b/src/Zcu.zig
@@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(
defer match_stack.deinit(gpa);
// Used as temporary buffers for namespace declaration instructions
- var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
- defer old_decls.deinit(gpa);
- var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
- defer new_decls.deinit(gpa);
+ var old_contents: Zir.DeclContents = .init;
+ defer old_contents.deinit(gpa);
+ var new_contents: Zir.DeclContents = .init;
+ defer new_contents.deinit(gpa);
// Map the main struct inst (and anything in its fields)
{
- try old_zir.findDeclsRoot(gpa, &old_decls);
- try new_zir.findDeclsRoot(gpa, &new_decls);
+ try old_zir.findTrackableRoot(gpa, &old_contents);
+ try new_zir.findTrackableRoot(gpa, &new_contents);
- assert(old_decls.items[0] == .main_struct_inst);
- assert(new_decls.items[0] == .main_struct_inst);
+ assert(old_contents.explicit_types.items[0] == .main_struct_inst);
+ assert(new_contents.explicit_types.items[0] == .main_struct_inst);
- // We don't have any smart way of matching up these type declarations, so we always
- // correlate them based on source order.
- const n = @min(old_decls.items.len, new_decls.items.len);
- try match_stack.ensureUnusedCapacity(gpa, n);
- for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
+ assert(old_contents.func_decl == null);
+ assert(new_contents.func_decl == null);
+
+ // We don't have any smart way of matching up these instructions, so we correlate them based on source order
+ // in their respective arrays.
+
+ const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
+ try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
+ for (
+ old_contents.explicit_types.items[0..num_explicit_types],
+ new_contents.explicit_types.items[0..num_explicit_types],
+ ) |old_inst, new_inst| {
+ // Here we use `match_stack`, so that we will recursively consider declarations on these types.
match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
}
+
+ const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
+ try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
+ for (
+ old_contents.other.items[0..num_other],
+ new_contents.other.items[0..num_other],
+ ) |old_inst, new_inst| {
+ // These instructions don't have declarations, so we just modify `inst_map` directly.
+ inst_map.putAssumeCapacity(old_inst, new_inst);
+ }
}
while (match_stack.popOrNull()) |match_item| {
@@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(
// Match the `declaration` instruction
try inst_map.put(gpa, old_decl_inst, new_decl_inst);
- // Find container type declarations within this declaration
- try old_zir.findDecls(gpa, &old_decls, old_decl_inst);
- try new_zir.findDecls(gpa, &new_decls, new_decl_inst);
+ // Find trackable instructions within this declaration
+ try old_zir.findTrackable(gpa, &old_contents, old_decl_inst);
+ try new_zir.findTrackable(gpa, &new_contents, new_decl_inst);
+
+ // We don't have any smart way of matching up these instructions, so we correlate them based on source order
+ // in their respective arrays.
- // We don't have any smart way of matching up these type declarations, so we always
- // correlate them based on source order.
- const n = @min(old_decls.items.len, new_decls.items.len);
- try match_stack.ensureUnusedCapacity(gpa, n);
- for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
+ const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
+ try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
+ for (
+ old_contents.explicit_types.items[0..num_explicit_types],
+ new_contents.explicit_types.items[0..num_explicit_types],
+ ) |old_inst, new_inst| {
+ // Here we use `match_stack`, so that we will recursively consider declarations on these types.
match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
}
+
+ const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
+ try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
+ for (
+ old_contents.other.items[0..num_other],
+ new_contents.other.items[0..num_other],
+ ) |old_inst, new_inst| {
+ // These instructions don't have declarations, so we just modify `inst_map` directly.
+ inst_map.putAssumeCapacity(old_inst, new_inst);
+ }
+
+ if (old_contents.func_decl) |old_func_inst| {
+ if (new_contents.func_decl) |new_func_inst| {
+ // There are no declarations on a function either, so again, we just directly add it to `inst_map`.
+ try inst_map.put(gpa, old_func_inst, new_func_inst);
+ }
+ }
}
}
}