| ... | @@ -5,11 +5,15 @@ const assert = std.debug.assert; | ... | @@ -5,11 +5,15 @@ const assert = std.debug.assert; |
| 5 | | 5 | |
| 6 | ast: *const Ast, | 6 | ast: *const Ast, |
| 7 | transformations: *std.ArrayList(Transformation), | 7 | transformations: *std.ArrayList(Transformation), |
| | 8 | unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index), |
| | 9 | gpa: std.mem.Allocator, |
| 8 | | 10 | |
| 9 | pub const Transformation = union(enum) { | 11 | pub const Transformation = union(enum) { |
| 10 | /// Replace the fn decl AST Node with one whose body is only `@trap()` with | 12 | /// Replace the fn decl AST Node with one whose body is only `@trap()` with |
| 11 | /// discarded parameters. | 13 | /// discarded parameters. |
| 12 | gut_function: Ast.Node.Index, | 14 | gut_function: Ast.Node.Index, |
| | 15 | /// Omit a global declaration. |
| | 16 | delete_node: Ast.Node.Index, |
| 13 | }; | 17 | }; |
| 14 | | 18 | |
| 15 | pub const Error = error{OutOfMemory}; | 19 | pub const Error = error{OutOfMemory}; |
| ... | @@ -21,16 +25,59 @@ pub fn findTransformations(ast: *const Ast, transformations: *std.ArrayList(Tran | ... | @@ -21,16 +25,59 @@ pub fn findTransformations(ast: *const Ast, transformations: *std.ArrayList(Tran |
| 21 | var walk: Walk = .{ | 25 | var walk: Walk = .{ |
| 22 | .ast = ast, | 26 | .ast = ast, |
| 23 | .transformations = transformations, | 27 | .transformations = transformations, |
| | 28 | .gpa = transformations.allocator, |
| | 29 | .unreferenced_globals = .{}, |
| 24 | }; | 30 | }; |
| | 31 | defer walk.unreferenced_globals.deinit(walk.gpa); |
| | 32 | |
| 25 | try walkMembers(&walk, walk.ast.rootDecls()); | 33 | try walkMembers(&walk, walk.ast.rootDecls()); |
| | 34 | |
| | 35 | const unreferenced_globals = walk.unreferenced_globals.values(); |
| | 36 | try transformations.ensureUnusedCapacity(unreferenced_globals.len); |
| | 37 | for (unreferenced_globals) |node| { |
| | 38 | transformations.appendAssumeCapacity(.{ .delete_node = node }); |
| | 39 | } |
| 26 | } | 40 | } |
| 27 | | 41 | |
| 28 | fn walkMembers(w: *Walk, members: []const Ast.Node.Index) Error!void { | 42 | fn walkMembers(w: *Walk, members: []const Ast.Node.Index) Error!void { |
| | 43 | // First we scan for globals so that we can delete them while walking. |
| | 44 | try scanDecls(w, members); |
| | 45 | |
| 29 | for (members) |member| { | 46 | for (members) |member| { |
| 30 | try walkMember(w, member); | 47 | try walkMember(w, member); |
| 31 | } | 48 | } |
| 32 | } | 49 | } |
| 33 | | 50 | |
| | 51 | fn scanDecls(w: *Walk, members: []const Ast.Node.Index) Error!void { |
| | 52 | const ast = w.ast; |
| | 53 | const gpa = w.gpa; |
| | 54 | const node_tags = ast.nodes.items(.tag); |
| | 55 | const main_tokens = ast.nodes.items(.main_token); |
| | 56 | const token_tags = ast.tokens.items(.tag); |
| | 57 | |
| | 58 | for (members) |member_node| { |
| | 59 | const name_token = switch (node_tags[member_node]) { |
| | 60 | .global_var_decl, |
| | 61 | .local_var_decl, |
| | 62 | .simple_var_decl, |
| | 63 | .aligned_var_decl, |
| | 64 | => main_tokens[member_node] + 1, |
| | 65 | |
| | 66 | .fn_proto_simple, |
| | 67 | .fn_proto_multi, |
| | 68 | .fn_proto_one, |
| | 69 | .fn_proto, |
| | 70 | .fn_decl, |
| | 71 | => main_tokens[member_node] + 1, |
| | 72 | |
| | 73 | else => continue, |
| | 74 | }; |
| | 75 | assert(token_tags[name_token] == .identifier); |
| | 76 | const name_bytes = ast.tokenSlice(name_token); |
| | 77 | try w.unreferenced_globals.put(gpa, name_bytes, member_node); |
| | 78 | } |
| | 79 | } |
| | 80 | |
| 34 | fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { | 81 | fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 35 | const ast = w.ast; | 82 | const ast = w.ast; |
| 36 | const datas = ast.nodes.items(.data); | 83 | const datas = ast.nodes.items(.data); |
| ... | @@ -53,6 +100,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { | ... | @@ -53,6 +100,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 53 | }, | 100 | }, |
| 54 | | 101 | |
| 55 | .@"usingnamespace" => { | 102 | .@"usingnamespace" => { |
| | 103 | try w.transformations.append(.{ .delete_node = decl }); |
| 56 | const expr = datas[decl].lhs; | 104 | const expr = datas[decl].lhs; |
| 57 | try walkExpression(w, expr); | 105 | try walkExpression(w, expr); |
| 58 | }, | 106 | }, |
| ... | @@ -61,9 +109,10 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { | ... | @@ -61,9 +109,10 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 61 | .local_var_decl, | 109 | .local_var_decl, |
| 62 | .simple_var_decl, | 110 | .simple_var_decl, |
| 63 | .aligned_var_decl, | 111 | .aligned_var_decl, |
| 64 | => try walkVarDecl(w, ast.fullVarDecl(decl).?), | 112 | => try walkGlobalVarDecl(w, decl, ast.fullVarDecl(decl).?), |
| 65 | | 113 | |
| 66 | .test_decl => { | 114 | .test_decl => { |
| | 115 | try w.transformations.append(.{ .delete_node = decl }); |
| 67 | try walkExpression(w, datas[decl].rhs); | 116 | try walkExpression(w, datas[decl].rhs); |
| 68 | }, | 117 | }, |
| 69 | | 118 | |
| ... | @@ -72,7 +121,10 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { | ... | @@ -72,7 +121,10 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 72 | .container_field, | 121 | .container_field, |
| 73 | => try walkContainerField(w, ast.fullContainerField(decl).?), | 122 | => try walkContainerField(w, ast.fullContainerField(decl).?), |
| 74 | | 123 | |
| 75 | .@"comptime" => try walkExpression(w, decl), | 124 | .@"comptime" => { |
| | 125 | try w.transformations.append(.{ .delete_node = decl }); |
| | 126 | try walkExpression(w, decl); |
| | 127 | }, |
| 76 | | 128 | |
| 77 | .root => unreachable, | 129 | .root => unreachable, |
| 78 | else => unreachable, | 130 | else => unreachable, |
| ... | @@ -86,7 +138,7 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { | ... | @@ -86,7 +138,7 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { |
| 86 | const node_tags = ast.nodes.items(.tag); | 138 | const node_tags = ast.nodes.items(.tag); |
| 87 | const datas = ast.nodes.items(.data); | 139 | const datas = ast.nodes.items(.data); |
| 88 | switch (node_tags[node]) { | 140 | switch (node_tags[node]) { |
| 89 | .identifier => {}, | 141 | .identifier => try walkIdentifier(w, main_tokens[node]), |
| 90 | | 142 | |
| 91 | .number_literal, | 143 | .number_literal, |
| 92 | .char_literal, | 144 | .char_literal, |
| ... | @@ -463,8 +515,32 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { | ... | @@ -463,8 +515,32 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { |
| 463 | } | 515 | } |
| 464 | } | 516 | } |
| 465 | | 517 | |
| | 518 | fn walkGlobalVarDecl(w: *Walk, decl_node: Ast.Node.Index, var_decl: Ast.full.VarDecl) Error!void { |
| | 519 | _ = decl_node; |
| | 520 | |
| | 521 | if (var_decl.ast.type_node != 0) { |
| | 522 | try walkExpression(w, var_decl.ast.type_node); |
| | 523 | } |
| | 524 | |
| | 525 | if (var_decl.ast.align_node != 0) { |
| | 526 | try walkExpression(w, var_decl.ast.align_node); |
| | 527 | } |
| | 528 | |
| | 529 | if (var_decl.ast.addrspace_node != 0) { |
| | 530 | try walkExpression(w, var_decl.ast.addrspace_node); |
| | 531 | } |
| | 532 | |
| | 533 | if (var_decl.ast.section_node != 0) { |
| | 534 | try walkExpression(w, var_decl.ast.section_node); |
| | 535 | } |
| | 536 | |
| | 537 | assert(var_decl.ast.init_node != 0); |
| | 538 | |
| | 539 | return walkExpression(w, var_decl.ast.init_node); |
| | 540 | } |
| | 541 | |
| 466 | fn walkVarDecl(w: *Walk, var_decl: Ast.full.VarDecl) Error!void { | 542 | fn walkVarDecl(w: *Walk, var_decl: Ast.full.VarDecl) Error!void { |
| 467 | try walkIdentifier(w, var_decl.ast.mut_token + 1); // name | 543 | try walkIdentifierNew(w, var_decl.ast.mut_token + 1); // name |
| 468 | | 544 | |
| 469 | if (var_decl.ast.type_node != 0) { | 545 | if (var_decl.ast.type_node != 0) { |
| 470 | try walkExpression(w, var_decl.ast.type_node); | 546 | try walkExpression(w, var_decl.ast.type_node); |
| ... | @@ -571,9 +647,17 @@ fn walkSlice( | ... | @@ -571,9 +647,17 @@ fn walkSlice( |
| 571 | } | 647 | } |
| 572 | } | 648 | } |
| 573 | | 649 | |
| 574 | fn walkIdentifier(w: *Walk, token_index: Ast.TokenIndex) Error!void { | 650 | fn walkIdentifier(w: *Walk, name_ident: Ast.TokenIndex) Error!void { |
| | 651 | const ast = w.ast; |
| | 652 | const token_tags = ast.tokens.items(.tag); |
| | 653 | assert(token_tags[name_ident] == .identifier); |
| | 654 | const name_bytes = ast.tokenSlice(name_ident); |
| | 655 | _ = w.unreferenced_globals.swapRemove(name_bytes); |
| | 656 | } |
| | 657 | |
| | 658 | fn walkIdentifierNew(w: *Walk, name_ident: Ast.TokenIndex) Error!void { |
| 575 | _ = w; | 659 | _ = w; |
| 576 | _ = token_index; | 660 | _ = name_ident; |
| 577 | } | 661 | } |
| 578 | | 662 | |
| 579 | fn walkContainerDecl( | 663 | fn walkContainerDecl( |
| ... | @@ -585,9 +669,7 @@ fn walkContainerDecl( | ... | @@ -585,9 +669,7 @@ fn walkContainerDecl( |
| 585 | if (container_decl.ast.arg != 0) { | 669 | if (container_decl.ast.arg != 0) { |
| 586 | try walkExpression(w, container_decl.ast.arg); | 670 | try walkExpression(w, container_decl.ast.arg); |
| 587 | } | 671 | } |
| 588 | for (container_decl.ast.members) |member| { | 672 | try walkMembers(w, container_decl.ast.members); |
| 589 | try walkMember(w, member); | | |
| 590 | } | | |
| 591 | } | 673 | } |
| 592 | | 674 | |
| 593 | fn walkBuiltinCall( | 675 | fn walkBuiltinCall( |