Browse Source

Begin work to move entry point code to Odin itself rather than in C++ side

gingerBill 3 years ago
parent
commit
7e4067c44c

+ 5 - 0
core/intrinsics/intrinsics.odin

@@ -197,3 +197,8 @@ type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
 
 type_equal_proc  :: proc($T: typeid) -> (equal:  proc "contextless" (rawptr, rawptr) -> bool)                 where type_is_comparable(T) ---
 type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
+
+
+// Internal compiler use only
+
+__entry_point :: proc() ---

+ 1 - 1
core/runtime/procs_windows_amd64.odin

@@ -22,4 +22,4 @@ windows_trap_type_assertion :: proc "contextless" () -> ! {
 when ODIN_NO_CRT {
 	@(require)
 	foreign import crt_lib "procs_windows_amd64.asm"
-}
+}

+ 6 - 0
src/check_builtin.cpp

@@ -219,6 +219,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name));
 		break;
 
+	case BuiltinProc___entry_point:
+		operand->mode = Addressing_NoValue;
+		operand->type = nullptr;
+		mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call);
+		break;
+
 	case BuiltinProc_DIRECTIVE: {
 		ast_node(bd, BasicDirective, ce->proc);
 		String name = bd->name.string;

+ 20 - 16
src/check_decl.cpp

@@ -777,21 +777,23 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 
 
 	if (e->pkg != nullptr && e->token.string == "main") {
-		if (pt->param_count != 0 ||
-		    pt->result_count != 0) {
-			gbString str = type_to_string(proc_type);
-			error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str);
-			gb_string_free(str);
-		}
-		if (pt->calling_convention != default_calling_convention()) {
-			error(e->token, "Procedure 'main' cannot have a custom calling convention");
-		}
-		pt->calling_convention = default_calling_convention();
-		if (e->pkg->kind == Package_Init) {
-			if (ctx->info->entry_point != nullptr) {
-				error(e->token, "Redeclaration of the entry pointer procedure 'main'");
-			} else {
-				ctx->info->entry_point = e;
+		if (e->pkg->kind != Package_Runtime) {
+			if (pt->param_count != 0 ||
+			    pt->result_count != 0) {
+				gbString str = type_to_string(proc_type);
+				error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str);
+				gb_string_free(str);
+			}
+			if (pt->calling_convention != default_calling_convention()) {
+				error(e->token, "Procedure 'main' cannot have a custom calling convention");
+			}
+			pt->calling_convention = default_calling_convention();
+			if (e->pkg->kind == Package_Init) {
+				if (ctx->info->entry_point != nullptr) {
+					error(e->token, "Redeclaration of the entry pointer procedure 'main'");
+				} else {
+					ctx->info->entry_point = e;
+				}
 			}
 		}
 	}
@@ -924,7 +926,9 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 				      "\tother at %s",
 				      LIT(name), token_pos_to_string(pos));
 			} else if (name == "main") {
-				error(d->proc_lit, "The link name 'main' is reserved for internal use");
+				if (d->entity->pkg->kind != Package_Runtime) {
+					error(d->proc_lit, "The link name 'main' is reserved for internal use");
+				}
 			} else {
 				string_map_set(fp, key, e);
 			}

+ 41 - 33
src/checker.cpp

@@ -823,6 +823,7 @@ void init_universal(void) {
 	add_global_bool_constant("ODIN_NO_CRT",                   bc->no_crt);
 	add_global_bool_constant("ODIN_USE_SEPARATE_MODULES",     bc->use_separate_modules);
 	add_global_bool_constant("ODIN_TEST",                     bc->command_kind == Command_test);
+	add_global_bool_constant("ODIN_NO_ENTRY_POINT",           bc->no_entry_point);
 
 
 // Builtin Procedures
@@ -941,6 +942,8 @@ void init_checker_info(CheckerInfo *i) {
 	mutex_init(&i->foreign_mutex);
 
 	semaphore_init(&i->collect_semaphore);
+
+	mpmc_init(&i->intrinsics_entry_point_usage, a, 1<<10); // just waste some memory here, even if it probably never used
 }
 
 void destroy_checker_info(CheckerInfo *i) {
@@ -1228,7 +1231,7 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty
 	while (prev_expr != expr) {
 		prev_expr = expr;
 		expr->tav.mode = mode;
-		if (type != nullptr && expr->tav.type != nullptr && 
+		if (type != nullptr && expr->tav.type != nullptr &&
 		    is_type_any(type) && is_type_untyped(expr->tav.type)) {
 			// ignore
 		} else {
@@ -1424,7 +1427,7 @@ bool could_entity_be_lazy(Entity *e, DeclInfo *d) {
 					return false;
 				} else if (name == "linkage") {
 					return false;
-				} 
+				}
 			}
 		}
 	}
@@ -1704,7 +1707,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
 		add_type_info_type_internal(c, bt->RelativeSlice.slice_type);
 		add_type_info_type_internal(c, bt->RelativeSlice.base_integer);
 		break;
-		
+
 	case Type_Matrix:
 		add_type_info_type_internal(c, bt->Matrix.elem);
 		break;
@@ -1919,7 +1922,7 @@ void add_min_dep_type_info(Checker *c, Type *t) {
 		add_min_dep_type_info(c, bt->RelativeSlice.slice_type);
 		add_min_dep_type_info(c, bt->RelativeSlice.base_integer);
 		break;
-		
+
 	case Type_Matrix:
 		add_min_dep_type_info(c, bt->Matrix.elem);
 		break;
@@ -2020,7 +2023,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		str_lit("__init_context"),
 		str_lit("__type_info_of"),
 		str_lit("cstring_to_string"),
-		str_lit("_cleanup_runtime"), 
+		str_lit("_cleanup_runtime"),
 
 		// Pseudo-CRT required procedures
 		str_lit("memset"),
@@ -2047,7 +2050,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		str_lit("gnu_h2f_ieee"),
 		str_lit("gnu_f2h_ieee"),
 		str_lit("extendhfsf2"),
-		
+
 		// WASM Specific
 		str_lit("__ashlti3"),
 		str_lit("__multi3"),
@@ -2119,25 +2122,25 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 			if (e->flags & EntityFlag_Init) {
 				Type *t = base_type(e->type);
 				GB_ASSERT(t->kind == Type_Proc);
-				
+
 				bool is_init = true;
-				
+
 				if (t->Proc.param_count != 0 || t->Proc.result_count != 0) {
 					gbString str = type_to_string(t);
 					error(e->token, "@(init) procedures must have a signature type with no parameters nor results, got %s", str);
 					gb_string_free(str);
 					is_init = false;
 				}
-				
+
 				if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
 					error(e->token, "@(init) procedures must be declared at the file scope");
 					is_init = false;
 				}
-				
+
 				if (is_init) {
 					add_dependency_to_set(c, e);
 					array_add(&c->info.init_procedures, e);
-				}					
+				}
 			}
 			break;
 		}
@@ -3677,11 +3680,6 @@ void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) {
 			error(e->token, "'main' is reserved as the entry point procedure in the initial scope");
 			return;
 		}
-	} else if (pkg->kind == Package_Runtime) {
-		if (e->token.string == "main") {
-			error(e->token, "'main' is reserved as the entry point procedure in the initial scope");
-			return;
-		}
 	}
 
 	check_entity_decl(ctx, e, d, nullptr);
@@ -3841,7 +3839,7 @@ void add_import_dependency_node(Checker *c, Ast *decl, PtrMap<AstPackage *, Impo
 }
 
 Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) {
-	PtrMap<AstPackage *, ImportGraphNode *> M = {}; 
+	PtrMap<AstPackage *, ImportGraphNode *> M = {};
 	map_init(&M, heap_allocator(), 2*c->parser->packages.count);
 	defer (map_destroy(&M));
 
@@ -4121,11 +4119,11 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
 		mpmc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e);
 		add_entity_use(ctx, nullptr, e);
 	}
-	
+
 	if (has_asm_extension(fullpath)) {
 		if (build_context.metrics.arch != TargetArch_amd64 ||
 		    build_context.metrics.os   != TargetOs_windows) {
-			error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", 
+			error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s",
 			      LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch]));
 		}
 	}
@@ -4327,7 +4325,7 @@ void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) {
 	if (!build_context.threaded_checker) {
 		worker_count = 0;
 	}
-	
+
 	semaphore_post(&c->info.collect_semaphore, cast(i32)thread_count);
 	if (worker_count == 0) {
 		ThreadProcCheckerSection section_all = {};
@@ -4351,7 +4349,7 @@ void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) {
 	}
 	GB_ASSERT(remaining_count <= 0);
 
-	
+
 	for (isize i = 0; i < thread_count; i++) {
 		global_thread_pool_add_task(proc, thread_data+i);
 	}
@@ -4750,11 +4748,11 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc
 	ctx.decl = pi->decl;
 	ctx.procs_to_check_queue = procs_to_check_queue;
 	GB_ASSERT(procs_to_check_queue != nullptr);
-	
+
 	GB_ASSERT(pi->type->kind == Type_Proc);
 	TypeProc *pt = &pi->type->Proc;
 	String name = pi->token.string;
-	
+
 	if (pt->is_polymorphic && !pt->is_poly_specialized) {
 		Token token = pi->token;
 		if (pi->poly_def_node != nullptr) {
@@ -4832,7 +4830,7 @@ void check_unchecked_bodies(Checker *c) {
 			if (pi->body == nullptr) {
 				continue;
 			}
-			
+
 			debugf("unchecked: %.*s\n", LIT(e->token.string));
 			mpmc_enqueue(&c->procs_to_check_queue, pi);
 		}
@@ -4943,14 +4941,14 @@ void check_procedure_bodies(Checker *c) {
 	}
 	if (worker_count == 0) {
 		auto *this_queue = &c->procs_to_check_queue;
-		
+
 		UntypedExprInfoMap untyped = {};
 		map_init(&untyped, heap_allocator());
-		
+
 		for (ProcInfo *pi = nullptr; mpmc_dequeue(this_queue, &pi); /**/) {
 			consume_proc_info_queue(c, pi, this_queue, &untyped);
 		}
-		
+
 		map_destroy(&untyped);
 
 		debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed));
@@ -4994,7 +4992,7 @@ void check_procedure_bodies(Checker *c) {
 	GB_ASSERT(total_queued == original_queue_count);
 
 	semaphore_post(&c->procs_to_check_semaphore, cast(i32)thread_count);
-	
+
 	for (isize i = 0; i < thread_count; i++) {
 		global_thread_pool_add_task(thread_proc_body, thread_data+i);
 	}
@@ -5031,7 +5029,7 @@ void check_deferred_procedures(Checker *c) {
 		Entity *dst = src->Procedure.deferred_procedure.entity;
 		GB_ASSERT(dst != nullptr);
 		GB_ASSERT(dst->kind == Entity_Procedure);
-		
+
 		char const *attribute = "deferred_none";
 		switch (dst_kind) {
 		case DeferredProcedure_none:
@@ -5232,7 +5230,7 @@ GB_COMPARE_PROC(init_procedures_cmp) {
 		cmp = 0;
 		return cmp;
 	}
-	
+
 	if (x->pkg != y->pkg) {
 		isize order_x = x->pkg ? x->pkg->order : 0;
 		isize order_y = y->pkg ? y->pkg->order : 0;
@@ -5246,14 +5244,14 @@ GB_COMPARE_PROC(init_procedures_cmp) {
 		String fullpath_y = y->file ? y->file->fullpath : (String{});
 		String file_x = filename_from_path(fullpath_x);
 		String file_y = filename_from_path(fullpath_y);
-		
+
 		cmp = string_compare(file_x, file_y);
 		if (cmp) {
 			return cmp;
 		}
 	}
 
-	
+
 	cmp = u64_cmp(x->order_in_src, y->order_in_src);
 	if (cmp) {
 		return cmp;
@@ -5433,9 +5431,19 @@ void check_parsed_files(Checker *c) {
 	TIME_SECTION("sanity checks");
 	GB_ASSERT(c->info.entity_queue.count.load(std::memory_order_relaxed) == 0);
 	GB_ASSERT(c->info.definition_queue.count.load(std::memory_order_relaxed) == 0);
-	
+
 	TIME_SECTION("sort init procedures");
 	check_sort_init_procedures(c);
 
+	if (c->info.intrinsics_entry_point_usage.count > 0) {
+		TIME_SECTION("check intrinsics.__entry_point usage");
+		Ast *node = nullptr;
+		while (mpmc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) {
+			if (c->info.entry_point == nullptr && node != nullptr) {
+				warning(node, "usage of intrinsics.__entry_point will be a no-op");
+			}
+		}
+	}
+
 	TIME_SECTION("type check finish");
 }

+ 3 - 0
src/checker.hpp

@@ -338,6 +338,9 @@ struct CheckerInfo {
 	MPMCQueue<Entity *> required_global_variable_queue;
 	MPMCQueue<Entity *> required_foreign_imports_through_force_queue;
 
+	MPMCQueue<Ast *> intrinsics_entry_point_usage;
+
+
 };
 
 struct CheckerContext {

+ 6 - 1
src/checker_builtin_procs.hpp

@@ -250,6 +250,8 @@ BuiltinProc__type_simple_boolean_end,
 
 BuiltinProc__type_end,
 
+	BuiltinProc___entry_point,
+
 	BuiltinProc_COUNT,
 };
 gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -497,6 +499,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 
 	{STR_LIT("type_equal_proc"),  1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
-	
+
+
 	{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
+
+	{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 };

+ 10 - 5
src/llvm_backend.cpp

@@ -873,7 +873,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 	} else {
 		if (m->info->entry_point != nullptr) {
 			lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point);
-			lb_emit_call(p, entry_point, {});
+			lb_emit_call(p, entry_point, {}, ProcInlining_no_inline);
 		}
 	}
 
@@ -1408,6 +1408,7 @@ void lb_generate_code(lbGenerator *gen) {
 	Entity *entry_point = info->entry_point;
 	bool has_dll_main = false;
 	bool has_win_main = false;
+	bool already_has_entry_point = false;
 
 	for_array(i, info->entities) {
 		Entity *e = info->entities[i];
@@ -1425,7 +1426,9 @@ void lb_generate_code(lbGenerator *gen) {
 			if (e->Procedure.is_export ||
 			    (e->Procedure.link_name.len > 0) ||
 			    ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) {
-				if (!has_dll_main && name == "DllMain") {
+				if (name == "main" || name == "DllMain" || name == "WinMain" || name == "mainCRTStartup") {
+					already_has_entry_point = true;
+				} else if (!has_dll_main && name == "DllMain") {
 					has_dll_main = true;
 				} else if (!has_win_main && name == "WinMain") {
 					has_win_main = true;
@@ -1643,9 +1646,11 @@ void lb_generate_code(lbGenerator *gen) {
 	}
 
 
-	if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
-		TIME_SECTION("LLVM main");
-		lb_create_main_procedure(default_module, startup_runtime);
+	if (!already_has_entry_point) {
+		if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
+			TIME_SECTION("LLVM main");
+			lb_create_main_procedure(default_module, startup_runtime);
+		}
 	}
 
 	for_array(j, gen->modules.entries) {

+ 8 - 0
src/llvm_backend_proc.cpp

@@ -1965,6 +1965,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 			return res;
 		}
 		
+	case BuiltinProc___entry_point:
+		if (p->module->info->entry_point) {
+			lbValue entry_point = lb_find_procedure_value_from_entity(p->module, p->module->info->entry_point);
+			GB_ASSERT(entry_point.value != nullptr);
+			lb_emit_call(p, entry_point, {});
+		}
+		return {};
+
 	case BuiltinProc_syscall:
 		{
 			unsigned arg_count = cast(unsigned)ce->args.count;