authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-04 20:27:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-04 20:27:15-07:00
loga9002156a09130038abcf418609fea725ce71bc2
treec84f00b3dddfa5302f516ee523a6fa1d9767dcfa
parentc4dddcbadbcce587e0bd8593636373712294b5b2

zig reduce: add reduction for removing var decls


2 files changed, 62 insertions(+), 17 deletions(-)

src/reduce.zig+6
......@@ -321,6 +321,12 @@ fn transformationsToFixups(
321321 .delete_node => |decl_node| {
322322 try fixups.omit_nodes.put(gpa, decl_node, {});
323323 },
324 .delete_var_decl => |delete_var_decl| {
325 try fixups.omit_nodes.put(gpa, delete_var_decl.var_decl_node, {});
326 for (delete_var_decl.references.items) |ident_node| {
327 try fixups.replace_nodes.put(gpa, ident_node, "undefined");
328 }
329 },
324330 .replace_with_undef => |node| {
325331 try fixups.replace_nodes.put(gpa, node, "undefined");
326332 },
src/reduce/Walk.zig+56-17
......@@ -8,6 +8,7 @@ ast: *const Ast,
88transformations: *std.ArrayList(Transformation),
99unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index),
1010in_scope_names: std.StringArrayHashMapUnmanaged(u32),
11replace_names: std.StringArrayHashMapUnmanaged(u32),
1112gpa: std.mem.Allocator,
1213arena: std.mem.Allocator,
1314
......@@ -17,6 +18,13 @@ pub const Transformation = union(enum) {
1718 gut_function: Ast.Node.Index,
1819 /// Omit a global declaration.
1920 delete_node: Ast.Node.Index,
21 /// Delete a local variable declaration and replace all of its references
22 /// with `undefined`.
23 delete_var_decl: struct {
24 var_decl_node: Ast.Node.Index,
25 /// Identifier nodes that reference the variable.
26 references: std.ArrayListUnmanaged(Ast.Node.Index),
27 },
2028 /// Replace an expression with `undefined`.
2129 replace_with_undef: Ast.Node.Index,
2230 /// Replace an `@import` with the imported file contents wrapped in a struct.
......@@ -48,10 +56,12 @@ pub fn findTransformations(
4856 .arena = arena,
4957 .unreferenced_globals = .{},
5058 .in_scope_names = .{},
59 .replace_names = .{},
5160 };
5261 defer {
5362 walk.unreferenced_globals.deinit(walk.gpa);
5463 walk.in_scope_names.deinit(walk.gpa);
64 walk.replace_names.deinit(walk.gpa);
5565 }
5666
5767 try walkMembers(&walk, walk.ast.rootDecls());
......@@ -133,6 +143,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void {
133143 try walkExpression(w, fn_proto);
134144 const body_node = datas[decl].rhs;
135145 if (!isFnBodyGutted(ast, body_node)) {
146 w.replace_names.clearRetainingCapacity();
136147 try w.transformations.append(.{ .gut_function = decl });
137148 try walkExpression(w, body_node);
138149 }
......@@ -187,7 +198,15 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
187198 const node_tags = ast.nodes.items(.tag);
188199 const datas = ast.nodes.items(.data);
189200 switch (node_tags[node]) {
190 .identifier => try walkIdentifier(w, main_tokens[node]),
201 .identifier => {
202 const name_ident = main_tokens[node];
203 assert(token_tags[name_ident] == .identifier);
204 const name_bytes = ast.tokenSlice(name_ident);
205 _ = w.unreferenced_globals.swapRemove(name_bytes);
206 if (w.replace_names.get(name_bytes)) |index| {
207 try w.transformations.items[index].delete_var_decl.references.append(w.arena, node);
208 }
209 },
191210
192211 .number_literal,
193212 .char_literal,
......@@ -646,13 +665,31 @@ fn walkBlock(
646665 .local_var_decl,
647666 .simple_var_decl,
648667 .aligned_var_decl,
649 => try walkLocalVarDecl(w, ast.fullVarDecl(stmt).?),
668 => {
669 const var_decl = ast.fullVarDecl(stmt).?;
670 if (var_decl.ast.init_node != 0 and
671 isUndefinedIdent(w.ast, var_decl.ast.init_node))
672 {
673 try w.transformations.append(.{ .delete_var_decl = .{
674 .var_decl_node = stmt,
675 .references = .{},
676 } });
677 const name_tok = var_decl.ast.mut_token + 1;
678 const name_bytes = ast.tokenSlice(name_tok);
679 try w.replace_names.put(w.gpa, name_bytes, @intCast(w.transformations.items.len - 1));
680 } else {
681 try walkLocalVarDecl(w, var_decl);
682 }
683 },
650684
651685 else => {
652 // Don't try to remove `_ = foo;` discards; those are handled separately.
653686 switch (categorizeStmt(ast, stmt)) {
687 // Don't try to remove `_ = foo;` discards; those are handled separately.
654688 .discard_identifier => {},
655 else => try w.transformations.append(.{ .delete_node = stmt }),
689 // definitely try to remove `_ = undefined;` though.
690 .discard_undefined, .trap_call, .other => {
691 try w.transformations.append(.{ .delete_node = stmt });
692 },
656693 }
657694 try walkExpression(w, stmt);
658695 },
......@@ -905,6 +942,7 @@ fn isFnBodyGutted(ast: *const Ast, body_node: Ast.Node.Index) bool {
905942}
906943
907944const StmtCategory = enum {
945 discard_undefined,
908946 discard_identifier,
909947 trap_call,
910948 other,
......@@ -930,8 +968,14 @@ fn categorizeStmt(ast: *const Ast, stmt: Ast.Node.Index) StmtCategory {
930968 },
931969 .assign => {
932970 const infix = datas[stmt];
933 if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier)
934 return .discard_identifier;
971 if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier) {
972 const name_bytes = ast.tokenSlice(main_tokens[infix.rhs]);
973 if (std.mem.eql(u8, name_bytes, "undefined")) {
974 return .discard_undefined;
975 } else {
976 return .discard_identifier;
977 }
978 }
935979 return .other;
936980 },
937981 else => return .other,
......@@ -951,26 +995,21 @@ fn categorizeBuiltinCall(
951995}
952996
953997fn isDiscardIdent(ast: *const Ast, node: Ast.Node.Index) bool {
954 const node_tags = ast.nodes.items(.tag);
955 const main_tokens = ast.nodes.items(.main_token);
956 switch (node_tags[node]) {
957 .identifier => {
958 const token_index = main_tokens[node];
959 const name_bytes = ast.tokenSlice(token_index);
960 return std.mem.eql(u8, name_bytes, "_");
961 },
962 else => return false,
963 }
998 return isMatchingIdent(ast, node, "_");
964999}
9651000
9661001fn isUndefinedIdent(ast: *const Ast, node: Ast.Node.Index) bool {
1002 return isMatchingIdent(ast, node, "undefined");
1003}
1004
1005fn isMatchingIdent(ast: *const Ast, node: Ast.Node.Index, string: []const u8) bool {
9671006 const node_tags = ast.nodes.items(.tag);
9681007 const main_tokens = ast.nodes.items(.main_token);
9691008 switch (node_tags[node]) {
9701009 .identifier => {
9711010 const token_index = main_tokens[node];
9721011 const name_bytes = ast.tokenSlice(token_index);
973 return std.mem.eql(u8, name_bytes, "undefined");
1012 return std.mem.eql(u8, name_bytes, string);
9741013 },
9751014 else => return false,
9761015 }