| ... | ... | @@ -5,11 +5,15 @@ const assert = std.debug.assert; |
| 5 | 5 | |
| 6 | 6 | ast: *const Ast, |
| 7 | 7 | transformations: *std.ArrayList(Transformation), |
| 8 | unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index), |
| 9 | gpa: std.mem.Allocator, |
| 8 | 10 | |
| 9 | 11 | pub const Transformation = union(enum) { |
| 10 | 12 | /// Replace the fn decl AST Node with one whose body is only `@trap()` with |
| 11 | 13 | /// discarded parameters. |
| 12 | 14 | gut_function: Ast.Node.Index, |
| 15 | /// Omit a global declaration. |
| 16 | delete_node: Ast.Node.Index, |
| 13 | 17 | }; |
| 14 | 18 | |
| 15 | 19 | pub const Error = error{OutOfMemory}; |
| ... | ... | @@ -21,16 +25,59 @@ pub fn findTransformations(ast: *const Ast, transformations: *std.ArrayList(Tran |
| 21 | 25 | var walk: Walk = .{ |
| 22 | 26 | .ast = ast, |
| 23 | 27 | .transformations = transformations, |
| 28 | .gpa = transformations.allocator, |
| 29 | .unreferenced_globals = .{}, |
| 24 | 30 | }; |
| 31 | defer walk.unreferenced_globals.deinit(walk.gpa); |
| 32 | |
| 25 | 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 | 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 | 46 | for (members) |member| { |
| 30 | 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 | 81 | fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 35 | 82 | const ast = w.ast; |
| 36 | 83 | const datas = ast.nodes.items(.data); |
| ... | ... | @@ -53,6 +100,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 53 | 100 | }, |
| 54 | 101 | |
| 55 | 102 | .@"usingnamespace" => { |
| 103 | try w.transformations.append(.{ .delete_node = decl }); |
| 56 | 104 | const expr = datas[decl].lhs; |
| 57 | 105 | try walkExpression(w, expr); |
| 58 | 106 | }, |
| ... | ... | @@ -61,9 +109,10 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void { |
| 61 | 109 | .local_var_decl, |
| 62 | 110 | .simple_var_decl, |
| 63 | 111 | .aligned_var_decl, |
| 64 | | => try walkVarDecl(w, ast.fullVarDecl(decl).?), |
| 112 | => try walkGlobalVarDecl(w, decl, ast.fullVarDecl(decl).?), |
| 65 | 113 | |
| 66 | 114 | .test_decl => { |
| 115 | try w.transformations.append(.{ .delete_node = decl }); |
| 67 | 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 | 121 | .container_field, |
| 73 | 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 | 129 | .root => unreachable, |
| 78 | 130 | else => unreachable, |
| ... | ... | @@ -86,7 +138,7 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { |
| 86 | 138 | const node_tags = ast.nodes.items(.tag); |
| 87 | 139 | const datas = ast.nodes.items(.data); |
| 88 | 140 | switch (node_tags[node]) { |
| 89 | | .identifier => {}, |
| 141 | .identifier => try walkIdentifier(w, main_tokens[node]), |
| 90 | 142 | |
| 91 | 143 | .number_literal, |
| 92 | 144 | .char_literal, |
| ... | ... | @@ -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 | 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 | 545 | if (var_decl.ast.type_node != 0) { |
| 470 | 546 | try walkExpression(w, var_decl.ast.type_node); |
| ... | ... | @@ -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 | 659 | _ = w; |
| 576 | | _ = token_index; |
| 660 | _ = name_ident; |
| 577 | 661 | } |
| 578 | 662 | |
| 579 | 663 | fn walkContainerDecl( |
| ... | ... | @@ -585,9 +669,7 @@ fn walkContainerDecl( |
| 585 | 669 | if (container_decl.ast.arg != 0) { |
| 586 | 670 | try walkExpression(w, container_decl.ast.arg); |
| 587 | 671 | } |
| 588 | | for (container_decl.ast.members) |member| { |
| 589 | | try walkMember(w, member); |
| 590 | | } |
| 672 | try walkMembers(w, container_decl.ast.members); |
| 591 | 673 | } |
| 592 | 674 | |
| 593 | 675 | fn walkBuiltinCall( |