Commit 87cdbb6c25

Andrew Kelley <superjoe30@gmail.com>
2016-02-08 02:32:19
improve performance for get_fn_type
1 parent 6b3ce91
src/all_types.hpp
@@ -810,11 +810,13 @@ struct AsmToken {
     int end;
 };
 
+// this struct is allocated with allocate_nonzero
 struct FnTypeParamInfo {
     bool is_noalias;
     TypeTableEntry *type;
 };
 
+static const int fn_type_id_prealloc_param_info_count = 4;
 struct FnTypeId {
     TypeTableEntry *return_type;
     FnTypeParamInfo *param_info;
@@ -823,10 +825,11 @@ struct FnTypeId {
     bool is_naked;
     bool is_cold;
     bool is_extern;
+    FnTypeParamInfo prealloc_param_info[fn_type_id_prealloc_param_info_count];
 };
 
-uint32_t fn_type_id_hash(FnTypeId);
-bool fn_type_id_eql(FnTypeId a, FnTypeId b);
+uint32_t fn_type_id_hash(FnTypeId*);
+bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
 
 
 struct TypeTableEntryPointer {
@@ -1061,7 +1064,7 @@ struct CodeGen {
     HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
     HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
     HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
-    HashMap<FnTypeId, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
+    HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
     HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
 
     uint32_t next_unresolved_index;
src/analyze.cpp
@@ -541,18 +541,21 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
 }
 
 // accepts ownership of fn_type_id memory
-TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
+TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
     auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
     if (table_entry) {
         return table_entry->value;
     }
 
     TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
-    fn_type->data.fn.fn_type_id = fn_type_id;
+    fn_type->data.fn.fn_type_id = *fn_type_id;
+    if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) {
+        fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0];
+    }
 
-    if (fn_type_id.is_cold) {
+    if (fn_type_id->is_cold) {
         fn_type->data.fn.calling_convention = LLVMColdCallConv;
-    } else if (fn_type_id.is_extern) {
+    } else if (fn_type_id->is_extern) {
         fn_type->data.fn.calling_convention = LLVMCCallConv;
     } else {
         fn_type->data.fn.calling_convention = LLVMFastCallConv;
@@ -560,12 +563,12 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
 
     // populate the name of the type
     buf_resize(&fn_type->name, 0);
-    const char *extern_str = fn_type_id.is_extern ? "extern " : "";
-    const char *naked_str = fn_type_id.is_naked ? "naked " : "";
-    const char *cold_str = fn_type_id.is_cold ? "cold " : "";
+    const char *extern_str = fn_type_id->is_extern ? "extern " : "";
+    const char *naked_str = fn_type_id->is_naked ? "naked " : "";
+    const char *cold_str = fn_type_id->is_cold ? "cold " : "";
     buf_appendf(&fn_type->name, "%s%s%sfn(", extern_str, naked_str, cold_str);
-    for (int i = 0; i < fn_type_id.param_count; i += 1) {
-        FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
+    for (int i = 0; i < fn_type_id->param_count; i += 1) {
+        FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
 
         TypeTableEntry *param_type = param_info->type;
         const char *comma = (i == 0) ? "" : ", ";
@@ -573,42 +576,42 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
         buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(&param_type->name));
     }
 
-    if (fn_type_id.is_var_args) {
-        const char *comma = (fn_type_id.param_count == 0) ? "" : ", ";
+    if (fn_type_id->is_var_args) {
+        const char *comma = (fn_type_id->param_count == 0) ? "" : ", ";
         buf_appendf(&fn_type->name, "%s...", comma);
     }
     buf_appendf(&fn_type->name, ")");
-    if (fn_type_id.return_type->id != TypeTableEntryIdVoid) {
-        buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id.return_type->name));
+    if (fn_type_id->return_type->id != TypeTableEntryIdVoid) {
+        buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name));
     }
 
 
     // next, loop over the parameters again and compute debug information
     // and codegen information
-    bool first_arg_return = handle_is_ptr(fn_type_id.return_type);
+    bool first_arg_return = handle_is_ptr(fn_type_id->return_type);
     // +1 for maybe making the first argument the return value
-    LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id.param_count);
+    LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);
     // +1 because 0 is the return type and +1 for maybe making first arg ret val
-    LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id.param_count);
-    param_di_types[0] = fn_type_id.return_type->di_type;
+    LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id->param_count);
+    param_di_types[0] = fn_type_id->return_type->di_type;
     int gen_param_index = 0;
     TypeTableEntry *gen_return_type;
     if (first_arg_return) {
-        TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id.return_type, false);
+        TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
         gen_param_types[gen_param_index] = gen_type->type_ref;
         gen_param_index += 1;
         // after the gen_param_index += 1 because 0 is the return type
         param_di_types[gen_param_index] = gen_type->di_type;
         gen_return_type = g->builtin_types.entry_void;
-    } else if (!type_has_bits(fn_type_id.return_type)) {
+    } else if (!type_has_bits(fn_type_id->return_type)) {
         gen_return_type = g->builtin_types.entry_void;
     } else {
-        gen_return_type = fn_type_id.return_type;
+        gen_return_type = fn_type_id->return_type;
     }
     fn_type->data.fn.gen_return_type = gen_return_type;
 
-    fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id.param_count);
-    for (int i = 0; i < fn_type_id.param_count; i += 1) {
+    fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
+    for (int i = 0; i < fn_type_id->param_count; i += 1) {
         FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
         TypeTableEntry *type_entry = src_param_info->type;
         FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
@@ -639,13 +642,13 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
     fn_type->data.fn.gen_param_count = gen_param_index;
 
     fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
-            gen_param_types, gen_param_index, fn_type_id.is_var_args);
+            gen_param_types, gen_param_index, fn_type_id->is_var_args);
     fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
     LLVMZigDIFile *di_file = nullptr;
     fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, di_file,
             param_di_types, gen_param_index + 1, 0);
 
-    g->fn_type_table.put(fn_type_id, fn_type);
+    g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
 
     return fn_type;
 }
@@ -747,7 +750,13 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
     fn_type_id.is_naked = is_naked;
     fn_type_id.is_cold = is_cold;
     fn_type_id.param_count = node->data.fn_proto.params.length;
-    fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);
+
+    if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
+        fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
+    } else {
+        fn_type_id.param_info = &fn_type_id.prealloc_param_info[0];
+    }
+
     fn_type_id.is_var_args = fn_proto->is_var_args;
     fn_type_id.return_type = analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type);
 
@@ -800,7 +809,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
         return g->builtin_types.entry_invalid;
     }
 
-    return get_fn_type(g, fn_type_id);
+    return get_fn_type(g, &fn_type_id);
 }
 
 
@@ -5855,35 +5864,35 @@ static uint32_t hash_ptr(void *ptr) {
     return a ^ b;
 }
 
-uint32_t fn_type_id_hash(FnTypeId id) {
+uint32_t fn_type_id_hash(FnTypeId *id) {
     uint32_t result = 0;
-    result += id.is_extern ? 3349388391 : 0;
-    result += id.is_naked ? 608688877 : 0;
-    result += id.is_cold ? 3605523458 : 0;
-    result += id.is_var_args ? 1931444534 : 0;
-    result += hash_ptr(id.return_type);
-    result += id.param_count;
-    for (int i = 0; i < id.param_count; i += 1) {
-        FnTypeParamInfo *info = &id.param_info[i];
+    result += id->is_extern ? 3349388391 : 0;
+    result += id->is_naked ? 608688877 : 0;
+    result += id->is_cold ? 3605523458 : 0;
+    result += id->is_var_args ? 1931444534 : 0;
+    result += hash_ptr(id->return_type);
+    result += id->param_count;
+    for (int i = 0; i < id->param_count; i += 1) {
+        FnTypeParamInfo *info = &id->param_info[i];
         result += info->is_noalias ? 892356923 : 0;
         result += hash_ptr(info->type);
     }
     return result;
 }
 
-bool fn_type_id_eql(FnTypeId a, FnTypeId b) {
-    if (a.is_extern != b.is_extern ||
-        a.is_naked != b.is_naked ||
-        a.is_cold != b.is_cold ||
-        a.return_type != b.return_type ||
-        a.is_var_args != b.is_var_args ||
-        a.param_count != b.param_count)
+bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
+    if (a->is_extern != b->is_extern ||
+        a->is_naked != b->is_naked ||
+        a->is_cold != b->is_cold ||
+        a->return_type != b->return_type ||
+        a->is_var_args != b->is_var_args ||
+        a->param_count != b->param_count)
     {
         return false;
     }
-    for (int i = 0; i < a.param_count; i += 1) {
-        FnTypeParamInfo *a_param_info = &a.param_info[i];
-        FnTypeParamInfo *b_param_info = &b.param_info[i];
+    for (int i = 0; i < a->param_count; i += 1) {
+        FnTypeParamInfo *a_param_info = &a->param_info[i];
+        FnTypeParamInfo *b_param_info = &b->param_info[i];
 
         if (a_param_info->type != b_param_info->type) {
             return false;
src/analyze.hpp
@@ -23,7 +23,7 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
 TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
 TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
 TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type);
-TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id);
+TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
 TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
 TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
 TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
src/parseh.cpp
@@ -506,7 +506,12 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
                     }
                 }
 
-                fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);
+                if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) {
+                    fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count);
+                } else {
+                    fn_type_id.param_info = &fn_type_id.prealloc_param_info[0];
+                }
+
                 for (int i = 0; i < fn_type_id.param_count; i += 1) {
                     QualType qt = fn_proto_ty->getParamType(i);
                     TypeTableEntry *param_type = resolve_qual_type(c, qt, decl);
@@ -521,7 +526,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
                     param_info->is_noalias = qt.isRestrictQualified();
                 }
 
-                return get_fn_type(c->codegen, fn_type_id);
+                return get_fn_type(c->codegen, &fn_type_id);
             }
         case Type::Record:
             {