diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-11-04 20:27:15 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-11-04 20:27:15 -0700 |
| commit | a9002156a09130038abcf418609fea725ce71bc2 (patch) | |
| tree | c84f00b3dddfa5302f516ee523a6fa1d9767dcfa /src | |
| parent | c4dddcbadbcce587e0bd8593636373712294b5b2 (diff) | |
| download | zig-a9002156a09130038abcf418609fea725ce71bc2.tar.gz zig-a9002156a09130038abcf418609fea725ce71bc2.zip | |
zig reduce: add reduction for removing var decls
Diffstat (limited to 'src')
| -rw-r--r-- | src/reduce.zig | 6 | ||||
| -rw-r--r-- | src/reduce/Walk.zig | 73 |
2 files changed, 62 insertions, 17 deletions
diff --git a/src/reduce.zig b/src/reduce.zig index 7013c70674..f11b2a6ae1 100644 --- a/src/reduce.zig +++ b/src/reduce.zig @@ -321,6 +321,12 @@ fn transformationsToFixups( .delete_node => |decl_node| { try fixups.omit_nodes.put(gpa, decl_node, {}); }, + .delete_var_decl => |delete_var_decl| { + try fixups.omit_nodes.put(gpa, delete_var_decl.var_decl_node, {}); + for (delete_var_decl.references.items) |ident_node| { + try fixups.replace_nodes.put(gpa, ident_node, "undefined"); + } + }, .replace_with_undef => |node| { try fixups.replace_nodes.put(gpa, node, "undefined"); }, diff --git a/src/reduce/Walk.zig b/src/reduce/Walk.zig index 23935398af..94ef0eeb26 100644 --- a/src/reduce/Walk.zig +++ b/src/reduce/Walk.zig @@ -8,6 +8,7 @@ ast: *const Ast, transformations: *std.ArrayList(Transformation), unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index), in_scope_names: std.StringArrayHashMapUnmanaged(u32), +replace_names: std.StringArrayHashMapUnmanaged(u32), gpa: std.mem.Allocator, arena: std.mem.Allocator, @@ -17,6 +18,13 @@ pub const Transformation = union(enum) { gut_function: Ast.Node.Index, /// Omit a global declaration. delete_node: Ast.Node.Index, + /// Delete a local variable declaration and replace all of its references + /// with `undefined`. + delete_var_decl: struct { + var_decl_node: Ast.Node.Index, + /// Identifier nodes that reference the variable. + references: std.ArrayListUnmanaged(Ast.Node.Index), + }, /// Replace an expression with `undefined`. replace_with_undef: Ast.Node.Index, /// Replace an `@import` with the imported file contents wrapped in a struct. @@ -48,10 +56,12 @@ pub fn findTransformations( .arena = arena, .unreferenced_globals = .{}, .in_scope_names = .{}, + .replace_names = .{}, }; defer { walk.unreferenced_globals.deinit(walk.gpa); walk.in_scope_names.deinit(walk.gpa); + walk.replace_names.deinit(walk.gpa); } try walkMembers(&walk, walk.ast.rootDecls()); @@ -133,6 +143,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { try walkExpression(w, fn_proto); const body_node = datas[decl].rhs; if (!isFnBodyGutted(ast, body_node)) { + w.replace_names.clearRetainingCapacity(); try w.transformations.append(.{ .gut_function = decl }); try walkExpression(w, body_node); } @@ -187,7 +198,15 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { const node_tags = ast.nodes.items(.tag); const datas = ast.nodes.items(.data); switch (node_tags[node]) { - .identifier => try walkIdentifier(w, main_tokens[node]), + .identifier => { + const name_ident = main_tokens[node]; + assert(token_tags[name_ident] == .identifier); + const name_bytes = ast.tokenSlice(name_ident); + _ = w.unreferenced_globals.swapRemove(name_bytes); + if (w.replace_names.get(name_bytes)) |index| { + try w.transformations.items[index].delete_var_decl.references.append(w.arena, node); + } + }, .number_literal, .char_literal, @@ -646,13 +665,31 @@ fn walkBlock( .local_var_decl, .simple_var_decl, .aligned_var_decl, - => try walkLocalVarDecl(w, ast.fullVarDecl(stmt).?), + => { + const var_decl = ast.fullVarDecl(stmt).?; + if (var_decl.ast.init_node != 0 and + isUndefinedIdent(w.ast, var_decl.ast.init_node)) + { + try w.transformations.append(.{ .delete_var_decl = .{ + .var_decl_node = stmt, + .references = .{}, + } }); + const name_tok = var_decl.ast.mut_token + 1; + const name_bytes = ast.tokenSlice(name_tok); + try w.replace_names.put(w.gpa, name_bytes, @intCast(w.transformations.items.len - 1)); + } else { + try walkLocalVarDecl(w, var_decl); + } + }, else => { - // Don't try to remove `_ = foo;` discards; those are handled separately. switch (categorizeStmt(ast, stmt)) { + // Don't try to remove `_ = foo;` discards; those are handled separately. .discard_identifier => {}, - else => try w.transformations.append(.{ .delete_node = stmt }), + // definitely try to remove `_ = undefined;` though. + .discard_undefined, .trap_call, .other => { + try w.transformations.append(.{ .delete_node = stmt }); + }, } try walkExpression(w, stmt); }, @@ -905,6 +942,7 @@ fn isFnBodyGutted(ast: *const Ast, body_node: Ast.Node.Index) bool { } const StmtCategory = enum { + discard_undefined, discard_identifier, trap_call, other, @@ -930,8 +968,14 @@ fn categorizeStmt(ast: *const Ast, stmt: Ast.Node.Index) StmtCategory { }, .assign => { const infix = datas[stmt]; - if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier) - return .discard_identifier; + if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier) { + const name_bytes = ast.tokenSlice(main_tokens[infix.rhs]); + if (std.mem.eql(u8, name_bytes, "undefined")) { + return .discard_undefined; + } else { + return .discard_identifier; + } + } return .other; }, else => return .other, @@ -951,26 +995,21 @@ fn categorizeBuiltinCall( } fn isDiscardIdent(ast: *const Ast, node: Ast.Node.Index) bool { - const node_tags = ast.nodes.items(.tag); - const main_tokens = ast.nodes.items(.main_token); - switch (node_tags[node]) { - .identifier => { - const token_index = main_tokens[node]; - const name_bytes = ast.tokenSlice(token_index); - return std.mem.eql(u8, name_bytes, "_"); - }, - else => return false, - } + return isMatchingIdent(ast, node, "_"); } fn isUndefinedIdent(ast: *const Ast, node: Ast.Node.Index) bool { + return isMatchingIdent(ast, node, "undefined"); +} + +fn isMatchingIdent(ast: *const Ast, node: Ast.Node.Index, string: []const u8) bool { const node_tags = ast.nodes.items(.tag); const main_tokens = ast.nodes.items(.main_token); switch (node_tags[node]) { .identifier => { const token_index = main_tokens[node]; const name_bytes = ast.tokenSlice(token_index); - return std.mem.eql(u8, name_bytes, "undefined"); + return std.mem.eql(u8, name_bytes, string); }, else => return false, } |
