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(...@@ -321,6 +321,12 @@ fn transformationsToFixups(
321 .delete_node => |decl_node| {321 .delete_node => |decl_node| {
322 try fixups.omit_nodes.put(gpa, decl_node, {});322 try fixups.omit_nodes.put(gpa, decl_node, {});
323 },323 },
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 },
324 .replace_with_undef => |node| {330 .replace_with_undef => |node| {
325 try fixups.replace_nodes.put(gpa, node, "undefined");331 try fixups.replace_nodes.put(gpa, node, "undefined");
326 },332 },
src/reduce/Walk.zig+56-17
...@@ -8,6 +8,7 @@ ast: *const Ast,...@@ -8,6 +8,7 @@ ast: *const Ast,
8transformations: *std.ArrayList(Transformation),8transformations: *std.ArrayList(Transformation),
9unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index),9unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index),
10in_scope_names: std.StringArrayHashMapUnmanaged(u32),10in_scope_names: std.StringArrayHashMapUnmanaged(u32),
11replace_names: std.StringArrayHashMapUnmanaged(u32),
11gpa: std.mem.Allocator,12gpa: std.mem.Allocator,
12arena: std.mem.Allocator,13arena: std.mem.Allocator,
1314
...@@ -17,6 +18,13 @@ pub const Transformation = union(enum) {...@@ -17,6 +18,13 @@ pub const Transformation = union(enum) {
17 gut_function: Ast.Node.Index,18 gut_function: Ast.Node.Index,
18 /// Omit a global declaration.19 /// Omit a global declaration.
19 delete_node: Ast.Node.Index,20 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 },
20 /// Replace an expression with `undefined`.28 /// Replace an expression with `undefined`.
21 replace_with_undef: Ast.Node.Index,29 replace_with_undef: Ast.Node.Index,
22 /// Replace an `@import` with the imported file contents wrapped in a struct.30 /// Replace an `@import` with the imported file contents wrapped in a struct.
...@@ -48,10 +56,12 @@ pub fn findTransformations(...@@ -48,10 +56,12 @@ pub fn findTransformations(
48 .arena = arena,56 .arena = arena,
49 .unreferenced_globals = .{},57 .unreferenced_globals = .{},
50 .in_scope_names = .{},58 .in_scope_names = .{},
59 .replace_names = .{},
51 };60 };
52 defer {61 defer {
53 walk.unreferenced_globals.deinit(walk.gpa);62 walk.unreferenced_globals.deinit(walk.gpa);
54 walk.in_scope_names.deinit(walk.gpa);63 walk.in_scope_names.deinit(walk.gpa);
64 walk.replace_names.deinit(walk.gpa);
55 }65 }
5666
57 try walkMembers(&walk, walk.ast.rootDecls());67 try walkMembers(&walk, walk.ast.rootDecls());
...@@ -133,6 +143,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void {...@@ -133,6 +143,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void {
133 try walkExpression(w, fn_proto);143 try walkExpression(w, fn_proto);
134 const body_node = datas[decl].rhs;144 const body_node = datas[decl].rhs;
135 if (!isFnBodyGutted(ast, body_node)) {145 if (!isFnBodyGutted(ast, body_node)) {
146 w.replace_names.clearRetainingCapacity();
136 try w.transformations.append(.{ .gut_function = decl });147 try w.transformations.append(.{ .gut_function = decl });
137 try walkExpression(w, body_node);148 try walkExpression(w, body_node);
138 }149 }
...@@ -187,7 +198,15 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {...@@ -187,7 +198,15 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
187 const node_tags = ast.nodes.items(.tag);198 const node_tags = ast.nodes.items(.tag);
188 const datas = ast.nodes.items(.data);199 const datas = ast.nodes.items(.data);
189 switch (node_tags[node]) {200 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
192 .number_literal,211 .number_literal,
193 .char_literal,212 .char_literal,
...@@ -646,13 +665,31 @@ fn walkBlock(...@@ -646,13 +665,31 @@ fn walkBlock(
646 .local_var_decl,665 .local_var_decl,
647 .simple_var_decl,666 .simple_var_decl,
648 .aligned_var_decl,667 .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
651 else => {685 else => {
652 // Don't try to remove `_ = foo;` discards; those are handled separately.
653 switch (categorizeStmt(ast, stmt)) {686 switch (categorizeStmt(ast, stmt)) {
687 // Don't try to remove `_ = foo;` discards; those are handled separately.
654 .discard_identifier => {},688 .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 },
656 }693 }
657 try walkExpression(w, stmt);694 try walkExpression(w, stmt);
658 },695 },
...@@ -905,6 +942,7 @@ fn isFnBodyGutted(ast: *const Ast, body_node: Ast.Node.Index) bool {...@@ -905,6 +942,7 @@ fn isFnBodyGutted(ast: *const Ast, body_node: Ast.Node.Index) bool {
905}942}
906943
907const StmtCategory = enum {944const StmtCategory = enum {
945 discard_undefined,
908 discard_identifier,946 discard_identifier,
909 trap_call,947 trap_call,
910 other,948 other,
...@@ -930,8 +968,14 @@ fn categorizeStmt(ast: *const Ast, stmt: Ast.Node.Index) StmtCategory {...@@ -930,8 +968,14 @@ fn categorizeStmt(ast: *const Ast, stmt: Ast.Node.Index) StmtCategory {
930 },968 },
931 .assign => {969 .assign => {
932 const infix = datas[stmt];970 const infix = datas[stmt];
933 if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier)971 if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier) {
934 return .discard_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 }
935 return .other;979 return .other;
936 },980 },
937 else => return .other,981 else => return .other,
...@@ -951,26 +995,21 @@ fn categorizeBuiltinCall(...@@ -951,26 +995,21 @@ fn categorizeBuiltinCall(
951}995}
952996
953fn isDiscardIdent(ast: *const Ast, node: Ast.Node.Index) bool {997fn isDiscardIdent(ast: *const Ast, node: Ast.Node.Index) bool {
954 const node_tags = ast.nodes.items(.tag);998 return isMatchingIdent(ast, node, "_");
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 }
964}999}
9651000
966fn isUndefinedIdent(ast: *const Ast, node: Ast.Node.Index) bool {1001fn 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 {
967 const node_tags = ast.nodes.items(.tag);1006 const node_tags = ast.nodes.items(.tag);
968 const main_tokens = ast.nodes.items(.main_token);1007 const main_tokens = ast.nodes.items(.main_token);
969 switch (node_tags[node]) {1008 switch (node_tags[node]) {
970 .identifier => {1009 .identifier => {
971 const token_index = main_tokens[node];1010 const token_index = main_tokens[node];
972 const name_bytes = ast.tokenSlice(token_index);1011 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);
974 },1013 },
975 else => return false,1014 else => return false,
976 }1015 }