From 7ab531bd21d19338e2e6fb9ed12a9443cca95d7e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 8 Jul 2023 12:07:11 +0100 Subject: Add `-tilde` for working on the new compiler --- src/main.cpp | 57 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 17 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index db2702b19..c16cfa35f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,6 +71,10 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" +#if defined(GB_SYSTEM_WINDOWS) +#include "tilde_backend.cpp" +#endif + #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) @@ -696,6 +700,8 @@ enum BuildFlagKind { BuildFlag_InternalIgnoreLLVMBuild, #if defined(GB_SYSTEM_WINDOWS) + BuildFlag_Tilde, + BuildFlag_IgnoreVsSearch, BuildFlag_ResourceFile, BuildFlag_WindowsPdbName, @@ -870,6 +876,8 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); #if defined(GB_SYSTEM_WINDOWS) + add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build); @@ -1537,6 +1545,10 @@ gb_internal bool parse_build_flags(Array args) { build_context.ignore_llvm_build = true; break; #if defined(GB_SYSTEM_WINDOWS) + case BuildFlag_Tilde: + build_context.tilde_backend = true; + break; + case BuildFlag_IgnoreVsSearch: { GB_ASSERT(value.kind == ExactValue_Invalid); build_context.ignore_microsoft_magic = true; @@ -2882,27 +2894,38 @@ int main(int arg_count, char const **arg_ptr) { return 0; } - MAIN_TIME_SECTION("LLVM API Code Gen"); - lbGenerator *gen = gb_alloc_item(permanent_allocator(), lbGenerator); - if (!lb_init_generator(gen, checker)) { - return 1; - } - if (lb_generate_code(gen)) { - switch (build_context.build_mode) { - case BuildMode_Executable: - case BuildMode_DynamicLibrary: - i32 result = linker_stage(gen); - if (result) { - if (build_context.show_timings) { - show_timings(checker, &global_timings); +#if defined(GB_SYSTEM_WINDOWS) + if (build_context.tilde_backend) { + MAIN_TIME_SECTION("Tilde Code Gen"); + if (!tb_generate_code(checker)) { + return 1; + } + + } else +#endif + { + MAIN_TIME_SECTION("LLVM API Code Gen"); + lbGenerator *gen = gb_alloc_item(permanent_allocator(), lbGenerator); + if (!lb_init_generator(gen, checker)) { + return 1; + } + if (lb_generate_code(gen)) { + switch (build_context.build_mode) { + case BuildMode_Executable: + case BuildMode_DynamicLibrary: + i32 result = linker_stage(gen); + if (result) { + if (build_context.show_timings) { + show_timings(checker, &global_timings); + } + return result; } - return result; + break; } - break; } - } - remove_temp_files(gen); + remove_temp_files(gen); + } if (build_context.show_timings) { show_timings(checker, &global_timings); -- cgit v1.2.3 From f0e77a309d2c1f93cabb2948ae3eefd31b7c1e31 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 8 Jul 2023 12:43:20 +0100 Subject: Hellope World! with Tilde --- src/main.cpp | 1 - src/tilde/tb.lib | Bin 4004042 -> 4295510 bytes src/tilde_backend.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index c16cfa35f..adb955460 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2900,7 +2900,6 @@ int main(int arg_count, char const **arg_ptr) { if (!tb_generate_code(checker)) { return 1; } - } else #endif { diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index bea6a58e3..ab5b02014 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 6f51784e8..87e1a1329 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -13,6 +13,43 @@ bool tb_generate_code(Checker *c) { - gb_printf_err("TODO(bill): implement Tilde Backend\n"); + TB_FeatureSet feature_set = {}; + bool is_jit = false; + TB_Module *m = tb_module_create(TB_ARCH_X86_64, TB_SYSTEM_WINDOWS, &feature_set, is_jit); + defer (tb_module_destroy(m)); + tb_module_set_tls_index(m, "_tls_index"); + + + TB_Arena *arena = nullptr; + + { + TB_PrototypeParam printf_ret = {TB_TYPE_I32}; + TB_PrototypeParam printf_params = {TB_TYPE_PTR}; + TB_FunctionPrototype *printf_proto = tb_prototype_create(m, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); + TB_External *printf_proc = tb_extern_create(m, "printf", TB_EXTERNAL_SO_LOCAL); + + TB_PrototypeParam main_ret = {TB_TYPE_I32}; + TB_FunctionPrototype *main_proto = tb_prototype_create(m, TB_STDCALL, 0, nullptr, 1, &main_ret, false); + TB_Function * p = tb_function_create(m, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); + tb_function_set_prototype(p, main_proto, arena); + + + TB_Node *params[2] = {}; + params[0] = tb_inst_cstring(p, "Hellope %s!\n"); + params[1] = tb_inst_cstring(p, "World"); + TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); + gb_unused(output); + + TB_Node *value = tb_inst_uint(p, TB_TYPE_I32, 0); + tb_inst_ret(p, 1, &value); + + tb_module_compile_function(m, p, TB_ISEL_FAST); + + TB_ExportBuffer export_buffer = tb_module_object_export(m, TB_DEBUGFMT_NONE); + defer (tb_export_buffer_free(export_buffer)); + + char const *path = "W:/Odin/tilde_main.obj"; + GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); + } return false; } \ No newline at end of file -- cgit v1.2.3 From 7cd2d14b6410a17783020cea390f2be9534fa432 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Jul 2023 11:58:18 +0100 Subject: Very start of working on Tilde Backend for Odin --- src/entity.cpp | 12 +- src/llvm_backend.hpp | 2 + src/main.cpp | 8 +- src/tilde_backend.cpp | 785 +++++++++++++++++++++++++++++++++++++++++++++++--- src/tilde_backend.hpp | 160 ++++++++++ 5 files changed, 927 insertions(+), 40 deletions(-) create mode 100644 src/tilde_backend.hpp (limited to 'src/main.cpp') diff --git a/src/entity.cpp b/src/entity.cpp index 649dd900d..c943863fc 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -2,8 +2,6 @@ struct Scope; struct Checker; struct Type; struct DeclInfo; -struct lbModule; -struct lbProcedure; #define ENTITY_KINDS \ @@ -183,8 +181,14 @@ struct Entity { Entity * aliased_of; - lbModule * code_gen_module; - lbProcedure *code_gen_procedure; + union { + struct lbModule *code_gen_module; + struct cgModule *cg_module; + }; + union { + struct lbProcedure *code_gen_procedure; + struct cgProcedure *cg_procedure; + }; u64 order_in_src; String deprecated_message; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index ce01485ff..15833c63a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -346,7 +346,9 @@ struct lbProcedure { }; +#ifndef ABI_PKG_NAME_SEPARATOR #define ABI_PKG_NAME_SEPARATOR "." +#endif #if !ODIN_LLVM_MINIMUM_VERSION_14 diff --git a/src/main.cpp b/src/main.cpp index adb955460..398f31b68 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2897,9 +2897,15 @@ int main(int arg_count, char const **arg_ptr) { #if defined(GB_SYSTEM_WINDOWS) if (build_context.tilde_backend) { MAIN_TIME_SECTION("Tilde Code Gen"); - if (!tb_generate_code(checker)) { + if (!cg_generate_code(checker)) { return 1; } + + if (build_context.show_timings) { + show_timings(checker, &global_timings); + } + + return 0; } else #endif { diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 63466e132..abaf0b825 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -1,23 +1,716 @@ -#if defined(GB_SYSTEM_WINDOWS) - #pragma warning(push) - #pragma warning(disable: 4200) - #pragma warning(disable: 4201) - #define restrict gb_restrict -#endif +#include "tilde_backend.hpp" -#include "tilde/tb.h" +gb_internal cgValue cg_value(TB_Global *g, Type *type) { + return cg_value((TB_Symbol *)g, type); +} +gb_internal cgValue cg_value(TB_External *e, Type *type) { + return cg_value((TB_Symbol *)e, type); +} +gb_internal cgValue cg_value(TB_Function *f, Type *type) { + return cg_value((TB_Symbol *)f, type); +} +gb_internal cgValue cg_value(TB_Symbol *s, Type *type) { + cgValue v = {}; + v.kind = cgValue_Symbol; + v.type = type; + v.symbol = s; + return v; +} +gb_internal cgValue cg_value(TB_Node *node, Type *type) { + cgValue v = {}; + v.kind = cgValue_Value; + v.type = type; + v.node = node; + return v; +} +gb_internal cgValue cg_lvalue_addr(TB_Node *node, Type *type) { + GB_ASSERT(node->dt.type == TB_PTR); + cgValue v = {}; + v.kind = cgValue_Addr; + v.type = type; + v.node = node; + return v; +} -#if defined(GB_SYSTEM_WINDOWS) - #pragma warning(pop) -#endif +gb_internal cgAddr cg_addr(cgValue const &value) { + cgAddr addr = {}; + addr.kind = cgAddr_Default; + addr.addr = value; + if (addr.addr.kind == cgValue_Addr) { + GB_ASSERT(addr.addr.node != nullptr); + addr.addr.kind = cgValue_Value; + addr.addr.type = alloc_type_pointer(addr.addr.type); + } + return addr; +} + + +gb_internal void cg_add_entity(cgModule *m, Entity *e, cgValue const &val) { + if (e) { + rw_mutex_lock(&m->values_mutex); + map_set(&m->values, e, val); + rw_mutex_unlock(&m->values_mutex); + } +} + +gb_internal void cg_add_member(cgModule *m, String const &name, cgValue const &val) { + if (name.len > 0) { + rw_mutex_lock(&m->values_mutex); + string_map_set(&m->members, name, val); + rw_mutex_unlock(&m->values_mutex); + } +} + +gb_internal void cg_add_procedure_value(cgModule *m, cgProcedure *p) { + rw_mutex_lock(&m->values_mutex); + if (p->entity != nullptr) { + map_set(&m->procedure_values, p->func, p->entity); + } + string_map_set(&m->procedures, p->name, p); + rw_mutex_unlock(&m->values_mutex); + +} + +gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { + auto *set = &info->minimum_dependency_type_info_set; + isize index = type_info_index(info, type, err_on_not_found); + if (index >= 0) { + auto *found = map_get(set, index); + if (found) { + GB_ASSERT(*found >= 0); + return *found + 1; + } + } + if (err_on_not_found) { + GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + } + return -1; +} + +gb_internal void cg_create_global_variables(cgModule *m) { + if (build_context.no_rtti) { + return; + } + + CheckerInfo *info = m->info; + { // Add type info data + isize max_type_info_count = info->minimum_dependency_type_info_set.count+1; + // gb_printf_err("max_type_info_count: %td\n", max_type_info_count); + Type *t = alloc_type_array(t_type_info, max_type_info_count); + + TB_Global *g = tb_global_create(m->mod, CG_TYPE_INFO_DATA_NAME, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, max_type_info_count); + + cgValue value = cg_value(g, alloc_type_pointer(t)); + cg_global_type_info_data_entity = alloc_entity_variable(nullptr, make_token_ident(CG_TYPE_INFO_DATA_NAME), t, EntityState_Resolved); + cg_add_entity(m, cg_global_type_info_data_entity, value); + } + + { // Type info member buffer + // NOTE(bill): Removes need for heap allocation by making it global memory + isize count = 0; + + for (Type *t : m->info->type_info_types) { + isize index = cg_type_info_index(m->info, t, false); + if (index < 0) { + continue; + } + + switch (t->kind) { + case Type_Union: + count += t->Union.variants.count; + break; + case Type_Struct: + count += t->Struct.fields.count; + break; + case Type_Tuple: + count += t->Tuple.variables.count; + break; + } + } + + if (count > 0) { + { + char const *name = CG_TYPE_INFO_TYPES_NAME; + Type *t = alloc_type_array(t_type_info_ptr, count); + TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_types = cg_addr(cg_value(g, alloc_type_pointer(t))); + + } + { + char const *name = CG_TYPE_INFO_NAMES_NAME; + Type *t = alloc_type_array(t_string, count); + TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_names = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + { + char const *name = CG_TYPE_INFO_OFFSETS_NAME; + Type *t = alloc_type_array(t_uintptr, count); + TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_offsets = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + + { + char const *name = CG_TYPE_INFO_USINGS_NAME; + Type *t = alloc_type_array(t_bool, count); + TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_usings = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + + { + char const *name = CG_TYPE_INFO_TAGS_NAME; + Type *t = alloc_type_array(t_string, count); + TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_tags = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + } + } +} + +cgModule *cg_module_create(Checker *c) { + cgModule *m = gb_alloc_item(permanent_allocator(), cgModule); + + m->checker = c; + m->info = &c->info; -bool tb_generate_code(Checker *c) { TB_FeatureSet feature_set = {}; bool is_jit = false; - TB_Module *m = tb_module_create(TB_ARCH_X86_64, TB_SYSTEM_WINDOWS, &feature_set, is_jit); - defer (tb_module_destroy(m)); - tb_module_set_tls_index(m, "_tls_index"); + m->mod = tb_module_create(TB_ARCH_X86_64, TB_SYSTEM_WINDOWS, &feature_set, is_jit); + tb_module_set_tls_index(m->mod, "_tls_index"); + + map_init(&m->values); + array_init(&m->procedures_to_generate, heap_allocator()); + + return m; +} + +void cg_module_destroy(cgModule *m) { + map_destroy(&m->values); + array_free(&m->procedures_to_generate); + + tb_module_destroy(m->mod); +} + +gb_internal String cg_set_nested_type_name_ir_mangled_name(Entity *e, cgProcedure *p) { + // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration + // and as a result, the declaration does not have time to determine what it should be + + GB_ASSERT(e != nullptr && e->kind == Entity_TypeName); + if (e->TypeName.ir_mangled_name.len != 0) { + return e->TypeName.ir_mangled_name; + } + GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0); + + if (p == nullptr) { + Entity *proc = nullptr; + if (e->parent_proc_decl != nullptr) { + proc = e->parent_proc_decl->entity; + } else { + Scope *scope = e->scope; + while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) { + scope = scope->parent; + } + GB_ASSERT(scope != nullptr); + GB_ASSERT(scope->flags & ScopeFlag_Proc); + proc = scope->procedure_entity; + } + GB_ASSERT(proc->kind == Entity_Procedure); + if (proc->cg_procedure != nullptr) { + p = proc->cg_procedure; + } + } + + // NOTE(bill): Generate a new name + // parent_proc.name-guid + String ts_name = e->token.string; + + if (p != nullptr) { + isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); + u32 guid = 1+p->module->nested_type_name_guid.fetch_add(1); + name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(p->name), LIT(ts_name), guid); + + String name = make_string(cast(u8 *)name_text, name_len-1); + e->TypeName.ir_mangled_name = name; + return name; + } else { + // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now + isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); + static std::atomic guid; + name_len = gb_snprintf(name_text, name_len, "_internal" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(ts_name), 1+guid.fetch_add(1)); + + String name = make_string(cast(u8 *)name_text, name_len-1); + e->TypeName.ir_mangled_name = name; + return name; + } +} + +gb_internal String cg_mangle_name(cgModule *m, Entity *e) { + String name = e->token.string; + + AstPackage *pkg = e->pkg; + GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name)); + String pkgn = pkg->name; + GB_ASSERT(!rune_is_digit(pkgn[0])); + if (pkgn == "llvm") { + GB_PANIC("llvm. entities are not allowed with the tilde backend"); + } + + isize max_len = pkgn.len + 1 + name.len + 1; + bool require_suffix_id = is_type_polymorphic(e->type, true); + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { + require_suffix_id = true; + } else if (is_blank_ident(e->token)) { + require_suffix_id = true; + }if (e->flags & EntityFlag_NotExported) { + require_suffix_id = true; + } + + if (require_suffix_id) { + max_len += 21; + } + + char *new_name = gb_alloc_array(permanent_allocator(), char, max_len); + isize new_name_len = gb_snprintf( + new_name, max_len, + "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s", LIT(pkgn), LIT(name) + ); + if (require_suffix_id) { + char *str = new_name + new_name_len-1; + isize len = max_len-new_name_len; + isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); + new_name_len += extra-1; + } + + String mangled_name = make_string((u8 const *)new_name, new_name_len-1); + return mangled_name; +} + +String cg_get_entity_name(cgModule *m, Entity *e) { + if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { + return e->TypeName.ir_mangled_name; + } + GB_ASSERT(e != nullptr); + + if (e->pkg == nullptr) { + return e->token.string; + } + + if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { + return cg_set_nested_type_name_ir_mangled_name(e, nullptr); + } + + String name = {}; + + bool no_name_mangle = false; + + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; + if (e->Variable.link_name.len > 0) { + return e->Variable.link_name; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + return e->Procedure.link_name; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + no_name_mangle = true; + } + + if (!no_name_mangle) { + name = cg_mangle_name(m, e); + } + if (name.len == 0) { + name = e->token.string; + } + + if (e->kind == Entity_TypeName) { + e->TypeName.ir_mangled_name = name; + } else if (e->kind == Entity_Procedure) { + e->Procedure.link_name = name; + } + + return name; +} + + +struct cgGlobalVariable { + cgValue var; + cgValue init; + DeclInfo *decl; + bool is_initialized; +}; + + +gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) { + GB_ASSERT(type != nullptr); + type = base_type(type); + GB_ASSERT(type->kind == Type_Proc); + TypeProc *pt = &type->Proc; + + auto params = array_make(heap_allocator(), 0, pt->param_count); + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + TB_PrototypeParam param = {}; + + Type *t = core_type(e->type); + i64 sz = type_size_of(t); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + case Basic_rune: + case Basic_int: + case Basic_uint: + case Basic_uintptr: + param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + case Basic_f16: param.dt = TB_TYPE_I16; break; + case Basic_f32: param.dt = TB_TYPE_F32; break; + case Basic_f64: param.dt = TB_TYPE_F64; break; + + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + param.dt = TB_TYPE_PTR; + break; + + + case Basic_rawptr: + param.dt = TB_TYPE_PTR; + break; + case Basic_string: // ^u8 + int + param.dt = TB_TYPE_PTR; + break; + case Basic_cstring: // ^u8 + param.dt = TB_TYPE_PTR; + break; + case Basic_any: // rawptr + ^Type_Info + param.dt = TB_TYPE_PTR; + break; + + case Basic_typeid: + param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + // Endian Specific Types + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_i128le: + case Basic_u128le: + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_i128be: + case Basic_u128be: + param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + case Basic_f16le: param.dt = TB_TYPE_I16; break; + case Basic_f32le: param.dt = TB_TYPE_F32; break; + case Basic_f64le: param.dt = TB_TYPE_F64; break; + + case Basic_f16be: param.dt = TB_TYPE_I16; break; + case Basic_f32be: param.dt = TB_TYPE_F32; break; + case Basic_f64be: param.dt = TB_TYPE_F64; break; + } + + } + + if (param.dt.width != 0) { + if (is_blank_ident(e->token)) { + param.name = alloc_cstring(temporary_allocator(), e->token.string); + } + array_add(¶ms, param); + } + } + + return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, 0, nullptr, false); +} + +gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false) { + GB_ASSERT(entity != nullptr); + GB_ASSERT(entity->kind == Entity_Procedure); + if (!entity->Procedure.is_foreign) { + if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) { + GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false)); + } + } + + String link_name = cg_get_entity_name(m, entity); + + cgProcedure *p = nullptr; + { + StringHashKey key = string_hash_string(link_name); + cgValue *found = string_map_get(&m->members, key); + if (found) { + cg_add_entity(m, entity, *found); + p = string_map_must_get(&m->procedures, key); + if (!ignore_body && p->func != nullptr) { + return nullptr; + } + } + } + + if (p == nullptr) { + p = gb_alloc_item(permanent_allocator(), cgProcedure); + } + + p->module = m; + p->entity = entity; + p->name = link_name; + + DeclInfo *decl = entity->decl_info; + + ast_node(pl, ProcLit, decl->proc_lit); + Type *pt = base_type(entity->type); + GB_ASSERT(pt->kind == Type_Proc); + + p->type = entity->type; + p->type_expr = decl->type_expr; + p->body = pl->body; + p->inlining = pl->inlining; + p->is_foreign = entity->Procedure.is_foreign; + p->is_export = entity->Procedure.is_export; + p->is_entry_point = false; + + gbAllocator a = heap_allocator(); + p->children.allocator = a; + // p->defer_stmts.allocator = a; + // p->blocks.allocator = a; + // p->branch_blocks.allocator = a; + // p->context_stack.allocator = a; + // p->scope_stack.allocator = a; + // map_init(&p->tuple_fix_map, 0); + + char const *link_name_c = alloc_cstring(temporary_allocator(), link_name); + + TB_Linkage linkage = TB_LINKAGE_PRIVATE; + if (p->is_export) { + linkage = TB_LINKAGE_PUBLIC; + } else if (p->is_foreign || ignore_body) { + if (ignore_body) { + linkage = TB_LINKAGE_PUBLIC; + } + p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name_c, TB_EXTERNAL_SO_LOCAL); + } + + if (p->symbol == nullptr) { + p->func = tb_function_create(m->mod, link_name_c, linkage, TB_COMDAT_NONE); + tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); + p->symbol = cast(TB_Symbol *)p->func; + } + + cgValue proc_value = cg_value(p->symbol, p->type); + cg_add_entity(m, entity, proc_value); + cg_add_member(m, p->name, proc_value); + cg_add_procedure_value(m, p); + + + return p; +} + +gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &link_name, Type *type) { + auto *prev_found = string_map_get(&m->members, link_name); + GB_ASSERT_MSG(prev_found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name)); + + cgProcedure *p = gb_alloc_item(permanent_allocator(), cgProcedure); + + p->module = m; + p->name = link_name; + + p->type = type; + p->type_expr = nullptr; + p->body = nullptr; + p->tags = 0; + p->inlining = ProcInlining_none; + p->is_foreign = false; + p->is_export = false; + p->is_entry_point = false; + + gbAllocator a = heap_allocator(); + p->children.allocator = a; + // p->defer_stmts.allocator = a; + // p->blocks.allocator = a; + // p->branch_blocks.allocator = a; + // p->context_stack.allocator = a; + // map_init(&p->tuple_fix_map, 0); + + + + char const *link_name_c = alloc_cstring(temporary_allocator(), link_name); + + TB_Linkage linkage = TB_LINKAGE_PRIVATE; + + p->func = tb_function_create(m->mod, link_name_c, linkage, TB_COMDAT_NONE); + tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); + p->symbol = cast(TB_Symbol *)p->func; + + cgValue proc_value = cg_value(p->symbol, p->type); + cg_add_member(m, p->name, proc_value); + cg_add_procedure_value(m, p); + + return p; +} + +gb_internal void cg_procedure_begin(cgProcedure *p) { + if (p == nullptr || p->func == nullptr) { + return; + } + gb_printf_err("cg_procedure_begin %.*s\n", LIT(p->name)); +} + +gb_internal void cg_procedure_end(cgProcedure *p) { + if (p == nullptr || p->func == nullptr) { + return; + } + gb_printf_err("cg_procedure_end %.*s\n", LIT(p->name)); + tb_inst_ret(p->func, 0, nullptr); + tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); +} + +gb_internal void cg_procedure_build_body(cgProcedure *p) { + if (p->body == nullptr) { + return; + } + + // TODO(bill): +} + + +gb_internal bool cg_generate_code(Checker *c) { + TIME_SECTION("Tilde Module Initializtion"); + + CheckerInfo *info = &c->info; + gb_unused(info); + + cgModule *m = cg_module_create(c); + defer (cg_module_destroy(m)); + + TIME_SECTION("Tilde Global Variables"); + + cg_create_global_variables(m); + + // isize global_variable_max_count = 0; + // bool already_has_entry_point = false; + + // for (Entity *e : info->entities) { + // String name = e->token.string; + + // if (e->kind == Entity_Variable) { + // global_variable_max_count++; + // } else if (e->kind == Entity_Procedure) { + // if ((e->scope->flags&ScopeFlag_Init) && name == "main") { + // GB_ASSERT(e == info->entry_point); + // } + // 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" || + // link_name == "DllMain" || + // link_name == "WinMain" || + // link_name == "wWinMain" || + // link_name == "mainCRTStartup" || + // link_name == "_start") { + // already_has_entry_point = true; + // } + // } + // } + // } + // } + // auto global_variables = array_make(permanent_allocator(), 0, global_variable_max_count); + + if (true) { + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + cgProcedure *p = cg_procedure_create_dummy(m, str_lit(CG_STARTUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + + cg_procedure_begin(p); + cg_procedure_end(p); + } + + if (true) { + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + cgProcedure *p = cg_procedure_create_dummy(m, str_lit(CG_CLEANUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + + cg_procedure_begin(p); + cg_procedure_end(p); + } + + auto *min_dep_set = &info->minimum_dependency_set; + + for (Entity *e : info->entities) { + String name = e->token.string; + Scope * scope = e->scope; + + if ((scope->flags & ScopeFlag_File) == 0) { + continue; + } + + Scope *package_scope = scope->parent; + GB_ASSERT(package_scope->flags & ScopeFlag_Pkg); + + if (e->kind != Entity_Procedure) { + continue; + } + + if (!ptr_set_exists(min_dep_set, e)) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + continue; + } + if (cgProcedure *p = cg_procedure_create(m, e)) { + array_add(&m->procedures_to_generate, p); + } + } + + + for (isize i = 0; i < m->procedures_to_generate.count; i++) { + cgProcedure *p = m->procedures_to_generate[i]; + cg_procedure_begin(p); + if (p->name == "main") { + cg_procedure_build_body(p); + } + cg_procedure_end(p); + } + + + + //////////////////////////////////////////////////////////////////////////////////// + TB_Arena *arena = tb_default_arena(); @@ -25,36 +718,36 @@ bool tb_generate_code(Checker *c) { { TB_Global *str_data = nullptr; { - str_data = tb_global_create(m, "csb$1", nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m, tb_module_get_rdata(m), str_data, 8, 1, 1); - void *region = tb_global_add_region(m, str_data, 0, 8); + str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1); + void *region = tb_global_add_region(m->mod, str_data, 0, 8); memcpy(region, "Hellope\x00", 8); } - str = tb_global_create(m, "global$str", nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m, tb_module_get_rdata(m), str, 16, 8, 2); - tb_global_add_symbol_reloc(m, str, 0, cast(TB_Symbol *)str_data); - void *len = tb_global_add_region(m, str, 8, 8); + str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2); + tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data); + void *len = tb_global_add_region(m->mod, str, 8, 8); *cast(i64 *)len = 7; } { TB_PrototypeParam printf_ret = {TB_TYPE_I32}; TB_PrototypeParam printf_params = {TB_TYPE_PTR}; - TB_FunctionPrototype *printf_proto = tb_prototype_create(m, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); - TB_External *printf_proc = tb_extern_create(m, "printf", TB_EXTERNAL_SO_LOCAL); + TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); + TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL); TB_PrototypeParam main_ret = {TB_TYPE_I32}; - TB_FunctionPrototype *main_proto = tb_prototype_create(m, TB_STDCALL, 0, nullptr, 1, &main_ret, false); - TB_Function * p = tb_function_create(m, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); + TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false); + TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); tb_function_set_prototype(p, main_proto, arena); - auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); + auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0); - auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); - auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); - auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); + auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); + auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); + auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); TB_Node *params[4] = {}; @@ -64,17 +757,39 @@ bool tb_generate_code(Checker *c) { params[3] = tb_inst_cstring(p, "World"); TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); gb_unused(output); + TB_Node *printf_return_value = output.single; + + TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0); + TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1); + + TB_Node *prev_case = tb_inst_get_control(p); + + TB_Node *true_case = tb_inst_region(p); + TB_Node *false_case = tb_inst_region(p); + + TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true); + tb_inst_if(p, cond, true_case, false_case); - TB_Node *value = tb_inst_uint(p, TB_TYPE_I32, 0); - tb_inst_ret(p, 1, &value); + tb_inst_set_control(p, true_case); + tb_inst_ret(p, 1, &zero); - tb_module_compile_function(m, p, TB_ISEL_FAST); + tb_inst_set_control(p, false_case); + tb_inst_ret(p, 1, &one); - TB_ExportBuffer export_buffer = tb_module_object_export(m, TB_DEBUGFMT_NONE); + tb_inst_set_control(p, prev_case); + + + tb_module_compile_function(m->mod, p, TB_ISEL_FAST); + + tb_function_print(p, tb_default_print_callback, stdout); + + TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, TB_DEBUGFMT_NONE); defer (tb_export_buffer_free(export_buffer)); char const *path = "W:/Odin/tilde_main.obj"; GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); } - return false; -} \ No newline at end of file + return true; +} + +#undef ABI_PKG_NAME_SEPARATOR diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp new file mode 100644 index 000000000..56b3bcb74 --- /dev/null +++ b/src/tilde_backend.hpp @@ -0,0 +1,160 @@ +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(push) + #pragma warning(disable: 4200) + #pragma warning(disable: 4201) + #define restrict gb_restrict +#endif + +#include "tilde/tb.h" + +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(pop) +#endif + +#define CG_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" +#define CG_CLEANUP_RUNTIME_PROC_NAME "__$cleanup_runtime" +#define CG_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" +#define CG_TYPE_INFO_DATA_NAME "__$type_info_data" +#define CG_TYPE_INFO_TYPES_NAME "__$type_info_types_data" +#define CG_TYPE_INFO_NAMES_NAME "__$type_info_names_data" +#define CG_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" +#define CG_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" +#define CG_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" + +struct cgModule; + + +enum cgValueKind : u32 { + cgValue_Value, + cgValue_Addr, + cgValue_Symbol, +}; + +struct cgValue { + cgValueKind kind; + Type * type; + union { + TB_Symbol *symbol; + TB_Node * node; + }; +}; + +enum cgAddrKind { + cgAddr_Default, + cgAddr_Map, + cgAddr_Context, + cgAddr_SoaVariable, + + cgAddr_RelativePointer, + cgAddr_RelativeSlice, + + cgAddr_Swizzle, + cgAddr_SwizzleLarge, +}; + +struct cgAddr { + cgAddrKind kind; + cgValue addr; + union { + struct { + cgValue key; + Type *type; + Type *result; + } map; + struct { + Selection sel; + } ctx; + struct { + cgValue index; + Ast *index_expr; + } soa; + struct { + cgValue index; + Ast *node; + } index_set; + struct { + bool deref; + } relative; + struct { + Type *type; + u8 count; // 2, 3, or 4 components + u8 indices[4]; + } swizzle; + struct { + Type *type; + Slice indices; + } swizzle_large; + }; +}; + + +struct cgProcedure { + u32 flags; + u16 state_flags; + + cgProcedure *parent; + Array children; + + TB_Function *func; + TB_Symbol *symbol; + + Entity * entity; + cgModule *module; + String name; + Type * type; + Ast * type_expr; + Ast * body; + u64 tags; + ProcInlining inlining; + bool is_foreign; + bool is_export; + bool is_entry_point; + bool is_startup; + + cgValue value; + +}; + + +struct cgModule { + TB_Module * mod; + Checker * checker; + CheckerInfo *info; + + RwMutex values_mutex; + PtrMap values; + StringMap members; + + StringMap procedures; + PtrMap procedure_values; + Array procedures_to_generate; + + std::atomic nested_type_name_guid; +}; + +#ifndef ABI_PKG_NAME_SEPARATOR +#define ABI_PKG_NAME_SEPARATOR "." +#endif + +gb_global Entity *cg_global_type_info_data_entity = {}; +gb_global cgAddr cg_global_type_info_member_types = {}; +gb_global cgAddr cg_global_type_info_member_names = {}; +gb_global cgAddr cg_global_type_info_member_offsets = {}; +gb_global cgAddr cg_global_type_info_member_usings = {}; +gb_global cgAddr cg_global_type_info_member_tags = {}; + +gb_global isize cg_global_type_info_data_index = 0; +gb_global isize cg_global_type_info_member_types_index = 0; +gb_global isize cg_global_type_info_member_names_index = 0; +gb_global isize cg_global_type_info_member_offsets_index = 0; +gb_global isize cg_global_type_info_member_usings_index = 0; +gb_global isize cg_global_type_info_member_tags_index = 0; + +gb_internal cgValue cg_value(TB_Global * g, Type *type); +gb_internal cgValue cg_value(TB_External *e, Type *type); +gb_internal cgValue cg_value(TB_Function *f, Type *type); +gb_internal cgValue cg_value(TB_Symbol * s, Type *type); +gb_internal cgValue cg_value(TB_Node * node, Type *type); + +gb_internal cgAddr cg_addr(cgValue const &value); + -- cgit v1.2.3 From e0e55a649c11167b845aaf74c09d8215ceb5b6ab Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 20:50:15 +0100 Subject: Rename tilde_backend* files to tilde* --- src/main.cpp | 2 +- src/tilde.cpp | 839 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde.hpp | 307 ++++++++++++++++++ src/tilde_backend.cpp | 839 -------------------------------------------------- src/tilde_backend.hpp | 307 ------------------ 5 files changed, 1147 insertions(+), 1147 deletions(-) create mode 100644 src/tilde.cpp create mode 100644 src/tilde.hpp delete mode 100644 src/tilde_backend.cpp delete mode 100644 src/tilde_backend.hpp (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 398f31b68..a59f452d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,7 +72,7 @@ gb_global Timings global_timings = {0}; #include "docs.cpp" #if defined(GB_SYSTEM_WINDOWS) -#include "tilde_backend.cpp" +#include "tilde.cpp" #endif #include "llvm_backend.cpp" diff --git a/src/tilde.cpp b/src/tilde.cpp new file mode 100644 index 000000000..188f5e0d0 --- /dev/null +++ b/src/tilde.cpp @@ -0,0 +1,839 @@ +#include "tilde.hpp" + +// returns TB_TYPE_VOID if not trivially possible +gb_internal TB_DataType cg_data_type(Type *t) { + GB_ASSERT(t != nullptr); + t = core_type(t); + i64 sz = type_size_of(t); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + + case Basic_rune: + + case Basic_int: + case Basic_uint: + case Basic_uintptr: + case Basic_typeid: + return TB_TYPE_INTN(cast(u16)gb_min(8*sz, 64)); + + case Basic_f16: return TB_TYPE_F16; + case Basic_f32: return TB_TYPE_F32; + case Basic_f64: return TB_TYPE_F64; + + case Basic_rawptr: return TB_TYPE_PTR; + case Basic_cstring: return TB_TYPE_PTR; + + + // Endian Specific Types + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_i128le: + case Basic_u128le: + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_i128be: + case Basic_u128be: + return TB_TYPE_INTN(cast(u16)gb_min(8*sz, 64)); + + case Basic_f16le: return TB_TYPE_F16; + case Basic_f32le: return TB_TYPE_F32; + case Basic_f64le: return TB_TYPE_F64; + + case Basic_f16be: return TB_TYPE_F16; + case Basic_f32be: return TB_TYPE_F32; + case Basic_f64be: return TB_TYPE_F64; + } + + case Type_Pointer: + case Type_MultiPointer: + case Type_Proc: + return TB_TYPE_PTR; + + case Type_BitSet: + return cg_data_type(bit_set_to_int(t)); + + case Type_RelativePointer: + return cg_data_type(t->RelativePointer.base_integer); + } + + // unknown + return {}; +} + + +gb_internal cgValue cg_value(TB_Global *g, Type *type) { + return cg_value((TB_Symbol *)g, type); +} +gb_internal cgValue cg_value(TB_External *e, Type *type) { + return cg_value((TB_Symbol *)e, type); +} +gb_internal cgValue cg_value(TB_Function *f, Type *type) { + return cg_value((TB_Symbol *)f, type); +} +gb_internal cgValue cg_value(TB_Symbol *s, Type *type) { + cgValue v = {}; + v.kind = cgValue_Symbol; + v.type = type; + v.symbol = s; + return v; +} +gb_internal cgValue cg_value(TB_Node *node, Type *type) { + cgValue v = {}; + v.kind = cgValue_Value; + v.type = type; + v.node = node; + return v; +} +gb_internal cgValue cg_lvalue_addr(TB_Node *node, Type *type) { + GB_ASSERT(node->dt.type == TB_PTR); + cgValue v = {}; + v.kind = cgValue_Addr; + v.type = type; + v.node = node; + return v; +} + +gb_internal cgValue cg_value_multi(cgValueMulti *multi, Type *type) { + GB_ASSERT(type->kind == Type_Tuple); + GB_ASSERT(multi != nullptr); + GB_ASSERT(type->Tuple.variables.count > 1); + GB_ASSERT(multi->values.count == type->Tuple.variables.count); + cgValue v = {}; + v.kind = cgValue_Multi; + v.type = type; + v.multi = multi; + return v; +} + +gb_internal cgAddr cg_addr(cgValue const &value) { + GB_ASSERT(value.kind != cgValue_Multi); + cgAddr addr = {}; + addr.kind = cgAddr_Default; + addr.addr = value; + if (addr.addr.kind == cgValue_Addr) { + GB_ASSERT(addr.addr.node != nullptr); + addr.addr.kind = cgValue_Value; + addr.addr.type = alloc_type_pointer(addr.addr.type); + } + return addr; +} + + +gb_internal void cg_add_entity(cgModule *m, Entity *e, cgValue const &val) { + if (e) { + rw_mutex_lock(&m->values_mutex); + map_set(&m->values, e, val); + rw_mutex_unlock(&m->values_mutex); + } +} + +gb_internal void cg_add_member(cgModule *m, String const &name, cgValue const &val) { + if (name.len > 0) { + rw_mutex_lock(&m->values_mutex); + string_map_set(&m->members, name, val); + rw_mutex_unlock(&m->values_mutex); + } +} + +gb_internal void cg_add_procedure_value(cgModule *m, cgProcedure *p) { + rw_mutex_lock(&m->values_mutex); + if (p->entity != nullptr) { + map_set(&m->procedure_values, p->func, p->entity); + } + string_map_set(&m->procedures, p->name, p); + rw_mutex_unlock(&m->values_mutex); + +} + +gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { + auto *set = &info->minimum_dependency_type_info_set; + isize index = type_info_index(info, type, err_on_not_found); + if (index >= 0) { + auto *found = map_get(set, index); + if (found) { + GB_ASSERT(*found >= 0); + return *found + 1; + } + } + if (err_on_not_found) { + GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + } + return -1; +} + + +gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type) { + GB_ASSERT(!build_context.no_rtti); + + type = default_type(type); + + u64 id = cast(u64)cg_type_info_index(m->info, type); + GB_ASSERT(id >= 0); + + u64 kind = Typeid_Invalid; + u64 named = is_type_named(type) && type->kind != Type_Basic; + u64 special = 0; + u64 reserved = 0; + + Type *bt = base_type(type); + TypeKind tk = bt->kind; + switch (tk) { + case Type_Basic: { + u32 flags = bt->Basic.flags; + if (flags & BasicFlag_Boolean) kind = Typeid_Boolean; + if (flags & BasicFlag_Integer) kind = Typeid_Integer; + if (flags & BasicFlag_Unsigned) kind = Typeid_Integer; + if (flags & BasicFlag_Float) kind = Typeid_Float; + if (flags & BasicFlag_Complex) kind = Typeid_Complex; + if (flags & BasicFlag_Pointer) kind = Typeid_Pointer; + if (flags & BasicFlag_String) kind = Typeid_String; + if (flags & BasicFlag_Rune) kind = Typeid_Rune; + } break; + case Type_Pointer: kind = Typeid_Pointer; break; + case Type_MultiPointer: kind = Typeid_Multi_Pointer; break; + case Type_Array: kind = Typeid_Array; break; + case Type_Matrix: kind = Typeid_Matrix; break; + case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; + case Type_Slice: kind = Typeid_Slice; break; + case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; + case Type_Map: kind = Typeid_Map; break; + case Type_Struct: kind = Typeid_Struct; break; + case Type_Enum: kind = Typeid_Enum; break; + case Type_Union: kind = Typeid_Union; break; + case Type_Tuple: kind = Typeid_Tuple; break; + case Type_Proc: kind = Typeid_Procedure; break; + case Type_BitSet: kind = Typeid_Bit_Set; break; + case Type_SimdVector: kind = Typeid_Simd_Vector; break; + case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; + case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; + case Type_SoaPointer: kind = Typeid_SoaPointer; break; + } + + if (is_type_cstring(type)) { + special = 1; + } else if (is_type_integer(type) && !is_type_unsigned(type)) { + special = 1; + } + + u64 data = 0; + if (build_context.ptr_size == 4) { + GB_ASSERT(id <= (1u<<24u)); + data |= (id &~ (1u<<24)) << 0u; // index + data |= (kind &~ (1u<<5)) << 24u; // kind + data |= (named &~ (1u<<1)) << 29u; // named + data |= (special &~ (1u<<1)) << 30u; // special + data |= (reserved &~ (1u<<1)) << 31u; // reserved + } else { + GB_ASSERT(build_context.ptr_size == 8); + GB_ASSERT(id <= (1ull<<56u)); + data |= (id &~ (1ull<<56)) << 0ul; // index + data |= (kind &~ (1ull<<5)) << 56ull; // kind + data |= (named &~ (1ull<<1)) << 61ull; // named + data |= (special &~ (1ull<<1)) << 62ull; // special + data |= (reserved &~ (1ull<<1)) << 63ull; // reserved + } + return data; +} + +gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) { + u64 x = cg_typeid_as_u64(p->module, t); + return cg_value(tb_inst_uint(p->func, cg_data_type(t_typeid), x), t_typeid); +} + + +struct cgGlobalVariable { + cgValue var; + cgValue init; + DeclInfo *decl; + bool is_initialized; +}; + +// Returns already_has_entry_point +gb_internal bool cg_global_variables_create(cgModule *m) { + isize global_variable_max_count = 0; + bool already_has_entry_point = false; + + for (Entity *e : m->info->entities) { + String name = e->token.string; + + if (e->kind == Entity_Variable) { + global_variable_max_count++; + } else if (e->kind == Entity_Procedure) { + if ((e->scope->flags&ScopeFlag_Init) && name == "main") { + GB_ASSERT(e == m->info->entry_point); + } + 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" || + link_name == "DllMain" || + link_name == "WinMain" || + link_name == "wWinMain" || + link_name == "mainCRTStartup" || + link_name == "_start") { + already_has_entry_point = true; + } + } + } + } + } + auto global_variables = array_make(permanent_allocator(), 0, global_variable_max_count); + + auto *min_dep_set = &m->info->minimum_dependency_set; + + for (DeclInfo *d : m->info->variable_init_order) { + Entity *e = d->entity; + + if ((e->scope->flags & ScopeFlag_File) == 0) { + continue; + } + + if (!ptr_set_exists(min_dep_set, e)) { + continue; + } + + DeclInfo *decl = decl_info_of_entity(e); + if (decl == nullptr) { + continue; + } + GB_ASSERT(e->kind == Entity_Variable); + + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + + String name = cg_get_entity_name(m, e); + + TB_Linkage linkage = TB_LINKAGE_PRIVATE; + + if (is_foreign) { + linkage = TB_LINKAGE_PUBLIC; + // lb_add_foreign_library_path(m, e->Variable.foreign_library); + // lb_set_wasm_import_attributes(g.value, e, name); + } else if (is_export) { + linkage = TB_LINKAGE_PUBLIC; + } + // lb_set_linkage_from_entity_flags(m, g.value, e->flags); + + TB_DebugType *debug_type = cg_debug_type(m, e->type); + TB_Global *global = tb_global_create(m->mod, name.len, cast(char const *)name.text, debug_type, linkage); + cgValue g = cg_value(global, alloc_type_pointer(e->type)); + + TB_ModuleSection *section = tb_module_get_data(m->mod); + + if (e->Variable.thread_local_model != "") { + section = tb_module_get_tls(m->mod); + } + if (e->Variable.link_section.len > 0) { + // TODO(bill): custom module sections + // LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); + } + + size_t max_objects = 0; + tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); + + cgGlobalVariable var = {}; + var.var = g; + var.decl = decl; + + if (decl->init_expr != nullptr) { + // TypeAndValue tav = type_and_value_of_expr(decl->init_expr); + // if (!is_type_any(e->type) && !is_type_union(e->type)) { + // if (tav.mode != Addressing_Invalid) { + // if (tav.value.kind != ExactValue_Invalid) { + // ExactValue v = tav.value; + // lbValue init = lb_const_value(m, tav.type, v); + // LLVMSetInitializer(g.value, init.value); + // var.is_initialized = true; + // } + // } + // } + // if (!var.is_initialized && is_type_untyped_nil(tav.type)) { + // var.is_initialized = true; + // } + } + + array_add(&global_variables, var); + + cg_add_entity(m, e, g); + cg_add_member(m, name, g); + } + + + + if (build_context.no_rtti) { + return already_has_entry_point; + } + + CheckerInfo *info = m->info; + { // Add type info data + isize max_type_info_count = info->minimum_dependency_type_info_set.count+1; + // gb_printf_err("max_type_info_count: %td\n", max_type_info_count); + Type *t = alloc_type_array(t_type_info, max_type_info_count); + + TB_Global *g = tb_global_create(m->mod, -1, CG_TYPE_INFO_DATA_NAME, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, max_type_info_count); + + cgValue value = cg_value(g, alloc_type_pointer(t)); + cg_global_type_info_data_entity = alloc_entity_variable(nullptr, make_token_ident(CG_TYPE_INFO_DATA_NAME), t, EntityState_Resolved); + cg_add_entity(m, cg_global_type_info_data_entity, value); + } + + { // Type info member buffer + // NOTE(bill): Removes need for heap allocation by making it global memory + isize count = 0; + + for (Type *t : m->info->type_info_types) { + isize index = cg_type_info_index(m->info, t, false); + if (index < 0) { + continue; + } + + switch (t->kind) { + case Type_Union: + count += t->Union.variants.count; + break; + case Type_Struct: + count += t->Struct.fields.count; + break; + case Type_Tuple: + count += t->Tuple.variables.count; + break; + } + } + + if (count > 0) { + { + char const *name = CG_TYPE_INFO_TYPES_NAME; + Type *t = alloc_type_array(t_type_info_ptr, count); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_types = cg_addr(cg_value(g, alloc_type_pointer(t))); + + } + { + char const *name = CG_TYPE_INFO_NAMES_NAME; + Type *t = alloc_type_array(t_string, count); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_names = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + { + char const *name = CG_TYPE_INFO_OFFSETS_NAME; + Type *t = alloc_type_array(t_uintptr, count); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_offsets = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + + { + char const *name = CG_TYPE_INFO_USINGS_NAME; + Type *t = alloc_type_array(t_bool, count); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_usings = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + + { + char const *name = CG_TYPE_INFO_TAGS_NAME; + Type *t = alloc_type_array(t_string, count); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); + cg_global_type_info_member_tags = cg_addr(cg_value(g, alloc_type_pointer(t))); + } + } + } + + return already_has_entry_point; +} + +gb_internal cgModule *cg_module_create(Checker *c) { + cgModule *m = gb_alloc_item(permanent_allocator(), cgModule); + + m->checker = c; + m->info = &c->info; + + + TB_FeatureSet feature_set = {}; + bool is_jit = false; + m->mod = tb_module_create(TB_ARCH_X86_64, TB_SYSTEM_WINDOWS, &feature_set, is_jit); + tb_module_set_tls_index(m->mod, 10, "_tls_index"); + + map_init(&m->values); + array_init(&m->procedures_to_generate, heap_allocator()); + + map_init(&m->file_id_map); + + map_init(&m->debug_type_map); + map_init(&m->proc_debug_type_map); + map_init(&m->proc_proto_map); + + + for_array(id, global_files) { + if (AstFile *f = global_files[id]) { + char const *path = alloc_cstring(permanent_allocator(), f->fullpath); + map_set(&m->file_id_map, cast(uintptr)id, tb_file_create(m->mod, path)); + } + } + + return m; +} + +gb_internal void cg_module_destroy(cgModule *m) { + map_destroy(&m->values); + array_free(&m->procedures_to_generate); + map_destroy(&m->file_id_map); + map_destroy(&m->debug_type_map); + map_destroy(&m->proc_debug_type_map); + map_destroy(&m->proc_proto_map); + + tb_module_destroy(m->mod); +} + +gb_internal String cg_set_nested_type_name_ir_mangled_name(Entity *e, cgProcedure *p) { + // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration + // and as a result, the declaration does not have time to determine what it should be + + GB_ASSERT(e != nullptr && e->kind == Entity_TypeName); + if (e->TypeName.ir_mangled_name.len != 0) { + return e->TypeName.ir_mangled_name; + } + GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0); + + if (p == nullptr) { + Entity *proc = nullptr; + if (e->parent_proc_decl != nullptr) { + proc = e->parent_proc_decl->entity; + } else { + Scope *scope = e->scope; + while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) { + scope = scope->parent; + } + GB_ASSERT(scope != nullptr); + GB_ASSERT(scope->flags & ScopeFlag_Proc); + proc = scope->procedure_entity; + } + GB_ASSERT(proc->kind == Entity_Procedure); + if (proc->cg_procedure != nullptr) { + p = proc->cg_procedure; + } + } + + // NOTE(bill): Generate a new name + // parent_proc.name-guid + String ts_name = e->token.string; + + if (p != nullptr) { + isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); + u32 guid = 1+p->module->nested_type_name_guid.fetch_add(1); + name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(p->name), LIT(ts_name), guid); + + String name = make_string(cast(u8 *)name_text, name_len-1); + e->TypeName.ir_mangled_name = name; + return name; + } else { + // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now + isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); + static std::atomic guid; + name_len = gb_snprintf(name_text, name_len, "_internal" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(ts_name), 1+guid.fetch_add(1)); + + String name = make_string(cast(u8 *)name_text, name_len-1); + e->TypeName.ir_mangled_name = name; + return name; + } +} + +gb_internal String cg_mangle_name(cgModule *m, Entity *e) { + String name = e->token.string; + + AstPackage *pkg = e->pkg; + GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name)); + String pkgn = pkg->name; + GB_ASSERT(!rune_is_digit(pkgn[0])); + if (pkgn == "llvm") { + GB_PANIC("llvm. entities are not allowed with the tilde backend"); + } + + isize max_len = pkgn.len + 1 + name.len + 1; + bool require_suffix_id = is_type_polymorphic(e->type, true); + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { + require_suffix_id = true; + } else if (is_blank_ident(e->token)) { + require_suffix_id = true; + }if (e->flags & EntityFlag_NotExported) { + require_suffix_id = true; + } + + if (require_suffix_id) { + max_len += 21; + } + + char *new_name = gb_alloc_array(permanent_allocator(), char, max_len); + isize new_name_len = gb_snprintf( + new_name, max_len, + "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s", LIT(pkgn), LIT(name) + ); + if (require_suffix_id) { + char *str = new_name + new_name_len-1; + isize len = max_len-new_name_len; + isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); + new_name_len += extra-1; + } + + String mangled_name = make_string((u8 const *)new_name, new_name_len-1); + return mangled_name; +} + +gb_internal String cg_get_entity_name(cgModule *m, Entity *e) { + if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { + return e->TypeName.ir_mangled_name; + } + GB_ASSERT(e != nullptr); + + if (e->pkg == nullptr) { + return e->token.string; + } + + if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { + return cg_set_nested_type_name_ir_mangled_name(e, nullptr); + } + + String name = {}; + + bool no_name_mangle = false; + + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; + if (e->Variable.link_name.len > 0) { + return e->Variable.link_name; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + return e->Procedure.link_name; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + no_name_mangle = true; + } + + if (!no_name_mangle) { + name = cg_mangle_name(m, e); + } + if (name.len == 0) { + name = e->token.string; + } + + if (e->kind == Entity_TypeName) { + e->TypeName.ir_mangled_name = name; + } else if (e->kind == Entity_Procedure) { + e->Procedure.link_name = name; + } + + return name; +} + +#include "tilde_const.cpp" +#include "tilde_debug.cpp" +#include "tilde_expr.cpp" +#include "tilde_proc.cpp" +#include "tilde_stmt.cpp" + + +gb_internal bool cg_generate_code(Checker *c) { + TIME_SECTION("Tilde Module Initializtion"); + + CheckerInfo *info = &c->info; + gb_unused(info); + + cgModule *m = cg_module_create(c); + defer (cg_module_destroy(m)); + + TIME_SECTION("Tilde Global Variables"); + + bool already_has_entry_point = cg_global_variables_create(m); + gb_unused(already_has_entry_point); + + if (true) { + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + cgProcedure *p = cg_procedure_create_dummy(m, str_lit(CG_STARTUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + + cg_procedure_begin(p); + cg_procedure_end(p); + } + + if (true) { + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + cgProcedure *p = cg_procedure_create_dummy(m, str_lit(CG_CLEANUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + + cg_procedure_begin(p); + cg_procedure_end(p); + } + + auto *min_dep_set = &info->minimum_dependency_set; + + for (Entity *e : info->entities) { + String name = e->token.string; + Scope * scope = e->scope; + + if ((scope->flags & ScopeFlag_File) == 0) { + continue; + } + + Scope *package_scope = scope->parent; + GB_ASSERT(package_scope->flags & ScopeFlag_Pkg); + + if (e->kind != Entity_Procedure) { + continue; + } + + if (!ptr_set_exists(min_dep_set, e)) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + continue; + } + if (cgProcedure *p = cg_procedure_create(m, e)) { + array_add(&m->procedures_to_generate, p); + } + } + + + for (isize i = 0; i < m->procedures_to_generate.count; i++) { + cg_procedure_generate(m->procedures_to_generate[i]); + } + + TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; + if (build_context.ODIN_DEBUG) { + switch (build_context.metrics.os) { + case TargetOs_windows: + debug_format = TB_DEBUGFMT_CODEVIEW; + break; + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_essence: + case TargetOs_freebsd: + case TargetOs_openbsd: + debug_format = TB_DEBUGFMT_DWARF; + break; + } + } + TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); + defer (tb_export_buffer_free(export_buffer)); + + char const *path = "W:/Odin/tilde_main.obj"; + GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); + + + //////////////////////////////////////////////////////////////////////////////////// + + + // TB_Arena *arena = tb_default_arena(); + + // TB_Global *str = nullptr; + // { + // TB_Global *str_data = nullptr; + // { + // str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE); + // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1); + // void *region = tb_global_add_region(m->mod, str_data, 0, 8); + // memcpy(region, "Hellope\x00", 8); + // } + + // str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE); + // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2); + // tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data); + // void *len = tb_global_add_region(m->mod, str, 8, 8); + // *cast(i64 *)len = 7; + // } + + // { + // TB_PrototypeParam printf_ret = {TB_TYPE_I32}; + // TB_PrototypeParam printf_params = {TB_TYPE_PTR}; + // TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); + // TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL); + + // TB_PrototypeParam main_ret = {TB_TYPE_I32}; + // TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false); + // TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); + // tb_function_set_prototype(p, main_proto, arena); + + + // auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); + // auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0); + // auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); + // auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); + // auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); + + + // TB_Node *params[4] = {}; + // params[0] = tb_inst_cstring(p, "%.*s %s!\n"); + // params[1] = tb_inst_trunc(p, str_len, TB_TYPE_I32); + // params[2] = str_data_ptr; + // params[3] = tb_inst_cstring(p, "World"); + // TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); + // gb_unused(output); + // TB_Node *printf_return_value = output.single; + + // TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0); + // TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1); + + // TB_Node *prev_case = tb_inst_get_control(p); + + // TB_Node *true_case = tb_inst_region(p); + // TB_Node *false_case = tb_inst_region(p); + + // TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true); + // tb_inst_if(p, cond, true_case, false_case); + + // tb_inst_set_control(p, true_case); + // tb_inst_ret(p, 1, &zero); + + // tb_inst_set_control(p, false_case); + // tb_inst_ret(p, 1, &one); + + // tb_inst_set_control(p, prev_case); + + + // tb_module_compile_function(m->mod, p, TB_ISEL_FAST); + + // tb_function_print(p, tb_default_print_callback, stdout); + + + // TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; + // TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); + // defer (tb_export_buffer_free(export_buffer)); + + // char const *path = "W:/Odin/tilde_main.obj"; + // GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); + // } + return true; +} + +#undef ABI_PKG_NAME_SEPARATOR diff --git a/src/tilde.hpp b/src/tilde.hpp new file mode 100644 index 000000000..99a97a664 --- /dev/null +++ b/src/tilde.hpp @@ -0,0 +1,307 @@ +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(push) + #pragma warning(disable: 4200) + #pragma warning(disable: 4201) + #define restrict gb_restrict +#endif + +#include "tilde/tb.h" + +#define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } } +#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } +#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)(8*build_context.int_size)) +#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size)) + +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(pop) +#endif + +#define CG_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" +#define CG_CLEANUP_RUNTIME_PROC_NAME "__$cleanup_runtime" +#define CG_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" +#define CG_TYPE_INFO_DATA_NAME "__$type_info_data" +#define CG_TYPE_INFO_TYPES_NAME "__$type_info_types_data" +#define CG_TYPE_INFO_NAMES_NAME "__$type_info_names_data" +#define CG_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" +#define CG_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" +#define CG_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" + +struct cgModule; + + +enum cgValueKind : u32 { + cgValue_Value, // rvalue + cgValue_Addr, // lvalue + cgValue_Symbol, // global + cgValue_Multi, // multiple values +}; + +struct cgValueMulti; + +struct cgValue { + cgValueKind kind; + Type * type; + union { + TB_Symbol *symbol; + TB_Node * node; + cgValueMulti *multi; + }; +}; + +struct cgValueMulti { + Slice values; +}; + + +enum cgAddrKind { + cgAddr_Default, + cgAddr_Map, + cgAddr_Context, + cgAddr_SoaVariable, + + cgAddr_RelativePointer, + cgAddr_RelativeSlice, + + cgAddr_Swizzle, + cgAddr_SwizzleLarge, +}; + +struct cgAddr { + cgAddrKind kind; + cgValue addr; + union { + struct { + cgValue key; + Type *type; + Type *result; + } map; + struct { + Selection sel; + } ctx; + struct { + cgValue index; + Ast *index_expr; + } soa; + struct { + cgValue index; + Ast *node; + } index_set; + struct { + bool deref; + } relative; + struct { + Type *type; + u8 count; // 2, 3, or 4 components + u8 indices[4]; + } swizzle; + struct { + Type *type; + Slice indices; + } swizzle_large; + }; +}; + + +struct cgTargetList { + cgTargetList *prev; + bool is_block; + // control regions + TB_Node * break_; + TB_Node * continue_; + TB_Node * fallthrough_; +}; + +struct cgBranchRegions { + Ast * label; + TB_Node *break_; + TB_Node *continue_; +}; + +enum cgDeferExitKind { + cgDeferExit_Default, + cgDeferExit_Return, + cgDeferExit_Branch, +}; + +enum cgDeferKind { + cgDefer_Node, + cgDefer_Proc, +}; + +struct cgDefer { + cgDeferKind kind; + isize scope_index; + isize context_stack_count; + TB_Node * control_region; + union { + Ast *stmt; + struct { + cgValue deferred; + Slice result_as_args; + } proc; + }; +}; + + +struct cgContextData { + cgAddr ctx; + isize scope_index; + isize uses; +}; + +struct cgControlRegion { + TB_Node *control_region; + isize scope_index; +}; + +struct cgProcedure { + u32 flags; + u16 state_flags; + + cgProcedure *parent; + Array children; + + TB_Function *func; + TB_FunctionPrototype *proto; + TB_Symbol *symbol; + + // includes parameters, pointers to return values, and context ptr + Slice param_nodes; + + Entity * entity; + cgModule *module; + String name; + Type * type; + Ast * type_expr; + Ast * body; + u64 tags; + ProcInlining inlining; + bool is_foreign; + bool is_export; + bool is_entry_point; + bool is_startup; + + TB_DebugType *debug_type; + + cgValue value; + + Ast *curr_stmt; + + cgTargetList * target_list; + Array defer_stack; + Array scope_stack; + Array context_stack; + + Array control_regions; + Array branch_regions; + + Scope *curr_scope; + i32 scope_index; + bool in_multi_assignment; + + + PtrMap variable_map; +}; + + +struct cgModule { + TB_Module * mod; + Checker * checker; + CheckerInfo *info; + + RwMutex values_mutex; + PtrMap values; + StringMap members; + + StringMap procedures; + PtrMap procedure_values; + Array procedures_to_generate; + + RecursiveMutex debug_type_mutex; + PtrMap debug_type_map; + PtrMap proc_debug_type_map; // not pointer to + + RecursiveMutex proc_proto_mutex; + PtrMap proc_proto_map; + + PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) + + std::atomic nested_type_name_guid; + std::atomic const_nil_guid; +}; + +#ifndef ABI_PKG_NAME_SEPARATOR +#define ABI_PKG_NAME_SEPARATOR "@" +#endif + +gb_global Entity *cg_global_type_info_data_entity = {}; +gb_global cgAddr cg_global_type_info_member_types = {}; +gb_global cgAddr cg_global_type_info_member_names = {}; +gb_global cgAddr cg_global_type_info_member_offsets = {}; +gb_global cgAddr cg_global_type_info_member_usings = {}; +gb_global cgAddr cg_global_type_info_member_tags = {}; + +gb_global isize cg_global_type_info_data_index = 0; +gb_global isize cg_global_type_info_member_types_index = 0; +gb_global isize cg_global_type_info_member_names_index = 0; +gb_global isize cg_global_type_info_member_offsets_index = 0; +gb_global isize cg_global_type_info_member_usings_index = 0; +gb_global isize cg_global_type_info_member_tags_index = 0; + +gb_internal cgValue cg_value(TB_Global * g, Type *type); +gb_internal cgValue cg_value(TB_External *e, Type *type); +gb_internal cgValue cg_value(TB_Function *f, Type *type); +gb_internal cgValue cg_value(TB_Symbol * s, Type *type); +gb_internal cgValue cg_value(TB_Node * node, Type *type); + +gb_internal cgAddr cg_addr(cgValue const &value); + + +gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value); +gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type); + +gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value); + +gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); +gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts); +gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); + +gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr); +gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr); + +gb_internal Type * cg_addr_type(cgAddr const &addr); +gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr); +gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value); +gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr); + +gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); + +gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); +gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); + +gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); + +gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); + +gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); + +gb_internal String cg_get_entity_name(cgModule *m, Entity *e); + +gb_internal cgValue cg_typeid(cgProcedure *m, Type *t); + +gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue index); +gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index); +gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index); +gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index); +gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel); + +gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t); +gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x); +gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right); +gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); + +gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); + + +gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); \ No newline at end of file diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp deleted file mode 100644 index e76912895..000000000 --- a/src/tilde_backend.cpp +++ /dev/null @@ -1,839 +0,0 @@ -#include "tilde_backend.hpp" - -// returns TB_TYPE_VOID if not trivially possible -gb_internal TB_DataType cg_data_type(Type *t) { - GB_ASSERT(t != nullptr); - t = core_type(t); - i64 sz = type_size_of(t); - switch (t->kind) { - case Type_Basic: - switch (t->Basic.kind) { - case Basic_bool: - case Basic_b8: - case Basic_b16: - case Basic_b32: - case Basic_b64: - - case Basic_i8: - case Basic_u8: - case Basic_i16: - case Basic_u16: - case Basic_i32: - case Basic_u32: - case Basic_i64: - case Basic_u64: - case Basic_i128: - case Basic_u128: - - case Basic_rune: - - case Basic_int: - case Basic_uint: - case Basic_uintptr: - case Basic_typeid: - return TB_TYPE_INTN(cast(u16)gb_min(8*sz, 64)); - - case Basic_f16: return TB_TYPE_F16; - case Basic_f32: return TB_TYPE_F32; - case Basic_f64: return TB_TYPE_F64; - - case Basic_rawptr: return TB_TYPE_PTR; - case Basic_cstring: return TB_TYPE_PTR; - - - // Endian Specific Types - case Basic_i16le: - case Basic_u16le: - case Basic_i32le: - case Basic_u32le: - case Basic_i64le: - case Basic_u64le: - case Basic_i128le: - case Basic_u128le: - case Basic_i16be: - case Basic_u16be: - case Basic_i32be: - case Basic_u32be: - case Basic_i64be: - case Basic_u64be: - case Basic_i128be: - case Basic_u128be: - return TB_TYPE_INTN(cast(u16)gb_min(8*sz, 64)); - - case Basic_f16le: return TB_TYPE_F16; - case Basic_f32le: return TB_TYPE_F32; - case Basic_f64le: return TB_TYPE_F64; - - case Basic_f16be: return TB_TYPE_F16; - case Basic_f32be: return TB_TYPE_F32; - case Basic_f64be: return TB_TYPE_F64; - } - - case Type_Pointer: - case Type_MultiPointer: - case Type_Proc: - return TB_TYPE_PTR; - - case Type_BitSet: - return cg_data_type(bit_set_to_int(t)); - - case Type_RelativePointer: - return cg_data_type(t->RelativePointer.base_integer); - } - - // unknown - return {}; -} - - -gb_internal cgValue cg_value(TB_Global *g, Type *type) { - return cg_value((TB_Symbol *)g, type); -} -gb_internal cgValue cg_value(TB_External *e, Type *type) { - return cg_value((TB_Symbol *)e, type); -} -gb_internal cgValue cg_value(TB_Function *f, Type *type) { - return cg_value((TB_Symbol *)f, type); -} -gb_internal cgValue cg_value(TB_Symbol *s, Type *type) { - cgValue v = {}; - v.kind = cgValue_Symbol; - v.type = type; - v.symbol = s; - return v; -} -gb_internal cgValue cg_value(TB_Node *node, Type *type) { - cgValue v = {}; - v.kind = cgValue_Value; - v.type = type; - v.node = node; - return v; -} -gb_internal cgValue cg_lvalue_addr(TB_Node *node, Type *type) { - GB_ASSERT(node->dt.type == TB_PTR); - cgValue v = {}; - v.kind = cgValue_Addr; - v.type = type; - v.node = node; - return v; -} - -gb_internal cgValue cg_value_multi(cgValueMulti *multi, Type *type) { - GB_ASSERT(type->kind == Type_Tuple); - GB_ASSERT(multi != nullptr); - GB_ASSERT(type->Tuple.variables.count > 1); - GB_ASSERT(multi->values.count == type->Tuple.variables.count); - cgValue v = {}; - v.kind = cgValue_Multi; - v.type = type; - v.multi = multi; - return v; -} - -gb_internal cgAddr cg_addr(cgValue const &value) { - GB_ASSERT(value.kind != cgValue_Multi); - cgAddr addr = {}; - addr.kind = cgAddr_Default; - addr.addr = value; - if (addr.addr.kind == cgValue_Addr) { - GB_ASSERT(addr.addr.node != nullptr); - addr.addr.kind = cgValue_Value; - addr.addr.type = alloc_type_pointer(addr.addr.type); - } - return addr; -} - - -gb_internal void cg_add_entity(cgModule *m, Entity *e, cgValue const &val) { - if (e) { - rw_mutex_lock(&m->values_mutex); - map_set(&m->values, e, val); - rw_mutex_unlock(&m->values_mutex); - } -} - -gb_internal void cg_add_member(cgModule *m, String const &name, cgValue const &val) { - if (name.len > 0) { - rw_mutex_lock(&m->values_mutex); - string_map_set(&m->members, name, val); - rw_mutex_unlock(&m->values_mutex); - } -} - -gb_internal void cg_add_procedure_value(cgModule *m, cgProcedure *p) { - rw_mutex_lock(&m->values_mutex); - if (p->entity != nullptr) { - map_set(&m->procedure_values, p->func, p->entity); - } - string_map_set(&m->procedures, p->name, p); - rw_mutex_unlock(&m->values_mutex); - -} - -gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { - auto *set = &info->minimum_dependency_type_info_set; - isize index = type_info_index(info, type, err_on_not_found); - if (index >= 0) { - auto *found = map_get(set, index); - if (found) { - GB_ASSERT(*found >= 0); - return *found + 1; - } - } - if (err_on_not_found) { - GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); - } - return -1; -} - - -gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type) { - GB_ASSERT(!build_context.no_rtti); - - type = default_type(type); - - u64 id = cast(u64)cg_type_info_index(m->info, type); - GB_ASSERT(id >= 0); - - u64 kind = Typeid_Invalid; - u64 named = is_type_named(type) && type->kind != Type_Basic; - u64 special = 0; - u64 reserved = 0; - - Type *bt = base_type(type); - TypeKind tk = bt->kind; - switch (tk) { - case Type_Basic: { - u32 flags = bt->Basic.flags; - if (flags & BasicFlag_Boolean) kind = Typeid_Boolean; - if (flags & BasicFlag_Integer) kind = Typeid_Integer; - if (flags & BasicFlag_Unsigned) kind = Typeid_Integer; - if (flags & BasicFlag_Float) kind = Typeid_Float; - if (flags & BasicFlag_Complex) kind = Typeid_Complex; - if (flags & BasicFlag_Pointer) kind = Typeid_Pointer; - if (flags & BasicFlag_String) kind = Typeid_String; - if (flags & BasicFlag_Rune) kind = Typeid_Rune; - } break; - case Type_Pointer: kind = Typeid_Pointer; break; - case Type_MultiPointer: kind = Typeid_Multi_Pointer; break; - case Type_Array: kind = Typeid_Array; break; - case Type_Matrix: kind = Typeid_Matrix; break; - case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; - case Type_Slice: kind = Typeid_Slice; break; - case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; - case Type_Map: kind = Typeid_Map; break; - case Type_Struct: kind = Typeid_Struct; break; - case Type_Enum: kind = Typeid_Enum; break; - case Type_Union: kind = Typeid_Union; break; - case Type_Tuple: kind = Typeid_Tuple; break; - case Type_Proc: kind = Typeid_Procedure; break; - case Type_BitSet: kind = Typeid_Bit_Set; break; - case Type_SimdVector: kind = Typeid_Simd_Vector; break; - case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; - case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; - case Type_SoaPointer: kind = Typeid_SoaPointer; break; - } - - if (is_type_cstring(type)) { - special = 1; - } else if (is_type_integer(type) && !is_type_unsigned(type)) { - special = 1; - } - - u64 data = 0; - if (build_context.ptr_size == 4) { - GB_ASSERT(id <= (1u<<24u)); - data |= (id &~ (1u<<24)) << 0u; // index - data |= (kind &~ (1u<<5)) << 24u; // kind - data |= (named &~ (1u<<1)) << 29u; // named - data |= (special &~ (1u<<1)) << 30u; // special - data |= (reserved &~ (1u<<1)) << 31u; // reserved - } else { - GB_ASSERT(build_context.ptr_size == 8); - GB_ASSERT(id <= (1ull<<56u)); - data |= (id &~ (1ull<<56)) << 0ul; // index - data |= (kind &~ (1ull<<5)) << 56ull; // kind - data |= (named &~ (1ull<<1)) << 61ull; // named - data |= (special &~ (1ull<<1)) << 62ull; // special - data |= (reserved &~ (1ull<<1)) << 63ull; // reserved - } - return data; -} - -gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) { - u64 x = cg_typeid_as_u64(p->module, t); - return cg_value(tb_inst_uint(p->func, cg_data_type(t_typeid), x), t_typeid); -} - - -struct cgGlobalVariable { - cgValue var; - cgValue init; - DeclInfo *decl; - bool is_initialized; -}; - -// Returns already_has_entry_point -gb_internal bool cg_global_variables_create(cgModule *m) { - isize global_variable_max_count = 0; - bool already_has_entry_point = false; - - for (Entity *e : m->info->entities) { - String name = e->token.string; - - if (e->kind == Entity_Variable) { - global_variable_max_count++; - } else if (e->kind == Entity_Procedure) { - if ((e->scope->flags&ScopeFlag_Init) && name == "main") { - GB_ASSERT(e == m->info->entry_point); - } - 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" || - link_name == "DllMain" || - link_name == "WinMain" || - link_name == "wWinMain" || - link_name == "mainCRTStartup" || - link_name == "_start") { - already_has_entry_point = true; - } - } - } - } - } - auto global_variables = array_make(permanent_allocator(), 0, global_variable_max_count); - - auto *min_dep_set = &m->info->minimum_dependency_set; - - for (DeclInfo *d : m->info->variable_init_order) { - Entity *e = d->entity; - - if ((e->scope->flags & ScopeFlag_File) == 0) { - continue; - } - - if (!ptr_set_exists(min_dep_set, e)) { - continue; - } - - DeclInfo *decl = decl_info_of_entity(e); - if (decl == nullptr) { - continue; - } - GB_ASSERT(e->kind == Entity_Variable); - - bool is_foreign = e->Variable.is_foreign; - bool is_export = e->Variable.is_export; - - String name = cg_get_entity_name(m, e); - - TB_Linkage linkage = TB_LINKAGE_PRIVATE; - - if (is_foreign) { - linkage = TB_LINKAGE_PUBLIC; - // lb_add_foreign_library_path(m, e->Variable.foreign_library); - // lb_set_wasm_import_attributes(g.value, e, name); - } else if (is_export) { - linkage = TB_LINKAGE_PUBLIC; - } - // lb_set_linkage_from_entity_flags(m, g.value, e->flags); - - TB_DebugType *debug_type = cg_debug_type(m, e->type); - TB_Global *global = tb_global_create(m->mod, name.len, cast(char const *)name.text, debug_type, linkage); - cgValue g = cg_value(global, alloc_type_pointer(e->type)); - - TB_ModuleSection *section = tb_module_get_data(m->mod); - - if (e->Variable.thread_local_model != "") { - section = tb_module_get_tls(m->mod); - } - if (e->Variable.link_section.len > 0) { - // TODO(bill): custom module sections - // LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); - } - - size_t max_objects = 0; - tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); - - cgGlobalVariable var = {}; - var.var = g; - var.decl = decl; - - if (decl->init_expr != nullptr) { - // TypeAndValue tav = type_and_value_of_expr(decl->init_expr); - // if (!is_type_any(e->type) && !is_type_union(e->type)) { - // if (tav.mode != Addressing_Invalid) { - // if (tav.value.kind != ExactValue_Invalid) { - // ExactValue v = tav.value; - // lbValue init = lb_const_value(m, tav.type, v); - // LLVMSetInitializer(g.value, init.value); - // var.is_initialized = true; - // } - // } - // } - // if (!var.is_initialized && is_type_untyped_nil(tav.type)) { - // var.is_initialized = true; - // } - } - - array_add(&global_variables, var); - - cg_add_entity(m, e, g); - cg_add_member(m, name, g); - } - - - - if (build_context.no_rtti) { - return already_has_entry_point; - } - - CheckerInfo *info = m->info; - { // Add type info data - isize max_type_info_count = info->minimum_dependency_type_info_set.count+1; - // gb_printf_err("max_type_info_count: %td\n", max_type_info_count); - Type *t = alloc_type_array(t_type_info, max_type_info_count); - - TB_Global *g = tb_global_create(m->mod, -1, CG_TYPE_INFO_DATA_NAME, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, max_type_info_count); - - cgValue value = cg_value(g, alloc_type_pointer(t)); - cg_global_type_info_data_entity = alloc_entity_variable(nullptr, make_token_ident(CG_TYPE_INFO_DATA_NAME), t, EntityState_Resolved); - cg_add_entity(m, cg_global_type_info_data_entity, value); - } - - { // Type info member buffer - // NOTE(bill): Removes need for heap allocation by making it global memory - isize count = 0; - - for (Type *t : m->info->type_info_types) { - isize index = cg_type_info_index(m->info, t, false); - if (index < 0) { - continue; - } - - switch (t->kind) { - case Type_Union: - count += t->Union.variants.count; - break; - case Type_Struct: - count += t->Struct.fields.count; - break; - case Type_Tuple: - count += t->Tuple.variables.count; - break; - } - } - - if (count > 0) { - { - char const *name = CG_TYPE_INFO_TYPES_NAME; - Type *t = alloc_type_array(t_type_info_ptr, count); - TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); - cg_global_type_info_member_types = cg_addr(cg_value(g, alloc_type_pointer(t))); - - } - { - char const *name = CG_TYPE_INFO_NAMES_NAME; - Type *t = alloc_type_array(t_string, count); - TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); - cg_global_type_info_member_names = cg_addr(cg_value(g, alloc_type_pointer(t))); - } - { - char const *name = CG_TYPE_INFO_OFFSETS_NAME; - Type *t = alloc_type_array(t_uintptr, count); - TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); - cg_global_type_info_member_offsets = cg_addr(cg_value(g, alloc_type_pointer(t))); - } - - { - char const *name = CG_TYPE_INFO_USINGS_NAME; - Type *t = alloc_type_array(t_bool, count); - TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); - cg_global_type_info_member_usings = cg_addr(cg_value(g, alloc_type_pointer(t))); - } - - { - char const *name = CG_TYPE_INFO_TAGS_NAME; - Type *t = alloc_type_array(t_string, count); - TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); - cg_global_type_info_member_tags = cg_addr(cg_value(g, alloc_type_pointer(t))); - } - } - } - - return already_has_entry_point; -} - -gb_internal cgModule *cg_module_create(Checker *c) { - cgModule *m = gb_alloc_item(permanent_allocator(), cgModule); - - m->checker = c; - m->info = &c->info; - - - TB_FeatureSet feature_set = {}; - bool is_jit = false; - m->mod = tb_module_create(TB_ARCH_X86_64, TB_SYSTEM_WINDOWS, &feature_set, is_jit); - tb_module_set_tls_index(m->mod, 10, "_tls_index"); - - map_init(&m->values); - array_init(&m->procedures_to_generate, heap_allocator()); - - map_init(&m->file_id_map); - - map_init(&m->debug_type_map); - map_init(&m->proc_debug_type_map); - map_init(&m->proc_proto_map); - - - for_array(id, global_files) { - if (AstFile *f = global_files[id]) { - char const *path = alloc_cstring(permanent_allocator(), f->fullpath); - map_set(&m->file_id_map, cast(uintptr)id, tb_file_create(m->mod, path)); - } - } - - return m; -} - -gb_internal void cg_module_destroy(cgModule *m) { - map_destroy(&m->values); - array_free(&m->procedures_to_generate); - map_destroy(&m->file_id_map); - map_destroy(&m->debug_type_map); - map_destroy(&m->proc_debug_type_map); - map_destroy(&m->proc_proto_map); - - tb_module_destroy(m->mod); -} - -gb_internal String cg_set_nested_type_name_ir_mangled_name(Entity *e, cgProcedure *p) { - // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration - // and as a result, the declaration does not have time to determine what it should be - - GB_ASSERT(e != nullptr && e->kind == Entity_TypeName); - if (e->TypeName.ir_mangled_name.len != 0) { - return e->TypeName.ir_mangled_name; - } - GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0); - - if (p == nullptr) { - Entity *proc = nullptr; - if (e->parent_proc_decl != nullptr) { - proc = e->parent_proc_decl->entity; - } else { - Scope *scope = e->scope; - while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) { - scope = scope->parent; - } - GB_ASSERT(scope != nullptr); - GB_ASSERT(scope->flags & ScopeFlag_Proc); - proc = scope->procedure_entity; - } - GB_ASSERT(proc->kind == Entity_Procedure); - if (proc->cg_procedure != nullptr) { - p = proc->cg_procedure; - } - } - - // NOTE(bill): Generate a new name - // parent_proc.name-guid - String ts_name = e->token.string; - - if (p != nullptr) { - isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - u32 guid = 1+p->module->nested_type_name_guid.fetch_add(1); - name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(p->name), LIT(ts_name), guid); - - String name = make_string(cast(u8 *)name_text, name_len-1); - e->TypeName.ir_mangled_name = name; - return name; - } else { - // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now - isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - static std::atomic guid; - name_len = gb_snprintf(name_text, name_len, "_internal" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(ts_name), 1+guid.fetch_add(1)); - - String name = make_string(cast(u8 *)name_text, name_len-1); - e->TypeName.ir_mangled_name = name; - return name; - } -} - -gb_internal String cg_mangle_name(cgModule *m, Entity *e) { - String name = e->token.string; - - AstPackage *pkg = e->pkg; - GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name)); - String pkgn = pkg->name; - GB_ASSERT(!rune_is_digit(pkgn[0])); - if (pkgn == "llvm") { - GB_PANIC("llvm. entities are not allowed with the tilde backend"); - } - - isize max_len = pkgn.len + 1 + name.len + 1; - bool require_suffix_id = is_type_polymorphic(e->type, true); - - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { - require_suffix_id = true; - } else if (is_blank_ident(e->token)) { - require_suffix_id = true; - }if (e->flags & EntityFlag_NotExported) { - require_suffix_id = true; - } - - if (require_suffix_id) { - max_len += 21; - } - - char *new_name = gb_alloc_array(permanent_allocator(), char, max_len); - isize new_name_len = gb_snprintf( - new_name, max_len, - "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s", LIT(pkgn), LIT(name) - ); - if (require_suffix_id) { - char *str = new_name + new_name_len-1; - isize len = max_len-new_name_len; - isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); - new_name_len += extra-1; - } - - String mangled_name = make_string((u8 const *)new_name, new_name_len-1); - return mangled_name; -} - -gb_internal String cg_get_entity_name(cgModule *m, Entity *e) { - if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { - return e->TypeName.ir_mangled_name; - } - GB_ASSERT(e != nullptr); - - if (e->pkg == nullptr) { - return e->token.string; - } - - if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { - return cg_set_nested_type_name_ir_mangled_name(e, nullptr); - } - - String name = {}; - - bool no_name_mangle = false; - - if (e->kind == Entity_Variable) { - bool is_foreign = e->Variable.is_foreign; - bool is_export = e->Variable.is_export; - no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; - if (e->Variable.link_name.len > 0) { - return e->Variable.link_name; - } - } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { - return e->Procedure.link_name; - } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { - no_name_mangle = true; - } - - if (!no_name_mangle) { - name = cg_mangle_name(m, e); - } - if (name.len == 0) { - name = e->token.string; - } - - if (e->kind == Entity_TypeName) { - e->TypeName.ir_mangled_name = name; - } else if (e->kind == Entity_Procedure) { - e->Procedure.link_name = name; - } - - return name; -} - -#include "tilde_const.cpp" -#include "tilde_debug.cpp" -#include "tilde_expr.cpp" -#include "tilde_proc.cpp" -#include "tilde_stmt.cpp" - - -gb_internal bool cg_generate_code(Checker *c) { - TIME_SECTION("Tilde Module Initializtion"); - - CheckerInfo *info = &c->info; - gb_unused(info); - - cgModule *m = cg_module_create(c); - defer (cg_module_destroy(m)); - - TIME_SECTION("Tilde Global Variables"); - - bool already_has_entry_point = cg_global_variables_create(m); - gb_unused(already_has_entry_point); - - if (true) { - Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); - cgProcedure *p = cg_procedure_create_dummy(m, str_lit(CG_STARTUP_RUNTIME_PROC_NAME), proc_type); - p->is_startup = true; - - cg_procedure_begin(p); - cg_procedure_end(p); - } - - if (true) { - Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); - cgProcedure *p = cg_procedure_create_dummy(m, str_lit(CG_CLEANUP_RUNTIME_PROC_NAME), proc_type); - p->is_startup = true; - - cg_procedure_begin(p); - cg_procedure_end(p); - } - - auto *min_dep_set = &info->minimum_dependency_set; - - for (Entity *e : info->entities) { - String name = e->token.string; - Scope * scope = e->scope; - - if ((scope->flags & ScopeFlag_File) == 0) { - continue; - } - - Scope *package_scope = scope->parent; - GB_ASSERT(package_scope->flags & ScopeFlag_Pkg); - - if (e->kind != Entity_Procedure) { - continue; - } - - if (!ptr_set_exists(min_dep_set, e)) { - // NOTE(bill): Nothing depends upon it so doesn't need to be built - continue; - } - if (cgProcedure *p = cg_procedure_create(m, e)) { - array_add(&m->procedures_to_generate, p); - } - } - - - for (isize i = 0; i < m->procedures_to_generate.count; i++) { - cg_procedure_generate(m->procedures_to_generate[i]); - } - - TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; - if (build_context.ODIN_DEBUG) { - switch (build_context.metrics.os) { - case TargetOs_windows: - debug_format = TB_DEBUGFMT_CODEVIEW; - break; - case TargetOs_darwin: - case TargetOs_linux: - case TargetOs_essence: - case TargetOs_freebsd: - case TargetOs_openbsd: - debug_format = TB_DEBUGFMT_DWARF; - break; - } - } - TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); - defer (tb_export_buffer_free(export_buffer)); - - char const *path = "W:/Odin/tilde_main.obj"; - GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); - - - //////////////////////////////////////////////////////////////////////////////////// - - - // TB_Arena *arena = tb_default_arena(); - - // TB_Global *str = nullptr; - // { - // TB_Global *str_data = nullptr; - // { - // str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE); - // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1); - // void *region = tb_global_add_region(m->mod, str_data, 0, 8); - // memcpy(region, "Hellope\x00", 8); - // } - - // str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE); - // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2); - // tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data); - // void *len = tb_global_add_region(m->mod, str, 8, 8); - // *cast(i64 *)len = 7; - // } - - // { - // TB_PrototypeParam printf_ret = {TB_TYPE_I32}; - // TB_PrototypeParam printf_params = {TB_TYPE_PTR}; - // TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); - // TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL); - - // TB_PrototypeParam main_ret = {TB_TYPE_I32}; - // TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false); - // TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); - // tb_function_set_prototype(p, main_proto, arena); - - - // auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); - // auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0); - // auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); - // auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); - // auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); - - - // TB_Node *params[4] = {}; - // params[0] = tb_inst_cstring(p, "%.*s %s!\n"); - // params[1] = tb_inst_trunc(p, str_len, TB_TYPE_I32); - // params[2] = str_data_ptr; - // params[3] = tb_inst_cstring(p, "World"); - // TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); - // gb_unused(output); - // TB_Node *printf_return_value = output.single; - - // TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0); - // TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1); - - // TB_Node *prev_case = tb_inst_get_control(p); - - // TB_Node *true_case = tb_inst_region(p); - // TB_Node *false_case = tb_inst_region(p); - - // TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true); - // tb_inst_if(p, cond, true_case, false_case); - - // tb_inst_set_control(p, true_case); - // tb_inst_ret(p, 1, &zero); - - // tb_inst_set_control(p, false_case); - // tb_inst_ret(p, 1, &one); - - // tb_inst_set_control(p, prev_case); - - - // tb_module_compile_function(m->mod, p, TB_ISEL_FAST); - - // tb_function_print(p, tb_default_print_callback, stdout); - - - // TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; - // TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); - // defer (tb_export_buffer_free(export_buffer)); - - // char const *path = "W:/Odin/tilde_main.obj"; - // GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); - // } - return true; -} - -#undef ABI_PKG_NAME_SEPARATOR diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp deleted file mode 100644 index 99a97a664..000000000 --- a/src/tilde_backend.hpp +++ /dev/null @@ -1,307 +0,0 @@ -#if defined(GB_SYSTEM_WINDOWS) - #pragma warning(push) - #pragma warning(disable: 4200) - #pragma warning(disable: 4201) - #define restrict gb_restrict -#endif - -#include "tilde/tb.h" - -#define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } } -#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } -#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)(8*build_context.int_size)) -#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size)) - -#if defined(GB_SYSTEM_WINDOWS) - #pragma warning(pop) -#endif - -#define CG_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" -#define CG_CLEANUP_RUNTIME_PROC_NAME "__$cleanup_runtime" -#define CG_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" -#define CG_TYPE_INFO_DATA_NAME "__$type_info_data" -#define CG_TYPE_INFO_TYPES_NAME "__$type_info_types_data" -#define CG_TYPE_INFO_NAMES_NAME "__$type_info_names_data" -#define CG_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" -#define CG_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" -#define CG_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" - -struct cgModule; - - -enum cgValueKind : u32 { - cgValue_Value, // rvalue - cgValue_Addr, // lvalue - cgValue_Symbol, // global - cgValue_Multi, // multiple values -}; - -struct cgValueMulti; - -struct cgValue { - cgValueKind kind; - Type * type; - union { - TB_Symbol *symbol; - TB_Node * node; - cgValueMulti *multi; - }; -}; - -struct cgValueMulti { - Slice values; -}; - - -enum cgAddrKind { - cgAddr_Default, - cgAddr_Map, - cgAddr_Context, - cgAddr_SoaVariable, - - cgAddr_RelativePointer, - cgAddr_RelativeSlice, - - cgAddr_Swizzle, - cgAddr_SwizzleLarge, -}; - -struct cgAddr { - cgAddrKind kind; - cgValue addr; - union { - struct { - cgValue key; - Type *type; - Type *result; - } map; - struct { - Selection sel; - } ctx; - struct { - cgValue index; - Ast *index_expr; - } soa; - struct { - cgValue index; - Ast *node; - } index_set; - struct { - bool deref; - } relative; - struct { - Type *type; - u8 count; // 2, 3, or 4 components - u8 indices[4]; - } swizzle; - struct { - Type *type; - Slice indices; - } swizzle_large; - }; -}; - - -struct cgTargetList { - cgTargetList *prev; - bool is_block; - // control regions - TB_Node * break_; - TB_Node * continue_; - TB_Node * fallthrough_; -}; - -struct cgBranchRegions { - Ast * label; - TB_Node *break_; - TB_Node *continue_; -}; - -enum cgDeferExitKind { - cgDeferExit_Default, - cgDeferExit_Return, - cgDeferExit_Branch, -}; - -enum cgDeferKind { - cgDefer_Node, - cgDefer_Proc, -}; - -struct cgDefer { - cgDeferKind kind; - isize scope_index; - isize context_stack_count; - TB_Node * control_region; - union { - Ast *stmt; - struct { - cgValue deferred; - Slice result_as_args; - } proc; - }; -}; - - -struct cgContextData { - cgAddr ctx; - isize scope_index; - isize uses; -}; - -struct cgControlRegion { - TB_Node *control_region; - isize scope_index; -}; - -struct cgProcedure { - u32 flags; - u16 state_flags; - - cgProcedure *parent; - Array children; - - TB_Function *func; - TB_FunctionPrototype *proto; - TB_Symbol *symbol; - - // includes parameters, pointers to return values, and context ptr - Slice param_nodes; - - Entity * entity; - cgModule *module; - String name; - Type * type; - Ast * type_expr; - Ast * body; - u64 tags; - ProcInlining inlining; - bool is_foreign; - bool is_export; - bool is_entry_point; - bool is_startup; - - TB_DebugType *debug_type; - - cgValue value; - - Ast *curr_stmt; - - cgTargetList * target_list; - Array defer_stack; - Array scope_stack; - Array context_stack; - - Array control_regions; - Array branch_regions; - - Scope *curr_scope; - i32 scope_index; - bool in_multi_assignment; - - - PtrMap variable_map; -}; - - -struct cgModule { - TB_Module * mod; - Checker * checker; - CheckerInfo *info; - - RwMutex values_mutex; - PtrMap values; - StringMap members; - - StringMap procedures; - PtrMap procedure_values; - Array procedures_to_generate; - - RecursiveMutex debug_type_mutex; - PtrMap debug_type_map; - PtrMap proc_debug_type_map; // not pointer to - - RecursiveMutex proc_proto_mutex; - PtrMap proc_proto_map; - - PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) - - std::atomic nested_type_name_guid; - std::atomic const_nil_guid; -}; - -#ifndef ABI_PKG_NAME_SEPARATOR -#define ABI_PKG_NAME_SEPARATOR "@" -#endif - -gb_global Entity *cg_global_type_info_data_entity = {}; -gb_global cgAddr cg_global_type_info_member_types = {}; -gb_global cgAddr cg_global_type_info_member_names = {}; -gb_global cgAddr cg_global_type_info_member_offsets = {}; -gb_global cgAddr cg_global_type_info_member_usings = {}; -gb_global cgAddr cg_global_type_info_member_tags = {}; - -gb_global isize cg_global_type_info_data_index = 0; -gb_global isize cg_global_type_info_member_types_index = 0; -gb_global isize cg_global_type_info_member_names_index = 0; -gb_global isize cg_global_type_info_member_offsets_index = 0; -gb_global isize cg_global_type_info_member_usings_index = 0; -gb_global isize cg_global_type_info_member_tags_index = 0; - -gb_internal cgValue cg_value(TB_Global * g, Type *type); -gb_internal cgValue cg_value(TB_External *e, Type *type); -gb_internal cgValue cg_value(TB_Function *f, Type *type); -gb_internal cgValue cg_value(TB_Symbol * s, Type *type); -gb_internal cgValue cg_value(TB_Node * node, Type *type); - -gb_internal cgAddr cg_addr(cgValue const &value); - - -gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value); -gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type); - -gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value); - -gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); -gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts); -gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); - -gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr); -gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr); - -gb_internal Type * cg_addr_type(cgAddr const &addr); -gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr); -gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value); -gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr); - -gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); - -gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); -gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); - -gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); - -gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); - -gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); - -gb_internal String cg_get_entity_name(cgModule *m, Entity *e); - -gb_internal cgValue cg_typeid(cgProcedure *m, Type *t); - -gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue index); -gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index); -gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index); -gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index); -gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel); - -gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t); -gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x); -gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right); -gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); - -gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); - - -gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); \ No newline at end of file -- cgit v1.2.3 From bd81c6f5b4bbcdb0c65cda5bedf1f3c5e0c0371e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 11:53:18 +0100 Subject: Move linker code into separate file --- src/linker.cpp | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/llvm_backend.hpp | 10 +- src/main.cpp | 425 ++------------------------------------------------ src/tilde/tb.lib | Bin 4161494 -> 4393788 bytes src/tilde_proc.cpp | 2 +- 5 files changed, 438 insertions(+), 426 deletions(-) create mode 100644 src/linker.cpp (limited to 'src/main.cpp') diff --git a/src/linker.cpp b/src/linker.cpp new file mode 100644 index 000000000..dc6e072d1 --- /dev/null +++ b/src/linker.cpp @@ -0,0 +1,427 @@ +struct LinkerData { + BlockingMutex foreign_mutex; + PtrSet foreign_libraries_set; + Array foreign_libraries; + + Array output_object_paths; + Array output_temp_paths; + String output_base; + String output_name; +}; + +gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...); + +gb_internal i32 linker_stage(LinkerData *gen) { + i32 result = 0; + Timings *timings = &global_timings; + + 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.o\" -o \"%.*s\" %.*s %.*s", + LIT(build_context.ODIN_ROOT), + 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.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) { +#if defined(GB_SYSTEM_UNIX) + result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", + 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]), + LIT(target_arch_names[build_context.metrics.arch]) + ); +#endif + } else if (build_context.cross_compiling && build_context.different_os) { + 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]), + LIT(target_arch_names[build_context.metrics.arch]) + ); + build_context.keep_object_files = true; + } else { + #if defined(GB_SYSTEM_WINDOWS) + bool is_windows = true; + #else + bool is_windows = false; + #endif + #if defined(GB_SYSTEM_OSX) + bool is_osx = true; + #else + bool is_osx = false; + #endif + + + if (is_windows) { + String section_name = str_lit("msvc-link"); + if (build_context.use_lld) { + section_name = str_lit("lld-link"); + } + timings_start_section(timings, section_name); + + gbString lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(lib_str)); + + gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); + defer (gb_string_free(link_settings)); + + // Add library search paths. + if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) { + String path = {}; + auto add_path = [&](String path) { + if (path[path.len-1] == '\\') { + path.len -= 1; + } + link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(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); + } + + + StringSet libs = {}; + string_set_init(&libs, 64); + defer (string_set_destroy(&libs)); + + StringSet asm_files = {}; + string_set_init(&asm_files, 64); + defer (string_set_destroy(&asm_files)); + + for (Entity *e : gen->foreign_libraries) { + GB_ASSERT(e->kind == Entity_LibraryName); + for_array(i, e->LibraryName.paths) { + String lib = string_trim_whitespace(e->LibraryName.paths[i]); + // IMPORTANT NOTE(bill): calling `string_to_lower` here is not an issue because + // we will never uses these strings afterwards + string_to_lower(&lib); + if (lib.len == 0) { + continue; + } + + if (has_asm_extension(lib)) { + if (!string_set_update(&asm_files, lib)) { + String asm_file = asm_files.entries[i].value; + String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); + + result = system_exec_command_line_app("nasm", + "\"%.*s\\bin\\nasm\\windows\\nasm.exe\" \"%.*s\" " + "-f win64 " + "-o \"%.*s\" " + "%.*s " + "", + LIT(build_context.ODIN_ROOT), LIT(asm_file), + LIT(obj_file), + LIT(build_context.extra_assembler_flags) + ); + + if (result) { + return result; + } + array_add(&gen->output_object_paths, obj_file); + } + } else { + if (!string_set_update(&libs, lib)) { + lib_str = gb_string_append_fmt(lib_str, " \"%.*s\"", LIT(lib)); + } + } + } + } + + for (Entity *e : gen->foreign_libraries) { + GB_ASSERT(e->kind == Entity_LibraryName); + if (e->LibraryName.extra_linker_flags.len != 0) { + lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags)); + } + } + + if (build_context.build_mode == BuildMode_DynamicLibrary) { + 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 != "") { + 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) { + link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); + } else { + link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); + } + + if (build_context.ODIN_DEBUG) { + link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); + } + + gbString object_files = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(object_files)); + for (String const &object_path : gen->output_object_paths) { + 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)); + + String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]); + defer (gb_free(heap_allocator(), windows_sdk_bin_path.text)); + + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; + if (!build_context.use_lld) { // msvc + String res_path = {}; + defer (gb_free(heap_allocator(), res_path.text)); + if (build_context.has_resource) { + String temp_res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); + res_path = concatenate3_strings(heap_allocator(), str_lit("\""), temp_res_path, str_lit("\"")); + gb_free(heap_allocator(), temp_res_path.text); + + String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); + defer (gb_free(heap_allocator(), rc_path.text)); + + result = system_exec_command_line_app("msvc-link", + "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"", + LIT(windows_sdk_bin_path), + LIT(res_path), + LIT(rc_path) + ); + + if (result) { + return result; + } + } + + switch (build_context.build_mode) { + case BuildMode_Executable: + link_settings = gb_string_append_fmt(link_settings, " /NOIMPLIB /NOEXP"); + break; + } + + result = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + "%.*s " + "%.*s " + "%s " + "", + LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename), + link_settings, + subsystem_str, + LIT(build_context.link_flags), + LIT(build_context.extra_linker_flags), + lib_str + ); + if (result) { + return result; + } + } else { // lld + result = system_exec_command_line_app("msvc-lld-link", + "\"%.*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_filename), + link_settings, + subsystem_str, + LIT(build_context.link_flags), + LIT(build_context.extra_linker_flags), + lib_str + ); + + if (result) { + return result; + } + } + } else { + timings_start_section(timings, str_lit("ld-link")); + + // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe + char cwd[256]; + #if !defined(GB_SYSTEM_WINDOWS) + getcwd(&cwd[0], 256); + #endif + //printf("%s\n", cwd); + + // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library + // files can be passed with -l: + gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + defer (gb_string_free(lib_str)); + + StringSet libs = {}; + string_set_init(&libs, 64); + defer (string_set_destroy(&libs)); + + for (Entity *e : gen->foreign_libraries) { + GB_ASSERT(e->kind == Entity_LibraryName); + for (String lib : e->LibraryName.paths) { + lib = string_trim_whitespace(lib); + if (lib.len == 0) { + continue; + } + if (string_set_update(&libs, lib)) { + continue; + } + + // NOTE(zangent): Sometimes, you have to use -framework on MacOS. + // This allows you to specify '-f' in a #foreign_system_library, + // without having to implement any new syntax specifically for MacOS. + if (build_context.metrics.os == TargetOs_darwin) { + if (string_ends_with(lib, str_lit(".framework"))) { + // framework thingie + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); + } else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) { + // For: + // object + // dynamic lib + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + } else { + // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, + // since those are statically linked to at link time. shared libraries (.so) has to be + // available at runtime wherever the executable is run, so we make require those to be + // local to the executable (unless the system collection is used, in which case we search + // the system library paths for the library file). + if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) { + // static libs and object files, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); + } 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 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 + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + } + } + } + + for (Entity *e : gen->foreign_libraries) { + GB_ASSERT(e->kind == Entity_LibraryName); + if (e->LibraryName.extra_linker_flags.len != 0) { + lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags)); + } + } + + gbString object_files = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(object_files)); + for (String object_path : gen->output_object_paths) { + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); + } + + gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); + + if (build_context.no_crt) { + link_settings = gb_string_append_fmt(link_settings, "-nostdlib "); + } + + // NOTE(dweiler): We use clang as a frontend for the linker as there are + // other runtime and compiler support libraries that need to be linked in + // very specific orders such as libgcc_s, ld-linux-so, unwind, etc. + // These are not always typically inside /lib, /lib64, or /usr versions + // of that, e.g libgcc.a is in /usr/lib/gcc/{version}, and can vary on + // the distribution of Linux even. The gcc or clang specs is the only + // reliable way to query this information to call ld directly. + if (build_context.build_mode == BuildMode_DynamicLibrary) { + // NOTE(dweiler): Let the frontend know we're building a shared library + // so it doesn't generate symbols which cannot be relocated. + link_settings = gb_string_appendc(link_settings, "-shared "); + + // NOTE(dweiler): _odin_entry_point must be called at initialization + // time of the shared object, similarly, _odin_exit_point must be called + // at deinitialization. We can pass both -init and -fini to the linker by + // using a comma separated list of arguments to -Wl. + // + // This previously used ld but ld cannot actually build a shared library + // 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. + if (build_context.metrics.os == TargetOs_darwin) { + link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); + // NOTE(weshardee): __odin_exit_point should also be added, but -fini + // does not exist on MacOS + } else { + 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 "); + } + + gbString platform_lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(platform_lib_str)); + if (build_context.metrics.os == TargetOs_darwin) { + platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib"); + } else { + platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm"); + } + + if (build_context.metrics.os == TargetOs_darwin) { + // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. + if (build_context.minimum_os_version_string.len) { + link_settings = gb_string_append_fmt(link_settings, " -mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string)); + } else if (build_context.metrics.arch == TargetArch_arm64) { + link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 "); + } else { + link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.12.0 "); + } + // This points the linker to where the entry point is + link_settings = gb_string_appendc(link_settings, " -e _main "); + } + + gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument "); + 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\" ", 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)); + link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags)); + link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings); + + result = system_exec_command_line_app("ld-link", link_command_line); + + if (result) { + return result; + } + + if (is_osx && 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", LIT(output_filename)); + + if (result) { + return result; + } + } + } + } + + return result; +} diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 15833c63a..e05bf8025 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -190,13 +190,9 @@ struct lbModule { LLVMPassManagerRef function_pass_managers[lbFunctionPassManager_COUNT]; }; -struct lbGenerator { +struct lbGenerator : LinkerData { CheckerInfo *info; - Array output_object_paths; - Array output_temp_paths; - String output_base; - String output_name; PtrMap modules; // key is `AstPackage *` (`void *` is used for future use) PtrMap modules_through_ctx; lbModule default_module; @@ -204,10 +200,6 @@ struct lbGenerator { RecursiveMutex anonymous_proc_lits_mutex; PtrMap anonymous_proc_lits; - BlockingMutex foreign_mutex; - PtrSet foreign_libraries_set; - Array foreign_libraries; - std::atomic global_array_index; std::atomic global_generated_index; diff --git a/src/main.cpp b/src/main.cpp index a59f452d8..70e887b9f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,6 +71,8 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" +#include "linker.cpp" + #if defined(GB_SYSTEM_WINDOWS) #include "tilde.cpp" #endif @@ -151,422 +153,6 @@ gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, return exit_code; } - -gb_internal i32 linker_stage(lbGenerator *gen) { - i32 result = 0; - Timings *timings = &global_timings; - - 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.o\" -o \"%.*s\" %.*s %.*s", - LIT(build_context.ODIN_ROOT), - 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.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) { -#if defined(GB_SYSTEM_UNIX) - result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - 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]), - LIT(target_arch_names[build_context.metrics.arch]) - ); -#endif - } else if (build_context.cross_compiling && build_context.different_os) { - 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]), - LIT(target_arch_names[build_context.metrics.arch]) - ); - build_context.keep_object_files = true; - } else { - #if defined(GB_SYSTEM_WINDOWS) - bool is_windows = true; - #else - bool is_windows = false; - #endif - #if defined(GB_SYSTEM_OSX) - bool is_osx = true; - #else - bool is_osx = false; - #endif - - - if (is_windows) { - String section_name = str_lit("msvc-link"); - if (build_context.use_lld) { - section_name = str_lit("lld-link"); - } - timings_start_section(timings, section_name); - - gbString lib_str = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(lib_str)); - - gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); - defer (gb_string_free(link_settings)); - - // Add library search paths. - if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) { - String path = {}; - auto add_path = [&](String path) { - if (path[path.len-1] == '\\') { - path.len -= 1; - } - link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(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); - } - - - StringSet libs = {}; - string_set_init(&libs, 64); - defer (string_set_destroy(&libs)); - - StringSet asm_files = {}; - string_set_init(&asm_files, 64); - defer (string_set_destroy(&asm_files)); - - for (Entity *e : gen->foreign_libraries) { - GB_ASSERT(e->kind == Entity_LibraryName); - for_array(i, e->LibraryName.paths) { - String lib = string_trim_whitespace(e->LibraryName.paths[i]); - // IMPORTANT NOTE(bill): calling `string_to_lower` here is not an issue because - // we will never uses these strings afterwards - string_to_lower(&lib); - if (lib.len == 0) { - continue; - } - - if (has_asm_extension(lib)) { - if (!string_set_update(&asm_files, lib)) { - String asm_file = asm_files.entries[i].value; - String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); - - result = system_exec_command_line_app("nasm", - "\"%.*s\\bin\\nasm\\windows\\nasm.exe\" \"%.*s\" " - "-f win64 " - "-o \"%.*s\" " - "%.*s " - "", - LIT(build_context.ODIN_ROOT), LIT(asm_file), - LIT(obj_file), - LIT(build_context.extra_assembler_flags) - ); - - if (result) { - return result; - } - array_add(&gen->output_object_paths, obj_file); - } - } else { - if (!string_set_update(&libs, lib)) { - lib_str = gb_string_append_fmt(lib_str, " \"%.*s\"", LIT(lib)); - } - } - } - } - - for (Entity *e : gen->foreign_libraries) { - GB_ASSERT(e->kind == Entity_LibraryName); - if (e->LibraryName.extra_linker_flags.len != 0) { - lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags)); - } - } - - if (build_context.build_mode == BuildMode_DynamicLibrary) { - 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 != "") { - 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) { - link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); - } else { - link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); - } - - if (build_context.ODIN_DEBUG) { - link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); - } - - gbString object_files = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(object_files)); - for (String const &object_path : gen->output_object_paths) { - 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)); - - String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]); - defer (gb_free(heap_allocator(), windows_sdk_bin_path.text)); - - char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; - if (!build_context.use_lld) { // msvc - String res_path = {}; - defer (gb_free(heap_allocator(), res_path.text)); - if (build_context.has_resource) { - String temp_res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); - res_path = concatenate3_strings(heap_allocator(), str_lit("\""), temp_res_path, str_lit("\"")); - gb_free(heap_allocator(), temp_res_path.text); - - String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); - defer (gb_free(heap_allocator(), rc_path.text)); - - result = system_exec_command_line_app("msvc-link", - "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"", - LIT(windows_sdk_bin_path), - LIT(res_path), - LIT(rc_path) - ); - - if (result) { - return result; - } - } - - switch (build_context.build_mode) { - case BuildMode_Executable: - link_settings = gb_string_append_fmt(link_settings, " /NOIMPLIB /NOEXP"); - break; - } - - result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s " - "/nologo /incremental:no /opt:ref /subsystem:%s " - "%.*s " - "%.*s " - "%s " - "", - LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename), - link_settings, - subsystem_str, - LIT(build_context.link_flags), - LIT(build_context.extra_linker_flags), - lib_str - ); - if (result) { - return result; - } - } else { // lld - result = system_exec_command_line_app("msvc-lld-link", - "\"%.*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_filename), - link_settings, - subsystem_str, - LIT(build_context.link_flags), - LIT(build_context.extra_linker_flags), - lib_str - ); - - if (result) { - return result; - } - } - } else { - timings_start_section(timings, str_lit("ld-link")); - - // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe - char cwd[256]; - #if !defined(GB_SYSTEM_WINDOWS) - getcwd(&cwd[0], 256); - #endif - //printf("%s\n", cwd); - - // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library - // files can be passed with -l: - gbString lib_str = gb_string_make(heap_allocator(), "-L/"); - defer (gb_string_free(lib_str)); - - StringSet libs = {}; - string_set_init(&libs, 64); - defer (string_set_destroy(&libs)); - - for (Entity *e : gen->foreign_libraries) { - GB_ASSERT(e->kind == Entity_LibraryName); - for (String lib : e->LibraryName.paths) { - lib = string_trim_whitespace(lib); - if (lib.len == 0) { - continue; - } - if (string_set_update(&libs, lib)) { - continue; - } - - // NOTE(zangent): Sometimes, you have to use -framework on MacOS. - // This allows you to specify '-f' in a #foreign_system_library, - // without having to implement any new syntax specifically for MacOS. - if (build_context.metrics.os == TargetOs_darwin) { - if (string_ends_with(lib, str_lit(".framework"))) { - // framework thingie - String lib_name = lib; - lib_name = remove_extension_from_path(lib_name); - lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); - } else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) { - // For: - // object - // dynamic lib - // static libs, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); - } else { - // dynamic or static system lib, just link regularly searching system library paths - lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); - } - } else { - // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, - // since those are statically linked to at link time. shared libraries (.so) has to be - // available at runtime wherever the executable is run, so we make require those to be - // local to the executable (unless the system collection is used, in which case we search - // the system library paths for the library file). - if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) { - // static libs and object files, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - } 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 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 - lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); - } - } - } - } - - for (Entity *e : gen->foreign_libraries) { - GB_ASSERT(e->kind == Entity_LibraryName); - if (e->LibraryName.extra_linker_flags.len != 0) { - lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags)); - } - } - - gbString object_files = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(object_files)); - for (String object_path : gen->output_object_paths) { - object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); - } - - gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); - - if (build_context.no_crt) { - link_settings = gb_string_append_fmt(link_settings, "-nostdlib "); - } - - // NOTE(dweiler): We use clang as a frontend for the linker as there are - // other runtime and compiler support libraries that need to be linked in - // very specific orders such as libgcc_s, ld-linux-so, unwind, etc. - // These are not always typically inside /lib, /lib64, or /usr versions - // of that, e.g libgcc.a is in /usr/lib/gcc/{version}, and can vary on - // the distribution of Linux even. The gcc or clang specs is the only - // reliable way to query this information to call ld directly. - if (build_context.build_mode == BuildMode_DynamicLibrary) { - // NOTE(dweiler): Let the frontend know we're building a shared library - // so it doesn't generate symbols which cannot be relocated. - link_settings = gb_string_appendc(link_settings, "-shared "); - - // NOTE(dweiler): _odin_entry_point must be called at initialization - // time of the shared object, similarly, _odin_exit_point must be called - // at deinitialization. We can pass both -init and -fini to the linker by - // using a comma separated list of arguments to -Wl. - // - // This previously used ld but ld cannot actually build a shared library - // 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. - if (build_context.metrics.os == TargetOs_darwin) { - link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); - // NOTE(weshardee): __odin_exit_point should also be added, but -fini - // does not exist on MacOS - } else { - 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 "); - } - - gbString platform_lib_str = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(platform_lib_str)); - if (build_context.metrics.os == TargetOs_darwin) { - platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib"); - } else { - platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm"); - } - - if (build_context.metrics.os == TargetOs_darwin) { - // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. - if (build_context.minimum_os_version_string.len) { - link_settings = gb_string_append_fmt(link_settings, " -mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string)); - } else if (build_context.metrics.arch == TargetArch_arm64) { - link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 "); - } else { - link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.12.0 "); - } - // This points the linker to where the entry point is - link_settings = gb_string_appendc(link_settings, " -e _main "); - } - - gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument "); - 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\" ", 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)); - link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags)); - link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings); - - result = system_exec_command_line_app("ld-link", link_command_line); - - if (result) { - return result; - } - - if (is_osx && 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", LIT(output_filename)); - - if (result) { - return result; - } - } - } - } - - return result; -} - gb_internal Array setup_args(int argc, char const **argv) { gbAllocator a = heap_allocator(); @@ -2359,6 +1945,8 @@ gb_internal void print_show_unused(Checker *c) { } gb_internal bool check_env(void) { + TIME_SECTION("init check env"); + gbAllocator a = heap_allocator(); char const *odin_root = gb_get_env("ODIN_ROOT", a); defer (gb_free(a, cast(void *)odin_root)); @@ -2560,6 +2148,7 @@ gb_internal int strip_semicolons(Parser *parser) { } gb_internal void init_terminal(void) { + TIME_SECTION("init terminal"); build_context.has_ansi_terminal_colours = false; gbAllocator a = heap_allocator(); @@ -2626,11 +2215,13 @@ int main(int arg_count, char const **arg_ptr) { return 1; } + TIME_SECTION("init default library collections"); array_init(&library_collections, heap_allocator()); // NOTE(bill): 'core' cannot be (re)defined by the user add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core"))); add_library_collection(str_lit("vendor"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("vendor"))); + TIME_SECTION("init args"); map_init(&build_context.defined_values); build_context.extra_packages.allocator = heap_allocator(); string_set_init(&build_context.test_names); @@ -2829,9 +2420,11 @@ int main(int arg_count, char const **arg_ptr) { } } + TIME_SECTION("init thread pool"); init_global_thread_pool(); defer (thread_pool_destroy(&global_thread_pool)); + TIME_SECTION("init universal"); init_universal(); // TODO(bill): prevent compiling without a linker diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index b35b28fc0..f5464cab0 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 8143c9a6e..fec77733d 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -358,7 +358,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { cg_procedure_end(p); if ( - string_starts_with(p->name, str_lit("runtime@_os_write")) || + // string_starts_with(p->name, str_lit("runtime@_os_write")) || false ) { // IR Printing TB_Arena *arena = tb_default_arena(); -- cgit v1.2.3 From b09cdc0f256bca71ffcb5960c75127e8aaa55b87 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 12:01:23 +0100 Subject: Hook up Tilde to the linker code --- src/linker.cpp | 33 +++++++++++++++++++++++++++++++++ src/llvm_backend_general.cpp | 36 +----------------------------------- src/main.cpp | 18 +++++++++++++----- src/tilde.cpp | 11 +++++++---- src/tilde.hpp | 1 + 5 files changed, 55 insertions(+), 44 deletions(-) (limited to 'src/main.cpp') diff --git a/src/linker.cpp b/src/linker.cpp index dc6e072d1..c0fbf596f 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -11,6 +11,39 @@ struct LinkerData { gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...); +gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String const &init_fullpath) { + gbAllocator ha = heap_allocator(); + array_init(&ld->output_object_paths, ha); + array_init(&ld->output_temp_paths, ha); + array_init(&ld->foreign_libraries, ha, 0, 1024); + ptr_set_init(&ld->foreign_libraries_set, 1024); + + if (build_context.out_filepath.len == 0) { + ld->output_name = remove_directory_from_path(init_fullpath); + ld->output_name = remove_extension_from_path(ld->output_name); + ld->output_name = string_trim_whitespace(ld->output_name); + if (ld->output_name.len == 0) { + ld->output_name = info->init_scope->pkg->name; + } + ld->output_base = ld->output_name; + } else { + ld->output_name = build_context.out_filepath; + ld->output_name = string_trim_whitespace(ld->output_name); + if (ld->output_name.len == 0) { + ld->output_name = info->init_scope->pkg->name; + } + isize pos = string_extension_position(ld->output_name); + if (pos < 0) { + ld->output_base = ld->output_name; + } else { + ld->output_base = substring(ld->output_name, 0, pos); + } + } + + ld->output_base = path_to_full_path(ha, ld->output_base); + +} + gb_internal i32 linker_stage(LinkerData *gen) { i32 result = 0; Timings *timings = &global_timings; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index ad8a1816a..f9c6de77d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -103,37 +103,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { } String init_fullpath = c->parser->init_fullpath; - - if (build_context.out_filepath.len == 0) { - gen->output_name = remove_directory_from_path(init_fullpath); - gen->output_name = remove_extension_from_path(gen->output_name); - gen->output_name = string_trim_whitespace(gen->output_name); - if (gen->output_name.len == 0) { - gen->output_name = c->info.init_scope->pkg->name; - } - gen->output_base = gen->output_name; - } else { - gen->output_name = build_context.out_filepath; - gen->output_name = string_trim_whitespace(gen->output_name); - if (gen->output_name.len == 0) { - gen->output_name = c->info.init_scope->pkg->name; - } - isize pos = string_extension_position(gen->output_name); - if (pos < 0) { - gen->output_base = gen->output_name; - } else { - gen->output_base = substring(gen->output_name, 0, pos); - } - } - gbAllocator ha = heap_allocator(); - array_init(&gen->output_object_paths, ha); - array_init(&gen->output_temp_paths, ha); - - gen->output_base = path_to_full_path(ha, gen->output_base); - - gbString output_file_path = gb_string_make_length(ha, gen->output_base.text, gen->output_base.len); - output_file_path = gb_string_appendc(output_file_path, ".obj"); - defer (gb_string_free(output_file_path)); + linker_data_init(gen, &c->info, init_fullpath); gen->info = &c->info; @@ -141,10 +111,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_init(&gen->modules_through_ctx, gen->info->packages.count*2); map_init(&gen->anonymous_proc_lits, 1024); - - array_init(&gen->foreign_libraries, heap_allocator(), 0, 1024); - ptr_set_init(&gen->foreign_libraries_set, 1024); - if (USE_SEPARATE_MODULES) { for (auto const &entry : gen->info->packages) { AstPackage *pkg = entry.value; diff --git a/src/main.cpp b/src/main.cpp index 70e887b9f..9f8530b04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2489,16 +2489,24 @@ int main(int arg_count, char const **arg_ptr) { #if defined(GB_SYSTEM_WINDOWS) if (build_context.tilde_backend) { + LinkerData linker_data = {}; MAIN_TIME_SECTION("Tilde Code Gen"); - if (!cg_generate_code(checker)) { + if (!cg_generate_code(checker, &linker_data)) { return 1; } - if (build_context.show_timings) { - show_timings(checker, &global_timings); + switch (build_context.build_mode) { + case BuildMode_Executable: + case BuildMode_DynamicLibrary: + i32 result = linker_stage(&linker_data); + if (result) { + if (build_context.show_timings) { + show_timings(checker, &global_timings); + } + return result; + } + break; } - - return 0; } else #endif { diff --git a/src/tilde.cpp b/src/tilde.cpp index ff2a540f5..2fa7ced53 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -717,11 +717,12 @@ gb_internal String cg_get_entity_name(cgModule *m, Entity *e) { #include "tilde_stmt.cpp" -gb_internal bool cg_generate_code(Checker *c) { +gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { TIME_SECTION("Tilde Module Initializtion"); CheckerInfo *info = &c->info; - gb_unused(info); + + linker_data_init(linker_data, info, c->parser->init_fullpath); global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); for_array(i, global_tb_arenas) { @@ -803,8 +804,10 @@ gb_internal bool cg_generate_code(Checker *c) { TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); defer (tb_export_buffer_free(export_buffer)); - char const *path = "W:/Odin/tilde_main.obj"; - GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); + char const *filepath_obj = "W:/Odin/tilde_main.obj"; + + array_add(&linker_data->output_object_paths, make_string_c(filepath_obj)); + GB_ASSERT(tb_export_buffer_to_file(export_buffer, filepath_obj)); return true; } diff --git a/src/tilde.hpp b/src/tilde.hpp index 8a29d4c90..44da86c35 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -208,6 +208,7 @@ struct cgModule { TB_Module * mod; Checker * checker; CheckerInfo *info; + LinkerData * linker_data; RwMutex values_mutex; PtrMap values; -- cgit v1.2.3 From 60e509b1e066da14461b3832307065726e651153 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 31 Jul 2023 11:09:19 +0100 Subject: Add separate `-vet` flags; `-vet-using-*` flags; `//+vet` file flags --- examples/demo/demo.odin | 1 + src/build_settings.cpp | 35 ++++++++++++++++++++-- src/check_decl.cpp | 2 +- src/check_expr.cpp | 6 ++-- src/check_stmt.cpp | 6 ++++ src/check_type.cpp | 6 ++++ src/checker.cpp | 24 +++++++++------ src/checker.hpp | 7 +++++ src/main.cpp | 57 ++++++++++++++++++++++++++++++----- src/parser.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.hpp | 2 ++ 11 files changed, 204 insertions(+), 22 deletions(-) (limited to 'src/main.cpp') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 7c98ca728..5f1e84bbf 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1,3 +1,4 @@ +//+vet !using-stmt !using-param package main import "core:fmt" diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 866631f9a..f234ff2ce 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -216,6 +216,37 @@ enum BuildPath : u8 { BuildPathCOUNT, }; +enum VetFlags : u64 { + VetFlag_NONE = 0, + VetFlag_Unused = 1u<<0, + VetFlag_Shadowing = 1u<<1, + VetFlag_UsingStmt = 1u<<2, + VetFlag_UsingParam = 1u<<3, + + VetFlag_Extra = 1u<<16, + + VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt, // excluding extra + + VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam, +}; + +u64 get_vet_flag_from_name(String const &name) { + if (name == "unused") { + return VetFlag_Unused; + } else if (name == "shadowing") { + return VetFlag_Shadowing; + } else if (name == "using-stmt") { + return VetFlag_UsingStmt; + } else if (name == "using-param") { + return VetFlag_UsingParam; + } else if (name == "extra") { + return VetFlag_Extra; + } + return VetFlag_NONE; +} + + + // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -255,6 +286,8 @@ struct BuildContext { String resource_filepath; String pdb_filepath; + u64 vet_flags; + bool has_resource; String link_flags; String extra_linker_flags; @@ -280,8 +313,6 @@ struct BuildContext { bool no_entry_point; bool no_thread_local; bool use_lld; - bool vet; - bool vet_extra; bool cross_compiling; bool different_os; bool keep_object_files; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 2b2fb867c..3dca7aafa 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1636,7 +1636,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de } check_close_scope(ctx); - check_scope_usage(ctx->checker, ctx->scope); + check_scope_usage(ctx->checker, ctx->scope, check_vet_flags(ctx)); add_deps_from_child_to_parent(decl); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 98154f33d..fe389e027 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3099,7 +3099,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { update_untyped_expr_type(c, x->expr, final_type, true); } - if (build_context.vet_extra) { + if (check_vet_flags(c) & VetFlag_Extra) { if (are_types_identical(x->type, type)) { gbString str = type_to_string(type); warning(x->expr, "Unneeded cast to the same type '%s'", str); @@ -3171,7 +3171,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type return false; } - if (build_context.vet_extra) { + if (check_vet_flags(c) & VetFlag_Extra) { if (are_types_identical(o->type, dst_t)) { gbString str = type_to_string(dst_t); warning(o->expr, "Unneeded transmute to the same type '%s'", str); @@ -10028,7 +10028,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast Type *type = type_of_expr(ac->expr); check_cast(c, o, type_hint); if (is_type_typed(type) && are_types_identical(type, type_hint)) { - if (build_context.vet_extra) { + if (check_vet_flags(c) & VetFlag_Extra) { error(node, "Redundant 'auto_cast' applied to expression"); } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a15977b7d..2c1ee8331 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2464,6 +2464,12 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(us->token, "Empty 'using' list"); return; } + if (check_vet_flags(ctx) & VetFlag_UsingStmt) { + ERROR_BLOCK(); + error(node, "'using' as a statement is now allowed when '-vet' or '-vet-using' is applied"); + error_line("\t'using' is considered bad practice to use as a statement outside of immediate refactoring\n"); + } + for (Ast *expr : us->list) { expr = unparen_expr(expr); Entity *e = nullptr; diff --git a/src/check_type.cpp b/src/check_type.cpp index a68f83ba9..c52f32f1a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1474,6 +1474,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para Type *specialization = nullptr; bool is_using = (p->flags&FieldFlag_using) != 0; + if ((build_context.vet_flags & VetFlag_UsingParam) && is_using) { + ERROR_BLOCK(); + error(param, "'using' on a procedure parameter is now allowed when '-vet' or '-vet-using-stmt' is applied"); + error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n"); + + } if (type_expr == nullptr) { param_value = handle_parameter_value(ctx, nullptr, &type, default_value, true); diff --git a/src/checker.cpp b/src/checker.cpp index 2a2cb5c42..a6b66f809 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -655,9 +655,9 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { return false; } -gb_internal void check_scope_usage(Checker *c, Scope *scope) { - bool vet_unused = true; - bool vet_shadowing = true; +gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { + bool vet_unused = (vet_flags & VetFlag_Unused) != 0; + bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0; Array vetted_entities = {}; array_init(&vetted_entities, heap_allocator()); @@ -691,15 +691,17 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) { if (ve.kind == VettedEntity_Shadowed_And_Unused) { error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line); - } else if (build_context.vet) { + } else if (vet_flags) { switch (ve.kind) { case VettedEntity_Unused: - error(e->token, "'%.*s' declared but not used", LIT(name)); + if (vet_flags & VetFlag_Unused) { + error(e->token, "'%.*s' declared but not used", LIT(name)); + } break; case VettedEntity_Shadowed: - if (e->flags&EntityFlag_Using) { + if ((vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0 && e->flags&EntityFlag_Using) { error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line); - } else { + } else if ((vet_flags & (VetFlag_Shadowing)) != 0) { error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line); } break; @@ -726,7 +728,7 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) { if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) { // Ignore these } else { - check_scope_usage(c, child); + check_scope_usage(c, child, vet_flags); } } } @@ -5952,7 +5954,11 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("check scope usage"); for (auto const &entry : c->info.files) { AstFile *f = entry.value; - check_scope_usage(c, f->scope); + u64 vet_flags = build_context.vet_flags; + if (f->vet_flags_set) { + vet_flags = f->vet_flags; + } + check_scope_usage(c, f->scope, vet_flags); } TIME_SECTION("add basic type information"); diff --git a/src/checker.hpp b/src/checker.hpp index b06d0a8f9..12090cbca 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -449,6 +449,13 @@ struct CheckerContext { Ast *assignment_lhs_hint; }; +u64 check_vet_flags(CheckerContext *c) { + if (c->file && c->file->vet_flags_set) { + return c->file->vet_flags; + } + return build_context.vet_flags; +} + struct Checker { Parser * parser; diff --git a/src/main.cpp b/src/main.cpp index db2702b19..1802e2984 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -654,6 +654,10 @@ enum BuildFlagKind { BuildFlag_NoThreadedChecker, BuildFlag_ShowDebugMessages, BuildFlag_Vet, + BuildFlag_VetShadowing, + BuildFlag_VetUnused, + BuildFlag_VetUsingStmt, + BuildFlag_VetUsingParam, BuildFlag_VetExtra, BuildFlag_IgnoreUnknownAttributes, BuildFlag_ExtraLinkerFlags, @@ -830,8 +834,14 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); + 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); @@ -1362,13 +1372,23 @@ gb_internal bool parse_build_flags(Array args) { build_context.show_debug_messages = true; break; case BuildFlag_Vet: - build_context.vet = true; + if (build_context.vet_flags & VetFlag_Extra) { + build_context.vet_flags |= VetFlag_All; + } else { + build_context.vet_flags &= ~VetFlag_Extra; + build_context.vet_flags |= VetFlag_All; + } break; - case BuildFlag_VetExtra: { - build_context.vet = true; - build_context.vet_extra = true; + + case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; + case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; + case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; + case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; + + case BuildFlag_VetExtra: + build_context.vet_flags = VetFlag_All | VetFlag_Extra; break; - } + case BuildFlag_IgnoreUnknownAttributes: build_context.ignore_unknown_attributes = true; break; @@ -2124,19 +2144,42 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Multithread the semantic checker stage"); print_usage_line(0, ""); #endif + } + if (check) { print_usage_line(1, "-vet"); print_usage_line(2, "Do extra checks on the code"); print_usage_line(2, "Extra checks include:"); - print_usage_line(3, "Variable shadowing within procedures"); - print_usage_line(3, "Unused declarations"); + print_usage_line(2, "-vet-unused"); + print_usage_line(2, "-vet-shadowing"); + print_usage_line(2, "-vet-using-stmt"); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-unused"); + print_usage_line(2, "Checks for unused declarations"); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-shadowing"); + print_usage_line(2, "Checks for variable shadowing within procedures"); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-using-stmt"); + print_usage_line(2, "Checks for the use of 'using' as a statement"); + print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-using-param"); + print_usage_line(2, "Checks for the use of 'using' on procedure parameters"); + print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); print_usage_line(0, ""); print_usage_line(1, "-vet-extra"); print_usage_line(2, "Do even more checks than standard vet on the code"); print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors"); print_usage_line(0, ""); + } + if (check) { print_usage_line(1, "-ignore-unknown-attributes"); print_usage_line(2, "Ignores unknown attributes"); print_usage_line(2, "This can be used with metaprogramming tools"); diff --git a/src/parser.cpp b/src/parser.cpp index b756412ff..b99182189 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5528,6 +5528,83 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { return any_correct; } +gb_internal String vet_tag_get_token(String s, String *out) { + s = string_trim_whitespace(s); + isize n = 0; + while (n < s.len) { + Rune rune = 0; + isize width = utf8_decode(&s[n], s.len-n, &rune); + if (n == 0 && rune == '!') { + + } else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-') { + isize k = gb_max(gb_max(n, width), 1); + *out = substring(s, k, s.len); + return substring(s, 0, k); + } + n += width; + } + out->len = 0; + return s; +} + + +gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { + String const prefix = str_lit("+vet"); + GB_ASSERT(string_starts_with(s, prefix)); + s = string_trim_whitespace(substring(s, prefix.len, s.len)); + + if (s.len == 0) { + return VetFlag_All; + } + + + u64 vet_flags = 0; + u64 vet_not_flags = 0; + + while (s.len > 0) { + String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + if (p.len == 0) break; + + bool is_notted = false; + if (p[0] == '!') { + is_notted = true; + p = substring(p, 1, p.len); + if (p.len == 0) { + syntax_error(token_for_pos, "Expected a vet flag name after '!'"); + break; + } + } + + if (p.len == 0) { + continue; + } + + u64 flag = get_vet_flag_from_name(p); + if (flag != VetFlag_NONE) { + if (is_notted) { + vet_not_flags |= flag; + } else { + vet_flags |= flag; + } + } else { + ERROR_BLOCK(); + syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p)); + error_line("\tExpected one of the following\n"); + error_line("\tunused\n"); + error_line("\tshadowing\n"); + error_line("\tusing-stmt\n"); + error_line("\tusing-param\n"); + error_line("\textra\n"); + break; + } + } + + if (vet_flags == 0 && vet_not_flags != 0) { + vet_flags = VetFlag_All; + } + return vet_flags &~ vet_not_flags; +} + gb_internal String dir_from_path(String path) { String base_dir = path; for (isize i = path.len-1; i >= 0; i--) { @@ -5679,6 +5756,9 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { if (!parse_build_tag(tok, lc)) { return false; } + } else if (string_starts_with(lc, str_lit("+vet"))) { + f->vet_flags = parse_vet_tag(tok, lc); + f->vet_flags_set = true; } else if (string_starts_with(lc, str_lit("+ignore"))) { return false; } else if (string_starts_with(lc, str_lit("+private"))) { diff --git a/src/parser.hpp b/src/parser.hpp index 900fddbab..fa169d3ad 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -104,6 +104,8 @@ struct AstFile { Token package_token; String package_name; + u64 vet_flags; + bool vet_flags_set; // >= 0: In Expression // < 0: In Control Clause -- cgit v1.2.3 From c35c58b023ec98aa7d42498b9ece68cf481f2c32 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Aug 2023 11:03:15 +0100 Subject: Add `-vet-style` and `-vet-semicolon` --- src/build_settings.cpp | 6 ++++ src/check_expr.cpp | 4 +-- src/main.cpp | 30 ++++++++++++++++---- src/parser.cpp | 75 +++++++++++++++++++++++++++++--------------------- 4 files changed, 77 insertions(+), 38 deletions(-) (limited to 'src/main.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b46ea10e0..48891e89c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -222,6 +222,8 @@ enum VetFlags : u64 { VetFlag_Shadowing = 1u<<1, // 2 VetFlag_UsingStmt = 1u<<2, // 4 VetFlag_UsingParam = 1u<<3, // 8 + VetFlag_Style = 1u<<4, // 16 + VetFlag_Semicolon = 1u<<5, // 32 VetFlag_Extra = 1u<<16, @@ -239,6 +241,10 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_UsingStmt; } else if (name == "using-param") { return VetFlag_UsingParam; + } else if (name == "style") { + return VetFlag_Style; + } else if (name == "semicolon") { + return VetFlag_Semicolon; } else if (name == "extra") { return VetFlag_Extra; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f9c62b506..8d159d920 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2261,7 +2261,7 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { } gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { - if (!build_context.strict_style) { + if (!(build_context.strict_style || (check_vet_flags(expr) & VetFlag_Style))) { return; } @@ -2351,7 +2351,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * o->type = alloc_type_pointer(o->type); } } else { - if (build_context.strict_style && ast_node_expect(node, Ast_UnaryExpr)) { + if (ast_node_expect(node, Ast_UnaryExpr)) { ast_node(ue, UnaryExpr, node); check_old_for_or_switch_value_usage(ue->expr); } diff --git a/src/main.cpp b/src/main.cpp index 1802e2984..5cecb5682 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -653,12 +653,16 @@ enum BuildFlagKind { BuildFlag_UseSeparateModules, BuildFlag_NoThreadedChecker, BuildFlag_ShowDebugMessages, + BuildFlag_Vet, BuildFlag_VetShadowing, BuildFlag_VetUnused, BuildFlag_VetUsingStmt, BuildFlag_VetUsingParam, + BuildFlag_VetStyle, + BuildFlag_VetSemicolon, BuildFlag_VetExtra, + BuildFlag_IgnoreUnknownAttributes, BuildFlag_ExtraLinkerFlags, BuildFlag_ExtraAssemblerFlags, @@ -839,7 +843,9 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetStyle, str_lit("vet-style"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); @@ -1380,10 +1386,12 @@ gb_internal bool parse_build_flags(Array args) { } break; - case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; - case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; - case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; + case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; + case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; + case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; + case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; + case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; case BuildFlag_VetExtra: build_context.vet_flags = VetFlag_All | VetFlag_Extra; @@ -2173,6 +2181,16 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); print_usage_line(0, ""); + print_usage_line(1, "-vet-style"); + print_usage_line(2, "Errs on missing trailing commas followed by a newline"); + print_usage_line(2, "Errs on deprecated syntax"); + print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)"); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-semicolon"); + print_usage_line(2, "Errs on unneeded semicolons"); + print_usage_line(0, ""); + print_usage_line(1, "-vet-extra"); print_usage_line(2, "Do even more checks than standard vet on the code"); print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors"); @@ -2249,10 +2267,12 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-strict-style"); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); + print_usage_line(2, "Errs on missing trailing commas followed by a newline"); + print_usage_line(2, "Errs on deprecated syntax"); print_usage_line(0, ""); print_usage_line(1, "-strict-style-init-only"); - print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons, only on the initial project"); + print_usage_line(2, "Same as -strict-style but only on the initial package"); print_usage_line(0, ""); print_usage_line(1, "-ignore-warnings"); diff --git a/src/parser.cpp b/src/parser.cpp index 7d1c37d84..c991f5741 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,7 +1,21 @@ #include "parser_pos.cpp" -// #undef at the bottom of this file -#define ALLOW_NEWLINE (!build_context.strict_style) +gb_internal u64 ast_file_vet_flags(AstFile *f) { + if (f->vet_flags_set) { + return f->vet_flags; + } + return build_context.vet_flags; +} + +gb_internal bool ast_file_vet_style(AstFile *f) { + return (ast_file_vet_flags(f) & VetFlag_Style) != 0; +} + + +gb_internal bool file_allow_newline(AstFile *f) { + bool is_strict = build_context.strict_style || ast_file_vet_style(f); + return !is_strict; +} gb_internal Token token_end_of_line(AstFile *f, Token tok) { u8 const *start = f->tokenizer.start + tok.pos.offset; @@ -1567,29 +1581,31 @@ gb_internal void assign_removal_flag_to_semicolon(AstFile *f) { Token *prev_token = &f->tokens[f->prev_token_index]; Token *curr_token = &f->tokens[f->curr_token_index]; GB_ASSERT(prev_token->kind == Token_Semicolon); - if (prev_token->string == ";") { - bool ok = false; - if (curr_token->pos.line > prev_token->pos.line) { + if (prev_token->string != ";") { + return; + } + bool ok = false; + if (curr_token->pos.line > prev_token->pos.line) { + ok = true; + } else if (curr_token->pos.line == prev_token->pos.line) { + switch (curr_token->kind) { + case Token_CloseBrace: + case Token_CloseParen: + case Token_EOF: ok = true; - } else if (curr_token->pos.line == prev_token->pos.line) { - switch (curr_token->kind) { - case Token_CloseBrace: - case Token_CloseParen: - case Token_EOF: - ok = true; - break; - } - } - - if (ok) { - if (build_context.strict_style) { - syntax_error(*prev_token, "Found unneeded semicolon"); - } else if (build_context.strict_style_init_only && f->pkg->kind == Package_Init) { - syntax_error(*prev_token, "Found unneeded semicolon"); - } - prev_token->flags |= TokenFlag_Remove; + break; } } + if (!ok) { + return; + } + + if (build_context.strict_style || (ast_file_vet_flags(f) & VetFlag_Semicolon)) { + syntax_error(*prev_token, "Found unneeded semicolon"); + } else if (build_context.strict_style_init_only && f->pkg->kind == Package_Init) { + syntax_error(*prev_token, "Found unneeded semicolon"); + } + prev_token->flags |= TokenFlag_Remove; } gb_internal void expect_semicolon(AstFile *f) { @@ -2748,7 +2764,7 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) { isize prev_expr_level = f->expr_level; bool prev_allow_newline = f->allow_newline; f->expr_level = 0; - f->allow_newline = ALLOW_NEWLINE; + f->allow_newline = file_allow_newline(f); open_paren = expect_token(f, Token_OpenParen); @@ -3147,7 +3163,7 @@ gb_internal Ast *parse_expr(AstFile *f, bool lhs) { gb_internal Array parse_expr_list(AstFile *f, bool lhs) { bool allow_newline = f->allow_newline; - f->allow_newline = ALLOW_NEWLINE; + f->allow_newline = file_allow_newline(f); auto list = array_make(heap_allocator()); for (;;) { @@ -3472,7 +3488,7 @@ gb_internal Ast *parse_results(AstFile *f, bool *diverging) { Ast *list = nullptr; expect_token(f, Token_OpenParen); list = parse_field_list(f, nullptr, FieldFlag_Results, Token_CloseParen, true, false); - if (ALLOW_NEWLINE) { + if (file_allow_newline(f)) { skip_possible_newline(f); } expect_token_after(f, Token_CloseParen, "parameter list"); @@ -3532,7 +3548,7 @@ gb_internal Ast *parse_proc_type(AstFile *f, Token proc_token) { expect_token(f, Token_OpenParen); params = parse_field_list(f, nullptr, FieldFlag_Signature, Token_CloseParen, true, true); - if (ALLOW_NEWLINE) { + if (file_allow_newline(f)) { skip_possible_newline(f); } expect_token_after(f, Token_CloseParen, "parameter list"); @@ -3754,7 +3770,7 @@ gb_internal bool allow_field_separator(AstFile *f) { } if (token.kind == Token_Semicolon) { bool ok = false; - if (ALLOW_NEWLINE && token_is_newline(token)) { + if (file_allow_newline(f) && token_is_newline(token)) { TokenKind next = peek_token(f).kind; switch (next) { case Token_CloseBrace: @@ -3818,7 +3834,7 @@ gb_internal bool check_procedure_name_list(Array const &names) { gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_typeid_token) { bool prev_allow_newline = f->allow_newline; defer (f->allow_newline = prev_allow_newline); - f->allow_newline = ALLOW_NEWLINE; + f->allow_newline = file_allow_newline(f); Token start_token = f->curr_token; @@ -6005,6 +6021,3 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { return ParseFile_None; } - - -#undef ALLOW_NEWLINE -- cgit v1.2.3 From 69e1f42aedad0d1992e64989aac1d236bee3d4d9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Aug 2023 11:11:15 +0100 Subject: Replace a lot of warnings with errors; remove deprecated stuff --- src/check_builtin.cpp | 2 +- src/check_decl.cpp | 26 +------------------------- src/check_expr.cpp | 2 +- src/checker.cpp | 6 +++--- src/main.cpp | 7 ------- src/tokenizer.cpp | 4 ++-- 6 files changed, 8 insertions(+), 39 deletions(-) (limited to 'src/main.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 269a0ec48..35720c914 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1406,7 +1406,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } return false; } else if (name == "load_or") { - warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'"); + error(call, "'#load_or' has now been removed in favour of '#load(path) or_else default'"); if (ce->args.count != 2) { if (ce->args.count == 0) { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9e96dae1c..4a1a636f8 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -354,31 +354,7 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, // using decl if (decl->is_using) { - warning(init_expr, "'using' an enum declaration is not allowed, prefer using implicit selector expressions e.g. '.A'"); - #if 1 - // NOTE(bill): Must be an enum declaration - if (te->kind == Ast_EnumType) { - Scope *parent = e->scope; - if (parent->flags&ScopeFlag_File) { - // NOTE(bill): Use package scope - parent = parent->parent; - } - - Type *t = base_type(e->type); - if (t->kind == Type_Enum) { - for (Entity *f : t->Enum.fields) { - if (f->kind != Entity_Constant) { - continue; - } - String name = f->token.string; - if (is_blank_ident(name)) { - continue; - } - add_entity(ctx, parent, nullptr, f); - } - } - } - #endif + error(init_expr, "'using' an enum declaration is not allowed, prefer using implicit selector expressions e.g. '.A'"); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8d159d920..40bf729c1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7153,7 +7153,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c i32 id = operand->builtin_id; Entity *e = entity_of_node(operand->expr); if (e != nullptr && e->token.string == "expand_to_tuple") { - warning(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'"); + error(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'"); } if (!check_builtin_procedure(c, operand, call, id, type_hint)) { operand->mode = Addressing_Invalid; diff --git a/src/checker.cpp b/src/checker.cpp index 895e3c528..91c62c20c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3085,7 +3085,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { check_expr(c, &o, value); Entity *e = entity_of_node(o.expr); if (e != nullptr && e->kind == Entity_Procedure) { - warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name)); + error(elem, "'%.*s' is not allowed any more, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name)); if (ac->deferred_procedure.entity != nullptr) { error(elem, "Previous usage of a 'deferred_*' attribute"); } @@ -4584,7 +4584,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { if (value != nullptr) { error(elem, "Expected no parameter for '%.*s'", LIT(name)); } else if (name == "force") { - warning(elem, "'force' is deprecated and is identical to 'require'"); + error(elem, "'force' was replaced with 'require'"); } ac->require_declaration = true; return true; @@ -6104,7 +6104,7 @@ gb_internal void check_parsed_files(Checker *c) { while (mpsc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) { if (c->info.entry_point == nullptr && node != nullptr) { if (node->file()->pkg->kind != Package_Runtime) { - warning(node, "usage of intrinsics.__entry_point will be a no-op"); + error(node, "usage of intrinsics.__entry_point will be a no-op"); } } } diff --git a/src/main.cpp b/src/main.cpp index 5cecb5682..aa5b2ed34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2142,16 +2142,9 @@ gb_internal void print_show_help(String const arg0, String const &command) { } if (check) { - #if defined(GB_SYSTEM_WINDOWS) print_usage_line(1, "-no-threaded-checker"); print_usage_line(2, "Disabled multithreading in the semantic checker stage"); print_usage_line(0, ""); - #else - print_usage_line(1, "-threaded-checker"); - print_usage_line(1, "[EXPERIMENTAL]"); - print_usage_line(2, "Multithread the semantic checker stage"); - print_usage_line(0, ""); - #endif } if (check) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 17a396b9f..ad7aa81de 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -696,8 +696,8 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { if (entry->kind != Token_Invalid && entry->hash == hash) { if (str_eq(entry->text, token->string)) { token->kind = entry->kind; - if (token->kind == Token_not_in && entry->text == "notin") { - syntax_warning(*token, "'notin' is deprecated in favour of 'not_in'"); + if (token->kind == Token_not_in && entry->text.len == 5) { + syntax_error(*token, "Did you mean 'not_in'?"); } } } -- cgit v1.2.3 From 2f094134a3e54cb6b99daf09b6a257b36f182b6e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Aug 2023 11:14:52 +0100 Subject: Remove `-strict-style-init-only` --- src/build_settings.cpp | 1 - src/main.cpp | 19 +------------------ src/parser.cpp | 2 -- 3 files changed, 1 insertion(+), 21 deletions(-) (limited to 'src/main.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 48891e89c..97098e545 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -325,7 +325,6 @@ struct BuildContext { bool disallow_do; bool strict_style; - bool strict_style_init_only; bool ignore_warnings; bool warnings_as_errors; diff --git a/src/main.cpp b/src/main.cpp index aa5b2ed34..abd01b7db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -679,7 +679,6 @@ enum BuildFlagKind { BuildFlag_DisallowDo, BuildFlag_DefaultToNilAllocator, BuildFlag_StrictStyle, - BuildFlag_StrictStyleInitOnly, BuildFlag_ForeignErrorProcedures, BuildFlag_NoRTTI, BuildFlag_DynamicMapCalls, @@ -863,7 +862,6 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check); - 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_NoRTTI, str_lit("no-rtti"), BuildFlagParam_None, Command__does_check); @@ -1484,20 +1482,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_ForeignErrorProcedures: build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true; break; - case BuildFlag_StrictStyle: { - if (build_context.strict_style_init_only) { - gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n"); - } + case BuildFlag_StrictStyle: build_context.strict_style = true; break; - } - case BuildFlag_StrictStyleInitOnly: { - if (build_context.strict_style) { - gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n"); - } - build_context.strict_style_init_only = true; - break; - } case BuildFlag_Short: build_context.cmd_doc_flags |= CmdDocFlag_Short; break; @@ -2264,10 +2251,6 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Errs on deprecated syntax"); print_usage_line(0, ""); - print_usage_line(1, "-strict-style-init-only"); - print_usage_line(2, "Same as -strict-style but only on the initial package"); - print_usage_line(0, ""); - print_usage_line(1, "-ignore-warnings"); print_usage_line(2, "Ignores warning messages"); print_usage_line(0, ""); diff --git a/src/parser.cpp b/src/parser.cpp index c991f5741..1aa03033e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1602,8 +1602,6 @@ gb_internal void assign_removal_flag_to_semicolon(AstFile *f) { if (build_context.strict_style || (ast_file_vet_flags(f) & VetFlag_Semicolon)) { syntax_error(*prev_token, "Found unneeded semicolon"); - } else if (build_context.strict_style_init_only && f->pkg->kind == Package_Init) { - syntax_error(*prev_token, "Found unneeded semicolon"); } prev_token->flags |= TokenFlag_Remove; } -- cgit v1.2.3 From fb30bda7d77ff01548e98a59f70d634b03d44f91 Mon Sep 17 00:00:00 2001 From: Hasan Yasin Ozturk Date: Tue, 1 Aug 2023 15:51:22 +0300 Subject: Add -show-system-calls flag info to cli usage help --- src/main.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index abd01b7db..cf61049da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -174,7 +174,7 @@ gb_internal i32 linker_stage(lbGenerator *gen) { } if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#if defined(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_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else @@ -498,13 +498,13 @@ gb_internal i32 linker_stage(lbGenerator *gen) { // line arguments prepared previously are incompatible with ld. if (build_context.metrics.os == TargetOs_darwin) { link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); - // NOTE(weshardee): __odin_exit_point should also be added, but -fini + // NOTE(weshardee): __odin_exit_point should also be added, but -fini // does not exist on MacOS } else { 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 "); @@ -1587,7 +1587,7 @@ gb_internal bool parse_build_flags(Array args) { if (path_is_directory(path)) { gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path)); bad_flags = true; - break; + break; } // #if defined(GB_SYSTEM_WINDOWS) // String ext = path_extension(path); @@ -2020,6 +2020,10 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds"); print_usage_line(0, ""); + print_usage_line(1, "-show-system-calls"); + print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler"); + print_usage_line(0, ""); + print_usage_line(1, "-export-timings:"); print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`"); print_usage_line(2, "Available options:"); @@ -2853,7 +2857,7 @@ int main(int arg_count, char const **arg_ptr) { 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(); -- cgit v1.2.3 From 8060da2132a4f21f5a2ee6c7967c4dd3fb581cf0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Aug 2023 13:16:23 +0100 Subject: Toggle tilde backend in the build script --- build.bat | 10 ++++++++-- src/main.cpp | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/main.cpp') diff --git a/build.bat b/build.bat index 33ada329b..ffa640c33 100644 --- a/build.bat +++ b/build.bat @@ -78,8 +78,14 @@ set compiler_includes= ^ set libs= ^ kernel32.lib ^ Synchronization.lib ^ - bin\llvm\windows\LLVM-C.lib ^ - src\tilde\tb.lib + bin\llvm\windows\LLVM-C.lib + +set tilde_backend=0 +if %tilde_backend% EQU 1 ( + set libs=%libs% src\tilde\tb.lib + set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND +) + set linker_flags= -incremental:no -opt:ref -subsystem:console diff --git a/src/main.cpp b/src/main.cpp index fbed6a2d1..2a7c90744 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,7 +72,7 @@ gb_global Timings global_timings = {0}; #include "linker.cpp" -#if defined(GB_SYSTEM_WINDOWS) +#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND) #define ALLOW_TILDE 1 #else #define ALLOW_TILDE 0 -- cgit v1.2.3