Commit 108af28c1b

Andrew Kelley <superjoe30@gmail.com>
2016-02-01 10:34:01
optimization: avoid codegening unused functions
1 parent 179443b
src/all_types.hpp
@@ -972,6 +972,7 @@ struct FnTableEntry {
     bool is_inline;
     bool internal_linkage;
     bool is_extern;
+    uint32_t ref_count; // if this is 0 we don't have to codegen it
 
     // reminder: hash tables must be initialized before use
     HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
@@ -1000,6 +1001,7 @@ struct BuiltinFnEntry {
     int param_count;
     TypeTableEntry *return_type;
     TypeTableEntry **param_types;
+    uint32_t ref_count;
     LLVMValueRef fn_val;
 };
 
src/analyze.cpp
@@ -1123,6 +1123,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
     fn_table_entry->is_extern = is_extern;
     fn_table_entry->label_table.init(8);
     fn_table_entry->member_of_struct = struct_type;
+    fn_table_entry->ref_count = (proto_node->data.fn_proto.visib_mod == VisibModExport) ? 1 : 0;
 
     if (struct_type) {
         buf_resize(&fn_table_entry->symbol_name, 0);
@@ -2244,6 +2245,7 @@ static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode
 }
 
 static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) {
+    fn->ref_count += 1;
     Expr *expr = get_resolved_expr(node);
     expr->const_val.ok = true;
     expr->const_val.data.x_fn = fn;
@@ -3658,6 +3660,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
         return g->builtin_types.entry_invalid;
     }
 
+    builtin_fn->ref_count += 1;
+
     switch (builtin_fn->id) {
         case BuiltinFnIdInvalid:
             zig_unreachable();
@@ -3913,6 +3917,8 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import,
 
     node->data.fn_call_expr.fn_entry = fn_table_entry;
 
+    fn_table_entry->ref_count += 1;
+
     return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type);
 
 }
src/codegen.cpp
@@ -2582,9 +2582,28 @@ static void gen_const_globals(CodeGen *g) {
     }
 }
 
+static void delete_unused_builtin_fns(CodeGen *g) {
+    auto it = g->builtin_fn_table.entry_iterator();
+    for (;;) {
+        auto *entry = it.next();
+        if (!entry)
+            break;
+
+        BuiltinFnEntry *builtin_fn = entry->value;
+        if (builtin_fn->ref_count == 0 &&
+            builtin_fn->fn_val)
+        {
+            LLVMDeleteFunction(entry->value->fn_val);
+        }
+    }
+}
+
 static void do_code_gen(CodeGen *g) {
     assert(!g->errors.length);
 
+    delete_unused_builtin_fns(g);
+
+
     gen_const_globals(g);
 
     // Generate module level variables
@@ -2633,6 +2652,12 @@ static void do_code_gen(CodeGen *g) {
     // Generate function prototypes
     for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
         FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
+        if (fn_table_entry->ref_count == 0) {
+            // huge time saver
+            LLVMDeleteFunction(fn_table_entry->fn_value);
+            continue;
+        }
+
         AstNode *proto_node = fn_table_entry->proto_node;
         assert(proto_node->type == NodeTypeFnProto);
         AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
@@ -2681,6 +2706,11 @@ static void do_code_gen(CodeGen *g) {
     // Generate function definitions.
     for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
         FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
+        if (fn_table_entry->ref_count == 0) {
+            // huge time saver
+            continue;
+        }
+
         ImportTableEntry *import = fn_table_entry->import_entry;
         AstNode *fn_def_node = fn_table_entry->fn_def_node;
         LLVMValueRef fn = fn_table_entry->fn_value;
@@ -3064,6 +3094,7 @@ static void define_builtin_fns(CodeGen *g) {
         builtin_fn->param_types[0] = nullptr; // manually checked later
         builtin_fn->param_types[1] = nullptr; // manually checked later
         builtin_fn->param_types[2] = g->builtin_types.entry_isize;
+        builtin_fn->ref_count = 1;
 
         LLVMTypeRef param_types[] = {
             LLVMPointerType(LLVMInt8Type(), 0),
@@ -3087,6 +3118,7 @@ static void define_builtin_fns(CodeGen *g) {
         builtin_fn->param_types[0] = nullptr; // manually checked later
         builtin_fn->param_types[1] = g->builtin_types.entry_u8;
         builtin_fn->param_types[2] = g->builtin_types.entry_isize;
+        builtin_fn->ref_count = 1;
 
         LLVMTypeRef param_types[] = {
             LLVMPointerType(LLVMInt8Type(), 0),