polymorphic proc generation optimization
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 14 Jan 2021 02:46:16 +0000 (20:46 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 14 Jan 2021 02:46:16 +0000 (20:46 -0600)
bin/onyx
include/onyxastnodes.h
onyx.exe
src/onyxclone.c
src/onyxutils.c

index 2098d5e29e8d38e993064109b5ee135791b4b6fc..4ceb49909ab66bc12981f75bb464912393de23a1 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 720833205ad6b638c2482e3faa9e7916b5bcd430..2deb3717f4c99df7c15d1a878bc84cb79b7c7df1 100644 (file)
@@ -71,6 +71,7 @@ typedef struct AstOverloadedFunction AstOverloadedFunction;
 
 typedef struct AstPolyParam AstPolyParam;
 typedef struct AstPolySolution AstPolySolution;
+typedef struct AstSolidifiedFunction AstSolidifiedFunction;
 typedef struct AstPolyProc AstPolyProc;
 
 typedef struct AstPackage AstPackage;
@@ -177,8 +178,8 @@ typedef enum AstFlags {
     Ast_Flag_Private_File          = BH_BIT(6),
 
     // Global flags
-    Ast_Flag_Global_Stack_Top      = BH_BIT(7),
-    Ast_Flag_Global_Stack_Base     = BH_BIT(8),
+    Ast_Flag_Global_Stack_Top      = BH_BIT(7), // These can go away for something better,
+    Ast_Flag_Global_Stack_Base     = BH_BIT(8), // like just checking the pointers since they will be unique.
 
     // Function flags
     Ast_Flag_Intrinsic             = BH_BIT(10),
@@ -186,28 +187,30 @@ typedef enum AstFlags {
 
     // Expression flags
     Ast_Flag_Expr_Ignored          = BH_BIT(13),
-    Ast_Flag_Param_Use             = BH_BIT(14),
+    Ast_Flag_Param_Use             = BH_BIT(14), // Unneeded, just use a bool on AstParam
     Ast_Flag_Address_Taken         = BH_BIT(15),
 
     // Type flags
     Ast_Flag_Type_Is_Resolved      = BH_BIT(16),
 
     // Enum flags
-    Ast_Flag_Enum_Is_Flags         = BH_BIT(17),
+    Ast_Flag_Enum_Is_Flags         = BH_BIT(17), // Unneeded, just use a bool on AstEnum
 
     // Struct flags
-    Ast_Flag_Struct_Is_Union       = BH_BIT(18),
+    Ast_Flag_Struct_Is_Union       = BH_BIT(18), // Unneeded, just a usea bool on AstStruct
 
     Ast_Flag_No_Clone              = BH_BIT(19),
 
     Ast_Flag_Cannot_Take_Addr      = BH_BIT(20),
 
-    Ast_Flag_Struct_Mem_Used       = BH_BIT(21),
+    Ast_Flag_Struct_Mem_Used       = BH_BIT(21), // Unneeded, just a usea bool on AstStructMember
 
     // HACK: NullProcHack
     Ast_Flag_Proc_Is_Null          = BH_BIT(22),
 
     Ast_Flag_From_Polymorphism     = BH_BIT(23),
+
+    Ast_Flag_Incomplete_Body       = BH_BIT(24),
 } AstFlags;
 
 typedef enum UnaryOp {
@@ -791,6 +794,10 @@ struct AstPolySolution {
         AstTyped* value;
     };
 };
+struct AstSolidifiedFunction {
+    AstFunction* func;
+    Scope*       poly_scope;
+};
 struct AstPolyProc {
     AstNode_base;
 
@@ -800,7 +807,7 @@ struct AstPolyProc {
     bh_arr(AstPolySolution) known_slns;
 
     AstFunction* base_func;
-    bh_table(AstFunction *) concrete_funcs;
+    bh_table(AstSolidifiedFunction) concrete_funcs;
 };
 struct AstOverloadedFunction {
     AstTyped_base;
@@ -972,6 +979,7 @@ void initialize_builtins(bh_allocator a, ProgramInfo* prog);
 AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
 AstNode* ast_clone(bh_allocator a, void* n);
 AstFunction* clone_function_header(bh_allocator a, AstFunction* func);
+void clone_function_body(bh_allocator a, AstFunction* dest, AstFunction* source);
 
 void promote_numlit_to_larger(AstNumLit* num);
 b32 convert_numlit_to_type(AstNumLit* num, Type* type);
index 2ff42df1cedcfc7d81d6fccb832c5c3b3d3ac1ee..b8a51481b2898517ce1baf85e77cbe6e4d9669d7 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 02200203d7bbd1ec4882faabb2028a4b2aa38294..31881815c8ca19012bb5d3ce5f66e44c4cefe9b2 100644 (file)
@@ -461,4 +461,16 @@ AstFunction* clone_function_header(bh_allocator a, AstFunction* func) {
     }
 
     return new_func;
+}
+
+// Clones a function body from a given function. It is assumed that `dest` is
+// a function from `clone_function_header`.
+void clone_function_body(bh_allocator a, AstFunction* dest, AstFunction* source) {
+    if (dest->kind != Ast_Kind_Function) return;
+    if (source->kind != Ast_Kind_Function) return;
+
+    dest->body = (AstBlock *) ast_clone(a, source->body);
+
+    dest->allocate_exprs = NULL;
+    bh_arr_new(global_heap_allocator, dest->allocate_exprs, 4);
 }
\ No newline at end of file
index 639e8dbdb9be27108b013b428763e4966d0f8dbb..cfdd13e599a150d782a9695dc7648ca3c16172ad 100644 (file)
@@ -148,6 +148,12 @@ void scope_clear(Scope* scope) {
     bh_table_clear(scope->symbols);
 }
 
+static void ensure_polyproc_cache_is_created(AstPolyProc* pp) {
+    if (pp->concrete_funcs == NULL) {
+        bh_table_init(global_heap_allocator, pp->concrete_funcs, 16);
+    }
+}
+
 static void insert_poly_slns_into_scope(Scope* scope, bh_arr(AstPolySolution) slns) {
     bh_arr_each(AstPolySolution, sln, slns) {
         AstNode *node = NULL;
@@ -438,9 +444,7 @@ sln_not_found:
 }
 
 AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos) {
-    if (pp->concrete_funcs == NULL) {
-        bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
-    }
+    ensure_polyproc_cache_is_created(pp);
 
     char *err_msg = NULL;
     bh_arr(AstPolySolution) slns = find_polymorphic_slns(pp, pp_lookup, actual, &err_msg);
@@ -502,51 +506,72 @@ static char* build_poly_slns_unique_key(bh_arr(AstPolySolution) slns) {
     return key_buf;
 }
 
-AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos) {
-    if (pp->concrete_funcs == NULL) {
-        bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
-    }
-
-    // NOTE: Check if a version of this polyproc has already been created.
-    char* unique_key = build_poly_slns_unique_key(slns);
-    if (bh_table_has(AstFunction *, pp->concrete_funcs, unique_key)) {
-        return bh_table_get(AstFunction *, pp->concrete_funcs, unique_key);
-    }
-
-    Scope* poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, pos);
-    insert_poly_slns_into_scope(poly_scope, slns);
-
-    AstFunction* func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func);
-    bh_table_put(AstFunction *, pp->concrete_funcs, unique_key, func);
+b32 add_solidified_function_entities(AstSolidifiedFunction solidified_func, b32 header_already_processed) {
+    solidified_func.func->flags |= Ast_Flag_Function_Used;
+    solidified_func.func->flags |= Ast_Flag_From_Polymorphism;
 
-    func->flags |= Ast_Flag_Function_Used;
-    func->flags |= Ast_Flag_From_Polymorphism;
+    EntityState header_start_state = Entity_State_Resolve_Symbols;
+    if (header_already_processed) header_start_state = Entity_State_Code_Gen;
 
     Entity func_header_entity = {
-        .state = Entity_State_Resolve_Symbols,
+        .state = header_start_state,
         .type = Entity_Type_Function_Header,
-        .function = func,
+        .function = solidified_func.func,
         .package = NULL,
-        .scope = poly_scope,
+        .scope = solidified_func.poly_scope,
     };
 
     entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen);
-    if (onyx_has_errors()) {
-        onyx_report_error(pos, "Error in polymorphic procedure header generated from this call site.");
-        return NULL;
-    }
+    if (onyx_has_errors()) return 0;
 
     Entity func_entity = {
         .state = Entity_State_Resolve_Symbols,
         .type = Entity_Type_Function,
-        .function = func,
+        .function = solidified_func.func,
         .package = NULL,
-        .scope = poly_scope,
+        .scope = solidified_func.poly_scope,
     };
 
     entity_heap_insert(&semstate.program->entities, func_header_entity);
     entity_heap_insert(&semstate.program->entities, func_entity);
-    return func;
+
+    return 1;
+}
+
+AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos) {
+    ensure_polyproc_cache_is_created(pp);
+
+    // NOTE: Check if a version of this polyproc has already been created.
+    char* unique_key = build_poly_slns_unique_key(slns);
+    if (bh_table_has(AstSolidifiedFunction, pp->concrete_funcs, unique_key)) {
+        AstSolidifiedFunction solidified_func = bh_table_get(AstSolidifiedFunction, pp->concrete_funcs, unique_key);
+
+        if (solidified_func.func->flags & Ast_Flag_Incomplete_Body) {
+            clone_function_body(semstate.node_allocator, solidified_func.func, pp->base_func);
+
+            if (!add_solidified_function_entities(solidified_func, 1)) {
+                onyx_report_error(pos, "Error in polymorphic procedure header generated from this call site.");
+                return NULL;
+            }
+
+            solidified_func.func->flags &= ~Ast_Flag_Incomplete_Body;
+        }
+
+        return solidified_func.func;
+    }
+
+    AstSolidifiedFunction solidified_func;
+    solidified_func.poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, pos);
+    insert_poly_slns_into_scope(solidified_func.poly_scope, slns);
+
+    solidified_func.func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func);
+    bh_table_put(AstSolidifiedFunction, pp->concrete_funcs, unique_key, solidified_func);
+
+    if (!add_solidified_function_entities(solidified_func, 0)) {
+        onyx_report_error(pos, "Error in polymorphic procedure header generated from this call site.");
+        return NULL;
+    }
+    return solidified_func.func;
 }
 
 // NOTE: This can return either a AstFunction or an AstPolyProc, depending if enough parameters were
@@ -588,10 +613,7 @@ AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
         new_pp->flags = pp->flags;
         new_pp->poly_params = pp->poly_params;
 
-        // POTENTIAL BUG: Copying this doesn't feel right...
-        if (pp->concrete_funcs == NULL) {
-            bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
-        }
+        ensure_polyproc_cache_is_created(pp);
         new_pp->concrete_funcs = pp->concrete_funcs;
 
         new_pp->known_slns = NULL;
@@ -608,21 +630,31 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM
     bh_arr(AstPolySolution) slns = find_polymorphic_slns(pp, pp_lookup, actual, NULL);
     if (slns == NULL) return NULL;
 
-    Scope* poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, (OnyxFilePos) { 0 });
-    insert_poly_slns_into_scope(poly_scope, slns);
+    ensure_polyproc_cache_is_created(pp);
+
+    char* unique_key = build_poly_slns_unique_key(slns);
+    if (bh_table_has(AstSolidifiedFunction, pp->concrete_funcs, unique_key)) {
+        AstSolidifiedFunction solidified_func = bh_table_get(AstSolidifiedFunction, pp->concrete_funcs, unique_key);
+        return solidified_func.func;
+    }
 
     // NOTE: This function is only going to have the header of it correctly created.
     // Nothing should happen to this function's body or else the original will be corrupted.
     //                                                      - brendanfh 2021/01/10
-    AstFunction* new_func = clone_function_header(semstate.node_allocator, pp->base_func);
-    new_func->flags |= Ast_Flag_From_Polymorphism;
+    AstSolidifiedFunction solidified_func;
+    solidified_func.poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, (OnyxFilePos) { 0 });
+    insert_poly_slns_into_scope(solidified_func.poly_scope, slns);
+
+    solidified_func.func = clone_function_header(semstate.node_allocator, pp->base_func);
+    solidified_func.func->flags |= Ast_Flag_Incomplete_Body;
+    solidified_func.func->flags |= Ast_Flag_From_Polymorphism;
 
     Entity func_header_entity = {
         .state = Entity_State_Resolve_Symbols,
         .type = Entity_Type_Function_Header,
-        .function = new_func,
+        .function = solidified_func.func,
         .package = NULL,
-        .scope = poly_scope,
+        .scope = solidified_func.poly_scope,
     };
 
     entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen);
@@ -631,7 +663,8 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM
         return NULL;
     }
 
-    return new_func;
+    bh_table_put(AstSolidifiedFunction, pp->concrete_funcs, unique_key, solidified_func);
+    return solidified_func.func;
 }
 
 char* build_poly_struct_name(AstPolyStructType* ps_type, Type* cs_type) {