From 8f91e9307c6ea7a243001efb2ecb135d37587301 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Mon, 10 Jan 2022 17:57:33 -0500 Subject: shared library fixes --- src/llvm_backend.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 5acd2a80f..1a657e47b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1238,12 +1238,18 @@ void lb_generate_code(lbGenerator *gen) { // NOTE(bill, 2021-05-04): Target machines must be unique to each module because they are not thread safe auto target_machines = array_make(permanent_allocator(), gen->modules.entries.count); + // NOTE(dweiler): Dynamic libraries require position-independent code. + LLVMRelocMode reloc_mode = LLVMRelocDefault; + if (build_context.build_mode == BuildMode_DynamicLibrary) { + reloc_mode = LLVMRelocPIC; + } + for_array(i, gen->modules.entries) { target_machines[i] = LLVMCreateTargetMachine( target, target_triple, llvm_cpu, llvm_features, code_gen_level, - LLVMRelocDefault, + reloc_mode, code_mode); LLVMSetModuleDataLayout(gen->modules.entries[i].value->mod, LLVMCreateTargetDataLayout(target_machines[i])); } -- cgit v1.2.3 From 7e4067c44ceb21b4ca0ce89e501df1bf9de106b7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 19:18:54 +0000 Subject: Begin work to move entry point code to Odin itself rather than in C++ side --- core/intrinsics/intrinsics.odin | 5 +++ core/runtime/procs_windows_amd64.odin | 2 +- src/check_builtin.cpp | 6 +++ src/check_decl.cpp | 36 +++++++++-------- src/checker.cpp | 74 +++++++++++++++++++---------------- src/checker.hpp | 3 ++ src/checker_builtin_procs.hpp | 7 +++- src/llvm_backend.cpp | 15 ++++--- src/llvm_backend_proc.cpp | 8 ++++ 9 files changed, 100 insertions(+), 56 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 2da7a7439..803b04d17 100644 --- a/core/intrinsics/intrinsics.odin +++ b/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() --- \ No newline at end of file diff --git a/core/runtime/procs_windows_amd64.odin b/core/runtime/procs_windows_amd64.odin index 273bb57b2..e430357be 100644 --- a/core/runtime/procs_windows_amd64.odin +++ b/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" -} \ No newline at end of file +} diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index dc8c209c9..82ad6d161 100644 --- a/src/check_builtin.cpp +++ b/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; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3f7d2f33d..f9bc17ba4 100644 --- a/src/check_decl.cpp +++ b/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); } diff --git a/src/checker.cpp b/src/checker.cpp index b4c5d0c72..42575f88d 100644 --- a/src/checker.cpp +++ b/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 generate_import_dependency_graph(Checker *c) { - PtrMap M = {}; + PtrMap 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"); } diff --git a/src/checker.hpp b/src/checker.hpp index db59ebce7..9a8753efd 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -338,6 +338,9 @@ struct CheckerInfo { MPMCQueue required_global_variable_queue; MPMCQueue required_foreign_imports_through_force_queue; + MPMCQueue intrinsics_entry_point_usage; + + }; struct CheckerContext { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index abd9fc6ca..e8f5174c0 100644 --- a/src/checker_builtin_procs.hpp +++ b/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}, }; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1a657e47b..b42ea8211 100644 --- a/src/llvm_backend.cpp +++ b/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) { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 50aa5f6db..10b8a093f 100644 --- a/src/llvm_backend_proc.cpp +++ b/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; -- cgit v1.2.3 From 5ec93677a04f17f38117f0cf301d9a72036a04e7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 19:27:49 +0000 Subject: Correct look for entry point in llvm backend (Windows only currently) --- src/llvm_backend.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index b42ea8211..0b4c674ac 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1406,19 +1406,15 @@ void lb_generate_code(lbGenerator *gen) { isize global_variable_max_count = 0; 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]; String name = e->token.string; - bool is_global = e->pkg != nullptr; - if (e->kind == Entity_Variable) { global_variable_max_count++; - } else if (e->kind == Entity_Procedure && !is_global) { + } else if (e->kind == Entity_Procedure) { if ((e->scope->flags&ScopeFlag_Init) && name == "main") { GB_ASSERT(e == entry_point); // entry_point = e; @@ -1426,12 +1422,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 (name == "main" || name == "DllMain" || name == "WinMain" || name == "mainCRTStartup") { + String link_name = e->Procedure.link_name; + if (link_name == "main" || link_name == "DllMain" || link_name == "WinMain" || link_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; } } } @@ -1647,10 +1640,8 @@ void lb_generate_code(lbGenerator *gen) { 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); - } + TIME_SECTION("LLVM main"); + lb_create_main_procedure(default_module, startup_runtime); } for_array(j, gen->modules.entries) { -- cgit v1.2.3 From fb0a3ab7c14d4bc3b821cef723ec6ea3e956c956 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:07:17 +0000 Subject: Correct linkage for entry point procedures on Windows --- src/checker.cpp | 8 +++++++- src/llvm_backend.cpp | 23 +++++++++++------------ src/llvm_backend_proc.cpp | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 42575f88d..f261c8f4a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2113,11 +2113,15 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { case Entity_Variable: if (e->Variable.is_export) { add_dependency_to_set(c, e); + } else if (e->flags & EntityFlag_Require) { + add_dependency_to_set(c, e); } break; case Entity_Procedure: if (e->Procedure.is_export) { add_dependency_to_set(c, e); + } else if (e->flags & EntityFlag_Require) { + add_dependency_to_set(c, e); } if (e->flags & EntityFlag_Init) { Type *t = base_type(e->type); @@ -5440,7 +5444,9 @@ void check_parsed_files(Checker *c) { 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"); + if (node->file()->pkg->kind != Package_Runtime) { + warning(node, "usage of intrinsics.__entry_point will be a no-op"); + } } } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0b4c674ac..1c3cf86ac 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1405,7 +1405,6 @@ void lb_generate_code(lbGenerator *gen) { isize global_variable_max_count = 0; - Entity *entry_point = info->entry_point; bool already_has_entry_point = false; for_array(i, info->entities) { @@ -1416,14 +1415,17 @@ void lb_generate_code(lbGenerator *gen) { global_variable_max_count++; } else if (e->kind == Entity_Procedure) { if ((e->scope->flags&ScopeFlag_Init) && name == "main") { - GB_ASSERT(e == entry_point); - // entry_point = e; + GB_ASSERT(e == info->entry_point); } if (e->Procedure.is_export || (e->Procedure.link_name.len > 0) || ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { String link_name = e->Procedure.link_name; - if (link_name == "main" || link_name == "DllMain" || link_name == "WinMain" || link_name == "mainCRTStartup") { + if (link_name == "main" || + link_name == "DllMain" || + link_name == "WinMain" || + link_name == "wWinMain" || + link_name == "mainCRTStartup") { already_has_entry_point = true; } } @@ -1562,6 +1564,11 @@ void lb_generate_code(lbGenerator *gen) { } } + TIME_SECTION("LLVM Runtime Type Information Creation"); + lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); + + TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); + lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { @@ -1621,14 +1628,6 @@ void lb_generate_code(lbGenerator *gen) { } } - - TIME_SECTION("LLVM Runtime Type Information Creation"); - lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); - - TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); - lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); - - TIME_SECTION("LLVM Procedure Generation"); for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 10b8a093f..c52572588 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -304,7 +304,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) { { lbValue *found = string_map_get(&m->members, link_name); - GB_ASSERT(found == nullptr); + GB_ASSERT_MSG(found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name)); } lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); -- cgit v1.2.3 From 6aa80ee8e4fc8f96c24e9881a5833f14c86eff05 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 15:38:09 +0000 Subject: Correct `_start` as an entry point --- src/llvm_backend.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1c3cf86ac..7a7f20f8d 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1420,13 +1420,16 @@ 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)) { - String link_name = e->Procedure.link_name; - if (link_name == "main" || - link_name == "DllMain" || - link_name == "WinMain" || - link_name == "wWinMain" || - link_name == "mainCRTStartup") { - already_has_entry_point = true; + String link_name = e->Procedure.link_name; + if (e->pkg->kind == Package_Runtime) { + if (link_name == "main" || + link_name == "DllMain" || + link_name == "WinMain" || + link_name == "wWinMain" || + link_name == "mainCRTStartup" || + link_name == "_start") { + already_has_entry_point = true; + } } } } -- cgit v1.2.3 From 29ebe0c3c92724f74392687ee859a0c2db503b0d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 17:40:00 +0000 Subject: Rename architecture `386` to `i386` --- core/c/c.odin | 2 +- core/crypto/_fiat/field_poly1305/field.odin | 2 +- core/crypto/chacha20/chacha20.odin | 2 +- core/runtime/entry_windows.odin | 2 +- core/runtime/procs_windows_386.odin | 28 --------------------------- core/runtime/procs_windows_i386.odin | 28 +++++++++++++++++++++++++++ core/sys/cpu/cpu_x86.odin | 2 +- core/sys/unix/syscalls_linux.odin | 2 +- src/build_settings.cpp | 30 ++++++++++++++--------------- src/check_builtin.cpp | 2 +- src/llvm_abi.cpp | 2 +- src/llvm_backend.cpp | 4 ++-- src/llvm_backend_expr.cpp | 2 +- src/llvm_backend_proc.cpp | 4 ++-- src/llvm_backend_utility.cpp | 2 +- src/microsoft_craziness.h | 10 +++++----- 16 files changed, 62 insertions(+), 62 deletions(-) delete mode 100644 core/runtime/procs_windows_386.odin create mode 100644 core/runtime/procs_windows_i386.odin (limited to 'src/llvm_backend.cpp') diff --git a/core/c/c.odin b/core/c/c.odin index 139d9920a..d0b8e377f 100644 --- a/core/c/c.odin +++ b/core/c/c.odin @@ -48,7 +48,7 @@ int_least64_t :: builtin.i64 uint_least64_t :: builtin.u64 // Same on Windows, Linux, and FreeBSD -when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { +when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { int_fast8_t :: builtin.i8 uint_fast8_t :: builtin.u8 int_fast16_t :: builtin.i32 diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index bfb7cf1f9..4ed8acbff 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a assert(len(arg1) == 16) - when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { + when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { // While it may be unwise to do deserialization here on our // own when fiat-crypto provides equivalent functionality, // doing it this way provides a little under 3x performance diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin index f6f551692..e32dacb2c 100644 --- a/core/crypto/chacha20/chacha20.odin +++ b/core/crypto/chacha20/chacha20.odin @@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { // Until dedicated assembly can be written leverage the fact that // the callers of this routine ensure that src/dst are valid. - when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { + when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { // util.PUT_U32_LE/util.U32_LE are not required on little-endian // systems that also happen to not be strict about aligned // memory access. diff --git a/core/runtime/entry_windows.odin b/core/runtime/entry_windows.odin index 97a5bebe6..35a6bb421 100644 --- a/core/runtime/entry_windows.odin +++ b/core/runtime/entry_windows.odin @@ -22,7 +22,7 @@ when ODIN_BUILD_MODE == .Dynamic { return true } } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { - when ODIN_ARCH == "386" || ODIN_NO_CRT { + when ODIN_ARCH == "i386" || ODIN_NO_CRT { @(link_name="mainCRTStartup", linkage="strong", require) mainCRTStartup :: proc "stdcall" () -> i32 { context = default_context() diff --git a/core/runtime/procs_windows_386.odin b/core/runtime/procs_windows_386.odin deleted file mode 100644 index f810197f1..000000000 --- a/core/runtime/procs_windows_386.odin +++ /dev/null @@ -1,28 +0,0 @@ -//+private -package runtime - -@require foreign import "system:int64.lib" - -foreign import kernel32 "system:Kernel32.lib" - -windows_trap_array_bounds :: proc "contextless" () -> ! { - DWORD :: u32 - ULONG_PTR :: uint - - EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C - - foreign kernel32 { - RaiseException :: proc "stdcall" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! --- - } - - RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, nil) -} - -windows_trap_type_assertion :: proc "contextless" () -> ! { - windows_trap_array_bounds() -} - -@(private, export, link_name="_fltused") _fltused: i32 = 0x9875 - -@(private, export, link_name="_tls_index") _tls_index: u32 -@(private, export, link_name="_tls_array") _tls_array: u32 diff --git a/core/runtime/procs_windows_i386.odin b/core/runtime/procs_windows_i386.odin new file mode 100644 index 000000000..f810197f1 --- /dev/null +++ b/core/runtime/procs_windows_i386.odin @@ -0,0 +1,28 @@ +//+private +package runtime + +@require foreign import "system:int64.lib" + +foreign import kernel32 "system:Kernel32.lib" + +windows_trap_array_bounds :: proc "contextless" () -> ! { + DWORD :: u32 + ULONG_PTR :: uint + + EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C + + foreign kernel32 { + RaiseException :: proc "stdcall" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! --- + } + + RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, nil) +} + +windows_trap_type_assertion :: proc "contextless" () -> ! { + windows_trap_array_bounds() +} + +@(private, export, link_name="_fltused") _fltused: i32 = 0x9875 + +@(private, export, link_name="_tls_index") _tls_index: u32 +@(private, export, link_name="_tls_array") _tls_array: u32 diff --git a/core/sys/cpu/cpu_x86.odin b/core/sys/cpu/cpu_x86.odin index 8f3560a87..146822e61 100644 --- a/core/sys/cpu/cpu_x86.odin +++ b/core/sys/cpu/cpu_x86.odin @@ -1,4 +1,4 @@ -//+build 386, amd64 +//+build i386, amd64 package sys_cpu _cache_line_size :: 64; diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 25c5ed0a1..3dc3d2c74 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -675,7 +675,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 -} else when ODIN_ARCH == "386" { +} else when ODIN_ARCH == "i386" { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 diff --git a/src/build_settings.cpp b/src/build_settings.cpp index bafa93042..5e4534517 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -29,7 +29,7 @@ enum TargetArchKind { TargetArch_Invalid, TargetArch_amd64, - TargetArch_386, + TargetArch_i386, TargetArch_arm64, TargetArch_wasm32, TargetArch_wasm64, @@ -63,7 +63,7 @@ String target_os_names[TargetOs_COUNT] = { String target_arch_names[TargetArch_COUNT] = { str_lit(""), str_lit("amd64"), - str_lit("386"), + str_lit("i386"), str_lit("arm64"), str_lit("wasm32"), str_lit("wasm64"), @@ -269,9 +269,9 @@ bool global_ignore_warnings(void) { } -gb_global TargetMetrics target_windows_386 = { +gb_global TargetMetrics target_windows_i386 = { TargetOs_windows, - TargetArch_386, + TargetArch_i386, 4, 8, str_lit("i386-pc-windows-msvc"), @@ -285,9 +285,9 @@ gb_global TargetMetrics target_windows_amd64 = { str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; -gb_global TargetMetrics target_linux_386 = { +gb_global TargetMetrics target_linux_i386 = { TargetOs_linux, - TargetArch_386, + TargetArch_i386, 4, 8, str_lit("i386-pc-linux-gnu"), @@ -328,9 +328,9 @@ gb_global TargetMetrics target_darwin_arm64 = { str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct? }; -gb_global TargetMetrics target_freebsd_386 = { +gb_global TargetMetrics target_freebsd_i386 = { TargetOs_freebsd, - TargetArch_386, + TargetArch_i386, 4, 8, str_lit("i386-unknown-freebsd-elf"), @@ -401,12 +401,12 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("darwin_amd64"), &target_darwin_amd64 }, { str_lit("darwin_arm64"), &target_darwin_arm64 }, { str_lit("essence_amd64"), &target_essence_amd64 }, - { str_lit("linux_386"), &target_linux_386 }, + { str_lit("linux_i386"), &target_linux_i386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("linux_arm64"), &target_linux_arm64 }, - { str_lit("windows_386"), &target_windows_386 }, + { str_lit("windows_i386"), &target_windows_i386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, - { str_lit("freebsd_386"), &target_freebsd_386 }, + { str_lit("freebsd_i386"), &target_freebsd_i386 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, @@ -879,13 +879,13 @@ void init_build_context(TargetMetrics *cross_target) { #endif #else #if defined(GB_SYSTEM_WINDOWS) - metrics = &target_windows_386; + metrics = &target_windows_i386; #elif defined(GB_SYSTEM_OSX) #error "Build Error: Unsupported architecture" #elif defined(GB_SYSTEM_FREEBSD) - metrics = &target_freebsd_386; + metrics = &target_freebsd_i386; #else - metrics = &target_linux_386; + metrics = &target_linux_i386; #endif #endif @@ -932,7 +932,7 @@ void init_build_context(TargetMetrics *cross_target) { bc->link_flags = str_lit("-arch x86-64 "); break; } - } else if (bc->metrics.arch == TargetArch_386) { + } else if (bc->metrics.arch == TargetArch_i386) { switch (bc->metrics.os) { case TargetOs_windows: bc->link_flags = str_lit("/machine:x86 "); diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 82ad6d161..a42741976 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3225,7 +3225,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case TargetOs_essence: case TargetOs_freebsd: switch (build_context.metrics.arch) { - case TargetArch_386: + case TargetArch_i386: case TargetArch_amd64: case TargetArch_arm64: max_arg_count = 7; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 42f05bb27..310df6639 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1193,7 +1193,7 @@ LB_ABI_INFO(lb_get_abi_info) { } else { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } - case TargetArch_386: + case TargetArch_i386: return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); case TargetArch_arm64: return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7a7f20f8d..63fb5d4e9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -783,7 +783,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true); params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true); call_cleanup = false; - } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_386 || build_context.no_crt)) { + } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) { name = str_lit("mainCRTStartup"); } else if (is_arch_wasm()) { name = str_lit("_start"); @@ -1140,7 +1140,7 @@ void lb_generate_code(lbGenerator *gen) { switch (build_context.metrics.arch) { case TargetArch_amd64: - case TargetArch_386: + case TargetArch_i386: LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); LLVMInitializeX86TargetMC(); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0b2f6b3fd..1f0ed6434 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -508,7 +508,7 @@ bool lb_is_matrix_simdable(Type *t) { case TargetArch_arm64: // TODO(bill): determine when this is fine return true; - case TargetArch_386: + case TargetArch_i386: case TargetArch_wasm32: case TargetArch_wasm64: return false; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index eccf9b360..2a6eb6bb3 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1361,7 +1361,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_cpu_relax: - if (build_context.metrics.arch == TargetArch_386 || + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("pause"), {}); @@ -2018,7 +2018,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; - case TargetArch_386: + case TargetArch_i386: { GB_ASSERT(arg_count <= 7); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 3fe96459f..5b1b11b44 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1494,7 +1494,7 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t case TargetArch_arm64: // possible break; - case TargetArch_386: + case TargetArch_i386: case TargetArch_wasm32: case TargetArch_wasm64: is_possible = false; diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h index 02f14dda3..b4f815284 100644 --- a/src/microsoft_craziness.h +++ b/src/microsoft_craziness.h @@ -460,7 +460,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res wchar_t *library_path = nullptr; if (build_context.metrics.arch == TargetArch_amd64) { library_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\lib\\x64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { library_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\lib\\x86\\"); } else { continue; @@ -472,7 +472,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res wchar_t *link_exe_path = nullptr; if (build_context.metrics.arch == TargetArch_amd64) { link_exe_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\bin\\Hostx64\\x64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { link_exe_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\bin\\Hostx86\\x86\\"); } else { continue; @@ -529,7 +529,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res if (build_context.metrics.arch == TargetArch_amd64) { lib_path = concat(buffer, L"VC\\Lib\\amd64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { lib_path = concat(buffer, L"VC\\Lib\\"); } else { continue; @@ -542,7 +542,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res if (os_file_exists(vcruntime_filename)) { if (build_context.metrics.arch == TargetArch_amd64) { result->vs_exe_path = concat(buffer, L"VC\\bin\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { // result->vs_exe_path = concat(buffer, L"VC\\bin\\amd64_x86\\"); result->vs_exe_path = concat(buffer, L"VC\\bin\\x86_amd64\\"); } else { @@ -573,7 +573,7 @@ Find_Result find_visual_studio_and_windows_sdk() { if (build_context.metrics.arch == TargetArch_amd64) { result.windows_sdk_um_library_path = concat(result.windows_sdk_root, L"um\\x64\\"); result.windows_sdk_ucrt_library_path = concat(result.windows_sdk_root, L"ucrt\\x64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { result.windows_sdk_um_library_path = concat(result.windows_sdk_root, L"um\\x86\\"); result.windows_sdk_ucrt_library_path = concat(result.windows_sdk_root, L"ucrt\\x86\\"); } -- cgit v1.2.3 From 3f59c45740403e538a23f50c2fe4cd25e815531b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 17:42:10 +0000 Subject: Remove `main` creation in llvm_backend.cpp and have it done purely in the runtime package (partial bootstrapping) --- src/llvm_backend.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 63fb5d4e9..304effb7f 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1572,6 +1572,7 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); + gb_unused(startup_runtime); TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { @@ -1640,12 +1641,6 @@ void lb_generate_code(lbGenerator *gen) { } } - - if (!already_has_entry_point) { - TIME_SECTION("LLVM main"); - lb_create_main_procedure(default_module, startup_runtime); - } - for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; for_array(i, m->missing_procedures_to_check) { -- cgit v1.2.3 From 0cc40db565a9c4b99e6fa0844b9ac512558626e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Feb 2022 17:04:55 +0000 Subject: Begin work on support objc intrinsics --- src/check_builtin.cpp | 223 +++++++++++++++++++++++++++++++++++++++++- src/check_decl.cpp | 3 + src/checker.cpp | 36 +++++++ src/checker.hpp | 15 ++- src/checker_builtin_procs.hpp | 6 ++ src/entity.cpp | 1 + src/llvm_backend.cpp | 59 ++++++++++- src/llvm_backend.hpp | 6 +- src/llvm_backend_general.cpp | 8 +- src/llvm_backend_proc.cpp | 3 + src/llvm_backend_utility.cpp | 96 ++++++++++++++++++ src/types.cpp | 10 ++ 12 files changed, 459 insertions(+), 7 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1fb3d6037..8ada77b12 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -143,6 +143,219 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na } +bool does_require_msgSend_stret(Type *return_type) { + if (return_type == nullptr) { + return false; + } + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { + i64 struct_limit = type_size_of(t_uintptr) << 1; + return type_size_of(return_type) > struct_limit; + } + if (build_context.metrics.arch == TargetArch_arm64) { + return false; + } + + // if (build_context.metrics.arch == TargetArch_arm32) { + // i64 struct_limit = type_size_of(t_uintptr); + // // NOTE(bill): This is technically wrong + // return is_type_struct(return_type) && !is_type_raw_union(return_type) && type_size_of(return_type) > struct_limit; + // } + GB_PANIC("unsupported architecture"); + return false; +} + +ObjcMsgKind get_objc_proc_kind(Type *return_type) { + if (return_type == nullptr) { + return ObjcMsg_normal; + } + + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { + if (is_type_float(return_type)) { + return ObjcMsg_fpret; + } + if (build_context.metrics.arch == TargetArch_amd64) { + if (is_type_complex(return_type)) { + // URL: https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/message.h#L143-L159 + return ObjcMsg_fpret; + } + } + } + if (build_context.metrics.arch != TargetArch_arm64) { + if (does_require_msgSend_stret(return_type)) { + return ObjcMsg_stret; + } + } + return ObjcMsg_normal; +} + +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types) { + ObjcMsgKind kind = get_objc_proc_kind(return_type); + + Scope *scope = create_scope(c->info, nullptr); + + // NOTE(bill, 2022-02-08): the backend's ABI handling should handle this correctly, I hope + Type *params = alloc_type_tuple(); + { + auto variables = array_make(permanent_allocator(), 0, param_types.count); + + for_array(i, param_types) { + Type *type = param_types[i]; + Entity *param = alloc_entity_param(scope, blank_token, type, false, true); + array_add(&variables, param); + } + params->Tuple.variables = slice_from_array(variables); + } + + Type *results = alloc_type_tuple(); + if (return_type) { + auto variables = array_make(permanent_allocator(), 1); + results->Tuple.variables = slice_from_array(variables); + Entity *param = alloc_entity_param(scope, blank_token, return_type, false, true); + results->Tuple.variables[0] = param; + } + + + ObjcMsgData data = {}; + data.kind = kind; + data.proc_type = alloc_type_proc(scope, params, param_types.count, results, results->Tuple.variables.count, false, ProcCC_CDecl); + + mutex_lock(&c->info->objc_types_mutex); + map_set(&c->info->objc_msgSend_types, call, data); + mutex_unlock(&c->info->objc_types_mutex); + + add_package_dependency(c, "runtime", "objc_lookUpClass"); + add_package_dependency(c, "runtime", "sel_registerName"); + + add_package_dependency(c, "runtime", "objc_msgSend"); + add_package_dependency(c, "runtime", "objc_msgSend_fpret"); + add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); + add_package_dependency(c, "runtime", "objc_msgSend_stret"); +} + +bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { + auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool { + Operand op = {}; + check_expr(c, &op, expr); + if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) { + if (name_) *name_ = op.value.value_string; + return true; + } + gbString e = expr_to_string(op.expr); + gbString t = type_to_string(op.type); + error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + }; + String builtin_name = builtin_procs[id].name; + + if (build_context.metrics.os != TargetOs_darwin) { + error(call, "'%.*s' only works on darwin", LIT(builtin_name)); + return false; + } + + + ast_node(ce, CallExpr, call); + switch (id) { + default: + GB_PANIC("Implement objective built-in procedure: %.*s", LIT(builtin_name)); + return false; + + case BuiltinProc_objc_send: { + Type *return_type = nullptr; + + Operand rt = {}; + check_expr_or_type(c, &rt, ce->args[0]); + if (rt.mode == Addressing_Type) { + return_type = rt.type; + } else if (is_operand_nil(rt)) { + return_type = nullptr; + } else { + gbString e = expr_to_string(rt.expr); + error(rt.expr, "'%.*s' expected a type or nil to define the return type of the Objective-C call, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + + operand->type = return_type; + operand->mode = return_type ? Addressing_Value : Addressing_NoValue; + + String class_name = {}; + String sel_name = {}; + + Type *sel_type = t_objc_SEL; + Operand self = {}; + check_expr_or_type(c, &self, ce->args[1]); + if (self.mode == Addressing_Type) { + if (!internal_check_is_assignable_to(self.type, t_objc_object)) { + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (!(self.type->kind == Type_Named && + self.type->Named.type_name != nullptr && + self.type->Named.type_name->TypeName.objc_class_name != "")) { + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=) , got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + sel_type = t_objc_Class; + } else if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) { + gbString e = expr_to_string(self.expr); + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s'3 expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind); + gb_string_free(t); + gb_string_free(e); + return false; + } else if (!is_type_pointer(self.type)) { + gbString e = expr_to_string(self.expr); + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } else { + Type *type = type_deref(self.type); + if (!(type->kind == Type_Named && + type->Named.type_name != nullptr && + type->Named.type_name->TypeName.objc_class_name != "")) { + gbString t = type_to_string(type); + error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=) , got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + } + + + if (!is_constant_string(c, builtin_name, ce->args[2], &sel_name)) { + return false; + } + + isize const arg_offset = 1; + auto param_types = slice_make(permanent_allocator(), ce->args.count-arg_offset); + param_types[0] = t_objc_id; + param_types[1] = sel_type; + + for (isize i = 2+arg_offset; i < ce->args.count; i++) { + Operand x = {}; + check_expr(c, &x, ce->args[i]); + param_types[i-arg_offset] = x.type; + } + + add_objc_proc_type(c, call, return_type, param_types); + + return true; + } break; + + case BuiltinProc_objc_create: { + GB_PANIC("TODO: BuiltinProc_objc_create"); + return false; + } break; + } +} bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); @@ -179,6 +392,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_len: case BuiltinProc_min: case BuiltinProc_max: + case BuiltinProc_objc_send: + case BuiltinProc_objc_create: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -202,7 +417,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } - String builtin_name = builtin_procs[id].name;; + String builtin_name = builtin_procs[id].name; if (ce->args.count > 0) { @@ -219,6 +434,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); break; + case BuiltinProc_objc_send: + case BuiltinProc_objc_create: + return check_builtin_objc_procedure(c, operand, call, id, type_hint); + case BuiltinProc___entry_point: operand->mode = Addressing_NoValue; operand->type = nullptr; @@ -3815,6 +4034,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = t_hasher_proc; break; } + + } return true; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f6dade812..243dbbbc6 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -338,6 +338,9 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) if (decl != nullptr) { AttributeContext ac = {}; check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac); + if (e->kind == Entity_TypeName && ac.objc_class != "") { + e->TypeName.objc_class_name = ac.objc_class; + } } diff --git a/src/checker.cpp b/src/checker.cpp index 7fb4fdb29..2ab487592 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -841,6 +841,17 @@ void add_global_enum_constant(Slice const &fields, char const *name, i GB_PANIC("Unfound enum value for global constant: %s %lld", name, cast(long long)value); } +Type *add_global_type_name(Scope *scope, String const &type_name, Type *backing_type) { + Entity *e = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); + Type *named_type = alloc_type_named(type_name, backing_type, e); + e->type = named_type; + set_base_type(named_type, backing_type); + if (scope_insert(scope, e)) { + compiler_error("double declaration of %.*s", LIT(e->token.string)); + } + return named_type; +} + void init_universal(void) { BuildContext *bc = &build_context; @@ -985,6 +996,17 @@ void init_universal(void) { t_f64_ptr = alloc_type_pointer(t_f64); t_u8_slice = alloc_type_slice(t_u8); t_string_slice = alloc_type_slice(t_string); + + // intrinsics types for objective-c stuff + { + t_objc_object = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_object"), alloc_type_struct()); + t_objc_selector = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_selector"), alloc_type_struct()); + t_objc_class = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_class"), alloc_type_struct()); + + t_objc_id = alloc_type_pointer(t_objc_object); + t_objc_SEL = alloc_type_pointer(t_objc_selector); + t_objc_Class = alloc_type_pointer(t_objc_class); + } } @@ -1041,6 +1063,9 @@ void init_checker_info(CheckerInfo *i) { 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 + + mutex_init(&i->objc_types_mutex); + map_init(&i->objc_msgSend_types, a); } void destroy_checker_info(CheckerInfo *i) { @@ -1073,6 +1098,9 @@ void destroy_checker_info(CheckerInfo *i) { mutex_destroy(&i->type_and_value_mutex); mutex_destroy(&i->identifier_uses_mutex); mutex_destroy(&i->foreign_mutex); + + mutex_destroy(&i->objc_types_mutex); + map_destroy(&i->objc_msgSend_types); } CheckerContext make_checker_context(Checker *c) { @@ -3161,6 +3189,14 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) { } else if (name == "private") { // NOTE(bill): Handled elsewhere `check_collect_value_decl` return true; + } else if (name == "objc_class") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind != ExactValue_String || ev.value_string == "") { + error(elem, "Expected a non-empty string value for '%.*s'", LIT(name)); + } else { + ac->objc_class = ev.value_string; + } + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index 9a8753efd..b812e10a4 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -107,6 +107,7 @@ struct AttributeContext { String thread_local_model; String deprecated_message; String warning_message; + String objc_class; DeferredProcedure deferred_procedure; bool is_export : 1; bool is_static : 1; @@ -267,6 +268,17 @@ struct UntypedExprInfo { typedef PtrMap UntypedExprInfoMap; typedef MPMCQueue ProcBodyQueue; +enum ObjcMsgKind : u32 { + ObjcMsg_normal, + ObjcMsg_fpret, + ObjcMsg_fp2ret, + ObjcMsg_stret, +}; +struct ObjcMsgData { + ObjcMsgKind kind; + Type *proc_type; +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -340,7 +352,8 @@ struct CheckerInfo { MPMCQueue intrinsics_entry_point_usage; - + BlockingMutex objc_types_mutex; + PtrMap objc_msgSend_types; }; struct CheckerContext { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index d833a055f..1a9d7d7a0 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -250,6 +250,9 @@ BuiltinProc__type_end, BuiltinProc___entry_point, + BuiltinProc_objc_send, + BuiltinProc_objc_create, + BuiltinProc_COUNT, }; gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { @@ -500,4 +503,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_create"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/entity.cpp b/src/entity.cpp index 8327a517e..4d5b3b9e1 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -186,6 +186,7 @@ struct Entity { Type * type_parameter_specialization; String ir_mangled_name; bool is_type_alias; + String objc_class_name; } TypeName; struct { u64 tags; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 304effb7f..7941c65a3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -652,7 +652,53 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) { return p; } -lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, Array &global_variables) { // Startup Runtime +lbProcedure *lb_create_objc_names(lbModule *main_module) { + if (build_context.metrics.os != TargetOs_darwin) { + return nullptr; + } + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); + lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit("__$init_objc_names"), proc_type); + p->is_startup = true; + return p; +} + +void lb_finalize_objc_names(lbProcedure *p) { + if (p == nullptr) { + return; + } + lbModule *m = p->module; + + LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); + lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); + LLVMFinalizeFunctionPassManager(default_function_pass_manager); + + LLVMSetLinkage(p->value, LLVMInternalLinkage); + lb_begin_procedure_body(p); + for_array(i, m->objc_classes.entries) { + auto const &entry = m->objc_classes.entries[i]; + String name = entry.key.string; + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); + lb_addr_store(p, entry.value, ptr); + } + + for_array(i, m->objc_selectors.entries) { + auto const &entry = m->objc_selectors.entries[i]; + String name = entry.key.string; + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); + lb_addr_store(p, entry.value, ptr); + } + + lb_end_procedure_body(p); + + lb_run_function_pass_manager(default_function_pass_manager, p); + +} + +lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, lbProcedure *objc_names, Array &global_variables) { // Startup Runtime LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(main_module->mod); lb_populate_function_pass_manager(main_module, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); @@ -666,6 +712,10 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + if (objc_names) { + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); + } + for_array(i, global_variables) { auto *var = &global_variables[i]; if (var->is_initialized) { @@ -1570,8 +1620,10 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Runtime Type Information Creation"); lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); + lbProcedure *objc_names = lb_create_objc_names(default_module); + TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); - lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); + lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, objc_names, global_variables); gb_unused(startup_runtime); TIME_SECTION("LLVM Global Procedures and Types"); @@ -1650,6 +1702,8 @@ void lb_generate_code(lbGenerator *gen) { } } + lb_finalize_objc_names(objc_names); + if (build_context.ODIN_DEBUG) { TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); for_array(j, gen->modules.entries) { @@ -1662,6 +1716,7 @@ void lb_generate_code(lbGenerator *gen) { } + TIME_SECTION("LLVM Function Pass"); for_array(i, gen->modules.entries) { lbModule *m = gen->modules.entries[i].value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d7093bc63..087cda22a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -144,6 +144,9 @@ struct lbModule { PtrMap debug_values; Array debug_incomplete_types; + + StringMap objc_classes; + StringMap objc_selectors; }; struct lbGenerator { @@ -293,7 +296,6 @@ struct lbProcedure { bool lb_init_generator(lbGenerator *gen, Checker *c); -void lb_generate_module(lbGenerator *gen); String lb_mangle_name(lbModule *m, Entity *e); String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); @@ -366,7 +368,7 @@ lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx); lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p); -lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}); +lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr); lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, i32 param_index=0, bool force_no_init=false); void lb_add_foreign_library_path(lbModule *m, Entity *e); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 2fc21b534..1c98aa77f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -72,6 +72,9 @@ void lb_init_module(lbModule *m, Checker *c) { map_init(&m->debug_values, a); array_init(&m->debug_incomplete_types, a, 0, 1024); + + string_map_init(&m->objc_classes, a); + string_map_init(&m->objc_selectors, a); } bool lb_init_generator(lbGenerator *gen, Checker *c) { @@ -2450,7 +2453,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { return {}; } -lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { +lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) { GB_ASSERT(type != nullptr); type = default_type(type); @@ -2476,6 +2479,9 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { lb_add_entity(m, e, g); lb_add_member(m, name, g); + + if (entity_) *entity_ = e; + return lb_addr(g); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7a6fac603..6de0aaed7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2106,6 +2106,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = t_uintptr; return res; } + + case BuiltinProc_objc_send: + return lb_handle_obj_send(p, expr); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 7e2bd7daa..d92f711ba 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1819,3 +1819,99 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) { LLVMSetVisibility(value, LLVMDefaultVisibility); LLVMAddTargetDependentFunctionAttr(value, "wasm-export-name", alloc_cstring(permanent_allocator(), export_name)); } + + +lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name); + +lbValue lb_handle_obj_id(lbProcedure *p, Ast *expr) { + TypeAndValue const &tav = type_and_value_of_expr(expr); + if (tav.mode == Addressing_Type) { + Type *type = tav.type; + GB_ASSERT_MSG(type->kind == Type_Named, "%s", type_to_string(type)); + Entity *e = type->Named.type_name; + GB_ASSERT(e->kind == Entity_TypeName); + String name = e->TypeName.objc_class_name; + + lbAddr *found = string_map_get(&p->module->objc_classes, name); + if (found) { + return lb_addr_load(p, *found); + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_classes, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_classes, name, local_addr); + } + return lb_addr_load(p, local_addr); + } + } + + return lb_build_expr(p, expr); +} + + +lbValue lb_handle_obj_selector(lbProcedure *p, String const &name) { + lbAddr *found = string_map_get(&p->module->objc_selectors, name); + if (found) { + return lb_addr_load(p, *found); + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_selectors, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_selectors, name, local_addr); + } + return lb_addr_load(p, local_addr); + } +} + + +lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + lbModule *m = p->module; + CheckerInfo *info = m->info; + ObjcMsgData data = map_must_get(&info->objc_msgSend_types, expr); + GB_ASSERT(data.proc_type != nullptr); + + GB_ASSERT(ce->args.count >= 3); + auto args = array_make(permanent_allocator(), 0, ce->args.count-1); + + lbValue id = lb_handle_obj_id(p, ce->args[1]); + Ast *sel_expr = ce->args[2]; + GB_ASSERT(sel_expr->tav.value.kind == ExactValue_String); + lbValue sel = lb_handle_obj_selector(p, sel_expr->tav.value.value_string); + + array_add(&args, id); + array_add(&args, sel); + for (isize i = 3; i < ce->args.count; i++) { + lbValue arg = lb_build_expr(p, ce->args[i]); + array_add(&args, arg); + } + + + lbValue the_proc = {}; + switch (data.kind) { + default: + GB_PANIC("unhandled ObjcMsgKind %u", data.kind); + break; + case ObjcMsg_normal: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend")); break; + case ObjcMsg_fpret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fpret")); break; + case ObjcMsg_fp2ret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fp2ret")); break; + case ObjcMsg_stret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_stret")); break; + } + + the_proc = lb_emit_conv(p, the_proc, data.proc_type); + + return lb_emit_call(p, the_proc, args); +} diff --git a/src/types.cpp b/src/types.cpp index 9ee6ba359..cdb31c6e1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -685,6 +685,16 @@ gb_global Type *t_map_header = nullptr; gb_global Type *t_equal_proc = nullptr; gb_global Type *t_hasher_proc = nullptr; +gb_global Type *t_objc_object = nullptr; +gb_global Type *t_objc_selector = nullptr; +gb_global Type *t_objc_class = nullptr; + +gb_global Type *t_objc_id = nullptr; +gb_global Type *t_objc_SEL = nullptr; +gb_global Type *t_objc_Class = nullptr; + + + gb_global RecursiveMutex g_type_mutex; struct TypePath; -- cgit v1.2.3 From 7386ca9272c527800720c0dd53a9ad351345aa41 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 14 Feb 2022 11:21:21 +0000 Subject: Add new objc intrinsics: objc_(register|find)_(selector|class) --- core/sys/darwin/Foundation/NSObject.odin | 2 +- src/check_builtin.cpp | 28 ++++++- src/checker_builtin_procs.hpp | 11 ++- src/llvm_backend.cpp | 5 +- src/llvm_backend_proc.cpp | 8 +- src/llvm_backend_utility.cpp | 133 +++++++++++++++++++++++-------- 6 files changed, 140 insertions(+), 47 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index 82d837fb8..55d87a14b 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -70,7 +70,7 @@ description :: proc(self: ^Object) -> ^String { @(objc_type=Object, objc_name="debugDescription") debugDescription :: proc(self: ^Object) -> ^String { - if msgSendSafeCheck(self, intrinsics.objc_selector_name("debugDescription")) { + if msgSendSafeCheck(self, intrinsics.objc_find_selector("debugDescription")) { return msgSend(^String, self, "debugDescription") } return nil diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a9ee5d25f..a6b1759f5 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -348,13 +348,27 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call return true; } break; - case BuiltinProc_objc_selector_name: { + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_selector: + case BuiltinProc_objc_register_class: + { String sel_name = {}; if (!is_constant_string(c, builtin_name, ce->args[0], &sel_name)) { return false; } - operand->type = t_objc_SEL; + switch (id) { + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_register_selector: + operand->type = t_objc_SEL; + break; + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_class: + operand->type = t_objc_Class; + break; + + } operand->mode = Addressing_Value; return true; } break; @@ -398,7 +412,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_max: case BuiltinProc_type_is_subtype_of: case BuiltinProc_objc_send: - case BuiltinProc_objc_selector_name: + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_selector: + case BuiltinProc_objc_register_class: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -440,7 +457,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_objc_send: - case BuiltinProc_objc_selector_name: + case BuiltinProc_objc_find_selector: + case BuiltinProc_objc_find_class: + case BuiltinProc_objc_register_selector: + case BuiltinProc_objc_register_class: return check_builtin_objc_procedure(c, operand, call, id, type_hint); case BuiltinProc___entry_point: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c14c18412..19fa94ee6 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -253,7 +253,10 @@ BuiltinProc__type_end, BuiltinProc___entry_point, BuiltinProc_objc_send, - BuiltinProc_objc_selector_name, + BuiltinProc_objc_find_selector, + BuiltinProc_objc_find_class, + BuiltinProc_objc_register_selector, + BuiltinProc_objc_register_class, BuiltinProc_COUNT, }; @@ -509,5 +512,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("objc_selector_name"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("objc_find_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7941c65a3..52c46cadc 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -672,12 +672,14 @@ void lb_finalize_objc_names(lbProcedure *p) { lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); + + auto args = array_make(permanent_allocator(), 1); + LLVMSetLinkage(p->value, LLVMInternalLinkage); lb_begin_procedure_body(p); for_array(i, m->objc_classes.entries) { auto const &entry = m->objc_classes.entries[i]; String name = entry.key.string; - auto args = array_make(permanent_allocator(), 1); args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); lb_addr_store(p, entry.value, ptr); @@ -686,7 +688,6 @@ void lb_finalize_objc_names(lbProcedure *p) { for_array(i, m->objc_selectors.entries) { auto const &entry = m->objc_selectors.entries[i]; String name = entry.key.string; - auto args = array_make(permanent_allocator(), 1); args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); lb_addr_store(p, entry.value, ptr); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index caa3dfa1a..2a0380605 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2108,10 +2108,12 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_objc_send: - return lb_handle_obj_send(p, expr); + return lb_handle_objc_send(p, expr); - case BuiltinProc_objc_selector_name: - return lb_handle_obj_selector_name(p, expr); + case BuiltinProc_objc_find_selector: return lb_handle_objc_find_selector(p, expr); + case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr); + case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr); + case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 8ef66df7a..75fb89314 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1823,7 +1823,101 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) { lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name); -lbValue lb_handle_obj_id(lbProcedure *p, Ast *expr) { + +lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) { + lbAddr *found = string_map_get(&p->module->objc_selectors, name); + if (found) { + return *found; + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_selectors, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_selectors, name, local_addr); + } + return local_addr; + } +} + +lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + return lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, name)); +} + +lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + lbModule *m = p->module; + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + lbAddr dst = lb_handle_objc_find_or_register_selector(p, name); + + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); + lb_addr_store(p, dst, ptr); + + return lb_addr_load(p, dst); +} + +lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) { + lbAddr *found = string_map_get(&p->module->objc_classes, name); + if (found) { + return *found; + } else { + lbModule *default_module = &p->module->gen->default_module; + Entity *e = nullptr; + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + + lbValue ptr = lb_find_value_from_entity(p->module, e); + lbAddr local_addr = lb_addr(ptr); + + string_map_set(&default_module->objc_classes, name, default_addr); + if (default_module != p->module) { + string_map_set(&p->module->objc_classes, name, local_addr); + } + return local_addr; + } +} + +lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); +} + +lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + lbModule *m = p->module; + + auto tav = ce->args[0]->tav; + GB_ASSERT(tav.value.kind == ExactValue_String); + String name = tav.value.value_string; + lbAddr dst = lb_handle_objc_find_or_register_class(p, name); + + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); + lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); + lb_addr_store(p, dst, ptr); + + return lb_addr_load(p, dst); +} + + +lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) { TypeAndValue const &tav = type_and_value_of_expr(expr); if (tav.mode == Addressing_Type) { Type *type = tav.type; @@ -1854,29 +1948,7 @@ lbValue lb_handle_obj_id(lbProcedure *p, Ast *expr) { return lb_build_expr(p, expr); } - -lbValue lb_handle_obj_selector(lbProcedure *p, String const &name) { - lbAddr *found = string_map_get(&p->module->objc_selectors, name); - if (found) { - return lb_addr_load(p, *found); - } else { - lbModule *default_module = &p->module->gen->default_module; - Entity *e = nullptr; - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); - - lbValue ptr = lb_find_value_from_entity(p->module, e); - lbAddr local_addr = lb_addr(ptr); - - string_map_set(&default_module->objc_selectors, name, default_addr); - if (default_module != p->module) { - string_map_set(&p->module->objc_selectors, name, local_addr); - } - return lb_addr_load(p, local_addr); - } -} - - -lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { +lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); lbModule *m = p->module; @@ -1887,10 +1959,10 @@ lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { GB_ASSERT(ce->args.count >= 3); auto args = array_make(permanent_allocator(), 0, ce->args.count-1); - lbValue id = lb_handle_obj_id(p, ce->args[1]); + lbValue id = lb_handle_objc_id(p, ce->args[1]); Ast *sel_expr = ce->args[2]; GB_ASSERT(sel_expr->tav.value.kind == ExactValue_String); - lbValue sel = lb_handle_obj_selector(p, sel_expr->tav.value.value_string); + lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, sel_expr->tav.value.value_string)); array_add(&args, id); array_add(&args, sel); @@ -1917,12 +1989,3 @@ lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) { } -lbValue lb_handle_obj_selector_name(lbProcedure *p, Ast *expr) { - ast_node(ce, CallExpr, expr); - - auto tav = ce->args[0]->tav; - GB_ASSERT(tav.value.kind == ExactValue_String); - String name = tav.value.value_string; - return lb_handle_obj_selector(p, name); - -} \ No newline at end of file -- cgit v1.2.3 From df23cf47c69877e69b75d109e4da58e782070ac8 Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 16 Feb 2022 22:08:39 -0500 Subject: fix odin test --- src/llvm_backend.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 52c46cadc..c777819c3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1694,6 +1694,11 @@ void lb_generate_code(lbGenerator *gen) { } } + if (build_context.command_kind == Command_test && !already_has_entry_point) { + TIME_SECTION("LLVM main"); + lb_create_main_procedure(default_module, startup_runtime); + } + for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; for_array(i, m->missing_procedures_to_check) { -- cgit v1.2.3 From bea2f3644325454e7fe0e12313528359d0782843 Mon Sep 17 00:00:00 2001 From: CiD- Date: Thu, 17 Feb 2022 10:48:30 -0500 Subject: improve entry point check logic --- src/llvm_backend.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index c777819c3..07b8e97b2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1468,9 +1468,8 @@ void lb_generate_code(lbGenerator *gen) { if ((e->scope->flags&ScopeFlag_Init) && name == "main") { GB_ASSERT(e == info->entry_point); } - if (e->Procedure.is_export || - (e->Procedure.link_name.len > 0) || - ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { + if (build_context.command_kind == Command_test && + (e->Procedure.is_export || e->Procedure.link_name.len > 0)) { String link_name = e->Procedure.link_name; if (e->pkg->kind == Package_Runtime) { if (link_name == "main" || -- cgit v1.2.3 From 1bec9e5331bad9aaecee8ba80bf2cbeb97bb3ef0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 14:19:52 +0000 Subject: Add `freestanding_amd64_gnu` --- src/build_settings.cpp | 36 ++++++++++++++++++++++++++++++++---- src/llvm_abi.cpp | 4 +++- src/llvm_backend.cpp | 13 +++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 610e4f847..cc76f9e7c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -8,7 +8,7 @@ // #define DEFAULT_TO_THREADED_CHECKER // #endif -enum TargetOsKind { +enum TargetOsKind : u16 { TargetOs_Invalid, TargetOs_windows, @@ -25,7 +25,7 @@ enum TargetOsKind { TargetOs_COUNT, }; -enum TargetArchKind { +enum TargetArchKind : u16 { TargetArch_Invalid, TargetArch_amd64, @@ -37,7 +37,7 @@ enum TargetArchKind { TargetArch_COUNT, }; -enum TargetEndianKind { +enum TargetEndianKind : u8 { TargetEndian_Invalid, TargetEndian_Little, @@ -46,6 +46,16 @@ enum TargetEndianKind { TargetEndian_COUNT, }; +enum TargetABIKind : u16 { + TargetABI_Default, + + TargetABI_MSVC, + TargetABI_GNU, + + TargetABI_COUNT, +}; + + String target_os_names[TargetOs_COUNT] = { str_lit(""), str_lit("windows"), @@ -75,6 +85,12 @@ String target_endian_names[TargetEndian_COUNT] = { str_lit("big"), }; +String target_abi_names[TargetABI_COUNT] = { + str_lit(""), + str_lit("win64"), + str_lit("sysv"), +}; + TargetEndianKind target_endians[TargetArch_COUNT] = { TargetEndian_Invalid, TargetEndian_Little, @@ -98,6 +114,7 @@ struct TargetMetrics { isize max_align; String target_triplet; String target_data_layout; + TargetABIKind abi; }; @@ -399,6 +416,16 @@ gb_global TargetMetrics target_wasi_wasm32 = { // str_lit(""), // }; +gb_global TargetMetrics target_freestanding_amd64_gnu = { + TargetOs_freestanding, + TargetArch_amd64, + 8, + 16, + str_lit("x86_64-pc-none-gnu"), + str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), + TargetABI_GNU, +}; + struct NamedTargetMetrics { @@ -420,7 +447,8 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, - // { str_lit("freestanding_wasm64"), &target_freestanding_wasm64 }, + + { str_lit("freestanding_amd64_gnu"), &target_freestanding_amd64_gnu }, }; NamedTargetMetrics *selected_target_metrics; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 0244b73d6..770e54ac8 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1194,8 +1194,10 @@ LB_ABI_INFO(lb_get_abi_info) { switch (build_context.metrics.arch) { case TargetArch_amd64: - if (build_context.metrics.os == TargetOs_windows) { + if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_MSVC) { return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } else if (build_context.metrics.abi == TargetABI_GNU) { + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } else { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 52c46cadc..934daee28 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -996,6 +996,19 @@ String lb_filepath_obj_for_module(lbModule *m) { case TargetOs_essence: ext = STR_LIT(".o"); break; + + case TargetOs_freestanding: + switch (build_context.metrics.abi) { + default: + case TargetABI_Default: + case TargetABI_GNU: + ext = STR_LIT(".o"); + break; + case TargetABI_MSVC: + ext = STR_LIT(".obj"); + break; + } + break; } } } -- cgit v1.2.3 From 3e5c60f74672651044d70303e8b0a8e56ca765f2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Feb 2022 14:48:12 +0000 Subject: Add `-reloc-mode:` --- src/build_settings.cpp | 9 +++++++++ src/llvm_backend.cpp | 14 ++++++++++++++ src/main.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index cd9bdb40c..d56a343df 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -189,6 +189,13 @@ enum ErrorPosStyle { ErrorPosStyle_COUNT }; +enum RelocMode { + RelocMode_Default, + RelocMode_Static, + RelocMode_PIC, + RelocMode_DynamicNoPIC, +}; + // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -270,6 +277,8 @@ struct BuildContext { bool copy_file_contents; + RelocMode reloc_mode; + u32 cmd_doc_flags; Array extra_packages; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 934daee28..692b96c51 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1308,6 +1308,20 @@ void lb_generate_code(lbGenerator *gen) { reloc_mode = LLVMRelocPIC; } + switch (build_context.reloc_mode) { + case RelocMode_Default: + break; + case RelocMode_Static: + reloc_mode = LLVMRelocStatic; + break; + case RelocMode_PIC: + reloc_mode = LLVMRelocPIC; + break; + case RelocMode_DynamicNoPIC: + reloc_mode = LLVMRelocDynamicNoPic; + break; + } + for_array(i, gen->modules.entries) { target_machines[i] = LLVMCreateTargetMachine( target, target_triple, llvm_cpu, diff --git a/src/main.cpp b/src/main.cpp index 5746ef146..087f2b442 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -625,6 +625,8 @@ enum BuildFlagKind { BuildFlag_ExtraAssemblerFlags, BuildFlag_Microarch, + BuildFlag_RelocMode, + BuildFlag_TestName, BuildFlag_DisallowDo, @@ -779,6 +781,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); @@ -1339,6 +1343,28 @@ bool parse_build_flags(Array args) { string_to_lower(&build_context.microarch); break; } + case BuildFlag_RelocMode: { + GB_ASSERT(value.kind == ExactValue_String); + String v = value.value_string; + if (v == "default") { + build_context.reloc_mode = RelocMode_Default; + } else if (v == "static") { + build_context.reloc_mode = RelocMode_Static; + } else if (v == "pic") { + build_context.reloc_mode = RelocMode_PIC; + } else if (v == "dynamic-no-pic") { + build_context.reloc_mode = RelocMode_DynamicNoPIC; + } else { + gb_printf_err("-reloc-mode flag expected one of the following\n"); + gb_printf_err("\tdefault\n"); + gb_printf_err("\tstatic\n"); + gb_printf_err("\tpic\n"); + gb_printf_err("\tdynamic-no-pic\n"); + bad_flags = true; + } + + break; + } case BuildFlag_TestName: { GB_ASSERT(value.kind == ExactValue_String); { -- cgit v1.2.3 From 3d209798c9aff4a0ebd135536234022620c9e650 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Feb 2022 11:19:51 +0000 Subject: Add help docs for `-reloc-mode:` --- src/build_settings.cpp | 2 +- src/llvm_backend.cpp | 2 ++ src/main.cpp | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d56a343df..790f7f1bc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -189,7 +189,7 @@ enum ErrorPosStyle { ErrorPosStyle_COUNT }; -enum RelocMode { +enum RelocMode : u8 { RelocMode_Default, RelocMode_Static, RelocMode_PIC, diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 692b96c51..ec22c7443 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1261,6 +1261,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMCodeModel code_mode = LLVMCodeModelDefault; if (is_arch_wasm()) { code_mode = LLVMCodeModelJITDefault; + } else if (build_context.metrics.os == TargetOs_freestanding) { + code_mode = LLVMCodeModelKernel; } char const *host_cpu_name = LLVMGetHostCPUName(); diff --git a/src/main.cpp b/src/main.cpp index 087f2b442..cfc7decb1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2087,6 +2087,15 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:native"); print_usage_line(0, ""); + + print_usage_line(1, "-reloc-mode:"); + print_usage_line(2, "Specifies the reloc mode"); + print_usage_line(2, "Options:"); + print_usage_line(3, "default"); + print_usage_line(3, "static"); + print_usage_line(3, "pic"); + print_usage_line(3, "dynamic-no-pic"); + print_usage_line(0, ""); } if (check) { -- cgit v1.2.3 From 4a04a32e0ab4ad91a7b62c0a94e57312002b85d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Feb 2022 11:33:28 +0000 Subject: Change target name to `freestanding_amd64_sysv` --- src/build_settings.cpp | 10 +++++----- src/llvm_abi.cpp | 4 ++-- src/llvm_backend.cpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 62f43fad3..d6cdd7006 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -49,8 +49,8 @@ enum TargetEndianKind : u8 { enum TargetABIKind : u16 { TargetABI_Default, - TargetABI_MSVC, - TargetABI_GNU, + TargetABI_Win64, + TargetABI_SysV, TargetABI_COUNT, }; @@ -428,14 +428,14 @@ gb_global TargetMetrics target_wasi_wasm32 = { // str_lit(""), // }; -gb_global TargetMetrics target_freestanding_amd64_gnu = { +gb_global TargetMetrics target_freestanding_amd64_sysv = { TargetOs_freestanding, TargetArch_amd64, 8, 16, str_lit("x86_64-pc-none-gnu"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), - TargetABI_GNU, + TargetABI_SysV, }; @@ -460,7 +460,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, - { str_lit("freestanding_amd64_gnu"), &target_freestanding_amd64_gnu }, + { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv }, }; NamedTargetMetrics *selected_target_metrics; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 770e54ac8..07d2dd6e3 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1194,9 +1194,9 @@ LB_ABI_INFO(lb_get_abi_info) { switch (build_context.metrics.arch) { case TargetArch_amd64: - if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_MSVC) { + if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) { return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); - } else if (build_context.metrics.abi == TargetABI_GNU) { + } else if (build_context.metrics.abi == TargetABI_SysV) { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } else { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ec22c7443..6ca256c4b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1001,10 +1001,10 @@ String lb_filepath_obj_for_module(lbModule *m) { switch (build_context.metrics.abi) { default: case TargetABI_Default: - case TargetABI_GNU: + case TargetABI_SysV: ext = STR_LIT(".o"); break; - case TargetABI_MSVC: + case TargetABI_Win64: ext = STR_LIT(".obj"); break; } -- cgit v1.2.3 From 278e239973ab1e680bd36f90c069ec798930e54b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 13:39:27 +0000 Subject: Commit rest of code for `-disallow-rtti` --- src/build_settings.cpp | 3 ++- src/check_builtin.cpp | 18 +++++++++++++----- src/check_decl.cpp | 2 ++ src/check_expr.cpp | 2 ++ src/check_type.cpp | 2 ++ src/checker.cpp | 25 ++++++++++++++++++++++++- src/llvm_backend.cpp | 6 +++++- src/llvm_backend_expr.cpp | 17 ++++++++++++++--- src/llvm_backend_type.cpp | 2 ++ src/llvm_backend_utility.cpp | 30 ++++++++++++++++++++++-------- src/main.cpp | 7 +++++++ 11 files changed, 95 insertions(+), 19 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d6cdd7006..b2d6c4f43 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -277,6 +277,8 @@ struct BuildContext { bool copy_file_contents; + bool disallow_rtti; + RelocMode reloc_mode; bool disable_red_zone; @@ -946,7 +948,6 @@ void init_build_context(TargetMetrics *cross_target) { } } - bc->copy_file_contents = true; TargetMetrics *metrics = nullptr; diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eb9d7f293..5561da01b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1241,6 +1241,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (c->scope->flags&ScopeFlag_Global) { compiler_error("'type_info_of' Cannot be declared within the runtime package due to how the internals of the compiler works"); } + if (build_context.disallow_rtti) { + error(call, "'%.*s' has been disallowed", LIT(builtin_name)); + return false; + } // NOTE(bill): The type information may not be setup yet init_core_type_info(c->checker); @@ -1253,9 +1257,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) { if (is_type_polymorphic(t)) { - error(ce->args[0], "Invalid argument for 'type_info_of', unspecialized polymorphic type"); + error(ce->args[0], "Invalid argument for '%.*s', unspecialized polymorphic type", LIT(builtin_name)); } else { - error(ce->args[0], "Invalid argument for 'type_info_of'"); + error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); } return false; } @@ -1266,7 +1270,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (is_operand_value(o) && is_type_typeid(t)) { add_package_dependency(c, "runtime", "__type_info_of"); } else if (o.mode != Addressing_Type) { - error(expr, "Expected a type or typeid for 'type_info_of'"); + error(expr, "Expected a type or typeid for '%.*s'", LIT(builtin_name)); return false; } @@ -1280,6 +1284,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (c->scope->flags&ScopeFlag_Global) { compiler_error("'typeid_of' Cannot be declared within the runtime package due to how the internals of the compiler works"); } + if (build_context.disallow_rtti) { + error(call, "'%.*s' has been disallowed", LIT(builtin_name)); + return false; + } // NOTE(bill): The type information may not be setup yet init_core_type_info(c->checker); @@ -1291,7 +1299,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) { - error(ce->args[0], "Invalid argument for 'typeid_of'"); + error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); return false; } t = default_type(t); @@ -1299,7 +1307,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 add_type_info_type(c, t); if (o.mode != Addressing_Type) { - error(expr, "Expected a type for 'typeid_of'"); + error(expr, "Expected a type for '%.*s'", LIT(builtin_name)); return false; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3fdd944f9..b3b1e4474 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1205,6 +1205,8 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Operand o = {}; check_expr_with_type_hint(ctx, &o, init_expr, e->type); check_init_variable(ctx, e, &o, str_lit("variable declaration")); + + check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed"); } void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e07dc3d60..f1bcb4cd9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9352,6 +9352,8 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi if (o->type != nullptr && is_type_untyped(o->type)) { add_untyped(c, node, o->mode, o->type, o->value); } + check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed"); + add_type_and_value(c->info, node, o->mode, o->type, o->value); return kind; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c2324ee5a..ff2c3d6a6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3031,5 +3031,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) { } set_base_type(named_type, type); + check_rtti_type_disallowed(e, type, "Use of a type, %s, which has been disallowed"); + return type; } diff --git a/src/checker.cpp b/src/checker.cpp index fe1d362fa..e6445d752 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -29,6 +29,23 @@ bool is_operand_undef(Operand o) { return o.mode == Addressing_Value && o.type == t_untyped_undef; } +bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) { + if (build_context.disallow_rtti && type) { + if (is_type_any(type)) { + gbString t = type_to_string(type); + error(token, format, t); + gb_string_free(t); + return true; + } + } + return false; +} + +bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) { + GB_ASSERT(expr != nullptr); + return check_rtti_type_disallowed(ast_token(expr), type, format); +} + void scope_reset(Scope *scope) { if (scope == nullptr) return; @@ -875,7 +892,8 @@ void init_universal(void) { // Types for (isize i = 0; i < gb_count_of(basic_types); i++) { - add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]); + String const &name = basic_types[i].Basic.name; + add_global_type_entity(name, &basic_types[i]); } add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]); @@ -977,6 +995,7 @@ void init_universal(void) { add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); add_global_bool_constant("ODIN_NO_ENTRY_POINT", bc->no_entry_point); add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES); + add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti); // Builtin Procedures @@ -1669,6 +1688,10 @@ void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) { void add_type_info_type(CheckerContext *c, Type *t) { void add_type_info_type_internal(CheckerContext *c, Type *t); + if (build_context.disallow_rtti) { + return; + } + mutex_lock(&c->info->type_info_mutex); add_type_info_type_internal(c, t); mutex_unlock(&c->info->type_info_mutex); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6ca256c4b..04c3200f8 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1285,7 +1285,11 @@ void lb_generate_code(lbGenerator *gen) { // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL if (ODIN_LLVM_MINIMUM_VERSION_12) { - llvm_cpu = "x86-64-v2"; + if (build_context.metrics.os == TargetOs_freestanding) { + llvm_cpu = "x86-64"; + } else { + llvm_cpu = "x86-64-v2"; + } } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 844deb43c..18b66572d 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2809,16 +2809,25 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); dst_tag = lb_const_union_tag(p->module, src_type, dst_type); } + + + isize arg_count = 6; + if (build_context.disallow_rtti) { + arg_count = 4; + } + lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - auto args = array_make(permanent_allocator(), 6); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); args[2] = lb_const_int(p->module, t_i32, pos.line); args[3] = lb_const_int(p->module, t_i32, pos.column); - args[4] = lb_typeid(p->module, src_type); - args[5] = lb_typeid(p->module, dst_type); + if (!build_context.disallow_rtti) { + args[4] = lb_typeid(p->module, src_type); + args[5] = lb_typeid(p->module, dst_type); + } lb_emit_runtime_call(p, "type_assertion_check", args); } @@ -2831,6 +2840,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { } lbValue data_ptr = lb_emit_struct_ev(p, v, 0); if ((p->state_flags & StateFlag_no_type_assert) == 0) { + GB_ASSERT(!build_context.disallow_rtti); + lbValue any_id = lb_emit_struct_ev(p, v, 1); lbValue id = lb_typeid(p->module, type); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 1d6297164..1aac75f9c 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -14,6 +14,8 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr } lbValue lb_typeid(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + type = default_type(type); u64 id = cast(u64)lb_type_info_index(m->info, type); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 98b7e07f0..fb52a9bd6 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -676,17 +676,24 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p // NOTE(bill): Panic on invalid conversion Type *dst_type = tuple->Tuple.variables[0]->type; + isize arg_count = 7; + if (build_context.disallow_rtti) { + arg_count = 4; + } + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); args[2] = lb_const_int(m, t_i32, pos.line); args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = lb_typeid(m, src_type); - args[5] = lb_typeid(m, dst_type); - args[6] = lb_emit_conv(p, value_, t_rawptr); + if (!build_context.disallow_rtti) { + args[4] = lb_typeid(m, src_type); + args[5] = lb_typeid(m, dst_type); + args[6] = lb_emit_conv(p, value_, t_rawptr); + } lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); @@ -744,16 +751,23 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos if (!is_tuple) { // NOTE(bill): Panic on invalid conversion lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), 7); + + isize arg_count = 7; + if (build_context.disallow_rtti) { + arg_count = 4; + } + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); args[2] = lb_const_int(m, t_i32, pos.line); args[3] = lb_const_int(m, t_i32, pos.column); - args[4] = any_typeid; - args[5] = dst_typeid; - args[6] = lb_emit_struct_ev(p, value, 0);; + if (!build_context.disallow_rtti) { + args[4] = any_typeid; + args[5] = dst_typeid; + args[6] = lb_emit_struct_ev(p, value, 0); + } lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); diff --git a/src/main.cpp b/src/main.cpp index 8f4155d39..d2263f5a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -638,6 +638,7 @@ enum BuildFlagKind { BuildFlag_StrictStyle, BuildFlag_StrictStyleInitOnly, BuildFlag_ForeignErrorProcedures, + BuildFlag_DisallowRTTI, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -796,6 +797,9 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check); + + add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); @@ -1390,6 +1394,9 @@ bool parse_build_flags(Array args) { case BuildFlag_DisallowDo: build_context.disallow_do = true; break; + case BuildFlag_DisallowRTTI: + build_context.disallow_rtti = true; + break; case BuildFlag_DefaultToNilAllocator: build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true; break; -- cgit v1.2.3 From 2d89faa17cf88b76e183e35f4d50722271c76d20 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 14:35:38 +0000 Subject: Add extra checks for -disallow-rtti --- src/llvm_backend.cpp | 9 +++++++-- src/llvm_backend_type.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 04c3200f8..40c06c23a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -624,6 +624,9 @@ struct lbGlobalVariable { }; lbProcedure *lb_create_startup_type_info(lbModule *m) { + if (build_context.disallow_rtti) { + return nullptr; + } LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); @@ -711,7 +714,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + if (startup_type_info) { + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + } if (objc_names) { LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); @@ -1394,7 +1399,7 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Global Variables"); - { + if (!build_context.disallow_rtti) { lbModule *m = default_module; { // Add type info data diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 1aac75f9c..e245a8b40 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -90,6 +90,8 @@ lbValue lb_typeid(lbModule *m, Type *type) { } lbValue lb_type_info(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + type = default_type(type); isize index = lb_type_info_index(m->info, type); @@ -108,6 +110,8 @@ lbValue lb_type_info(lbModule *m, Type *type) { } lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { + GB_ASSERT(!build_context.disallow_rtti); + i32 index = cast(i32)lb_type_info_index(m->info, type); GB_ASSERT(index >= 0); // gb_printf_err("%d %s\n", index, type_to_string(type)); @@ -157,6 +161,10 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) { void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data + if (build_context.disallow_rtti) { + return; + } + lbModule *m = p->module; CheckerInfo *info = m->info; -- cgit v1.2.3 From 09e4fff5b18a314876c5f5d79f01cdd90aed7362 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 28 Feb 2022 15:08:50 +0000 Subject: `-target-features:` This just passes a string directly to the LLVM features string --- src/build_settings.cpp | 1 + src/llvm_backend.cpp | 4 ++++ src/main.cpp | 10 +++++++++- src/string.cpp | 8 -------- 4 files changed, 14 insertions(+), 9 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 7beee8664..e94fade4e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -232,6 +232,7 @@ struct BuildContext { String extra_linker_flags; String extra_assembler_flags; String microarch; + String target_features; BuildModeKind build_mode; bool generate_docs; i32 optimization_level; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 40c06c23a..ed3ae7dfc 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1298,6 +1298,10 @@ void lb_generate_code(lbGenerator *gen) { } } + if (build_context.target_features.len != 0) { + llvm_features = alloc_cstring(permanent_allocator(), build_context.target_features); + } + // GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target)); LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone; diff --git a/src/main.cpp b/src/main.cpp index d2263f5a7..5a77e09d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -626,6 +626,7 @@ enum BuildFlagKind { BuildFlag_ExtraLinkerFlags, BuildFlag_ExtraAssemblerFlags, BuildFlag_Microarch, + BuildFlag_TargetFeatures, BuildFlag_RelocMode, BuildFlag_DisableRedZone, @@ -783,7 +784,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); @@ -1351,6 +1353,12 @@ bool parse_build_flags(Array args) { string_to_lower(&build_context.microarch); break; } + case BuildFlag_TargetFeatures: { + GB_ASSERT(value.kind == ExactValue_String); + build_context.target_features = value.value_string; + string_to_lower(&build_context.target_features); + break; + } case BuildFlag_RelocMode: { GB_ASSERT(value.kind == ExactValue_String); String v = value.value_string; diff --git a/src/string.cpp b/src/string.cpp index bcaf23b9b..d3dbc6904 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -10,10 +10,6 @@ struct String { u8 * text; isize len; - // u8 &operator[](isize i) { - // GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); - // return text[i]; - // } u8 const &operator[](isize i) const { GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); return text[i]; @@ -33,10 +29,6 @@ struct String { struct String16 { wchar_t *text; isize len; - wchar_t &operator[](isize i) { - GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); - return text[i]; - } wchar_t const &operator[](isize i) const { GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); return text[i]; -- cgit v1.2.3 From f76f70c7cf369a7e247a52e0c36da2fbe8d960c6 Mon Sep 17 00:00:00 2001 From: Sébastien Marie Date: Mon, 28 Feb 2022 15:24:22 +0000 Subject: openbsd: defaults to PIE executable OpenBSD uses PIE code by default to allow the system to load the binary at a random location. don't pass -no-pie to preserve this behaviour, and build objects with -fPIC (LLVMRelocPIC). --- src/llvm_backend.cpp | 5 +++++ src/main.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 52c46cadc..3b11f95a2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1295,6 +1295,11 @@ void lb_generate_code(lbGenerator *gen) { reloc_mode = LLVMRelocPIC; } + if (build_context.metrics.os == TargetOs_openbsd) { + // Always use PIC for OpenBSD: it defaults to PIE + reloc_mode = LLVMRelocPIC; + } + for_array(i, gen->modules.entries) { target_machines[i] = LLVMCreateTargetMachine( target, target_triple, llvm_cpu, diff --git a/src/main.cpp b/src/main.cpp index c738b860d..f8a3e6f85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -463,7 +463,8 @@ i32 linker_stage(lbGenerator *gen) { #endif link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); - } else { + } else if (build_context.metrics.os != TargetOs_openbsd) { + // OpenBSD defaults to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } if (build_context.out_filepath.len > 0) { -- cgit v1.2.3 From 3cab2592c3e5a06882ffd711871a08c893b043f1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 6 Apr 2022 18:26:23 +0200 Subject: Compiler: Add early error for output path being a directory. - Introduce new `Path` type and an array of build paths on the build context. - Resolve input and output paths/files early (before parsing). - Error early if inputs are missing or outputs are directories. - Plumb new file path generation into linker stage instead of its adhoc method. TODO: - Remove more adhoc file path generation in parser and linker stage. - Make intermediate object file generation use new path system. - Round out and robustify Path helper functions. --- .gitignore | 1 + Makefile | 4 +- build_odin.sh | 4 +- src/build_settings.cpp | 220 ++++++++++++++++++++++++---- src/common.cpp | 257 +------------------------------- src/gb/gb.h | 46 ++++-- src/llvm_backend.cpp | 14 +- src/llvm_backend_general.cpp | 1 - src/main.cpp | 152 +++++++++---------- src/parser.cpp | 2 +- src/path.cpp | 333 ++++++++++++++++++++++++++++++++++++++++++ src/string.cpp | 10 +- tests/core/build.bat | 28 ++-- tests/core/math/big/build.bat | 2 +- tests/issues/run.sh | 4 +- 15 files changed, 674 insertions(+), 404 deletions(-) create mode 100644 src/path.cpp (limited to 'src/llvm_backend.cpp') diff --git a/.gitignore b/.gitignore index e8b3d3050..d03a86fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -269,6 +269,7 @@ bin/ # - Linux/MacOS odin odin.dSYM +*.bin # shared collection shared/ diff --git a/Makefile b/Makefile index 82150c6a2..1a1c93180 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -all: debug demo +all: debug demo: - ./odin run examples/demo/demo.odin + ./odin run examples/demo report: ./odin report diff --git a/build_odin.sh b/build_odin.sh index aef3f2836..4810cafd2 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -102,7 +102,7 @@ build_odin() { } run_demo() { - ./odin run examples/demo/demo.odin -file + ./odin run examples/demo } case $OS in @@ -147,4 +147,4 @@ if [[ $# -eq 1 ]]; then exit 0 else panic "Too many arguments!" -fi +fi \ No newline at end of file diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 2f3eb03a5..0b582eac8 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -3,7 +3,6 @@ #include #endif - // #if defined(GB_SYSTEM_WINDOWS) // #define DEFAULT_TO_THREADED_CHECKER // #endif @@ -198,6 +197,22 @@ enum RelocMode : u8 { RelocMode_DynamicNoPIC, }; +enum BuildPath : u8 { + BuildPath_Main_Package, // Input Path to the package directory (or file) we're building. + BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`. + BuildPath_RES, // Output Path for .res file, generated from previous. + BuildPath_Win_SDK_Root, // windows_sdk_root + BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path + BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path + BuildPath_VS_EXE, // vs_exe_path + BuildPath_VS_LIB, // vs_library_path + + BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`. + BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`. + + BuildPathCOUNT, +}; + // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -226,9 +241,13 @@ struct BuildContext { bool show_help; + Array build_paths; // Contains `Path` objects to output filename, pdb, resource and intermediate files. + // BuildPath enum contains the indices of paths we know *before* the work starts. + String out_filepath; String resource_filepath; String pdb_filepath; + bool has_resource; String link_flags; String extra_linker_flags; @@ -300,8 +319,6 @@ struct BuildContext { }; - - gb_global BuildContext build_context = {0}; bool global_warnings_as_errors(void) { @@ -605,28 +622,6 @@ bool allow_check_foreign_filepath(void) { // is_abs_path // has_subdir -enum TargetFileValidity : u8 { - TargetFileValidity_Invalid, - - TargetFileValidity_Writable_File, - TargetFileValidity_No_Write_Permission, - TargetFileValidity_Directory, - - TargetTargetFileValidity_COUNT, -}; - -TargetFileValidity set_output_filename(void) { - // Assembles the output filename from build_context information. - // Returns `true` if it doesn't exist or is a file. - // Returns `false` if a directory or write-protected file. - - - - - return TargetFileValidity_Writable_File; -} - - String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; @@ -973,7 +968,6 @@ char *token_pos_to_string(TokenPos const &pos) { return s; } - void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; @@ -1152,8 +1146,178 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); - - #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } + +#if defined(GB_SYSTEM_WINDOWS) +// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. +// NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`. +#include "microsoft_craziness.h" +#endif + +// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. +// We've previously called `parse_build_flags`, so `out_filepath` should be set. +bool init_build_paths(String init_filename) { + gbAllocator ha = heap_allocator(); + BuildContext *bc = &build_context; + + // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index. + array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT); + + // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. + bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); + + bool produces_output_file = false; + if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { + produces_output_file = true; + } else if (bc->command_kind & Command__does_build) { + produces_output_file = true; + } + + if (!produces_output_file) { + // Command doesn't produce output files. We're done. + return true; + } + + #if defined(GB_SYSTEM_WINDOWS) + if (bc->resource_filepath.len > 0) { + bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); + bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); + bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); + bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res")); + } + + if (bc->pdb_filepath.len > 0) { + bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath); + } + + if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + return false; + } + + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + + if (find_result.windows_sdk_root.len > 0) { + bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); + } + + if (find_result.windows_sdk_um_library_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path); + } + + if (find_result.windows_sdk_ucrt_library_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path); + } + + if (find_result.vs_exe_path.len > 0) { + bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path); + } + + if (find_result.vs_library_path.len > 0) { + bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path); + } + + gb_free(ha, find_result.windows_sdk_root.text); + gb_free(ha, find_result.windows_sdk_um_library_path.text); + gb_free(ha, find_result.windows_sdk_ucrt_library_path.text); + gb_free(ha, find_result.vs_exe_path.text); + gb_free(ha, find_result.vs_library_path.text); + + } + #endif + + // All the build targets and OSes. + String output_extension; + + if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { + output_extension = STR_LIT("odin-doc"); + } else if (is_arch_wasm()) { + output_extension = STR_LIT("wasm"); + } else if (build_context.build_mode == BuildMode_Executable) { + // By default use a .bin executable extension. + output_extension = STR_LIT("bin"); + + if (build_context.metrics.os == TargetOs_windows) { + output_extension = STR_LIT("exe"); + } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { + output_extension = make_string(nullptr, 0); + } + } else if (build_context.build_mode == BuildMode_DynamicLibrary) { + // By default use a .so shared library extension. + output_extension = STR_LIT("so"); + + if (build_context.metrics.os == TargetOs_windows) { + output_extension = STR_LIT("dll"); + } else if (build_context.metrics.os == TargetOs_darwin) { + output_extension = STR_LIT("dylib"); + } + } else if (build_context.build_mode == BuildMode_Object) { + // By default use a .o object extension. + output_extension = STR_LIT("o"); + + if (build_context.metrics.os == TargetOs_windows) { + output_extension = STR_LIT("obj"); + } + } else if (build_context.build_mode == BuildMode_Assembly) { + // By default use a .S asm extension. + output_extension = STR_LIT("S"); + } else if (build_context.build_mode == BuildMode_LLVM_IR) { + output_extension = STR_LIT("ll"); + } else { + GB_PANIC("Unhandled build mode/target combination.\n"); + } + + if (bc->out_filepath.len > 0) { + bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath); + } else { + String output_name = remove_directory_from_path(init_filename); + output_name = remove_extension_from_path(output_name); + output_name = copy_string(ha, string_trim_whitespace(output_name)); + + /* + NOTE(Jeroen): This fallback substitution can't be made at this stage. + if (gen->output_name.len == 0) { + gen->output_name = c->info.init_scope->pkg->name; + } + */ + Path output_path = path_from_string(ha, output_name); + + #ifndef GB_SYSTEM_WINDOWS + char cwd[4096]; + getcwd(&cwd[0], 4096); + + const u8 * cwd_str = (const u8 *)&cwd[0]; + output_path.basename = copy_string(ha, make_string(cwd_str, strlen(cwd))); + #endif + + // Replace extension. + if (output_path.ext.len > 0) { + gb_free(ha, output_path.ext.text); + } + output_path.ext = copy_string(ha, output_extension); + + bc->build_paths[BuildPath_Output] = output_path; + } + + // Do we have an extension? We might not if the output filename was supplied. + if (bc->build_paths[BuildPath_Output].ext.len == 0) { + bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); + } + + // Check if output path is a directory. + if (path_is_directory(bc->build_paths[BuildPath_Output])) { + String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); + defer (gb_free(ha, output_file.text)); + gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file)); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/common.cpp b/src/common.cpp index aaacda04b..94248fb62 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -675,262 +675,7 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) { #endif - -#if defined(GB_SYSTEM_WINDOWS) - bool path_is_directory(String path) { - gbAllocator a = heap_allocator(); - String16 wstr = string_to_string16(a, path); - defer (gb_free(a, wstr.text)); - - i32 attribs = GetFileAttributesW(wstr.text); - if (attribs < 0) return false; - - return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; - } - -#else - bool path_is_directory(String path) { - gbAllocator a = heap_allocator(); - char *copy = cast(char *)copy_string(a, path).text; - defer (gb_free(a, copy)); - - struct stat s; - if (stat(copy, &s) == 0) { - return (s.st_mode & S_IFDIR) != 0; - } - return false; - } -#endif - - -String path_to_full_path(gbAllocator a, String path) { - gbAllocator ha = heap_allocator(); - char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); - defer (gb_free(ha, path_c)); - - char *fullpath = gb_path_get_full_name(a, path_c); - String res = string_trim_whitespace(make_string_c(fullpath)); -#if defined(GB_SYSTEM_WINDOWS) - for (isize i = 0; i < res.len; i++) { - if (res.text[i] == '\\') { - res.text[i] = '/'; - } - } -#endif - return res; -} - - - -struct FileInfo { - String name; - String fullpath; - i64 size; - bool is_dir; -}; - -enum ReadDirectoryError { - ReadDirectory_None, - - ReadDirectory_InvalidPath, - ReadDirectory_NotExists, - ReadDirectory_Permission, - ReadDirectory_NotDir, - ReadDirectory_Empty, - ReadDirectory_Unknown, - - ReadDirectory_COUNT, -}; - -i64 get_file_size(String path) { - char *c_str = alloc_cstring(heap_allocator(), path); - defer (gb_free(heap_allocator(), c_str)); - - gbFile f = {}; - gbFileError err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - if (err != gbFileError_None) { - return -1; - } - return gb_file_size(&f); -} - - -#if defined(GB_SYSTEM_WINDOWS) -ReadDirectoryError read_directory(String path, Array *fi) { - GB_ASSERT(fi != nullptr); - - gbAllocator a = heap_allocator(); - - while (path.len > 0) { - Rune end = path[path.len-1]; - if (end == '/') { - path.len -= 1; - } else if (end == '\\') { - path.len -= 1; - } else { - break; - } - } - - if (path.len == 0) { - return ReadDirectory_InvalidPath; - } - { - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - case gbFileError_Invalid: return ReadDirectory_InvalidPath; - case gbFileError_NotExists: return ReadDirectory_NotExists; - // case gbFileError_Permission: return ReadDirectory_Permission; - } - } - - if (!path_is_directory(path)) { - return ReadDirectory_NotDir; - } - - - char *new_path = gb_alloc_array(a, char, path.len+3); - defer (gb_free(a, new_path)); - - gb_memmove(new_path, path.text, path.len); - gb_memmove(new_path+path.len, "/*", 2); - new_path[path.len+2] = 0; - - String np = make_string(cast(u8 *)new_path, path.len+2); - String16 wstr = string_to_string16(a, np); - defer (gb_free(a, wstr.text)); - - WIN32_FIND_DATAW file_data = {}; - HANDLE find_file = FindFirstFileW(wstr.text, &file_data); - if (find_file == INVALID_HANDLE_VALUE) { - return ReadDirectory_Unknown; - } - defer (FindClose(find_file)); - - array_init(fi, a, 0, 100); - - do { - wchar_t *filename_w = file_data.cFileName; - i64 size = cast(i64)file_data.nFileSizeLow; - size |= (cast(i64)file_data.nFileSizeHigh) << 32; - String name = string16_to_string(a, make_string16_c(filename_w)); - if (name == "." || name == "..") { - gb_free(a, name.text); - continue; - } - - String filepath = {}; - filepath.len = path.len+1+name.len; - filepath.text = gb_alloc_array(a, u8, filepath.len+1); - defer (gb_free(a, filepath.text)); - gb_memmove(filepath.text, path.text, path.len); - gb_memmove(filepath.text+path.len, "/", 1); - gb_memmove(filepath.text+path.len+1, name.text, name.len); - - FileInfo info = {}; - info.name = name; - info.fullpath = path_to_full_path(a, filepath); - info.size = size; - info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - array_add(fi, info); - } while (FindNextFileW(find_file, &file_data)); - - if (fi->count == 0) { - return ReadDirectory_Empty; - } - - return ReadDirectory_None; -} -#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) - -#include - -ReadDirectoryError read_directory(String path, Array *fi) { - GB_ASSERT(fi != nullptr); - - gbAllocator a = heap_allocator(); - - char *c_path = alloc_cstring(a, path); - defer (gb_free(a, c_path)); - - DIR *dir = opendir(c_path); - if (!dir) { - switch (errno) { - case ENOENT: - return ReadDirectory_NotExists; - case EACCES: - return ReadDirectory_Permission; - case ENOTDIR: - return ReadDirectory_NotDir; - default: - // ENOMEM: out of memory - // EMFILE: per-process limit on open fds reached - // ENFILE: system-wide limit on total open files reached - return ReadDirectory_Unknown; - } - GB_PANIC("unreachable"); - } - - array_init(fi, a, 0, 100); - - for (;;) { - struct dirent *entry = readdir(dir); - if (entry == nullptr) { - break; - } - - String name = make_string_c(entry->d_name); - if (name == "." || name == "..") { - continue; - } - - String filepath = {}; - filepath.len = path.len+1+name.len; - filepath.text = gb_alloc_array(a, u8, filepath.len+1); - defer (gb_free(a, filepath.text)); - gb_memmove(filepath.text, path.text, path.len); - gb_memmove(filepath.text+path.len, "/", 1); - gb_memmove(filepath.text+path.len+1, name.text, name.len); - filepath.text[filepath.len] = 0; - - - struct stat dir_stat = {}; - - if (stat((char *)filepath.text, &dir_stat)) { - continue; - } - - if (S_ISDIR(dir_stat.st_mode)) { - continue; - } - - i64 size = dir_stat.st_size; - - FileInfo info = {}; - info.name = name; - info.fullpath = path_to_full_path(a, filepath); - info.size = size; - array_add(fi, info); - } - - if (fi->count == 0) { - return ReadDirectory_Empty; - } - - return ReadDirectory_None; -} -#else -#error Implement read_directory -#endif - - +#include "path.cpp" struct LoadedFile { void *handle; diff --git a/src/gb/gb.h b/src/gb/gb.h index b72a893f7..3b2d6434c 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6273,20 +6273,44 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) { #else char *p, *result, *fullpath = NULL; isize len; - p = realpath(path, NULL); - fullpath = p; - if (p == NULL) { - // NOTE(bill): File does not exist - fullpath = cast(char *)path; - } + fullpath = realpath(path, NULL); + + if (fullpath == NULL) { + // NOTE(Jeroen): Path doesn't exist. + if (gb_strlen(path) > 0 && path[0] == '/') { + // But it is an absolute path, so return as-is. + + fullpath = (char *)path; + len = gb_strlen(fullpath) + 1; + result = gb_alloc_array(a, char, len + 1); + + gb_memmove(result, fullpath, len); + result[len] = 0; + + } else { + // Appears to be a relative path, so construct an absolute one relative to . + char cwd[4096]; + getcwd(&cwd[0], 4096); + + isize path_len = gb_strlen(path); + isize cwd_len = gb_strlen(cwd); + len = cwd_len + 1 + path_len + 1; + result = gb_alloc_array(a, char, len); - len = gb_strlen(fullpath); + gb_memmove(result, (void *)cwd, cwd_len); + result[cwd_len] = '/'; - result = gb_alloc_array(a, char, len + 1); - gb_memmove(result, fullpath, len); - result[len] = 0; - free(p); + gb_memmove(result + cwd_len + 1, (void *)path, gb_strlen(path)); + result[len] = 0; + } + } else { + len = gb_strlen(fullpath) + 1; + result = gb_alloc_array(a, char, len + 1); + gb_memmove(result, fullpath, len); + result[len] = 0; + free(fullpath); + } return result; #endif } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index f5cb84785..7781997f7 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -967,7 +967,12 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) } String lb_filepath_ll_for_module(lbModule *m) { - String path = m->gen->output_base; + String path = concatenate3_strings(permanent_allocator(), + build_context.build_paths[BuildPath_Output].basename, + STR_LIT("/"), + build_context.build_paths[BuildPath_Output].name + ); + if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } else if (USE_SEPARATE_MODULES) { @@ -978,7 +983,12 @@ String lb_filepath_ll_for_module(lbModule *m) { return path; } String lb_filepath_obj_for_module(lbModule *m) { - String path = m->gen->output_base; + String path = concatenate3_strings(permanent_allocator(), + build_context.build_paths[BuildPath_Output].basename, + STR_LIT("/"), + build_context.build_paths[BuildPath_Output].name + ); + if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 330059622..1a431a4ac 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -87,7 +87,6 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { return false; } - String init_fullpath = c->parser->init_fullpath; if (build_context.out_filepath.len == 0) { diff --git a/src/main.cpp b/src/main.cpp index fc8792ceb..7b0364149 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,6 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" - #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) @@ -57,16 +56,8 @@ gb_global Timings global_timings = {0}; #endif #include "query_data.cpp" - - -#if defined(GB_SYSTEM_WINDOWS) -// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. -#include "microsoft_craziness.h" -#endif - #include "bug_report.cpp" - // NOTE(bill): 'name' is used in debugging and profiling modes i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { isize const cmd_cap = 64<<20; // 64 MiB should be more than enough @@ -130,34 +121,35 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { } - - i32 linker_stage(lbGenerator *gen) { i32 result = 0; Timings *timings = &global_timings; - String output_base = gen->output_base; + String output_filename = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); + debugf("Linking %.*s\n", LIT(output_filename)); + + // TOOD(Jeroen): Make a `build_paths[BuildPath_Object] to avoid `%.*s.o`. if (is_arch_wasm()) { timings_start_section(timings, str_lit("wasm-ld")); #if defined(GB_SYSTEM_WINDOWS) result = system_exec_command_line_app("wasm-ld", - "\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", + "\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s", LIT(build_context.ODIN_ROOT), - LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else result = system_exec_command_line_app("wasm-ld", - "wasm-ld \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", - LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + "wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s", + LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #endif return result; } if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#ifdef GB_SYSTEM_UNIX +#if defined(GB_SYSTEM_UNIX) result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", LIT(target_os_names[build_context.metrics.os]), @@ -181,28 +173,11 @@ i32 linker_stage(lbGenerator *gen) { gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); - char const *output_ext = "exe"; gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); defer (gb_string_free(link_settings)); - - // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); - exit(1); - } - - if (build_context.ignore_microsoft_magic) { - find_result = {}; - } - // Add library search paths. - if (find_result.vs_library_path.len > 0) { - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - + if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) { String path = {}; auto add_path = [&](String path) { if (path[path.len-1] == '\\') { @@ -210,9 +185,9 @@ i32 linker_stage(lbGenerator *gen) { } link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); }; - add_path(find_result.windows_sdk_um_library_path); - add_path(find_result.windows_sdk_ucrt_library_path); - add_path(find_result.vs_library_path); + add_path(build_context.build_paths[BuildPath_Win_SDK_UM_Lib].basename); + add_path(build_context.build_paths[BuildPath_Win_SDK_UCRT_Lib].basename); + add_path(build_context.build_paths[BuildPath_VS_LIB].basename); } @@ -252,14 +227,14 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.build_mode == BuildMode_DynamicLibrary) { - output_ext = "dll"; link_settings = gb_string_append_fmt(link_settings, " /DLL"); } else { link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); } if (build_context.pdb_filepath != "") { - link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]); + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(pdb_path)); } if (build_context.no_crt) { @@ -300,13 +275,21 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } + String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]); + defer (gb_free(heap_allocator(), vs_exe_path.text)); + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; if (!build_context.use_lld) { // msvc if (build_context.has_resource) { + String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); + String res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); + defer (gb_free(heap_allocator(), rc_path.text)); + defer (gb_free(heap_allocator(), res_path.text)); + result = system_exec_command_line_app("msvc-link", - "\"rc.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", - LIT(output_base), - LIT(build_context.resource_filepath) + "\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"", + LIT(res_path), + LIT(rc_path) ); if (result) { @@ -314,13 +297,13 @@ i32 linker_stage(lbGenerator *gen) { } result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s " + "\"%.*slink.exe\" %s \"%.*s\" -OUT:\"%.*s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext, + LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename), link_settings, subsystem_str, LIT(build_context.link_flags), @@ -329,13 +312,13 @@ i32 linker_stage(lbGenerator *gen) { ); } else { result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s " + "\"%.*slink.exe\" %s -OUT:\"%.*s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext, + LIT(vs_exe_path), object_files, LIT(output_filename), link_settings, subsystem_str, LIT(build_context.link_flags), @@ -350,13 +333,13 @@ i32 linker_stage(lbGenerator *gen) { } else { // lld result = system_exec_command_line_app("msvc-lld-link", - "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " + "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(build_context.ODIN_ROOT), object_files, LIT(output_base),output_ext, + LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), link_settings, subsystem_str, LIT(build_context.link_flags), @@ -415,7 +398,7 @@ i32 linker_stage(lbGenerator *gen) { } else if (string_ends_with(lib, str_lit(".so"))) { // dynamic lib, relative path to executable // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtimeto the executable + // at runtime to the executable lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths @@ -431,9 +414,6 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } - // Unlike the Win32 linker code, the output_ext includes the dot, because - // typically executable files on *NIX systems don't have extensions. - String output_ext = {}; gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); if (build_context.no_crt) { @@ -461,26 +441,12 @@ i32 linker_stage(lbGenerator *gen) { // correctly this way since all the other dependencies provided implicitly // by the compiler frontend are still needed and most of the command // line arguments prepared previously are incompatible with ld. - // - // Shared libraries are .dylib on MacOS and .so on Linux. - if (build_context.metrics.os == TargetOs_darwin) { - output_ext = STR_LIT(".dylib"); - } else { - output_ext = STR_LIT(".so"); - } link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } else if (build_context.metrics.os != TargetOs_openbsd) { // OpenBSD defaults to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } - if (build_context.out_filepath.len > 0) { - //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that - isize pos = string_extension_position(build_context.out_filepath); - if (pos > 0) { - output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); - } - } gbString platform_lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(platform_lib_str)); @@ -507,7 +473,7 @@ i32 linker_stage(lbGenerator *gen) { defer (gb_string_free(link_command_line)); link_command_line = gb_string_appendc(link_command_line, object_files); - link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext)); + link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags)); @@ -524,9 +490,7 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe // to the symbols in the object file - result = system_exec_command_line_app("dsymutil", - "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) - ); + result = system_exec_command_line_app("dsymutil", "dsymutil %.*s", LIT(output_filename)); if (result) { return result; @@ -1526,6 +1490,10 @@ bool parse_build_flags(Array args) { gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); bad_flags = true; break; + } else if (!gb_file_exists((const char *)path.text)) { + gb_printf_err("Invalid -resource path %.*s, file does not exist.\n", LIT(path)); + bad_flags = true; + break; } build_context.resource_filepath = substring(path, 0, string_extension_position(path)); build_context.has_resource = true; @@ -1540,6 +1508,11 @@ bool parse_build_flags(Array args) { String path = value.value_string; path = string_trim_whitespace(path); if (is_build_flag_path_valid(path)) { + if (path_is_directory(path)) { + gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path)); + bad_flags = true; + break; + } // #if defined(GB_SYSTEM_WINDOWS) // String ext = path_extension(path); // if (ext != ".pdb") { @@ -2666,6 +2639,8 @@ int main(int arg_count, char const **arg_ptr) { return 1; } + init_filename = copy_string(permanent_allocator(), init_filename); + if (init_filename == "-help" || init_filename == "--help") { build_context.show_help = true; @@ -2688,6 +2663,12 @@ int main(int arg_count, char const **arg_ptr) { gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n"); return 1; + } else { + String const ext = str_lit(".odin"); + if (!string_ends_with(init_filename, ext)) { + gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); + return 1; + } } } } @@ -2709,13 +2690,24 @@ int main(int arg_count, char const **arg_ptr) { get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared"))); } - init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr); // if (build_context.word_size == 4 && build_context.metrics.os != TargetOs_js) { // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0])); // return 1; // } + // Set and check build paths... + if (!init_build_paths(init_filename)) { + return 1; + } + + if (build_context.show_debug_messages) { + for_array(i, build_context.build_paths) { + String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); + debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); + } + } + init_global_thread_pool(); defer (thread_pool_destroy(&global_thread_pool)); @@ -2732,6 +2724,8 @@ int main(int arg_count, char const **arg_ptr) { } defer (destroy_parser(parser)); + // TODO(jeroen): Remove the `init_filename` param. + // Let's put that on `build_context.build_paths[0]` instead. if (parse_packages(parser, init_filename) != ParseFile_None) { return 1; } @@ -2810,16 +2804,14 @@ int main(int arg_count, char const **arg_ptr) { } if (run_output) { + String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); + defer (gb_free(heap_allocator(), exe_name.text)); + #if defined(GB_SYSTEM_WINDOWS) - return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen->output_base), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "%.*s %.*s", LIT(exe_name), LIT(run_args_string)); #else - //NOTE(thebirk): This whole thing is a little leaky - String output_ext = {}; - String complete_path = concatenate_strings(permanent_allocator(), gen->output_base, output_ext); - complete_path = path_to_full_path(permanent_allocator(), complete_path); - return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); #endif } - return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index 767119aa8..df7f908a6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5751,7 +5751,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } } } - + { // Add these packages serially and then process them parallel mutex_lock(&p->wait_mutex); diff --git a/src/path.cpp b/src/path.cpp new file mode 100644 index 000000000..8d8e532b8 --- /dev/null +++ b/src/path.cpp @@ -0,0 +1,333 @@ +/* + Path handling utilities. +*/ + +#if defined(GB_SYSTEM_WINDOWS) + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + String16 wstr = string_to_string16(a, path); + defer (gb_free(a, wstr.text)); + + i32 attribs = GetFileAttributesW(wstr.text); + if (attribs < 0) return false; + + return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + +#else + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + char *copy = cast(char *)copy_string(a, path).text; + defer (gb_free(a, copy)); + + struct stat s; + if (stat(copy, &s) == 0) { + return (s.st_mode & S_IFDIR) != 0; + } + return false; + } +#endif + + +String path_to_full_path(gbAllocator a, String path) { + gbAllocator ha = heap_allocator(); + char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); + defer (gb_free(ha, path_c)); + + char *fullpath = gb_path_get_full_name(a, path_c); + String res = string_trim_whitespace(make_string_c(fullpath)); +#if defined(GB_SYSTEM_WINDOWS) + for (isize i = 0; i < res.len; i++) { + if (res.text[i] == '\\') { + res.text[i] = '/'; + } + } +#endif + return copy_string(a, res); +} + +struct Path { + String basename; + String name; + String ext; +}; + +// NOTE(Jeroen): Naively turns a Path into a string. +String path_to_string(gbAllocator a, Path path) { + if (path.basename.len + path.name.len + path.ext.len == 0) { + return make_string(nullptr, 0); + } + + isize len = path.basename.len + 1 + path.name.len + 1; + if (path.ext.len > 0) { + len += path.ext.len + 1; + } + + u8 *str = gb_alloc_array(a, u8, len); + + isize i = 0; + gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len; + gb_memmove(str+i, "/", 1); i += 1; + gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len; + if (path.ext.len > 0) { + gb_memmove(str+i, ".", 1); i += 1; + gb_memmove(str+i, path.ext.text, path.ext.len); i += path.ext.len; + } + str[i] = 0; + + String res = make_string(str, i); + res = string_trim_whitespace(res); + return res; +} + +// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`. +String path_to_full_path(gbAllocator a, Path path) { + String temp = path_to_string(heap_allocator(), path); + defer (gb_free(heap_allocator(), temp.text)); + + return path_to_full_path(a, temp); +} + +// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path, +// and then breaks it into its components to make a Path. +Path path_from_string(gbAllocator a, String const &path) { + Path res = {}; + + if (path.len == 0) return res; + + String fullpath = path_to_full_path(a, path); + defer (gb_free(heap_allocator(), fullpath.text)); + + res.basename = directory_from_path(fullpath); + res.basename = copy_string(a, res.basename); + + if (string_ends_with(fullpath, '/')) { + // It's a directory. We don't need to tinker with the name and extension. + return res; + } + + isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len; + res.name = substring(fullpath, name_start, fullpath.len); + res.name = remove_extension_from_path(res.name); + res.name = copy_string(a, res.name); + + res.ext = path_extension(fullpath, false); // false says not to include the dot. + res.ext = copy_string(a, res.ext); + return res; +} + +bool path_is_directory(Path path) { + String path_string = path_to_full_path(heap_allocator(), path); + defer (gb_free(heap_allocator(), path_string.text)); + + return path_is_directory(path_string); +} + +struct FileInfo { + String name; + String fullpath; + i64 size; + bool is_dir; +}; + +enum ReadDirectoryError { + ReadDirectory_None, + + ReadDirectory_InvalidPath, + ReadDirectory_NotExists, + ReadDirectory_Permission, + ReadDirectory_NotDir, + ReadDirectory_Empty, + ReadDirectory_Unknown, + + ReadDirectory_COUNT, +}; + +i64 get_file_size(String path) { + char *c_str = alloc_cstring(heap_allocator(), path); + defer (gb_free(heap_allocator(), c_str)); + + gbFile f = {}; + gbFileError err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + if (err != gbFileError_None) { + return -1; + } + return gb_file_size(&f); +} + + +#if defined(GB_SYSTEM_WINDOWS) +ReadDirectoryError read_directory(String path, Array *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + while (path.len > 0) { + Rune end = path[path.len-1]; + if (end == '/') { + path.len -= 1; + } else if (end == '\\') { + path.len -= 1; + } else { + break; + } + } + + if (path.len == 0) { + return ReadDirectory_InvalidPath; + } + { + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + case gbFileError_Invalid: return ReadDirectory_InvalidPath; + case gbFileError_NotExists: return ReadDirectory_NotExists; + // case gbFileError_Permission: return ReadDirectory_Permission; + } + } + + if (!path_is_directory(path)) { + return ReadDirectory_NotDir; + } + + + char *new_path = gb_alloc_array(a, char, path.len+3); + defer (gb_free(a, new_path)); + + gb_memmove(new_path, path.text, path.len); + gb_memmove(new_path+path.len, "/*", 2); + new_path[path.len+2] = 0; + + String np = make_string(cast(u8 *)new_path, path.len+2); + String16 wstr = string_to_string16(a, np); + defer (gb_free(a, wstr.text)); + + WIN32_FIND_DATAW file_data = {}; + HANDLE find_file = FindFirstFileW(wstr.text, &file_data); + if (find_file == INVALID_HANDLE_VALUE) { + return ReadDirectory_Unknown; + } + defer (FindClose(find_file)); + + array_init(fi, a, 0, 100); + + do { + wchar_t *filename_w = file_data.cFileName; + i64 size = cast(i64)file_data.nFileSizeLow; + size |= (cast(i64)file_data.nFileSizeHigh) << 32; + String name = string16_to_string(a, make_string16_c(filename_w)); + if (name == "." || name == "..") { + gb_free(a, name.text); + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + array_add(fi, info); + } while (FindNextFileW(find_file, &file_data)); + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) + +#include + +ReadDirectoryError read_directory(String path, Array *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + char *c_path = alloc_cstring(a, path); + defer (gb_free(a, c_path)); + + DIR *dir = opendir(c_path); + if (!dir) { + switch (errno) { + case ENOENT: + return ReadDirectory_NotExists; + case EACCES: + return ReadDirectory_Permission; + case ENOTDIR: + return ReadDirectory_NotDir; + default: + // ENOMEM: out of memory + // EMFILE: per-process limit on open fds reached + // ENFILE: system-wide limit on total open files reached + return ReadDirectory_Unknown; + } + GB_PANIC("unreachable"); + } + + array_init(fi, a, 0, 100); + + for (;;) { + struct dirent *entry = readdir(dir); + if (entry == nullptr) { + break; + } + + String name = make_string_c(entry->d_name); + if (name == "." || name == "..") { + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + filepath.text[filepath.len] = 0; + + + struct stat dir_stat = {}; + + if (stat((char *)filepath.text, &dir_stat)) { + continue; + } + + if (S_ISDIR(dir_stat.st_mode)) { + continue; + } + + i64 size = dir_stat.st_size; + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + array_add(fi, info); + } + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#else +#error Implement read_directory +#endif + diff --git a/src/string.cpp b/src/string.cpp index d3dbc6904..3515df48e 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -245,15 +245,14 @@ gb_inline isize string_extension_position(String const &str) { return dot_pos; } -String path_extension(String const &str) { +String path_extension(String const &str, bool include_dot = true) { isize pos = string_extension_position(str); if (pos < 0) { return make_string(nullptr, 0); } - return substring(str, pos, str.len); + return substring(str, include_dot ? pos : pos + 1, str.len); } - String string_trim_whitespace(String str) { while (str.len > 0 && rune_is_whitespace(str[str.len-1])) { str.len--; @@ -328,7 +327,10 @@ String directory_from_path(String const &s) { break; } } - return substring(s, 0, i); + if (i >= 0) { + return substring(s, 0, i); + } + return substring(s, 0, 0); } String concatenate_strings(gbAllocator a, String const &x, String const &y) { diff --git a/tests/core/build.bat b/tests/core/build.bat index 2f9ba672e..1973c22aa 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -5,61 +5,61 @@ python3 download_assets.py echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% +%PATH_TO_ODIN% run image %COMMON% -out:test_image echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% +%PATH_TO_ODIN% run compress %COMMON% -out:test_compress echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% +%PATH_TO_ODIN% run strings %COMMON% -out:test_strings echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size +%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_hash echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size +%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_odin echo --- echo Running core:crypto hash tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% +%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding/hxa %COMMON% -%PATH_TO_ODIN% run encoding/json %COMMON% -%PATH_TO_ODIN% run encoding/varint %COMMON% +%PATH_TO_ODIN% run encoding/hxa %COMMON% -out:test_hxa +%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json +%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% +%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise echo --- echo Running core:math tests echo --- -%PATH_TO_ODIN% run math %COMMON% +%PATH_TO_ODIN% run math %COMMON% -out:test_math echo --- echo Running core:math/linalg/glsl tests echo --- -%PATH_TO_ODIN% run math/linalg/glsl %COMMON% +%PATH_TO_ODIN% run math/linalg/glsl %COMMON% -out:test_glsl echo --- echo Running core:path/filepath tests echo --- -%PATH_TO_ODIN% run path/filepath %COMMON% +%PATH_TO_ODIN% run path/filepath %COMMON% -out:test_filepath echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% +%PATH_TO_ODIN% run reflect %COMMON% -out:test_reflect diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index 16bdbc8ca..ad199d775 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -4,7 +4,7 @@ set PATH_TO_ODIN==..\..\..\..\odin set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= -set OUT_NAME=math_big_test_library +set OUT_NAME=math_big_test_library.dll set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style echo --- echo Running core:math/big tests diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 117a9a5f1..91ec99e05 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -8,10 +8,10 @@ COMMON="-collection:tests=tests -out:tests/issues/build/test_issue" set -x ./odin build tests/issues/test_issue_829.odin $COMMON -file -tests/issues/build/test_issue +tests/issues/build/test_issue.bin ./odin build tests/issues/test_issue_1592.odin $COMMON -file -tests/issues/build/test_issue +tests/issues/build/test_issue.bin set +x -- cgit v1.2.3