diff --git a/build.bat b/build.bat index b6e8b890d..9cddcc375 100644 --- a/build.bat +++ b/build.bat @@ -107,16 +107,6 @@ set libs= ^ set odin_res=misc\odin.res set odin_rc=misc\odin.rc -rem DO NOT TOUCH! -rem THIS TILDE STUFF IS FOR DEVELOPMENT ONLY! -set tilde_backend=0 -if %tilde_backend% EQU 1 ( - set libs=%libs% src\tilde\tb.lib - set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND -) -rem DO NOT TOUCH! - - set linker_flags= -incremental:no -opt:ref -subsystem:console -MANIFEST:EMBED if %release_mode% EQU 0 ( rem Debug diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 9663d5db5..41849fd6b 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -607,8 +607,6 @@ struct BuildContext { isize max_error_count; - bool tilde_backend; - u32 cmd_doc_flags; Array extra_packages; diff --git a/src/checker.cpp b/src/checker.cpp index ce8042b41..0d82ec9f9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1295,7 +1295,6 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_NO_RTTI", bc->no_rtti); add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT); - add_global_bool_constant("ODIN_TILDE", bc->tilde_backend); add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp())); @@ -3009,7 +3008,7 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("aeabi_d2h") ); - FORCE_ADD_RUNTIME_ENTITIES(is_arch_wasm() && !build_context.tilde_backend, + FORCE_ADD_RUNTIME_ENTITIES(is_arch_wasm(), // // Extended data type internal procedures // str_lit("umodti3"), // str_lit("udivti3"), diff --git a/src/entity.cpp b/src/entity.cpp index 5062599de..7bb6e88ca 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -184,14 +184,8 @@ struct Entity { Entity * aliased_of; - union { - std::atomic code_gen_module; - struct cgModule *cg_module; - }; - union { - std::atomic code_gen_procedure; - struct cgProcedure *cg_procedure; - }; + std::atomic code_gen_module; + std::atomic code_gen_procedure; u64 order_in_src; String deprecated_message; diff --git a/src/main.cpp b/src/main.cpp index 4d68d3d73..a79ac77a5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,16 +76,6 @@ gb_global Timings global_timings = {0}; #include "linker.cpp" #include "bundle_command.cpp" -#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND) -#define ALLOW_TILDE 1 -#else -#define ALLOW_TILDE 0 -#endif - -#if ALLOW_TILDE -#include "tilde.cpp" -#endif - #include "llvm_backend.cpp" #include "bug_report.cpp" @@ -414,8 +404,6 @@ enum BuildFlagKind { BuildFlag_InternalLLVMMem2Reg, BuildFlag_InternalEnableRVO, - BuildFlag_Tilde, - BuildFlag_Sanitize, BuildFlag_LTO, @@ -647,9 +635,6 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalLLVMMem2Reg, str_lit("internal-llvm-mem2reg"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalEnableRVO, str_lit("internal-enable-rvo"), BuildFlagParam_None, Command_all); -#if ALLOW_TILDE - add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); -#endif add_flag(&build_flags, BuildFlag_Sanitize, str_lit("sanitize"), BuildFlagParam_String, Command__does_build, true); add_flag(&build_flags, BuildFlag_LTO, str_lit("lto"), BuildFlagParam_String, Command__does_build); @@ -1646,11 +1631,6 @@ gb_internal bool parse_build_flags(Array args) { break; - - case BuildFlag_Tilde: - build_context.tilde_backend = true; - break; - case BuildFlag_Sanitize: GB_ASSERT(value.kind == ExactValue_String); @@ -4120,36 +4100,6 @@ int main(int arg_count, char const **arg_ptr) { failed_to_cache_parsing = true; } -#if ALLOW_TILDE - if (build_context.tilde_backend) { - LinkerData linker_data = {}; - MAIN_TIME_SECTION("Tilde Code Gen"); - if (!cg_generate_code(checker, &linker_data)) { - return 1; - } - - switch (build_context.build_mode) { - case BuildMode_Executable: - case BuildMode_StaticLibrary: - case BuildMode_DynamicLibrary: - i32 result = linker_stage(&linker_data); - if (result) { - if (build_context.show_timings) { - show_timings(checker, &global_timings); - } - if (build_context.show_import_graph) { - show_import_graph(checker); - } - - if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(checker); - } - return result; - } - break; - } - } else -#endif { lbGenerator *gen = permanent_alloc_item(); if (!lb_init_generator(gen, checker)) { diff --git a/src/tilde.cpp b/src/tilde.cpp deleted file mode 100644 index f6fed0f9a..000000000 --- a/src/tilde.cpp +++ /dev/null @@ -1,842 +0,0 @@ -#include "tilde.hpp" - - -gb_global Slice global_tb_arenas; - -gb_internal TB_Arena *cg_arena(void) { - return &global_tb_arenas[current_thread_index()]; -} - -gb_internal void cg_global_arena_init(void) { - global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); - for_array(i, global_tb_arenas) { - tb_arena_create(&global_tb_arenas[i], 2ull<<20); - } -} - -// 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; - } - break; - - 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_lvalue_addr_to_value(cgValue v) { - if (v.kind == cgValue_Value) { - GB_ASSERT(is_type_pointer(v.type)); - GB_ASSERT(v.node->dt.type == TB_PTR); - } else { - GB_ASSERT(v.kind == cgValue_Addr); - GB_ASSERT(v.node->dt.type == TB_PTR); - v.kind = cgValue_Value; - v.type = alloc_type_pointer(v.type); - } - 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 cgValue cg_value_multi(Slice const &values, Type *type) { - cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti); - multi->values = values; - return cg_value_multi(multi, type); -} - - -gb_internal cgValue cg_value_multi2(cgValue const &x, cgValue const &y, Type *type) { - GB_ASSERT(type->kind == Type_Tuple); - GB_ASSERT(type->Tuple.variables.count == 2); - cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti); - multi->values = slice_make(permanent_allocator(), 2); - multi->values[0] = x; - multi->values[1] = y; - return cg_value_multi(multi, type); -} - - -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 cgAddr cg_addr_map(cgValue addr, cgValue map_key, Type *map_type, Type *map_result) { - GB_ASSERT(is_type_pointer(addr.type)); - Type *mt = type_deref(addr.type); - GB_ASSERT(is_type_map(mt)); - - cgAddr v = {cgAddr_Map, addr}; - v.map.key = map_key; - v.map.type = map_type; - v.map.result = map_result; - return v; -} - -gb_internal cgAddr cg_addr_soa_variable(cgValue addr, cgValue index, Ast *index_expr) { - cgAddr v = {cgAddr_SoaVariable, addr}; - v.soa.index = index; - v.soa.index_expr = index_expr; - return v; -} - - - -gb_internal void cg_set_debug_pos_from_node(cgProcedure *p, Ast *node) { - if (node) { - TokenPos pos = ast_token(node).pos; - TB_SourceFile **file = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id); - if (file) { - tb_inst_location(p->func, *file, pos.line, pos.column); - } - } -} - -gb_internal void cg_add_symbol(cgModule *m, Entity *e, TB_Symbol *symbol) { - if (e) { - rw_mutex_lock(&m->values_mutex); - map_set(&m->symbols, e, symbol); - rw_mutex_unlock(&m->values_mutex); - } -} - -gb_internal void cg_add_entity(cgModule *m, Entity *e, cgValue const &val) { - if (e) { - rw_mutex_lock(&m->values_mutex); - GB_ASSERT(val.node != nullptr); - 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); - if (p->symbol != nullptr) { - map_set(&m->symbols, p->entity, p->symbol); - } - } - string_map_set(&m->procedures, p->name, p); - rw_mutex_unlock(&m->values_mutex); - -} - -gb_internal TB_Symbol *cg_find_symbol_from_entity(cgModule *m, Entity *e) { - GB_ASSERT(e != nullptr); - - rw_mutex_lock(&m->values_mutex); - TB_Symbol **found = map_get(&m->symbols, e); - if (found) { - rw_mutex_unlock(&m->values_mutex); - return *found; - } - - String link_name = cg_get_entity_name(m, e); - cgProcedure **proc_found = string_map_get(&m->procedures, link_name); - if (proc_found) { - TB_Symbol *symbol = (*proc_found)->symbol; - map_set(&m->symbols, e, symbol); - rw_mutex_unlock(&m->values_mutex); - return symbol; - } - rw_mutex_unlock(&m->values_mutex); - - if (e->kind == Entity_Procedure) { - debugf("[Tilde] try to generate procedure %.*s as it was not in the minimum_dependency_set", LIT(e->token.string)); - // IMPORTANT TODO(bill): This is an utter bodge, try and fix this shit - cgProcedure *p = cg_procedure_create(m, e); - if (p != nullptr) { - GB_ASSERT(p->symbol != nullptr); - cg_add_procedure_to_queue(p); - return p->symbol; - } - } - - - GB_PANIC("could not find entity's symbol %.*s", LIT(e->token.string)); - return nullptr; -} - - -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, Array *global_variables) { - 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; - } - } - } - } - } - *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); - } 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_ModuleSectionHandle 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)); - } - - - cgGlobalVariable var = {}; - var.var = g; - var.decl = decl; - - if (decl->init_expr != nullptr) { - TypeAndValue tav = type_and_value_of_expr(decl->init_expr); - - isize max_regions = cg_global_const_calculate_region_count(tav.value, e->type); - tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_regions); - - if (tav.mode == Addressing_Constant && - tav.value.kind != ExactValue_Invalid) { - cg_global_const_add_region(m, tav.value, e->type, global, 0); - var.is_initialized = true; - } - if (!var.is_initialized && is_type_untyped_nil(tav.type)) { - var.is_initialized = true; - } - } else { - var.is_initialized = true; - // TODO(bill): is this even needed; - i64 max_regions = cg_global_const_calculate_region_count_from_basic_type(e->type); - tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_regions); - } - - array_add(global_variables, var); - - cg_add_symbol(m, e, cast(TB_Symbol *)global); - cg_add_entity(m, e, g); - cg_add_member(m, name, g); - } - - cg_setup_type_info_data(m); - - return already_has_entry_point; -} - -gb_internal void cg_global_variables_initialize(cgProcedure *p, Array *global_variables) { - for (cgGlobalVariable &var : *global_variables) { - if (var.is_initialized) { - continue; - } - cgValue src = cg_build_expr(p, var.decl->init_expr); - cgValue dst = cg_flatten_value(p, var.var); - cg_emit_store(p, dst, src); - } -} - - -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); - map_init(&m->symbols); - 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); - map_init(&m->anonymous_proc_lits_map); - map_init(&m->equal_procs); - map_init(&m->hasher_procs); - map_init(&m->map_get_procs); - map_init(&m->map_set_procs); - map_init(&m->map_info_map); - map_init(&m->map_cell_info_map); - - array_init(&m->single_threaded_procedure_queue, heap_allocator()); - - - for_array(id, global_files) { - if (AstFile *f = global_files[id]) { - char const *path = alloc_cstring(temporary_allocator(), f->fullpath); - TB_SourceFile *file = tb_get_source_file(m->mod, path); - map_set(&m->file_id_map, cast(uintptr)id, file); - } - } - - return m; -} - -gb_internal void cg_module_destroy(cgModule *m) { - map_destroy(&m->values); - map_destroy(&m->symbols); - 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); - map_destroy(&m->anonymous_proc_lits_map); - map_destroy(&m->equal_procs); - map_destroy(&m->hasher_procs); - map_destroy(&m->map_get_procs); - map_destroy(&m->map_set_procs); - map_destroy(&m->map_info_map); - map_destroy(&m->map_cell_info_map); - - array_free(&m->single_threaded_procedure_queue); - - 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_builtin.cpp" -#include "tilde_type_info.cpp" -#include "tilde_proc.cpp" -#include "tilde_stmt.cpp" - - -gb_internal String cg_filepath_obj_for_module(cgModule *m, bool use_assembly) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - - // if (m->file) { - // char buf[32] = {}; - // isize n = gb_snprintf(buf, gb_size_of(buf), "-%u", m->file->id); - // String suffix = make_string((u8 *)buf, n-1); - // path = concatenate_strings(permanent_allocator(), path, suffix); - // } else if (m->pkg) { - // path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); - // } - - String ext = {}; - - if (use_assembly) { - ext = STR_LIT(".S"); - } else { - if (is_arch_wasm()) { - ext = STR_LIT(".wasm.o"); - } else { - switch (build_context.metrics.os) { - case TargetOs_windows: - ext = STR_LIT(".obj"); - break; - default: - case TargetOs_darwin: - case TargetOs_linux: - case TargetOs_essence: - ext = STR_LIT(".o"); - break; - - case TargetOs_freestanding: - switch (build_context.metrics.abi) { - default: - case TargetABI_Default: - case TargetABI_SysV: - ext = STR_LIT(".o"); - break; - case TargetABI_Win64: - ext = STR_LIT(".obj"); - break; - } - break; - } - } - } - - return concatenate_strings(permanent_allocator(), path, ext); -} - - -gb_internal WORKER_TASK_PROC(cg_procedure_generate_worker_proc) { - cgProcedure *p = cast(cgProcedure *)data; - cg_procedure_generate(p); - return 0; -} - -gb_internal void cg_add_procedure_to_queue(cgProcedure *p) { - if (p == nullptr) { - return; - } - cgModule *m = p->module; - if (m->do_threading) { - thread_pool_add_task(cg_procedure_generate_worker_proc, p); - } else { - array_add(&m->single_threaded_procedure_queue, p); - } -} - -gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { - TIME_SECTION("Tilde Module Initializtion"); - - CheckerInfo *info = &c->info; - - linker_data_init(linker_data, info, c->parser->init_fullpath); - - #if defined(GB_SYSTEM_OSX) - linker_enable_system_library_linking(linker_data); - #endif - - cg_global_arena_init(); - - cgModule *m = cg_module_create(c); - defer (cg_module_destroy(m)); - - m->do_threading = false; - - TIME_SECTION("Tilde Global Variables"); - - Array global_variables = {}; - bool already_has_entry_point = cg_global_variables_create(m, &global_variables); - 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_startup_runtime_proc = 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_cleanup_runtime_proc = p; - } - - auto *min_dep_set = &info->minimum_dependency_set; - - Array procedures_to_generate = {}; - array_init(&procedures_to_generate, heap_allocator()); - defer (array_free(&procedures_to_generate)); - - 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(&procedures_to_generate, p); - } - } - for (cgProcedure *p : procedures_to_generate) { - cg_add_procedure_to_queue(p); - } - - if (!m->do_threading) { - for (isize i = 0; i < m->single_threaded_procedure_queue.count; i++) { - cgProcedure *p = m->single_threaded_procedure_queue[i]; - cg_procedure_generate(p); - } - } - - thread_pool_wait(); - - { - cgProcedure *p = cg_startup_runtime_proc; - cg_procedure_begin(p); - cg_global_variables_initialize(p, &global_variables); - tb_inst_ret(p->func, 0, nullptr); - cg_procedure_end(p); - } - { - cgProcedure *p = cg_cleanup_runtime_proc; - cg_procedure_begin(p); - tb_inst_ret(p->func, 0, nullptr); - cg_procedure_end(p); - } - - - 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: - case TargetOs_haiku: - 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)); - - String filepath_obj = cg_filepath_obj_for_module(m, false); - array_add(&linker_data->output_object_paths, filepath_obj); - GB_ASSERT(tb_export_buffer_to_file(export_buffer, cast(char const *)filepath_obj.text)); - - return true; -} - -#undef ABI_PKG_NAME_SEPARATOR diff --git a/src/tilde.hpp b/src/tilde.hpp deleted file mode 100644 index d141b2330..000000000 --- a/src/tilde.hpp +++ /dev/null @@ -1,386 +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" -#include "tilde/tb_arena.h" - -#define TB_TYPE_F16 TB_DataType{ { TB_INT, 16 } } -#define TB_TYPE_I128 TB_DataType{ { TB_INT, 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" -#define CG_TYPE_INFO_ENUM_VALUES_NAME "__$type_info_enum_values_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 { - // NOTE: any value in this union must be a pointer - 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; - - 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; - isize split_returns_index; - bool return_by_ptr; - - PtrMap variable_map; - PtrMap soa_values_map; -}; - - -struct cgModule { - TB_Module * mod; - Checker * checker; - CheckerInfo *info; - LinkerData * linker_data; - - bool do_threading; - Array single_threaded_procedure_queue; - - RwMutex values_mutex; - PtrMap values; - PtrMap symbols; - StringMap members; - StringMap procedures; - PtrMap procedure_values; - - RecursiveMutex debug_type_mutex; - PtrMap debug_type_map; - PtrMap proc_debug_type_map; // not pointer to - - RecursiveMutex proc_proto_mutex; - PtrMap proc_proto_map; - - BlockingMutex anonymous_proc_lits_mutex; - PtrMap anonymous_proc_lits_map; - - RecursiveMutex generated_procs_mutex; - PtrMap equal_procs; - PtrMap hasher_procs; - PtrMap map_get_procs; - PtrMap map_set_procs; - - RecursiveMutex map_info_mutex; - PtrMap map_info_map; - PtrMap map_cell_info_map; - - // NOTE(bill): no need to protect this with a mutex - 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 - -struct GlobalTypeInfoData { - TB_Global *global; - Type * array_type; - Type * elem_type; - isize index; -}; - -gb_global Entity *cg_global_type_info_data_entity = {}; -gb_global GlobalTypeInfoData cg_global_type_info_member_types = {}; -gb_global GlobalTypeInfoData cg_global_type_info_member_names = {}; -gb_global GlobalTypeInfoData cg_global_type_info_member_offsets = {}; -gb_global GlobalTypeInfoData cg_global_type_info_member_usings = {}; -gb_global GlobalTypeInfoData cg_global_type_info_member_tags = {}; -gb_global GlobalTypeInfoData cg_global_type_info_member_enum_values = {}; - -gb_global cgProcedure *cg_startup_runtime_proc = nullptr; -gb_global cgProcedure *cg_cleanup_runtime_proc = nullptr; - - - -gb_internal TB_Arena *cg_arena(void); - -gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false); -gb_internal void cg_add_procedure_to_queue(cgProcedure *p); -gb_internal void cg_setup_type_info_data(cgModule *m); -gb_internal cgProcedure *cg_procedure_generate_anonymous(cgModule *m, Ast *expr, cgProcedure *parent); - -gb_internal isize cg_global_const_calculate_region_count(ExactValue const &value, Type *type); -gb_internal i64 cg_global_const_calculate_region_count_from_basic_type(Type *type); -gb_internal bool cg_global_const_add_region(cgModule *m, ExactValue const &value, Type *type, TB_Global *global, i64 offset); - -gb_internal String cg_get_entity_name(cgModule *m, Entity *e); - -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 cgAddr cg_addr_map(cgValue addr, cgValue map_key, Type *map_type, Type *map_result); - -gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type); -gb_internal cgValue cg_type_info(cgProcedure *p, Type *type); -gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true); - -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 cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr); -gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block, TB_Node *false_block); - -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 src, bool is_volatile=false); - -gb_internal cgAddr cg_add_local (cgProcedure *p, Type *type, Entity *e, bool zero_init); -gb_internal cgAddr cg_add_global(cgProcedure *p, Type *type, Entity *e); -gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); -gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment); - -gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); - -gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results); -gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results); -gb_internal void cg_build_return_stmt_internal_single(cgProcedure *p, cgValue result); -gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node); - -gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e); -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_struct_ev(cgProcedure *p, cgValue s, i64 index); - -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 cgValue cg_emit_unary_arith(cgProcedure *p, TokenKind op, cgValue x, Type *type); -gb_internal void cg_emit_increment(cgProcedure *p, cgValue addr); - -gb_internal cgProcedure *cg_equal_proc_for_type (cgModule *m, Type *type); -gb_internal cgProcedure *cg_hasher_proc_for_type(cgModule *m, Type *type); -gb_internal cgValue cg_hasher_proc_value_for_type(cgProcedure *p, Type *type); -gb_internal cgValue cg_equal_proc_value_for_type(cgProcedure *p, Type *type); - -gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice const &args); -gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice const &args); - -gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); - -gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); - -gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_values, cgValue src_value); - -gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); - -gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value); -gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x); -gb_internal cgValue cg_builtin_map_info(cgProcedure *p, Type *map_type); -gb_internal cgValue cg_builtin_map_cell_info(cgProcedure *p, Type *type); -gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos); -gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Ast *node); - - -gb_internal cgValue cg_internal_dynamic_map_get_ptr(cgProcedure *p, cgValue const &map_ptr, cgValue const &key); -gb_internal void cg_internal_dynamic_map_set(cgProcedure *p, cgValue const &map_ptr, Type *map_type, - cgValue const &map_key, cgValue const &map_value, Ast *node); \ No newline at end of file diff --git a/src/tilde/tb.h b/src/tilde/tb.h deleted file mode 100644 index 4fe21c902..000000000 --- a/src/tilde/tb.h +++ /dev/null @@ -1,1309 +0,0 @@ -// Glossary (because i don't know where else to put it) -// IR - intermediate representation -// SoN - sea of nodes (https://www.oracle.com/technetwork/java/javase/tech/c2-ir95-150110.pdf) -// SSA - single static assignment -// GVN - global value numbering -// CSE - common subexpression elimination -// CFG - control flow graph -// DSE - dead store elimination -// GCM - global code motion -// SROA - scalar replacement of aggregates -// SCCP - sparse conditional constant propagation -// RPO - reverse postorder -// BB - basic block -// ZTC - zero trip count -// SCC - strongly connected components -#ifndef TB_CORE_H -#define TB_CORE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -// https://semver.org/ -#define TB_VERSION_MAJOR 0 -#define TB_VERSION_MINOR 3 -#define TB_VERSION_PATCH 0 - -#ifndef TB_API -# ifdef __cplusplus -# define TB_EXTERN extern "C" -# else -# define TB_EXTERN -# endif -# ifdef TB_DLL -# ifdef TB_IMPORT_DLL -# define TB_API TB_EXTERN __declspec(dllimport) -# else -# define TB_API TB_EXTERN __declspec(dllexport) -# endif -# else -# define TB_API TB_EXTERN -# endif -#endif - -// These are flags -typedef enum TB_ArithmeticBehavior { - TB_ARITHMATIC_NONE = 0, - TB_ARITHMATIC_NSW = 1, - TB_ARITHMATIC_NUW = 2, -} TB_ArithmeticBehavior; - -typedef enum TB_DebugFormat { - TB_DEBUGFMT_NONE, - - TB_DEBUGFMT_DWARF, - TB_DEBUGFMT_CODEVIEW, - - TB_DEBUGFMT_COLINPILLED -} TB_DebugFormat; - -typedef enum TB_Arch { - TB_ARCH_UNKNOWN, - - TB_ARCH_X86_64, - TB_ARCH_AARCH64, // unsupported but planned - TB_ARCH_WASM32, -} TB_Arch; - -typedef enum TB_System { - TB_SYSTEM_WINDOWS, - TB_SYSTEM_LINUX, - TB_SYSTEM_MACOS, - TB_SYSTEM_ANDROID, // Not supported yet - TB_SYSTEM_WEB, - - TB_SYSTEM_MAX, -} TB_System; - -typedef enum TB_WindowsSubsystem { - TB_WIN_SUBSYSTEM_UNKNOWN, - - TB_WIN_SUBSYSTEM_WINDOWS, - TB_WIN_SUBSYSTEM_CONSOLE, - TB_WIN_SUBSYSTEM_EFI_APP, -} TB_WindowsSubsystem; - -typedef enum TB_ABI { - // Used on 64bit Windows platforms - TB_ABI_WIN64, - - // Used on Mac, BSD and Linux platforms - TB_ABI_SYSTEMV, -} TB_ABI; - -typedef enum TB_OutputFlavor { - TB_FLAVOR_OBJECT, // .o .obj - TB_FLAVOR_SHARED, // .so .dll - TB_FLAVOR_STATIC, // .a .lib - TB_FLAVOR_EXECUTABLE, // .exe -} TB_OutputFlavor; - -typedef enum TB_CallingConv { - TB_CDECL, - TB_STDCALL -} TB_CallingConv; - -typedef enum TB_FeatureSet_X64 { - TB_FEATURE_X64_SSE3 = (1u << 0u), - TB_FEATURE_X64_SSE41 = (1u << 1u), - TB_FEATURE_X64_SSE42 = (1u << 2u), - - TB_FEATURE_X64_POPCNT = (1u << 3u), - TB_FEATURE_X64_LZCNT = (1u << 4u), - - TB_FEATURE_X64_CLMUL = (1u << 5u), - TB_FEATURE_X64_F16C = (1u << 6u), - - TB_FEATURE_X64_BMI1 = (1u << 7u), - TB_FEATURE_X64_BMI2 = (1u << 8u), - - TB_FEATURE_X64_AVX = (1u << 9u), - TB_FEATURE_X64_AVX2 = (1u << 10u), -} TB_FeatureSet_X64; - -typedef struct TB_FeatureSet { - TB_FeatureSet_X64 x64; -} TB_FeatureSet; - -typedef enum TB_Linkage { - TB_LINKAGE_PUBLIC, - TB_LINKAGE_PRIVATE -} TB_Linkage; - -typedef enum { - TB_COMDAT_NONE, - - TB_COMDAT_MATCH_ANY, -} TB_ComdatType; - -typedef enum TB_MemoryOrder { - TB_MEM_ORDER_RELAXED, - TB_MEM_ORDER_CONSUME, - TB_MEM_ORDER_ACQUIRE, - TB_MEM_ORDER_RELEASE, - TB_MEM_ORDER_ACQ_REL, - TB_MEM_ORDER_SEQ_CST, -} TB_MemoryOrder; - -typedef enum TB_DataTypeEnum { - // Integers, note void is an i0 and bool is an i1 - // i(0-64) - TB_INT, - // Floating point numbers - // f{32,64} - TB_FLOAT, - // Pointers - TB_PTR, - // represents control flow for REGION, BRANCH - TB_CONTROL, - // represents memory (and I/O) - TB_MEMORY, - // continuation (usually just return addresses :p) - TB_CONT, - // Tuples, these cannot be used in memory ops, just accessed via projections - TB_TUPLE, -} TB_DataTypeEnum; - -typedef enum TB_FloatFormat { - // IEEE 754 floats - TB_FLT_32, TB_FLT_64 -} TB_FloatFormat; - -typedef union TB_DataType { - struct { - uint16_t type : 4; - // for integers it's the bitwidth - uint16_t data : 12; - }; - uint16_t raw; -} TB_DataType; -static_assert(sizeof(TB_DataType) == 2, "im expecting this to be a uint16_t"); - -// classify data types -#define TB_IS_VOID_TYPE(x) ((x).type == TB_INT && (x).data == 0) -#define TB_IS_BOOL_TYPE(x) ((x).type == TB_INT && (x).data == 1) -#define TB_IS_INTEGER_TYPE(x) ((x).type == TB_INT) -#define TB_IS_FLOAT_TYPE(x) ((x).type == TB_FLOAT) -#define TB_IS_POINTER_TYPE(x) ((x).type == TB_PTR) - -// accessors -#define TB_GET_INT_BITWIDTH(x) ((x).data) -#define TB_GET_FLOAT_FORMAT(x) ((x).data) -#define TB_GET_PTR_ADDRSPACE(x) ((x).data) - -//////////////////////////////// -// ANNOTATIONS -//////////////////////////////// -// -// (A, B) -> (C, D) -// -// node takes A and B, produces C, D. if there's multiple -// results we need to use projections and the indices are -// based on the order seen here, proj0 is C, proj1 is D. -// -// (A, B) & C -> Int -// -// nodes takes A and B along with C in it's extra data. this is -// where non-node inputs fit. -// -typedef enum TB_NodeTypeEnum { - TB_NULL = 0, - - //////////////////////////////// - // CONSTANTS - //////////////////////////////// - TB_INTEGER_CONST, - TB_FLOAT32_CONST, - TB_FLOAT64_CONST, - - //////////////////////////////// - // MISCELLANEOUS - //////////////////////////////// - // this is an unspecified value, usually generated by the optimizer - // when malformed input is folded into an operation. - TB_POISON, // () -> Any - // projections just extract a single field of a tuple - TB_PROJ, // Tuple & Int -> Any - // this is a simple way to embed machine code into the code - TB_MACHINE_OP, // (Control, Memory) & Buffer -> (Control, Memory) - // reads the TSC on x64 - TB_CYCLE_COUNTER, // (Control) -> Int64 - // prefetches data for reading. The number next to the - // - // 0 is temporal - // 1-3 are just cache levels - TB_PREFETCH, // (Memory, Ptr) & Int -> Memory - - //////////////////////////////// - // CONTROL - //////////////////////////////// - // there's only one START and STOP per function - TB_START, // () -> (Control, Memory, Data...) - TB_END, // (Control, Memory, Data?) -> () - // regions are used to represent paths which have multiple entries. - // each input is a predecessor. - TB_REGION, // (Control...) -> (Control) - // phi nodes work the same as in SSA CFG, the value is based on which predecessor was taken. - // each input lines up with the regions such that region.in[i] will use phi.in[i+1] as the - // subsequent data. - TB_PHI, // (Control, Data...) -> Data - // branch is used to implement most control flow, it acts like a switch - // statement in C usually. they take a key and match against some cases, - // if they match, it'll jump to that successor, if none match it'll take - // the default successor. - // - // if (cond) { A; } else { B; } is just switch (cond) { case 0: B; default: A; } - // - // it's possible to not pass a key and the default successor is always called, this is - // a GOTO. tb_inst_goto, tb_inst_if can handle common cases for you. - TB_BRANCH, // (Control, Data?) -> (Control...) - // debugbreak will trap in a continuable manner. - TB_DEBUGBREAK, // (Control, Memory) -> (Control) - // trap will not be continuable but will stop execution. - TB_TRAP, // (Control) -> (Control) - // unreachable means it won't trap or be continuable. - TB_UNREACHABLE, // (Control) -> () - // this is generated when a path becomes disconnected - // from the main IR, it'll be reduced by the monotonic - // rewrites. - TB_DEAD, // () -> (Control) - - //////////////////////////////// - // CONTROL + MEMORY - //////////////////////////////// - // nothing special, it's just a function call, 3rd argument here is the - // target pointer (or syscall number) and the rest are just data args. - TB_CALL, // (Control, Memory, Data, Data...) -> (Control, Memory, Data) - TB_SYSCALL, // (Control, Memory, Data, Data...) -> (Control, Memory, Data) - // performs call while recycling the stack frame somewhat - TB_TAILCALL, // (Control, Memory, RPC, Data, Data...) -> () - // safepoint polls are the same except they only trigger if the poll site - // says to (platform specific but almost always just the page being made - // unmapped/guard), 3rd argument is the poll site. - TB_SAFEPOINT_POLL, // (Control, Memory, Ptr?, Data...) -> (Control) - // this safepoint which doesn't emit any poll site, it's just - // an address, this is used by AOT compiles to encode line info. - TB_SAFEPOINT_NOP, // (Control, Memory, Ptr?, Data...) -> (Control) - - //////////////////////////////// - // MEMORY - //////////////////////////////// - // MERGEMEM will join multiple non-aliasing memory effects, because - // they don't alias there's no ordering guarentee. - TB_MERGEMEM, // (Memory...) -> Memory - // LOAD and STORE are standard memory accesses, they can be folded away. - TB_LOAD, // (Control?, Memory, Ptr) -> Data - TB_STORE, // (Control, Memory, Ptr, Data) -> Memory - // bulk memory ops. - TB_MEMCPY, // (Control, Memory, Ptr, Ptr, Size) -> Memory - TB_MEMSET, // (Control, Memory, Ptr, Int8, Size) -> Memory - // these memory accesses represent "volatile" which means - // they may produce side effects and thus cannot be eliminated. - TB_READ, // (Control, Memory, Ptr) -> (Memory, Data) - TB_WRITE, // (Control, Memory, Ptr, Data) -> (Memory, Data) - // atomics have multiple observers (if not they wouldn't need to - // be atomic) and thus produce side effects everywhere just like - // volatiles except they have synchronization guarentees. the atomic - // data ops will return the value before the operation is performed. - // Atomic CAS return the old value and a boolean for success (true if - // the value was changed) - TB_ATOMIC_LOAD, // (Control, Memory, Ptr) -> (Memory, Data) - TB_ATOMIC_XCHG, // (Control, Memory, Ptr, Data) -> (Memory, Data) - TB_ATOMIC_ADD, // (Control, Memory, Ptr, Data) -> (Memory, Data) - TB_ATOMIC_SUB, // (Control, Memory, Ptr, Data) -> (Memory, Data) - TB_ATOMIC_AND, // (Control, Memory, Ptr, Data) -> (Memory, Data) - TB_ATOMIC_XOR, // (Control, Memory, Ptr, Data) -> (Memory, Data) - TB_ATOMIC_OR, // (Control, Memory, Ptr, Data) -> (Memory, Data) - TB_ATOMIC_CAS, // (Control, Memory, Data, Data) -> (Memory, Data, Bool) - - // like a multi-way branch but without the control flow aspect, but for data. - TB_LOOKUP, - - //////////////////////////////// - // POINTERS - //////////////////////////////// - // LOCAL will statically allocate stack space - TB_LOCAL, // () & (Int, Int) -> Ptr - // SYMBOL will return a pointer to a TB_Symbol - TB_SYMBOL, // () & TB_Symbol* -> Ptr - // offsets pointer by constant value - TB_MEMBER_ACCESS, // Ptr & Int -> Ptr - // arguments represent base, index, and stride respectively - // and will perform `base + index*stride` - TB_ARRAY_ACCESS, // (Ptr, Int) & Int -> Ptr - // converts an integer to a pointer - TB_INT2PTR, // Int -> Ptr - // converts a pointer to an integer - TB_PTR2INT, // Ptr -> Int - - // Conversions - TB_TRUNCATE, - TB_FLOAT_EXT, - TB_SIGN_EXT, - TB_ZERO_EXT, - TB_UINT2FLOAT, - TB_FLOAT2UINT, - TB_INT2FLOAT, - TB_FLOAT2INT, - TB_BITCAST, - - // Select - TB_SELECT, - - // Bitmagic - TB_BSWAP, - TB_CLZ, - TB_CTZ, - TB_POPCNT, - - // Unary operations - TB_NOT, - TB_NEG, - - // Integer arithmatic - TB_AND, - TB_OR, - TB_XOR, - TB_ADD, - TB_SUB, - TB_MUL, - - TB_SHL, - TB_SHR, - TB_SAR, - TB_ROL, - TB_ROR, - TB_UDIV, - TB_SDIV, - TB_UMOD, - TB_SMOD, - - // Float arithmatic - TB_FADD, - TB_FSUB, - TB_FMUL, - TB_FDIV, - TB_FMAX, - TB_FMIN, - - // Comparisons - TB_CMP_EQ, - TB_CMP_NE, - TB_CMP_ULT, - TB_CMP_ULE, - TB_CMP_SLT, - TB_CMP_SLE, - TB_CMP_FLT, - TB_CMP_FLE, - - // Special ops - // adds two paired integers to two other paired integers and returns - // a low and high value - TB_ADDPAIR, - // does full multiplication (64x64=128 and so on) returning - // the low and high values in separate projections - TB_MULPAIR, - - // variadic - TB_VA_START, - - // x86 intrinsics - TB_X86INTRIN_LDMXCSR, - TB_X86INTRIN_STMXCSR, - TB_X86INTRIN_SQRT, - TB_X86INTRIN_RSQRT, -} TB_NodeTypeEnum; -typedef uint8_t TB_NodeType; - -// just represents some region of bytes, usually in file parsing crap -typedef struct { - size_t length; - const uint8_t* data; -} TB_Slice; - -// represents byte counts -typedef uint32_t TB_CharUnits; - -// will get interned so each TB_Module has a unique identifier for the source file -typedef struct { - // used by the debug info export - int id; - - size_t len; - uint8_t path[]; -} TB_SourceFile; - -typedef struct TB_Location { - TB_SourceFile* file; - int line, column; - uint32_t pos; -} TB_Location; - -// SO refers to shared objects which mean either shared libraries (.so or .dll) -// or executables (.exe or ELF executables) -typedef enum { - // exports to the rest of the shared object - TB_EXTERNAL_SO_LOCAL, - - // exports outside of the shared object - TB_EXTERNAL_SO_EXPORT, -} TB_ExternalType; - -typedef struct TB_Global TB_Global; -typedef struct TB_External TB_External; -typedef struct TB_Function TB_Function; - -typedef struct TB_Module TB_Module; -typedef struct TB_DebugType TB_DebugType; -typedef struct TB_ModuleSection TB_ModuleSection; -typedef struct TB_FunctionPrototype TB_FunctionPrototype; - -enum { TB_MODULE_SECTION_NONE = -1 }; -typedef int32_t TB_ModuleSectionHandle; -typedef struct TB_Attrib TB_Attrib; - -// target-specific, just a unique ID for the registers -typedef int TB_PhysicalReg; - -// Thread local module state -typedef struct TB_ThreadInfo TB_ThreadInfo; - -typedef enum { - TB_SYMBOL_NONE, - TB_SYMBOL_EXTERNAL, - TB_SYMBOL_GLOBAL, - TB_SYMBOL_FUNCTION, - TB_SYMBOL_MAX, -} TB_SymbolTag; - -// Refers generically to objects within a module -// -// TB_Function, TB_Global, and TB_External are all subtypes of TB_Symbol -// and thus are safely allowed to cast into a symbol for operations. -typedef struct TB_Symbol { - #ifdef __cplusplus - TB_SymbolTag tag; - #else - _Atomic TB_SymbolTag tag; - #endif - - // which thread info it's tied to (we may need to remove it, this - // is used for that) - TB_ThreadInfo* info; - char* name; - - // It's kinda a weird circular reference but yea - TB_Module* module; - - // helpful for sorting and getting consistent builds - uint64_t ordinal; - - union { - // if we're JITing then this maps to the address of the symbol - void* address; - size_t symbol_id; - }; - - // after this point it's tag-specific storage -} TB_Symbol; - -typedef struct TB_Node TB_Node; -typedef struct User User; -struct User { - User* next; - TB_Node* n; - int slot; -}; - -struct TB_Node { - TB_NodeType type; - uint16_t input_count; - TB_DataType dt; - - // makes it easier to track in graph walks - uint32_t gvn; - - // only value while inside of a TB_Passes, - // these are unordered and usually just - // help perform certain transformations or - // analysis (not necessarily semantics) - User* users; - - // ordered def-use edges, jolly ol' semantics - TB_Node** inputs; - - char extra[]; -}; - -// These are the extra data in specific nodes -#define TB_NODE_GET_EXTRA(n) ((void*) n->extra) -#define TB_NODE_GET_EXTRA_T(n, T) ((T*) (n)->extra) -#define TB_NODE_SET_EXTRA(n, T, ...) (*((T*) (n)->extra) = (T){ __VA_ARGS__ }) - -// this represents switch (many targets), if (one target) and goto (only default) logic. -typedef struct { // TB_BRANCH - size_t succ_count; - int64_t keys[]; -} TB_NodeBranch; - -typedef struct { // TB_PROJ - int index; -} TB_NodeProj; - -typedef struct { // TB_INTEGER_CONST - uint64_t value; -} TB_NodeInt; - -typedef struct { // any compare operator - TB_DataType cmp_dt; -} TB_NodeCompare; - -typedef struct { // any integer binary operator - TB_ArithmeticBehavior ab; -} TB_NodeBinopInt; - -typedef struct { - TB_CharUnits align; -} TB_NodeMemAccess; - -typedef struct { - int level; -} TB_NodePrefetch; - -typedef struct { - TB_CharUnits size, align; - int alias_index; // 0 if local is used beyond direct memops, 1...n as a unique alias name -} TB_NodeLocal; - -typedef struct { - // this is the raw buffer - size_t length; - const uint8_t* data; - - // represents the outputs, inputs and temporaries in that order - size_t outs, ins, tmps; - TB_PhysicalReg regs[]; -} TB_NodeMachineOp; - -typedef struct { - float value; -} TB_NodeFloat32; - -typedef struct { - double value; -} TB_NodeFloat64; - -typedef struct { - int64_t stride; -} TB_NodeArray; - -typedef struct { - int64_t offset; -} TB_NodeMember; - -typedef struct { - TB_Symbol* sym; -} TB_NodeSymbol; - -typedef struct { - TB_MemoryOrder order; - TB_MemoryOrder order2; - TB_Node* proj0; - TB_Node* proj1; -} TB_NodeAtomic; - -typedef struct { - // line info on safepoints - TB_SourceFile* file; - int line, column; -} TB_NodeSafepoint; - -typedef struct { - TB_FunctionPrototype* proto; - int proj_count; - TB_Node* projs[]; -} TB_NodeCall; - -typedef struct { - TB_FunctionPrototype* proto; -} TB_NodeTailcall; - -typedef struct { - const char* tag; - - // magic factor for hot-code, higher means run more often - float freq; - - // used for IR building only, stale after that. - TB_Node *mem_in, *mem_out; -} TB_NodeRegion; - -typedef struct { - int64_t key; - uint64_t val; -} TB_LookupEntry; - -typedef struct { - size_t entry_count; - TB_LookupEntry entries[]; -} TB_NodeLookup; - -typedef struct TB_MultiOutput { - size_t count; - union { - // count = 1 - TB_Node* single; - // count > 1 - TB_Node** multiple; - }; -} TB_MultiOutput; -#define TB_MULTI_OUTPUT(o) ((o).count > 1 ? (o).multiple : &(o).single) - -typedef struct { - int64_t key; - TB_Node* value; -} TB_SwitchEntry; - -typedef enum { - TB_EXECUTABLE_UNKNOWN, - TB_EXECUTABLE_PE, - TB_EXECUTABLE_ELF, -} TB_ExecutableType; - -typedef struct { - TB_Node* node; // type == TB_SAFEPOINT - void* userdata; - - uint32_t ip; // relative to the function body. - uint32_t count; // same as node->input_count - int32_t values[]; -} TB_Safepoint; - -typedef enum { - TB_MODULE_SECTION_WRITE = 1, - TB_MODULE_SECTION_EXEC = 2, - TB_MODULE_SECTION_TLS = 4, -} TB_ModuleSectionFlags; - -// ******************************* -// Public macros -// ******************************* -#ifdef __cplusplus - -#define TB_TYPE_TUPLE TB_DataType{ { TB_TUPLE } } -#define TB_TYPE_CONTROL TB_DataType{ { TB_CONTROL } } -#define TB_TYPE_VOID TB_DataType{ { TB_INT, 0 } } -#define TB_TYPE_I8 TB_DataType{ { TB_INT, 8 } } -#define TB_TYPE_I16 TB_DataType{ { TB_INT, 16 } } -#define TB_TYPE_I32 TB_DataType{ { TB_INT, 32 } } -#define TB_TYPE_I64 TB_DataType{ { TB_INT, 64 } } -#define TB_TYPE_F32 TB_DataType{ { TB_FLOAT, TB_FLT_32 } } -#define TB_TYPE_F64 TB_DataType{ { TB_FLOAT, TB_FLT_64 } } -#define TB_TYPE_BOOL TB_DataType{ { TB_INT, 1 } } -#define TB_TYPE_PTR TB_DataType{ { TB_PTR, 0 } } -#define TB_TYPE_MEMORY TB_DataType{ { TB_MEMORY,0 } } -#define TB_TYPE_CONT TB_DataType{ { TB_CONT, 0 } } -#define TB_TYPE_INTN(N) TB_DataType{ { TB_INT, (N) } } -#define TB_TYPE_PTRN(N) TB_DataType{ { TB_PTR, (N) } } - -#else - -#define TB_TYPE_TUPLE (TB_DataType){ { TB_TUPLE } } -#define TB_TYPE_CONTROL (TB_DataType){ { TB_CONTROL } } -#define TB_TYPE_VOID (TB_DataType){ { TB_INT, 0 } } -#define TB_TYPE_I8 (TB_DataType){ { TB_INT, 8 } } -#define TB_TYPE_I16 (TB_DataType){ { TB_INT, 16 } } -#define TB_TYPE_I32 (TB_DataType){ { TB_INT, 32 } } -#define TB_TYPE_I64 (TB_DataType){ { TB_INT, 64 } } -#define TB_TYPE_F32 (TB_DataType){ { TB_FLOAT, TB_FLT_32 } } -#define TB_TYPE_F64 (TB_DataType){ { TB_FLOAT, TB_FLT_64 } } -#define TB_TYPE_BOOL (TB_DataType){ { TB_INT, 1 } } -#define TB_TYPE_PTR (TB_DataType){ { TB_PTR, 0 } } -#define TB_TYPE_CONT (TB_DataType){ { TB_CONT, 0 } } -#define TB_TYPE_MEMORY (TB_DataType){ { TB_MEMORY,0 } } -#define TB_TYPE_INTN(N) (TB_DataType){ { TB_INT, (N) } } -#define TB_TYPE_PTRN(N) (TB_DataType){ { TB_PTR, (N) } } - -#endif - -typedef void (*TB_PrintCallback)(void* user_data, const char* fmt, ...); - -// defined in common/arena.h -typedef struct TB_Arena TB_Arena; - -// 0 for default -TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size); -TB_API void tb_arena_destroy(TB_Arena* restrict arena); -TB_API bool tb_arena_is_empty(TB_Arena* restrict arena); -TB_API void tb_arena_clear(TB_Arena* restrict arena); - -//////////////////////////////// -// Module management -//////////////////////////////// -// Creates a module with the correct target and settings -TB_API TB_Module* tb_module_create(TB_Arch arch, TB_System sys, const TB_FeatureSet* features, bool is_jit); - -// Creates a module but defaults on the architecture and system based on the host machine -TB_API TB_Module* tb_module_create_for_host(const TB_FeatureSet* features, bool is_jit); - -// Frees all resources for the TB_Module and it's functions, globals and -// compiled code. -TB_API void tb_module_destroy(TB_Module* m); - -// When targetting windows & thread local storage, you'll need to bind a tls index -// which is usually just a global that the runtime support has initialized, if you -// dont and the tls_index is used, it'll crash -TB_API void tb_module_set_tls_index(TB_Module* m, ptrdiff_t len, const char* name); - -TB_API TB_ModuleSectionHandle tb_module_create_section(TB_Module* m, ptrdiff_t len, const char* name, TB_ModuleSectionFlags flags, TB_ComdatType comdat); - -typedef struct { - TB_ThreadInfo* info; - size_t i; -} TB_SymbolIter; - -// Lovely iterator for all the symbols... it's probably not "fast" -TB_SymbolIter tb_symbol_iter(TB_Module* mod); -TB_Symbol* tb_symbol_iter_next(TB_SymbolIter* iter); - -//////////////////////////////// -// Compiled code introspection -//////////////////////////////// -enum { TB_ASSEMBLY_CHUNK_CAP = 4*1024 - sizeof(size_t[2]) }; - -typedef struct TB_Assembly TB_Assembly; -struct TB_Assembly { - TB_Assembly* next; - - // nice chunk of text here - size_t length; - char data[]; -}; - -// this is where the machine code and other relevant pieces go. -typedef struct TB_FunctionOutput TB_FunctionOutput; - -TB_API void tb_output_print_asm(TB_FunctionOutput* out, FILE* fp); - -TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length); - -// returns NULL if there's no line info -TB_API TB_Location* tb_output_get_locations(TB_FunctionOutput* out, size_t* out_count); - -// returns NULL if no assembly was generated -TB_API TB_Assembly* tb_output_get_asm(TB_FunctionOutput* out); - -// this is relative to the start of the function (the start of the prologue) -TB_API TB_Safepoint* tb_safepoint_get(TB_Function* f, uint32_t relative_ip); - -//////////////////////////////// -// JIT compilation -//////////////////////////////// -typedef struct TB_JIT TB_JIT; -typedef struct TB_CPUContext TB_CPUContext; - -// passing 0 to jit_heap_capacity will default to 4MiB -TB_API TB_JIT* tb_jit_begin(TB_Module* m, size_t jit_heap_capacity); -TB_API void* tb_jit_place_function(TB_JIT* jit, TB_Function* f); -TB_API void* tb_jit_place_global(TB_JIT* jit, TB_Global* g); -TB_API void tb_jit_dump_heap(TB_JIT* jit); -TB_API void tb_jit_end(TB_JIT* jit); - -typedef struct { - TB_Symbol* base; - uint32_t offset; -} TB_ResolvedAddr; - -typedef struct { - TB_Function* f; - TB_Location* loc; - uint32_t start, end; -} TB_ResolvedLine; - -TB_API TB_ResolvedAddr tb_jit_addr2sym(TB_JIT* jit, void* ptr); -TB_API TB_ResolvedLine tb_jit_addr2line(TB_JIT* jit, void* ptr); -TB_API void* tb_jit_get_code_ptr(TB_Function* f); - -typedef enum { - // just keeps running - TB_DBG_NONE, - // stops after one instruction - TB_DBG_INST, - // stops once the line changes - TB_DBG_LINE, -} TB_DbgStep; - -// Debugger stuff -// creates a new context we can run JIT code in, you don't -// technically need this but it's a nice helper for writing -// JITs especially when it comes to breakpoints (and eventually -// safepoints) -TB_API TB_CPUContext* tb_jit_thread_create(void* entry, void* arg); -// runs until TB_DbgStep condition is met -TB_API bool tb_jit_thread_resume(TB_JIT* jit, TB_CPUContext* cpu, TB_DbgStep step); -TB_API void* tb_jit_thread_pc(TB_CPUContext* cpu); -TB_API void tb_jit_breakpoint(TB_JIT* jit, void* addr); -TB_API void tb_jit_thread_dump_stack(TB_JIT* jit, TB_CPUContext* cpu); - -//////////////////////////////// -// Disassembler -//////////////////////////////// -TB_API ptrdiff_t tb_print_disassembly_inst(TB_Arch arch, size_t length, const void* ptr); - -//////////////////////////////// -// Exporter -//////////////////////////////// -// Export buffers are generated in chunks because it's easier, usually the -// chunks are "massive" (representing some connected piece of the buffer) -// but they don't have to be. -typedef struct TB_ExportChunk TB_ExportChunk; -struct TB_ExportChunk { - TB_ExportChunk* next; - size_t pos, size; - uint8_t data[]; -}; - -typedef struct { - size_t total; - TB_ExportChunk *head, *tail; -} TB_ExportBuffer; - -TB_API TB_ExportBuffer tb_module_object_export(TB_Module* m, TB_DebugFormat debug_fmt); -TB_API bool tb_export_buffer_to_file(TB_ExportBuffer buffer, const char* path); -TB_API void tb_export_buffer_free(TB_ExportBuffer buffer); - -//////////////////////////////// -// Linker exporter -//////////////////////////////// -// This is used to export shared objects or executables -typedef struct TB_Linker TB_Linker; -typedef struct TB_LinkerSection TB_LinkerSection; -typedef struct TB_LinkerSectionPiece TB_LinkerSectionPiece; - -typedef struct { - enum { - TB_LINKER_MSG_NULL, - - // pragma comment(lib, "blah") - TB_LINKER_MSG_IMPORT, - } tag; - union { - // pragma lib request - TB_Slice import_path; - }; -} TB_LinkerMsg; - -TB_API TB_ExecutableType tb_system_executable_format(TB_System s); - -TB_API TB_Linker* tb_linker_create(TB_ExecutableType type, TB_Arch arch); -TB_API TB_ExportBuffer tb_linker_export(TB_Linker* l); -TB_API void tb_linker_destroy(TB_Linker* l); - -TB_API bool tb_linker_get_msg(TB_Linker* l, TB_LinkerMsg* msg); - -// windows only -TB_API void tb_linker_set_subsystem(TB_Linker* l, TB_WindowsSubsystem subsystem); - -TB_API void tb_linker_set_entrypoint(TB_Linker* l, const char* name); - -// Links compiled module into output -TB_API void tb_linker_append_module(TB_Linker* l, TB_Module* m); - -// Adds object file to output -TB_API void tb_linker_append_object(TB_Linker* l, TB_Slice obj_name, TB_Slice content); - -// Adds static library to output -// this can include imports (wrappers for DLL symbols) along with -// normal sections. -TB_API void tb_linker_append_library(TB_Linker* l, TB_Slice ar_name, TB_Slice content); - -//////////////////////////////// -// Symbols -//////////////////////////////// -TB_API TB_Global* tb_extern_transmute(TB_External* e, TB_DebugType* dbg_type, TB_Linkage linkage); -TB_API TB_External* tb_extern_create(TB_Module* m, ptrdiff_t len, const char* name, TB_ExternalType type); - -TB_API TB_SourceFile* tb_get_source_file(TB_Module* m, const char* path); - -// Called once you're done with TB operations on a thread (or i guess when it's -// about to be killed :p), not calling it can only result in leaks on that thread -// and calling it too early will result in TB potentially reallocating it but there's -// should be no crashes from this, just potential slowdown or higher than expected memory -// usage. -TB_API void tb_free_thread_resources(void); - -//////////////////////////////// -// Function Prototypes -//////////////////////////////// -typedef struct TB_PrototypeParam { - TB_DataType dt; - TB_DebugType* debug_type; - - // does not apply for returns - const char* name; -} TB_PrototypeParam; - -struct TB_FunctionPrototype { - // header - TB_CallingConv call_conv; - uint16_t return_count, param_count; - bool has_varargs; - - // params are directly followed by returns - TB_PrototypeParam params[]; -}; -#define TB_PROTOTYPE_RETURNS(p) ((p)->params + (p)->param_count) - -// creates a function prototype used to define a function's parameters and returns. -// -// function prototypes do not get freed individually and last for the entire run -// of the backend, they can also be reused for multiple functions which have -// matching signatures. -TB_API TB_FunctionPrototype* tb_prototype_create(TB_Module* m, TB_CallingConv cc, size_t param_count, const TB_PrototypeParam* params, size_t return_count, const TB_PrototypeParam* returns, bool has_varargs); - -// same as tb_function_set_prototype except it will handle lowering from types like the TB_DebugType -// into the correct ABI and exposing sane looking nodes to the parameters. -// -// returns the parameters -TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_ModuleSectionHandle section, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count); -TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg); - -// used for ABI parameter passing -typedef enum { - // needs a direct value - TB_PASSING_DIRECT, - - // needs an address to the value - TB_PASSING_INDIRECT, - - // doesn't use this parameter - TB_PASSING_IGNORE, -} TB_PassingRule; - -TB_API TB_PassingRule tb_get_passing_rule_from_dbg(TB_Module* mod, TB_DebugType* param_type, bool is_return); - -//////////////////////////////// -// Globals -//////////////////////////////// -TB_API TB_Global* tb_global_create(TB_Module* m, ptrdiff_t len, const char* name, TB_DebugType* dbg_type, TB_Linkage linkage); - -// allocate space for the global -TB_API void tb_global_set_storage(TB_Module* m, TB_ModuleSectionHandle section, TB_Global* global, size_t size, size_t align, size_t max_objects); - -// returns a buffer which the user can fill to then have represented in the initializer -TB_API void* tb_global_add_region(TB_Module* m, TB_Global* global, size_t offset, size_t size); - -// places a relocation for a global at offset, the size of the relocation -// depends on the pointer size -TB_API void tb_global_add_symbol_reloc(TB_Module* m, TB_Global* global, size_t offset, const TB_Symbol* symbol); - -TB_API TB_ModuleSectionHandle tb_module_get_text(TB_Module* m); -TB_API TB_ModuleSectionHandle tb_module_get_rdata(TB_Module* m); -TB_API TB_ModuleSectionHandle tb_module_get_data(TB_Module* m); -TB_API TB_ModuleSectionHandle tb_module_get_tls(TB_Module* m); - -//////////////////////////////// -// Function Attributes -//////////////////////////////// -// These are parts of a function that describe metadata for instructions -TB_API void tb_function_attrib_variable(TB_Function* f, TB_Node* n, TB_Node* parent, ptrdiff_t len, const char* name, TB_DebugType* type); -TB_API void tb_function_attrib_scope(TB_Function* f, TB_Node* n, TB_Node* parent); - -//////////////////////////////// -// Debug info Generation -//////////////////////////////// -TB_API TB_DebugType* tb_debug_get_void(TB_Module* m); -TB_API TB_DebugType* tb_debug_get_bool(TB_Module* m); -TB_API TB_DebugType* tb_debug_get_integer(TB_Module* m, bool is_signed, int bits); -TB_API TB_DebugType* tb_debug_get_float(TB_Module* m, TB_FloatFormat fmt); -TB_API TB_DebugType* tb_debug_create_ptr(TB_Module* m, TB_DebugType* base); -TB_API TB_DebugType* tb_debug_create_array(TB_Module* m, TB_DebugType* base, size_t count); -TB_API TB_DebugType* tb_debug_create_alias(TB_Module* m, TB_DebugType* base, ptrdiff_t len, const char* tag); -TB_API TB_DebugType* tb_debug_create_struct(TB_Module* m, ptrdiff_t len, const char* tag); -TB_API TB_DebugType* tb_debug_create_union(TB_Module* m, ptrdiff_t len, const char* tag); -TB_API TB_DebugType* tb_debug_create_field(TB_Module* m, TB_DebugType* type, ptrdiff_t len, const char* name, TB_CharUnits offset); - -// returns the array you need to fill with fields -TB_API TB_DebugType** tb_debug_record_begin(TB_Module* m, TB_DebugType* type, size_t count); -TB_API void tb_debug_record_end(TB_DebugType* type, TB_CharUnits size, TB_CharUnits align); - -TB_API TB_DebugType* tb_debug_create_func(TB_Module* m, TB_CallingConv cc, size_t param_count, size_t return_count, bool has_varargs); - -TB_API TB_DebugType* tb_debug_field_type(TB_DebugType* type); - -TB_API size_t tb_debug_func_return_count(TB_DebugType* type); -TB_API size_t tb_debug_func_param_count(TB_DebugType* type); - -// you'll need to fill these if you make a function -TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type); -TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type); - -//////////////////////////////// -// Symbols -//////////////////////////////// -// returns NULL if the tag doesn't match -TB_API TB_Function* tb_symbol_as_function(TB_Symbol* s); -TB_API TB_External* tb_symbol_as_external(TB_Symbol* s); -TB_API TB_Global* tb_symbol_as_global(TB_Symbol* s); - -//////////////////////////////// -// Function IR Generation -//////////////////////////////// -TB_API void tb_get_data_type_size(TB_Module* mod, TB_DataType dt, size_t* size, size_t* align); - -// the user_data is expected to be a valid FILE* -TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...); - -TB_API void tb_inst_location(TB_Function* f, TB_SourceFile* file, int line, int column); - -// this is where the STOP will be -TB_API void tb_inst_set_exit_location(TB_Function* f, TB_SourceFile* file, int line, int column); - -// if section is NULL, default to .text -TB_API TB_Function* tb_function_create(TB_Module* m, ptrdiff_t len, const char* name, TB_Linkage linkage); - -TB_API TB_Arena* tb_function_get_arena(TB_Function* f); - -// if len is -1, it's null terminated -TB_API void tb_symbol_set_name(TB_Symbol* s, ptrdiff_t len, const char* name); - -TB_API void tb_symbol_bind_ptr(TB_Symbol* s, void* ptr); -TB_API const char* tb_symbol_get_name(TB_Symbol* s); - -// if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources -TB_API void tb_function_set_prototype(TB_Function* f, TB_ModuleSectionHandle section, TB_FunctionPrototype* p, TB_Arena* arena); -TB_API TB_FunctionPrototype* tb_function_get_prototype(TB_Function* f); - -TB_API void tb_inst_set_control(TB_Function* f, TB_Node* control); -TB_API TB_Node* tb_inst_get_control(TB_Function* f); - -TB_API TB_Node* tb_inst_region(TB_Function* f); - -// if len is -1, it's null terminated -TB_API void tb_inst_set_region_name(TB_Function* f, TB_Node* n, ptrdiff_t len, const char* name); - -TB_API void tb_inst_unreachable(TB_Function* f); -TB_API void tb_inst_debugbreak(TB_Function* f); -TB_API void tb_inst_trap(TB_Function* f); -TB_API TB_Node* tb_inst_poison(TB_Function* f, TB_DataType dt); - -TB_API TB_Node* tb_inst_param(TB_Function* f, int param_id); - -TB_API TB_Node* tb_inst_fpxt(TB_Function* f, TB_Node* src, TB_DataType dt); -TB_API TB_Node* tb_inst_sxt(TB_Function* f, TB_Node* src, TB_DataType dt); -TB_API TB_Node* tb_inst_zxt(TB_Function* f, TB_Node* src, TB_DataType dt); -TB_API TB_Node* tb_inst_trunc(TB_Function* f, TB_Node* src, TB_DataType dt); -TB_API TB_Node* tb_inst_int2ptr(TB_Function* f, TB_Node* src); -TB_API TB_Node* tb_inst_ptr2int(TB_Function* f, TB_Node* src, TB_DataType dt); -TB_API TB_Node* tb_inst_int2float(TB_Function* f, TB_Node* src, TB_DataType dt, bool is_signed); -TB_API TB_Node* tb_inst_float2int(TB_Function* f, TB_Node* src, TB_DataType dt, bool is_signed); -TB_API TB_Node* tb_inst_bitcast(TB_Function* f, TB_Node* src, TB_DataType dt); - -TB_API TB_Node* tb_inst_local(TB_Function* f, TB_CharUnits size, TB_CharUnits align); - -TB_API TB_Node* tb_inst_load(TB_Function* f, TB_DataType dt, TB_Node* addr, TB_CharUnits align, bool is_volatile); -TB_API void tb_inst_store(TB_Function* f, TB_DataType dt, TB_Node* addr, TB_Node* val, TB_CharUnits align, bool is_volatile); - -TB_API void tb_inst_safepoint_poll(TB_Function* f, TB_Node* addr, int input_count, TB_Node** inputs); - -TB_API TB_Node* tb_inst_bool(TB_Function* f, bool imm); -TB_API TB_Node* tb_inst_sint(TB_Function* f, TB_DataType dt, int64_t imm); -TB_API TB_Node* tb_inst_uint(TB_Function* f, TB_DataType dt, uint64_t imm); -TB_API TB_Node* tb_inst_float32(TB_Function* f, float imm); -TB_API TB_Node* tb_inst_float64(TB_Function* f, double imm); -TB_API TB_Node* tb_inst_cstring(TB_Function* f, const char* str); -TB_API TB_Node* tb_inst_string(TB_Function* f, size_t len, const char* str); - -// write 'val' over 'count' bytes on 'dst' -TB_API void tb_inst_memset(TB_Function* f, TB_Node* dst, TB_Node* val, TB_Node* count, TB_CharUnits align); - -// zero 'count' bytes on 'dst' -TB_API void tb_inst_memzero(TB_Function* f, TB_Node* dst, TB_Node* count, TB_CharUnits align); - -// performs a copy of 'count' elements from one memory location to another -// both locations cannot overlap. -TB_API void tb_inst_memcpy(TB_Function* f, TB_Node* dst, TB_Node* src, TB_Node* count, TB_CharUnits align); - -// result = base + (index * stride) -TB_API TB_Node* tb_inst_array_access(TB_Function* f, TB_Node* base, TB_Node* index, int64_t stride); - -// result = base + offset -// where base is a pointer -TB_API TB_Node* tb_inst_member_access(TB_Function* f, TB_Node* base, int64_t offset); - -TB_API TB_Node* tb_inst_get_symbol_address(TB_Function* f, TB_Symbol* target); - -// Performs a conditional select between two values, if the operation is -// performed wide then the cond is expected to be the same type as a and b where -// the condition is resolved as true if the MSB (per component) is 1. -// -// result = cond ? a : b -// a, b must match in type -TB_API TB_Node* tb_inst_select(TB_Function* f, TB_Node* cond, TB_Node* a, TB_Node* b); - -// Integer arithmatic -TB_API TB_Node* tb_inst_add(TB_Function* f, TB_Node* a, TB_Node* b, TB_ArithmeticBehavior arith_behavior); -TB_API TB_Node* tb_inst_sub(TB_Function* f, TB_Node* a, TB_Node* b, TB_ArithmeticBehavior arith_behavior); -TB_API TB_Node* tb_inst_mul(TB_Function* f, TB_Node* a, TB_Node* b, TB_ArithmeticBehavior arith_behavior); -TB_API TB_Node* tb_inst_div(TB_Function* f, TB_Node* a, TB_Node* b, bool signedness); -TB_API TB_Node* tb_inst_mod(TB_Function* f, TB_Node* a, TB_Node* b, bool signedness); - -// Bitmagic operations -TB_API TB_Node* tb_inst_bswap(TB_Function* f, TB_Node* n); -TB_API TB_Node* tb_inst_clz(TB_Function* f, TB_Node* n); -TB_API TB_Node* tb_inst_ctz(TB_Function* f, TB_Node* n); -TB_API TB_Node* tb_inst_popcount(TB_Function* f, TB_Node* n); - -// Bitwise operations -TB_API TB_Node* tb_inst_not(TB_Function* f, TB_Node* n); -TB_API TB_Node* tb_inst_neg(TB_Function* f, TB_Node* n); -TB_API TB_Node* tb_inst_and(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_or(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_xor(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_sar(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_shl(TB_Function* f, TB_Node* a, TB_Node* b, TB_ArithmeticBehavior arith_behavior); -TB_API TB_Node* tb_inst_shr(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_rol(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_ror(TB_Function* f, TB_Node* a, TB_Node* b); - -// Atomics -// By default you can use TB_MEM_ORDER_SEQ_CST for the memory order to get -// correct but possibly slower results on certain platforms (those with relaxed -// memory models). - -// Must be aligned to the natural alignment of dt -TB_API TB_Node* tb_inst_atomic_load(TB_Function* f, TB_Node* addr, TB_DataType dt, TB_MemoryOrder order); - -// All atomic operations here return the old value and the operations are -// performed in the same data type as 'src' with alignment of 'addr' being -// the natural alignment of 'src' -TB_API TB_Node* tb_inst_atomic_xchg(TB_Function* f, TB_Node* addr, TB_Node* src, TB_MemoryOrder order); -TB_API TB_Node* tb_inst_atomic_add(TB_Function* f, TB_Node* addr, TB_Node* src, TB_MemoryOrder order); -TB_API TB_Node* tb_inst_atomic_sub(TB_Function* f, TB_Node* addr, TB_Node* src, TB_MemoryOrder order); -TB_API TB_Node* tb_inst_atomic_and(TB_Function* f, TB_Node* addr, TB_Node* src, TB_MemoryOrder order); -TB_API TB_Node* tb_inst_atomic_xor(TB_Function* f, TB_Node* addr, TB_Node* src, TB_MemoryOrder order); -TB_API TB_Node* tb_inst_atomic_or(TB_Function* f, TB_Node* addr, TB_Node* src, TB_MemoryOrder order); - -// returns old_value from *addr -TB_API TB_Node* tb_inst_atomic_cmpxchg(TB_Function* f, TB_Node* addr, TB_Node* expected, TB_Node* desired, TB_MemoryOrder succ, TB_MemoryOrder fail); - -// Float math -TB_API TB_Node* tb_inst_fadd(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_fsub(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_fmul(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_fdiv(TB_Function* f, TB_Node* a, TB_Node* b); - -// Comparisons -TB_API TB_Node* tb_inst_cmp_eq(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_cmp_ne(TB_Function* f, TB_Node* a, TB_Node* b); - -TB_API TB_Node* tb_inst_cmp_ilt(TB_Function* f, TB_Node* a, TB_Node* b, bool signedness); -TB_API TB_Node* tb_inst_cmp_ile(TB_Function* f, TB_Node* a, TB_Node* b, bool signedness); -TB_API TB_Node* tb_inst_cmp_igt(TB_Function* f, TB_Node* a, TB_Node* b, bool signedness); -TB_API TB_Node* tb_inst_cmp_ige(TB_Function* f, TB_Node* a, TB_Node* b, bool signedness); - -TB_API TB_Node* tb_inst_cmp_flt(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_cmp_fle(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_cmp_fgt(TB_Function* f, TB_Node* a, TB_Node* b); -TB_API TB_Node* tb_inst_cmp_fge(TB_Function* f, TB_Node* a, TB_Node* b); - -// General intrinsics -TB_API TB_Node* tb_inst_va_start(TB_Function* f, TB_Node* a); -TB_API TB_Node* tb_inst_cycle_counter(TB_Function* f); -TB_API TB_Node* tb_inst_prefetch(TB_Function* f, TB_Node* addr, int level); - -// x86 Intrinsics -TB_API TB_Node* tb_inst_x86_ldmxcsr(TB_Function* f, TB_Node* a); -TB_API TB_Node* tb_inst_x86_stmxcsr(TB_Function* f); -TB_API TB_Node* tb_inst_x86_sqrt(TB_Function* f, TB_Node* a); -TB_API TB_Node* tb_inst_x86_rsqrt(TB_Function* f, TB_Node* a); - -// Control flow -TB_API TB_Node* tb_inst_syscall(TB_Function* f, TB_DataType dt, TB_Node* syscall_num, size_t param_count, TB_Node** params); -TB_API TB_MultiOutput tb_inst_call(TB_Function* f, TB_FunctionPrototype* proto, TB_Node* target, size_t param_count, TB_Node** params); -TB_API void tb_inst_tailcall(TB_Function* f, TB_FunctionPrototype* proto, TB_Node* target, size_t param_count, TB_Node** params); - -TB_API TB_Node* tb_inst_safepoint(TB_Function* f, TB_Node* poke_site, size_t param_count, TB_Node** params); - -TB_API TB_Node* tb_inst_incomplete_phi(TB_Function* f, TB_DataType dt, TB_Node* region, size_t preds); -TB_API bool tb_inst_add_phi_operand(TB_Function* f, TB_Node* phi, TB_Node* region, TB_Node* val); - -TB_API TB_Node* tb_inst_phi2(TB_Function* f, TB_Node* region, TB_Node* a, TB_Node* b); -TB_API void tb_inst_goto(TB_Function* f, TB_Node* target); -TB_API void tb_inst_if(TB_Function* f, TB_Node* cond, TB_Node* true_case, TB_Node* false_case); -TB_API void tb_inst_branch(TB_Function* f, TB_DataType dt, TB_Node* key, TB_Node* default_case, size_t entry_count, const TB_SwitchEntry* keys); - -TB_API void tb_inst_ret(TB_Function* f, size_t count, TB_Node** values); - -//////////////////////////////// -// Passes -//////////////////////////////// -typedef enum { - // allowed to remove PHIs nodes, this is - // helpful because the default IR building - // will produce tons of useless memory PHIs. - TB_PEEPHOLE_PHI = 1, - - // it's allowed to fold memory operations (store or load elimination) - TB_PEEPHOLE_MEMORY = 2, - - // just do every reduction rule i can provide you - TB_PEEPHOLE_ALL = 7, -} TB_PeepholeFlags; - -// Function analysis, optimizations, and codegen are all part of this -typedef struct TB_Passes TB_Passes; - -// the arena is used to allocate the nodes while passes are being done. -TB_API TB_Passes* tb_pass_enter(TB_Function* f, TB_Arena* arena); -TB_API void tb_pass_exit(TB_Passes* opt); - -// transformation passes: -// peephole: 99% of the optimizer, i'm sea of nodes pilled so i -// break down most optimizations into local rewrites, it's -// incremental and recommended to run after any non-peephole -// pass. -// -// mem2reg: lowers TB_LOCALs into SoN values, this makes more -// data flow analysis possible on the code and allows to codegen -// to place variables into registers. -// -// SROA: splits LOCALs into multiple to allow for more dataflow -// analysis later on. -TB_API void tb_pass_peephole(TB_Passes* opt, TB_PeepholeFlags flags); -TB_API void tb_pass_sroa(TB_Passes* opt); -TB_API bool tb_pass_mem2reg(TB_Passes* opt); -TB_API bool tb_pass_loop(TB_Passes* opt); - -// this just runs the optimizer in the default configuration -TB_API void tb_pass_optimize(TB_Passes* opt); - -// analysis -// print: prints IR in a flattened text form. -TB_API bool tb_pass_print(TB_Passes* opt); -// print-dot: prints IR as DOT -TB_API void tb_pass_print_dot(TB_Passes* opt, TB_PrintCallback callback, void* user_data); - -// codegen -TB_API TB_FunctionOutput* tb_pass_codegen(TB_Passes* opt, bool emit_asm); - -TB_API void tb_pass_kill_node(TB_Passes* opt, TB_Node* n); -TB_API void tb_pass_mark(TB_Passes* opt, TB_Node* n); -TB_API void tb_pass_mark_users(TB_Passes* opt, TB_Node* n); - -//////////////////////////////// -// IR access -//////////////////////////////// -TB_API const char* tb_node_get_name(TB_Node* n); - -TB_API TB_Node* tb_get_parent_region(TB_Node* n); -TB_API bool tb_node_is_constant_non_zero(TB_Node* n); -TB_API bool tb_node_is_constant_zero(TB_Node* n); - -#endif /* TB_CORE_H */ diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib deleted file mode 100644 index 510569b0e..000000000 Binary files a/src/tilde/tb.lib and /dev/null differ diff --git a/src/tilde/tb_arena.h b/src/tilde/tb_arena.h deleted file mode 100644 index 67ec0e181..000000000 --- a/src/tilde/tb_arena.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include -#include - -#ifndef TB_API -# ifdef __cplusplus -# define TB_EXTERN extern "C" -# else -# define TB_EXTERN -# endif -# ifdef TB_DLL -# ifdef TB_IMPORT_DLL -# define TB_API TB_EXTERN __declspec(dllimport) -# else -# define TB_API TB_EXTERN __declspec(dllexport) -# endif -# else -# define TB_API TB_EXTERN -# endif -#endif - -enum { - TB_ARENA_SMALL_CHUNK_SIZE = 4 * 1024, - TB_ARENA_MEDIUM_CHUNK_SIZE = 512 * 1024, - TB_ARENA_LARGE_CHUNK_SIZE = 16 * 1024 * 1024, - - TB_ARENA_ALIGNMENT = 16, -}; - -typedef struct TB_ArenaChunk TB_ArenaChunk; -struct TB_ArenaChunk { - TB_ArenaChunk* next; - size_t pad; - char data[]; -}; - -typedef struct TB_Arena { - size_t chunk_size; - TB_ArenaChunk* base; - TB_ArenaChunk* top; - - // top of the allocation space - char* watermark; - char* high_point; // &top->data[chunk_size] -} TB_Arena; - -typedef struct TB_ArenaSavepoint { - TB_ArenaChunk* top; - char* watermark; -} TB_ArenaSavepoint; - -#define TB_ARENA_FOR(it, arena) for (TB_ArenaChunk* it = (arena)->base; it != NULL; it = it->next) - -#define TB_ARENA_ALLOC(arena, T) tb_arena_alloc(arena, sizeof(T)) -#define TB_ARENA_ARR_ALLOC(arena, count, T) tb_arena_alloc(arena, (count) * sizeof(T)) - -TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size); -TB_API void tb_arena_destroy(TB_Arena* restrict arena); - -TB_API void* tb_arena_unaligned_alloc(TB_Arena* restrict arena, size_t size); -TB_API void* tb_arena_alloc(TB_Arena* restrict arena, size_t size); - -// return false on failure -TB_API bool tb_arena_free(TB_Arena* restrict arena, void* ptr, size_t size); -TB_API void tb_arena_pop(TB_Arena* restrict arena, void* ptr, size_t size); - -// in case you wanna mix unaligned and aligned arenas -TB_API void tb_arena_realign(TB_Arena* restrict arena); - -TB_API bool tb_arena_is_empty(TB_Arena* arena); - -TB_API size_t tb_arena_current_size(TB_Arena* arena); - -// savepoints -TB_API TB_ArenaSavepoint tb_arena_save(TB_Arena* arena); -TB_API void tb_arena_restore(TB_Arena* arena, TB_ArenaSavepoint sp); - -// resets to only having one chunk -TB_API void tb_arena_clear(TB_Arena* arena); diff --git a/src/tilde/tb_coff.h b/src/tilde/tb_coff.h deleted file mode 100644 index ddedd6ffe..000000000 --- a/src/tilde/tb_coff.h +++ /dev/null @@ -1,334 +0,0 @@ -// PE/COFF is the executable/object format used by Microsoft. -#ifndef TB_COFF_H -#define TB_COFF_H - -#include "tb_formats.h" - -#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 - -#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 -#define IMAGE_SYM_CLASS_STATIC 0x0003 -#define IMAGE_SYM_CLASS_LABEL 0x0006 -#define IMAGE_SYM_CLASS_FILE 0x0067 -#define IMAGE_SYM_CLASS_SECTION 0x0068 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 - -#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 - -#define IMAGE_REL_AMD64_ADDR64 0x0001 -#define IMAGE_REL_AMD64_ADDR32 0x0002 -#define IMAGE_REL_AMD64_ADDR32NB 0x0003 -#define IMAGE_REL_AMD64_REL32 0x0004 -#define IMAGE_REL_AMD64_REL32_1 0x0005 -#define IMAGE_REL_AMD64_REL32_2 0x0006 -#define IMAGE_REL_AMD64_REL32_3 0x0007 -#define IMAGE_REL_AMD64_REL32_4 0x0008 -#define IMAGE_REL_AMD64_REL32_5 0x0009 -#define IMAGE_REL_AMD64_SECTION 0x000A -#define IMAGE_REL_AMD64_SECREL 0x000B - -#define IMAGE_SCN_LNK_REMOVE 0x00000800 -#define IMAGE_SCN_LNK_COMDAT 0x00001000 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 - -#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */ -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */ -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */ - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP -#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers -#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor - -#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 -#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 -#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 - -typedef enum { - TB_COFF_SECTION_NO_PAD = 0x00000008, - TB_COFF_SECTION_CODE = 0x00000020, - TB_COFF_SECTION_INIT = 0x00000040, - TB_COFF_SECTION_UNINIT = 0x00000080, - TB_COFF_SECTION_OTHER = 0x00000100, - TB_COFF_SECTION_INFO = 0x00000200, - TB_COFF_SECTION_REMOVE = 0x00000800, - TB_COFF_SECTION_COMDAT = 0x00001000, - - // this is actually a 4bit field - TB_COFF_SECTION_ALIGN = 0x00F00000, - - // if we have more than 65535 relocations we do this - TB_COFF_SECTION_RELOC_OVR = 0x00F00000, - - // memory flags - TB_COFF_SECTION_DISCARDABLE = 0x02000000, - TB_COFF_SECTION_NOT_CACHED = 0x04000000, - TB_COFF_SECTION_NOT_PAGED = 0x08000000, - TB_COFF_SECTION_SHARED = 0x10000000, - TB_COFF_SECTION_EXECUTE = 0x20000000, - TB_COFF_SECTION_READ = 0x40000000, - TB_COFF_SECTION_WRITE = 0x80000000, -} TB_COFF_SectionFlags; - -typedef struct TB_COFF_Parser { - // inputs - TB_Slice name, file; - - // results - size_t section_count; - size_t symbol_table, symbol_count; - - // private - TB_Slice string_table; -} TB_COFF_Parser; - -// fills the parser with results from the COFF header -bool tb_coff_parse_init(TB_COFF_Parser* restrict parser); -bool tb_coff_parse_section(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSection* out_sec); - -// how many symbols does this one symbol take up (basically 1 + aux symbols). -// returns 0 if error. -size_t tb_coff_parse_symbol(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSymbol* restrict out_sym); - -#endif // TB_COFF_H - -#ifdef TB_COFF_IMPL -#include - -#pragma pack(push, 2) -typedef struct COFF_SectionHeader { - char name[8]; - union { - uint32_t physical_address; - uint32_t virtual_size; - } misc; - uint32_t virtual_address; - uint32_t raw_data_size; - uint32_t raw_data_pos; - uint32_t pointer_to_reloc; - uint32_t pointer_to_lineno; - uint16_t num_reloc; - uint16_t num_lineno; - uint32_t characteristics; -} COFF_SectionHeader; - -typedef struct COFF_FileHeader { - uint16_t machine; - uint16_t section_count; - uint32_t timestamp; - uint32_t symbol_table; - uint32_t symbol_count; - uint16_t optional_header_size; - uint16_t flags; -} COFF_FileHeader; - -typedef struct COFF_Symbol { - union { - uint8_t short_name[8]; - uint32_t long_name[2]; - }; - uint32_t value; - int16_t section_number; - uint16_t type; - uint8_t storage_class; - uint8_t aux_symbols_count; -} COFF_Symbol; - -typedef struct COFF_ImageReloc { - union { - uint32_t VirtualAddress; - uint32_t RelocCount; - }; - uint32_t SymbolTableIndex; - uint16_t Type; -} COFF_ImageReloc; -#pragma pack(pop) - -// sanity checks -static_assert(sizeof(COFF_SectionHeader) == 40, "COFF Section header size != 40 bytes"); -static_assert(sizeof(COFF_ImageReloc) == 10, "COFF Image Relocation size != 10 bytes"); -static_assert(sizeof(COFF_FileHeader) == 20, "COFF File header size != 20 bytes"); -static_assert(sizeof(COFF_Symbol) == 18, "COFF Symbol size != 18 bytes"); - -bool tb_coff_parse_init(TB_COFF_Parser* restrict parser) { - TB_Slice file = parser->file; - - if (file.length < sizeof(COFF_FileHeader)) return false; - COFF_FileHeader* header = (COFF_FileHeader*) &parser->file.data[0]; - - // locate string table (it spans until the end of the file) - size_t string_table_pos = header->symbol_table + (header->symbol_count * sizeof(COFF_Symbol)); - if (file.length < string_table_pos) return false; - - parser->symbol_count = header->symbol_count; - parser->symbol_table = header->symbol_table; - parser->section_count = header->section_count; - parser->string_table = (TB_Slice){ - .length = file.length - string_table_pos, - .data = &file.data[string_table_pos] - }; - - return true; -} - -static long long tb__parse_decimal_int(size_t n, const char* str) { - const char* end = &str[n]; - - int result = 0; - while (str != end) { - if (*str < '0' || *str > '9') break; - - result *= 10; - result += *str - '0'; - str++; - } - - return result; -} - -bool tb_coff_parse_section(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSection* restrict out_sec) { - TB_Slice file = parser->file; - size_t section_offset = sizeof(COFF_FileHeader) + (i * sizeof(COFF_SectionHeader)); - - if (file.length < section_offset + sizeof(COFF_SectionHeader)) { - return false; - } - - COFF_SectionHeader* sec = (COFF_SectionHeader*) &file.data[section_offset]; - *out_sec = (TB_ObjectSection) { .flags = sec->characteristics }; - - // Parse string table name stuff - if (sec->name[0] == '/') { - // string table access - int offset = tb__parse_decimal_int(7, &sec->name[1]); - if (file.length > offset) { - return false; - } - - const uint8_t* data = &parser->string_table.data[offset]; - out_sec->name = (TB_Slice){ strlen((const char*) data), data }; - } else { - // normal inplace string - size_t len = strlen(sec->name); - out_sec->name = (TB_Slice){ len, (uint8_t*) sec->name }; - } - - // Parse relocations - if (sec->num_reloc > 0) { - out_sec->relocation_count = sec->num_reloc; - COFF_ImageReloc* src_relocs = (COFF_ImageReloc*) &file.data[sec->pointer_to_reloc]; - - TB_ObjectReloc* dst_relocs = tb_platform_heap_alloc(sec->num_reloc * sizeof(TB_ObjectReloc)); - FOREACH_N(j, 0, sec->num_reloc) { - dst_relocs[j] = (TB_ObjectReloc){ 0 }; - switch (src_relocs[j].Type) { - case IMAGE_REL_AMD64_ADDR32NB: dst_relocs[j].type = TB_OBJECT_RELOC_ADDR32NB; break; - case IMAGE_REL_AMD64_ADDR32: dst_relocs[j].type = TB_OBJECT_RELOC_ADDR32; break; - case IMAGE_REL_AMD64_ADDR64: dst_relocs[j].type = TB_OBJECT_RELOC_ADDR64; break; - case IMAGE_REL_AMD64_SECREL: dst_relocs[j].type = TB_OBJECT_RELOC_SECREL; break; - case IMAGE_REL_AMD64_SECTION: dst_relocs[j].type = TB_OBJECT_RELOC_SECTION; break; - - case IMAGE_REL_AMD64_REL32: - case IMAGE_REL_AMD64_REL32_1: - case IMAGE_REL_AMD64_REL32_2: - case IMAGE_REL_AMD64_REL32_3: - case IMAGE_REL_AMD64_REL32_4: - case IMAGE_REL_AMD64_REL32_5: - dst_relocs[j].type = TB_OBJECT_RELOC_REL32; - break; - - default: tb_todo(); - } - - if (src_relocs[j].Type >= IMAGE_REL_AMD64_REL32 && src_relocs[j].Type <= IMAGE_REL_AMD64_REL32_5) { - dst_relocs[j].addend = 4 + (src_relocs[j].Type - IMAGE_REL_AMD64_REL32); - } - - dst_relocs[j].symbol_index = src_relocs[j].SymbolTableIndex; - dst_relocs[j].virtual_address = src_relocs[j].VirtualAddress; - } - - out_sec->relocations = dst_relocs; - } - - // Parse virtual region - out_sec->virtual_address = sec->virtual_address; - out_sec->virtual_size = sec->misc.virtual_size; - - // Read raw data (if applies) - if (sec->raw_data_size) { - assert(sec->raw_data_pos + sec->raw_data_size < file.length); - out_sec->raw_data = (TB_Slice){ sec->raw_data_size, &file.data[sec->raw_data_pos] }; - } - - return true; -} - -TB_ObjectSymbolType classify_symbol_type(uint16_t st_class) { - switch (st_class) { - case 2: return TB_OBJECT_SYMBOL_EXTERN; - case 3: return TB_OBJECT_SYMBOL_STATIC; - case 6: return TB_OBJECT_SYMBOL_STATIC; - case 0x68: return TB_OBJECT_SYMBOL_SECTION; - case 0x69: return TB_OBJECT_SYMBOL_WEAK_EXTERN; - default: return TB_OBJECT_SYMBOL_UNKNOWN; - } -} - -size_t tb_coff_parse_symbol(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSymbol* restrict out_sym) { - TB_Slice file = parser->file; - size_t symbol_offset = parser->symbol_table + (i * sizeof(COFF_Symbol)); - - if (file.length < symbol_offset + sizeof(COFF_Symbol)) { - return 0; - } - - COFF_Symbol* sym = (COFF_Symbol*) &file.data[symbol_offset]; - *out_sym = (TB_ObjectSymbol) { - .ordinal = i, - .type = classify_symbol_type(sym->storage_class), - .section_num = sym->section_number, - .value = sym->value - }; - - // Parse string table name stuff - if (sym->long_name[0] == 0) { - // string table access (read a cstring) - // TODO(NeGate): bounds check this - const uint8_t* data = &parser->string_table.data[sym->long_name[1]]; - out_sym->name = (TB_Slice){ strlen((const char*) data), data }; - } else { - // normal inplace string - size_t len = 1; - const char* name = (const char*) sym->short_name; - while (len < 8 && name[len] != 0) { - len++; - } - out_sym->name = (TB_Slice){ len, sym->short_name }; - } - - // TODO(NeGate): Process aux symbols - if (sym->aux_symbols_count) { - out_sym->extra = &sym[1]; - - // FOREACH_N(j, 0, sym->aux_symbols_count) {} - } - - return sym->aux_symbols_count + 1; -} - -#endif // TB_COFF_IMPL diff --git a/src/tilde/tb_elf.h b/src/tilde/tb_elf.h deleted file mode 100644 index 5260d7372..000000000 --- a/src/tilde/tb_elf.h +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef TB_ELF_H -#define TB_ELF_H - -#include - -#define TB_EI_MAG0 0 -#define TB_EI_MAG1 1 -#define TB_EI_MAG2 2 -#define TB_EI_MAG3 3 -#define TB_EI_CLASS 4 /* Class of machine. */ -#define TB_EI_DATA 5 /* Data format. */ -#define TB_EI_VERSION 6 /* ELF format version. */ -#define TB_EI_OSABI 7 /* Operating system / ABI identification */ -#define TB_EI_ABIVERSION 8 /* ABI version */ -#define TB_OLD_EI_BRAND 8 /* Start of architecture identification. */ -#define TB_EI_PAD 9 /* Start of padding (per SVR4 ABI). */ -#define TB_EI_NIDENT 16 /* Size of e_ident array. */ - -/* Values for e_type. */ -#define TB_ET_NONE 0 /* Unknown type. */ -#define TB_ET_REL 1 /* Relocatable. */ -#define TB_ET_EXEC 2 /* Executable. */ -#define TB_ET_DYN 3 /* Shared object. */ -#define TB_ET_CORE 4 /* Core file. */ -#define TB_ET_LOOS 0xfe00 /* First operating system specific. */ -#define TB_ET_HIOS 0xfeff /* Last operating system-specific. */ -#define TB_ET_LOPROC 0xff00 /* First processor-specific. */ -#define TB_ET_HIPROC 0xffff /* Last processor-specific. */ - -/* Values for e_machine. */ -#define TB_EM_NONE 0 /* Unknown machine. */ -#define TB_EM_X86_64 62 /* Advanced Micro Devices x86-64 */ -#define TB_EM_AARCH64 183 /* AArch64 (64-bit ARM) */ - -/* sh_type */ -#define TB_SHT_NULL 0 /* inactive */ -#define TB_SHT_PROGBITS 1 /* program defined information */ -#define TB_SHT_SYMTAB 2 /* symbol table section */ -#define TB_SHT_STRTAB 3 /* string table section */ -#define TB_SHT_RELA 4 /* relocation section with addends */ -#define TB_SHT_NOBITS 8 /* no space section */ - -/* Flags for sh_flags. */ -#define TB_SHF_WRITE 0x1 /* Section contains writable data. */ -#define TB_SHF_ALLOC 0x2 /* Section occupies memory. */ -#define TB_SHF_EXECINSTR 0x4 /* Section contains instructions. */ -#define TB_SHF_MERGE 0x10 /* Section may be merged. */ -#define TB_SHF_STRINGS 0x20 /* Section contains strings. */ -#define TB_SHF_INFO_LINK 0x40 /* sh_info holds section index. */ -#define TB_SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ -#define TB_SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ -#define TB_SHF_GROUP 0x200 /* Member of section group. */ -#define TB_SHF_TLS 0x400 /* Section contains TLS data. */ -#define TB_SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ -#define TB_SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ - -/* Values for p_flags. */ -#define TB_PF_X 0x1 /* Executable. */ -#define TB_PF_W 0x2 /* Writable. */ -#define TB_PF_R 0x4 /* Readable. */ -#define TB_PF_MASKOS 0x0ff00000 /* Operating system-specific. */ -#define TB_PF_MASKPROC 0xf0000000 /* Processor-specific. */ - -/* Values for p_type. */ -#define TB_PT_NULL 0 /* Unused entry. */ -#define TB_PT_LOAD 1 /* Loadable segment. */ -#define TB_PT_DYNAMIC 2 /* Dynamic linking information segment. */ -#define TB_PT_INTERP 3 /* Pathname of interpreter. */ -#define TB_PT_NOTE 4 /* Auxiliary information. */ -#define TB_PT_SHLIB 5 /* Reserved (not used). */ -#define TB_PT_PHDR 6 /* Location of program header itself. */ -#define TB_PT_TLS 7 /* Thread local storage segment */ - -/* Values for relocation */ -typedef enum { - TB_ELF_X86_64_NONE = 0, - TB_ELF_X86_64_64 = 1, - TB_ELF_X86_64_PC32 = 2, - TB_ELF_X86_64_GOT32 = 3, - TB_ELF_X86_64_PLT32 = 4, - TB_ELF_X86_64_GOTPCREL = 9, -} TB_ELF_RelocType; - -// ST_TYPE -#define TB_ELF64_STT_NOTYPE 0 -#define TB_ELF64_STT_OBJECT 1 -#define TB_ELF64_STT_FUNC 2 -#define TB_ELF64_STT_SECTION 3 - -// ST_INFO -#define TB_ELF64_STB_LOCAL 0 -#define TB_ELF64_STB_GLOBAL 1 -#define TB_ELF64_STB_WEAK 2 - -/* Macros for accessing the fields of st_info. */ -#define TB_ELF64_ST_BIND(info) ((info) >> 4) -#define TB_ELF64_ST_TYPE(info) ((info) & 0xf) - -#define TB_ELF64_ST_INFO(b, t) (((b) << 4) | ((t) & 0xF)) - -#define TB_ELF64_R_SYM(i) ((i) >> 32u) -#define TB_ELF64_R_TYPE(i) ((i)&0xffffffffULL) -#define TB_ELF64_R_INFO(s, t) (((uint64_t)(s) << 32ULL) + ((uint64_t)(t) & 0xffffffffULL)) - -// http://web.mit.edu/freebsd/head/sys/sys/elf64.h -// https://cirosantilli.com/elf-hello-world#minimal-elf-file -// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format -typedef struct { - uint8_t ident[16]; - uint16_t type; - uint16_t machine; - uint32_t version; - uint64_t entry; - uint64_t phoff; - uint64_t shoff; - uint32_t flags; - uint16_t ehsize; - uint16_t phentsize; - uint16_t phnum; - uint16_t shentsize; - uint16_t shnum; - uint16_t shstrndx; -} TB_Elf64_Ehdr; - -typedef struct { - uint32_t name; - uint32_t type; - uint64_t flags; - uint64_t addr; - uint64_t offset; - uint64_t size; - uint32_t link; - uint32_t info; - uint64_t addralign; - uint64_t entsize; -} TB_Elf64_Shdr; - -// Segment header for ELF64. -typedef struct { - uint32_t type; // Type of segment - uint32_t flags; // Segment flags - uint64_t offset; // File offset where segment is located, in bytes - uint64_t vaddr; // Virtual address of beginning of segment - uint64_t paddr; // Physical addr of beginning of segment (OS-specific) - uint64_t filesz; // Num. of bytes in file image of segment (may be zero) - uint64_t memsz; // Num. of bytes in mem image of segment (may be zero) - uint64_t align; // Segment alignment constraint -} TB_Elf64_Phdr; - -typedef struct { - uint32_t name; - uint8_t info; - uint8_t other; - uint16_t shndx; - uint64_t value; - uint64_t size; -} TB_Elf64_Sym; - -typedef struct { - uint64_t offset; - uint64_t info; - int64_t addend; -} TB_Elf64_Rela; - -typedef struct { - uint64_t offset; - uint64_t info; -} TB_Elf64_Rel; - -#endif /* TB_ELF_H */ diff --git a/src/tilde/tb_formats.h b/src/tilde/tb_formats.h deleted file mode 100644 index 1975d5848..000000000 --- a/src/tilde/tb_formats.h +++ /dev/null @@ -1,132 +0,0 @@ -// This handles the generalized executable/object format parsing stuff -#ifndef TB_OBJECT_H -#define TB_OBJECT_H - -#include -#include - -typedef enum { - TB_OBJECT_RELOC_NONE, // how? - - // Target independent - TB_OBJECT_RELOC_ADDR32, - TB_OBJECT_RELOC_ADDR64, // unsupported on 32bit platforms - TB_OBJECT_RELOC_SECREL, - TB_OBJECT_RELOC_SECTION, - - // COFF only - TB_OBJECT_RELOC_ADDR32NB, // Relative virtual address - - // x64 only - TB_OBJECT_RELOC_REL32, // relative 32bit displacement - - // Aarch64 only - TB_OBJECT_RELOC_BRANCH26, // 26bit displacement for B and BL instructions - TB_OBJECT_RELOC_REL21, // for ADR instructions - - // TODO(NeGate): fill in the rest of this later -} TB_ObjectRelocType; - -typedef struct { - TB_ObjectRelocType type; - uint32_t symbol_index; - size_t virtual_address; - size_t addend; -} TB_ObjectReloc; - -typedef enum { - TB_OBJECT_SYMBOL_UNKNOWN, - TB_OBJECT_SYMBOL_EXTERN, // exported - TB_OBJECT_SYMBOL_WEAK_EXTERN, // weak - TB_OBJECT_SYMBOL_IMPORT, // forward decl - TB_OBJECT_SYMBOL_STATIC, // local - TB_OBJECT_SYMBOL_SECTION, // local -} TB_ObjectSymbolType; - -typedef struct { - TB_ObjectSymbolType type; - int section_num; - - uint32_t ordinal; - uint32_t value; - - TB_Slice name; - - // for COFF, this is the auxillary - void* extra; - - // this is zeroed out by the loader and left for the user to do crap with - void* user_data; -} TB_ObjectSymbol; - -typedef struct { - TB_Slice name; - uint32_t flags; - - size_t virtual_address; - size_t virtual_size; - - // You can have a virtual size without having a raw - // data size, that's how the BSS section works - TB_Slice raw_data; - - size_t relocation_count; - TB_ObjectReloc* relocations; - - // this is zeroed out by the loader and left for the user to do crap with - void* user_data; -} TB_ObjectSection; - -typedef enum { - TB_OBJECT_FILE_UNKNOWN, - - TB_OBJECT_FILE_COFF, - TB_OBJECT_FILE_ELF64 -} TB_ObjectFileType; - -typedef struct { - TB_ObjectFileType type; - TB_Arch arch; - - TB_Slice name; - TB_Slice ar_name; - - size_t symbol_count; - TB_ObjectSymbol* symbols; - - size_t section_count; - TB_ObjectSection sections[]; -} TB_ObjectFile; - -//////////////////////////////// -// Archive parser -//////////////////////////////// -typedef struct { - TB_Slice name; - - // if import_name is empty, we're dealing with an object file - TB_Slice import_name; - uint16_t ordinal; - - TB_Slice content; -} TB_ArchiveEntry; - -typedef struct { - TB_Slice file; - size_t pos; - - size_t member_count; - uint32_t* members; - - size_t symbol_count; - uint16_t* symbols; - - TB_Slice strtbl; -} TB_ArchiveFileParser; - -// We do this to parse the header -bool tb_archive_parse(TB_Slice file, TB_ArchiveFileParser* restrict out_parser); -// After that we can enumerate any symbol entries to resolve imports -size_t tb_archive_parse_entries(TB_ArchiveFileParser* restrict parser, size_t i, size_t count, TB_ArchiveEntry* out_entry); - -#endif // TB_OBJECT_H diff --git a/src/tilde/tb_x64.h b/src/tilde/tb_x64.h deleted file mode 100644 index 58b3d656c..000000000 --- a/src/tilde/tb_x64.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef TB_X64_H -#define TB_X64_H - -#include -#include - -typedef enum { - // uses xmm registers for the reg array - TB_X86_INSTR_XMMREG = (1u << 0u), - - // r/m is a memory operand - TB_X86_INSTR_USE_MEMOP = (1u << 1u), - - // r/m is a rip-relative address (TB_X86_INSTR_USE_MEMOP is always set when this is set) - TB_X86_INSTR_USE_RIPMEM = (1u << 2u), - - // LOCK prefix is present - TB_X86_INSTR_LOCK = (1u << 3u), - - // uses a signed immediate - TB_X86_INSTR_IMMEDIATE = (1u << 4u), - - // absolute means it's using the 64bit immediate (cannot be applied while a memory operand is active) - TB_X86_INSTR_ABSOLUTE = (1u << 5u), - - // set if the r/m can be found on the right hand side - TB_X86_INSTR_DIRECTION = (1u << 6u), - - // uses the second data type because the instruction is weird like MOVSX or MOVZX - TB_X86_INSTR_TWO_DATA_TYPES = (1u << 7u), - - // REP prefix is present - TB_X86_INSTR_REP = (1u << 8u), - - // REPNE prefix is present - TB_X86_INSTR_REPNE = (1u << 9u), -} TB_X86_InstFlags; - -typedef enum { - TB_X86_RAX, TB_X86_RCX, TB_X86_RDX, TB_X86_RBX, TB_X86_RSP, TB_X86_RBP, TB_X86_RSI, TB_X86_RDI, - TB_X86_R8, TB_X86_R9, TB_X86_R10, TB_X86_R11, TB_X86_R12, TB_X86_R13, TB_X86_R14, TB_X86_R15, -} TB_X86_GPR; - -typedef enum { - TB_X86_SEGMENT_DEFAULT = 0, - - TB_X86_SEGMENT_ES, TB_X86_SEGMENT_CS, - TB_X86_SEGMENT_SS, TB_X86_SEGMENT_DS, - TB_X86_SEGMENT_GS, TB_X86_SEGMENT_FS, -} TB_X86_Segment; - -typedef enum { - TB_X86_TYPE_NONE = 0, - - TB_X86_TYPE_BYTE, // 1 - TB_X86_TYPE_WORD, // 2 - TB_X86_TYPE_DWORD, // 4 - TB_X86_TYPE_QWORD, // 8 - - TB_X86_TYPE_PBYTE, // int8 x 16 = 16 - TB_X86_TYPE_PWORD, // int16 x 8 = 16 - TB_X86_TYPE_PDWORD, // int32 x 4 = 16 - TB_X86_TYPE_PQWORD, // int64 x 2 = 16 - - TB_X86_TYPE_SSE_SS, // float32 x 1 = 4 - TB_X86_TYPE_SSE_SD, // float64 x 1 = 8 - TB_X86_TYPE_SSE_PS, // float32 x 4 = 16 - TB_X86_TYPE_SSE_PD, // float64 x 2 = 16 - - TB_X86_TYPE_XMMWORD, // the generic idea of them -} TB_X86_DataType; - -typedef struct { - int32_t opcode; - - // registers (there's 4 max taking up 8bit slots each) - int8_t regs[4]; - uint16_t flags; - - // bitpacking amirite - TB_X86_DataType data_type : 8; - TB_X86_DataType data_type2 : 8; - TB_X86_Segment segment : 4; - uint8_t length : 4; - - // memory operand - // X86_INSTR_USE_MEMOP - uint8_t base, index, scale; - int32_t disp; - - // immediate operand - // imm for INSTR_IMMEDIATE - // abs for INSTR_ABSOLUTE - union { - int32_t imm; - uint64_t abs; - }; -} TB_X86_Inst; - -bool tb_x86_disasm(TB_X86_Inst* restrict inst, size_t length, const uint8_t* data); -const char* tb_x86_reg_name(int8_t reg, TB_X86_DataType dt); -const char* tb_x86_type_name(TB_X86_DataType dt); -const char* tb_x86_mnemonic(TB_X86_Inst* inst); - -#endif /* TB_X64_H */ diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp deleted file mode 100644 index 3b4e4f900..000000000 --- a/src/tilde_builtin.cpp +++ /dev/null @@ -1,592 +0,0 @@ -gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value) { - Type *t = base_type(value.type); - - switch (t->kind) { - case Type_Basic: - switch (t->Basic.kind) { - case Basic_string: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); - return cg_emit_load(p, len_ptr); - } - case Basic_cstring: - GB_PANIC("TODO(bill): len(cstring)"); - break; - } - break; - case Type_Array: - return cg_const_int(p, t_int, t->Array.count); - case Type_EnumeratedArray: - return cg_const_int(p, t_int, t->EnumeratedArray.count); - case Type_Slice: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); - return cg_emit_load(p, len_ptr); - } - case Type_DynamicArray: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); - return cg_emit_load(p, len_ptr); - } - case Type_Map: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); - return cg_emit_conv(p, cg_emit_load(p, len_ptr), t_int); - } - case Type_Struct: - GB_ASSERT(is_type_soa_struct(t)); - { - if (t->Struct.soa_kind == StructSoa_Fixed) { - return cg_const_int(p, t_int, t->Struct.soa_count); - } - - GB_ASSERT(t->Struct.soa_kind == StructSoa_Slice || - t->Struct.soa_kind == StructSoa_Dynamic); - - isize n = 0; - Type *elem = base_type(t->Struct.soa_elem); - if (elem->kind == Type_Struct) { - n = cast(isize)elem->Struct.fields.count; - } else if (elem->kind == Type_Array) { - n = cast(isize)elem->Array.count; - } else { - GB_PANIC("Unreachable"); - } - - return cg_emit_struct_ev(p, value, n); - } - break; - } - - GB_PANIC("TODO(bill): cg_builtin_len %s", type_to_string(t)); - return {}; -} - -gb_internal cgValue cg_builtin_cap(cgProcedure *p, cgValue value) { - Type *t = base_type(value.type); - - switch (t->kind) { - case Type_Basic: - switch (t->Basic.kind) { - case Basic_string: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); - return cg_emit_load(p, len_ptr); - } - case Basic_cstring: - GB_PANIC("TODO(bill): cap(cstring)"); - break; - } - break; - case Type_Array: - return cg_const_int(p, t_int, t->Array.count); - case Type_EnumeratedArray: - return cg_const_int(p, t_int, t->EnumeratedArray.count); - case Type_Slice: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); - return cg_emit_load(p, len_ptr); - } - case Type_DynamicArray: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue len_ptr = cg_emit_struct_ep(p, ptr, 2); - return cg_emit_load(p, len_ptr); - } - case Type_Map: - { - TB_DataType dt_uintptr = cg_data_type(t_uintptr); - TB_Node *zero = tb_inst_uint(p->func, dt_uintptr, 0); - TB_Node *one = tb_inst_uint(p->func, dt_uintptr, 0); - TB_Node *mask = tb_inst_uint(p->func, dt_uintptr, MAP_CACHE_LINE_SIZE-1); - - TB_Node *data = cg_emit_struct_ev(p, value, 0).node; - TB_Node *log2_cap = tb_inst_and(p->func, data, mask); - TB_Node *cap = tb_inst_shl(p->func, one, log2_cap, cast(TB_ArithmeticBehavior)0); - TB_Node *cmp = tb_inst_cmp_eq(p->func, data, zero); - - cgValue res = cg_value(tb_inst_select(p->func, cmp, zero, cap), t_uintptr); - return cg_emit_conv(p, res, t_int); - } - case Type_Struct: - GB_ASSERT(is_type_soa_struct(t)); - break; - } - - GB_PANIC("TODO(bill): cg_builtin_cap %s", type_to_string(t)); - return {}; -} - - -gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) { - Type *t = base_type(value.type); - cgValue res = {}; - switch (t->kind) { - case Type_Slice: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0); - res = cg_emit_load(p, data_ptr); - GB_ASSERT(is_type_multi_pointer(res.type)); - } - break; - case Type_DynamicArray: - { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0); - res = cg_emit_load(p, data_ptr); - } - break; - case Type_Basic: - if (t->Basic.kind == Basic_string) { - GB_ASSERT(value.kind == cgValue_Addr); - cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); - cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0); - res = cg_emit_load(p, data_ptr); - } else if (t->Basic.kind == Basic_cstring) { - res = cg_emit_conv(p, value, t_u8_multi_ptr); - } - break; - case Type_Pointer: - GB_ASSERT(is_type_array_like(t->Pointer.elem)); - GB_ASSERT(value.kind == cgValue_Value); - res = cg_value(value.node, alloc_type_multi_pointer(base_array_type(t->Pointer.elem))); - break; - case Type_MultiPointer: - - GB_PANIC("TODO(bill) %s", type_to_string(value.type)); - // res = cg_emit_conv(p, value, tv.type); - break; - } - GB_ASSERT(res.node != nullptr); - return res; -} - -gb_internal cgValue cg_builtin_min(cgProcedure *p, Type *t, cgValue x, cgValue y) { - x = cg_emit_conv(p, x, t); - y = cg_emit_conv(p, y, t); - return cg_emit_select(p, cg_emit_comp(p, Token_Lt, x, y), x, y); -} -gb_internal cgValue cg_builtin_max(cgProcedure *p, Type *t, cgValue x, cgValue y) { - x = cg_emit_conv(p, x, t); - y = cg_emit_conv(p, y, t); - return cg_emit_select(p, cg_emit_comp(p, Token_Gt, x, y), x, y); -} - -gb_internal cgValue cg_builtin_abs(cgProcedure *p, cgValue const &x) { - if (is_type_unsigned(x.type)) { - return x; - } - - if (is_type_quaternion(x.type)) { - GB_PANIC("TODO(bill): abs quaternion"); - } else if (is_type_complex(x.type)) { - GB_PANIC("TODO(bill): abs complex"); - } - - TB_DataType dt = cg_data_type(x.type); - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); - TB_Node *zero = nullptr; - if (dt.type == TB_FLOAT) { - if (dt.data == 32) { - zero = tb_inst_float32(p->func, 0); - } else if (dt.data == 64) { - zero = tb_inst_float64(p->func, 0); - } - } else { - zero = tb_inst_uint(p->func, dt, 0); - } - GB_ASSERT(zero != nullptr); - - cgValue cond = cg_emit_comp(p, Token_Lt, x, cg_value(zero, x.type)); - cgValue neg = cg_emit_unary_arith(p, Token_Sub, x, x.type); - return cg_emit_select(p, cond, neg, x); -} - -gb_internal cgValue cg_builtin_clamp(cgProcedure *p, Type *t, cgValue const &x, cgValue const &min, cgValue const &max) { - cgValue z = x; - z = cg_builtin_max(p, t, z, min); - z = cg_builtin_min(p, t, z, max); - return z; -} - - - -gb_internal cgValue cg_builtin_mem_zero(cgProcedure *p, cgValue const &ptr, cgValue const &len) { - GB_ASSERT(ptr.kind == cgValue_Value); - GB_ASSERT(len.kind == cgValue_Value); - tb_inst_memzero(p->func, ptr.node, len.node, 1); - return ptr; -} - -gb_internal cgValue cg_builtin_mem_copy(cgProcedure *p, cgValue const &dst, cgValue const &src, cgValue const &len) { - GB_ASSERT(dst.kind == cgValue_Value); - GB_ASSERT(src.kind == cgValue_Value); - GB_ASSERT(len.kind == cgValue_Value); - // TODO(bill): This needs to be memmove - tb_inst_memcpy(p->func, dst.node, src.node, len.node, 1); - return dst; -} - -gb_internal cgValue cg_builtin_mem_copy_non_overlapping(cgProcedure *p, cgValue const &dst, cgValue const &src, cgValue const &len) { - GB_ASSERT(dst.kind == cgValue_Value); - GB_ASSERT(src.kind == cgValue_Value); - GB_ASSERT(len.kind == cgValue_Value); - tb_inst_memcpy(p->func, dst.node, src.node, len.node, 1); - return dst; -} - -gb_internal TB_Symbol *cg_builtin_map_cell_info_symbol(cgModule *m, Type *type) { - MUTEX_GUARD(&m->map_info_mutex); - TB_Symbol **found = map_get(&m->map_cell_info_map, type); - if (found) { - return *found; - } - i64 size = 0, len = 0; - map_cell_size_and_len(type, &size, &len); - - TB_Global *global = tb_global_create(m->mod, 0, "", cg_debug_type(m, t_map_cell_info), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_map_cell_info), type_align_of(t_map_cell_info), 4); - - i64 ptr_size = build_context.ptr_size; - void *size_of_type = tb_global_add_region(m->mod, global, 0*ptr_size, ptr_size); - void *align_of_type = tb_global_add_region(m->mod, global, 1*ptr_size, ptr_size); - void *size_of_cell = tb_global_add_region(m->mod, global, 2*ptr_size, ptr_size); - void *elements_per_cell = tb_global_add_region(m->mod, global, 3*ptr_size, ptr_size); - - cg_write_uint_at_ptr(size_of_type, type_size_of(type), t_uintptr); - cg_write_uint_at_ptr(align_of_type, type_align_of(type), t_uintptr); - cg_write_uint_at_ptr(size_of_cell, size, t_uintptr); - cg_write_uint_at_ptr(elements_per_cell, len, t_uintptr); - - map_set(&m->map_cell_info_map, type, cast(TB_Symbol *)global); - - return cast(TB_Symbol *)global; -} - - -gb_internal cgValue cg_builtin_map_cell_info(cgProcedure *p, Type *type) { - type = core_type(type); - TB_Symbol *symbol = cg_builtin_map_cell_info_symbol(p->module, type); - TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); - return cg_value(node, t_map_cell_info_ptr); -} - -gb_internal cgValue cg_builtin_map_info(cgProcedure *p, Type *map_type) { - map_type = base_type(map_type); - GB_ASSERT(map_type->kind == Type_Map); - - cgModule *m = p->module; - MUTEX_GUARD(&m->map_info_mutex); - TB_Global *global = nullptr; - TB_Symbol **found = map_get(&m->map_info_map, map_type); - if (found) { - global = cast(TB_Global *)*found; - } else { - global = tb_global_create(m->mod, 0, "", cg_debug_type(m, t_map_info), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_map_info), type_align_of(t_map_info), 4); - - TB_Symbol *key_cell_info = cg_builtin_map_cell_info_symbol(m, map_type->Map.key); - TB_Symbol *value_cell_info = cg_builtin_map_cell_info_symbol(m, map_type->Map.value); - cgProcedure *key_hasher = cg_hasher_proc_for_type(p->module, map_type->Map.key); - cgProcedure *key_equal = cg_equal_proc_for_type (p->module, map_type->Map.key); - - tb_global_add_symbol_reloc(p->module->mod, global, 0*build_context.ptr_size, key_cell_info); - tb_global_add_symbol_reloc(p->module->mod, global, 1*build_context.ptr_size, value_cell_info); - tb_global_add_symbol_reloc(p->module->mod, global, 2*build_context.ptr_size, key_hasher->symbol); - tb_global_add_symbol_reloc(p->module->mod, global, 3*build_context.ptr_size, key_equal->symbol); - - map_set(&m->map_info_map, map_type, cast(TB_Symbol *)global); - } - - GB_ASSERT(global != nullptr); - TB_Node *node = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); - return cg_value(node, t_map_info_ptr); -} - - - - -gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) { - ast_node(ce, CallExpr, expr); - - if (BuiltinProc__simd_begin < id && id < BuiltinProc__simd_end) { - GB_PANIC("TODO(bill): cg_build_builtin_simd_proc"); - // return cg_build_builtin_simd_proc(p, expr, tv, id); - } - - String builtin_name = builtin_procs[id].name; - - switch (id) { - case BuiltinProc_DIRECTIVE: { - ast_node(bd, BasicDirective, ce->proc); - String name = bd->name.string; - GB_ASSERT(name == "location"); - String procedure = p->entity->token.string; - TokenPos pos = ast_token(ce->proc).pos; - if (ce->args.count > 0) { - Ast *ident = unselector_expr(ce->args[0]); - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - - if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { - procedure = e->parent_proc_decl->entity->token.string; - } else { - procedure = str_lit(""); - } - pos = e->token.pos; - - } - return cg_emit_source_code_location_as_global(p, procedure, pos); - } break; - - case BuiltinProc_len: { - cgValue v = cg_build_expr(p, ce->args[0]); - Type *t = base_type(v.type); - if (is_type_pointer(t)) { - // IMPORTANT TODO(bill): Should there be a nil pointer check? - v = cg_emit_load(p, v); - t = type_deref(t); - } - return cg_builtin_len(p, v); - } - - case BuiltinProc_cap: { - cgValue v = cg_build_expr(p, ce->args[0]); - Type *t = base_type(v.type); - if (is_type_pointer(t)) { - // IMPORTANT TODO(bill): Should there be a nil pointer check? - v = cg_emit_load(p, v); - t = type_deref(t); - } - return cg_builtin_cap(p, v); - } - - case BuiltinProc_raw_data: - { - cgValue v = cg_build_expr(p, ce->args[0]); - return cg_builtin_raw_data(p, v); - } - - case BuiltinProc_min: - if (ce->args.count == 2) { - Type *t = type_of_expr(expr); - cgValue x = cg_build_expr(p, ce->args[0]); - cgValue y = cg_build_expr(p, ce->args[1]); - return cg_builtin_min(p, t, x, y); - } else { - Type *t = type_of_expr(expr); - cgValue x = cg_build_expr(p, ce->args[0]); - for (isize i = 1; i < ce->args.count; i++) { - cgValue y = cg_build_expr(p, ce->args[i]); - x = cg_builtin_min(p, t, x, y); - } - return x; - } - break; - case BuiltinProc_max: - if (ce->args.count == 2) { - Type *t = type_of_expr(expr); - cgValue x = cg_build_expr(p, ce->args[0]); - cgValue y = cg_build_expr(p, ce->args[1]); - return cg_builtin_max(p, t, x, y); - } else { - Type *t = type_of_expr(expr); - cgValue x = cg_build_expr(p, ce->args[0]); - for (isize i = 1; i < ce->args.count; i++) { - cgValue y = cg_build_expr(p, ce->args[i]); - x = cg_builtin_max(p, t, x, y); - } - return x; - } - break; - - case BuiltinProc_abs: - { - cgValue x = cg_build_expr(p, ce->args[0]); - return cg_builtin_abs(p, x); - } - - case BuiltinProc_clamp: - { - cgValue x = cg_build_expr(p, ce->args[0]); - cgValue min = cg_build_expr(p, ce->args[1]); - cgValue max = cg_build_expr(p, ce->args[2]); - return cg_builtin_clamp(p, type_of_expr(expr), x, min, max); - } - - case BuiltinProc_debug_trap: - tb_inst_debugbreak(p->func); - return {}; - case BuiltinProc_trap: - tb_inst_trap(p->func); - return {}; - - case BuiltinProc_mem_zero: - { - cgValue ptr = cg_build_expr(p, ce->args[0]); - cgValue len = cg_build_expr(p, ce->args[1]); - return cg_builtin_mem_zero(p, ptr, len); - } - - case BuiltinProc_mem_copy: - { - cgValue dst = cg_build_expr(p, ce->args[0]); - cgValue src = cg_build_expr(p, ce->args[1]); - cgValue len = cg_build_expr(p, ce->args[2]); - return cg_builtin_mem_copy(p, dst, src, len); - } - - case BuiltinProc_mem_copy_non_overlapping: - { - cgValue dst = cg_build_expr(p, ce->args[0]); - cgValue src = cg_build_expr(p, ce->args[1]); - cgValue len = cg_build_expr(p, ce->args[2]); - return cg_builtin_mem_copy_non_overlapping(p, dst, src, len); - } - - - case BuiltinProc_overflow_add: - { - Type *res_type = type_of_expr(expr); - GB_ASSERT(res_type->kind == Type_Tuple); - GB_ASSERT(res_type->Tuple.variables.count == 2); - // TODO(bill): do a proper overflow add - Type *type = res_type->Tuple.variables[0]->type; - Type *ok_type = res_type->Tuple.variables[1]->type; - cgValue x = cg_build_expr(p, ce->args[0]); - cgValue y = cg_build_expr(p, ce->args[1]); - x = cg_emit_conv(p, x, type); - y = cg_emit_conv(p, y, type); - cgValue res = cg_emit_arith(p, Token_Add, x, y, type); - cgValue ok = cg_const_int(p, ok_type, false); - - return cg_value_multi2(res, ok, res_type); - } - - - case BuiltinProc_ptr_offset: - { - cgValue ptr = cg_build_expr(p, ce->args[0]); - cgValue len = cg_build_expr(p, ce->args[1]); - len = cg_emit_conv(p, len, t_int); - return cg_emit_ptr_offset(p, ptr, len); - } - case BuiltinProc_ptr_sub: - { - Type *elem0 = type_deref(type_of_expr(ce->args[0])); - Type *elem1 = type_deref(type_of_expr(ce->args[1])); - GB_ASSERT(are_types_identical(elem0, elem1)); - Type *elem = elem0; - - cgValue ptr0 = cg_emit_conv(p, cg_build_expr(p, ce->args[0]), t_uintptr); - cgValue ptr1 = cg_emit_conv(p, cg_build_expr(p, ce->args[1]), t_uintptr); - - cgValue diff = cg_emit_arith(p, Token_Sub, ptr0, ptr1, t_uintptr); - diff = cg_emit_conv(p, diff, t_int); - return cg_emit_arith(p, Token_Quo, diff, cg_const_int(p, t_int, type_size_of(elem)), t_int); - } - - case BuiltinProc_type_info_of: - { - Ast *arg = ce->args[0]; - TypeAndValue tav = type_and_value_of_expr(arg); - if (tav.mode == Addressing_Type) { - Type *t = default_type(type_of_expr(arg)); - return cg_type_info(p, t); - } - GB_ASSERT(is_type_typeid(tav.type)); - - auto args = slice_make(permanent_allocator(), 1); - args[0] = cg_build_expr(p, arg); - return cg_emit_runtime_call(p, "__type_info_of", args); - } - - - case BuiltinProc_type_equal_proc: - return cg_equal_proc_value_for_type(p, ce->args[0]->tav.type); - - case BuiltinProc_type_hasher_proc: - return cg_hasher_proc_value_for_type(p, ce->args[0]->tav.type); - - case BuiltinProc_type_map_cell_info: - return cg_builtin_map_cell_info(p, ce->args[0]->tav.type); - case BuiltinProc_type_map_info: - return cg_builtin_map_info(p, ce->args[0]->tav.type); - - case BuiltinProc_expect: - { - Type *t = default_type(expr->tav.type); - cgValue x = cg_emit_conv(p, cg_build_expr(p, ce->args[0]), t); - cgValue y = cg_emit_conv(p, cg_build_expr(p, ce->args[1]), t); - gb_unused(y); - return x; - } - - case BuiltinProc_count_leading_zeros: - { - cgValue n = cg_build_expr(p, ce->args[0]); - n = cg_emit_conv(p, n, default_type(expr->tav.type)); - GB_ASSERT(n.kind == cgValue_Value); - TB_Node *val = tb_inst_clz(p->func, n.node); - val = tb_inst_zxt(p->func, val, cg_data_type(n.type)); - return cg_value(val, n.type); - } - - - case BuiltinProc_count_trailing_zeros: - { - cgValue n = cg_build_expr(p, ce->args[0]); - n = cg_emit_conv(p, n, default_type(expr->tav.type)); - GB_ASSERT(n.kind == cgValue_Value); - TB_Node *val = tb_inst_ctz(p->func, n.node); - val = tb_inst_zxt(p->func, val, cg_data_type(n.type)); - return cg_value(val, n.type); - } - - case BuiltinProc_count_ones: - { - cgValue n = cg_build_expr(p, ce->args[0]); - n = cg_emit_conv(p, n, default_type(expr->tav.type)); - GB_ASSERT(n.kind == cgValue_Value); - TB_Node *val = tb_inst_popcount(p->func, n.node); - val = tb_inst_zxt(p->func, val, cg_data_type(n.type)); - return cg_value(val, n.type); - } - - case BuiltinProc_count_zeros: - { - cgValue n = cg_build_expr(p, ce->args[0]); - n = cg_emit_conv(p, n, default_type(expr->tav.type)); - GB_ASSERT(n.kind == cgValue_Value); - TB_DataType dt = cg_data_type(n.type); - TB_Node *ones = tb_inst_popcount(p->func, n.node); - ones = tb_inst_zxt(p->func, ones, dt); - - cgValue size = cg_const_int(p, n.type, 8*type_size_of(n.type)); - return cg_emit_arith(p, Token_Sub, size, cg_value(ones, n.type), n.type); - } - - } - - - GB_PANIC("TODO(bill): builtin procs %d %.*s", id, LIT(builtin_name)); - return {}; -} - diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp deleted file mode 100644 index 456b2cdc7..000000000 --- a/src/tilde_const.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -gb_internal bool cg_is_expr_constant_zero(Ast *expr) { - GB_ASSERT(expr != nullptr); - auto v = exact_value_to_integer(expr->tav.value); - if (v.kind == ExactValue_Integer) { - return big_int_cmp_zero(&v.value_integer) == 0; - } - return false; -} - -gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, Type *type) { - GB_ASSERT(m != nullptr); - Type *original_type = type; - type = core_type(type); - i64 size = type_size_of(type); - i64 align = type_align_of(type); - TB_DataType dt = cg_data_type(type); - if (TB_IS_VOID_TYPE(dt)) { - char name[32] = {}; - gb_snprintf(name, 31, "cnil$%u", 1+m->const_nil_guid.fetch_add(1)); - TB_Global *global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, size, align, 0); - - TB_Symbol *symbol = cast(TB_Symbol *)global; - if (p) { - TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); - return cg_lvalue_addr(node, type); - } else { - return cg_value(symbol, type); - } - } - - if (is_type_internally_pointer_like(type)) { - return cg_value(tb_inst_uint(p->func, dt, 0), type); - } else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type) || is_type_typeid(type)) { - return cg_value(tb_inst_uint(p->func, dt, 0), type); - } else if (is_type_float(type)) { - switch (size) { - case 2: - return cg_value(tb_inst_uint(p->func, dt, 0), type); - case 4: - return cg_value(tb_inst_float32(p->func, 0), type); - case 8: - return cg_value(tb_inst_float64(p->func, 0), type); - } - } - GB_PANIC("TODO(bill): cg_const_nil %s", type_to_string(original_type)); - return {}; -} - -gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { - return cg_const_nil(p->module, p, type); -} - -gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Type *type, TB_Global *global, i64 offset); -gb_internal void cg_write_int_at_ptr(void *dst, i64 i, Type *original_type); - -gb_internal void cg_global_source_code_location_const(cgModule *m, String const &proc_name, TokenPos pos, TB_Global *global, i64 offset) { - // Source_Code_Location :: struct { - // file_path: string, - // line, column: i32, - // procedure: string, - // } - - i64 file_path_offset = type_offset_of(t_source_code_location, 0); - i64 line_offset = type_offset_of(t_source_code_location, 1); - i64 column_offset = type_offset_of(t_source_code_location, 2); - i64 procedure_offset = type_offset_of(t_source_code_location, 3); - - String file_path = get_file_path_string(pos.file_id); - if (file_path.len != 0) { - cg_global_const_string(m, file_path, t_string, global, offset+file_path_offset); - } - - void *line_ptr = tb_global_add_region(m->mod, global, offset+line_offset, 4); - void *column_ptr = tb_global_add_region(m->mod, global, offset+column_offset, 4); - cg_write_int_at_ptr(line_ptr, pos.line, t_i32); - cg_write_int_at_ptr(column_ptr, pos.column, t_i32); - - if (proc_name.len != 0) { - cg_global_const_string(m, proc_name, t_string, global, offset+procedure_offset); - } -} - - -gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) { - cgModule *m = p->module; - char name[32] = {}; - gb_snprintf(name, 31, "scl$%u", 1+m->const_nil_guid.fetch_add(1)); - - TB_Global *global = tb_global_create(m->mod, -1, name, cg_debug_type(m, t_source_code_location), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_source_code_location), type_align_of(t_source_code_location), 6); - - cg_global_source_code_location_const(m, proc_name, pos, global, 0); - - TB_Node *ptr = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); - return cg_lvalue_addr(ptr, t_source_code_location); -} - -gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Ast *node) { - String proc_name = p->name; - TokenPos pos = ast_token(node).pos; - return cg_emit_source_code_location_as_global(p, proc_name, pos); -} - -gb_internal void cg_write_big_int_at_ptr(void *dst, BigInt const *a, Type *original_type) { - GB_ASSERT(build_context.endian_kind == TargetEndian_Little); - size_t sz = cast(size_t)type_size_of(original_type); - if (big_int_is_zero(a)) { - gb_memset(dst, 0, sz); - return; - } - u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will be fine :P - u8 *rop = cast(u8 *)rop64; - - size_t max_count = 0; - size_t written = 0; - size_t size = 1; - size_t nails = 0; - mp_endian endian = MP_LITTLE_ENDIAN; - - max_count = mp_pack_count(a, nails, size); - if (sz < max_count) { - debug_print_big_int(a); - gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz);; - } - GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu, type %s", max_count, sz, written, type_to_string(original_type)); - GB_ASSERT(gb_size_of(rop64) >= sz); - - mp_err err = mp_pack(rop, sz, &written, - MP_LSB_FIRST, - size, endian, nails, - a); - GB_ASSERT(err == MP_OKAY); - - if (!is_type_endian_little(original_type)) { - for (size_t i = 0; i < sz/2; i++) { - u8 tmp = rop[i]; - rop[i] = rop[sz-1-i]; - rop[sz-1-i] = tmp; - } - } - - gb_memcopy(dst, rop, sz); - return; -} - - -gb_internal void cg_write_int_at_ptr(void *dst, i64 i, Type *original_type) { - ExactValue v = exact_value_i64(i); - cg_write_big_int_at_ptr(dst, &v.value_integer, original_type); -} -gb_internal void cg_write_uint_at_ptr(void *dst, u64 i, Type *original_type) { - ExactValue v = exact_value_u64(i); - cg_write_big_int_at_ptr(dst, &v.value_integer, original_type); -} - -gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Type *type, TB_Global *global, i64 offset) { - GB_ASSERT(is_type_string(type)); - - char name[32] = {}; - gb_snprintf(name, 31, "csb$%u", 1+m->const_nil_guid.fetch_add(1)); - TB_Global *str_global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - i64 size = str.len+1; - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, size, 1, 1); - u8 *data = cast(u8 *)tb_global_add_region(m->mod, str_global, 0, size); - gb_memcopy(data, str.text, str.len); - data[str.len] = 0; - - if (is_type_cstring(type)) { - if (global) { - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)str_global); - } - return str_global; - } - - if (global == nullptr) { - gb_snprintf(name, 31, "cstr$%u", 1+m->const_nil_guid.fetch_add(1)); - global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(type), type_align_of(type), 2); - } - - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)str_global); - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, str.len, t_int); - - return global; -} - -gb_internal bool cg_elem_type_can_be_constant(Type *t) { - t = base_type(t); - if (t == t_invalid) { - return false; - } - if (is_type_dynamic_array(t) || is_type_map(t)) { - return false; - } - return true; -} - - -gb_internal bool cg_is_elem_const(Ast *elem, Type *elem_type) { - if (!cg_elem_type_can_be_constant(elem_type)) { - return false; - } - if (elem->kind == Ast_FieldValue) { - elem = elem->FieldValue.value; - } - TypeAndValue tav = type_and_value_of_expr(elem); - GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(elem), type_to_string(tav.type)); - return tav.value.kind != ExactValue_Invalid; -} - -gb_internal bool cg_is_nested_possibly_constant(Type *ft, Selection const &sel, Ast *elem) { - GB_ASSERT(!sel.indirect); - for (i32 index : sel.index) { - Type *bt = base_type(ft); - switch (bt->kind) { - case Type_Struct: - // if (bt->Struct.is_raw_union) { - // return false; - // } - ft = bt->Struct.fields[index]->type; - break; - case Type_Array: - ft = bt->Array.elem; - break; - default: - return false; - } - } - return cg_is_elem_const(elem, ft); -} - -gb_internal i64 cg_global_const_calculate_region_count_from_basic_type(Type *type) { - type = core_type(type); - - switch (type->kind) { - case Type_Basic: - switch (type->Basic.kind) { - case Basic_string: // ^u8 + int - case Basic_any: // rawptr + typeid - return 2; - } - return 1; - case Type_Pointer: - case Type_MultiPointer: - return 2; // allows for offsets - case Type_Proc: - return 1; - case Type_Slice: - return 3; // alows for offsets - case Type_DynamicArray: - return 5; - case Type_Map: - return 4; - - case Type_Enum: - case Type_BitSet: - return 1; - - case Type_RelativePointer: - case Type_RelativeMultiPointer: - return 2; // allows for offsets - - case Type_Matrix: - return 1; - - case Type_Array: - { - Type *elem = type->Array.elem; - i64 count = cg_global_const_calculate_region_count_from_basic_type(elem); - return count*type->Array.count; - } - case Type_EnumeratedArray: - { - Type *elem = type->EnumeratedArray.elem; - i64 count = cg_global_const_calculate_region_count_from_basic_type(elem); - return count*type->EnumeratedArray.count; - } - - case Type_Struct: - if (type->Struct.is_raw_union) { - i64 max_count = 0; - for (Entity *f : type->Struct.fields) { - i64 count = cg_global_const_calculate_region_count_from_basic_type(f->type); - max_count = gb_max(count, max_count); - } - return max_count; - } else { - i64 max_count = 0; - for (Entity *f : type->Struct.fields) { - max_count += cg_global_const_calculate_region_count_from_basic_type(f->type); - } - return max_count; - } - break; - case Type_Union: - { - i64 max_count = 0; - for (Type *t : type->Union.variants) { - i64 count = cg_global_const_calculate_region_count_from_basic_type(t); - max_count = gb_max(count, max_count); - } - return max_count+1; - } - break; - - default: - GB_PANIC("TODO(bill): %s", type_to_string(type)); - break; - } - return -1; -} -gb_internal isize cg_global_const_calculate_region_count(ExactValue const &value, Type *type) { - Type *bt = base_type(type); - if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { - if (is_type_rune_array(type)) { - return 1; - } - - Type *et = base_array_type(type); - i64 base_count = 2; - if (is_type_cstring(et)) { - base_count = 1; - } - return base_count * bt->Array.count; - } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { - return 1; - } else if (is_type_array(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_String && - value.kind != ExactValue_Compound) { - Type *elem = type->Array.elem; - - i64 base_count = cg_global_const_calculate_region_count(value, elem); - return base_count * type->Array.count; - } else if (is_type_matrix(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_Compound) { - return 1; - } else if (is_type_simd_vector(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_Compound) { - return 1; - } - - isize count = 0; - switch (value.kind) { - case ExactValue_Invalid: - return 0; - case ExactValue_Bool: - case ExactValue_Integer: - case ExactValue_Float: - case ExactValue_Typeid: - case ExactValue_Complex: - case ExactValue_Quaternion: - return 1; - case ExactValue_Pointer: - return 2; - - case ExactValue_Procedure: - return 1; - - case ExactValue_String: - if (is_type_string(type)) { - return 3; - } else if (is_type_cstring(type) || is_type_array_like(type)) { - return 2; - } - return 3; - - case ExactValue_Compound: { - ast_node(cl, CompoundLit, value.value_compound); - Type *bt = base_type(type); - switch (bt->kind) { - case Type_Struct: - if (cl->elems[0]->kind == Ast_FieldValue) { - for (isize i = 0; i < cl->elems.count; i++) { - ast_node(fv, FieldValue, cl->elems[i]); - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, false); - GB_ASSERT(!sel.indirect); - - Entity *f = bt->Struct.fields[sel.index[0]]; - - if (!cg_elem_type_can_be_constant(f->type)) { - continue; - } - - if (sel.index.count == 1) { - count += cg_global_const_calculate_region_count(fv->value->tav.value, f->type); - } else { - count += 1; // just in case - if (cg_is_nested_possibly_constant(type, sel, fv->value)) { - Type *cv_type = sel.entity->type; - count += cg_global_const_calculate_region_count(fv->value->tav.value, cv_type); - } - } - } - } else { - for_array(i, cl->elems) { - i64 field_index = i; - Ast *elem = cl->elems[i]; - TypeAndValue tav = elem->tav; - Entity *f = bt->Struct.fields[field_index]; - if (!cg_elem_type_can_be_constant(f->type)) { - continue; - } - - ExactValue value = {}; - if (tav.mode != Addressing_Invalid) { - value = tav.value; - } - count += cg_global_const_calculate_region_count(value, type); - } - } - break; - case Type_Array: - case Type_EnumeratedArray: - case Type_SimdVector: { - Type *et = base_array_type(bt); - if (!cg_elem_type_can_be_constant(et)) { - break; - } - for (Ast *elem : cl->elems) { - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - ExactValue const &value = elem->FieldValue.value->tav.value; - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - for (i64 i = lo; i < hi; i++) { - count += cg_global_const_calculate_region_count(value, et); - } - } else { - count += cg_global_const_calculate_region_count(value, et); - } - } else { - ExactValue const &value = elem->tav.value; - count += cg_global_const_calculate_region_count(value, et); - } - } - } break; - - case Type_BitSet: - return 1; - case Type_Matrix: - return 1; - - case Type_Slice: - return 3; - - default: - GB_PANIC("TODO(bill): %s", type_to_string(type)); - break; - } - }break; - } - return count; -} - -gb_internal TB_Global *cg_global_const_comp_literal(cgModule *m, Type *type, ExactValue const &value, TB_Global *global, i64 base_offset); - -gb_internal bool cg_global_const_add_region(cgModule *m, ExactValue const &value, Type *type, TB_Global *global, i64 offset) { - GB_ASSERT(is_type_endian_little(type)); - GB_ASSERT(!is_type_different_to_arch_endianness(type)); - - GB_ASSERT(global != nullptr); - - Type *bt = base_type(type); - i64 size = type_size_of(type); - if (value.kind == ExactValue_Invalid) { - return false; - } - if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { - if (is_type_rune_array(type)) { - i64 count = type->Array.count; - Rune rune; - isize rune_offset = 0; - isize width = 1; - String s = value.value_string; - - Rune *runes = cast(Rune *)tb_global_add_region(m->mod, global, offset, count*4); - - for (i64 i = 0; i < count && rune_offset < s.len; i++) { - width = utf8_decode(s.text+rune_offset, s.len-rune_offset, &rune); - runes[i] = rune; - rune_offset += width; - - } - GB_ASSERT(offset == s.len); - return true; - } - Type *et = bt->Array.elem; - i64 elem_size = type_size_of(et); - - for (i64 i = 0; i < bt->Array.count; i++) { - cg_global_const_add_region(m, value, et, global, offset+(i * elem_size)); - } - return true; - } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { - u8 *dst = cast(u8 *)tb_global_add_region(m->mod, global, offset, size); - gb_memcopy(dst, value.value_string.text, gb_min(value.value_string.len, size)); - return true; - } else if (is_type_array(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_String && - value.kind != ExactValue_Compound) { - - Type *et = bt->Array.elem; - i64 elem_size = type_size_of(et); - - for (i64 i = 0; i < bt->Array.count; i++) { - cg_global_const_add_region(m, value, et, global, offset+(i * elem_size)); - } - - return true; - } else if (is_type_matrix(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_Compound) { - GB_PANIC("TODO(bill): matrices"); - - i64 row = bt->Matrix.row_count; - i64 column = bt->Matrix.column_count; - GB_ASSERT(row == column); - - Type *elem = bt->Matrix.elem; - - i64 elem_size = type_size_of(elem); - gb_unused(elem_size); - - // 1 region in memory, not many - - return true; - } else if (is_type_simd_vector(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_Compound) { - - GB_PANIC("TODO(bill): #simd vectors"); - - Type *et = type->SimdVector.elem; - i64 elem_size = type_size_of(et); - gb_unused(elem_size); - - // 1 region in memory, not many - - return true; - } - - - switch (value.kind) { - case ExactValue_Bool: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - bool *res = cast(bool *)tb_global_add_region(m->mod, global, offset, size); - *res = !!value.value_bool; - } - break; - - case ExactValue_Integer: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - void *res = tb_global_add_region(m->mod, global, offset, size); - cg_write_big_int_at_ptr(res, &value.value_integer, type); - } - break; - - case ExactValue_Float: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - f64 f = exact_value_to_f64(value); - void *res = tb_global_add_region(m->mod, global, offset, size); - switch (size) { - case 2: *(u16 *)res = f32_to_f16(cast(f32)f); break; - case 4: *(f32 *)res = cast(f32)f; break; - case 8: *(f64 *)res = cast(f64)f; break; - } - } - break; - - case ExactValue_Pointer: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - void *res = tb_global_add_region(m->mod, global, offset, size); - *(u64 *)res = exact_value_to_u64(value); - } - break; - - case ExactValue_String: - if (is_type_array_like(type)) { - GB_ASSERT(global != nullptr); - void *data = tb_global_add_region(m->mod, global, offset, size); - gb_memcopy(data, value.value_string.text, gb_min(value.value_string.len, size)); - } else { - cg_global_const_string(m, value.value_string, type, global, offset); - } - break; - - case ExactValue_Typeid: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - void *dst = tb_global_add_region(m->mod, global, offset, size); - u64 id = cg_typeid_as_u64(m, value.value_typeid); - cg_write_uint_at_ptr(dst, id, t_typeid); - } - break; - - case ExactValue_Compound: - { - TB_Global *out_global = cg_global_const_comp_literal(m, type, value, global, offset); - GB_ASSERT(out_global == global); - } - break; - - case ExactValue_Procedure: - GB_PANIC("TODO(bill): nested procedure values/literals\n"); - break; - case ExactValue_Complex: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - Complex128 c = {}; - if (value.value_complex) { - c = *value.value_complex; - } - void *res = tb_global_add_region(m->mod, global, offset, size); - switch (size) { - case 4: - ((u16 *)res)[0] = f32_to_f16(cast(f32)c.real); - ((u16 *)res)[1] = f32_to_f16(cast(f32)c.imag); - break; - case 8: - ((f32 *)res)[0] = cast(f32)c.real; - ((f32 *)res)[1] = cast(f32)c.imag; - break; - case 16: - ((f64 *)res)[0] = cast(f64)c.real; - ((f64 *)res)[1] = cast(f64)c.imag; - break; - } - } - break; - case ExactValue_Quaternion: - { - GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); - // @QuaternionLayout - Quaternion256 q = {}; - if (value.value_quaternion) { - q = *value.value_quaternion; - } - void *res = tb_global_add_region(m->mod, global, offset, size); - switch (size) { - case 8: - ((u16 *)res)[0] = f32_to_f16(cast(f32)q.imag); - ((u16 *)res)[1] = f32_to_f16(cast(f32)q.jmag); - ((u16 *)res)[2] = f32_to_f16(cast(f32)q.kmag); - ((u16 *)res)[3] = f32_to_f16(cast(f32)q.real); - break; - case 16: - ((f32 *)res)[0] = cast(f32)q.imag; - ((f32 *)res)[1] = cast(f32)q.jmag; - ((f32 *)res)[2] = cast(f32)q.kmag; - ((f32 *)res)[3] = cast(f32)q.real; - break; - case 32: - ((f64 *)res)[0] = cast(f64)q.imag; - ((f64 *)res)[1] = cast(f64)q.jmag; - ((f64 *)res)[2] = cast(f64)q.kmag; - ((f64 *)res)[3] = cast(f64)q.real; - break; - } - } - break; - default: - GB_PANIC("%s", type_to_string(type)); - break; - } - return true; -} - - -gb_internal TB_Global *cg_global_const_comp_literal(cgModule *m, Type *original_type, ExactValue const &value, TB_Global *global, i64 base_offset) { - GB_ASSERT(value.kind == ExactValue_Compound); - Ast *value_compound = value.value_compound; - ast_node(cl, CompoundLit, value_compound); - - TEMPORARY_ALLOCATOR_GUARD(); - - if (global == nullptr) { - char name[32] = {}; - gb_snprintf(name, 31, "complit$%u", 1+m->const_nil_guid.fetch_add(1)); - global = tb_global_create(m->mod, -1, name, cg_debug_type(m, original_type), TB_LINKAGE_PRIVATE); - i64 size = type_size_of(original_type); - i64 align = type_align_of(original_type); - - // READ ONLY? - TB_ModuleSectionHandle section = 0; - if (is_type_string(original_type) || is_type_cstring(original_type)) { - section = tb_module_get_rdata(m->mod); - } else { - section = tb_module_get_data(m->mod); - } - - if (cl->elems.count == 0) { - tb_global_set_storage(m->mod, section, global, size, align, 0); - return global; - } - - - isize global_region_count = cg_global_const_calculate_region_count(value, original_type); - tb_global_set_storage(m->mod, section, global, size, align, global_region_count); - } - - if (cl->elems.count == 0) { - return global; - } - - - Type *bt = base_type(original_type); - i64 bt_size = type_size_of(bt); - - switch (bt->kind) { - case Type_Struct: - if (cl->elems[0]->kind == Ast_FieldValue) { - isize elem_count = cl->elems.count; - for (isize i = 0; i < elem_count; i++) { - ast_node(fv, FieldValue, cl->elems[i]); - String name = fv->field->Ident.token.string; - - TypeAndValue tav = fv->value->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - ExactValue value = tav.value; - - Selection sel = lookup_field(bt, name, false); - GB_ASSERT(!sel.indirect); - - if (!cg_is_nested_possibly_constant(bt, sel, fv->value)) { - continue; - } - - i64 offset = type_offset_of_from_selection(bt, sel); - cg_global_const_add_region(m, value, sel.entity->type, global, base_offset+offset); - } - } else { - for_array(i, cl->elems) { - i64 field_index = i; - Ast *elem = cl->elems[i]; - TypeAndValue tav = elem->tav; - Entity *f = bt->Struct.fields[field_index]; - if (!cg_elem_type_can_be_constant(f->type)) { - continue; - } - - i64 offset = bt->Struct.offsets[field_index]; - - ExactValue value = {}; - if (tav.mode != Addressing_Invalid) { - value = tav.value; - } - cg_global_const_add_region(m, value, f->type, global, base_offset+offset); - } - } - return global; - - case Type_Array: - case Type_EnumeratedArray: - case Type_SimdVector: - if (cl->elems[0]->kind == Ast_FieldValue) { - Type *et = base_array_type(bt); - i64 elem_size = type_size_of(et); - for (Ast *elem : cl->elems) { - ast_node(fv, FieldValue, elem); - - ExactValue const &value = fv->value->tav.value; - - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - for (i64 i = lo; i < hi; i++) { - i64 offset = i * elem_size; - cg_global_const_add_region(m, value, et, global, base_offset+offset); - } - } else { - TypeAndValue index_tav = fv->field->tav; - GB_ASSERT(index_tav.mode == Addressing_Constant); - i64 i = exact_value_to_i64(index_tav.value); - i64 offset = i * elem_size; - cg_global_const_add_region(m, value, et, global, base_offset+offset); - } - } - } else { - Type *et = base_array_type(bt); - i64 elem_size = type_size_of(et); - i64 offset = 0; - for (Ast *elem : cl->elems) { - ExactValue const &value = elem->tav.value; - cg_global_const_add_region(m, value, et, global, base_offset+offset); - offset += elem_size; - } - } - - return global; - - case Type_BitSet: - if (bt_size > 0) { - BigInt bits = {}; - BigInt one = {}; - big_int_from_u64(&one, 1); - - for_array(i, cl->elems) { - Ast *e = cl->elems[i]; - GB_ASSERT(e->kind != Ast_FieldValue); - - TypeAndValue tav = e->tav; - if (tav.mode != Addressing_Constant) { - continue; - } - GB_ASSERT(tav.value.kind == ExactValue_Integer); - i64 v = big_int_to_i64(&tav.value.value_integer); - i64 lower = bt->BitSet.lower; - u64 index = cast(u64)(v-lower); - BigInt bit = {}; - big_int_from_u64(&bit, index); - big_int_shl(&bit, &one, &bit); - big_int_or(&bits, &bits, &bit); - } - - void *dst = tb_global_add_region(m->mod, global, base_offset, bt_size); - cg_write_big_int_at_ptr(dst, &bits, original_type); - } - return global; - - case Type_Matrix: - GB_PANIC("TODO(bill): constant compound literal for %s", type_to_string(original_type)); - break; - - case Type_Slice: - { - i64 count = gb_max(cl->elems.count, cl->max_count); - Type *elem = bt->Slice.elem; - Type *t = alloc_type_array(elem, count); - TB_Global *backing_array = cg_global_const_comp_literal(m, t, value, nullptr, 0); - - tb_global_add_symbol_reloc(m->mod, global, base_offset+0, cast(TB_Symbol *)backing_array); - - void *len_ptr = tb_global_add_region(m->mod, global, base_offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); - } - return global; - } - - GB_PANIC("TODO(bill): constant compound literal for %s", type_to_string(original_type)); - return nullptr; -} - - -gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { - GB_ASSERT(p != nullptr); - TB_Node *node = nullptr; - - if (is_type_untyped(type)) { - // TODO(bill): THIS IS A COMPLETE HACK, WHY DOES THIS NOT A TYPE? - GB_ASSERT(type->kind == Type_Basic); - switch (type->Basic.kind) { - case Basic_UntypedBool: - type = t_bool; - break; - case Basic_UntypedInteger: - type = t_i64; - break; - case Basic_UntypedFloat: - type = t_f64; - break; - case Basic_UntypedComplex: - type = t_complex128; - break; - case Basic_UntypedQuaternion: - type = t_quaternion256; - break; - case Basic_UntypedString: - type = t_string; - break; - case Basic_UntypedRune: - type = t_rune; - break; - case Basic_UntypedNil: - case Basic_UntypedUninit: - return cg_value(cast(TB_Node *)nullptr, type); - } - } - TB_DataType dt = cg_data_type(type); - - switch (value.kind) { - case ExactValue_Invalid: - return cg_const_nil(p, type); - - case ExactValue_Typeid: - return cg_typeid(p, value.value_typeid); - - case ExactValue_Procedure: - { - Ast *expr = unparen_expr(value.value_procedure); - if (expr->kind == Ast_ProcLit) { - cgProcedure *anon = cg_procedure_generate_anonymous(p->module, expr, p); - TB_Node *ptr = tb_inst_get_symbol_address(p->func, anon->symbol); - GB_ASSERT(are_types_identical(type, anon->type)); - return cg_value(ptr, type); - } - - Entity *e = entity_of_node(expr); - if (e != nullptr) { - TB_Symbol *found = cg_find_symbol_from_entity(p->module, e); - GB_ASSERT_MSG(found != nullptr, "could not find '%.*s'", LIT(e->token.string)); - TB_Node *ptr = tb_inst_get_symbol_address(p->func, found); - GB_ASSERT(type != nullptr); - GB_ASSERT(are_types_identical(type, e->type)); - return cg_value(ptr, type); - } - - GB_PANIC("TODO(bill): cg_const_value ExactValue_Procedure %s", expr_to_string(expr)); - } - break; - } - - switch (value.kind) { - case ExactValue_Bool: - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); - return cg_value(tb_inst_uint(p->func, dt, value.value_bool), type); - - case ExactValue_Integer: - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); - // GB_ASSERT(dt.raw != TB_TYPE_I128.raw); - if (is_type_unsigned(type)) { - u64 i = 0; - if (value.kind == ExactValue_Integer && value.value_integer.sign) { - i = exact_value_to_i64(value); - } else { - i = exact_value_to_u64(value); - } - return cg_value(tb_inst_uint(p->func, dt, i), type); - } else { - i64 i = exact_value_to_i64(value); - return cg_value(tb_inst_sint(p->func, dt, i), type); - } - break; - - case ExactValue_Float: - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); - GB_ASSERT(dt.raw != TB_TYPE_F16.raw); - GB_ASSERT(!is_type_different_to_arch_endianness(type)); - { - f64 f = exact_value_to_f64(value); - if (type_size_of(type) == 8) { - return cg_value(tb_inst_float64(p->func, f), type); - } else { - return cg_value(tb_inst_float32(p->func, cast(f32)f), type); - } - } - break; - - case ExactValue_String: - { - GB_ASSERT(is_type_string(type)); - cgModule *m = p->module; - - String str = value.value_string; - - char name[32] = {}; - gb_snprintf(name, 31, "csb$%u", 1+m->const_nil_guid.fetch_add(1)); - TB_Global *cstr_global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); - - i64 size = str.len+1; - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), cstr_global, size, 1, 1); - u8 *data = cast(u8 *)tb_global_add_region(m->mod, cstr_global, 0, size); - gb_memcopy(data, str.text, str.len); - data[str.len] = 0; - - if (is_type_cstring(type)) { - cgValue s = cg_value(cstr_global, type); - return cg_flatten_value(p, s); - } - - gb_snprintf(name, 31, "str$%u", 1+m->const_nil_guid.fetch_add(1)); - TB_Global *str_global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, type_size_of(type), type_align_of(type), 2); - - tb_global_add_symbol_reloc(m->mod, str_global, 0, cast(TB_Symbol *)cstr_global); - void *len_ptr = tb_global_add_region(m->mod, str_global, build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, str.len, t_int); - - TB_Node *s = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)str_global); - return cg_lvalue_addr(s, type); - - } - - case ExactValue_Pointer: - return cg_value(tb_inst_uint(p->func, dt, exact_value_to_u64(value)), type); - - case ExactValue_Compound: - { - TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_comp_literal(p->module, type, value, nullptr, 0); - TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); - return cg_lvalue_addr(node, type); - } - break; - } - - - GB_ASSERT(node != nullptr); - return cg_value(node, type); -} - -gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) { - return cg_const_value(p, type, exact_value_i64(i)); -} -gb_internal cgValue cg_const_bool(cgProcedure *p, Type *type, bool v) { - return cg_value(tb_inst_bool(p->func, v), type); -} - -gb_internal cgValue cg_const_string(cgProcedure *p, Type *type, String const &str) { - return cg_const_value(p, type, exact_value_string(str)); -} - -gb_internal cgValue cg_const_union_tag(cgProcedure *p, Type *u, Type *v) { - return cg_const_value(p, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); -} - diff --git a/src/tilde_debug.cpp b/src/tilde_debug.cpp deleted file mode 100644 index a4b82bf72..000000000 --- a/src/tilde_debug.cpp +++ /dev/null @@ -1,482 +0,0 @@ -gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type); -gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { - type = reduce_tuple_to_single_type(type); - - mutex_lock(&m->debug_type_mutex); - defer (mutex_unlock(&m->debug_type_mutex)); - TB_DebugType **found = map_get(&m->debug_type_map, type); - if (found) { - return *found; - } - - TB_DebugType *res = cg_debug_type_internal(m, type); - map_set(&m->debug_type_map, type, res); - return res; -} - -gb_internal TB_DebugType *cg_debug_type_for_proc(cgModule *m, Type *type) { - GB_ASSERT(is_type_proc(type)); - TB_DebugType **func_found = nullptr; - TB_DebugType *func_ptr = cg_debug_type(m, type); - GB_ASSERT(func_ptr != nullptr); - - mutex_lock(&m->debug_type_mutex); - func_found = map_get(&m->proc_debug_type_map, type); - mutex_unlock(&m->debug_type_mutex); - GB_ASSERT(func_found != nullptr); - return *func_found; -} - - -gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, String const &record_name) { - Type *bt = base_type(type); - switch (bt->kind) { - case Type_Struct: - { - type_set_offsets(bt); - - TB_DebugType *record = nullptr; - if (bt->Struct.is_raw_union) { - record = tb_debug_create_union(m->mod, record_name.len, cast(char const *)record_name.text); - } else { - record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); - } - if (record_name.len != 0) { - map_set(&m->debug_type_map, type, record); - } - - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, bt->Struct.fields.count); - for_array(i, bt->Struct.fields) { - Entity *e = bt->Struct.fields[i]; - Type *type = e->type; - if (is_type_proc(type)) { - type = t_rawptr; - } - TB_DebugType *field_type = cg_debug_type(m, type); - String name = e->token.string; - TB_CharUnits offset = cast(TB_CharUnits)bt->Struct.offsets[i]; - if (name.len == 0) { - name = str_lit("_"); - } - - fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); - } - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - return record; - } - break; - - case Type_Tuple: - { - GB_ASSERT(record_name.len == 0); - type_set_offsets(bt); - - TB_DebugType *record = tb_debug_create_struct(m->mod, 0, ""); - isize record_count = 0; - for (Entity *e : bt->Tuple.variables) { - if (e->kind == Entity_Variable) { - record_count += 1; - } - } - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, record_count); - for_array(i, bt->Tuple.variables) { - Entity *e = bt->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - Type *type = e->type; - if (is_type_proc(type)) { - type = t_rawptr; - } - TB_DebugType *field_type = cg_debug_type(m, type); - String name = e->token.string; - TB_CharUnits offset = cast(TB_CharUnits)bt->Tuple.offsets[i]; - if (name.len == 0) { - name = str_lit("_"); - } - - fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); - } - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - return record; - } - break; - case Type_Union: - { - TB_DebugType *record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); - if (record_name.len != 0) { - map_set(&m->debug_type_map, type, record); - } - - i64 variant_count = bt->Union.variants.count; - if (is_type_union_maybe_pointer(bt)) { - // NO TAG - GB_ASSERT(variant_count == 1); - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, variant_count); - TB_DebugType *variant_type = cg_debug_type(m, bt->Union.variants[0]); - fields[0] = tb_debug_create_field(m->mod, variant_type, -1, "v0", 0); - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - } else { - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, variant_count+1); - for_array(i, bt->Union.variants) { - Type *v = bt->Union.variants[i]; - TB_DebugType *variant_type = cg_debug_type(m, v); - char name[32] = {}; - u32 v_index = cast(u32)i; - if (bt->Union.kind != UnionType_no_nil) { - v_index += 1; - } - gb_snprintf(name, 31, "v%u", v_index); - fields[i] = tb_debug_create_field(m->mod, variant_type, -1, name, 0); - } - - TB_DebugType *tag_type = cg_debug_type(m, union_tag_type(bt)); - fields[variant_count] = tb_debug_create_field(m->mod, tag_type, -1, "tag", cast(TB_CharUnits)bt->Union.variant_block_size); - - } - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - return record; - } - break; - } - return nullptr; -} - - -gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { - if (type == nullptr) { - return tb_debug_get_void(m->mod); - } - Type *original_type = type; - if (type->kind == Type_Named) { - String name = type->Named.name; - TB_DebugType *res = cg_debug_type_internal_record(m, type, name); - if (res) { - return res; - } - type = base_type(type->Named.base); - } - - TB_CharUnits int_size = cast(TB_CharUnits)build_context.int_size; - TB_CharUnits ptr_size = cast(TB_CharUnits)build_context.ptr_size; - TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); - int bits = cast(int)(8*size); - bool is_signed = is_type_integer(core_type(type)) && !is_type_unsigned(core_type(type)); - - switch (type->kind) { - case Type_Basic: - switch (type->Basic.kind) { - case Basic_bool: return tb_debug_get_bool(m->mod); - case Basic_b8: return tb_debug_get_bool(m->mod); - case Basic_b16: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_b32: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_b64: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i8: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u8: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i16: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u16: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i32: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u32: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i64: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u64: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i128: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u128: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_rune: return tb_debug_get_integer(m->mod, is_signed, bits); - - case Basic_f16: return tb_debug_get_integer(m->mod, false, bits); - case Basic_f32: return tb_debug_get_float(m->mod, TB_FLT_32); - case Basic_f64: return tb_debug_get_float(m->mod, TB_FLT_64); - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - Type *et = base_complex_elem_type(type); - TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); - TB_DebugType *elem = cg_debug_type(m, et); - - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 2); - fields[0] = tb_debug_create_field(m->mod, elem, -1, "real", 0*elem_size); - fields[1] = tb_debug_create_field(m->mod, elem, -1, "imag", 1*elem_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - Type *et = base_complex_elem_type(type); - TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); - TB_DebugType *elem = cg_debug_type(m, et); - - // @QuaternionLayout - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 4); - fields[0] = tb_debug_create_field(m->mod, elem, -1, "imag", 0*elem_size); - fields[1] = tb_debug_create_field(m->mod, elem, -1, "jmag", 1*elem_size); - fields[2] = tb_debug_create_field(m->mod, elem, -1, "kmag", 2*elem_size); - fields[3] = tb_debug_create_field(m->mod, elem, -1, "real", 3*elem_size); - - tb_debug_record_end(record, size, align); - return record; - } - - case Basic_int: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits); - - case Basic_rawptr: - return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); - case Basic_string: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - // @QuaternionLayout - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_u8_ptr), -1, "data", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Basic_cstring: - return tb_debug_create_ptr(m->mod, tb_debug_get_integer(m->mod, false, 8)); - - case Basic_any: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - // @QuaternionLayout - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_rawptr), -1, "data", 0*ptr_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_typeid), -1, "id", 1*ptr_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Basic_typeid: return tb_debug_get_integer(m->mod, false, bits); - - case Basic_i16le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u16le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i32le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u32le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i64le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u64le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i128le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u128le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i16be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u16be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i32be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u32be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i64be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u64be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i128be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u128be: return tb_debug_get_integer(m->mod, is_signed, bits); - - case Basic_f16le: return tb_debug_get_integer(m->mod, false, bits); - case Basic_f32le: return tb_debug_get_float(m->mod, TB_FLT_32); - case Basic_f64le: return tb_debug_get_float(m->mod, TB_FLT_64); - case Basic_f16be: return tb_debug_get_integer(m->mod, false, bits); - case Basic_f32be: return tb_debug_get_float(m->mod, TB_FLT_32); - case Basic_f64be: return tb_debug_get_float(m->mod, TB_FLT_64); - } - break; - case Type_Generic: - GB_PANIC("SHOULD NEVER HIT"); - break; - case Type_Pointer: - return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->Pointer.elem)); - case Type_MultiPointer: - return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->MultiPointer.elem)); - case Type_Array: - return tb_debug_create_array(m->mod, cg_debug_type(m, type->Array.elem), type->Array.count); - case Type_EnumeratedArray: - return tb_debug_create_array(m->mod, cg_debug_type(m, type->EnumeratedArray.elem), type->EnumeratedArray.count); - case Type_Slice: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Type_DynamicArray: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 4); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); - fields[2] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "cap", 2*int_size); - fields[3] = tb_debug_create_field(m->mod, cg_debug_type(m, t_allocator), -1, "allocator", 3*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Type_Map: - return cg_debug_type(m, t_raw_map); - - case Type_Struct: - case Type_Tuple: - case Type_Union: - return cg_debug_type_internal_record(m, type, {}); - - case Type_Enum: - return tb_debug_get_integer(m->mod, is_signed, bits); - - case Type_Proc: - { - TypeProc *pt = &type->Proc; - isize param_count = 0; - isize return_count = 0; - - bool is_odin_cc = is_calling_convention_odin(pt->calling_convention); - - if (pt->params) for (Entity *e : pt->params->Tuple.variables) { - if (e->kind == Entity_Variable) { - param_count += 1; - } - } - - if (pt->result_count > 0) { - if (is_odin_cc) { - // Split returns - param_count += pt->result_count-1; - return_count = 1; - } else { - return_count = 1; - } - } - - if (pt->calling_convention == ProcCC_Odin) { - // `context` ptr - param_count += 1; - } - - TB_CallingConv tb_cc = TB_CDECL; - if (pt->calling_convention == ProcCC_StdCall) { - tb_cc = TB_STDCALL; - } - TB_DebugType *func = tb_debug_create_func(m->mod, tb_cc, param_count, return_count, pt->c_vararg); - - map_set(&m->proc_debug_type_map, original_type, func); - map_set(&m->proc_debug_type_map, type, func); - - TB_DebugType *func_ptr = tb_debug_create_ptr(m->mod, func); - map_set(&m->debug_type_map, original_type, func_ptr); - map_set(&m->debug_type_map, type, func_ptr); - - TB_DebugType **params = tb_debug_func_params(func); - TB_DebugType **returns = tb_debug_func_returns(func); - - isize param_index = 0; - isize return_index = 0; - if (pt->params) for (Entity *e : pt->params->Tuple.variables) { - if (e->kind == Entity_Variable) { - Type *type = e->type; - if (is_type_proc(type)) { - type = t_rawptr; - } - String name = e->token.string; - if (name.len == 0) { - name = str_lit("_"); - } - params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); - } - } - - if (pt->result_count) { - GB_ASSERT(pt->results); - if (is_odin_cc) { - // Split Returns - for (isize i = 0; i < pt->results->Tuple.variables.count-1; i++) { - Entity *e = pt->results->Tuple.variables[i]; - GB_ASSERT(e->kind == Entity_Variable); - Type *type = e->type; - if (is_type_proc(e->type)) { - type = t_rawptr; - } - type = alloc_type_pointer(type); - - String name = e->token.string; - if (name.len == 0) { - name = str_lit("_"); - } - params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); - } - - Type *last_type = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; - if (is_type_proc(last_type)) { - last_type = t_rawptr; - } - returns[return_index++] = cg_debug_type(m, last_type); - } else { - returns[return_index++] = cg_debug_type(m, pt->results); - } - } - - if (pt->calling_convention == ProcCC_Odin) { - Type *type = t_context_ptr; - String name = str_lit("__.context_ptr"); - params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); - } - - GB_ASSERT_MSG(param_index == param_count, "%td vs %td for %s", param_index, param_count, type_to_string(type)); - GB_ASSERT_MSG(return_index == return_count, "%td vs %td for %s", return_index, return_count, type_to_string(type)); - - return func_ptr; - } - break; - case Type_BitSet: - return cg_debug_type(m, bit_set_to_int(type)); - case Type_SimdVector: - return tb_debug_create_array(m->mod, cg_debug_type(m, type->SimdVector.elem), type->SimdVector.count); - case Type_RelativePointer: - return cg_debug_type(m, type->RelativePointer.base_integer); - case Type_RelativeMultiPointer: - return cg_debug_type(m, type->RelativeMultiPointer.base_integer); - case Type_Matrix: - { - i64 count = matrix_type_total_internal_elems(type); - return tb_debug_create_array(m->mod, cg_debug_type(m, type->Matrix.elem), count); - } - case Type_SoaPointer: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - TB_DebugType **fields = tb_debug_record_begin(m->mod, record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->SoaPointer.elem)), -1, "ptr", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "offset", 1*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - } - - // TODO(bill): cg_debug_type - return tb_debug_get_void(m->mod); -} diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp deleted file mode 100644 index 236d0cf7d..000000000 --- a/src/tilde_expr.cpp +++ /dev/null @@ -1,3961 +0,0 @@ -gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { - GB_ASSERT(value.kind != cgValue_Multi); - if (value.kind == cgValue_Symbol) { - GB_ASSERT(is_type_internally_pointer_like(value.type)); - return cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); - } else if (value.kind == cgValue_Addr) { - // TODO(bill): Is this a good idea? - // this converts an lvalue to an rvalue if trivially possible - TB_DataType dt = cg_data_type(value.type); - if (!TB_IS_VOID_TYPE(dt)) { - TB_CharUnits align = cast(TB_CharUnits)type_align_of(value.type); - return cg_value(tb_inst_load(p->func, dt, value.node, align, false), value.type); - } - } - return value; -} - -gb_internal cgValue cg_emit_select(cgProcedure *p, cgValue const &cond, cgValue const &x, cgValue const &y) { - GB_ASSERT(x.kind == y.kind); - GB_ASSERT(cond.kind == cgValue_Value); - cgValue res = x; - res.node = tb_inst_select(p->func, cond.node, x.node, y.node); - return res; -} - - -gb_internal bool cg_is_expr_untyped_const(Ast *expr) { - auto const &tv = type_and_value_of_expr(expr); - if (is_type_untyped(tv.type)) { - return tv.value.kind != ExactValue_Invalid; - } - return false; -} -gb_internal cgValue cg_expr_untyped_const_to_typed(cgProcedure *p, Ast *expr, Type *t) { - GB_ASSERT(is_type_typed(t)); - auto const &tv = type_and_value_of_expr(expr); - return cg_const_value(p, t, tv.value); -} - -gb_internal cgContextData *cg_push_context_onto_stack(cgProcedure *p, cgAddr ctx) { - ctx.kind = cgAddr_Context; - cgContextData *cd = array_add_and_get(&p->context_stack); - cd->ctx = ctx; - cd->scope_index = p->scope_index; - return cd; -} - -gb_internal cgAddr cg_find_or_generate_context_ptr(cgProcedure *p) { - if (p->context_stack.count > 0) { - return p->context_stack[p->context_stack.count-1].ctx; - } - - Type *pt = base_type(p->type); - GB_ASSERT(pt->kind == Type_Proc); - GB_ASSERT(pt->Proc.calling_convention != ProcCC_Odin); - - cgAddr c = cg_add_local(p, t_context, nullptr, true); - tb_function_attrib_variable(p->func, c.addr.node, nullptr, -1, "context", cg_debug_type(p->module, t_context)); - c.kind = cgAddr_Context; - // lb_emit_init_context(p, c); - cg_push_context_onto_stack(p, c); - // lb_add_debug_context_variable(p, c); - - return c; -} - -gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e) { - e = strip_entity_wrapping(e); - GB_ASSERT(e != nullptr); - - GB_ASSERT(e->token.string != "_"); - - if (e->kind == Entity_Procedure) { - return cg_find_procedure_value_from_entity(m, e); - } - - cgValue *found = nullptr; - rw_mutex_shared_lock(&m->values_mutex); - found = map_get(&m->values, e); - rw_mutex_shared_unlock(&m->values_mutex); - if (found) { - return *found; - } - - GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); - return {}; -} - -gb_internal cgValue cg_get_using_variable(cgProcedure *p, Entity *e) { - GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); - String name = e->token.string; - Entity *parent = e->using_parent; - Selection sel = lookup_field(parent->type, name, false); - GB_ASSERT(sel.entity != nullptr); - cgValue *pv = map_get(&p->module->values, parent); - - cgValue v = {}; - - if (pv == nullptr && parent->flags & EntityFlag_SoaPtrField) { - // NOTE(bill): using SOA value (probably from for-in statement) - GB_PANIC("TODO(bill): cg_get_soa_variable_addr"); - // cgAddr parent_addr = cg_get_soa_variable_addr(p, parent); - // v = cg_addr_get_ptr(p, parent_addr); - } else if (pv != nullptr) { - v = *pv; - } else { - GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s %.*s", LIT(e->token.string), LIT(name)); - v = cg_build_addr_ptr(p, e->using_expr); - } - GB_ASSERT(v.node != nullptr); - GB_ASSERT_MSG(parent->type == type_deref(v.type), "%s %s", type_to_string(parent->type), type_to_string(v.type)); - cgValue ptr = cg_emit_deep_field_gep(p, v, sel); - // if (parent->scope) { - // if ((parent->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { - // cg_add_debug_local_variable(p, ptr.value, e->type, e->token); - // } - // } else { - // cg_add_debug_local_variable(p, ptr.value, e->type, e->token); - // } - return ptr; -} -gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *expr) { - GB_ASSERT(e != nullptr); - if (e->kind == Entity_Constant) { - Type *t = default_type(type_of_expr(expr)); - cgValue v = cg_const_value(p, t, e->Constant.value); - GB_PANIC("TODO(bill): cg_add_global_generated"); - // return cg_add_global_generated(p->module, t, v); - return {}; - } - - cgAddr *local_found = map_get(&p->variable_map, e); - if (local_found) { - return *local_found; - } - - cgValue v = {}; - - cgModule *m = p->module; - - rw_mutex_lock(&m->values_mutex); - cgValue *found = map_get(&m->values, e); - rw_mutex_unlock(&m->values_mutex); - if (found) { - v = *found; - } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - // NOTE(bill): Calculate the using variable every time - v = cg_get_using_variable(p, e); - } else if (e->flags & EntityFlag_SoaPtrField) { - return map_must_get(&p->soa_values_map, e); - } - - - if (v.node == nullptr) { - cgValue v = cg_find_value_from_entity(m, e); - v = cg_flatten_value(p, v); - return cg_addr(v); - } - - return cg_addr(v); -} - -gb_internal cgValue cg_emit_union_tag_ptr(cgProcedure *p, cgValue const &parent_ptr) { - Type *t = parent_ptr.type; - Type *ut = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); - GB_ASSERT_MSG(ut->kind == Type_Union, "%s", type_to_string(t)); - - GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut)); - GB_ASSERT(!is_type_union_maybe_pointer(ut)); - GB_ASSERT(type_size_of(ut) > 0); - - Type *tag_type = union_tag_type(ut); - i64 tag_offset = ut->Union.variant_block_size; - - GB_ASSERT(parent_ptr.kind == cgValue_Value); - TB_Node *ptr = parent_ptr.node; - TB_Node *tag_ptr = tb_inst_member_access(p->func, ptr, tag_offset); - return cg_value(tag_ptr, alloc_type_pointer(tag_type)); -} - - - -gb_internal cgValue cg_correct_endianness(cgProcedure *p, cgValue value) { - Type *src = core_type(value.type); - GB_ASSERT(is_type_integer(src) || is_type_float(src)); - if (is_type_different_to_arch_endianness(src)) { - GB_PANIC("TODO(bill): cg_correct_endianness"); - // Type *platform_src_type = integer_endian_type_to_platform_type(src); - // value = cg_emit_byte_swap(p, value, platform_src_type); - } - return value; -} - -gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) { - GB_ASSERT(type_size_of(value.type) == type_size_of(type)); - - value = cg_flatten_value(p, value); - - if (are_types_identical(value.type, type)) { - return value; - } - if (are_types_identical(core_type(value.type), core_type(type))) { - value.type = type; - return value; - } - - i64 src_align = type_align_of(value.type); - i64 dst_align = type_align_of(type); - - if (dst_align > src_align) { - cgAddr local = cg_add_local(p, type, nullptr, false); - cgValue dst = local.addr; - dst.type = alloc_type_pointer(value.type); - cg_emit_store(p, dst, value); - return cg_addr_load(p, local); - } - - TB_DataType dt = cg_data_type(type); - switch (value.kind) { - case cgValue_Value: - GB_ASSERT_MSG(!TB_IS_VOID_TYPE(dt), "%d %s -> %s", dt.type, type_to_string(value.type), type_to_string(type)); - value.type = type; - if (value.node->dt.raw != dt.raw) { - switch (value.node->dt.type) { - case TB_INT: - switch (value.node->dt.type) { - case TB_INT: - break; - case TB_FLOAT: - value.node = tb_inst_bitcast(p->func, value.node, dt); - break; - case TB_PTR: - value.node = tb_inst_int2ptr(p->func, value.node); - break; - } - break; - case TB_FLOAT: - switch (value.node->dt.type) { - case TB_INT: - value.node = tb_inst_bitcast(p->func, value.node, dt); - break; - case TB_FLOAT: - break; - case TB_PTR: - value.node = tb_inst_bitcast(p->func, value.node, TB_TYPE_INTPTR); - value.node = tb_inst_int2ptr(p->func, value.node); - break; - } - break; - case TB_PTR: - switch (value.node->dt.type) { - case TB_INT: - value.node = tb_inst_ptr2int(p->func, value.node, dt); - break; - case TB_FLOAT: - value.node = tb_inst_ptr2int(p->func, value.node, TB_TYPE_INTPTR); - value.node = tb_inst_bitcast(p->func, value.node, dt); - break; - case TB_PTR: - break; - } - break; - } - } - return value; - case cgValue_Addr: - value.type = type; - return value; - case cgValue_Symbol: - GB_PANIC("should be handled above"); - break; - case cgValue_Multi: - GB_PANIC("cannot transmute multiple values at once"); - break; - } - return value; - -} -gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_type) { - GB_ASSERT(type_size_of(value.type) == type_size_of(end_type)); - - if (type_size_of(value.type) < 2) { - return value; - } - - if (is_type_float(value.type)) { - i64 sz = type_size_of(value.type); - Type *integer_type = nullptr; - switch (sz) { - case 2: integer_type = t_u16; break; - case 4: integer_type = t_u32; break; - case 8: integer_type = t_u64; break; - } - GB_ASSERT(integer_type != nullptr); - value = cg_emit_transmute(p, value, integer_type); - } - - GB_ASSERT(value.kind == cgValue_Value); - - // TODO(bill): bswap - // value.node = tb_inst_bswap(p->func, value.node); - return cg_emit_transmute(p, value, end_type); -} - -gb_internal cgValue cg_emit_comp_records(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right, Type *type) { - GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type)); - cgValue left_ptr = cg_address_from_load_or_generate_local(p, left); - cgValue right_ptr = cg_address_from_load_or_generate_local(p, right); - cgValue res = {}; - if (type_size_of(type) == 0) { - switch (op_kind) { - case Token_CmpEq: - return cg_const_bool(p, t_bool, true); - case Token_NotEq: - return cg_const_bool(p, t_bool, false); - } - GB_PANIC("invalid operator"); - } - TEMPORARY_ALLOCATOR_GUARD(); - if (is_type_simple_compare(type)) { - // TODO(bill): Test to see if this is actually faster!!!! - auto args = slice_make(temporary_allocator(), 3); - args[0] = cg_emit_conv(p, left_ptr, t_rawptr); - args[1] = cg_emit_conv(p, right_ptr, t_rawptr); - args[2] = cg_const_int(p, t_int, type_size_of(type)); - res = cg_emit_runtime_call(p, "memory_equal", args); - } else { - cgProcedure *equal_proc = cg_equal_proc_for_type(p->module, type); - cgValue value = cg_value(tb_inst_get_symbol_address(p->func, equal_proc->symbol), equal_proc->type); - auto args = slice_make(temporary_allocator(), 2); - args[0] = cg_emit_conv(p, left_ptr, t_rawptr); - args[1] = cg_emit_conv(p, right_ptr, t_rawptr); - res = cg_emit_call(p, value, args); - } - if (op_kind == Token_NotEq) { - res = cg_emit_unary_arith(p, Token_Not, res, res.type); - } - return res; -} - -gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right) { - GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); - - Type *a = core_type(left.type); - Type *b = core_type(right.type); - - cgValue nil_check = {}; - if (is_type_array_like(left.type) || is_type_array_like(right.type)) { - // don't do `nil` check if it is array-like - } else if (is_type_untyped_nil(left.type)) { - nil_check = cg_emit_comp_against_nil(p, op_kind, right); - } else if (is_type_untyped_nil(right.type)) { - nil_check = cg_emit_comp_against_nil(p, op_kind, left); - } - if (nil_check.node != nullptr) { - return nil_check; - } - - if (are_types_identical(a, b)) { - // NOTE(bill): No need for a conversion - } /*else if (cg_is_const(left) || cg_is_const_nil(left)) { - left = cg_emit_conv(p, left, right.type); - } else if (cg_is_const(right) || cg_is_const_nil(right)) { - right = cg_emit_conv(p, right, left.type); - }*/ else { - Type *lt = left.type; - Type *rt = right.type; - - lt = left.type; - rt = right.type; - i64 ls = type_size_of(lt); - i64 rs = type_size_of(rt); - - // NOTE(bill): Quick heuristic, larger types are usually the target type - if (ls < rs) { - left = cg_emit_conv(p, left, rt); - } else if (ls > rs) { - right = cg_emit_conv(p, right, lt); - } else { - if (is_type_union(rt)) { - left = cg_emit_conv(p, left, rt); - } else { - right = cg_emit_conv(p, right, lt); - } - } - } - - a = core_type(left.type); - b = core_type(right.type); - left = cg_flatten_value(p, left); - right = cg_flatten_value(p, right); - - - if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { - GB_PANIC("TODO(bill): cg_emit_comp matrix"); - // Type *tl = base_type(a); - // lbValue lhs = lb_address_from_load_or_generate_local(p, left); - // lbValue rhs = lb_address_from_load_or_generate_local(p, right); - - - // // TODO(bill): Test to see if this is actually faster!!!! - // auto args = array_make(permanent_allocator(), 3); - // args[0] = lb_emit_conv(p, lhs, t_rawptr); - // args[1] = lb_emit_conv(p, rhs, t_rawptr); - // args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); - // lbValue val = lb_emit_runtime_call(p, "memory_compare", args); - // lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); - // return lb_emit_conv(p, res, t_bool); - } - if (is_type_array_like(a)) { - GB_PANIC("TODO(bill): cg_emit_comp is_type_array_like"); - // Type *tl = base_type(a); - // lbValue lhs = lb_address_from_load_or_generate_local(p, left); - // lbValue rhs = lb_address_from_load_or_generate_local(p, right); - - - // TokenKind cmp_op = Token_And; - // lbValue res = lb_const_bool(p->module, t_bool, true); - // if (op_kind == Token_NotEq) { - // res = lb_const_bool(p->module, t_bool, false); - // cmp_op = Token_Or; - // } else if (op_kind == Token_CmpEq) { - // res = lb_const_bool(p->module, t_bool, true); - // cmp_op = Token_And; - // } - - // bool inline_array_arith = lb_can_try_to_inline_array_arith(tl); - // i32 count = 0; - // switch (tl->kind) { - // case Type_Array: count = cast(i32)tl->Array.count; break; - // case Type_EnumeratedArray: count = cast(i32)tl->EnumeratedArray.count; break; - // } - - // if (inline_array_arith) { - // // inline - // lbAddr val = lb_add_local_generated(p, t_bool, false); - // lb_addr_store(p, val, res); - // for (i32 i = 0; i < count; i++) { - // lbValue x = lb_emit_load(p, lb_emit_array_epi(p, lhs, i)); - // lbValue y = lb_emit_load(p, lb_emit_array_epi(p, rhs, i)); - // lbValue cmp = lb_emit_comp(p, op_kind, x, y); - // lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); - // lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); - // } - - // return lb_addr_load(p, val); - // } else { - // if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { - // // TODO(bill): Test to see if this is actually faster!!!! - // auto args = array_make(permanent_allocator(), 3); - // args[0] = lb_emit_conv(p, lhs, t_rawptr); - // args[1] = lb_emit_conv(p, rhs, t_rawptr); - // args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); - // lbValue val = lb_emit_runtime_call(p, "memory_compare", args); - // lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); - // return lb_emit_conv(p, res, t_bool); - // } else { - // lbAddr val = lb_add_local_generated(p, t_bool, false); - // lb_addr_store(p, val, res); - // auto loop_data = lb_loop_start(p, count, t_i32); - // { - // lbValue i = loop_data.idx; - // lbValue x = lb_emit_load(p, lb_emit_array_ep(p, lhs, i)); - // lbValue y = lb_emit_load(p, lb_emit_array_ep(p, rhs, i)); - // lbValue cmp = lb_emit_comp(p, op_kind, x, y); - // lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); - // lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); - // } - // lb_loop_end(p, loop_data); - - // return lb_addr_load(p, val); - // } - // } - } - - if ((is_type_struct(a) || is_type_union(a)) && is_type_comparable(a)) { - return cg_emit_comp_records(p, op_kind, left, right, a); - } - - if ((is_type_struct(b) || is_type_union(b)) && is_type_comparable(b)) { - return cg_emit_comp_records(p, op_kind, left, right, b); - } - - if (is_type_string(a)) { - if (is_type_cstring(a)) { - left = cg_emit_conv(p, left, t_string); - right = cg_emit_conv(p, right, t_string); - } - - char const *runtime_procedure = nullptr; - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "string_eq"; break; - case Token_NotEq: runtime_procedure = "string_ne"; break; - case Token_Lt: runtime_procedure = "string_lt"; break; - case Token_Gt: runtime_procedure = "string_gt"; break; - case Token_LtEq: runtime_procedure = "string_le"; break; - case Token_GtEq: runtime_procedure = "string_gt"; break; - } - GB_ASSERT(runtime_procedure != nullptr); - - auto args = slice_make(permanent_allocator(), 2); - args[0] = left; - args[1] = right; - return cg_emit_runtime_call(p, runtime_procedure, args); - } - - if (is_type_complex(a)) { - char const *runtime_procedure = ""; - i64 sz = 8*type_size_of(a); - switch (sz) { - case 32: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "complex32_eq"; break; - case Token_NotEq: runtime_procedure = "complex32_ne"; break; - } - break; - case 64: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "complex64_eq"; break; - case Token_NotEq: runtime_procedure = "complex64_ne"; break; - } - break; - case 128: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "complex128_eq"; break; - case Token_NotEq: runtime_procedure = "complex128_ne"; break; - } - break; - } - GB_ASSERT(runtime_procedure != nullptr); - - GB_PANIC("TODO(bill): cg_emit_runtime_call"); - // auto args = array_make(permanent_allocator(), 2); - // args[0] = left; - // args[1] = right; - // return lb_emit_runtime_call(p, runtime_procedure, args); - } - - if (is_type_quaternion(a)) { - char const *runtime_procedure = ""; - i64 sz = 8*type_size_of(a); - switch (sz) { - case 64: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "quaternion64_eq"; break; - case Token_NotEq: runtime_procedure = "quaternion64_ne"; break; - } - break; - case 128: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "quaternion128_eq"; break; - case Token_NotEq: runtime_procedure = "quaternion128_ne"; break; - } - break; - case 256: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "quaternion256_eq"; break; - case Token_NotEq: runtime_procedure = "quaternion256_ne"; break; - } - break; - } - GB_ASSERT(runtime_procedure != nullptr); - - GB_PANIC("TODO(bill): cg_emit_runtime_call"); - // auto args = array_make(permanent_allocator(), 2); - // args[0] = left; - // args[1] = right; - // return lb_emit_runtime_call(p, runtime_procedure, args); - } - - if (is_type_bit_set(a)) { - switch (op_kind) { - case Token_Lt: - case Token_LtEq: - case Token_Gt: - case Token_GtEq: - { - Type *it = bit_set_to_int(a); - cgValue lhs = cg_emit_transmute(p, left, it); - cgValue rhs = cg_emit_transmute(p, right, it); - cgValue res = cg_emit_arith(p, Token_And, lhs, rhs, it); - GB_ASSERT(lhs.kind == cgValue_Value); - GB_ASSERT(rhs.kind == cgValue_Value); - GB_ASSERT(res.kind == cgValue_Value); - - if (op_kind == Token_Lt || op_kind == Token_LtEq) { - // (lhs & rhs) == lhs - res = cg_value(tb_inst_cmp_eq(p->func, res.node, lhs.node), t_bool); - } else if (op_kind == Token_Gt || op_kind == Token_GtEq) { - // (lhs & rhs) == rhs - res = cg_value(tb_inst_cmp_eq(p->func, res.node, rhs.node), t_bool); - } - - // NOTE(bill): Strict subsets - if (op_kind == Token_Lt || op_kind == Token_Gt) { - // res &~ (lhs == rhs) - cgValue eq = cg_value(tb_inst_cmp_eq(p->func, lhs.node, rhs.node), t_bool); - res = cg_emit_arith(p, Token_AndNot, res, eq, t_bool); - } - return res; - } - - case Token_CmpEq: - GB_ASSERT(left.kind == cgValue_Value); - GB_ASSERT(right.kind == cgValue_Value); - return cg_value(tb_inst_cmp_eq(p->func, left.node, right.node), t_bool); - case Token_NotEq: - GB_ASSERT(left.kind == cgValue_Value); - GB_ASSERT(right.kind == cgValue_Value); - return cg_value(tb_inst_cmp_ne(p->func, left.node, right.node), t_bool); - } - } - - if (op_kind != Token_CmpEq && op_kind != Token_NotEq) { - Type *t = left.type; - if (is_type_integer(t) && is_type_different_to_arch_endianness(t)) { - Type *platform_type = integer_endian_type_to_platform_type(t); - cgValue x = cg_emit_byte_swap(p, left, platform_type); - cgValue y = cg_emit_byte_swap(p, right, platform_type); - left = x; - right = y; - } else if (is_type_float(t) && is_type_different_to_arch_endianness(t)) { - Type *platform_type = integer_endian_type_to_platform_type(t); - cgValue x = cg_emit_conv(p, left, platform_type); - cgValue y = cg_emit_conv(p, right, platform_type); - left = x; - right = y; - } - } - - a = core_type(left.type); - b = core_type(right.type); - - - if (is_type_integer(a) || - is_type_boolean(a) || - is_type_pointer(a) || - is_type_multi_pointer(a) || - is_type_proc(a) || - is_type_enum(a) || - is_type_typeid(a)) { - TB_Node *lhs = left.node; - TB_Node *rhs = right.node; - TB_Node *res = nullptr; - - bool is_signed = is_type_integer(left.type) && !is_type_unsigned(left.type); - switch (op_kind) { - case Token_CmpEq: res = tb_inst_cmp_eq(p->func, lhs, rhs); break; - case Token_NotEq: res = tb_inst_cmp_ne(p->func, lhs, rhs); break; - case Token_Gt: res = tb_inst_cmp_igt(p->func, lhs, rhs, is_signed); break; - case Token_GtEq: res = tb_inst_cmp_ige(p->func, lhs, rhs, is_signed); break; - case Token_Lt: res = tb_inst_cmp_ilt(p->func, lhs, rhs, is_signed); break; - case Token_LtEq: res = tb_inst_cmp_ile(p->func, lhs, rhs, is_signed); break; - } - - GB_ASSERT(res != nullptr); - return cg_value(res, t_bool); - } else if (is_type_float(a)) { - TB_Node *lhs = left.node; - TB_Node *rhs = right.node; - TB_Node *res = nullptr; - switch (op_kind) { - case Token_CmpEq: res = tb_inst_cmp_eq(p->func, lhs, rhs); break; - case Token_NotEq: res = tb_inst_cmp_ne(p->func, lhs, rhs); break; - case Token_Gt: res = tb_inst_cmp_fgt(p->func, lhs, rhs); break; - case Token_GtEq: res = tb_inst_cmp_fge(p->func, lhs, rhs); break; - case Token_Lt: res = tb_inst_cmp_flt(p->func, lhs, rhs); break; - case Token_LtEq: res = tb_inst_cmp_fle(p->func, lhs, rhs); break; - } - GB_ASSERT(res != nullptr); - return cg_value(res, t_bool); - } else if (is_type_simd_vector(a)) { - GB_PANIC("TODO(bill): #simd vector"); - // LLVMValueRef mask = nullptr; - // Type *elem = base_array_type(a); - // if (is_type_float(elem)) { - // LLVMRealPredicate pred = {}; - // switch (op_kind) { - // case Token_CmpEq: pred = LLVMRealOEQ; break; - // case Token_NotEq: pred = LLVMRealONE; break; - // } - // mask = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); - // } else { - // LLVMIntPredicate pred = {}; - // switch (op_kind) { - // case Token_CmpEq: pred = LLVMIntEQ; break; - // case Token_NotEq: pred = LLVMIntNE; break; - // } - // mask = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); - // } - // GB_ASSERT_MSG(mask != nullptr, "Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); - - // /* NOTE(bill, 2022-05-28): - // Thanks to Per Vognsen, sign extending to - // a vector of the same width as the input vector, bit casting to an integer, - // and then comparing against zero is the better option - // See: https://lists.llvm.org/pipermail/llvm-dev/2012-September/053046.html - - // // Example assuming 128-bit vector - - // %1 = <4 x float> ... - // %2 = <4 x float> ... - // %3 = fcmp oeq <4 x float> %1, %2 - // %4 = sext <4 x i1> %3 to <4 x i32> - // %5 = bitcast <4 x i32> %4 to i128 - // %6 = icmp ne i128 %5, 0 - // br i1 %6, label %true1, label %false2 - - // This will result in 1 cmpps + 1 ptest + 1 br - // (even without SSE4.1, contrary to what the mail list states, because of pmovmskb) - - // */ - - // unsigned count = cast(unsigned)get_array_type_count(a); - // unsigned elem_sz = cast(unsigned)(type_size_of(elem)*8); - // LLVMTypeRef mask_type = LLVMVectorType(LLVMIntTypeInContext(p->module->ctx, elem_sz), count); - // mask = LLVMBuildSExtOrBitCast(p->builder, mask, mask_type, ""); - - // LLVMTypeRef mask_int_type = LLVMIntTypeInContext(p->module->ctx, cast(unsigned)(8*type_size_of(a))); - // LLVMValueRef mask_int = LLVMBuildBitCast(p->builder, mask, mask_int_type, ""); - // res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(LLVMTypeOf(mask_int)), ""); - // return res; - } - - GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); - return {}; -} - -gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x) { - GB_ASSERT(op_kind == Token_CmpEq || op_kind == Token_NotEq); - x = cg_flatten_value(p, x); - cgValue res = {}; - Type *t = x.type; - - TB_DataType dt = cg_data_type(t); - - Type *bt = base_type(t); - TypeKind type_kind = bt->kind; - - switch (type_kind) { - case Type_Basic: - switch (bt->Basic.kind) { - case Basic_rawptr: - case Basic_cstring: - GB_ASSERT(x.kind == cgValue_Value); - if (op_kind == Token_CmpEq) { - return cg_value(tb_inst_cmp_eq(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); - } else if (op_kind == Token_NotEq) { - return cg_value(tb_inst_cmp_ne(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); - } - break; - case Basic_any: - { - GB_ASSERT(x.kind == cgValue_Addr); - // // TODO(bill): is this correct behaviour for nil comparison for any? - cgValue data = cg_emit_struct_ev(p, x, 0); - cgValue id = cg_emit_struct_ev(p, x, 1); - - if (op_kind == Token_CmpEq) { - TB_Node *a = tb_inst_cmp_eq(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); - TB_Node *b = tb_inst_cmp_eq(p->func, id.node, tb_inst_uint(p->func, id.node->dt, 0)); - TB_Node *c = tb_inst_or(p->func, a, b); - return cg_value(c, t_bool); - } else if (op_kind == Token_NotEq) { - TB_Node *a = tb_inst_cmp_ne(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); - TB_Node *b = tb_inst_cmp_ne(p->func, id.node, tb_inst_uint(p->func, id.node->dt, 0)); - TB_Node *c = tb_inst_and(p->func, a, b); - return cg_value(c, t_bool); - } - } - break; - case Basic_typeid: - cgValue invalid_typeid = cg_const_value(p, t_typeid, exact_value_i64(0)); - return cg_emit_comp(p, op_kind, x, invalid_typeid); - } - break; - - case Type_Enum: - case Type_Pointer: - case Type_MultiPointer: - case Type_Proc: - case Type_BitSet: - GB_ASSERT(x.kind == cgValue_Value); - if (op_kind == Token_CmpEq) { - return cg_value(tb_inst_cmp_eq(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); - } else if (op_kind == Token_NotEq) { - return cg_value(tb_inst_cmp_ne(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); - } - break; - - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - { - // NOTE(bill): all of their data "pointer-like" fields are at the 0-index - cgValue data = cg_emit_struct_ev(p, x, 0); - if (op_kind == Token_CmpEq) { - TB_Node *a = tb_inst_cmp_eq(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); - return cg_value(a, t_bool); - } else if (op_kind == Token_NotEq) { - TB_Node *a = tb_inst_cmp_ne(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); - return cg_value(a, t_bool); - } - } - break; - - case Type_Union: - { - if (type_size_of(t) == 0) { - return cg_const_bool(p, t_bool, op_kind == Token_CmpEq); - } else if (is_type_union_maybe_pointer(t)) { - cgValue tag = cg_emit_transmute(p, x, t_rawptr); - return cg_emit_comp_against_nil(p, op_kind, tag); - } else { - GB_ASSERT("TODO(bill): cg_emit_union_tag_value"); - // cgValue tag = cg_emit_union_tag_value(p, x); - // return cg_emit_comp(p, op_kind, tag, cg_zero(p->module, tag.type)); - } - } - break; - case Type_Struct: - GB_PANIC("TODO(bill): cg_emit_struct_ev"); - // if (is_type_soa_struct(t)) { - // Type *bt = base_type(t); - // if (bt->Struct.soa_kind == StructSoa_Slice) { - // LLVMValueRef the_value = {}; - // if (bt->Struct.fields.count == 0) { - // cgValue len = cg_soa_struct_len(p, x); - // the_value = len.value; - // } else { - // cgValue first_field = cg_emit_struct_ev(p, x, 0); - // the_value = first_field.value; - // } - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, the_value, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); - // return res; - // } - // } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { - // LLVMValueRef the_value = {}; - // if (bt->Struct.fields.count == 0) { - // cgValue cap = cg_soa_struct_cap(p, x); - // the_value = cap.value; - // } else { - // cgValue first_field = cg_emit_struct_ev(p, x, 0); - // the_value = first_field.value; - // } - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, the_value, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); - // return res; - // } - // } - // } else if (is_type_struct(t) && type_has_nil(t)) { - // auto args = array_make(permanent_allocator(), 2); - // cgValue lhs = cg_address_from_load_or_generate_local(p, x); - // args[0] = cg_emit_conv(p, lhs, t_rawptr); - // args[1] = cg_const_int(p->module, t_int, type_size_of(t)); - // cgValue val = cg_emit_runtime_call(p, "memory_compare_zero", args); - // cgValue res = cg_emit_comp(p, op_kind, val, cg_const_int(p->module, t_int, 0)); - // return res; - // } - break; - } - GB_PANIC("Unknown handled type: %s -> %s", type_to_string(t), type_to_string(bt)); - return {}; -} - -gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { - t = reduce_tuple_to_single_type(t); - - value = cg_flatten_value(p, value); - - Type *src_type = value.type; - if (are_types_identical(t, src_type)) { - return value; - } - - if (is_type_untyped_uninit(src_type)) { - // return cg_const_undef(m, t); - return cg_const_nil(p, t); - } - if (is_type_untyped_nil(src_type)) { - return cg_const_nil(p, t); - } - - Type *src = core_type(src_type); - Type *dst = core_type(t); - GB_ASSERT(src != nullptr); - GB_ASSERT(dst != nullptr); - - if (are_types_identical(src, dst)) { - return cg_emit_transmute(p, value, t); - } - - TB_DataType st = cg_data_type(src); - if (value.kind == cgValue_Value && !TB_IS_VOID_TYPE(value.node->dt)) { - st = value.node->dt; - } - TB_DataType dt = cg_data_type(t); - - if (is_type_integer(src) && is_type_integer(dst)) { - GB_ASSERT(src->kind == Type_Basic && - dst->kind == Type_Basic); - GB_ASSERT(value.kind == cgValue_Value); - - i64 sz = type_size_of(default_type(src)); - i64 dz = type_size_of(default_type(dst)); - - if (sz == dz) { - if (dz > 1 && !types_have_same_internal_endian(src, dst)) { - return cg_emit_byte_swap(p, value, t); - } - value.type = t; - return value; - } - - if (sz > 1 && is_type_different_to_arch_endianness(src)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - value = cg_emit_byte_swap(p, value, platform_src_type); - } - - TB_Node* (*op)(TB_Function* f, TB_Node* src, TB_DataType dt) = tb_inst_trunc; - - if (dz < sz) { - op = tb_inst_trunc; - } else if (dz == sz) { - op = tb_inst_bitcast; - } else if (dz > sz) { - op = is_type_unsigned(src) ? tb_inst_zxt : tb_inst_sxt; // zero extent - } - - if (dz > 1 && is_type_different_to_arch_endianness(dst)) { - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - - cgValue res = cg_value(op(p->func, value.node, cg_data_type(platform_dst_type)), platform_dst_type); - return cg_emit_byte_swap(p, res, t); - } else { - return cg_value(op(p->func, value.node, dt), t); - } - } - - // boolean -> boolean/integer - if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) { - TB_Node *v = tb_inst_cmp_ne(p->func, value.node, tb_inst_uint(p->func, st, 0)); - return cg_value(tb_inst_zxt(p->func, v, dt), t); - } - - // integer -> boolean - if (is_type_integer(src) && is_type_boolean(dst)) { - TB_Node *v = tb_inst_cmp_ne(p->func, value.node, tb_inst_uint(p->func, st, 0)); - return cg_value(tb_inst_zxt(p->func, v, dt), t); - } - - if (is_type_cstring(src) && is_type_u8_ptr(dst)) { - return cg_emit_transmute(p, value, dst); - } - if (is_type_u8_ptr(src) && is_type_cstring(dst)) { - return cg_emit_transmute(p, value, dst); - } - if (is_type_cstring(src) && is_type_u8_multi_ptr(dst)) { - return cg_emit_transmute(p, value, dst); - } - if (is_type_u8_multi_ptr(src) && is_type_cstring(dst)) { - return cg_emit_transmute(p, value, dst); - } - if (is_type_cstring(src) && is_type_rawptr(dst)) { - return cg_emit_transmute(p, value, dst); - } - if (is_type_rawptr(src) && is_type_cstring(dst)) { - return cg_emit_transmute(p, value, dst); - } - - - if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { - TEMPORARY_ALLOCATOR_GUARD(); - cgValue c = cg_emit_conv(p, value, t_cstring); - auto args = slice_make(temporary_allocator(), 1); - args[0] = c; - cgValue s = cg_emit_runtime_call(p, "cstring_to_string", args); - return cg_emit_conv(p, s, dst); - } - - // float -> float - if (is_type_float(src) && is_type_float(dst)) { - i64 sz = type_size_of(src); - i64 dz = type_size_of(dst); - - if (sz == 2 || dz == 2) { - GB_PANIC("TODO(bill): f16 conversions"); - } - - - if (dz == sz) { - if (types_have_same_internal_endian(src, dst)) { - return cg_value(value.node, t); - } else { - return cg_emit_byte_swap(p, value, t); - } - } - - if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - cgValue res = {}; - res = cg_emit_conv(p, value, platform_src_type); - res = cg_emit_conv(p, res, platform_dst_type); - if (is_type_different_to_arch_endianness(dst)) { - res = cg_emit_byte_swap(p, res, t); - } - return cg_emit_conv(p, res, t); - } - - - if (dz >= sz) { - return cg_value(tb_inst_fpxt(p->func, value.node, dt), t); - } - return cg_value(tb_inst_trunc(p->func, value.node, dt), t); - } - - if (is_type_complex(src) && is_type_complex(dst)) { - GB_PANIC("TODO(bill): complex -> complex"); - } - - if (is_type_quaternion(src) && is_type_quaternion(dst)) { - // @QuaternionLayout - GB_PANIC("TODO(bill): quaternion -> quaternion"); - } - if (is_type_integer(src) && is_type_complex(dst)) { - GB_PANIC("TODO(bill): int -> complex"); - } - if (is_type_float(src) && is_type_complex(dst)) { - GB_PANIC("TODO(bill): float -> complex"); - } - if (is_type_integer(src) && is_type_quaternion(dst)) { - GB_PANIC("TODO(bill): int -> quaternion"); - } - if (is_type_float(src) && is_type_quaternion(dst)) { - GB_PANIC("TODO(bill): float -> quaternion"); - } - if (is_type_complex(src) && is_type_quaternion(dst)) { - GB_PANIC("TODO(bill): complex -> quaternion"); - } - - - // float <-> integer - if (is_type_float(src) && is_type_integer(dst)) { - if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - cgValue res = {}; - res = cg_emit_conv(p, value, platform_src_type); - res = cg_emit_conv(p, res, platform_dst_type); - return cg_emit_conv(p, res, t); - } - - // if (is_type_integer_128bit(dst)) { - // TEMPORARY_ALLOCATOR_GUARD(); - - // auto args = array_make(temporary_allocator(), 1); - // args[0] = value; - // char const *call = "fixunsdfdi"; - // if (is_type_unsigned(dst)) { - // call = "fixunsdfti"; - // } - // lbValue res_i128 = lb_emit_runtime_call(p, call, args); - // return lb_emit_conv(p, res_i128, t); - // } - - bool is_signed = !is_type_unsigned(dst); - return cg_value(tb_inst_float2int(p->func, value.node, dt, is_signed), t); - } - if (is_type_integer(src) && is_type_float(dst)) { - if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - cgValue res = {}; - res = cg_emit_conv(p, value, platform_src_type); - res = cg_emit_conv(p, res, platform_dst_type); - if (is_type_different_to_arch_endianness(dst)) { - res = cg_emit_byte_swap(p, res, t); - } - return cg_emit_conv(p, res, t); - } - - // if (is_type_integer_128bit(src)) { - // TEMPORARY_ALLOCATOR_GUARD(); - - // auto args = array_make(temporary_allocator(), 1); - // args[0] = value; - // char const *call = "floattidf"; - // if (is_type_unsigned(src)) { - // call = "floattidf_unsigned"; - // } - // lbValue res_f64 = lb_emit_runtime_call(p, call, args); - // return lb_emit_conv(p, res_f64, t); - // } - - bool is_signed = !is_type_unsigned(dst); - return cg_value(tb_inst_int2float(p->func, value.node, dt, is_signed), t); - } - - if (is_type_simd_vector(dst)) { - GB_PANIC("TODO(bill): ? -> #simd vector"); - } - - - // Pointer <-> uintptr - if (is_type_pointer(src) && is_type_uintptr(dst)) { - return cg_value(tb_inst_ptr2int(p->func, value.node, dt), t); - } - if (is_type_uintptr(src) && is_type_pointer(dst)) { - return cg_value(tb_inst_int2ptr(p->func, value.node), t); - } - if (is_type_multi_pointer(src) && is_type_uintptr(dst)) { - return cg_value(tb_inst_ptr2int(p->func, value.node, dt), t); - } - if (is_type_uintptr(src) && is_type_multi_pointer(dst)) { - return cg_value(tb_inst_int2ptr(p->func, value.node), t); - } - - if (is_type_union(dst)) { - GB_PANIC("TODO(bill): ? -> union"); - } - - // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's - // subtype polymorphism casting - if (check_is_assignable_to_using_subtype(src_type, t)) { - GB_PANIC("TODO(bill): ? -> subtyping"); - } - - // Pointer <-> Pointer - if (is_type_pointer(src) && is_type_pointer(dst)) { - return cg_value(value.node, t); - } - if (is_type_multi_pointer(src) && is_type_pointer(dst)) { - return cg_value(value.node, t); - } - if (is_type_pointer(src) && is_type_multi_pointer(dst)) { - return cg_value(value.node, t); - } - if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) { - return cg_value(value.node, t); - } - - // proc <-> proc - if (is_type_proc(src) && is_type_proc(dst)) { - return cg_value(value.node, t); - } - - // pointer -> proc - if (is_type_pointer(src) && is_type_proc(dst)) { - return cg_value(value.node, t); - } - // proc -> pointer - if (is_type_proc(src) && is_type_pointer(dst)) { - return cg_value(value.node, t); - } - - // []byte/[]u8 <-> string - if (is_type_u8_slice(src) && is_type_string(dst)) { - return cg_emit_transmute(p, value, t); - } - if (is_type_string(src) && is_type_u8_slice(dst)) { - return cg_emit_transmute(p, value, t); - } - - if (is_type_matrix(dst) && !is_type_matrix(src)) { - GB_PANIC("TODO(bill): !matrix -> matrix"); - } - - if (is_type_matrix(dst) && is_type_matrix(src)) { - GB_PANIC("TODO(bill): matrix -> matrix"); - } - - if (is_type_any(dst)) { - if (is_type_untyped_nil(src) || - is_type_untyped_uninit(src)) { - return cg_const_nil(p, t); - } - - cgAddr result = cg_add_local(p, t, nullptr, false); - - Type *st = default_type(src_type); - - cgValue data = cg_address_from_load_or_generate_local(p, value); - GB_ASSERT(is_type_pointer(data.type)); - GB_ASSERT(is_type_typed(st)); - - data = cg_emit_conv(p, data, t_rawptr); - if (p->name == "main@main") { - GB_PANIC("HERE %s %llu", type_to_string(st), cg_typeid_as_u64(p->module, value.type)); - } - - cgValue id = cg_typeid(p, st); - cgValue data_ptr = cg_emit_struct_ep(p, result.addr, 0); - cgValue id_ptr = cg_emit_struct_ep(p, result.addr, 1); - - cg_emit_store(p, data_ptr, data); - cg_emit_store(p, id_ptr, id); - - return cg_addr_load(p, result); - } - - i64 src_sz = type_size_of(src); - i64 dst_sz = type_size_of(dst); - - if (src_sz == dst_sz) { - // bit_set <-> integer - if (is_type_integer(src) && is_type_bit_set(dst)) { - cgValue v = cg_emit_conv(p, value, bit_set_to_int(dst)); - return cg_emit_transmute(p, v, t); - } - if (is_type_bit_set(src) && is_type_integer(dst)) { - cgValue bs = cg_emit_transmute(p, value, bit_set_to_int(src)); - return cg_emit_conv(p, bs, dst); - } - - // typeid <-> integer - if (is_type_integer(src) && is_type_typeid(dst)) { - return cg_emit_transmute(p, value, dst); - } - if (is_type_typeid(src) && is_type_integer(dst)) { - return cg_emit_transmute(p, value, dst); - } - } - - - if (is_type_untyped(src)) { - if (is_type_string(src) && is_type_string(dst)) { - cgAddr result = cg_add_local(p, t, nullptr, false); - cg_addr_store(p, result, value); - return cg_addr_load(p, result); - } - } - - - gb_printf_err("%.*s\n", LIT(p->name)); - gb_printf_err("cg_emit_conv: src -> dst\n"); - gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); - gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); - gb_printf_err("Not Identical %p != %p\n", src_type, t); - gb_printf_err("Not Identical %p != %p\n", src, dst); - - - GB_PANIC("Invalid type conversion: '%s' to '%s' for procedure '%.*s'", - type_to_string(src_type), type_to_string(t), - LIT(p->name)); - - return {}; -} - -gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type) { - if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) { - GB_PANIC("TODO(bill): cg_emit_arith_array"); - } else if (is_type_matrix(lhs.type) || is_type_matrix(rhs.type)) { - GB_PANIC("TODO(bill): cg_emit_arith_matrix"); - } else if (is_type_complex(type)) { - GB_PANIC("TODO(bill): cg_emit_arith complex"); - } else if (is_type_quaternion(type)) { - GB_PANIC("TODO(bill): cg_emit_arith quaternion"); - } - - lhs = cg_flatten_value(p, cg_emit_conv(p, lhs, type)); - rhs = cg_flatten_value(p, cg_emit_conv(p, rhs, type)); - GB_ASSERT(lhs.kind == cgValue_Value); - GB_ASSERT(rhs.kind == cgValue_Value); - - if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) { - switch (op) { - case Token_AndNot: - case Token_And: - case Token_Or: - case Token_Xor: - goto handle_op; - } - - Type *platform_type = integer_endian_type_to_platform_type(type); - cgValue x = cg_emit_byte_swap(p, lhs, integer_endian_type_to_platform_type(lhs.type)); - cgValue y = cg_emit_byte_swap(p, rhs, integer_endian_type_to_platform_type(rhs.type)); - - cgValue res = cg_emit_arith(p, op, x, y, platform_type); - - return cg_emit_byte_swap(p, res, type); - } - - if (is_type_float(type) && is_type_different_to_arch_endianness(type)) { - Type *platform_type = integer_endian_type_to_platform_type(type); - cgValue x = cg_emit_conv(p, lhs, integer_endian_type_to_platform_type(lhs.type)); - cgValue y = cg_emit_conv(p, rhs, integer_endian_type_to_platform_type(rhs.type)); - - cgValue res = cg_emit_arith(p, op, x, y, platform_type); - - return cg_emit_byte_swap(p, res, type); - } - -handle_op:; - - // NOTE(bill): Bit Set Aliases for + and - - if (is_type_bit_set(type)) { - switch (op) { - case Token_Add: op = Token_Or; break; - case Token_Sub: op = Token_AndNot; break; - } - } - - TB_ArithmeticBehavior arith_behavior = cast(TB_ArithmeticBehavior)0; - - Type *integral_type = type; - if (is_type_simd_vector(integral_type)) { - GB_PANIC("TODO(bill): cg_emit_arith #simd vector"); - // integral_type = core_array_type(integral_type); - } - - switch (op) { - case Token_Add: - if (is_type_float(integral_type)) { - return cg_value(tb_inst_fadd(p->func, lhs.node, rhs.node), type); - } - return cg_value(tb_inst_add(p->func, lhs.node, rhs.node, arith_behavior), type); - case Token_Sub: - if (is_type_float(integral_type)) { - return cg_value(tb_inst_fsub(p->func, lhs.node, rhs.node), type); - } - return cg_value(tb_inst_sub(p->func, lhs.node, rhs.node, arith_behavior), type); - case Token_Mul: - if (is_type_float(integral_type)) { - return cg_value(tb_inst_fmul(p->func, lhs.node, rhs.node), type); - } - return cg_value(tb_inst_mul(p->func, lhs.node, rhs.node, arith_behavior), type); - case Token_Quo: - if (is_type_float(integral_type)) { - return cg_value(tb_inst_fdiv(p->func, lhs.node, rhs.node), type); - } - return cg_value(tb_inst_div(p->func, lhs.node, rhs.node, !is_type_unsigned(integral_type)), type); - case Token_Mod: - if (is_type_float(integral_type)) { - GB_PANIC("TODO(bill): float %% float"); - } - return cg_value(tb_inst_mod(p->func, lhs.node, rhs.node, !is_type_unsigned(integral_type)), type); - case Token_ModMod: - if (is_type_unsigned(integral_type)) { - return cg_value(tb_inst_mod(p->func, lhs.node, rhs.node, false), type); - } else { - TB_Node *a = tb_inst_mod(p->func, lhs.node, rhs.node, true); - TB_Node *b = tb_inst_add(p->func, a, rhs.node, arith_behavior); - TB_Node *c = tb_inst_mod(p->func, b, rhs.node, true); - return cg_value(c, type); - } - - case Token_And: - return cg_value(tb_inst_and(p->func, lhs.node, rhs.node), type); - case Token_Or: - return cg_value(tb_inst_or(p->func, lhs.node, rhs.node), type); - case Token_Xor: - return cg_value(tb_inst_xor(p->func, lhs.node, rhs.node), type); - case Token_Shl: - { - rhs = cg_emit_conv(p, rhs, lhs.type); - TB_DataType dt = cg_data_type(lhs.type); - TB_Node *lhsval = lhs.node; - TB_Node *bits = rhs.node; - - TB_Node *bit_size = tb_inst_uint(p->func, dt, 8*type_size_of(lhs.type)); - TB_Node *zero = tb_inst_uint(p->func, dt, 0); - - TB_Node *width_test = tb_inst_cmp_ilt(p->func, bits, bit_size, false); - - TB_Node *res = tb_inst_shl(p->func, lhsval, bits, arith_behavior); - res = tb_inst_select(p->func, width_test, res, zero); - return cg_value(res, type); - } - case Token_Shr: - { - rhs = cg_emit_conv(p, rhs, lhs.type); - TB_DataType dt = cg_data_type(lhs.type); - TB_Node *lhsval = lhs.node; - TB_Node *bits = rhs.node; - - TB_Node *bit_size = tb_inst_uint(p->func, dt, 8*type_size_of(lhs.type)); - TB_Node *zero = tb_inst_uint(p->func, dt, 0); - - TB_Node *width_test = tb_inst_cmp_ilt(p->func, bits, bit_size, false); - - TB_Node *res = nullptr; - - if (is_type_unsigned(integral_type)) { - res = tb_inst_shr(p->func, lhsval, bits); - } else { - res = tb_inst_sar(p->func, lhsval, bits); - } - - - res = tb_inst_select(p->func, width_test, res, zero); - return cg_value(res, type); - } - case Token_AndNot: - return cg_value(tb_inst_and(p->func, lhs.node, tb_inst_not(p->func, rhs.node)), type); - } - - GB_PANIC("unhandled operator of cg_emit_arith"); - - return {}; -} - - -gb_internal void cg_fill_slice(cgProcedure *p, cgAddr const &slice, cgValue data, cgValue len) { - cgValue slice_ptr = cg_addr_get_ptr(p, slice); - cgValue data_ptr = cg_emit_struct_ep(p, slice_ptr, 0); - cgValue len_ptr = cg_emit_struct_ep(p, slice_ptr, 1); - - data = cg_emit_conv(p, data, type_deref(data_ptr.type)); - len = cg_emit_conv(p, len, t_int); - cg_emit_store(p, data_ptr, data); - cg_emit_store(p, len_ptr, len); -} - -gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { - ast_node(se, SliceExpr, expr); - - cgValue low = cg_const_int(p, t_int, 0); - cgValue high = {}; - - if (se->low != nullptr) { - low = cg_correct_endianness(p, cg_build_expr(p, se->low)); - } - if (se->high != nullptr) { - high = cg_correct_endianness(p, cg_build_expr(p, se->high)); - } - - bool no_indices = se->low == nullptr && se->high == nullptr; - gb_unused(no_indices); - - cgAddr addr = cg_build_addr(p, se->expr); - cgValue base = cg_addr_load(p, addr); - Type *type = base_type(base.type); - - if (is_type_pointer(type)) { - type = base_type(type_deref(type)); - addr = cg_addr(base); - base = cg_addr_load(p, addr); - } - - switch (type->kind) { - case Type_Basic: - case Type_Slice: { - if (type->kind == Type_Basic) { - GB_ASSERT(type->Basic.kind == Basic_string); - } - - Type *slice_type = type; - if (high.node == nullptr) { - cgValue len = cg_builtin_len(p, base); - high = len; - } - - if (!no_indices) { - // cg_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - cgValue elem = cg_emit_ptr_offset(p, cg_builtin_raw_data(p, base), low); - cgValue new_len = cg_emit_arith(p, Token_Sub, high, low, t_int); - - cgAddr slice = cg_add_local(p, slice_type, nullptr, true); - cg_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_RelativeMultiPointer: - GB_PANIC("TODO(bill): Type_RelativeMultiPointer should be handled above already on the cg_addr_load"); - break; - - case Type_DynamicArray: { - // Type *elem_type = type->DynamicArray.elem; - // Type *slice_type = alloc_type_slice(elem_type); - - // lbValue len = lb_dynamic_array_len(p, base); - // if (high.value == nullptr) high = len; - - // if (!no_indices) { - // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - // } - - // lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); - // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - // lbAddr slice = lb_add_local_generated(p, slice_type, false); - // lb_fill_slice(p, slice, elem, new_len); - // return slice; - GB_PANIC("cg_build_addr_slice_expr Type_DynamicArray"); - break; - } - - case Type_MultiPointer: { - Type *res_type = type_of_expr(expr); - if (se->high == nullptr) { - cgAddr res = cg_add_local(p, res_type, nullptr, false); - GB_ASSERT(base.kind == cgValue_Value); - GB_ASSERT(low.kind == cgValue_Value); - - i64 stride = type_size_of(type->MultiPointer.elem); - cgValue offset = cg_value(tb_inst_array_access(p->func, base.node, low.node, stride), base.type); - cg_addr_store(p, res, offset); - return res; - } else { - cgAddr res = cg_add_local(p, res_type, nullptr, true); - low = cg_emit_conv(p, low, t_int); - high = cg_emit_conv(p, high, t_int); - - // cg_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); - - i64 stride = type_size_of(type->MultiPointer.elem); - TB_Node *offset = tb_inst_array_access(p->func, base.node, low.node, stride); - TB_Node *len = tb_inst_sub(p->func, high.node, low.node, cast(TB_ArithmeticBehavior)0); - - TB_Node *data_ptr = tb_inst_member_access(p->func, res.addr.node, type_offset_of(res_type, 0)); - TB_Node *len_ptr = tb_inst_member_access(p->func, res.addr.node, type_offset_of(res_type, 1)); - - tb_inst_store(p->func, TB_TYPE_PTR, data_ptr, offset, cast(TB_CharUnits)build_context.ptr_size, false); - tb_inst_store(p->func, TB_TYPE_INT, len_ptr, len, cast(TB_CharUnits)build_context.int_size, false); - return res; - } - } - - case Type_Array: { - Type *slice_type = type_of_expr(expr); - GB_ASSERT(is_type_slice(slice_type)); - cgValue len = cg_const_int(p, t_int, type->Array.count); - if (high.node == nullptr) high = len; - - // bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; - // bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; - // if (!low_const || !high_const) { - // if (!no_indices) { - // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - // } - // } - cgValue elem = cg_emit_ptr_offset(p, cg_builtin_raw_data(p, cg_addr_get_ptr(p, addr)), low); - cgValue new_len = cg_emit_arith(p, Token_Sub, high, low, t_int); - - cgAddr slice = cg_add_local(p, slice_type, nullptr, true); - cg_fill_slice(p, slice, elem, new_len); - return slice; - } - - - case Type_Struct: - // if (is_type_soa_struct(type)) { - // lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); - // if (high.value == nullptr) high = len; - - // if (!no_indices) { - // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - // } - // #if 1 - - // lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); - // if (type->Struct.soa_kind == StructSoa_Fixed) { - // i32 field_count = cast(i32)type->Struct.fields.count; - // for (i32 i = 0; i < field_count; i++) { - // lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - // lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); - // field_src = lb_emit_array_ep(p, field_src, low); - // lb_emit_store(p, field_dst, field_src); - // } - - // lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - // lb_emit_store(p, len_dst, new_len); - // } else if (type->Struct.soa_kind == StructSoa_Slice) { - // if (no_indices) { - // lb_addr_store(p, dst, base); - // } else { - // i32 field_count = cast(i32)type->Struct.fields.count - 1; - // for (i32 i = 0; i < field_count; i++) { - // lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - // lbValue field_src = lb_emit_struct_ev(p, base, i); - // field_src = lb_emit_ptr_offset(p, field_src, low); - // lb_emit_store(p, field_dst, field_src); - // } - - - // lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - // lb_emit_store(p, len_dst, new_len); - // } - // } else if (type->Struct.soa_kind == StructSoa_Dynamic) { - // i32 field_count = cast(i32)type->Struct.fields.count - 3; - // for (i32 i = 0; i < field_count; i++) { - // lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - // lbValue field_src = lb_emit_struct_ev(p, base, i); - // field_src = lb_emit_ptr_offset(p, field_src, low); - // lb_emit_store(p, field_dst, field_src); - // } - - - // lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - // lb_emit_store(p, len_dst, new_len); - // } - - // return dst; - // #endif - // } - GB_PANIC("cg_build_addr_slice_expr Type_Struct"); - break; - - } - - GB_PANIC("Unknown slicable type"); - return {}; -} - -gb_internal cgValue cg_emit_unary_arith(cgProcedure *p, TokenKind op, cgValue x, Type *type) { - switch (op) { - case Token_Add: - return x; - case Token_Not: // Boolean not - case Token_Xor: // Bitwise not - case Token_Sub: // Number negation - break; - case Token_Pointer: - GB_PANIC("This should be handled elsewhere"); - break; - } - - x = cg_flatten_value(p, x); - - if (is_type_array_like(x.type)) { - GB_PANIC("TODO(bill): cg_emit_unary_arith is_type_array_like"); - // // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory - // Type *tl = base_type(x.type); - // cgValue val = cg_address_from_load_or_generate_local(p, x); - // GB_ASSERT(is_type_array_like(type)); - // Type *elem_type = base_array_type(type); - - // // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops - // cgAddr res_addr = cg_add_local(p, type, nullptr, false); - // cgValue res = cg_addr_get_ptr(p, res_addr); - - // bool inline_array_arith = cg_can_try_to_inline_array_arith(type); - - // i32 count = cast(i32)get_array_type_count(tl); - - // LLVMTypeRef vector_type = nullptr; - // if (op != Token_Not && cg_try_vector_cast(p->module, val, &vector_type)) { - // LLVMValueRef vp = LLVMBuildPointerCast(p->builder, val.value, LLVMPointerType(vector_type, 0), ""); - // LLVMValueRef v = LLVMBuildLoad2(p->builder, vector_type, vp, ""); - - // LLVMValueRef opv = nullptr; - // switch (op) { - // case Token_Xor: - // opv = LLVMBuildNot(p->builder, v, ""); - // break; - // case Token_Sub: - // if (is_type_float(elem_type)) { - // opv = LLVMBuildFNeg(p->builder, v, ""); - // } else { - // opv = LLVMBuildNeg(p->builder, v, ""); - // } - // break; - // } - - // if (opv != nullptr) { - // LLVMSetAlignment(res.value, cast(unsigned)cg_alignof(vector_type)); - // LLVMValueRef res_ptr = LLVMBuildPointerCast(p->builder, res.value, LLVMPointerType(vector_type, 0), ""); - // LLVMBuildStore(p->builder, opv, res_ptr); - // return cg_emit_conv(p, cg_emit_load(p, res), type); - // } - // } - - // if (inline_array_arith) { - // // inline - // for (i32 i = 0; i < count; i++) { - // cgValue e = cg_emit_load(p, cg_emit_array_epi(p, val, i)); - // cgValue z = cg_emit_unary_arith(p, op, e, elem_type); - // cg_emit_store(p, cg_emit_array_epi(p, res, i), z); - // } - // } else { - // auto loop_data = cg_loop_start(p, count, t_i32); - - // cgValue e = cg_emit_load(p, cg_emit_array_ep(p, val, loop_data.idx)); - // cgValue z = cg_emit_unary_arith(p, op, e, elem_type); - // cg_emit_store(p, cg_emit_array_ep(p, res, loop_data.idx), z); - - // cg_loop_end(p, loop_data); - // } - // return cg_emit_load(p, res); - } - - if (op == Token_Xor) { - GB_ASSERT(x.kind == cgValue_Value); - cgValue cmp = cg_value(tb_inst_not(p->func, x.node), x.type); - return cg_emit_conv(p, cmp, type); - } - - if (op == Token_Not) { - TB_Node *zero = cg_const_nil(p, x.type).node; - cgValue cmp = cg_value(tb_inst_cmp_ne(p->func, x.node, zero), x.type); - return cg_emit_conv(p, cmp, type); - } - - if (op == Token_Sub && is_type_integer(type) && is_type_different_to_arch_endianness(type)) { - Type *platform_type = integer_endian_type_to_platform_type(type); - cgValue v = cg_emit_byte_swap(p, x, platform_type); - - cgValue res = cg_value(tb_inst_neg(p->func, v.node), platform_type); - return cg_emit_byte_swap(p, res, type); - } - - if (op == Token_Sub && is_type_float(type) && is_type_different_to_arch_endianness(type)) { - Type *platform_type = integer_endian_type_to_platform_type(type); - cgValue v = cg_emit_byte_swap(p, x, platform_type); - - cgValue res = cg_value(tb_inst_neg(p->func, v.node), platform_type); - return cg_emit_byte_swap(p, res, type); - } - - cgValue res = {}; - - if (op == Token_Sub) { // Number negation - if (is_type_integer(x.type)) { - res = cg_value(tb_inst_neg(p->func, x.node), x.type); - } else if (is_type_float(x.type)) { - res = cg_value(tb_inst_neg(p->func, x.node), x.type); - } else if (is_type_complex(x.type)) { - GB_PANIC("TODO(bill): neg complex"); - // LLVMValueRef v0 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 0, ""), ""); - // LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); - - // cgAddr addr = cg_add_local_generated(p, x.type, false); - // LLVMTypeRef type = llvm_addr_type(p->module, addr.addr); - // LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, "")); - // LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, "")); - // return cg_addr_load(p, addr); - - } else if (is_type_quaternion(x.type)) { - GB_PANIC("TODO(bill): neg quaternion"); - // LLVMValueRef v0 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 0, ""), ""); - // LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); - // LLVMValueRef v2 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 2, ""), ""); - // LLVMValueRef v3 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 3, ""), ""); - - // cgAddr addr = cg_add_local_generated(p, x.type, false); - // LLVMTypeRef type = llvm_addr_type(p->module, addr.addr); - // LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, "")); - // LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, "")); - // LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 2, "")); - // LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 3, "")); - // return cg_addr_load(p, addr); - } else if (is_type_simd_vector(x.type)) { - GB_PANIC("TODO(bill): neg simd"); - // Type *elem = base_array_type(x.type); - // if (is_type_float(elem)) { - // res.value = LLVMBuildFNeg(p->builder, x.value, ""); - // } else { - // res.value = LLVMBuildNeg(p->builder, x.value, ""); - // } - } else if (is_type_matrix(x.type)) { - GB_PANIC("TODO(bill): neg matrix"); - // cgValue zero = {}; - // zero.value = LLVMConstNull(cg_type(p->module, type)); - // zero.type = type; - // return cg_emit_arith_matrix(p, Token_Sub, zero, x, type, true); - } else { - GB_PANIC("Unhandled type %s", type_to_string(x.type)); - } - res.type = x.type; - return res; - } - - return res; -} - -gb_internal void cg_emit_if(cgProcedure *p, cgValue const &cond, TB_Node *true_region, TB_Node *false_region) { - GB_ASSERT(cond.kind == cgValue_Value); - tb_inst_if(p->func, cond.node, true_region, false_region); -} - - -struct cgLoopData { - cgAddr index_addr; - cgValue index; - TB_Node *body; - TB_Node *done; - TB_Node *loop; -}; - -gb_internal cgLoopData cg_loop_start(cgProcedure *p, isize count, Type *index_type) { - cgLoopData data = {}; - - cgValue max = cg_const_int(p, index_type, count); - - data.index_addr = cg_add_local(p, index_type, nullptr, true); - - data.body = cg_control_region(p, "loop_body"); - data.done = cg_control_region(p, "loop_done"); - data.loop = cg_control_region(p, "loop_loop"); - - cg_emit_goto(p, data.loop); - tb_inst_set_control(p->func, data.loop); - - data.index = cg_addr_load(p, data.index_addr); - - cgValue cond = cg_emit_comp(p, Token_Lt, data.index, max); - cg_emit_if(p, cond, data.body, data.done); - tb_inst_set_control(p->func, data.body); - - return data; -} - -gb_internal void cg_loop_end(cgProcedure *p, cgLoopData const &data) { - if (data.index_addr.addr.node != nullptr) { - cg_emit_increment(p, data.index_addr.addr); - cg_emit_goto(p, data.loop); - tb_inst_set_control(p->func, data.done); - } -} - - - -gb_internal void cg_build_try_lhs_rhs(cgProcedure *p, Ast *arg, Type *final_type, cgValue *lhs_, cgValue *rhs_) { - cgValue lhs = {}; - cgValue rhs = {}; - - cgValue value = cg_build_expr(p, arg); - if (value.kind == cgValue_Multi) { - auto const &values = value.multi->values; - if (values.count == 2) { - lhs = values[0]; - rhs = values[1]; - } else { - rhs = values[values.count-1]; - if (values.count > 1) { - lhs = cg_value_multi(slice(values, 0, values.count-1), final_type); - } - } - } else { - rhs = value; - } - - GB_ASSERT(rhs.node != nullptr); - - if (lhs_) *lhs_ = lhs; - if (rhs_) *rhs_ = rhs; -} - -gb_internal cgValue cg_emit_try_has_value(cgProcedure *p, cgValue rhs) { - cgValue has_value = {}; - if (is_type_boolean(rhs.type)) { - has_value = rhs; - } else { - GB_ASSERT_MSG(type_has_nil(rhs.type), "%s", type_to_string(rhs.type)); - has_value = cg_emit_comp_against_nil(p, Token_CmpEq, rhs); - } - GB_ASSERT(has_value.node != nullptr); - return has_value; -} - -gb_internal cgValue cg_build_or_return(cgProcedure *p, Ast *arg, Type *final_type) { - cgValue lhs = {}; - cgValue rhs = {}; - cg_build_try_lhs_rhs(p, arg, final_type, &lhs, &rhs); - - TB_Node *return_region = cg_control_region(p, "or_return_return"); - TB_Node *continue_region = cg_control_region(p, "or_return_continue"); - - cgValue cond = cg_emit_try_has_value(p, rhs); - cg_emit_if(p, cond, continue_region, return_region); - tb_inst_set_control(p->func, return_region); - { - Type *proc_type = base_type(p->type); - Type *results = proc_type->Proc.results; - GB_ASSERT(results != nullptr && results->kind == Type_Tuple); - TypeTuple *tuple = &results->Tuple; - - GB_ASSERT(tuple->variables.count != 0); - - Entity *end_entity = tuple->variables[tuple->variables.count-1]; - rhs = cg_emit_conv(p, rhs, end_entity->type); - if (p->type->Proc.has_named_results) { - GB_ASSERT(end_entity->token.string.len != 0); - - // NOTE(bill): store the named values before returning - cgAddr found = map_must_get(&p->variable_map, end_entity); - cg_addr_store(p, found, rhs); - - cg_build_return_stmt(p, {}); - } else { - GB_ASSERT(tuple->variables.count == 1); - Slice results = {}; - results.data = &rhs; - results.count = 1;; - cg_build_return_stmt_internal(p, results); - } - } - tb_inst_set_control(p->func, continue_region); - if (final_type != nullptr && !is_type_tuple(final_type)) { - return cg_emit_conv(p, lhs, final_type); - } - return {}; -} - -gb_internal cgValue cg_build_or_else(cgProcedure *p, Ast *arg, Ast *else_expr, Type *final_type) { - if (arg->state_flags & StateFlag_DirectiveWasFalse) { - return cg_build_expr(p, else_expr); - } - - cgValue lhs = {}; - cgValue rhs = {}; - cg_build_try_lhs_rhs(p, arg, final_type, &lhs, &rhs); - - GB_ASSERT(else_expr != nullptr); - - if (is_diverging_expr(else_expr)) { - TB_Node *then = cg_control_region(p, "or_else_then"); - TB_Node *else_ = cg_control_region(p, "or_else_else"); - - cg_emit_if(p, cg_emit_try_has_value(p, rhs), then, else_); - // NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used - // from the then block - tb_inst_set_control(p->func, else_); - - cg_build_expr(p, else_expr); - - tb_inst_set_control(p->func, then); - return cg_emit_conv(p, lhs, final_type); - } else { - TB_Node *incoming_values[2] = {}; - TB_Node *incoming_regions[2] = {}; - - TB_Node *then = cg_control_region(p, "or_else_then"); - TB_Node *done = cg_control_region(p, "or_else_done"); // NOTE(bill): Append later - TB_Node *else_ = cg_control_region(p, "or_else_else"); - - cg_emit_if(p, cg_emit_try_has_value(p, rhs), then, else_); - tb_inst_set_control(p->func, then); - - cgValue x = cg_emit_conv(p, lhs, final_type); - incoming_values[0] = x.node; - incoming_regions[0] = tb_inst_get_control(p->func); - - tb_inst_goto(p->func, done); - tb_inst_set_control(p->func, else_); - - cgValue y = cg_emit_conv(p, cg_build_expr(p, else_expr), final_type); - incoming_values[1] = y.node; - incoming_regions[1] = tb_inst_get_control(p->func); - - tb_inst_goto(p->func, done); - tb_inst_set_control(p->func, done); - - GB_ASSERT(x.kind == y.kind); - GB_ASSERT(incoming_values[0]->dt.raw == incoming_values[1]->dt.raw); - cgValue res = {}; - res.kind = x.kind; - res.type = final_type; - - res.node = tb_inst_incomplete_phi(p->func, incoming_values[0]->dt, done, 2); - tb_inst_add_phi_operand(p->func, res.node, incoming_regions[0], incoming_values[0]); - tb_inst_add_phi_operand(p->func, res.node, incoming_regions[1], incoming_values[1]); - return res; - } -} - - -gb_internal isize cg_control_region_pred_count(TB_Node *region) { - GB_ASSERT(region->type == TB_REGION); - GB_ASSERT(region->input_count > 0); - return region->input_count; -} - -gb_internal cgValue cg_build_logical_binary_expr(cgProcedure *p, TokenKind op, Ast *left, Ast *right, Type *final_type) { - TB_Node *rhs = cg_control_region(p, "logical_cmp_rhs"); - TB_Node *done = cg_control_region(p, "logical_cmp_done"); - - cgValue short_circuit = {}; - if (op == Token_CmpAnd) { - cg_build_cond(p, left, rhs, done); - short_circuit = cg_const_bool(p, t_bool, false); - } else if (op == Token_CmpOr) { - cg_build_cond(p, left, done, rhs); - short_circuit = cg_const_bool(p, t_bool, true); - } - - if (rhs->input_count == 0) { - tb_inst_set_control(p->func, done); - return cg_emit_conv(p, short_circuit, final_type); - } - - if (done->input_count == 0) { - tb_inst_set_control(p->func, rhs); - return cg_build_expr(p, right); - } - - tb_inst_set_control(p->func, rhs); - cgValue edge = cg_build_expr(p, right); - TB_Node *edge_region = tb_inst_get_control(p->func); - - tb_inst_goto(p->func, done); - tb_inst_set_control(p->func, done); - - TB_DataType dt = edge.node->dt; - TB_Node *phi = tb_inst_incomplete_phi(p->func, dt, done, done->input_count); - for (size_t i = 0; i < done->input_count; i++) { - TB_Node *val = short_circuit.node; - TB_Node *region = done->inputs[i]; - if (region == edge_region) { - val = edge.node; - } - tb_inst_add_phi_operand(p->func, phi, region, val); - } - return cg_emit_conv(p, cg_value(phi, t_bool), final_type); -} - - - -gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) { - ast_node(be, BinaryExpr, expr); - - TypeAndValue tv = type_and_value_of_expr(expr); - - if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) { - cgValue left = cg_build_expr(p, be->left); - cgValue right = cg_build_expr(p, be->right); - GB_PANIC("TODO(bill): cg_emit_arith_matrix"); - // return cg_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type), false); - } - - - switch (be->op.kind) { - case Token_Add: - case Token_Sub: - case Token_Mul: - case Token_Quo: - case Token_Mod: - case Token_ModMod: - case Token_And: - case Token_Or: - case Token_Xor: - case Token_AndNot: { - Type *type = default_type(tv.type); - cgValue left = cg_build_expr(p, be->left); - cgValue right = cg_build_expr(p, be->right); - return cg_emit_arith(p, be->op.kind, left, right, type); - } - - case Token_Shl: - case Token_Shr: { - cgValue left, right; - Type *type = default_type(tv.type); - left = cg_build_expr(p, be->left); - - if (cg_is_expr_untyped_const(be->right)) { - // NOTE(bill): RHS shift operands can still be untyped - // Just bypass the standard cg_build_expr - right = cg_expr_untyped_const_to_typed(p, be->right, type); - } else { - right = cg_build_expr(p, be->right); - } - return cg_emit_arith(p, be->op.kind, left, right, type); - } - - case Token_CmpEq: - case Token_NotEq: - if (is_type_untyped_nil(be->right->tav.type)) { - // `x == nil` or `x != nil` - cgValue left = cg_build_expr(p, be->left); - cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, left); - Type *type = default_type(tv.type); - return cg_emit_conv(p, cmp, type); - } else if (is_type_untyped_nil(be->left->tav.type)) { - // `nil == x` or `nil != x` - cgValue right = cg_build_expr(p, be->right); - cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, right); - Type *type = default_type(tv.type); - return cg_emit_conv(p, cmp, type); - }/* else if (cg_is_empty_string_constant(be->right)) { - // `x == ""` or `x != ""` - cgValue s = cg_build_expr(p, be->left); - s = cg_emit_conv(p, s, t_string); - cgValue len = cg_string_len(p, s); - cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); - Type *type = default_type(tv.type); - return cg_emit_conv(p, cmp, type); - } else if (cg_is_empty_string_constant(be->left)) { - // `"" == x` or `"" != x` - cgValue s = cg_build_expr(p, be->right); - s = cg_emit_conv(p, s, t_string); - cgValue len = cg_string_len(p, s); - cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); - Type *type = default_type(tv.type); - return cg_emit_conv(p, cmp, type); - }*/ - /*fallthrough*/ - case Token_Lt: - case Token_LtEq: - case Token_Gt: - case Token_GtEq: - { - cgValue left = {}; - cgValue right = {}; - - if (be->left->tav.mode == Addressing_Type) { - left = cg_typeid(p, be->left->tav.type); - } - if (be->right->tav.mode == Addressing_Type) { - right = cg_typeid(p, be->right->tav.type); - } - if (left.node == nullptr) left = cg_build_expr(p, be->left); - if (right.node == nullptr) right = cg_build_expr(p, be->right); - cgValue cmp = cg_emit_comp(p, be->op.kind, left, right); - Type *type = default_type(tv.type); - return cg_emit_conv(p, cmp, type); - } - - case Token_CmpAnd: - case Token_CmpOr: - return cg_build_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type); - - case Token_in: - case Token_not_in: - { - cgValue left = cg_build_expr(p, be->left); - cgValue right = cg_build_expr(p, be->right); - Type *rt = base_type(right.type); - if (is_type_pointer(rt)) { - right = cg_emit_load(p, right); - rt = base_type(type_deref(rt)); - } - - switch (rt->kind) { - case Type_Map: - { - cgValue map_ptr = cg_address_from_load_or_generate_local(p, right); - cgValue key = left; - cgValue ptr = cg_internal_dynamic_map_get_ptr(p, map_ptr, key); - if (be->op.kind == Token_in) { - return cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); - } else { - return cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool); - } - } - break; - case Type_BitSet: - { - Type *key_type = rt->BitSet.elem; - GB_ASSERT(are_types_identical(left.type, key_type)); - - Type *it = bit_set_to_int(rt); - left = cg_emit_conv(p, left, it); - if (is_type_different_to_arch_endianness(it)) { - left = cg_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it)); - } - - cgValue lower = cg_const_value(p, left.type, exact_value_i64(rt->BitSet.lower)); - cgValue key = cg_emit_arith(p, Token_Sub, left, lower, left.type); - cgValue bit = cg_emit_arith(p, Token_Shl, cg_const_int(p, left.type, 1), key, left.type); - bit = cg_emit_conv(p, bit, it); - - cgValue old_value = cg_emit_transmute(p, right, it); - cgValue new_value = cg_emit_arith(p, Token_And, old_value, bit, it); - - GB_PANIC("TODO(bill): cg_emit_comp"); - // TokenKind op = (be->op.kind == Token_in) ? Token_NotEq : Token_CmpEq; - // return cg_emit_conv(p, cg_emit_comp(p, op, new_value, cg_const_int(p, new_value.type, 0)), t_bool); - } - break; - default: - GB_PANIC("Invalid 'in' type"); - } - break; - } - break; - default: - GB_PANIC("Invalid binary expression"); - break; - } - return {}; -} - -gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block, TB_Node *false_block) { - cond = unparen_expr(cond); - - GB_ASSERT(cond != nullptr); - GB_ASSERT(true_block != nullptr); - GB_ASSERT(false_block != nullptr); - - // Use to signal not to do compile time short circuit for consts - cgValue no_comptime_short_circuit = {}; - - switch (cond->kind) { - case_ast_node(ue, UnaryExpr, cond); - if (ue->op.kind == Token_Not) { - cgValue cond_val = cg_build_cond(p, ue->expr, false_block, true_block); - return cond_val; - // if (cond_val.value && LLVMIsConstant(cond_val.value)) { - // return cg_const_bool(p->module, cond_val.type, LLVMConstIntGetZExtValue(cond_val.value) == 0); - // } - // return no_comptime_short_circuit; - } - case_end; - - case_ast_node(be, BinaryExpr, cond); - if (be->op.kind == Token_CmpAnd) { - TB_Node *block = cg_control_region(p, "cmp_and"); - cg_build_cond(p, be->left, block, false_block); - tb_inst_set_control(p->func, block); - cg_build_cond(p, be->right, true_block, false_block); - return no_comptime_short_circuit; - } else if (be->op.kind == Token_CmpOr) { - TB_Node *block = cg_control_region(p, "cmp_or"); - cg_build_cond(p, be->left, true_block, block); - tb_inst_set_control(p->func, block); - cg_build_cond(p, be->right, true_block, false_block); - return no_comptime_short_circuit; - } - case_end; - } - - cgValue v = {}; - if (cg_is_expr_untyped_const(cond)) { - v = cg_expr_untyped_const_to_typed(p, cond, t_bool); - } else { - v = cg_build_expr(p, cond); - } - cg_emit_if(p, v, true_block, false_block); - return v; -} - -gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); -gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { - cg_set_debug_pos_from_node(p, expr); - - u16 prev_state_flags = p->state_flags; - defer (p->state_flags = prev_state_flags); - - if (expr->state_flags != 0) { - u16 in = expr->state_flags; - u16 out = p->state_flags; - - if (in & StateFlag_bounds_check) { - out |= StateFlag_bounds_check; - out &= ~StateFlag_no_bounds_check; - } else if (in & StateFlag_no_bounds_check) { - out |= StateFlag_no_bounds_check; - out &= ~StateFlag_bounds_check; - } - - if (in & StateFlag_type_assert) { - out |= StateFlag_type_assert; - out &= ~StateFlag_no_type_assert; - } else if (in & StateFlag_no_type_assert) { - out |= StateFlag_no_type_assert; - out &= ~StateFlag_type_assert; - } - - p->state_flags = out; - } - - - // IMPORTANT NOTE(bill): - // Selector Call Expressions (foo->bar(...)) - // must only evaluate `foo` once as it gets transformed into - // `foo.bar(foo, ...)` - // And if `foo` is a procedure call or something more complex, storing the value - // once is a very good idea - // If a stored value is found, it must be removed from the cache - if (expr->state_flags & StateFlag_SelectorCallExpr) { - // cgValue *pp = map_get(&p->selector_values, expr); - // if (pp != nullptr) { - // cgValue res = *pp; - // map_remove(&p->selector_values, expr); - // return res; - // } - // cgAddr *pa = map_get(&p->selector_addr, expr); - // if (pa != nullptr) { - // cgAddr res = *pa; - // map_remove(&p->selector_addr, expr); - // return cg_addr_load(p, res); - // } - } - - cgValue res = cg_build_expr_internal(p, expr); - if (res.kind == cgValue_Symbol) { - GB_ASSERT(is_type_internally_pointer_like(res.type)); - res = cg_value(tb_inst_get_symbol_address(p->func, res.symbol), res.type); - } - - if (expr->state_flags & StateFlag_SelectorCallExpr) { - // map_set(&p->selector_values, expr, res); - } - return res; -} - - -gb_internal cgValue cg_find_ident(cgProcedure *p, Entity *e, Ast *expr) { - cgAddr *found_addr = map_get(&p->variable_map, e); - if (found_addr) { - return cg_addr_load(p, *found_addr); - } - - cgValue *found = nullptr; - rw_mutex_shared_lock(&p->module->values_mutex); - found = map_get(&p->module->values, e); - rw_mutex_shared_unlock(&p->module->values_mutex); - - if (found) { - - auto v = *found; - // NOTE(bill): This is because pointers are already pointers in LLVM - if (is_type_proc(v.type)) { - return v; - } - return cg_emit_load(p, v); - } else if (e != nullptr && e->kind == Entity_Variable) { - return cg_addr_load(p, cg_build_addr(p, expr)); - } - - if (e->kind == Entity_Procedure) { - return cg_find_procedure_value_from_entity(p->module, e); - } - - String pkg = {}; - if (e->pkg) { - pkg = e->pkg->name; - } - gb_printf_err("Error in: %s\n", token_pos_to_string(ast_token(expr).pos)); - GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr); - return {}; -} - -cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { - struct cgCompoundLitElemTempData { - Ast * expr; - cgValue value; - i64 elem_index; - i64 elem_length; - cgValue gep; - }; - - - auto const &populate = [](cgProcedure *p, Slice const &elems, Array *temp_data, Type *compound_type) { - Type *bt = base_type(compound_type); - Type *et = nullptr; - switch (bt->kind) { - case Type_Array: et = bt->Array.elem; break; - case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; - case Type_Slice: et = bt->Slice.elem; break; - case Type_BitSet: et = bt->BitSet.elem; break; - case Type_DynamicArray: et = bt->DynamicArray.elem; break; - case Type_SimdVector: et = bt->SimdVector.elem; break; - case Type_Matrix: et = bt->Matrix.elem; break; - } - GB_ASSERT(et != nullptr); - - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, elems) { - Ast *elem = elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - cgValue value = cg_emit_conv(p, cg_build_expr(p, fv->value), et); - - GB_ASSERT((hi-lo) > 0); - - if (bt->kind == Type_Matrix) { - GB_PANIC("TODO(bill): Type_Matrix"); - // for (i64 k = lo; k < hi; k++) { - // cgCompoundLitElemTempData data = {}; - // data.value = value; - - // data.elem_index = matrix_row_major_index_to_offset(bt, k); - // array_add(temp_data, data); - // } - } else { - enum {MAX_ELEMENT_AMOUNT = 32}; - if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { - for (i64 k = lo; k < hi; k++) { - cgCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = k; - array_add(temp_data, data); - } - } else { - cgCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = lo; - data.elem_length = hi-lo; - array_add(temp_data, data); - } - } - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - cgValue value = cg_emit_conv(p, cg_build_expr(p, fv->value), et); - GB_ASSERT(!is_type_tuple(value.type)); - - cgCompoundLitElemTempData data = {}; - data.value = value; - data.expr = fv->value; - if (bt->kind == Type_Matrix) { - GB_PANIC("TODO(bill): Type_Matrix"); - // data.elem_index = matrix_row_major_index_to_offset(bt, index); - } else { - data.elem_index = index; - } - array_add(temp_data, data); - } - - } else { - // if (bt->kind != Type_DynamicArray && lb_is_elem_const(elem, et)) { - // continue; - // } - - cgValue field_expr = cg_build_expr(p, elem); - GB_ASSERT(!is_type_tuple(field_expr.type)); - - cgValue ev = cg_emit_conv(p, field_expr, et); - - cgCompoundLitElemTempData data = {}; - data.value = ev; - if (bt->kind == Type_Matrix) { - GB_PANIC("TODO(bill): Type_Matrix"); - // data.elem_index = matrix_row_major_index_to_offset(bt, i); - } else { - data.elem_index = i; - } - array_add(temp_data, data); - } - } - }; - - auto const &assign_array = [](cgProcedure *p, Array const &temp_data) { - for (auto const &td : temp_data) if (td.value.node != nullptr) { - if (td.elem_length > 0) { - GB_PANIC("TODO(bill): range"); - // auto loop_data = cg_loop_start(p, cast(isize)td.elem_length, t_i32); - // { - // cgValue dst = td.gep; - // dst = cg_emit_ptr_offset(p, dst, loop_data.idx); - // cg_emit_store(p, dst, td.value); - // } - // cg_loop_end(p, loop_data); - } else { - cg_emit_store(p, td.gep, td.value); - } - } - }; - - - - ast_node(cl, CompoundLit, expr); - - Type *type = type_of_expr(expr); - Type *bt = base_type(type); - - cgAddr v = {}; - if (p->is_startup) { - v = cg_add_global(p, type, nullptr); - } else { - v = cg_add_local(p, type, nullptr, true); - } - - if (cl->elems.count == 0) { - // No need to create it - return v; - } - - TEMPORARY_ALLOCATOR_GUARD(); - - Type *et = nullptr; - switch (bt->kind) { - case Type_Array: et = bt->Array.elem; break; - case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; - case Type_Slice: et = bt->Slice.elem; break; - case Type_BitSet: et = bt->BitSet.elem; break; - case Type_SimdVector: et = bt->SimdVector.elem; break; - case Type_Matrix: et = bt->Matrix.elem; break; - } - - String proc_name = {}; - if (p->entity) { - proc_name = p->entity->token.string; - } - TokenPos pos = ast_token(expr).pos; - - - switch (bt->kind) { - default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; - - case Type_Struct: { - TypeStruct *st = &bt->Struct; - cgValue comp_lit_ptr = cg_addr_get_ptr(p, v); - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - cgValue field_expr = {}; - Entity *field = nullptr; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); - GB_ASSERT(!sel.indirect); - - elem = fv->value; - if (sel.index.count > 1) { - cgValue dst = cg_emit_deep_field_gep(p, comp_lit_ptr, sel); - field_expr = cg_build_expr(p, elem); - field_expr = cg_emit_conv(p, field_expr, sel.entity->type); - cg_emit_store(p, dst, field_expr); - continue; - } - - index = sel.index[0]; - } else { - Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); - GB_ASSERT(sel.index.count == 1); - GB_ASSERT(!sel.indirect); - index = sel.index[0]; - } - - field = st->fields[index]; - Type *ft = field->type; - - field_expr = cg_build_expr(p, elem); - - cgValue gep = {}; - if (st->is_raw_union) { - gep = cg_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); - } else { - gep = cg_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); - } - - Type *fet = field_expr.type; - GB_ASSERT(fet->kind != Type_Tuple); - - // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! - if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { - GB_ASSERT_MSG(union_variant_index(ft, fet) >= 0, "%s", type_to_string(fet)); - - GB_PANIC("TODO(bill): cg_emit_store_union_variant"); - // cg_emit_store_union_variant(p, gep, field_expr, fet); - } else { - cgValue fv = cg_emit_conv(p, field_expr, ft); - cg_emit_store(p, gep, fv); - } - } - return v; - } - - case Type_Map: { - GB_ASSERT(!build_context.no_dynamic_literals); - GB_PANIC("TODO(bill): map literals"); - - // cgValue err = cg_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); - // gb_unused(err); - - // for (Ast *elem : cl->elems) { - // ast_node(fv, FieldValue, elem); - - // cgValue key = cg_build_expr(p, fv->field); - // cgValue value = cg_build_expr(p, fv->value); - // cg_internal_dynamic_map_set(p, v.addr, type, key, value, elem); - // } - break; - } - - case Type_Array: { - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - populate(p, cl->elems, &temp_data, type); - - cgValue dst_ptr = cg_addr_get_ptr(p, v); - for_array(i, temp_data) { - i32 index = cast(i32)(temp_data[i].elem_index); - temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); - } - - assign_array(p, temp_data); - break; - } - case Type_EnumeratedArray: { - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - populate(p, cl->elems, &temp_data, type); - - cgValue dst_ptr = cg_addr_get_ptr(p, v); - i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value); - for_array(i, temp_data) { - i32 index = cast(i32)(temp_data[i].elem_index - index_offset); - temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); - } - - assign_array(p, temp_data); - break; - } - case Type_Slice: { - isize count = gb_max(cl->elems.count, cl->max_count); - - TB_CharUnits backing_size = cast(TB_CharUnits)(type_size_of(bt->Slice.elem) * count); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(bt->Slice.elem); - - TB_Node *backing = nullptr; - if (p->is_startup) { - TB_Global *global = tb_global_create(p->module->mod, 0, "", nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(p->module->mod, tb_module_get_data(p->module->mod), global, backing_size, align, 0); - backing = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); - } else { - backing = tb_inst_local(p->func, backing_size, align); - } - - cgValue data = cg_value(backing, alloc_type_multi_pointer(bt->Slice.elem)); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - populate(p, cl->elems, &temp_data, type); - - - for_array(i, temp_data) { - temp_data[i].gep = cg_emit_ptr_offset(p, data, cg_const_int(p, t_int, temp_data[i].elem_index)); - } - - assign_array(p, temp_data); - cg_fill_slice(p, v, data, cg_const_int(p, t_int, count)); - return v; - } - - case Type_DynamicArray: { - GB_ASSERT(!build_context.no_dynamic_literals); - - Type *et = bt->DynamicArray.elem; - cgValue size = cg_const_int(p, t_int, type_size_of(et)); - cgValue align = cg_const_int(p, t_int, type_align_of(et)); - - i64 item_count = gb_max(cl->max_count, cl->elems.count); - { - - auto args = slice_make(temporary_allocator(), 5); - args[0] = cg_emit_conv(p, cg_addr_get_ptr(p, v), t_rawptr); - args[1] = size; - args[2] = align; - args[3] = cg_const_int(p, t_int, item_count); - args[4] = cg_emit_source_code_location_as_global(p, proc_name, pos); - cg_emit_runtime_call(p, "__dynamic_array_reserve", args); - } - - Type *array_type = alloc_type_array(et, item_count); - cgAddr items_addr = cg_add_local(p, array_type, nullptr, true); - cgValue items = cg_addr_get_ptr(p, items_addr); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - populate(p, cl->elems, &temp_data, type); - - for_array(i, temp_data) { - temp_data[i].gep = cg_emit_array_epi(p, items, temp_data[i].elem_index); - } - assign_array(p, temp_data); - - { - auto args = slice_make(temporary_allocator(), 6); - args[0] = cg_emit_conv(p, v.addr, t_rawptr); - args[1] = size; - args[2] = align; - args[3] = cg_emit_conv(p, items, t_rawptr); - args[4] = cg_const_int(p, t_int, item_count); - args[5] = cg_emit_source_code_location_as_global(p, proc_name, pos); - cg_emit_runtime_call(p, "__dynamic_array_append", args); - } - break; - } - - case Type_Basic: { - GB_ASSERT(is_type_any(bt)); - String field_names[2] = { - str_lit("data"), - str_lit("id"), - }; - Type *field_types[2] = { - t_rawptr, - t_typeid, - }; - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - cgValue field_expr = {}; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); - index = sel.index[0]; - elem = fv->value; - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field(bt, field_names[field_index], false); - index = sel.index[0]; - } - - field_expr = cg_build_expr(p, elem); - - GB_ASSERT(field_expr.type->kind != Type_Tuple); - - Type *ft = field_types[index]; - cgValue fv = cg_emit_conv(p, field_expr, ft); - cgValue gep = cg_emit_struct_ep(p, cg_addr_get_ptr(p, v), index); - cg_emit_store(p, gep, fv); - } - break; - } - - case Type_BitSet: { - i64 sz = type_size_of(type); - if (sz == 0) { - return v; - } - cgValue lower = cg_const_value(p, t_int, exact_value_i64(bt->BitSet.lower)); - Type *it = bit_set_to_int(bt); - cgValue one = cg_const_value(p, it, exact_value_i64(1)); - for (Ast *elem : cl->elems) { - GB_ASSERT(elem->kind != Ast_FieldValue); - - cgValue expr = cg_build_expr(p, elem); - GB_ASSERT(expr.type->kind != Type_Tuple); - - cgValue e = cg_emit_conv(p, expr, it); - e = cg_emit_arith(p, Token_Sub, e, lower, it); - e = cg_emit_arith(p, Token_Shl, one, e, it); - - cgValue old_value = cg_emit_transmute(p, cg_addr_load(p, v), it); - cgValue new_value = cg_emit_arith(p, Token_Or, old_value, e, it); - new_value = cg_emit_transmute(p, new_value, type); - cg_addr_store(p, v, new_value); - } - return v; - } - - case Type_Matrix: { - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - populate(p, cl->elems, &temp_data, type); - - cgValue dst_ptr = cg_addr_get_ptr(p, v); - for_array(i, temp_data) { - temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, temp_data[i].elem_index); - } - - assign_array(p, temp_data); - break; - } - - case Type_SimdVector: { - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // populate(p, cl->elems, &temp_data, type); - - // // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` - // // might be a better option - // for (auto const &td : temp_data) if (td.value.node != nullptr) { - // if (td.elem_length > 0) { - // for (i64 k = 0; k < td.elem_length; k++) { - // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index + k).value; - // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); - // } - // } else { - // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index).value; - // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); - - // } - // } - break; - } - } - - return v; -} - -gb_internal cgValue cg_make_soa_pointer(cgProcedure *p, Type *type, cgValue const &addr, cgValue const &index) { - cgAddr v = cg_add_local(p, type, nullptr, true); - cgValue ptr = cg_emit_struct_ep(p, v.addr, 0); - cgValue idx = cg_emit_struct_ep(p, v.addr, 1); - cg_emit_store(p, ptr, addr); - cg_emit_store(p, idx, cg_emit_conv(p, index, t_int)); - - return cg_addr_load(p, v); -} - -gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) { - ast_node(ue, UnaryExpr, expr); - auto tv = type_and_value_of_expr(expr); - - - Ast *ue_expr = unparen_expr(ue->expr); - if (ue_expr->kind == Ast_IndexExpr && tv.mode == Addressing_OptionalOkPtr && is_type_tuple(tv.type)) { - GB_PANIC("TODO(bill): &m[k]"); - // Type *tuple = tv.type; - - // Type *map_type = type_of_expr(ue_expr->IndexExpr.expr); - // Type *ot = base_type(map_type); - // Type *t = base_type(type_deref(ot)); - // bool deref = t != ot; - // GB_ASSERT(t->kind == Type_Map); - // ast_node(ie, IndexExpr, ue_expr); - - // cgValue map_val = cg_build_addr_ptr(p, ie->expr); - // if (deref) { - // map_val = cg_emit_load(p, map_val); - // } - - // cgValue key = lb_build_expr(p, ie->index); - // key = lb_emit_conv(p, key, t->Map.key); - - // lbAddr addr = lb_addr_map(map_val, key, t, alloc_type_pointer(t->Map.value)); - // lbValue ptr = lb_addr_get_ptr(p, addr); - - // lbValue ok = lb_emit_comp_against_nil(p, Token_NotEq, ptr); - // ok = lb_emit_conv(p, ok, tuple->Tuple.variables[1]->type); - - // lbAddr res = lb_add_local_generated(p, tuple, false); - // lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - // lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - // lb_emit_store(p, gep0, ptr); - // lb_emit_store(p, gep1, ok); - // return lb_addr_load(p, res); - - } else if (is_type_soa_pointer(tv.type)) { - ast_node(ie, IndexExpr, ue_expr); - cgValue addr = cg_build_addr_ptr(p, ie->expr); - cgValue index = cg_build_expr(p, ie->index); - - if (!build_context.no_bounds_check) { - // TODO(bill): soa bounds checking - } - - return cg_make_soa_pointer(p, tv.type, addr, index); - } else if (ue_expr->kind == Ast_CompoundLit) { - cgAddr addr = cg_build_addr_compound_lit(p, expr); - return addr.addr; - } else if (ue_expr->kind == Ast_TypeAssertion) { - GB_PANIC("TODO(bill): &v.(T)"); - // if (is_type_tuple(tv.type)) { - // Type *tuple = tv.type; - // Type *ptr_type = tuple->Tuple.variables[0]->type; - // Type *ok_type = tuple->Tuple.variables[1]->type; - - // ast_node(ta, TypeAssertion, ue_expr); - // TokenPos pos = ast_token(expr).pos; - // Type *type = type_of_expr(ue_expr); - // GB_ASSERT(!is_type_tuple(type)); - - // lbValue e = lb_build_expr(p, ta->expr); - // Type *t = type_deref(e.type); - // if (is_type_union(t)) { - // lbValue v = e; - // if (!is_type_pointer(v.type)) { - // v = lb_address_from_load_or_generate_local(p, v); - // } - // Type *src_type = type_deref(v.type); - // Type *dst_type = type; - - // lbValue src_tag = {}; - // lbValue dst_tag = {}; - // if (is_type_union_maybe_pointer(src_type)) { - // src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - // dst_tag = lb_const_bool(p->module, t_bool, true); - // } else { - // src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - // dst_tag = lb_const_union_tag(p->module, src_type, dst_type); - // } - - // lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - - // lbValue data_ptr = lb_emit_conv(p, v, ptr_type); - // lbAddr res = lb_add_local_generated(p, tuple, true); - // lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - // lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - // lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type))); - // lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type)); - // return lb_addr_load(p, res); - // } else if (is_type_any(t)) { - // lbValue v = e; - // if (is_type_pointer(v.type)) { - // v = lb_emit_load(p, v); - // } - - // lbValue data_ptr = lb_emit_conv(p, lb_emit_struct_ev(p, v, 0), ptr_type); - // lbValue any_id = lb_emit_struct_ev(p, v, 1); - // lbValue id = lb_typeid(p->module, type); - - // lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - - // lbAddr res = lb_add_local_generated(p, tuple, false); - // lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - // lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - // lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type))); - // lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type)); - // return lb_addr_load(p, res); - // } else { - // GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); - // } - - // } else { - // GB_ASSERT(is_type_pointer(tv.type)); - - // ast_node(ta, TypeAssertion, ue_expr); - // TokenPos pos = ast_token(expr).pos; - // Type *type = type_of_expr(ue_expr); - // GB_ASSERT(!is_type_tuple(type)); - - // lbValue e = lb_build_expr(p, ta->expr); - // Type *t = type_deref(e.type); - // if (is_type_union(t)) { - // lbValue v = e; - // if (!is_type_pointer(v.type)) { - // v = lb_address_from_load_or_generate_local(p, v); - // } - // Type *src_type = type_deref(v.type); - // Type *dst_type = type; - - - // if ((p->state_flags & StateFlag_no_type_assert) == 0) { - // lbValue src_tag = {}; - // lbValue dst_tag = {}; - // if (is_type_union_maybe_pointer(src_type)) { - // src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - // dst_tag = lb_const_bool(p->module, t_bool, true); - // } else { - // src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - // dst_tag = lb_const_union_tag(p->module, src_type, dst_type); - // } - - - // isize arg_count = 6; - // if (build_context.no_rtti) { - // arg_count = 4; - // } - - // lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - // auto args = array_make(permanent_allocator(), arg_count); - // args[0] = ok; - - // args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - // args[2] = lb_const_int(p->module, t_i32, pos.line); - // args[3] = lb_const_int(p->module, t_i32, pos.column); - - // if (!build_context.no_rtti) { - // args[4] = lb_typeid(p->module, src_type); - // args[5] = lb_typeid(p->module, dst_type); - // } - // lb_emit_runtime_call(p, "type_assertion_check", args); - // } - - // lbValue data_ptr = v; - // return lb_emit_conv(p, data_ptr, tv.type); - // } else if (is_type_any(t)) { - // lbValue v = e; - // if (is_type_pointer(v.type)) { - // v = lb_emit_load(p, v); - // } - // lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - // if ((p->state_flags & StateFlag_no_type_assert) == 0) { - // GB_ASSERT(!build_context.no_rtti); - - // lbValue any_id = lb_emit_struct_ev(p, v, 1); - - // lbValue id = lb_typeid(p->module, type); - // lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - // auto args = array_make(permanent_allocator(), 6); - // args[0] = ok; - - // args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - // args[2] = lb_const_int(p->module, t_i32, pos.line); - // args[3] = lb_const_int(p->module, t_i32, pos.column); - - // args[4] = any_id; - // args[5] = id; - // lb_emit_runtime_call(p, "type_assertion_check", args); - // } - - // return lb_emit_conv(p, data_ptr, tv.type); - // } else { - // GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); - // } - // } - } - - return cg_build_addr_ptr(p, ue->expr); -} - -gb_internal cgValue cg_emit_cast_union(cgProcedure *p, cgValue value, Type *type, TokenPos pos) { - Type *src_type = value.type; - bool is_ptr = is_type_pointer(src_type); - - bool is_tuple = true; - Type *tuple = type; - if (type->kind != Type_Tuple) { - is_tuple = false; - tuple = make_optional_ok_type(type); - } - - - if (is_ptr) { - value = cg_emit_load(p, value); - } - Type *src = base_type(type_deref(src_type)); - GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type)); - Type *dst = tuple->Tuple.variables[0]->type; - - cgValue value_ = cg_address_from_load_or_generate_local(p, value); - - if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) { - // just do a bit cast of the data at the front - cgValue ptr = cg_emit_conv(p, value_, alloc_type_pointer(type)); - return cg_emit_load(p, ptr); - } - - - cgValue tag = {}; - cgValue dst_tag = {}; - cgValue cond = {}; - cgValue data = {}; - - cgValue gep0 = cg_add_local(p, tuple->Tuple.variables[0]->type, nullptr, true).addr; - cgValue gep1 = cg_add_local(p, tuple->Tuple.variables[1]->type, nullptr, true).addr; - - if (is_type_union_maybe_pointer(src)) { - data = cg_emit_load(p, cg_emit_conv(p, value_, gep0.type)); - } else { - tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, value_)); - dst_tag = cg_const_union_tag(p, src, dst); - } - - TB_Node *ok_block = cg_control_region(p, "union_cast_ok"); - TB_Node *end_block = cg_control_region(p, "union_cast_end"); - - if (data.node != nullptr) { - GB_ASSERT(is_type_union_maybe_pointer(src)); - cond = cg_emit_comp_against_nil(p, Token_NotEq, data); - } else { - cond = cg_emit_comp(p, Token_CmpEq, tag, dst_tag); - } - - cg_emit_if(p, cond, ok_block, end_block); - tb_inst_set_control(p->func, ok_block); - - if (data.node == nullptr) { - data = cg_emit_load(p, cg_emit_conv(p, value_, gep0.type)); - } - cg_emit_store(p, gep0, data); - cg_emit_store(p, gep1, cg_const_bool(p, t_bool, true)); - - cg_emit_goto(p, end_block); - tb_inst_set_control(p->func, end_block); - - if (!is_tuple) { - GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0); - // NOTE(bill): Panic on invalid conversion - Type *dst_type = tuple->Tuple.variables[0]->type; - - isize arg_count = 7; - if (build_context.no_rtti) { - arg_count = 4; - } - - cgValue ok = cg_emit_load(p, gep1); - auto args = slice_make(permanent_allocator(), arg_count); - args[0] = ok; - - args[1] = cg_const_string(p, t_string, get_file_path_string(pos.file_id)); - args[2] = cg_const_int(p, t_i32, pos.line); - args[3] = cg_const_int(p, t_i32, pos.column); - - if (!build_context.no_rtti) { - args[4] = cg_typeid(p, src_type); - args[5] = cg_typeid(p, dst_type); - args[6] = cg_emit_conv(p, value_, t_rawptr); - } - cg_emit_runtime_call(p, "type_assertion_check2", args); - - return cg_emit_load(p, gep0); - } - - return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple); -} - -gb_internal cgValue cg_emit_cast_any(cgProcedure *p, cgValue value, Type *type, TokenPos pos) { - Type *src_type = value.type; - - if (is_type_pointer(src_type)) { - value = cg_emit_load(p, value); - } - - bool is_tuple = true; - Type *tuple = type; - if (type->kind != Type_Tuple) { - is_tuple = false; - tuple = make_optional_ok_type(type); - } - Type *dst_type = tuple->Tuple.variables[0]->type; - - if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) { - // just do a bit cast of the data at the front - cgValue ptr = cg_emit_struct_ev(p, value, 0); - ptr = cg_emit_conv(p, ptr, alloc_type_pointer(type)); - return cg_emit_load(p, ptr); - } - - cgValue dst_typeid = cg_typeid(p, dst_type); - cgValue any_typeid = cg_emit_struct_ev(p, value, 1); - - - TB_Node *ok_block = cg_control_region(p, "any_cast_ok"); - TB_Node *end_block = cg_control_region(p, "any_cast_end"); - cgValue cond = cg_emit_comp(p, Token_CmpEq, any_typeid, dst_typeid); - cg_emit_if(p, cond, ok_block, end_block); - tb_inst_set_control(p->func, ok_block); - - cgValue gep0 = cg_add_local(p, tuple->Tuple.variables[0]->type, nullptr, true).addr; - cgValue gep1 = cg_add_local(p, tuple->Tuple.variables[1]->type, nullptr, true).addr; - - cgValue any_data = cg_emit_struct_ev(p, value, 0); - cgValue ptr = cg_emit_conv(p, any_data, alloc_type_pointer(dst_type)); - cg_emit_store(p, gep0, cg_emit_load(p, ptr)); - cg_emit_store(p, gep1, cg_const_bool(p, t_bool, true)); - - cg_emit_goto(p, end_block); - tb_inst_set_control(p->func, end_block); - - if (!is_tuple) { - // NOTE(bill): Panic on invalid conversion - cgValue ok = cg_emit_load(p, gep1); - - isize arg_count = 7; - if (build_context.no_rtti) { - arg_count = 4; - } - auto args = slice_make(permanent_allocator(), arg_count); - args[0] = ok; - - args[1] = cg_const_string(p, t_string, get_file_path_string(pos.file_id)); - args[2] = cg_const_int(p, t_i32, pos.line); - args[3] = cg_const_int(p, t_i32, pos.column); - - if (!build_context.no_rtti) { - args[4] = any_typeid; - args[5] = dst_typeid; - args[6] = cg_emit_struct_ev(p, value, 0); - } - cg_emit_runtime_call(p, "type_assertion_check2", args); - - return cg_emit_load(p, gep0); - } - - return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple); -} - - -gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *type) { - ast_node(ta, TypeAssertion, expr); - - TokenPos pos = ast_token(expr).pos; - cgValue e = cg_build_expr(p, ta->expr); - Type *t = type_deref(e.type); - - if (is_type_union(t)) { - return cg_emit_cast_union(p, e, type, pos); - } else if (is_type_any(t)) { - return cg_emit_cast_any(p, e, type, pos); - } - GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); - return {}; -} - - -gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { - expr = unparen_expr(expr); - - TokenPos expr_pos = ast_token(expr).pos; - TypeAndValue tv = type_and_value_of_expr(expr); - Type *type = type_of_expr(expr); - GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); - - if (tv.value.kind != ExactValue_Invalid && - expr->kind != Ast_CompoundLit) { - // NOTE(bill): The commented out code below is just for debug purposes only - // if (is_type_untyped(type)) { - // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); - // GB_PANIC("%s\n", type_to_string(tv.type)); - // } - // NOTE(bill): Short on constant values - return cg_const_value(p, type, tv.value); - } else if (tv.mode == Addressing_Type) { - // NOTE(bill, 2023-01-16): is this correct? I hope so at least - return cg_typeid(p, tv.type); - } - - switch (expr->kind) { - case_ast_node(bl, BasicLit, expr); - TokenPos pos = bl->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind])); - case_end; - - case_ast_node(bd, BasicDirective, expr); - TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); - case_end; - - case_ast_node(i, Ident, expr); - Entity *e = entity_from_expr(expr); - e = strip_entity_wrapping(e); - - GB_ASSERT_MSG(e != nullptr, "%s in %.*s %p", expr_to_string(expr), LIT(p->name), expr); - - if (e->kind == Entity_Builtin) { - Token token = ast_token(expr); - GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" - "\t at %s", LIT(builtin_procs[e->Builtin.id].name), - token_pos_to_string(token.pos)); - return {}; - } else if (e->kind == Entity_Nil) { - // TODO(bill): is this correct? - return cg_value(cast(TB_Node *)nullptr, e->type); - } - GB_ASSERT(e->kind != Entity_ProcGroup); - - cgAddr *addr = map_get(&p->variable_map, e); - if (addr) { - return cg_addr_load(p, *addr); - } - return cg_find_ident(p, e, expr); - case_end; - - case_ast_node(i, Implicit, expr); - return cg_addr_load(p, cg_build_addr(p, expr)); - case_end; - - case_ast_node(u, Uninit, expr); - if (is_type_untyped(type)) { - return cg_value(cast(TB_Node *)nullptr, t_untyped_uninit); - } - return cg_value(tb_inst_poison(p->func, cg_data_type(type)), type); - case_end; - - case_ast_node(de, DerefExpr, expr); - return cg_addr_load(p, cg_build_addr(p, expr)); - case_end; - - - case_ast_node(se, SelectorExpr, expr); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode != Addressing_Invalid); - return cg_addr_load(p, cg_build_addr(p, expr)); - case_end; - - case_ast_node(ise, ImplicitSelectorExpr, expr); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode == Addressing_Constant); - - return cg_const_value(p, type, tv.value); - case_end; - - - case_ast_node(se, SelectorCallExpr, expr); - GB_ASSERT(se->modified_call); - return cg_build_call_expr(p, se->call); - case_end; - - case_ast_node(i, CallExpr, expr); - return cg_build_call_expr(p, expr); - case_end; - - case_ast_node(cl, CompoundLit, expr); - cgAddr addr = cg_build_addr_compound_lit(p, expr); - return cg_addr_load(p, addr); - case_end; - - - case_ast_node(te, TernaryIfExpr, expr); - cgValue incoming_values[2] = {}; - TB_Node *incoming_regions[2] = {}; - - TB_Node *then = cg_control_region(p, "if_then"); - TB_Node *done = cg_control_region(p, "if_done"); - TB_Node *else_ = cg_control_region(p, "if_else"); - - cg_build_cond(p, te->cond, then, else_); - tb_inst_set_control(p->func, then); - - Type *type = default_type(type_of_expr(expr)); - - incoming_values [0] = cg_emit_conv(p, cg_build_expr(p, te->x), type); - incoming_regions[0] = tb_inst_get_control(p->func); - - cg_emit_goto(p, done); - tb_inst_set_control(p->func, else_); - - incoming_values [1] = cg_emit_conv(p, cg_build_expr(p, te->y), type); - incoming_regions[1] = tb_inst_get_control(p->func); - - cg_emit_goto(p, done); - tb_inst_set_control(p->func, done); - - GB_ASSERT(incoming_values[0].kind == cgValue_Value || - incoming_values[0].kind == cgValue_Addr); - GB_ASSERT(incoming_values[0].kind == incoming_values[1].kind); - - cgValue res = {}; - res.kind = incoming_values[0].kind; - res.type = type; - TB_DataType dt = cg_data_type(type); - if (res.kind == cgValue_Addr) { - dt = TB_TYPE_PTR; - } - res.node = tb_inst_incomplete_phi(p->func, dt, done, 2); - tb_inst_add_phi_operand(p->func, res.node, incoming_regions[0], incoming_values[0].node); - tb_inst_add_phi_operand(p->func, res.node, incoming_regions[1], incoming_values[1].node); - return res; - case_end; - - case_ast_node(te, TernaryWhenExpr, expr); - TypeAndValue tav = type_and_value_of_expr(te->cond); - GB_ASSERT(tav.mode == Addressing_Constant); - GB_ASSERT(tav.value.kind == ExactValue_Bool); - if (tav.value.value_bool) { - return cg_build_expr(p, te->x); - } else { - return cg_build_expr(p, te->y); - } - case_end; - - case_ast_node(tc, TypeCast, expr); - cgValue e = cg_build_expr(p, tc->expr); - switch (tc->token.kind) { - case Token_cast: - return cg_emit_conv(p, e, type); - case Token_transmute: - return cg_emit_transmute(p, e, type); - } - GB_PANIC("Invalid AST TypeCast"); - case_end; - - case_ast_node(ac, AutoCast, expr); - cgValue value = cg_build_expr(p, ac->expr); - return cg_emit_conv(p, value, type); - case_end; - - case_ast_node(se, SliceExpr, expr); - if (is_type_slice(type_of_expr(se->expr))) { - // NOTE(bill): Quick optimization - if (se->high == nullptr && - (se->low == nullptr || cg_is_expr_constant_zero(se->low))) { - return cg_build_expr(p, se->expr); - } - } - return cg_addr_load(p, cg_build_addr(p, expr)); - case_end; - - case_ast_node(ie, IndexExpr, expr); - return cg_addr_load(p, cg_build_addr(p, expr)); - case_end; - - case_ast_node(ie, MatrixIndexExpr, expr); - return cg_addr_load(p, cg_build_addr(p, expr)); - case_end; - - case_ast_node(ue, UnaryExpr, expr); - if (ue->op.kind == Token_And) { - return cg_build_unary_and(p, expr); - } - cgValue v = cg_build_expr(p, ue->expr); - return cg_emit_unary_arith(p, ue->op.kind, v, type); - case_end; - case_ast_node(be, BinaryExpr, expr); - return cg_build_binary_expr(p, expr); - case_end; - - case_ast_node(oe, OrReturnExpr, expr); - return cg_build_or_return(p, oe->expr, tv.type); - case_end; - - case_ast_node(oe, OrElseExpr, expr); - return cg_build_or_else(p, oe->x, oe->y, tv.type); - case_end; - - case_ast_node(ta, TypeAssertion, expr); - return cg_build_type_assertion(p, expr, tv.type); - case_end; - - case_ast_node(pl, ProcLit, expr); - cgProcedure *anon = cg_procedure_generate_anonymous(p->module, expr, p); - GB_ASSERT(anon != nullptr); - GB_ASSERT(anon->symbol != nullptr); - return cg_value(tb_inst_get_symbol_address(p->func, anon->symbol), type); - case_end; - - } - TokenPos token_pos = ast_token(expr).pos; - GB_PANIC("Unexpected expression\n" - "\tAst: %.*s @ " - "%s\n", - LIT(ast_strings[expr->kind]), - token_pos_to_string(token_pos)); - - return {}; -} - - -gb_internal cgValue cg_map_data_uintptr(cgProcedure *p, cgValue value) { - GB_ASSERT(is_type_map(value.type) || are_types_identical(value.type, t_raw_map)); - cgValue data = cg_emit_struct_ev(p, value, 0); - u64 mask_value = 0; - if (build_context.ptr_size == 4) { - mask_value = 0xfffffffful & ~(MAP_CACHE_LINE_SIZE-1); - } else { - mask_value = 0xffffffffffffffffull & ~(MAP_CACHE_LINE_SIZE-1); - } - cgValue mask = cg_const_int(p, t_uintptr, mask_value); - return cg_emit_arith(p, Token_And, data, mask, t_uintptr); -} - -gb_internal cgValue cg_gen_map_key_hash(cgProcedure *p, cgValue const &map_ptr, cgValue key, cgValue *key_ptr_) { - TEMPORARY_ALLOCATOR_GUARD(); - - cgValue key_ptr = cg_address_from_load_or_generate_local(p, key); - key_ptr = cg_emit_conv(p, key_ptr, t_rawptr); - - if (key_ptr_) *key_ptr_ = key_ptr; - - Type* key_type = base_type(type_deref(map_ptr.type))->Map.key; - - cgValue hasher = cg_hasher_proc_value_for_type(p, key_type); - - Slice args = {}; - args = slice_make(temporary_allocator(), 1); - args[0] = cg_map_data_uintptr(p, cg_emit_load(p, map_ptr)); - cgValue seed = cg_emit_runtime_call(p, "map_seed_from_map_data", args); - - args = slice_make(temporary_allocator(), 2); - args[0] = key_ptr; - args[1] = seed; - return cg_emit_call(p, hasher, args); -} - -gb_internal cgValue cg_internal_dynamic_map_get_ptr(cgProcedure *p, cgValue const &map_ptr, cgValue const &key) { - TEMPORARY_ALLOCATOR_GUARD(); - - Type *map_type = base_type(type_deref(map_ptr.type)); - GB_ASSERT(map_type->kind == Type_Map); - - cgValue ptr = {}; - cgValue key_ptr = {}; - cgValue hash = cg_gen_map_key_hash(p, map_ptr, key, &key_ptr); - - auto args = slice_make(temporary_allocator(), 4); - args[0] = cg_emit_transmute(p, map_ptr, t_raw_map_ptr); - args[1] = cg_builtin_map_info(p, map_type); - args[2] = hash; - args[3] = key_ptr; - - ptr = cg_emit_runtime_call(p, "__dynamic_map_get", args); - - return cg_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); -} - - -gb_internal void cg_internal_dynamic_map_set(cgProcedure *p, cgValue const &map_ptr, Type *map_type, - cgValue const &map_key, cgValue const &map_value, Ast *node) { - TEMPORARY_ALLOCATOR_GUARD(); - - map_type = base_type(map_type); - GB_ASSERT(map_type->kind == Type_Map); - - cgValue key_ptr = {}; - cgValue hash = cg_gen_map_key_hash(p, map_ptr, map_key, &key_ptr); - - cgValue v = cg_emit_conv(p, map_value, map_type->Map.value); - cgValue value_ptr = cg_address_from_load_or_generate_local(p, v); - - auto args = slice_make(temporary_allocator(), 6); - args[0] = cg_emit_conv(p, map_ptr, t_raw_map_ptr); - args[1] = cg_builtin_map_info(p, map_type); - args[2] = hash; - args[3] = cg_emit_conv(p, key_ptr, t_rawptr); - args[4] = cg_emit_conv(p, value_ptr, t_rawptr); - args[5] = cg_emit_source_code_location_as_global(p, node); - cg_emit_runtime_call(p, "__dynamic_map_set", args); -} - - - - -gb_internal cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr) { - cgAddr addr = cg_build_addr(p, expr); - return cg_addr_get_ptr(p, addr); -} - -gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr); -gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr) { - expr = unparen_expr(expr); - - // IMPORTANT NOTE(bill): - // Selector Call Expressions (foo->bar(...)) - // must only evaluate `foo` once as it gets transformed into - // `foo.bar(foo, ...)` - // And if `foo` is a procedure call or something more complex, storing the value - // once is a very good idea - // If a stored value is found, it must be removed from the cache - if (expr->state_flags & StateFlag_SelectorCallExpr) { - // lbAddr *pp = map_get(&p->selector_addr, expr); - // if (pp != nullptr) { - // lbAddr res = *pp; - // map_remove(&p->selector_addr, expr); - // return res; - // } - } - cgAddr addr = cg_build_addr_internal(p, expr); - if (expr->state_flags & StateFlag_SelectorCallExpr) { - // map_set(&p->selector_addr, expr, addr); - } - return addr; -} - -gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) { - ast_node(ie, IndexExpr, expr); - - Type *t = base_type(type_of_expr(ie->expr)); - - bool deref = is_type_pointer(t); - t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { - cgValue val = cg_build_addr_ptr(p, ie->expr); - if (deref) { - val = cg_emit_load(p, val); - } - - cgValue index = cg_build_expr(p, ie->index); - return cg_addr_soa_variable(val, index, ie->index); - } - - if (ie->expr->tav.mode == Addressing_SoaVariable) { - GB_PANIC("TODO(bill): #soa"); - // // SOA Structures for slices/dynamic arrays - // GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); - - // lbValue field = lb_build_expr(p, ie->expr); - // lbValue index = lb_build_expr(p, ie->index); - - - // if (!build_context.no_bounds_check) { - // // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // // GB_ASSERT(LLVMIsALoadInst(field.value)); - - // // lbValue a = {}; - // // a.value = LLVMGetOperand(field.value, 0); - // // a.type = alloc_type_pointer(field.type); - - // // irInstr *b = &a->Instr; - // // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // // lbValue base_struct = b->StructElementPtr.address; - - // // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // // lbValue len = ir_soa_struct_len(p, base_struct); - // // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - // } - // lbValue val = lb_emit_ptr_offset(p, field, index); - // return lb_addr(val); - } - - GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); - - if (is_type_map(t)) { - cgAddr map_addr = cg_build_addr(p, ie->expr); - cgValue key = cg_build_expr(p, ie->index); - key = cg_emit_conv(p, key, t->Map.key); - - Type *result_type = type_of_expr(expr); - cgValue map_ptr = cg_addr_get_ptr(p, map_addr); - if (is_type_pointer(type_deref(map_ptr.type))) { - map_ptr = cg_emit_load(p, map_ptr); - } - return cg_addr_map(map_ptr, key, t, result_type); - } - - switch (t->kind) { - case Type_Array: { - cgValue array = {}; - array = cg_build_addr_ptr(p, ie->expr); - if (deref) { - array = cg_emit_load(p, array); - } - cgValue index = cg_build_expr(p, ie->index); - index = cg_emit_conv(p, index, t_int); - cgValue elem = cg_emit_array_ep(p, array, index); - - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - // cgValue len = cg_const_int(p->module, t_int, t->Array.count); - // cg_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return cg_addr(elem); - } - - case Type_EnumeratedArray: { - cgValue array = {}; - array = cg_build_addr_ptr(p, ie->expr); - if (deref) { - array = cg_emit_load(p, array); - } - - Type *index_type = t->EnumeratedArray.index; - - auto index_tv = type_and_value_of_expr(ie->index); - - cgValue index = {}; - if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { - if (index_tv.mode == Addressing_Constant) { - ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); - index = cg_const_value(p, index_type, idx); - } else { - index = cg_emit_arith(p, Token_Sub, - cg_build_expr(p, ie->index), - cg_const_value(p, index_type, *t->EnumeratedArray.min_value), - index_type); - index = cg_emit_conv(p, index, t_int); - } - } else { - index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int); - } - - cgValue elem = cg_emit_array_ep(p, array, index); - - if (index_tv.mode != Addressing_Constant) { - // cgValue len = cg_const_int(p->module, t_int, t->EnumeratedArray.count); - // cg_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return cg_addr(elem); - } - - case Type_Slice: { - cgValue slice = {}; - slice = cg_build_expr(p, ie->expr); - if (deref) { - slice = cg_emit_load(p, slice); - } - cgValue elem = cg_builtin_raw_data(p, slice); - cgValue index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int); - // cgValue len = cg_builtin_len(p, slice); - // cg_emit_bounds_check(p, ast_token(ie->index), index, len); - cgValue v = cg_emit_ptr_offset(p, elem, index); - v.type = alloc_type_pointer(type_deref(v.type, true)); - return cg_addr(v); - } - - case Type_MultiPointer: { - cgValue multi_ptr = {}; - multi_ptr = cg_build_expr(p, ie->expr); - if (deref) { - multi_ptr = cg_emit_load(p, multi_ptr); - } - cgValue index = cg_build_expr(p, ie->index); - index = cg_emit_conv(p, index, t_int); - - cgValue v = cg_emit_ptr_offset(p, multi_ptr, index); - v.type = alloc_type_pointer(type_deref(v.type, true)); - return cg_addr(v); - } - - case Type_RelativeMultiPointer: { - cgValue multi_ptr = {}; - multi_ptr = cg_build_expr(p, ie->expr); - if (deref) { - multi_ptr = cg_emit_load(p, multi_ptr); - } - cgValue index = cg_build_expr(p, ie->index); - index = cg_emit_conv(p, index, t_int); - - cgValue v = cg_emit_ptr_offset(p, multi_ptr, index); - v.type = alloc_type_pointer(type_deref(v.type, true)); - return cg_addr(v); - } - - case Type_DynamicArray: { - cgValue dynamic_array = {}; - dynamic_array = cg_build_expr(p, ie->expr); - if (deref) { - dynamic_array = cg_emit_load(p, dynamic_array); - } - cgValue elem = cg_builtin_raw_data(p, dynamic_array); - cgValue index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int); - // cgValue len = cg_dynamic_array_len(p, dynamic_array); - // cg_emit_bounds_check(p, ast_token(ie->index), index, len); - cgValue v = cg_emit_ptr_offset(p, elem, index); - v.type = alloc_type_pointer(type_deref(v.type, true)); - return cg_addr(v); - } - - case Type_Matrix: { - GB_PANIC("TODO(bill): matrix"); - // lbValue matrix = {}; - // matrix = lb_build_addr_ptr(p, ie->expr); - // if (deref) { - // matrix = lb_emit_load(p, matrix); - // } - // lbValue index = lb_build_expr(p, ie->index); - // index = lb_emit_conv(p, index, t_int); - // lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); - // elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); - - // auto index_tv = type_and_value_of_expr(ie->index); - // if (index_tv.mode != Addressing_Constant) { - // lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - // } - // return lb_addr(elem); - } - - - case Type_Basic: { // Basic_string - cgValue str; - cgValue elem; - cgValue len; - cgValue index; - - str = cg_build_expr(p, ie->expr); - if (deref) { - str = cg_emit_load(p, str); - } - elem = cg_builtin_raw_data(p, str); - len = cg_builtin_len(p, str); - - index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int); - // cg_emit_bounds_check(p, ast_token(ie->index), index, len); - - cgValue v = cg_emit_ptr_offset(p, elem, index); - v.type = alloc_type_pointer(type_deref(v.type, true)); - return cg_addr(v); - } - } - return {}; -} - -gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { - switch (expr->kind) { - case_ast_node(i, Implicit, expr); - cgAddr v = {}; - switch (i->kind) { - case Token_context: - v = cg_find_or_generate_context_ptr(p); - break; - } - - GB_ASSERT(v.addr.node != nullptr); - return v; - case_end; - - case_ast_node(i, Ident, expr); - if (is_blank_ident(expr)) { - cgAddr val = {}; - return val; - } - String name = i->token.string; - Entity *e = entity_of_node(expr); - return cg_build_addr_from_entity(p, e, expr); - case_end; - - case_ast_node(de, DerefExpr, expr); - Type *t = type_of_expr(de->expr); - if (is_type_relative_pointer(t)) { - cgAddr addr = cg_build_addr(p, de->expr); - addr.relative.deref = true; - return addr; - } else if (is_type_soa_pointer(t)) { - cgValue value = cg_build_expr(p, de->expr); - cgValue ptr = cg_emit_struct_ev(p, value, 0); - cgValue idx = cg_emit_struct_ev(p, value, 1); - return cg_addr_soa_variable(ptr, idx, nullptr); - } - cgValue addr = cg_build_expr(p, de->expr); - return cg_addr(addr); - case_end; - - case_ast_node(ie, IndexExpr, expr); - return cg_build_addr_index_expr(p, expr); - case_end; - - case_ast_node(se, SliceExpr, expr); - return cg_build_addr_slice_expr(p, expr); - case_end; - - case_ast_node(se, SelectorExpr, expr); - Ast *sel_node = unparen_expr(se->selector); - if (sel_node->kind != Ast_Ident) { - GB_PANIC("Unsupported selector expression"); - } - String selector = sel_node->Ident.token.string; - TypeAndValue tav = type_and_value_of_expr(se->expr); - - if (tav.mode == Addressing_Invalid) { - // NOTE(bill): Imports - Entity *imp = entity_of_node(se->expr); - if (imp != nullptr) { - GB_ASSERT(imp->kind == Entity_ImportName); - } - return cg_build_addr(p, unparen_expr(se->selector)); - } - - - Type *type = base_type(tav.type); - if (tav.mode == Addressing_Type) { // Addressing_Type - Selection sel = lookup_field(tav.type, selector, true); - if (sel.pseudo_field) { - GB_ASSERT(sel.entity->kind == Entity_Procedure); - return cg_addr(cg_find_value_from_entity(p->module, sel.entity)); - } - GB_PANIC("Unreachable %.*s", LIT(selector)); - } - - if (se->swizzle_count > 0) { - Type *array_type = base_type(type_deref(tav.type)); - GB_ASSERT(array_type->kind == Type_Array); - u8 swizzle_count = se->swizzle_count; - u8 swizzle_indices_raw = se->swizzle_indices; - u8 swizzle_indices[4] = {}; - for (u8 i = 0; i < swizzle_count; i++) { - u8 index = swizzle_indices_raw>>(i*2) & 3; - swizzle_indices[i] = index; - } - cgValue a = {}; - if (is_type_pointer(tav.type)) { - a = cg_build_expr(p, se->expr); - } else { - cgAddr addr = cg_build_addr(p, se->expr); - a = cg_addr_get_ptr(p, addr); - } - - GB_ASSERT(is_type_array(expr->tav.type)); - GB_PANIC("TODO(bill): cg_addr_swizzle"); - // return cg_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); - } - - Selection sel = lookup_field(type, selector, false); - GB_ASSERT(sel.entity != nullptr); - if (sel.pseudo_field) { - GB_ASSERT(sel.entity->kind == Entity_Procedure); - Entity *e = entity_of_node(sel_node); - return cg_addr(cg_find_value_from_entity(p->module, e)); - } - - { - cgAddr addr = cg_build_addr(p, se->expr); - if (addr.kind == cgAddr_Map) { - cgValue v = cg_addr_load(p, addr); - cgValue a = cg_address_from_load_or_generate_local(p, v); - a = cg_emit_deep_field_gep(p, a, sel); - return cg_addr(a); - } else if (addr.kind == cgAddr_Context) { - GB_ASSERT(sel.index.count > 0); - if (addr.ctx.sel.index.count >= 0) { - sel = selection_combine(addr.ctx.sel, sel); - } - addr.ctx.sel = sel; - addr.kind = cgAddr_Context; - return addr; - } else if (addr.kind == cgAddr_SoaVariable) { - cgValue index = addr.soa.index; - i64 first_index = sel.index[0]; - Selection sub_sel = sel; - sub_sel.index.data += 1; - sub_sel.index.count -= 1; - - cgValue arr = cg_emit_struct_ep(p, addr.addr, first_index); - - Type *t = base_type(type_deref(addr.addr.type)); - GB_ASSERT(is_type_soa_struct(t)); - - // TODO(bill): bounds checking for soa variable - // if (addr.soa.index_expr != nullptr && (!cg_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { - // cgValue len = cg_soa_struct_len(p, addr.addr); - // cg_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); - // } - - cgValue item = {}; - - if (t->Struct.soa_kind == StructSoa_Fixed) { - item = cg_emit_array_ep(p, arr, index); - } else { - item = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); - } - if (sub_sel.index.count > 0) { - item = cg_emit_deep_field_gep(p, item, sub_sel); - } - item.type = alloc_type_pointer(type_deref(item.type, true)); - return cg_addr(item); - } else if (addr.kind == cgAddr_Swizzle) { - GB_ASSERT(sel.index.count > 0); - // NOTE(bill): just patch the index in place - sel.index[0] = addr.swizzle.indices[sel.index[0]]; - } else if (addr.kind == cgAddr_SwizzleLarge) { - GB_ASSERT(sel.index.count > 0); - // NOTE(bill): just patch the index in place - sel.index[0] = addr.swizzle.indices[sel.index[0]]; - } - - cgValue a = cg_addr_get_ptr(p, addr); - a = cg_emit_deep_field_gep(p, a, sel); - return cg_addr(a); - } - case_end; - - case_ast_node(ce, CallExpr, expr); - cgValue res = cg_build_expr(p, expr); - switch (res.kind) { - case cgValue_Value: - return cg_addr(cg_address_from_load_or_generate_local(p, res)); - case cgValue_Addr: - return cg_addr(res); - case cgValue_Multi: - GB_PANIC("cannot address a multi-valued expression"); - break; - } - case_end; - - case_ast_node(cl, CompoundLit, expr); - return cg_build_addr_compound_lit(p, expr); - case_end; - - } - - TokenPos token_pos = ast_token(expr).pos; - GB_PANIC("Unexpected address expression\n" - "\tAst: %.*s @ " - "%s\n", - LIT(ast_strings[expr->kind]), - token_pos_to_string(token_pos)); - - return {}; -} \ No newline at end of file diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp deleted file mode 100644 index 8e9b80144..000000000 --- a/src/tilde_proc.cpp +++ /dev/null @@ -1,1327 +0,0 @@ -gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) { - GB_ASSERT(is_type_proc(type)); - mutex_lock(&m->proc_proto_mutex); - defer (mutex_unlock(&m->proc_proto_mutex)); - - if (type->kind == Type_Named) { - type = base_type(type); - } - TB_FunctionPrototype **found = map_get(&m->proc_proto_map, type); - if (found) { - return *found; - } - - TB_DebugType *dbg = cg_debug_type_for_proc(m, type); - TB_FunctionPrototype *proto = tb_prototype_from_dbg(m->mod, dbg); - - map_set(&m->proc_proto_map, type, proto); - return proto; -} - -gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body) { - 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); - rw_mutex_lock(&m->values_mutex); - p = string_map_must_get(&m->procedures, key); - rw_mutex_unlock(&m->values_mutex); - 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; - p->split_returns_index = -1; - - gbAllocator a = heap_allocator(); - p->children.allocator = a; - - p->defer_stack.allocator = a; - p->scope_stack.allocator = a; - p->context_stack.allocator = a; - - p->control_regions.allocator = a; - p->branch_regions.allocator = a; - - map_init(&p->variable_map); - map_init(&p->soa_values_map); - - 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.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL); - } - if (p->name == "main") { - // TODO(bill): figure out when this should be public or not - linkage = TB_LINKAGE_PUBLIC; - } - - if (p->symbol == nullptr) { - p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage); - - p->debug_type = cg_debug_type_for_proc(m, p->type); - p->proto = tb_prototype_from_dbg(m->mod, p->debug_type); - - p->symbol = cast(TB_Symbol *)p->func; - } - - p->value = cg_value(p->symbol, p->type); - - cg_add_symbol(m, entity, p->symbol); - cg_add_entity(m, entity, p->value); - cg_add_member(m, p->name, p->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; - p->split_returns_index = -1; - - gbAllocator a = heap_allocator(); - p->children.allocator = a; - - p->defer_stack.allocator = a; - p->scope_stack.allocator = a; - p->context_stack.allocator = a; - - p->control_regions.allocator = a; - p->branch_regions.allocator = a; - - map_init(&p->variable_map); - map_init(&p->soa_values_map); - - TB_Linkage linkage = TB_LINKAGE_PRIVATE; - - p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage); - - p->debug_type = cg_debug_type_for_proc(m, p->type); - p->proto = tb_prototype_from_dbg(m->mod, p->debug_type); - - 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 cgProcedure *cg_procedure_generate_anonymous(cgModule *m, Ast *expr, cgProcedure *parent) { - expr = unparen_expr(expr); - ast_node(pl, ProcLit, expr); - - mutex_lock(&m->anonymous_proc_lits_mutex); - defer (mutex_unlock(&m->anonymous_proc_lits_mutex)); - - cgProcedure **found = map_get(&m->anonymous_proc_lits_map, expr); - if (found) { - return *found; - } - - TokenPos pos = ast_token(expr).pos; - - // NOTE(bill): Generate a new name - // parent$count - - String prefix_name = str_lit("proc_lit"); - if (parent) { - prefix_name = parent->name; - } - - isize name_len = prefix_name.len + 6 + 11; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - - static std::atomic name_id; - name_len = gb_snprintf(name_text, name_len, "%.*s$anon-%d", LIT(prefix_name), 1+name_id.fetch_add(1)); - String name = make_string((u8 *)name_text, name_len-1); - - Type *type = type_of_expr(expr); - - GB_ASSERT(pl->decl->entity == nullptr); - Token token = {}; - token.pos = ast_token(expr).pos; - token.kind = Token_Ident; - token.string = name; - Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags); - e->file = expr->file(); - - // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time - e->decl_info = pl->decl; - pl->decl->entity = e; - e->flags |= EntityFlag_ProcBodyChecked; - - cgProcedure *p = cg_procedure_create(m, e); - - map_set(&m->anonymous_proc_lits_map, expr, p); - - if (parent != nullptr) { - array_add(&parent->children, p); - } - - cg_add_procedure_to_queue(p); - return p; - -} - -gb_internal void cg_procedure_begin(cgProcedure *p) { - if (p == nullptr || p->func == nullptr) { - return; - } - - TB_ModuleSectionHandle section = tb_module_get_text(p->module->mod); - tb_function_set_prototype(p->func, section, p->proto, cg_arena()); - - if (p->body == nullptr) { - return; - } - - - DeclInfo *decl = decl_info_of_entity(p->entity); - if (decl != nullptr) { - for_array(i, decl->labels) { - BlockLabel bl = decl->labels[i]; - cgBranchRegions bb = {bl.label, nullptr, nullptr}; - array_add(&p->branch_regions, bb); - } - } - - GB_ASSERT(p->type->kind == Type_Proc); - TypeProc *pt = &p->type->Proc; - bool is_odin_like_cc = is_calling_convention_odin(pt->calling_convention); - int param_index = 0; - int param_count = p->proto->param_count; - - if (pt->results) { - Type *result_type = nullptr; - if (is_odin_like_cc) { - result_type = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; - } else { - result_type = pt->results; - } - TB_DebugType *debug_type = cg_debug_type(p->module, result_type); - TB_PassingRule rule = tb_get_passing_rule_from_dbg(p->module->mod, debug_type, true); - if (rule == TB_PASSING_INDIRECT) { - p->return_by_ptr = true; - param_index++; - } - } - - if (pt->params != nullptr) for (Entity *e : pt->params->Tuple.variables) { - if (e->kind != Entity_Variable) { - continue; - } - - GB_ASSERT_MSG(param_index < param_count, "%d < %d %.*s :: %s", param_index, param_count, LIT(p->name), type_to_string(p->type)); - - TB_Node *param_ptr = nullptr; - - TB_CharUnits size = cast(TB_CharUnits)type_size_of(e->type); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(e->type); - TB_DebugType *debug_type = cg_debug_type(p->module, e->type); - TB_PassingRule rule = tb_get_passing_rule_from_dbg(p->module->mod, debug_type, false); - switch (rule) { - case TB_PASSING_DIRECT: { - TB_Node *param = tb_inst_param(p->func, param_index++); - param_ptr = tb_inst_local(p->func, size, align); - tb_inst_store(p->func, param->dt, param_ptr, param, align, false); - } break; - case TB_PASSING_INDIRECT: - // TODO(bill): does this need a copy? for non-odin calling convention stuff? - param_ptr = tb_inst_param(p->func, param_index++); - break; - case TB_PASSING_IGNORE: - continue; - } - - GB_ASSERT(param_ptr->dt.type == TB_PTR); - - cgValue local = cg_value(param_ptr, alloc_type_pointer(e->type)); - - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - String name = e->token.string; - TB_DebugType *param_debug_type = debug_type; - TB_Node * param_ptr_to_use = param_ptr; - if (rule == TB_PASSING_INDIRECT) { - // HACK TODO(bill): this is just to get the debug information - TB_CharUnits ptr_size = cast(TB_CharUnits)build_context.ptr_size; - TB_Node *dummy_param = tb_inst_local(p->func, ptr_size, ptr_size); - tb_inst_store(p->func, TB_TYPE_PTR, dummy_param, param_ptr, ptr_size, false); - param_ptr_to_use = dummy_param; - param_debug_type = tb_debug_create_ptr(p->module->mod, param_debug_type); - } - tb_function_attrib_variable( - p->func, - param_ptr_to_use, - nullptr, // parent - name.len, cast(char const *)name.text, - param_debug_type - ); - } - cgAddr addr = cg_addr(local); - if (e) { - map_set(&p->variable_map, e, addr); - } - } - - if (is_odin_like_cc) { - p->split_returns_index = param_index; - } - - if (pt->calling_convention == ProcCC_Odin) { - // NOTE(bill): Push context on to stack from implicit parameter - - String name = str_lit("__.context_ptr"); - - Entity *e = alloc_entity_param(nullptr, make_token_ident(name), t_context_ptr, false, false); - e->flags |= EntityFlag_NoAlias; - - TB_Node *param_ptr = tb_inst_param(p->func, param_count-1); - cgValue local = cg_value(param_ptr, t_context_ptr); - cgAddr addr = cg_addr(local); - map_set(&p->variable_map, e, addr); - - - cgContextData *cd = array_add_and_get(&p->context_stack); - cd->ctx = addr; - cd->scope_index = -1; - cd->uses = +1; // make sure it has been used already - } - - if (pt->has_named_results) { - auto const &results = pt->results->Tuple.variables; - for_array(i, results) { - Entity *e = results[i]; - GB_ASSERT(e->kind == Entity_Variable); - - if (e->token.string == "") { - continue; - } - GB_ASSERT(!is_blank_ident(e->token)); - - cgAddr res = cg_add_local(p, e->type, e, true); - - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - cgValue c = cg_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); - cg_addr_store(p, res, c); - } - } - } -} - - -gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { - cgProcedure *p = cast(cgProcedure *)data; - - TB_Passes *opt = tb_pass_enter(p->func, cg_arena()); - defer (tb_pass_exit(opt)); - - // optimization passes - if (false) { - tb_pass_peephole(opt, TB_PEEPHOLE_ALL); - tb_pass_mem2reg(opt); - tb_pass_peephole(opt, TB_PEEPHOLE_ALL); - } - - bool emit_asm = false; - if ( - // string_starts_with(p->name, str_lit("runtime@_windows_default_alloc_or_resize")) || - false - ) { - emit_asm = true; - } - - // emit ir - if ( - // string_starts_with(p->name, str_lit("main@")) || - false - ) { // IR Printing - TB_Arena *arena = cg_arena(); - TB_Passes *passes = tb_pass_enter(p->func, arena); - defer (tb_pass_exit(passes)); - - tb_pass_print(passes); - fprintf(stdout, "\n"); - fflush(stdout); - } - if (false) { // GraphViz printing - tb_pass_print_dot(opt, tb_default_print_callback, stdout); - } - - // compile - TB_FunctionOutput *output = tb_pass_codegen(opt, emit_asm); - if (emit_asm) { - tb_output_print_asm(output, stdout); - fprintf(stdout, "\n"); - fflush(stdout); - } - - return 0; -} - -gb_internal void cg_procedure_end(cgProcedure *p) { - if (p == nullptr || p->func == nullptr) { - return; - } - if (tb_inst_get_control(p->func)) { - if (p->type->Proc.result_count == 0) { - tb_inst_ret(p->func, 0, nullptr); - } else { - tb_inst_unreachable(p->func); - } - } - - if (p->module->do_threading) { - thread_pool_add_task(cg_procedure_compile_worker_proc, p); - } else { - cg_procedure_compile_worker_proc(p); - } -} - -gb_internal void cg_procedure_generate(cgProcedure *p) { - if (p->body == nullptr) { - return; - } - - cg_procedure_begin(p); - cg_build_stmt(p, p->body); - cg_procedure_end(p); -} - -gb_internal void cg_build_nested_proc(cgProcedure *p, AstProcLit *pd, Entity *e) { - GB_ASSERT(pd->body != nullptr); - cgModule *m = p->module; - auto *min_dep_set = &m->info->minimum_dependency_set; - - if (ptr_set_exists(min_dep_set, e) == false) { - // NOTE(bill): Nothing depends upon it so doesn't need to be built - return; - } - - // NOTE(bill): Generate a new name - // parent.name-guid - String original_name = e->token.string; - String pd_name = original_name; - if (e->Procedure.link_name.len > 0) { - pd_name = e->Procedure.link_name; - } - - - isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - - i32 guid = cast(i32)p->children.count; - name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s-%d", LIT(p->name), LIT(pd_name), guid); - String name = make_string(cast(u8 *)name_text, name_len-1); - - e->Procedure.link_name = name; - - cgProcedure *nested_proc = cg_procedure_create(p->module, e); - e->cg_procedure = nested_proc; - - cgValue value = nested_proc->value; - - cg_add_entity(m, e, value); - array_add(&p->children, nested_proc); - cg_add_procedure_to_queue(nested_proc); -} - - - - - -gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e) { - GB_ASSERT(is_type_proc(e->type)); - e = strip_entity_wrapping(e); - GB_ASSERT(e != nullptr); - GB_ASSERT(e->kind == Entity_Procedure); - - cgValue *found = nullptr; - rw_mutex_shared_lock(&m->values_mutex); - found = map_get(&m->values, e); - rw_mutex_shared_unlock(&m->values_mutex); - if (found) { - GB_ASSERT(found->node != nullptr); - return *found; - } - - GB_PANIC("Error in: %s, missing procedure %.*s\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); - return {}; -} - - - -gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr); -gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) { - expr = unparen_expr(expr); - ast_node(ce, CallExpr, expr); - - cgValue res = cg_build_call_expr_internal(p, expr); - - if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures - GB_ASSERT(res.kind == cgValue_Multi); - GB_ASSERT(res.multi->values.count == 2); - return res.multi->values[0]; - } - return res; -} - -gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice const &args) { - if (value.kind == cgValue_Symbol) { - value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); - } - GB_ASSERT(value.kind == cgValue_Value); - TEMPORARY_ALLOCATOR_GUARD(); - - TB_Module *m = p->module->mod; - - - Type *type = base_type(value.type); - GB_ASSERT(type->kind == Type_Proc); - TypeProc *pt = &type->Proc; - gb_unused(pt); - - TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, type); - TB_Node *target = value.node; - auto params = slice_make(temporary_allocator(), proto->param_count); - - - GB_ASSERT(build_context.metrics.os == TargetOs_windows); - // TODO(bill): Support more than Win64 ABI - - bool is_odin_like_cc = is_calling_convention_odin(pt->calling_convention); - - bool return_is_indirect = false; - - Slice result_entities = {}; - Slice param_entities = {}; - if (pt->results) { - result_entities = pt->results->Tuple.variables; - } - if (pt->params) { - param_entities = pt->params->Tuple.variables; - } - - isize param_index = 0; - if (pt->result_count != 0) { - Type *return_type = nullptr; - if (is_odin_like_cc) { - return_type = result_entities[result_entities.count-1]->type; - } else { - return_type = pt->results; - } - TB_DebugType *dbg = cg_debug_type(p->module, return_type); - TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, true); - if (rule == TB_PASSING_INDIRECT) { - return_is_indirect = true; - TB_CharUnits size = cast(TB_CharUnits)type_size_of(return_type); - TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(return_type), 16); - TB_Node *local = tb_inst_local(p->func, size, align); - tb_inst_memzero(p->func, local, tb_inst_uint(p->func, TB_TYPE_INT, size), align); - params[param_index++] = local; - } - } - isize param_entity_index = 0; - for_array(i, args) { - Entity *param_entity = nullptr; - do { - param_entity = param_entities[param_entity_index++]; - } while (param_entity->kind != Entity_Variable); - Type *param_type = param_entity->type; - cgValue arg = args[i]; - arg = cg_emit_conv(p, arg, param_type); - arg = cg_flatten_value(p, arg); - - TB_Node *param = nullptr; - - TB_DebugType *dbg = cg_debug_type(p->module, param_type); - TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, false); - switch (rule) { - case TB_PASSING_DIRECT: - GB_ASSERT(arg.kind == cgValue_Value); - param = arg.node; - break; - case TB_PASSING_INDIRECT: - { - cgValue arg_ptr = {}; - // indirect - if (is_odin_like_cc) { - arg_ptr = cg_address_from_load_or_generate_local(p, arg); - } else { - arg_ptr = cg_copy_value_to_ptr(p, arg, param_type, 16); - } - GB_ASSERT(arg_ptr.kind == cgValue_Value); - param = arg_ptr.node; - } - break; - case TB_PASSING_IGNORE: - continue; - } - - params[param_index++] = param; - } - - // Split returns - isize split_offset = -1; - if (is_odin_like_cc) { - split_offset = param_index; - for (isize i = 0; i < pt->result_count-1; i++) { - Type *result = result_entities[i]->type; - TB_CharUnits size = cast(TB_CharUnits)type_size_of(result); - TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(result), 16); - TB_Node *local = tb_inst_local(p->func, size, align); - // TODO(bill): Should this need to be zeroed any way? - tb_inst_memzero(p->func, local, tb_inst_uint(p->func, TB_TYPE_INT, size), align); - params[param_index++] = local; - } - } - - if (pt->calling_convention == ProcCC_Odin) { - cgValue ctx_ptr = cg_find_or_generate_context_ptr(p).addr; - GB_ASSERT(ctx_ptr.kind == cgValue_Value); - params[param_index++] = ctx_ptr.node; - } - GB_ASSERT_MSG(param_index == params.count, "%td vs %td\n %s %u %u", - param_index, params.count, - type_to_string(type), - proto->return_count, - proto->param_count); - - for (TB_Node *param : params) { - GB_ASSERT(param != nullptr); - } - - GB_ASSERT(target != nullptr); - TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, params.count, params.data); - gb_unused(multi_output); - - switch (pt->result_count) { - case 0: - return {}; - case 1: - if (return_is_indirect) { - return cg_lvalue_addr(params[0], pt->results->Tuple.variables[0]->type); - } else { - GB_ASSERT(multi_output.count == 1); - TB_Node *node = multi_output.single; - return cg_value(node, pt->results->Tuple.variables[0]->type); - } - } - - cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti); - multi->values = slice_make(permanent_allocator(), pt->result_count); - - if (is_odin_like_cc) { - GB_ASSERT(split_offset >= 0); - for (isize i = 0; i < pt->result_count-1; i++) { - multi->values[i] = cg_lvalue_addr(params[split_offset+i], result_entities[i]->type); - } - - Type *end_type = result_entities[pt->result_count-1]->type; - if (return_is_indirect) { - multi->values[pt->result_count-1] = cg_lvalue_addr(params[0], end_type); - } else { - GB_ASSERT(multi_output.count == 1); - TB_DataType dt = cg_data_type(end_type); - TB_Node *res = multi_output.single; - if (res->dt.raw != dt.raw) { - // struct-like returns passed in registers - TB_CharUnits size = cast(TB_CharUnits)type_size_of(end_type); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(end_type); - TB_Node *addr = tb_inst_local(p->func, size, align); - tb_inst_store(p->func, res->dt, addr, res, align, false); - multi->values[pt->result_count-1] = cg_lvalue_addr(addr, end_type); - } else { - multi->values[pt->result_count-1] = cg_value(res, end_type); - } - } - } else { - TB_Node *the_tuple = {}; - if (return_is_indirect) { - the_tuple = params[0]; - } else { - GB_ASSERT(multi_output.count == 1); - TB_Node *res = multi_output.single; - - // struct-like returns passed in registers - TB_CharUnits size = cast(TB_CharUnits)type_size_of(pt->results); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(pt->results); - the_tuple = tb_inst_local(p->func, size, align); - tb_inst_store(p->func, res->dt, the_tuple, res, align, false); - } - for (isize i = 0; i < pt->result_count; i++) { - i64 offset = type_offset_of(pt->results, i, nullptr); - TB_Node *ptr = tb_inst_member_access(p->func, the_tuple, offset); - multi->values[i] = cg_lvalue_addr(ptr, result_entities[i]->type); - } - } - - return cg_value_multi(multi, pt->results); -} - -gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice const &args) { - AstPackage *pkg = p->module->info->runtime_package; - Entity *e = scope_lookup_current(pkg->scope, make_string_c(name)); - cgValue value = cg_find_procedure_value_from_entity(p->module, e); - return cg_emit_call(p, value, args); -} - -gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) { - switch (param_value.kind) { - case ParameterValue_Constant: - if (is_type_constant_type(parameter_type)) { - auto res = cg_const_value(p, parameter_type, param_value.value); - return res; - } else { - ExactValue ev = param_value.value; - cgValue arg = {}; - Type *type = type_of_expr(param_value.original_ast_expr); - if (type != nullptr) { - arg = cg_const_value(p, type, ev); - } else { - arg = cg_const_value(p, parameter_type, param_value.value); - } - return cg_emit_conv(p, arg, parameter_type); - } - - case ParameterValue_Nil: - return cg_const_nil(p, parameter_type); - case ParameterValue_Location: - { - String proc_name = {}; - if (p->entity != nullptr) { - proc_name = p->entity->token.string; - } - return cg_emit_source_code_location_as_global(p, proc_name, pos); - } - case ParameterValue_Value: - return cg_build_expr(p, param_value.ast_value); - } - return cg_const_nil(p, parameter_type); -} - -gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { - ast_node(ce, CallExpr, expr); - - TypeAndValue tv = type_and_value_of_expr(expr); - - TypeAndValue proc_tv = type_and_value_of_expr(ce->proc); - AddressingMode proc_mode = proc_tv.mode; - if (proc_mode == Addressing_Type) { - GB_ASSERT(ce->args.count == 1); - cgValue x = cg_build_expr(p, ce->args[0]); - return cg_emit_conv(p, x, tv.type); - } - - Ast *proc_expr = unparen_expr(ce->proc); - if (proc_mode == Addressing_Builtin) { - Entity *e = entity_of_node(proc_expr); - BuiltinProcId id = BuiltinProc_Invalid; - if (e != nullptr) { - id = cast(BuiltinProcId)e->Builtin.id; - } else { - id = BuiltinProc_DIRECTIVE; - } - if (id == BuiltinProc___entry_point) { - if (p->module->info->entry_point) { - cgValue entry_point = cg_find_procedure_value_from_entity(p->module, p->module->info->entry_point); - GB_ASSERT(entry_point.node != nullptr); - cg_emit_call(p, entry_point, {}); - } - return {}; - } - - return cg_build_builtin(p, id, expr); - } - - // NOTE(bill): Regular call - cgValue value = {}; - - Entity *proc_entity = entity_of_node(proc_expr); - if (proc_entity != nullptr) { - if (proc_entity->flags & EntityFlag_Disabled) { - GB_ASSERT(tv.type == nullptr); - return {}; - } - } - - if (proc_expr->tav.mode == Addressing_Constant) { - ExactValue v = proc_expr->tav.value; - switch (v.kind) { - case ExactValue_Integer: - { - u64 u = big_int_to_u64(&v.value_integer); - cgValue x = cg_value(tb_inst_uint(p->func, TB_TYPE_PTR, u), t_rawptr); - value = cg_emit_conv(p, x, proc_expr->tav.type); - break; - } - case ExactValue_Pointer: - { - u64 u = cast(u64)v.value_pointer; - cgValue x = cg_value(tb_inst_uint(p->func, TB_TYPE_PTR, u), t_rawptr); - value = cg_emit_conv(p, x, proc_expr->tav.type); - break; - } - } - } - - if (value.node == nullptr) { - value = cg_build_expr(p, proc_expr); - } - if (value.kind == cgValue_Addr) { - value = cg_emit_load(p, value); - } - GB_ASSERT(value.kind == cgValue_Value); - GB_ASSERT(value.node != nullptr); - GB_ASSERT(is_type_proc(value.type)); - - TEMPORARY_ALLOCATOR_GUARD(); - - Type *proc_type_ = base_type(value.type); - GB_ASSERT(proc_type_->kind == Type_Proc); - TypeProc *pt = &proc_type_->Proc; - - GB_ASSERT(ce->split_args != nullptr); - - isize internal_param_count = 0; - if (pt->params) for (Entity *e : pt->params->Tuple.variables) { - if (e->kind == Entity_Variable) { - internal_param_count += 1; - } - } - GB_ASSERT(internal_param_count <= pt->param_count); - - auto args = array_make(temporary_allocator(), 0, internal_param_count); - - bool vari_expand = (ce->ellipsis.pos.line != 0); - bool is_c_vararg = pt->c_vararg; - - for_array(i, ce->split_args->positional) { - Entity *e = pt->params->Tuple.variables[i]; - if (e->kind == Entity_TypeName) { - continue; - } else if (e->kind == Entity_Constant) { - continue; - } - - GB_ASSERT(e->kind == Entity_Variable); - if (pt->variadic && pt->variadic_index == i) { - cgValue variadic_args = cg_const_nil(p, e->type); - auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count); - if (variadic.count != 0) { - // variadic call argument generation - Type *slice_type = e->type; - GB_ASSERT(slice_type->kind == Type_Slice); - - if (is_c_vararg) { - GB_ASSERT(!vari_expand); - - Type *elem_type = slice_type->Slice.elem; - - for (Ast *var_arg : variadic) { - cgValue arg = cg_build_expr(p, var_arg); - if (is_type_any(elem_type)) { - array_add(&args, cg_emit_conv(p, arg, default_type(arg.type))); - } else { - array_add(&args, cg_emit_conv(p, arg, elem_type)); - } - } - break; - } else if (vari_expand) { - GB_ASSERT(variadic.count == 1); - variadic_args = cg_build_expr(p, variadic[0]); - variadic_args = cg_emit_conv(p, variadic_args, slice_type); - } else { - Type *elem_type = slice_type->Slice.elem; - - auto var_args = array_make(temporary_allocator(), 0, variadic.count); - for (Ast *var_arg : variadic) { - cgValue v = cg_build_expr(p, var_arg); - cg_append_tuple_values(p, &var_args, v); - } - isize slice_len = var_args.count; - if (slice_len > 0) { - cgAddr slice = cg_add_local(p, slice_type, nullptr, true); - cgAddr base_array = cg_add_local(p, alloc_type_array(elem_type, slice_len), nullptr, true); - - for (isize i = 0; i < var_args.count; i++) { - cgValue addr = cg_emit_array_epi(p, base_array.addr, cast(i32)i); - cgValue var_arg = var_args[i]; - var_arg = cg_emit_conv(p, var_arg, elem_type); - cg_emit_store(p, addr, var_arg); - } - - cgValue base_elem = cg_emit_array_epi(p, base_array.addr, 0); - cgValue len = cg_const_int(p, t_int, slice_len); - cg_fill_slice(p, slice, base_elem, len); - - variadic_args = cg_addr_load(p, slice); - } - } - } - array_add(&args, variadic_args); - - break; - } else { - cgValue value = cg_build_expr(p, ce->split_args->positional[i]); - cg_append_tuple_values(p, &args, value); - } - } - - if (!is_c_vararg) { - array_resize(&args, internal_param_count); - } - - for (Ast *arg : ce->split_args->named) { - ast_node(fv, FieldValue, arg); - GB_ASSERT(fv->field->kind == Ast_Ident); - String name = fv->field->Ident.token.string; - gb_unused(name); - isize param_index = lookup_procedure_parameter(pt, name); - GB_ASSERT(param_index >= 0); - - cgValue value = cg_build_expr(p, fv->value); - GB_ASSERT(!is_type_tuple(value.type)); - args[param_index] = value; - } - - TokenPos pos = ast_token(ce->proc).pos; - - - if (pt->params != nullptr) { - isize min_count = internal_param_count; - if (is_c_vararg) { - min_count -= 1; - } - GB_ASSERT_MSG(args.count >= min_count, "in %.*s", LIT(p->name)); - isize arg_index = 0; - for_array(param_index, pt->params->Tuple.variables) { - Entity *e = pt->params->Tuple.variables[param_index]; - if (e->kind == Entity_TypeName) { - continue; - } else if (e->kind == Entity_Constant) { - continue; - } - GB_ASSERT(e->kind == Entity_Variable); - - if (pt->variadic && param_index == pt->variadic_index) { - if (!is_c_vararg && args[arg_index].node == nullptr) { - args[arg_index++] = cg_const_nil(p, e->type); - continue; - } - } - - cgValue arg = args[arg_index]; - if (arg.node == nullptr) { - GB_ASSERT(e->kind == Entity_Variable); - args[arg_index++] = cg_handle_param_value(p, e->type, e->Variable.param_value, pos); - } else { - args[arg_index++] = cg_emit_conv(p, arg, e->type); - } - } - } - - isize final_count = is_c_vararg ? args.count : internal_param_count; - auto call_args = slice(args, 0, final_count); - - return cg_emit_call(p, value, call_args); -} - - - -gb_internal cgValue cg_hasher_proc_value_for_type(cgProcedure *p, Type *type) { - cgProcedure *found = cg_hasher_proc_for_type(p->module, type); - return cg_value(tb_inst_get_symbol_address(p->func, found->symbol), found->type); -} - -gb_internal cgValue cg_equal_proc_value_for_type(cgProcedure *p, Type *type) { - cgProcedure *found = cg_equal_proc_for_type(p->module, type); - return cg_value(tb_inst_get_symbol_address(p->func, found->symbol), found->type); -} - - - -gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type) { - type = base_type(type); - GB_ASSERT(is_type_comparable(type)); - - mutex_lock(&m->generated_procs_mutex); - defer (mutex_unlock(&m->generated_procs_mutex)); - - cgProcedure **found = map_get(&m->equal_procs, type); - if (found) { - return *found; - } - - static std::atomic proc_index; - - char buf[32] = {}; - isize n = gb_snprintf(buf, 32, "__$equal%u", 1+proc_index.fetch_add(1)); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); - - - cgProcedure *p = cg_procedure_create_dummy(m, proc_name, t_equal_proc); - map_set(&m->equal_procs, type, p); - p->split_returns_index = 2; - - cg_procedure_begin(p); - - TB_Node *x = tb_inst_param(p->func, 0); - TB_Node *y = tb_inst_param(p->func, 1); - GB_ASSERT(x->dt.type == TB_PTR); - GB_ASSERT(y->dt.type == TB_PTR); - - TB_DataType ret_dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; - - TB_Node *node_true = tb_inst_uint(p->func, ret_dt, true); - TB_Node *node_false = tb_inst_uint(p->func, ret_dt, false); - - TB_Node *same_ptr_region = cg_control_region(p, "same_ptr"); - TB_Node *diff_ptr_region = cg_control_region(p, "diff_ptr"); - - TB_Node *is_same_ptr = tb_inst_cmp_eq(p->func, x, y); - tb_inst_if(p->func, is_same_ptr, same_ptr_region, diff_ptr_region); - - tb_inst_set_control(p->func, same_ptr_region); - tb_inst_ret(p->func, 1, &node_true); - - tb_inst_set_control(p->func, diff_ptr_region); - - Type *pt = alloc_type_pointer(type); - cgValue lhs = cg_value(x, pt); - cgValue rhs = cg_value(y, pt); - - if (type->kind == Type_Struct) { - type_set_offsets(type); - - TB_Node *false_region = cg_control_region(p, "bfalse"); - cgValue res = cg_const_bool(p, t_bool, true); - - for_array(i, type->Struct.fields) { - TB_Node *next_region = cg_control_region(p, "btrue"); - - cgValue plhs = cg_emit_struct_ep(p, lhs, i); - cgValue prhs = cg_emit_struct_ep(p, rhs, i); - cgValue left = cg_emit_load(p, plhs); - cgValue right = cg_emit_load(p, prhs); - cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right); - - cg_emit_if(p, ok, next_region, false_region); - - cg_emit_goto(p, next_region); - tb_inst_set_control(p->func, next_region); - } - - tb_inst_ret(p->func, 1, &node_true); - tb_inst_set_control(p->func, false_region); - tb_inst_ret(p->func, 1, &node_false); - - } else if (type->kind == Type_Union) { - if (type_size_of(type) == 0) { - tb_inst_ret(p->func, 1, &node_true); - } else if (is_type_union_maybe_pointer(type)) { - Type *v = type->Union.variants[0]; - Type *pv = alloc_type_pointer(v); - - cgValue left = cg_emit_load(p, cg_emit_conv(p, lhs, pv)); - cgValue right = cg_emit_load(p, cg_emit_conv(p, rhs, pv)); - cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right); - cg_build_return_stmt_internal_single(p, ok); - } else { - TB_Node *false_region = cg_control_region(p, "bfalse"); - TB_Node *switch_region = cg_control_region(p, "bswitch"); - - cgValue lhs_tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, lhs)); - cgValue rhs_tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, rhs)); - - cgValue tag_eq = cg_emit_comp(p, Token_CmpEq, lhs_tag, rhs_tag); - cg_emit_if(p, tag_eq, switch_region, false_region); - - size_t entry_count = type->Union.variants.count; - if (type->Union.kind != UnionType_no_nil) { - entry_count += 1; - } - - size_t entry_offset = 0; - - TB_SwitchEntry *keys = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, entry_count); - if (type->Union.kind != UnionType_no_nil) { - TB_Node *region = cg_control_region(p, "bcase"); - keys[entry_offset].key = 0; - keys[entry_offset].value = region; - entry_offset += 1; - - tb_inst_set_control(p->func, region); - cgValue ok = cg_const_bool(p, t_bool, true); - cg_build_return_stmt_internal_single(p, ok); - } - - for (isize i = 0; i < type->Union.variants.count; i++) { - TB_Node *region = cg_control_region(p, "bcase"); - Type *variant = type->Union.variants[i]; - keys[entry_offset+i].key = union_variant_index(type, variant); - keys[entry_offset+i].value = region; - - tb_inst_set_control(p->func, region); - Type *vp = alloc_type_pointer(variant); - cgValue left = cg_emit_load(p, cg_emit_conv(p, lhs, vp)); - cgValue right = cg_emit_load(p, cg_emit_conv(p, rhs, vp)); - cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right); - cg_build_return_stmt_internal_single(p, ok); - } - - - tb_inst_set_control(p->func, switch_region); - TB_DataType tag_dt = cg_data_type(lhs_tag.type); - GB_ASSERT(lhs_tag.kind == cgValue_Value); - tb_inst_branch(p->func, tag_dt, lhs_tag.node, false_region, entry_count, keys); - - tb_inst_set_control(p->func, false_region); - tb_inst_ret(p->func, 1, &node_false); - } - } else { - cgValue left = cg_lvalue_addr(x, type); - cgValue right = cg_lvalue_addr(y, type); - cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right); - cg_build_return_stmt_internal_single(p, ok); - } - - cg_procedure_end(p); - - return p; -} - - -gb_internal cgValue cg_simple_compare_hash(cgProcedure *p, Type *type, cgValue data, cgValue seed) { - TEMPORARY_ALLOCATOR_GUARD(); - - GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); - - auto args = slice_make(temporary_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = cg_const_int(p, t_int, type_size_of(type)); - return cg_emit_runtime_call(p, "default_hasher", args); -} - - - - - -gb_internal cgProcedure *cg_hasher_proc_for_type(cgModule *m, Type *type) { - type = base_type(type); - GB_ASSERT(is_type_valid_for_keys(type)); - - mutex_lock(&m->generated_procs_mutex); - defer (mutex_unlock(&m->generated_procs_mutex)); - - cgProcedure **found = map_get(&m->hasher_procs, type); - if (found) { - return *found; - } - - static std::atomic proc_index; - - char buf[32] = {}; - isize n = gb_snprintf(buf, 32, "__$hasher%u", 1+proc_index.fetch_add(1)); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); - - - cgProcedure *p = cg_procedure_create_dummy(m, proc_name, t_hasher_proc); - map_set(&m->hasher_procs, type, p); - p->split_returns_index = 2; - - cg_procedure_begin(p); - defer (cg_procedure_end(p)); - - TB_Node *x = tb_inst_param(p->func, 0); // data - TB_Node *y = tb_inst_param(p->func, 1); // seed - - cgValue data = cg_value(x, t_rawptr); - cgValue seed = cg_value(y, t_uintptr); - - if (is_type_simple_compare(type)) { - cgValue res = cg_simple_compare_hash(p, type, data, seed); - cg_build_return_stmt_internal_single(p, res); - return p; - } - - TEMPORARY_ALLOCATOR_GUARD(); - - auto args = slice_make(temporary_allocator(), 2); - - if (type->kind == Type_Struct) { - type_set_offsets(type); - for_array(i, type->Struct.fields) { - i64 offset = type->Struct.offsets[i]; - Entity *field = type->Struct.fields[i]; - cgValue field_hasher = cg_hasher_proc_value_for_type(p, field->type); - - TB_Node *ptr = tb_inst_member_access(p->func, data.node, offset); - - args[0] = cg_value(ptr, alloc_type_pointer(field->type)); - args[1] = seed; - seed = cg_emit_call(p, field_hasher, args); - } - - cg_build_return_stmt_internal_single(p, seed); - } else if (type->kind == Type_Union) { - if (type_size_of(type) == 0) { - cg_build_return_stmt_internal_single(p, seed); - } else if (is_type_union_maybe_pointer(type)) { - Type *v = type->Union.variants[0]; - cgValue variant_hasher = cg_hasher_proc_value_for_type(p, v); - - args[0] = data; - args[1] = seed; - cgValue res = cg_emit_call(p, variant_hasher, args); - cg_build_return_stmt_internal_single(p, seed); - } else { - TB_Node *end_region = cg_control_region(p, "bend"); - TB_Node *switch_region = cg_control_region(p, "bswitch"); - - cg_emit_goto(p, switch_region); - - size_t entry_count = type->Union.variants.count; - TB_SwitchEntry *keys = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, entry_count); - for (size_t i = 0; i < entry_count; i++) { - TB_Node *region = cg_control_region(p, "bcase"); - Type *variant = type->Union.variants[i]; - keys[i].key = union_variant_index(type, variant); - keys[i].value = region; - - tb_inst_set_control(p->func, region); - - cgValue variant_hasher = cg_hasher_proc_value_for_type(p, variant); - - args[0] = data; - args[1] = seed; - cgValue res = cg_emit_call(p, variant_hasher, args); - cg_build_return_stmt_internal_single(p, res); - } - - tb_inst_set_control(p->func, switch_region); - - cgValue tag_ptr = cg_emit_union_tag_ptr(p, data); - cgValue tag = cg_emit_load(p, tag_ptr); - - TB_DataType tag_dt = cg_data_type(tag.type); - GB_ASSERT(tag.kind == cgValue_Value); - tb_inst_branch(p->func, tag_dt, tag.node, end_region, entry_count, keys); - - tb_inst_set_control(p->func, end_region); - cg_build_return_stmt_internal_single(p, seed); - } - } else if (type->kind == Type_Array) { - cgAddr pres = cg_add_local(p, t_uintptr, nullptr, false); - cg_addr_store(p, pres, seed); - - cgValue elem_hasher = cg_hasher_proc_value_for_type(p, type->Array.elem); - - auto loop_data = cg_loop_start(p, type->Array.count, t_int); - - i64 stride = type_size_of(type->Array.elem); - TB_Node *ptr = tb_inst_array_access(p->func, data.node, loop_data.index.node, stride); - args[0] = cg_value(ptr, alloc_type_pointer(type->Array.elem)); - args[1] = cg_addr_load(p, pres); - - cgValue new_seed = cg_emit_call(p, elem_hasher, args); - cg_addr_store(p, pres, new_seed); - - cg_loop_end(p, loop_data); - - cgValue res = cg_addr_load(p, pres); - cg_build_return_stmt_internal_single(p, res); - } else if (type->kind == Type_EnumeratedArray) { - cgAddr pres = cg_add_local(p, t_uintptr, nullptr, false); - cg_addr_store(p, pres, seed); - - cgValue elem_hasher = cg_hasher_proc_value_for_type(p, type->EnumeratedArray.elem); - - auto loop_data = cg_loop_start(p, type->EnumeratedArray.count, t_int); - - i64 stride = type_size_of(type->EnumeratedArray.elem); - TB_Node *ptr = tb_inst_array_access(p->func, data.node, loop_data.index.node, stride); - args[0] = cg_value(ptr, alloc_type_pointer(type->EnumeratedArray.elem)); - args[1] = cg_addr_load(p, pres); - - cgValue new_seed = cg_emit_call(p, elem_hasher, args); - cg_addr_store(p, pres, new_seed); - - cg_loop_end(p, loop_data); - - cgValue res = cg_addr_load(p, pres); - cg_build_return_stmt_internal_single(p, res); - } else if (is_type_cstring(type)) { - args[0] = data; - args[1] = seed; - cgValue res = cg_emit_runtime_call(p, "default_hasher_cstring", args); - cg_build_return_stmt_internal_single(p, seed); - } else if (is_type_string(type)) { - args[0] = data; - args[1] = seed; - cgValue res = cg_emit_runtime_call(p, "default_hasher_string", args); - cg_build_return_stmt_internal_single(p, seed); - } else { - GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); - } - return p; -} \ No newline at end of file diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp deleted file mode 100644 index 597a4262c..000000000 --- a/src/tilde_stmt.cpp +++ /dev/null @@ -1,2889 +0,0 @@ -gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region) { - if (tb_inst_get_control(p->func)) { - tb_inst_goto(p->func, control_region); - return true; - } - return false; -} - -gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name) { - TEMPORARY_ALLOCATOR_GUARD(); - - isize n = gb_strlen(name); - - char *new_name = gb_alloc_array(temporary_allocator(), char, n+12); - n = -1 + gb_snprintf(new_name, n+11, "%.*s_%u", cast(int)n, name, p->control_regions.count); - - TB_Node *region = tb_inst_region(p->func); - tb_inst_set_region_name(p->func, region, n, new_name); - - GB_ASSERT(p->scope_index >= 0); - array_add(&p->control_regions, cgControlRegion{region, p->scope_index}); - - return region; -} - -gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) { - GB_ASSERT_MSG(is_type_pointer(ptr.type), "%s", type_to_string(ptr.type)); - Type *type = type_deref(ptr.type); - TB_DataType dt = cg_data_type(type); - - if (TB_IS_VOID_TYPE(dt)) { - switch (ptr.kind) { - case cgValue_Value: - return cg_lvalue_addr(ptr.node, type); - case cgValue_Addr: - GB_PANIC("NOT POSSIBLE - Cannot load an lvalue to begin with"); - break; - case cgValue_Multi: - GB_PANIC("NOT POSSIBLE - Cannot load multiple values at once"); - break; - case cgValue_Symbol: - return cg_lvalue_addr(tb_inst_get_symbol_address(p->func, ptr.symbol), type); - } - } - GB_ASSERT(dt.type != TB_MEMORY); - GB_ASSERT(dt.type != TB_TUPLE); - - // use the natural alignment - // if people need a special alignment, they can use `intrinsics.unaligned_load` - TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); - - TB_Node *the_ptr = nullptr; - switch (ptr.kind) { - case cgValue_Value: - the_ptr = ptr.node; - break; - case cgValue_Addr: - the_ptr = tb_inst_load(p->func, TB_TYPE_PTR, ptr.node, alignment, is_volatile); - break; - case cgValue_Multi: - GB_PANIC("NOT POSSIBLE - Cannot load multiple values at once"); - break; - case cgValue_Symbol: - the_ptr = tb_inst_get_symbol_address(p->func, ptr.symbol); - break; - } - return cg_value(tb_inst_load(p->func, dt, the_ptr, alignment, is_volatile), type); -} - -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue src, bool is_volatile) { - GB_ASSERT_MSG(dst.kind != cgValue_Multi, "cannot store to multiple values at once"); - - if (dst.kind == cgValue_Addr) { - dst = cg_emit_load(p, dst, is_volatile); - } else if (dst.kind == cgValue_Symbol) { - dst = cg_value(tb_inst_get_symbol_address(p->func, dst.symbol), dst.type); - } - - GB_ASSERT(is_type_pointer(dst.type)); - Type *dst_type = type_deref(dst.type); - - GB_ASSERT_MSG(are_types_identical(core_type(dst_type), core_type(src.type)), "%s vs %s", type_to_string(dst_type), type_to_string(src.type)); - - TB_DataType dt = cg_data_type(dst_type); - TB_DataType st = cg_data_type(src.type); - GB_ASSERT(dt.raw == st.raw); - - // use the natural alignment - // if people need a special alignment, they can use `intrinsics.unaligned_store` - TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(dst_type); - - if (TB_IS_VOID_TYPE(dt)) { - TB_Node *dst_ptr = nullptr; - TB_Node *src_ptr = nullptr; - - switch (dst.kind) { - case cgValue_Value: - dst_ptr = dst.node; - break; - case cgValue_Addr: - GB_PANIC("DST cgValue_Addr should be handled above"); - break; - case cgValue_Symbol: - dst_ptr = tb_inst_get_symbol_address(p->func, dst.symbol); - break; - } - - switch (src.kind) { - case cgValue_Value: - GB_PANIC("SRC cgValue_Value should be handled above"); - break; - case cgValue_Symbol: - GB_PANIC("SRC cgValue_Symbol should be handled above"); - break; - case cgValue_Addr: - src_ptr = src.node; - break; - } - - // IMPORTANT TODO(bill): needs to be memmove - i64 sz = type_size_of(dst_type); - TB_Node *count = tb_inst_uint(p->func, TB_TYPE_INT, cast(u64)sz); - tb_inst_memcpy(p->func, dst_ptr, src_ptr, count, alignment/*, is_volatile*/); - return; - } - - - switch (dst.kind) { - case cgValue_Value: - switch (src.kind) { - case cgValue_Value: - if (src.node->dt.type == TB_INT && src.node->dt.data == 1) { - src.node = tb_inst_zxt(p->func, src.node, dt); - } - tb_inst_store(p->func, dt, dst.node, src.node, alignment, is_volatile); - return; - case cgValue_Addr: - tb_inst_store(p->func, dt, dst.node, - tb_inst_load(p->func, st, src.node, alignment, is_volatile), - alignment, is_volatile); - return; - case cgValue_Symbol: - tb_inst_store(p->func, dt, dst.node, - tb_inst_get_symbol_address(p->func, src.symbol), - alignment, is_volatile); - return; - } - case cgValue_Addr: - GB_PANIC("cgValue_Addr should be handled above"); - break; - case cgValue_Symbol: - GB_PANIC(" cgValue_Symbol should be handled above"); - break; - } -} - - -gb_internal cgValue cg_address_from_load(cgProcedure *p, cgValue value) { - switch (value.kind) { - case cgValue_Value: - { - TB_Node *load_inst = value.node; - GB_ASSERT_MSG(load_inst->type == TB_LOAD, "expected a load instruction"); - TB_Node *ptr = load_inst->inputs[2]; - return cg_value(ptr, alloc_type_pointer(value.type)); - } - case cgValue_Addr: - return cg_value(value.node, alloc_type_pointer(value.type)); - case cgValue_Symbol: - GB_PANIC("Symbol is an invalid use case for cg_address_from_load"); - return {}; - case cgValue_Multi: - GB_PANIC("Multi is an invalid use case for cg_address_from_load"); - break; - } - GB_PANIC("Invalid cgValue for cg_address_from_load"); - return {}; - -} - -gb_internal bool cg_addr_is_empty(cgAddr const &addr) { - switch (addr.kind) { - case cgValue_Value: - case cgValue_Addr: - return addr.addr.node == nullptr; - case cgValue_Symbol: - return addr.addr.symbol == nullptr; - case cgValue_Multi: - return addr.addr.multi == nullptr; - } - return true; -} - -gb_internal Type *cg_addr_type(cgAddr const &addr) { - if (cg_addr_is_empty(addr)) { - return nullptr; - } - switch (addr.kind) { - case cgAddr_Map: - { - Type *t = base_type(addr.map.type); - GB_ASSERT(is_type_map(t)); - return t->Map.value; - } - case cgAddr_Swizzle: - return addr.swizzle.type; - case cgAddr_SwizzleLarge: - return addr.swizzle_large.type; - case cgAddr_Context: - if (addr.ctx.sel.index.count > 0) { - Type *t = t_context; - for_array(i, addr.ctx.sel.index) { - GB_ASSERT(is_type_struct(t)); - t = base_type(t)->Struct.fields[addr.ctx.sel.index[i]]->type; - } - return t; - } - break; - } - return type_deref(addr.addr.type); -} - -gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr) { - if (addr.addr.node == nullptr) { - return {}; - } - switch (addr.kind) { - case cgAddr_Default: - return cg_emit_load(p, addr.addr); - - case cgAddr_Map: - { - Type *map_type = base_type(type_deref(addr.addr.type)); - GB_ASSERT(map_type->kind == Type_Map); - cgAddr v_addr = cg_add_local(p, map_type->Map.value, nullptr, true); - - cgValue ptr = cg_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); - cgValue ok = cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); - - TB_Node *then = cg_control_region(p, "map.get.then"); - TB_Node *done = cg_control_region(p, "map.get.done"); - cg_emit_if(p, ok, then, done); - tb_inst_set_control(p->func, then); - { - cgValue value = cg_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); - value = cg_emit_load(p, value); - cg_addr_store(p, v_addr, value); - } - cg_emit_goto(p, done); - tb_inst_set_control(p->func, done); - - cgValue v = cg_addr_load(p, v_addr); - if (is_type_tuple(addr.map.result)) { - return cg_value_multi2(v, ok, addr.map.result); - } else { - return v; - } - } - - case cgAddr_SoaVariable: - { - Type *t = type_deref(addr.addr.type); - t = base_type(t); - GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); - Type *elem = t->Struct.soa_elem; - - cgValue len = {}; - if (t->Struct.soa_kind == StructSoa_Fixed) { - len = cg_const_int(p, t_int, t->Struct.soa_count); - } else { - cgValue v = cg_emit_load(p, addr.addr); - len = cg_builtin_len(p, v); - } - - cgAddr res = cg_add_local(p, elem, nullptr, true); - - // if (addr.soa.index_expr != nullptr && (!cg_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { - // cg_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); - // } - - if (t->Struct.soa_kind == StructSoa_Fixed) { - for_array(i, t->Struct.fields) { - Entity *field = t->Struct.fields[i]; - Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Array); - - cgValue dst = cg_emit_struct_ep(p, res.addr, cast(i32)i); - cgValue src_ptr = cg_emit_struct_ep(p, addr.addr, cast(i32)i); - src_ptr = cg_emit_array_ep(p, src_ptr, addr.soa.index); - cgValue src = cg_emit_load(p, src_ptr); - cg_emit_store(p, dst, src); - } - } else { - isize field_count = t->Struct.fields.count; - if (t->Struct.soa_kind == StructSoa_Slice) { - field_count -= 1; - } else if (t->Struct.soa_kind == StructSoa_Dynamic) { - field_count -= 3; - } - for (isize i = 0; i < field_count; i++) { - Entity *field = t->Struct.fields[i]; - Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Pointer); - - cgValue dst = cg_emit_struct_ep(p, res.addr, cast(i32)i); - cgValue src_ptr = cg_emit_struct_ep(p, addr.addr, cast(i32)i); - cgValue src = cg_emit_load(p, src_ptr); - src = cg_emit_ptr_offset(p, src, addr.soa.index); - src = cg_emit_load(p, src); - cg_emit_store(p, dst, src); - } - } - - return cg_addr_load(p, res); - } - } - GB_PANIC("TODO(bill): cg_addr_load %p", addr.addr.node); - return {}; -} - - -gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) { - if (cg_addr_is_empty(addr)) { - return; - } - GB_ASSERT(value.type != nullptr); - if (is_type_untyped_uninit(value.type)) { - Type *t = cg_addr_type(addr); - value = cg_value(tb_inst_poison(p->func, cg_data_type(t)), t); - // TODO(bill): IS THIS EVEN A GOOD IDEA? - } else if (is_type_untyped_nil(value.type)) { - Type *t = cg_addr_type(addr); - value = cg_const_nil(p, t); - } - - if (addr.kind == cgAddr_RelativePointer && addr.relative.deref) { - addr = cg_addr(cg_address_from_load(p, cg_addr_load(p, addr))); - } - - if (addr.kind == cgAddr_RelativePointer) { - GB_PANIC("TODO(bill): cgAddr_RelativePointer"); - } else if (addr.kind == cgAddr_RelativeSlice) { - GB_PANIC("TODO(bill): cgAddr_RelativeSlice"); - } else if (addr.kind == cgAddr_Map) { - cg_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt); - return; - } else if (addr.kind == cgAddr_Context) { - cgAddr old_addr = cg_find_or_generate_context_ptr(p); - - bool create_new = true; - for_array(i, p->context_stack) { - cgContextData *ctx_data = &p->context_stack[i]; - if (ctx_data->ctx.addr.node == old_addr.addr.node) { - if (ctx_data->uses > 0) { - create_new = true; - } else if (p->scope_index > ctx_data->scope_index) { - create_new = true; - } else { - // gb_printf_err("%.*s (curr:%td) (ctx:%td) (uses:%td)\n", LIT(p->name), p->scope_index, ctx_data->scope_index, ctx_data->uses); - create_new = false; - } - break; - } - } - - cgValue next = {}; - if (create_new) { - cgValue old = cg_addr_load(p, old_addr); - cgAddr next_addr = cg_add_local(p, t_context, nullptr, true); - cg_addr_store(p, next_addr, old); - cg_push_context_onto_stack(p, next_addr); - next = next_addr.addr; - } else { - next = old_addr.addr; - } - - if (addr.ctx.sel.index.count > 0) { - cgValue lhs = cg_emit_deep_field_gep(p, next, addr.ctx.sel); - cgValue rhs = cg_emit_conv(p, value, type_deref(lhs.type)); - cg_emit_store(p, lhs, rhs); - } else { - cgValue lhs = next; - cgValue rhs = cg_emit_conv(p, value, cg_addr_type(addr)); - cg_emit_store(p, lhs, rhs); - } - return; - } else if (addr.kind == cgAddr_SoaVariable) { - GB_PANIC("TODO(bill): cgAddr_SoaVariable"); - } else if (addr.kind == cgAddr_Swizzle) { - GB_ASSERT(addr.swizzle.count <= 4); - GB_PANIC("TODO(bill): cgAddr_Swizzle"); - } else if (addr.kind == cgAddr_SwizzleLarge) { - GB_PANIC("TODO(bill): cgAddr_SwizzleLarge"); - } - - value = cg_emit_conv(p, value, cg_addr_type(addr)); - cg_emit_store(p, addr.addr, value); -} - -gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr) { - if (cg_addr_is_empty(addr)) { - GB_PANIC("Illegal addr -> nullptr"); - return {}; - } - - switch (addr.kind) { - case cgAddr_Map: - GB_PANIC("TODO(bill): cg_addr_get_ptr cgAddr_Map"); - // return cg_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); - break; - - case cgAddr_RelativePointer: { - Type *rel_ptr = base_type(cg_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); - - cgValue ptr = cg_emit_conv(p, addr.addr, t_uintptr); - cgValue offset = cg_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = cg_emit_load(p, offset); - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = cg_emit_conv(p, offset, t_i64); - } - offset = cg_emit_conv(p, offset, t_uintptr); - - cgValue absolute_ptr = cg_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = cg_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); - - GB_PANIC("TODO(bill): cg_addr_get_ptr cgAddr_RelativePointer"); - // cgValue cond = cg_emit_comp(p, Token_CmpEq, offset, cg_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); - - // NOTE(bill): nil check - // cgValue nil_ptr = cg_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); - // cgValue final_ptr = cg_emit_select(p, cond, nil_ptr, absolute_ptr); - // return final_ptr; - break; - } - - case cgAddr_SoaVariable: - // TODO(bill): FIX THIS HACK - return cg_address_from_load(p, cg_addr_load(p, addr)); - - case cgAddr_Context: - GB_PANIC("cgAddr_Context should be handled elsewhere"); - break; - - case cgAddr_Swizzle: - case cgAddr_SwizzleLarge: - // TOOD(bill): is this good enough logic? - break; - } - - return addr.addr; -} - -gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue index) { - GB_ASSERT(ptr.kind == cgValue_Value); - GB_ASSERT(index.kind == cgValue_Value); - GB_ASSERT(is_type_pointer(ptr.type) || is_type_multi_pointer(ptr.type)); - GB_ASSERT(is_type_integer(index.type)); - - Type *elem = type_deref(ptr.type, true); - i64 stride = type_size_of(elem); - return cg_value(tb_inst_array_access(p->func, ptr.node, index.node, stride), alloc_type_pointer(elem)); -} -gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index) { - GB_ASSERT(s.kind == cgValue_Value); - GB_ASSERT(index.kind == cgValue_Value); - - Type *t = s.type; - GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); - Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); - GB_ASSERT_MSG(is_type_integer(core_type(index.type)), "%s", type_to_string(index.type)); - - - Type *elem = base_array_type(st); - i64 stride = type_size_of(elem); - return cg_value(tb_inst_array_access(p->func, s.node, index.node, stride), alloc_type_pointer(elem)); -} -gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index) { - return cg_emit_array_ep(p, s, cg_const_int(p, t_int, index)); -} - - -gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { - s = cg_flatten_value(p, s); - - GB_ASSERT(is_type_pointer(s.type)); - Type *t = base_type(type_deref(s.type)); - Type *result_type = nullptr; - - if (is_type_relative_pointer(t)) { - s = cg_addr_get_ptr(p, cg_addr(s)); - } - i64 offset = -1; - i64 int_size = build_context.int_size; - i64 ptr_size = build_context.ptr_size; - - switch (t->kind) { - case Type_Struct: - type_set_offsets(t); - result_type = t->Struct.fields[index]->type; - offset = t->Struct.offsets[index]; - break; - case Type_Union: - GB_ASSERT(index == -1); - GB_PANIC("TODO(bill): cg_emit_union_tag_ptr"); - break; - // return cg_emit_union_tag_ptr(p, s); - case Type_Tuple: - type_set_offsets(t); - result_type = t->Tuple.variables[index]->type; - offset = t->Tuple.offsets[index]; - GB_PANIC("TODO(bill): cg_emit_tuple_ep %d", s.kind); - break; - // return cg_emit_tuple_ep(p, s, index); - case Type_Slice: - switch (index) { - case 0: - result_type = alloc_type_multi_pointer(t->Slice.elem); - offset = 0; - break; - case 1: - result_type = t_int; - offset = int_size; - break; - } - break; - case Type_Basic: - switch (t->Basic.kind) { - case Basic_string: - switch (index) { - case 0: - result_type = t_u8_multi_ptr; - offset = 0; - break; - case 1: - result_type = t_int; - offset = int_size; - break; - } - break; - case Basic_any: - switch (index) { - case 0: - result_type = t_rawptr; - offset = 0; - break; - case 1: - result_type = t_typeid; - offset = ptr_size; - break; - } - break; - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - { - Type *ft = base_complex_elem_type(t); - i64 sz = type_size_of(ft); - switch (index) { - case 0: case 1: - result_type = ft; offset = sz * index; break; - default: goto error_case; - } - break; - } - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - { - Type *ft = base_complex_elem_type(t); - i64 sz = type_size_of(ft); - switch (index) { - case 0: case 1: case 2: case 3: - result_type = ft; offset = sz * index; break; - default: goto error_case; - } - } - break; - default: - goto error_case; - } - break; - case Type_DynamicArray: - switch (index) { - case 0: - result_type = alloc_type_multi_pointer(t->DynamicArray.elem); - offset = index*int_size; - break; - case 1: case 2: - result_type = t_int; - offset = index*int_size; - break; - case 3: - result_type = t_allocator; - offset = index*int_size; - break; - default: goto error_case; - } - break; - case Type_Map: - { - init_map_internal_types(t); - Type *itp = alloc_type_pointer(t_raw_map); - s = cg_emit_transmute(p, s, itp); - - Type *rms = base_type(t_raw_map); - GB_ASSERT(rms->kind == Type_Struct); - - if (0 <= index && index < 3) { - result_type = rms->Struct.fields[index]->type; - offset = rms->Struct.offsets[index]; - } else { - goto error_case; - } - break; - } - case Type_Array: - return cg_emit_array_epi(p, s, index); - case Type_SoaPointer: - switch (index) { - case 0: - result_type = alloc_type_pointer(t->SoaPointer.elem); - offset = 0; - break; - case 1: - result_type = t_int; - offset = int_size; - break; - } - break; - default: - error_case:; - GB_PANIC("TODO(bill): struct_gep type: %s, %lld", type_to_string(s.type), cast(long long)index); - break; - } - - GB_ASSERT_MSG(result_type != nullptr, "%s %lld", type_to_string(t), cast(long long)index); - GB_ASSERT_MSG(offset >= 0, "%s %lld", type_to_string(t), cast(long long)offset); - - GB_ASSERT(s.kind == cgValue_Value); - return cg_value( - tb_inst_member_access(p->func, s.node, offset), - alloc_type_pointer(result_type) - ); -} - - -gb_internal cgValue cg_emit_struct_ev(cgProcedure *p, cgValue s, i64 index) { - s = cg_address_from_load_or_generate_local(p, s); - cgValue ptr = cg_emit_struct_ep(p, s, index); - return cg_flatten_value(p, cg_emit_load(p, ptr)); -} - - -gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel) { - GB_ASSERT(sel.index.count > 0); - Type *type = type_deref(e.type); - - for_array(i, sel.index) { - i64 index = sel.index[i]; - if (is_type_pointer(type)) { - type = type_deref(type); - e = cg_emit_load(p, e); - } - type = core_type(type); - - switch (type->kind) { - case Type_SoaPointer: { - cgValue addr = cg_emit_struct_ep(p, e, 0); - cgValue index = cg_emit_struct_ep(p, e, 1); - addr = cg_emit_load(p, addr); - index = cg_emit_load(p, index); - - i64 first_index = sel.index[0]; - Selection sub_sel = sel; - sub_sel.index.data += 1; - sub_sel.index.count -= 1; - - cgValue arr = cg_emit_struct_ep(p, addr, first_index); - - Type *t = base_type(type_deref(addr.type)); - GB_ASSERT(is_type_soa_struct(t)); - - if (t->Struct.soa_kind == StructSoa_Fixed) { - e = cg_emit_array_ep(p, arr, index); - } else { - e = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); - } - break; - } - case Type_Basic: - switch (type->Basic.kind) { - case Basic_any: - if (index == 0) { - type = t_rawptr; - } else if (index == 1) { - type = t_type_info_ptr; - } - e = cg_emit_struct_ep(p, e, index); - break; - default: - e = cg_emit_struct_ep(p, e, index); - break; - } - break; - case Type_Struct: - if (type->Struct.is_raw_union) { - type = get_struct_field_type(type, index); - GB_ASSERT(is_type_pointer(e.type)); - e = cg_emit_transmute(p, e, alloc_type_pointer(type)); - } else { - type = get_struct_field_type(type, index); - e = cg_emit_struct_ep(p, e, index); - } - break; - case Type_Union: - GB_ASSERT(index == -1); - type = t_type_info_ptr; - e = cg_emit_struct_ep(p, e, index); - break; - case Type_Tuple: - type = type->Tuple.variables[index]->type; - e = cg_emit_struct_ep(p, e, index); - break; - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - case Type_RelativePointer: - e = cg_emit_struct_ep(p, e, index); - break; - case Type_Array: - e = cg_emit_array_epi(p, e, index); - break; - default: - GB_PANIC("un-gep-able type %s", type_to_string(type)); - break; - } - } - - return e; -} - - - - - - - - -gb_internal cgBranchRegions cg_lookup_branch_regions(cgProcedure *p, Ast *ident) { - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e->kind == Entity_Label); - for (cgBranchRegions const &b : p->branch_regions) { - if (b.label == e->Label.node) { - return b; - } - } - - GB_PANIC("Unreachable"); - cgBranchRegions empty = {}; - return empty; -} - -gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Node *break_, TB_Node *continue_, TB_Node *fallthrough_) { - cgTargetList *tl = gb_alloc_item(permanent_allocator(), cgTargetList); - tl->prev = p->target_list; - tl->break_ = break_; - tl->continue_ = continue_; - tl->fallthrough_ = fallthrough_; - p->target_list = tl; - - if (label != nullptr) { // Set label blocks - GB_ASSERT(label->kind == Ast_Label); - - for (cgBranchRegions &b : p->branch_regions) { - GB_ASSERT(b.label != nullptr && label != nullptr); - GB_ASSERT(b.label->kind == Ast_Label); - if (b.label == label) { - b.break_ = break_; - b.continue_ = continue_; - return tl; - } - } - - GB_PANIC("Unreachable"); - } - - return tl; -} - -gb_internal void cg_pop_target_list(cgProcedure *p) { - p->target_list = p->target_list->prev; -} -gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init) { - GB_ASSERT(type != nullptr); - - isize size = type_size_of(type); - TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); - if (is_type_matrix(type)) { - alignment *= 2; // NOTE(bill): Just in case - } - - TB_Node *local = tb_inst_local(p->func, cast(u32)size, alignment); - - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - String name = e->token.string; - TB_DebugType *debug_type = cg_debug_type(p->module, type); - tb_function_attrib_variable(p->func, local, nullptr, name.len, cast(char const *)name.text, debug_type); - } - - if (zero_init) { - bool is_volatile = false; - gb_unused(is_volatile); - TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); - TB_Node *count = tb_inst_uint(p->func, TB_TYPE_I32, cast(u64)size); - tb_inst_memset(p->func, local, zero, count, alignment/*, is_volatile*/); - } - - cgAddr addr = cg_addr(cg_value(local, alloc_type_pointer(type))); - if (e) { - map_set(&p->variable_map, e, addr); - } - return addr; -} - -gb_internal cgAddr cg_add_global(cgProcedure *p, Type *type, Entity *e) { - GB_ASSERT(type != nullptr); - - isize size = type_size_of(type); - TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); - if (is_type_matrix(type)) { - alignment *= 2; // NOTE(bill): Just in case - } - - TB_Global *global = tb_global_create(p->module->mod, 0, "", nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(p->module->mod, tb_module_get_data(p->module->mod), global, size, alignment, 0); - TB_Node *local = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); - - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - String name = e->token.string; - TB_DebugType *debug_type = cg_debug_type(p->module, type); - tb_function_attrib_variable(p->func, local, nullptr, name.len, cast(char const *)name.text, debug_type); - } - - cgAddr addr = cg_addr(cg_value(local, alloc_type_pointer(type))); - if (e) { - map_set(&p->variable_map, e, addr); - } - return addr; -} - - -gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment) { - TB_CharUnits size = cast(TB_CharUnits)type_size_of(original_type); - TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(original_type), min_alignment); - TB_Node *copy = tb_inst_local(p->func, size, align); - if (value.kind == cgValue_Value) { - tb_inst_store(p->func, cg_data_type(original_type), copy, value.node, align, false); - } else { - GB_ASSERT(value.kind == cgValue_Addr); - tb_inst_memcpy(p->func, copy, value.node, tb_inst_uint(p->func, TB_TYPE_INT, size), align); - } - - return cg_value(copy, alloc_type_pointer(original_type)); -} - -gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value) { - switch (value.kind) { - case cgValue_Value: - if (value.node->type == TB_LOAD) { - TB_Node *ptr = value.node->inputs[2]; - return cg_value(ptr, alloc_type_pointer(value.type)); - } - break; - case cgValue_Addr: - return cg_value(value.node, alloc_type_pointer(value.type)); - case cgValue_Multi: - GB_PANIC("cgValue_Multi not allowed"); - } - - cgAddr res = cg_add_local(p, value.type, nullptr, false); - cg_addr_store(p, res, value); - return res.addr; -} - - -gb_internal void cg_build_defer_stmt(cgProcedure *p, cgDefer const &d) { - TB_Node *curr_region = tb_inst_get_control(p->func); - if (curr_region == nullptr) { - return; - } - - // NOTE(bill): The prev block may defer injection before it's terminator - TB_Node *last_inst = nullptr; - // if (curr_region->input_count) { - // last_inst = *(curr_region->inputs + curr_region->input_count); - // } - // if (last_inst && TB_IS_NODE_TERMINATOR(last_inst->type)) { - // // NOTE(bill): ReturnStmt defer stuff will be handled previously - // return; - // } - - isize prev_context_stack_count = p->context_stack.count; - GB_ASSERT(prev_context_stack_count <= p->context_stack.capacity); - defer (p->context_stack.count = prev_context_stack_count); - p->context_stack.count = d.context_stack_count; - - TB_Node *b = cg_control_region(p, "defer"); - if (last_inst == nullptr) { - cg_emit_goto(p, b); - } - - tb_inst_set_control(p->func, b); - if (d.kind == cgDefer_Node) { - cg_build_stmt(p, d.stmt); - } else if (d.kind == cgDefer_Proc) { - cg_emit_call(p, d.proc.deferred, d.proc.result_as_args); - } -} - - -gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { - isize count = p->defer_stack.count; - isize i = count; - while (i --> 0) { - cgDefer const &d = p->defer_stack[i]; - - if (kind == cgDeferExit_Default) { - if (p->scope_index == d.scope_index && - d.scope_index > 0) { - cg_build_defer_stmt(p, d); - array_pop(&p->defer_stack); - continue; - } else { - break; - } - } else if (kind == cgDeferExit_Return) { - cg_build_defer_stmt(p, d); - } else if (kind == cgDeferExit_Branch) { - GB_ASSERT(control_region != nullptr); - isize lower_limit = -1; - for (auto const &cr : p->control_regions) { - if (cr.control_region == control_region) { - lower_limit = cr.scope_index; - break; - } - } - GB_ASSERT(lower_limit >= 0); - if (lower_limit < d.scope_index) { - cg_build_defer_stmt(p, d); - } - } - } -} - -gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { - // TODO(bill): debug scope information - p->scope_index += 1; - array_add(&p->scope_stack, scope); -} - -gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { - cg_emit_defer_stmts(p, kind, control_region); - GB_ASSERT(p->scope_index > 0); - - while (p->context_stack.count > 0) { - auto *ctx = &p->context_stack[p->context_stack.count-1]; - if (ctx->scope_index < p->scope_index) { - break; - } - array_pop(&p->context_stack); - } - - p->scope_index -= 1; - array_pop(&p->scope_stack); -} - - -gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_values, cgValue src_value) { - isize init_count = dst_values->count; - Type *t = src_value.type; - if (t && t->kind == Type_Tuple) { - GB_ASSERT(src_value.kind == cgValue_Multi); - GB_ASSERT(src_value.multi != nullptr); - GB_ASSERT(src_value.multi->values.count == t->Tuple.variables.count); - for (cgValue const &value : src_value.multi->values) { - array_add(dst_values, value); - } - } else { - array_add(dst_values, src_value); - } - return dst_values->count - init_count; -} -gb_internal void cg_build_assignment(cgProcedure *p, Array const &lvals, Slice const &values) { - if (values.count == 0) { - return; - } - - auto inits = array_make(permanent_allocator(), 0, lvals.count); - - for (Ast *rhs : values) { - cgValue init = cg_build_expr(p, rhs); - cg_append_tuple_values(p, &inits, init); - } - - bool prev_in_assignment = p->in_multi_assignment; - - isize lval_count = 0; - for (cgAddr const &lval : lvals) { - if (!cg_addr_is_empty(lval)) { - // check if it is not a blank identifier - lval_count += 1; - } - } - p->in_multi_assignment = lval_count > 1; - - GB_ASSERT(lvals.count == inits.count); - - - if (inits.count > 1) for_array(i, inits) { - cgAddr lval = lvals[i]; - cgValue init = cg_flatten_value(p, inits[i]); - - GB_ASSERT(init.kind != cgValue_Multi); - if (init.type == nullptr) { - continue; - } - - Type *type = cg_addr_type(lval); - if (!cg_addr_is_empty(lval)) { - GB_ASSERT_MSG(are_types_identical(init.type, type), "%s = %s", type_to_string(init.type), type_to_string(type)); - } - - if (init.kind == cgValue_Addr && - !cg_addr_is_empty(lval)) { - // NOTE(bill): This is needed for certain constructs such as this: - // a, b = b, a - // NOTE(bill): This is a bodge and not necessarily a good way of doing things whatsoever - TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); - TB_Node *copy = tb_inst_local(p->func, size, align); - tb_inst_memcpy(p->func, copy, init.node, tb_inst_uint(p->func, TB_TYPE_INT, size), align); - // use the copy instead - init.node = copy; - } - inits[i] = init; - } - - for_array(i, inits) { - cgAddr lval = lvals[i]; - cgValue init = inits[i]; - GB_ASSERT(init.kind != cgValue_Multi); - if (init.type == nullptr) { - continue; - } - cg_addr_store(p, lval, init); - } - - p->in_multi_assignment = prev_in_assignment; -} - -gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { - if (as->op.kind == Token_Eq) { - auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); - - for (Ast *lhs : as->lhs) { - cgAddr lval = {}; - if (!is_blank_ident(lhs)) { - lval = cg_build_addr(p, lhs); - } - array_add(&lvals, lval); - } - cg_build_assignment(p, lvals, as->rhs); - return; - } - - GB_ASSERT(as->lhs.count == 1); - GB_ASSERT(as->rhs.count == 1); - // NOTE(bill): Only 1 += 1 is allowed, no tuples - // +=, -=, etc - - i32 op_ = cast(i32)as->op.kind; - op_ += Token_Add - Token_AddEq; // Convert += to + - TokenKind op = cast(TokenKind)op_; - - if (op == Token_CmpAnd || op == Token_CmpOr) { - GB_PANIC("TODO(bill): cg_emit_logical_binary_expr"); - // Type *type = as->lhs[0]->tav.type; - // cgValue new_value = cg_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); - - // cgAddr lhs = cg_build_addr(p, as->lhs[0]); - // cg_addr_store(p, lhs, new_value); - } else { - cgAddr lhs = cg_build_addr(p, as->lhs[0]); - cgValue value = cg_build_expr(p, as->rhs[0]); - Type *lhs_type = cg_addr_type(lhs); - - // NOTE(bill): Allow for the weird edge case of: - // array *= matrix - if (op == Token_Mul && is_type_matrix(value.type) && is_type_array(lhs_type)) { - GB_PANIC("TODO(bill): array *= matrix"); - // cgValue old_value = cg_addr_load(p, lhs); - // Type *type = old_value.type; - // cgValue new_value = cg_emit_vector_mul_matrix(p, old_value, value, type); - // cg_addr_store(p, lhs, new_value); - // return; - } - - if (is_type_array(lhs_type)) { - GB_PANIC("TODO(bill): cg_build_assign_stmt_array"); - // cg_build_assign_stmt_array(p, op, lhs, value); - // return; - } else { - cgValue old_value = cg_addr_load(p, lhs); - Type *type = old_value.type; - - cgValue change = cg_emit_conv(p, value, type); - cgValue new_value = cg_emit_arith(p, op, old_value, change, type); - cg_addr_store(p, lhs, new_value); - } - } -} - -gb_internal void cg_build_return_stmt_internal_single(cgProcedure *p, cgValue result) { - Slice results = {}; - results.data = &result; - results.count = 1; - cg_build_return_stmt_internal(p, results); -} - - -gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results) { - TypeTuple *tuple = &p->type->Proc.results->Tuple; - isize return_count = p->type->Proc.result_count; - - if (return_count == 0) { - tb_inst_ret(p->func, 0, nullptr); - return; - } - - if (p->split_returns_index >= 0) { - GB_ASSERT(is_calling_convention_odin(p->type->Proc.calling_convention)); - - for (isize i = 0; i < return_count-1; i++) { - Entity *e = tuple->variables[i]; - TB_Node *ret_ptr = tb_inst_param(p->func, cast(int)(p->split_returns_index+i)); - cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type)); - cg_emit_store(p, ptr, results[i]); - } - - if (p->return_by_ptr) { - Entity *e = tuple->variables[return_count-1]; - TB_Node *ret_ptr = tb_inst_param(p->func, 0); - cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type)); - cg_emit_store(p, ptr, results[return_count-1]); - - tb_inst_ret(p->func, 0, nullptr); - return; - } else { - GB_ASSERT(p->proto->return_count == 1); - TB_DataType dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; - - cgValue result = results[return_count-1]; - result = cg_flatten_value(p, result); - TB_Node *final_res = nullptr; - if (result.kind == cgValue_Addr) { - TB_CharUnits align = cast(TB_CharUnits)type_align_of(result.type); - final_res = tb_inst_load(p->func, dt, result.node, align, false); - } else { - GB_ASSERT(result.kind == cgValue_Value); - TB_DataType st = result.node->dt; - GB_ASSERT(st.type == dt.type); - if (st.raw == dt.raw) { - final_res = result.node; - } else if (st.type == TB_INT && st.data == 1) { - final_res = tb_inst_zxt(p->func, result.node, dt); - } else { - final_res = tb_inst_bitcast(p->func, result.node, dt); - } - } - GB_ASSERT(final_res != nullptr); - - tb_inst_ret(p->func, 1, &final_res); - return; - } - - } else { - GB_ASSERT_MSG(!is_calling_convention_odin(p->type->Proc.calling_convention), "missing %s", proc_calling_convention_strings[p->type->Proc.calling_convention]); - - if (p->return_by_ptr) { - Entity *e = tuple->variables[return_count-1]; - TB_Node *ret_ptr = tb_inst_param(p->func, 0); - cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type)); - cg_emit_store(p, ptr, results[return_count-1]); - - tb_inst_ret(p->func, 0, nullptr); - return; - } else { - GB_ASSERT(p->proto->return_count == 1); - TB_DataType dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; - if (results.count == 1) { - cgValue result = results[0]; - result = cg_flatten_value(p, result); - - TB_Node *final_res = nullptr; - if (result.kind == cgValue_Addr) { - TB_CharUnits align = cast(TB_CharUnits)type_align_of(result.type); - final_res = tb_inst_load(p->func, dt, result.node, align, false); - } else { - GB_ASSERT(result.kind == cgValue_Value); - TB_DataType st = result.node->dt; - GB_ASSERT(st.type == dt.type); - if (st.raw == dt.raw) { - final_res = result.node; - } else if (st.type == TB_INT && st.data == 1) { - final_res = tb_inst_zxt(p->func, result.node, dt); - } else { - final_res = tb_inst_bitcast(p->func, result.node, dt); - } - } - - GB_ASSERT(final_res != nullptr); - - tb_inst_ret(p->func, 1, &final_res); - return; - } else { - GB_ASSERT_MSG(results.count == 1, "TODO(bill): multi-return values for the return"); - return; - } - } - - } -} - - -gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { - TypeTuple *tuple = &p->type->Proc.results->Tuple; - isize return_count = p->type->Proc.result_count; - - if (return_count == 0) { - tb_inst_ret(p->func, 0, nullptr); - return; - } - TEMPORARY_ALLOCATOR_GUARD(); - - auto results = array_make(temporary_allocator(), 0, return_count); - - if (return_results.count != 0) { - for (isize i = 0; i < return_results.count; i++) { - cgValue res = cg_build_expr(p, return_results[i]); - cg_append_tuple_values(p, &results, res); - } - } else { - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; - cgAddr addr = map_must_get(&p->variable_map, e); - cgValue res = cg_addr_load(p, addr); - array_add(&results, res); - } - } - GB_ASSERT(results.count == return_count); - - if (return_results.count != 0 && p->type->Proc.has_named_results) { - // NOTE(bill): store the named values before returning - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; - cgAddr addr = map_must_get(&p->variable_map, e); - cg_addr_store(p, addr, results[i]); - } - } - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; - results[i] = cg_emit_conv(p, results[i], e->type); - } - - cg_build_return_stmt_internal(p, slice_from_array(results)); -} - -gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { - ast_node(is, IfStmt, node); - cg_scope_open(p, is->scope); // Scope #1 - defer (cg_scope_close(p, cgDeferExit_Default, nullptr)); - - if (is->init != nullptr) { - TB_Node *init = cg_control_region(p, "if_init"); - cg_emit_goto(p, init); - tb_inst_set_control(p->func, init); - cg_build_stmt(p, is->init); - } - - TB_Node *then = cg_control_region(p, "if_then"); - TB_Node *done = cg_control_region(p, "if_done"); - TB_Node *else_ = done; - if (is->else_stmt != nullptr) { - else_ = cg_control_region(p, "if_else"); - } - - cgValue cond = cg_build_cond(p, is->cond, then, else_); - gb_unused(cond); - - if (is->label != nullptr) { - cgTargetList *tl = cg_push_target_list(p, is->label, done, nullptr, nullptr); - tl->is_block = true; - } - - // TODO(bill): should we do a constant check? - // Which philosophy are we following? - // - IR represents what the code represents (probably this) - // - IR represents what the code executes - - tb_inst_set_control(p->func, then); - - cg_build_stmt(p, is->body); - - cg_emit_goto(p, done); - - if (is->else_stmt != nullptr) { - tb_inst_set_control(p->func, else_); - - cg_scope_open(p, scope_of_node(is->else_stmt)); - cg_build_stmt(p, is->else_stmt); - cg_scope_close(p, cgDeferExit_Default, nullptr); - - cg_emit_goto(p, done); - } - - tb_inst_set_control(p->func, done); -} - -gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { - ast_node(fs, ForStmt, node); - - cg_scope_open(p, fs->scope); - defer (cg_scope_close(p, cgDeferExit_Default, nullptr)); - - if (fs->init != nullptr) { - TB_Node *init = cg_control_region(p, "for_init"); - cg_emit_goto(p, init); - tb_inst_set_control(p->func, init); - cg_build_stmt(p, fs->init); - } - TB_Node *body = cg_control_region(p, "for_body"); - TB_Node *done = cg_control_region(p, "for_done"); - TB_Node *loop = body; - if (fs->cond != nullptr) { - loop = cg_control_region(p, "for_loop"); - } - TB_Node *post = loop; - if (fs->post != nullptr) { - post = cg_control_region(p, "for_post"); - } - - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - if (loop != body) { - cg_build_cond(p, fs->cond, body, done); - tb_inst_set_control(p->func, body); - } - - cg_push_target_list(p, fs->label, done, post, nullptr); - cg_build_stmt(p, fs->body); - cg_pop_target_list(p); - - cg_emit_goto(p, post); - - if (fs->post != nullptr) { - tb_inst_set_control(p->func, post); - cg_build_stmt(p, fs->post); - cg_emit_goto(p, loop); - } - tb_inst_set_control(p->func, done); -} - - -gb_internal Ast *cg_strip_and_prefix(Ast *ident) { - if (ident != nullptr) { - if (ident->kind == Ast_UnaryExpr && ident->UnaryExpr.op.kind == Token_And) { - ident = ident->UnaryExpr.expr; - } - GB_ASSERT(ident->kind == Ast_Ident); - } - return ident; -} - -gb_internal void cg_emit_increment(cgProcedure *p, cgValue addr) { - GB_ASSERT(is_type_pointer(addr.type)); - Type *type = type_deref(addr.type); - cgValue v_one = cg_const_value(p, type, exact_value_i64(1)); - cg_emit_store(p, addr, cg_emit_arith(p, Token_Add, cg_emit_load(p, addr), v_one, type)); - -} - -gb_internal void cg_range_stmt_store_val(cgProcedure *p, Ast *stmt_val, cgValue const &value) { - Entity *e = entity_of_node(stmt_val); - if (e == nullptr) { - return; - } - - if (e->flags & EntityFlag_Value) { - if (value.kind == cgValue_Addr) { - cgValue ptr = cg_address_from_load_or_generate_local(p, value); - cg_add_entity(p->module, e, ptr); - return; - } - } - - cgAddr addr = cg_add_local(p, e->type, e, false); - cg_addr_store(p, addr, value); - return; -} - -gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *node, - AstRangeStmt *rs, Scope *scope) { - bool ADD_EXTRA_WRAPPING_CHECK = true; - - cg_scope_open(p, scope); - - Ast *val0 = rs->vals.count > 0 ? cg_strip_and_prefix(rs->vals[0]) : nullptr; - Ast *val1 = rs->vals.count > 1 ? cg_strip_and_prefix(rs->vals[1]) : nullptr; - Type *val0_type = nullptr; - Type *val1_type = nullptr; - if (val0 != nullptr && !is_blank_ident(val0)) { - val0_type = type_of_expr(val0); - } - if (val1 != nullptr && !is_blank_ident(val1)) { - val1_type = type_of_expr(val1); - } - - TokenKind op = Token_Lt; - switch (node->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_RangeFull: op = Token_LtEq; break; - case Token_RangeHalf: op = Token_Lt; break; - default: GB_PANIC("Invalid interval operator"); break; - } - - - cgValue lower = cg_build_expr(p, node->left); - cgValue upper = {}; // initialized each time in the loop - - cgAddr value; - if (val0_type != nullptr) { - value = cg_add_local(p, val0_type, entity_of_node(val0), false); - } else { - value = cg_add_local(p, lower.type, nullptr, false); - } - cg_addr_store(p, value, lower); - - cgAddr index; - if (val1_type != nullptr) { - index = cg_add_local(p, val1_type, entity_of_node(val1), false); - } else { - index = cg_add_local(p, t_int, nullptr, false); - } - cg_addr_store(p, index, cg_const_int(p, t_int, 0)); - - TB_Node *loop = cg_control_region(p, "for_interval_loop"); - TB_Node *body = cg_control_region(p, "for_interval_body"); - TB_Node *done = cg_control_region(p, "for_interval_done"); - - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - upper = cg_build_expr(p, node->right); - cgValue curr_value = cg_addr_load(p, value); - cgValue cond = cg_emit_comp(p, op, curr_value, upper); - cg_emit_if(p, cond, body, done); - tb_inst_set_control(p->func, body); - - cgValue val = cg_addr_load(p, value); - cgValue idx = cg_addr_load(p, index); - - if (val0_type) cg_range_stmt_store_val(p, val0, val); - if (val1_type) cg_range_stmt_store_val(p, val1, idx); - - - { - // NOTE: this check block will most likely be optimized out, and is here - // to make this code easier to read - TB_Node *check = nullptr; - TB_Node *post = cg_control_region(p, "for_interval_post"); - - TB_Node *continue_block = post; - - if (ADD_EXTRA_WRAPPING_CHECK && - op == Token_LtEq) { - check = cg_control_region(p, "for_interval_check"); - continue_block = check; - } - - cg_push_target_list(p, rs->label, done, continue_block, nullptr); - - cg_build_stmt(p, rs->body); - - cg_scope_close(p, cgDeferExit_Default, nullptr); - cg_pop_target_list(p); - - if (check != nullptr) { - cg_emit_goto(p, check); - tb_inst_set_control(p->func, check); - - cgValue check_cond = cg_emit_comp(p, Token_NotEq, curr_value, upper); - cg_emit_if(p, check_cond, post, done); - } else { - cg_emit_goto(p, post); - } - - tb_inst_set_control(p->func, post); - cg_emit_increment(p, value.addr); - cg_emit_increment(p, index.addr); - cg_emit_goto(p, loop); - } - - tb_inst_set_control(p->func, done); -} - -gb_internal void cg_build_range_stmt_indexed(cgProcedure *p, cgValue expr, Type *val_type, cgValue count_ptr, - cgValue *val_, cgValue *idx_, TB_Node **loop_, TB_Node **done_, - bool is_reverse) { - cgValue count = {}; - Type *expr_type = base_type(type_deref(expr.type)); - switch (expr_type->kind) { - case Type_Array: - count = cg_const_int(p, t_int, expr_type->Array.count); - break; - } - - cgValue val = {}; - cgValue idx = {}; - TB_Node *loop = nullptr; - TB_Node *done = nullptr; - TB_Node *body = nullptr; - - loop = cg_control_region(p, "for_index_loop"); - body = cg_control_region(p, "for_index_body"); - done = cg_control_region(p, "for_index_done"); - - cgAddr index = cg_add_local(p, t_int, nullptr, false); - - if (!is_reverse) { - /* - for x, i in array { - ... - } - - i := -1 - for { - i += 1 - if !(i < len(array)) { - break - } - #no_bounds_check x := array[i] - ... - } - */ - - cg_addr_store(p, index, cg_const_int(p, t_int, cast(u64)-1)); - - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - cgValue incr = cg_emit_arith(p, Token_Add, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); - cg_addr_store(p, index, incr); - - if (count.node == nullptr) { - GB_ASSERT(count_ptr.node != nullptr); - count = cg_emit_load(p, count_ptr); - } - cgValue cond = cg_emit_comp(p, Token_Lt, incr, count); - cg_emit_if(p, cond, body, done); - } else { - // NOTE(bill): REVERSED LOGIC - /* - #reverse for x, i in array { - ... - } - - i := len(array) - for { - i -= 1 - if i < 0 { - break - } - #no_bounds_check x := array[i] - ... - } - */ - - if (count.node == nullptr) { - GB_ASSERT(count_ptr.node != nullptr); - count = cg_emit_load(p, count_ptr); - } - count = cg_emit_conv(p, count, t_int); - cg_addr_store(p, index, count); - - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - cgValue incr = cg_emit_arith(p, Token_Sub, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); - cg_addr_store(p, index, incr); - - cgValue anti_cond = cg_emit_comp(p, Token_Lt, incr, cg_const_int(p, t_int, 0)); - cg_emit_if(p, anti_cond, done, body); - } - - tb_inst_set_control(p->func, body); - - idx = cg_addr_load(p, index); - switch (expr_type->kind) { - case Type_Array: { - if (val_type != nullptr) { - val = cg_emit_load(p, cg_emit_array_ep(p, expr, idx)); - } - break; - } - case Type_EnumeratedArray: { - if (val_type != nullptr) { - val = cg_emit_load(p, cg_emit_array_ep(p, expr, idx)); - // NOTE(bill): Override the idx value for the enumeration - Type *index_type = expr_type->EnumeratedArray.index; - if (compare_exact_values(Token_NotEq, *expr_type->EnumeratedArray.min_value, exact_value_u64(0))) { - idx = cg_emit_arith(p, Token_Add, idx, cg_const_value(p, index_type, *expr_type->EnumeratedArray.min_value), index_type); - } - } - break; - } - case Type_Slice: { - if (val_type != nullptr) { - cgValue elem = cg_builtin_raw_data(p, expr); - val = cg_emit_load(p, cg_emit_ptr_offset(p, elem, idx)); - } - break; - } - case Type_DynamicArray: { - if (val_type != nullptr) { - cgValue elem = cg_emit_struct_ep(p, expr, 0); - elem = cg_emit_load(p, elem); - val = cg_emit_load(p, cg_emit_ptr_offset(p, elem, idx)); - } - break; - } - case Type_Struct: { - GB_ASSERT(is_type_soa_struct(expr_type)); - break; - } - - default: - GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); - break; - } - - if (val_) *val_ = val; - if (idx_) *idx_ = idx; - if (loop_) *loop_ = loop; - if (done_) *done_ = done; - -} - -gb_internal void cg_build_range_stmt_enum(cgProcedure *p, Type *enum_type, Type *val_type, cgValue *val_, cgValue *idx_, TB_Node **loop_, TB_Node **done_) { - Type *t = enum_type; - GB_ASSERT(is_type_enum(t)); - t = base_type(t); - Type *core_elem = core_type(t); - GB_ASSERT(t->kind == Type_Enum); - i64 enum_count = t->Enum.fields.count; - cgValue max_count = cg_const_int(p, t_int, enum_count); - - cgValue ti = cg_type_info(p, t); - cgValue variant = cg_emit_struct_ep(p, ti, 4); - cgValue eti_ptr = cg_emit_conv(p, variant, t_type_info_enum_ptr); - cgValue values = cg_emit_load(p, cg_emit_struct_ep(p, eti_ptr, 2)); - cgValue values_data = cg_builtin_raw_data(p, values); - - cgAddr offset_ = cg_add_local(p, t_int, nullptr, false); - cg_addr_store(p, offset_, cg_const_int(p, t_int, 0)); - - TB_Node *loop = cg_control_region(p, "for_enum_loop"); - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - TB_Node *body = cg_control_region(p, "for_enum_body"); - TB_Node *done = cg_control_region(p, "for_enum_done"); - - cgValue offset = cg_addr_load(p, offset_); - cgValue cond = cg_emit_comp(p, Token_Lt, offset, max_count); - cg_emit_if(p, cond, body, done); - tb_inst_set_control(p->func, body); - - cgValue val_ptr = cg_emit_ptr_offset(p, values_data, offset); - cg_emit_increment(p, offset_.addr); - - cgValue val = {}; - if (val_type != nullptr) { - GB_ASSERT(are_types_identical(enum_type, val_type)); - - if (is_type_integer(core_elem)) { - cgValue i = cg_emit_load(p, cg_emit_conv(p, val_ptr, t_i64_ptr)); - val = cg_emit_conv(p, i, t); - } else { - GB_PANIC("TODO(bill): enum core type %s", type_to_string(core_elem)); - } - } - - if (val_) *val_ = val; - if (idx_) *idx_ = offset; - if (loop_) *loop_ = loop; - if (done_) *done_ = done; -} - -gb_internal void cg_build_range_stmt_struct_soa(cgProcedure *p, AstRangeStmt *rs, Scope *scope) { - Ast *expr = unparen_expr(rs->expr); - TypeAndValue tav = type_and_value_of_expr(expr); - - TB_Node *loop = nullptr; - TB_Node *body = nullptr; - TB_Node *done = nullptr; - - bool is_reverse = rs->reverse; - - cg_scope_open(p, scope); - - Ast *val0 = rs->vals.count > 0 ? cg_strip_and_prefix(rs->vals[0]) : nullptr; - Ast *val1 = rs->vals.count > 1 ? cg_strip_and_prefix(rs->vals[1]) : nullptr; - Type *val_types[2] = {}; - if (val0 != nullptr && !is_blank_ident(val0)) { - val_types[0] = type_of_expr(val0); - } - if (val1 != nullptr && !is_blank_ident(val1)) { - val_types[1] = type_of_expr(val1); - } - - cgAddr array = cg_build_addr(p, expr); - if (is_type_pointer(cg_addr_type(array))) { - array = cg_addr(cg_addr_load(p, array)); - } - cgValue count = cg_builtin_len(p, cg_addr_load(p, array)); - - - cgAddr index = cg_add_local(p, t_int, nullptr, false); - - if (!is_reverse) { - /* - for x, i in array { - ... - } - - i := -1 - for { - i += 1 - if !(i < len(array)) { - break - } - x := array[i] // but #soa-ified - ... - } - */ - - cg_addr_store(p, index, cg_const_int(p, t_int, cast(u64)-1)); - - loop = cg_control_region(p, "for_soa_loop"); - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - cgValue incr = cg_emit_arith(p, Token_Add, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); - cg_addr_store(p, index, incr); - - body = cg_control_region(p, "for_soa_body"); - done = cg_control_region(p, "for_soa_done"); - - cgValue cond = cg_emit_comp(p, Token_Lt, incr, count); - cg_emit_if(p, cond, body, done); - } else { - // NOTE(bill): REVERSED LOGIC - /* - #reverse for x, i in array { - ... - } - - i := len(array) - for { - i -= 1 - if i < 0 { - break - } - #no_bounds_check x := array[i] // but #soa-ified - ... - } - */ - cg_addr_store(p, index, count); - - loop = cg_control_region(p, "for_soa_loop"); - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, loop); - - cgValue incr = cg_emit_arith(p, Token_Sub, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); - cg_addr_store(p, index, incr); - - body = cg_control_region(p, "for_soa_body"); - done = cg_control_region(p, "for_soa_done"); - - cgValue cond = cg_emit_comp(p, Token_Lt, incr, cg_const_int(p, t_int, 0)); - cg_emit_if(p, cond, done, body); - } - tb_inst_set_control(p->func, body); - - - if (val_types[0]) { - Entity *e = entity_of_node(val0); - if (e != nullptr) { - cgAddr soa_val = cg_addr_soa_variable(array.addr, cg_addr_load(p, index), nullptr); - map_set(&p->soa_values_map, e, soa_val); - } - } - if (val_types[1]) { - cg_range_stmt_store_val(p, val1, cg_addr_load(p, index)); - } - - - cg_push_target_list(p, rs->label, done, loop, nullptr); - - cg_build_stmt(p, rs->body); - - cg_scope_close(p, cgDeferExit_Default, nullptr); - cg_pop_target_list(p); - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, done); - -} - - -gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { - ast_node(rs, RangeStmt, node); - - Ast *expr = unparen_expr(rs->expr); - - if (is_ast_range(expr)) { - cg_build_range_stmt_interval(p, &expr->BinaryExpr, rs, rs->scope); - return; - } - - Type *expr_type = type_of_expr(expr); - if (expr_type != nullptr) { - Type *et = base_type(type_deref(expr_type)); - if (is_type_soa_struct(et)) { - cg_build_range_stmt_struct_soa(p, rs, rs->scope); - return; - } - } - - cg_scope_open(p, rs->scope); - - - Ast *val0 = rs->vals.count > 0 ? cg_strip_and_prefix(rs->vals[0]) : nullptr; - Ast *val1 = rs->vals.count > 1 ? cg_strip_and_prefix(rs->vals[1]) : nullptr; - Type *val0_type = nullptr; - Type *val1_type = nullptr; - if (val0 != nullptr && !is_blank_ident(val0)) { - val0_type = type_of_expr(val0); - } - if (val1 != nullptr && !is_blank_ident(val1)) { - val1_type = type_of_expr(val1); - } - - cgValue val = {}; - cgValue key = {}; - TB_Node *loop = nullptr; - TB_Node *done = nullptr; - bool is_map = false; - TypeAndValue tav = type_and_value_of_expr(expr); - - if (tav.mode == Addressing_Type) { - cg_build_range_stmt_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done); - } else { - Type *expr_type = type_of_expr(expr); - Type *et = base_type(type_deref(expr_type)); - switch (et->kind) { - case Type_Map: { - is_map = true; - cgValue map = cg_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(map.type))) { - map = cg_emit_load(p, map); - } - GB_PANIC("TODO(bill): cg_build_range_map"); - // cg_build_range_map(p, map, val1_type, &val, &key, &loop, &done); - break; - } - case Type_Array: { - cgValue array = cg_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = cg_emit_load(p, array); - } - cgAddr count_ptr = cg_add_local(p, t_int, nullptr, false); - cg_addr_store(p, count_ptr, cg_const_int(p, t_int, et->Array.count)); - cg_build_range_stmt_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); - break; - } - case Type_EnumeratedArray: { - cgValue array = cg_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = cg_emit_load(p, array); - } - cgAddr count_ptr = cg_add_local(p, t_int, nullptr, false); - cg_addr_store(p, count_ptr, cg_const_int(p, t_int, et->EnumeratedArray.count)); - cg_build_range_stmt_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); - break; - } - case Type_DynamicArray: { - cgValue count_ptr = {}; - cgValue array = cg_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = cg_emit_load(p, array); - } - count_ptr = cg_emit_struct_ep(p, array, 1); - cg_build_range_stmt_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); - break; - } - case Type_Slice: { - cgValue count_ptr = {}; - cgValue slice = cg_build_expr(p, expr); - if (is_type_pointer(slice.type)) { - count_ptr = cg_emit_struct_ep(p, slice, 1); - slice = cg_emit_load(p, slice); - } else { - count_ptr = cg_add_local(p, t_int, nullptr, false).addr; - cg_emit_store(p, count_ptr, cg_builtin_len(p, slice)); - } - cg_build_range_stmt_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); - break; - } - case Type_Basic: { - cgValue string = cg_build_expr(p, expr); - if (is_type_pointer(string.type)) { - string = cg_emit_load(p, string); - } - if (is_type_untyped(expr_type)) { - cgAddr s = cg_add_local(p, default_type(string.type), nullptr, false); - cg_addr_store(p, s, string); - string = cg_addr_load(p, s); - } - Type *t = base_type(string.type); - GB_ASSERT(!is_type_cstring(t)); - GB_PANIC("TODO(bill): cg_build_range_string"); - // cg_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); - break; - } - case Type_Tuple: - GB_PANIC("TODO(bill): cg_build_range_tuple"); - // cg_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); - break; - default: - GB_PANIC("Cannot range over %s", type_to_string(expr_type)); - break; - } - } - - if (is_map) { - if (val0_type) cg_range_stmt_store_val(p, val0, key); - if (val1_type) cg_range_stmt_store_val(p, val1, val); - } else { - if (val0_type) cg_range_stmt_store_val(p, val0, val); - if (val1_type) cg_range_stmt_store_val(p, val1, key); - } - - cg_push_target_list(p, rs->label, done, loop, nullptr); - - cg_build_stmt(p, rs->body); - - cg_scope_close(p, cgDeferExit_Default, nullptr); - cg_pop_target_list(p); - cg_emit_goto(p, loop); - tb_inst_set_control(p->func, done); -} - -gb_internal bool cg_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss) { - if (ss->tag == nullptr) { - return false; - } - enum { DISALLOW_64_SWITCH = true }; - - bool is_typeid = false; - TypeAndValue tv = type_and_value_of_expr(ss->tag); - if (is_type_integer(core_type(tv.type))) { - i64 sz = type_size_of(tv.type); - if (sz > 8) { - return false; - } - if (DISALLOW_64_SWITCH && sz == 8) { - return false; - } - // okay - } else if (is_type_typeid(tv.type)) { - // okay - is_typeid = true; - if (DISALLOW_64_SWITCH && build_context.ptr_size == 8) { - return false; - } - } else { - return false; - } - - ast_node(body, BlockStmt, ss->body); - for (Ast *clause : body->stmts) { - ast_node(cc, CaseClause, clause); - - if (cc->list.count == 0) { - continue; - } - - for (Ast *expr : cc->list) { - expr = unparen_expr(expr); - if (is_ast_range(expr)) { - return false; - } - if (expr->tav.mode == Addressing_Type) { - GB_ASSERT(is_typeid); - continue; - } - tv = type_and_value_of_expr(expr); - if (tv.mode != Addressing_Constant) { - return false; - } - if (!is_type_integer(core_type(tv.type))) { - return false; - } - } - - } - - return true; -} - - -gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { - ast_node(ss, SwitchStmt, node); - cg_scope_open(p, ss->scope); - - if (ss->init != nullptr) { - cg_build_stmt(p, ss->init); - } - cgValue tag = {}; - if (ss->tag != nullptr) { - tag = cg_build_expr(p, ss->tag); - } else { - tag = cg_const_bool(p, t_bool, true); - } - - TB_Node *done = cg_control_region(p, "switch_done"); - - ast_node(body, BlockStmt, ss->body); - - isize case_count = body->stmts.count; - Slice default_stmts = {}; - TB_Node *default_fall = nullptr; - TB_Node *default_block = nullptr; - Scope * default_scope = nullptr; - TB_Node *fall = nullptr; - - - auto body_regions = slice_make(permanent_allocator(), body->stmts.count); - auto body_scopes = slice_make(permanent_allocator(), body->stmts.count); - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - body_regions[i] = cg_control_region(p, cc->list.count == 0 ? "switch_default_body" : "switch_case_body"); - body_scopes[i] = cc->scope; - if (cc->list.count == 0) { - default_block = body_regions[i]; - default_scope = cc->scope; - } - } - - bool is_trivial = cg_switch_stmt_can_be_trivial_jump_table(ss); - if (is_trivial) { - isize key_count = 0; - for (Ast *clause : body->stmts) { - ast_node(cc, CaseClause, clause); - key_count += cc->list.count; - } - TB_SwitchEntry *keys = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, key_count); - isize key_index = 0; - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - TB_Node *region = body_regions[i]; - for (Ast *expr : cc->list) { - i64 key = 0; - expr = unparen_expr(expr); - GB_ASSERT(!is_ast_range(expr)); - if (expr->tav.mode == Addressing_Type) { - Type *type = expr->tav.value.value_typeid; - if (type == nullptr || type == t_invalid) { - type = expr->tav.type; - } - key = cg_typeid_as_u64(p->module, type); - } else { - auto tv = type_and_value_of_expr(expr); - GB_ASSERT(tv.mode == Addressing_Constant); - key = exact_value_to_i64(tv.value); - } - keys[key_index++] = {key, region}; - } - } - GB_ASSERT(key_index == key_count); - - TB_Node *end_block = done; - if (default_block) { - end_block = default_block; - } - - TB_DataType dt = cg_data_type(tag.type); - GB_ASSERT(tag.kind == cgValue_Value); - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); - - tb_inst_branch(p->func, dt, tag.node, end_block, key_count, keys); - } - - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - TB_Node *body_region = body_regions[i]; - Scope *body_scope = body_scopes[i]; - fall = done; - if (i+1 < case_count) { - fall = body_regions[i+1]; - } - - if (cc->list.count == 0) { - // default case - default_stmts = cc->stmts; - default_fall = fall; - GB_ASSERT(default_block == body_region); - continue; - } - - TB_Node *next_cond = nullptr; - if (!is_trivial) for (Ast *expr : cc->list) { - expr = unparen_expr(expr); - - next_cond = cg_control_region(p, "switch_case_next"); - - cgValue cond = {}; - if (is_ast_range(expr)) { - ast_node(ie, BinaryExpr, expr); - TokenKind op = Token_Invalid; - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_RangeFull: op = Token_LtEq; break; - case Token_RangeHalf: op = Token_Lt; break; - default: GB_PANIC("Invalid interval operator"); break; - } - cgValue lhs = cg_build_expr(p, ie->left); - cgValue rhs = cg_build_expr(p, ie->right); - - cgValue cond_lhs = cg_emit_comp(p, Token_LtEq, lhs, tag); - cgValue cond_rhs = cg_emit_comp(p, op, tag, rhs); - cond = cg_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool); - } else { - if (expr->tav.mode == Addressing_Type) { - GB_ASSERT(is_type_typeid(tag.type)); - cgValue e = cg_typeid(p, expr->tav.type); - e = cg_emit_conv(p, e, tag.type); - cond = cg_emit_comp(p, Token_CmpEq, tag, e); - } else { - cond = cg_emit_comp(p, Token_CmpEq, tag, cg_build_expr(p, expr)); - } - } - - GB_ASSERT(cond.kind == cgValue_Value); - tb_inst_if(p->func, cond.node, body_region, next_cond); - tb_inst_set_control(p->func, next_cond); - } - - tb_inst_set_control(p->func, body_region); - - cg_push_target_list(p, ss->label, done, nullptr, fall); - cg_scope_open(p, body_scope); - cg_build_stmt_list(p, cc->stmts); - cg_scope_close(p, cgDeferExit_Default, body_region); - cg_pop_target_list(p); - - cg_emit_goto(p, done); - tb_inst_set_control(p->func, next_cond); - } - - if (default_block != nullptr) { - if (!is_trivial) { - cg_emit_goto(p, default_block); - } - tb_inst_set_control(p->func, default_block); - - cg_push_target_list(p, ss->label, done, nullptr, default_fall); - cg_scope_open(p, default_scope); - cg_build_stmt_list(p, default_stmts); - cg_scope_close(p, cgDeferExit_Default, default_block); - cg_pop_target_list(p); - } - - - cg_emit_goto(p, done); - tb_inst_set_control(p->func, done); - - cg_scope_close(p, cgDeferExit_Default, done); -} - -gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { - ast_node(ss, TypeSwitchStmt, node); - - TB_Node *done_region = cg_control_region(p, "typeswitch_done"); - TB_Node *else_region = done_region; - TB_Node *default_region = nullptr; - isize num_cases = 0; - - cg_scope_open(p, ss->scope); - defer (cg_scope_close(p, cgDeferExit_Default, done_region)); - - ast_node(as, AssignStmt, ss->tag); - GB_ASSERT(as->lhs.count == 1); - GB_ASSERT(as->rhs.count == 1); - - cgValue parent = cg_build_expr(p, as->rhs[0]); - bool is_parent_ptr = is_type_pointer(parent.type); - Type *parent_base_type = type_deref(parent.type); - gb_unused(parent_base_type); - - TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type); - GB_ASSERT(switch_kind != TypeSwitch_Invalid); - - - cgValue parent_value = parent; - - cgValue parent_ptr = parent; - if (!is_parent_ptr) { - parent_ptr = cg_address_from_load_or_generate_local(p, parent); - } - - cgValue tag = {}; - cgValue union_data = {}; - if (switch_kind == TypeSwitch_Union) { - union_data = cg_emit_conv(p, parent_ptr, t_rawptr); - Type *union_type = type_deref(parent_ptr.type); - if (is_type_union_maybe_pointer(union_type)) { - tag = cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_NotEq, union_data), t_int); - } else if (union_tag_size(union_type) == 0) { - tag = {}; // there is no tag for a zero sized union - } else { - cgValue tag_ptr = cg_emit_union_tag_ptr(p, parent_ptr); - tag = cg_emit_load(p, tag_ptr); - } - } else if (switch_kind == TypeSwitch_Any) { - tag = cg_emit_load(p, cg_emit_struct_ep(p, parent_ptr, 1)); - } else { - GB_PANIC("Unknown switch kind"); - } - - ast_node(body, BlockStmt, ss->body); - - for (Ast *clause : body->stmts) { - ast_node(cc, CaseClause, clause); - num_cases += cc->list.count; - if (cc->list.count == 0) { - GB_ASSERT(default_region == nullptr); - default_region = cg_control_region(p, "typeswitch_default_body"); - else_region = default_region; - } - } - - bool all_by_reference = false; - for (Ast *clause : body->stmts) { - ast_node(cc, CaseClause, clause); - if (cc->list.count != 1) { - continue; - } - Entity *case_entity = implicit_entity_of_node(clause); - all_by_reference |= (case_entity->flags & EntityFlag_Value) == 0; - break; - } - - TB_Node *backing_ptr = nullptr; - if (!all_by_reference) { - bool variants_found = false; - i64 max_size = 0; - i64 max_align = 1; - for (Ast *clause : body->stmts) { - ast_node(cc, CaseClause, clause); - if (cc->list.count != 1) { - continue; - } - Entity *case_entity = implicit_entity_of_node(clause); - if (!is_type_untyped_nil(case_entity->type)) { - max_size = gb_max(max_size, type_size_of(case_entity->type)); - max_align = gb_max(max_align, type_align_of(case_entity->type)); - variants_found = true; - } - } - if (variants_found) { - backing_ptr = tb_inst_local(p->func, cast(TB_CharUnits)max_size, cast(TB_CharUnits)max_align); - } - } - - TEMPORARY_ALLOCATOR_GUARD(); - TB_Node **control_regions = gb_alloc_array(temporary_allocator(), TB_Node *, body->stmts.count); - TB_SwitchEntry *switch_entries = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, num_cases); - - isize case_index = 0; - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - if (cc->list.count == 0) { - control_regions[i] = default_region; - continue; - } - - TB_Node *region = cg_control_region(p, "typeswitch_body"); - control_regions[i] = region; - - for (Ast *type_expr : cc->list) { - Type *case_type = type_of_expr(type_expr); - i64 key = -1; - if (switch_kind == TypeSwitch_Union) { - Type *ut = base_type(type_deref(parent.type)); - if (is_type_untyped_nil(case_type)) { - key = 0; - } else { - key = union_variant_index(ut, case_type); - } - } else if (switch_kind == TypeSwitch_Any) { - if (is_type_untyped_nil(case_type)) { - key = 0; - } else { - key = cast(i64)cg_typeid_as_u64(p->module, case_type); - } - } - GB_ASSERT(key >= 0); - - switch_entries[case_index++] = TB_SwitchEntry{key, region}; - } - } - - GB_ASSERT(case_index == num_cases); - - { - TB_DataType dt = {}; - TB_Node *key = nullptr; - if (type_size_of(parent_base_type) == 0) { - GB_ASSERT(tag.node == nullptr); - key = tb_inst_bool(p->func, false); - dt = cg_data_type(t_bool); - } else { - GB_ASSERT(tag.kind == cgValue_Value && tag.node != nullptr); - dt = cg_data_type(tag.type); - key = tag.node; - } - - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); - tb_inst_branch(p->func, dt, key, else_region, num_cases, switch_entries); - } - - - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - bool saw_nil = false; - for (Ast *type_expr : cc->list) { - Type *case_type = type_of_expr(type_expr); - if (is_type_untyped_nil(case_type)) { - saw_nil = true; - } - } - - Entity *case_entity = implicit_entity_of_node(clause); - bool by_reference = (case_entity->flags & EntityFlag_Value) == 0; - - cg_scope_open(p, cc->scope); - - TB_Node *body_region = control_regions[i]; - tb_inst_set_control(p->func, body_region); - - if (cc->list.count == 1 && !saw_nil) { - cgValue data = {}; - if (switch_kind == TypeSwitch_Union) { - data = union_data; - } else if (switch_kind == TypeSwitch_Any) { - data = cg_emit_load(p, cg_emit_struct_ep(p, parent_ptr, 0)); - } - GB_ASSERT(data.kind == cgValue_Value); - - Type *ct = case_entity->type; - Type *ct_ptr = alloc_type_pointer(ct); - - cgValue ptr = {}; - - if (backing_ptr) { // by value - GB_ASSERT(!by_reference); - - i64 size = type_size_of(case_entity->type); - i64 align = type_align_of(case_entity->type); - - // make a copy of the case value - tb_inst_memcpy(p->func, - backing_ptr, // dst - data.node, // src - tb_inst_uint(p->func, TB_TYPE_INT, size), - cast(TB_CharUnits)align - ); - - ptr = cg_value(backing_ptr, ct_ptr); - - } else { // by reference - GB_ASSERT(by_reference); - ptr = cg_emit_conv(p, data, ct_ptr); - } - GB_ASSERT(are_types_identical(case_entity->type, type_deref(ptr.type))); - - cg_add_entity(p->module, case_entity, ptr); - String name = case_entity->token.string; - tb_function_attrib_variable(p->func, ptr.node, nullptr, name.len, cast(char const *)name.text, cg_debug_type(p->module, ct)); - } else { - if (case_entity->flags & EntityFlag_Value) { - // by value - cgAddr x = cg_add_local(p, case_entity->type, case_entity, false); - cg_addr_store(p, x, parent_value); - } else { - // by reference - cg_add_entity(p->module, case_entity, parent_value); - } - } - - cg_push_target_list(p, ss->label, done_region, nullptr, nullptr); - cg_build_stmt_list(p, cc->stmts); - cg_scope_close(p, cgDeferExit_Default, body_region); - cg_pop_target_list(p); - - cg_emit_goto(p, done_region); - } - - cg_emit_goto(p, done_region); - tb_inst_set_control(p->func, done_region); -} - - -gb_internal void cg_build_mutable_value_decl(cgProcedure *p, Ast *node) { - ast_node(vd, ValueDecl, node); - if (!vd->is_mutable) { - return; - } - - bool is_static = false; - for (Ast *name : vd->names) if (!is_blank_ident(name)) { - // NOTE(bill): Sanity check to check for the existence of the variable's Entity - GB_ASSERT(name->kind == Ast_Ident); - Entity *e = entity_of_node(name); - TokenPos pos = ast_token(name).pos; - GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); - if (e->flags & EntityFlag_Static) { - // NOTE(bill): If one of the entities is static, they all are - is_static = true; - } - } - - if (is_static) { - for_array(i, vd->names) { - Ast *ident = vd->names[i]; - GB_ASSERT(!is_blank_ident(ident)); - Entity *e = entity_of_node(ident); - GB_ASSERT(e->flags & EntityFlag_Static); - String name = e->token.string; - - String mangled_name = {}; - { - gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); - str = gb_string_appendc(str, "-"); - str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); - mangled_name.text = cast(u8 *)str; - mangled_name.len = gb_string_length(str); - } - - cgModule *m = p->module; - - TB_DebugType *debug_type = cg_debug_type(m, e->type); - TB_Global *global = tb_global_create(m->mod, mangled_name.len, cast(char const *)mangled_name.text, debug_type, TB_LINKAGE_PRIVATE); - - TB_ModuleSectionHandle section = tb_module_get_data(m->mod); - if (e->Variable.thread_local_model != "") { - section = tb_module_get_tls(m->mod); - String model = e->Variable.thread_local_model; - if (model == "default") { - // TODO(bill): Thread Local Storage models - } else if (model == "localdynamic") { - // TODO(bill): Thread Local Storage models - } else if (model == "initialexec") { - // TODO(bill): Thread Local Storage models - } else if (model == "localexec") { - // TODO(bill): Thread Local Storage models - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(model)); - } - } - - i64 max_objects = 0; - ExactValue value = {}; - - if (vd->values.count > 0) { - GB_ASSERT(vd->names.count == vd->values.count); - Ast *ast_value = vd->values[i]; - GB_ASSERT(ast_value->tav.mode == Addressing_Constant || - ast_value->tav.mode == Addressing_Invalid); - - value = ast_value->tav.value; - max_objects = cg_global_const_calculate_region_count(value, e->type); - } - tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); - - cg_global_const_add_region(m, value, e->type, global, 0); - - TB_Node *node = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); - cgValue global_val = cg_value(node, alloc_type_pointer(e->type)); - cg_add_entity(p->module, e, global_val); - cg_add_member(p->module, mangled_name, global_val); - } - return; - } - - TEMPORARY_ALLOCATOR_GUARD(); - - - - auto inits = array_make(temporary_allocator(), 0, vd->values.count != 0 ? vd->names.count : 0); - for (Ast *rhs : vd->values) { - cgValue init = cg_build_expr(p, rhs); - cg_append_tuple_values(p, &inits, init); - } - - - auto lvals = slice_make(temporary_allocator(), vd->names.count); - for_array(i, vd->names) { - Ast *name = vd->names[i]; - if (!is_blank_ident(name)) { - Entity *e = entity_of_node(name); - bool zero_init = vd->values.count == 0; - if (vd->names.count == vd->values.count) { - Ast *expr = unparen_expr(vd->values[i]); - if (expr->kind == Ast_CompoundLit && - inits[i].kind == cgValue_Addr) { - TB_Node *ptr = inits[i].node; - - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - String name = e->token.string; - TB_DebugType *debug_type = cg_debug_type(p->module, e->type); - tb_function_attrib_variable(p->func, ptr, nullptr, name.len, cast(char const *)name.text, debug_type); - } - - cgAddr addr = cg_addr(inits[i]); - map_set(&p->variable_map, e, addr); - continue; - } - } - - lvals[i] = cg_add_local(p, e->type, e, zero_init); - } - } - - - GB_ASSERT(vd->values.count == 0 || lvals.count == inits.count); - for_array(i, inits) { - cgAddr lval = lvals[i]; - cgValue init = inits[i]; - cg_addr_store(p, lval, init); - } -} - - -gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { - Ast *prev_stmt = p->curr_stmt; - defer (p->curr_stmt = prev_stmt); - p->curr_stmt = node; - - // TODO(bill): check if last instruction was a terminating one or not - - cg_set_debug_pos_from_node(p, node); - - u16 prev_state_flags = p->state_flags; - defer (p->state_flags = prev_state_flags); - - if (node->state_flags != 0) { - u16 in = node->state_flags; - u16 out = p->state_flags; - - if (in & StateFlag_bounds_check) { - out |= StateFlag_bounds_check; - out &= ~StateFlag_no_bounds_check; - } else if (in & StateFlag_no_bounds_check) { - out |= StateFlag_no_bounds_check; - out &= ~StateFlag_bounds_check; - } - if (in & StateFlag_no_type_assert) { - out |= StateFlag_no_type_assert; - out &= ~StateFlag_type_assert; - } else if (in & StateFlag_type_assert) { - out |= StateFlag_type_assert; - out &= ~StateFlag_no_type_assert; - } - - p->state_flags = out; - } - - switch (node->kind) { - case_ast_node(bs, EmptyStmt, node); - case_end; - - case_ast_node(us, UsingStmt, node); - case_end; - - case_ast_node(ws, WhenStmt, node); - cg_build_when_stmt(p, ws); - case_end; - - case_ast_node(bs, BlockStmt, node); - TB_Node *done = nullptr; - if (bs->label != nullptr) { - done = cg_control_region(p, "block_done"); - cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr); - tl->is_block = true; - } - - cg_scope_open(p, bs->scope); - cg_build_stmt_list(p, bs->stmts); - cg_scope_close(p, cgDeferExit_Default, nullptr); - - if (done != nullptr) { - cg_emit_goto(p, done); - tb_inst_set_control(p->func, done); - } - - if (bs->label != nullptr) { - cg_pop_target_list(p); - } - case_end; - - case_ast_node(vd, ValueDecl, node); - cg_build_mutable_value_decl(p, node); - case_end; - - case_ast_node(bs, BranchStmt, node); - TB_Node *block = nullptr; - - if (bs->label != nullptr) { - cgBranchRegions bb = cg_lookup_branch_regions(p, bs->label); - switch (bs->token.kind) { - case Token_break: block = bb.break_; break; - case Token_continue: block = bb.continue_; break; - case Token_fallthrough: - GB_PANIC("fallthrough cannot have a label"); - break; - } - } else { - for (cgTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) { - if (t->is_block) { - continue; - } - - switch (bs->token.kind) { - case Token_break: block = t->break_; break; - case Token_continue: block = t->continue_; break; - case Token_fallthrough: block = t->fallthrough_; break; - } - } - } - GB_ASSERT(block != nullptr); - - cg_emit_defer_stmts(p, cgDeferExit_Branch, block); - cg_emit_goto(p, block); - case_end; - - case_ast_node(es, ExprStmt, node); - cg_build_expr(p, es->expr); - case_end; - - case_ast_node(as, AssignStmt, node); - cg_build_assign_stmt(p, as); - case_end; - - case_ast_node(rs, ReturnStmt, node); - cg_build_return_stmt(p, rs->results); - case_end; - - case_ast_node(is, IfStmt, node); - cg_build_if_stmt(p, node); - case_end; - - case_ast_node(fs, ForStmt, node); - cg_build_for_stmt(p, node); - case_end; - - case_ast_node(rs, RangeStmt, node); - cg_build_range_stmt(p, node); - case_end; - - case_ast_node(rs, UnrollRangeStmt, node); - GB_PANIC("TODO(bill): lb_build_unroll_range_stmt"); - // cg_build_range_stmt(p, rs, rs->scope); - case_end; - - case_ast_node(fs, SwitchStmt, node); - cg_build_switch_stmt(p, node); - case_end; - - case_ast_node(ts, TypeSwitchStmt, node); - cg_build_type_switch_stmt(p, node); - case_end; - - case_ast_node(ds, DeferStmt, node); - Type *pt = base_type(p->type); - GB_ASSERT(pt->kind == Type_Proc); - if (pt->Proc.calling_convention == ProcCC_Odin) { - GB_ASSERT(p->context_stack.count != 0); - } - - cgDefer *d = array_add_and_get(&p->defer_stack); - d->kind = cgDefer_Node; - d->scope_index = p->scope_index; - d->context_stack_count = p->context_stack.count; - d->control_region = tb_inst_get_control(p->func); - GB_ASSERT(d->control_region != nullptr); - d->stmt = ds->stmt; - case_end; - - - - default: - GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); - break; - } -} - -gb_internal void cg_build_constant_value_decl(cgProcedure *p, AstValueDecl *vd) { - if (vd == nullptr || vd->is_mutable) { - return; - } - - auto *min_dep_set = &p->module->info->minimum_dependency_set; - - static i32 global_guid = 0; - - for (Ast *ident : vd->names) { - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - if (e->kind != Entity_TypeName) { - continue; - } - - bool polymorphic_struct = false; - if (e->type != nullptr && e->kind == Entity_TypeName) { - Type *bt = base_type(e->type); - if (bt->kind == Type_Struct) { - polymorphic_struct = bt->Struct.is_polymorphic; - } - } - - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { - continue; - } - - if (e->TypeName.ir_mangled_name.len != 0) { - // NOTE(bill): Already set - continue; - } - - cg_set_nested_type_name_ir_mangled_name(e, p); - } - - for_array(i, vd->names) { - Ast *ident = vd->names[i]; - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - if (e->kind != Entity_Procedure) { - continue; - } - GB_ASSERT (vd->values[i] != nullptr); - - Ast *value = unparen_expr(vd->values[i]); - if (value->kind != Ast_ProcLit) { - continue; // It's an alias - } - - DeclInfo *decl = decl_info_of_entity(e); - ast_node(pl, ProcLit, decl->proc_lit); - if (pl->body != nullptr) { - GenProcsData *gpd = e->Procedure.gen_procs; - if (gpd) { - rw_mutex_shared_lock(&gpd->mutex); - for (Entity *e : gpd->procs) { - if (!ptr_set_exists(min_dep_set, e)) { - continue; - } - DeclInfo *d = decl_info_of_entity(e); - cg_build_nested_proc(p, &d->proc_lit->ProcLit, e); - } - rw_mutex_shared_unlock(&gpd->mutex); - } else { - cg_build_nested_proc(p, pl, e); - } - } else { - - // FFI - Foreign function interace - String original_name = e->token.string; - String name = original_name; - - if (e->Procedure.is_foreign) { - GB_PANIC("cg_add_foreign_library_path"); - // cg_add_foreign_library_path(p->module, e->Procedure.foreign_library); - } - - if (e->Procedure.link_name.len > 0) { - name = e->Procedure.link_name; - } - - cgValue *prev_value = string_map_get(&p->module->members, name); - if (prev_value != nullptr) { - // NOTE(bill): Don't do mutliple declarations in the IR - return; - } - - e->Procedure.link_name = name; - - cgProcedure *nested_proc = cg_procedure_create(p->module, e); - - cgValue value = p->value; - - array_add(&p->children, nested_proc); - string_map_set(&p->module->members, name, value); - cg_add_procedure_to_queue(nested_proc); - } - } -} - - -gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts) { - for (Ast *stmt : stmts) { - switch (stmt->kind) { - case_ast_node(vd, ValueDecl, stmt); - cg_build_constant_value_decl(p, vd); - case_end; - case_ast_node(fb, ForeignBlockDecl, stmt); - ast_node(block, BlockStmt, fb->body); - cg_build_stmt_list(p, block->stmts); - case_end; - } - } - for (Ast *stmt : stmts) { - cg_build_stmt(p, stmt); - } -} - - -gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws) { - TypeAndValue tv = type_and_value_of_expr(ws->cond); - GB_ASSERT(is_type_boolean(tv.type)); - GB_ASSERT(tv.value.kind == ExactValue_Bool); - if (tv.value.value_bool) { - cg_build_stmt_list(p, ws->body->BlockStmt.stmts); - } else if (ws->else_stmt) { - switch (ws->else_stmt->kind) { - case Ast_BlockStmt: - cg_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); - break; - case Ast_WhenStmt: - cg_build_when_stmt(p, &ws->else_stmt->WhenStmt); - break; - default: - GB_PANIC("Invalid 'else' statement in 'when' statement"); - break; - } - } -} - diff --git a/src/tilde_type_info.cpp b/src/tilde_type_info.cpp deleted file mode 100644 index 96a101376..000000000 --- a/src/tilde_type_info.cpp +++ /dev/null @@ -1,985 +0,0 @@ -gb_internal void cg_global_const_type_info_ptr(cgModule *m, Type *type, TB_Global *global, i64 offset) { - GB_ASSERT(type != nullptr); - TB_Symbol *type_table_array = cg_find_symbol_from_entity(m, cg_global_type_info_data_entity); - - - i64 index_in_bytes = cast(i64)cg_type_info_index(m->info, type); - index_in_bytes *= type_size_of(t_type_info); - - void *ti_ptr_ptr = tb_global_add_region(m->mod, global, offset, build_context.ptr_size); - // NOTE(bill): define the byte offset for the pointer - cg_write_int_at_ptr(ti_ptr_ptr, index_in_bytes, t_uintptr); - - // NOTE(bill): this will add to the byte offset set previously - tb_global_add_symbol_reloc(m->mod, global, offset, type_table_array); -} - -gb_internal cgValue cg_global_type_info_data_ptr(cgProcedure *p) { - cgValue v = cg_find_value_from_entity(p->module, cg_global_type_info_data_entity); - return cg_flatten_value(p, v); -} - -gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found) { - 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 cgValue cg_type_info(cgProcedure *p, Type *type) { - GB_ASSERT(!build_context.no_rtti); - - type = default_type(type); - - isize index = cg_type_info_index(p->module->info, type); - GB_ASSERT(index >= 0); - - cgValue data = cg_global_type_info_data_ptr(p); - return cg_emit_array_epi(p, data, index); -} - - -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_RelativeMultiPointer: kind = Typeid_Relative_Multi_Pointer; 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); -} - - - - -gb_internal void cg_set_type_info_member_types(cgModule *m, TB_Global *global, isize offset, isize count, void *userdata, Type *(*type_proc)(isize index, void *userdata)) { - if (count == 0) { - return; - } - - void *data_ptr = tb_global_add_region(m->mod, global, offset+0, build_context.ptr_size); - i64 offset_in_bytes = cg_global_type_info_member_types.index * type_size_of(cg_global_type_info_member_types.elem_type); - cg_global_type_info_member_types.index += count; - - cg_write_int_at_ptr(data_ptr, offset_in_bytes, t_uintptr); - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)cg_global_type_info_member_types.global); - - for (isize i = 0; i < count; i++) { - i64 elem_size = type_size_of(cg_global_type_info_member_types.elem_type); - Type *type = type_proc(i, userdata); - i64 offset_for_elem = offset_in_bytes + i*elem_size; - cg_global_const_type_info_ptr(m, type, cg_global_type_info_member_types.global, offset_for_elem); - } - - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); -} - - -gb_internal void cg_set_type_info_member_names(cgModule *m, TB_Global *global, isize offset, isize count, void *userdata, String (*name_proc)(isize index, void *userdata)) { - if (count == 0) { - return; - } - void *data_ptr = tb_global_add_region(m->mod, global, offset+0, build_context.ptr_size); - i64 offset_in_bytes = cg_global_type_info_member_names.index * type_size_of(cg_global_type_info_member_names.elem_type); - cg_global_type_info_member_names.index += count; - - cg_write_int_at_ptr(data_ptr, offset_in_bytes, t_uintptr); - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)cg_global_type_info_member_names.global); - - for (isize i = 0; i < count; i++) { - i64 elem_size = type_size_of(cg_global_type_info_member_names.elem_type); - String name = name_proc(i, userdata); - i64 offset_for_elem = offset_in_bytes + i*elem_size; - cg_global_const_string(m, name, cg_global_type_info_member_names.elem_type, cg_global_type_info_member_names.global, offset_for_elem); - - } - - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); -} - - -gb_internal void cg_set_type_info_member_offsets(cgModule *m, TB_Global *global, isize offset, isize count, void *userdata, i64 (*offset_proc)(isize index, void *userdata)) { - if (count == 0) { - return; - } - void *data_ptr = tb_global_add_region(m->mod, global, offset+0, build_context.ptr_size); - i64 offset_in_bytes = cg_global_type_info_member_offsets.index * type_size_of(cg_global_type_info_member_offsets.elem_type); - cg_global_type_info_member_offsets.index += count; - - cg_write_int_at_ptr(data_ptr, offset_in_bytes, t_uintptr); - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)cg_global_type_info_member_offsets.global); - - for (isize i = 0; i < count; i++) { - i64 elem_size = type_size_of(cg_global_type_info_member_offsets.elem_type); - i64 the_offset = offset_proc(i, userdata); - i64 offset_for_elem = offset_in_bytes + i*elem_size; - - void *offset_ptr = tb_global_add_region(m->mod, cg_global_type_info_member_offsets.global, offset_for_elem, elem_size); - cg_write_uint_at_ptr(offset_ptr, the_offset, t_uintptr); - } - - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); -} - -gb_internal void cg_set_type_info_member_usings(cgModule *m, TB_Global *global, isize offset, isize count, void *userdata, bool (*usings_proc)(isize index, void *userdata)) { - if (count == 0) { - return; - } - void *data_ptr = tb_global_add_region(m->mod, global, offset+0, build_context.ptr_size); - i64 offset_in_bytes = cg_global_type_info_member_usings.index * type_size_of(cg_global_type_info_member_usings.elem_type); - cg_global_type_info_member_usings.index += count; - - cg_write_int_at_ptr(data_ptr, offset_in_bytes, t_uintptr); - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)cg_global_type_info_member_usings.global); - - for (isize i = 0; i < count; i++) { - i64 elem_size = type_size_of(cg_global_type_info_member_usings.elem_type); - GB_ASSERT(elem_size == 1); - bool the_usings = usings_proc(i, userdata); - i64 offset_for_elem = offset_in_bytes + i*elem_size; - - bool *usings_ptr = cast(bool *)tb_global_add_region(m->mod, cg_global_type_info_member_usings.global, offset_for_elem, 1); - *usings_ptr = the_usings; - } - - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); -} - - - -gb_internal void cg_set_type_info_member_tags(cgModule *m, TB_Global *global, isize offset, isize count, void *userdata, String (*tag_proc)(isize index, void *userdata)) { - if (count == 0) { - return; - } - void *data_ptr = tb_global_add_region(m->mod, global, offset+0, build_context.ptr_size); - i64 offset_in_bytes = cg_global_type_info_member_tags.index * type_size_of(cg_global_type_info_member_tags.elem_type); - cg_global_type_info_member_tags.index += count; - - cg_write_int_at_ptr(data_ptr, offset_in_bytes, t_uintptr); - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)cg_global_type_info_member_tags.global); - - for (isize i = 0; i < count; i++) { - i64 elem_size = type_size_of(cg_global_type_info_member_tags.elem_type); - String tag = tag_proc(i, userdata); - i64 offset_for_elem = offset_in_bytes + i*elem_size; - cg_global_const_string(m, tag, cg_global_type_info_member_tags.elem_type, cg_global_type_info_member_tags.global, offset_for_elem); - - } - - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); -} - -gb_internal void cg_set_type_info_member_enum_values(cgModule *m, TB_Global *global, isize offset, isize count, void *userdata, i64 (*value_proc)(isize index, void *userdata)) { - if (count == 0) { - return; - } - void *data_ptr = tb_global_add_region(m->mod, global, offset+0, build_context.ptr_size); - i64 offset_in_bytes = cg_global_type_info_member_enum_values.index * type_size_of(cg_global_type_info_member_enum_values.elem_type); - cg_global_type_info_member_enum_values.index += count; - - cg_write_int_at_ptr(data_ptr, offset_in_bytes, t_uintptr); - tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)cg_global_type_info_member_enum_values.global); - - for (isize i = 0; i < count; i++) { - i64 elem_size = type_size_of(cg_global_type_info_member_enum_values.elem_type); - GB_ASSERT(elem_size == 8); - i64 the_value = value_proc(i, userdata); - i64 offset_for_elem = offset_in_bytes + i*elem_size; - - void *offset_ptr = tb_global_add_region(m->mod, cg_global_type_info_member_enum_values.global, offset_for_elem, elem_size); - cg_write_uint_at_ptr(offset_ptr, the_value, cg_global_type_info_member_enum_values.elem_type); - } - - void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, count, t_int); -} - - - -gb_internal void cg_setup_type_info_data(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); - - i64 max_objects = cast(i64)max_type_info_count * cg_global_const_calculate_region_count_from_basic_type(t_type_info); - - 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_objects); - - 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_symbol(m, cg_global_type_info_data_entity, cast(TB_Symbol *)g); - 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; - isize enum_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; - case Type_Enum: - enum_count += t->Enum.fields.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*3); - cg_global_type_info_member_types = GlobalTypeInfoData{g, t, t_type_info_ptr, 0}; - } - if (count > 0 || enum_count > 0) { - char const *name = CG_TYPE_INFO_NAMES_NAME; - Type *t = alloc_type_array(t_string, (enum_count+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, (enum_count+count)*3); - cg_global_type_info_member_names = GlobalTypeInfoData{g, t, t_string, 0}; - } - if (count > 0) { - 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 = GlobalTypeInfoData{g, t, t_uintptr, 0}; - } - - if (count > 0) { - 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 = GlobalTypeInfoData{g, t, t_bool, 0}; - } - - if (count > 0) { - 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*3); - cg_global_type_info_member_tags = GlobalTypeInfoData{g, t, t_string, 0}; - } - - if (enum_count > 0) { - char const *name = CG_TYPE_INFO_ENUM_VALUES_NAME; - Type *t = alloc_type_array(t_i64, enum_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, enum_count); - cg_global_type_info_member_enum_values = GlobalTypeInfoData{g, t, t_i64, 0}; - } - } - gb_unused(info); - - - i64 global_type_info_data_entity_count = 0; - - // NOTE(bill): Set the type_table slice with the global backing array - TB_Global *type_table_slice = cast(TB_Global *)cg_find_symbol_from_entity(m, scope_lookup_current(m->info->runtime_package->scope, str_lit("type_table"))); - GB_ASSERT(type_table_slice != nullptr); - - TB_Global *type_table_array = cast(TB_Global *)cg_find_symbol_from_entity(m, cg_global_type_info_data_entity); - GB_ASSERT(type_table_array != nullptr); - - Type *type = base_type(cg_global_type_info_data_entity->type); - GB_ASSERT(is_type_array(type)); - global_type_info_data_entity_count = type->Array.count; - - tb_global_add_symbol_reloc(m->mod, type_table_slice, 0, cast(TB_Symbol *)type_table_array); - - void *len_ptr = tb_global_add_region(m->mod, type_table_slice, build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(len_ptr, type->Array.count, t_int); - - // Useful types - Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags")); - Type *t_type_info_flags = type_info_flags_entity->type; - GB_ASSERT(type_size_of(t_type_info_flags) == 4); - - auto entries_handled = slice_make(heap_allocator(), cast(isize)global_type_info_data_entity_count); - defer (gb_free(heap_allocator(), entries_handled.data)); - entries_handled[0] = true; - - - i64 type_info_size = type_size_of(t_type_info); - i64 size_offset = type_offset_of(t_type_info, 0); - i64 align_offset = type_offset_of(t_type_info, 1); - i64 flags_offset = type_offset_of(t_type_info, 2); - i64 id_offset = type_offset_of(t_type_info, 3); - i64 variant_offset = type_offset_of(t_type_info, 4); - - Type *type_info_union = base_type(t_type_info)->Struct.fields[4]->type; - GB_ASSERT(type_info_union->kind == Type_Union); - - i64 union_tag_offset = type_info_union->Union.variant_block_size; - Type *ti_union_tag_type = union_tag_type(type_info_union); - u64 union_tag_type_size = type_size_of(ti_union_tag_type); - - auto const &set_bool = [](cgModule *m, TB_Global *global, i64 offset, bool value) { - bool *ptr = cast(bool *)tb_global_add_region(m->mod, global, offset, 1); - *ptr = value; - }; - - - for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; - if (t == nullptr || t == t_invalid) { - continue; - } - - isize entry_index = cg_type_info_index(info, t, false); - if (entry_index <= 0) { - continue; - } - - if (entries_handled[entry_index]) { - continue; - } - entries_handled[entry_index] = true; - - TB_Global *global = type_table_array; - - i64 offset = entry_index * type_info_size; - - i64 size = type_size_of(t); - i64 align = type_align_of(t); - u32 flags = type_info_flags_of_type(t); - u64 id = cg_typeid_as_u64(m, t); - - void *size_ptr = tb_global_add_region(m->mod, global, offset+size_offset, build_context.int_size); - void *align_ptr = tb_global_add_region(m->mod, global, offset+align_offset, build_context.int_size); - void *flags_ptr = tb_global_add_region(m->mod, global, offset+flags_offset, 4); - void *id_ptr = tb_global_add_region(m->mod, global, offset+id_offset, build_context.ptr_size); - cg_write_int_at_ptr (size_ptr, size, t_int); - cg_write_int_at_ptr (align_ptr, align, t_int); - cg_write_int_at_ptr (flags_ptr, flags, t_u32); - cg_write_uint_at_ptr(id_ptr, id, t_typeid); - - - // add data to the offset to make it easier to deal with later on - offset += variant_offset; - - Type *tag_type = nullptr; - - switch (t->kind) { - case Type_Named: { - // Type_Info_Named :: struct { - // name: string, - // base: ^Type_Info, - // pkg: string, - // loc: Source_Code_Location, - // } - tag_type = t_type_info_named; - - i64 name_offset = type_offset_of(tag_type, 0); - String name = t->Named.type_name->token.string; - cg_global_const_string(m, name, t_string, global, offset+name_offset); - - i64 base_offset = type_offset_of(tag_type, 1); - cg_global_const_type_info_ptr(m, t->Named.base, global, offset+base_offset); - - if (t->Named.type_name->pkg) { - i64 pkg_offset = type_offset_of(tag_type, 2); - String pkg_name = t->Named.type_name->pkg->name; - cg_global_const_string(m, pkg_name, t_string, global, offset+pkg_offset); - } - - String proc_name = {}; - if (t->Named.type_name->parent_proc_decl) { - DeclInfo *decl = t->Named.type_name->parent_proc_decl; - if (decl->entity && decl->entity->kind == Entity_Procedure) { - i64 name_offset = type_offset_of(tag_type, 0); - proc_name = decl->entity->token.string; - cg_global_const_string(m, proc_name, t_string, global, offset+name_offset); - } - } - - i64 loc_offset = type_offset_of(tag_type, 3); - TokenPos pos = t->Named.type_name->token.pos; - cg_global_source_code_location_const(m, proc_name, pos, global, offset+loc_offset); - - break; - } - - case Type_Basic: - switch (t->Basic.kind) { - case Basic_bool: - case Basic_b8: - case Basic_b16: - case Basic_b32: - case Basic_b64: - tag_type = t_type_info_boolean; - break; - - 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_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: - - case Basic_int: - case Basic_uint: - case Basic_uintptr: { - tag_type = t_type_info_integer; - - bool is_signed = (t->Basic.flags & BasicFlag_Unsigned) == 0; - // NOTE(bill): This is matches the runtime layout - u8 endianness_value = 0; - if (t->Basic.flags & BasicFlag_EndianLittle) { - endianness_value = 1; - } else if (t->Basic.flags & BasicFlag_EndianBig) { - endianness_value = 2; - } - u8 *signed_ptr = cast(u8 *)tb_global_add_region(m->mod, global, offset+0, 1); - u8 *endianness_ptr = cast(u8 *)tb_global_add_region(m->mod, global, offset+1, 1); - *signed_ptr = is_signed; - *endianness_ptr = endianness_value; - break; - } - - case Basic_rune: - tag_type = t_type_info_rune; - break; - - case Basic_f16: - case Basic_f32: - case Basic_f64: - case Basic_f16le: - case Basic_f32le: - case Basic_f64le: - case Basic_f16be: - case Basic_f32be: - case Basic_f64be: - { - tag_type = t_type_info_float; - - // // NOTE(bill): This is matches the runtime layout - u8 endianness_value = 0; - if (t->Basic.flags & BasicFlag_EndianLittle) { - endianness_value = 1; - } else if (t->Basic.flags & BasicFlag_EndianBig) { - endianness_value = 2; - } - - u8 *ptr = cast(u8 *)tb_global_add_region(m->mod, global, offset+0, 1); - *ptr = endianness_value; - } - break; - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - tag_type = t_type_info_complex; - break; - - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - tag_type = t_type_info_quaternion; - break; - - case Basic_rawptr: - tag_type = t_type_info_pointer; - break; - - case Basic_string: - tag_type = t_type_info_string; - break; - - case Basic_cstring: - tag_type = t_type_info_string; - set_bool(m, global, offset+0, true); - break; - - case Basic_any: - tag_type = t_type_info_any; - break; - - case Basic_typeid: - tag_type = t_type_info_typeid; - break; - } - break; - - case Type_Pointer: - tag_type = t_type_info_pointer; - cg_global_const_type_info_ptr(m, t->Pointer.elem, global, offset+0); - break; - case Type_MultiPointer: - tag_type = t_type_info_multi_pointer; - cg_global_const_type_info_ptr(m, t->MultiPointer.elem, global, offset+0); - break; - case Type_SoaPointer: - tag_type = t_type_info_soa_pointer; - cg_global_const_type_info_ptr(m, t->SoaPointer.elem, global, offset+0); - break; - - case Type_Array: - { - tag_type = t_type_info_array; - - cg_global_const_type_info_ptr(m, t->Array.elem, global, offset+0); - void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size); - void *count_ptr = tb_global_add_region(m->mod, global, offset+2*build_context.int_size, build_context.int_size); - - cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Array.elem), t_int); - cg_write_int_at_ptr(count_ptr, t->Array.count, t_int); - } - break; - - case Type_EnumeratedArray: - { - tag_type = t_type_info_enumerated_array; - - i64 elem_offset = type_offset_of(tag_type, 0); - i64 index_offset = type_offset_of(tag_type, 1); - i64 elem_size_offset = type_offset_of(tag_type, 2); - i64 count_offset = type_offset_of(tag_type, 3); - i64 min_value_offset = type_offset_of(tag_type, 4); - i64 max_value_offset = type_offset_of(tag_type, 5); - i64 is_sparse_offset = type_offset_of(tag_type, 6); - - cg_global_const_type_info_ptr(m, t->EnumeratedArray.elem, global, offset+elem_offset); - cg_global_const_type_info_ptr(m, t->EnumeratedArray.index, global, offset+index_offset); - - void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+elem_size_offset, build_context.int_size); - void *count_ptr = tb_global_add_region(m->mod, global, offset+count_offset, build_context.int_size); - - void *min_value_ptr = tb_global_add_region(m->mod, global, offset+min_value_offset, type_size_of(t_type_info_enum_value)); - void *max_value_ptr = tb_global_add_region(m->mod, global, offset+max_value_offset, type_size_of(t_type_info_enum_value)); - - cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->EnumeratedArray.elem), t_int); - cg_write_int_at_ptr(count_ptr, t->EnumeratedArray.count, t_int); - - cg_write_int_at_ptr(min_value_ptr, exact_value_to_i64(*t->EnumeratedArray.min_value), t_type_info_enum_value); - cg_write_int_at_ptr(max_value_ptr, exact_value_to_i64(*t->EnumeratedArray.max_value), t_type_info_enum_value); - set_bool(m, global, offset+is_sparse_offset, t->EnumeratedArray.is_sparse); - } - break; - - case Type_DynamicArray: - { - tag_type = t_type_info_dynamic_array; - - cg_global_const_type_info_ptr(m, t->DynamicArray.elem, global, offset+0); - void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->DynamicArray.elem), t_int); - } - break; - case Type_Slice: - { - tag_type = t_type_info_slice; - - cg_global_const_type_info_ptr(m, t->Slice.elem, global, offset+0); - void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size); - cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Slice.elem), t_int); - } - break; - - case Type_Proc: - { - tag_type = t_type_info_procedure; - - i64 params_offset = type_offset_of(tag_type, 0); - i64 results_offset = type_offset_of(tag_type, 1); - i64 variadic_offset = type_offset_of(tag_type, 2); - i64 convention_offset = type_offset_of(tag_type, 3); - - if (t->Proc.params) { - cg_global_const_type_info_ptr(m, t->Proc.params, global, offset+params_offset); - } - if (t->Proc.results) { - cg_global_const_type_info_ptr(m, t->Proc.results, global, offset+results_offset); - } - - set_bool(m, global, offset+variadic_offset, t->Proc.variadic); - - u8 *convention_ptr = cast(u8 *)tb_global_add_region(m->mod, global, offset+convention_offset, 1); - *convention_ptr = cast(u8)t->Proc.calling_convention; - } - break; - - case Type_Tuple: - { - tag_type = t_type_info_parameters; - - i64 types_offset = type_offset_of(tag_type, 0); - i64 names_offset = type_offset_of(tag_type, 1); - - i64 count = t->Tuple.variables.count; - - cg_set_type_info_member_types(m, global, offset+types_offset, count, t, [](isize i, void *userdata) -> Type * { - Type *t = cast(Type *)userdata; - return t->Tuple.variables[i]->type; - }); - - cg_set_type_info_member_names(m, global, offset+names_offset, count, t, [](isize i, void *userdata) -> String { - Type *t = cast(Type *)userdata; - return t->Tuple.variables[i]->token.string; - }); - } - break; - - case Type_Enum: - { - tag_type = t_type_info_enum; - - i64 base_offset = type_offset_of(tag_type, 0); - i64 names_offset = type_offset_of(tag_type, 1); - i64 values_offset = type_offset_of(tag_type, 2); - - cg_global_const_type_info_ptr(m, t->Enum.base_type, global, offset+base_offset); - - i64 count = t->Enum.fields.count; - - cg_set_type_info_member_names(m, global, offset+names_offset, count, t, [](isize i, void *userdata) -> String { - Type *t = cast(Type *)userdata; - return t->Enum.fields[i]->token.string; - }); - - cg_set_type_info_member_enum_values(m, global, offset+values_offset, count, t, [](isize i, void *userdata) -> i64 { - Type *t = cast(Type *)userdata; - Entity *e = t->Enum.fields[i]; - GB_ASSERT(e->kind == Entity_Constant); - return exact_value_to_i64(e->Constant.value); - }); - } - break; - case Type_Struct: - { - tag_type = t_type_info_struct; - - i64 types_offset = type_offset_of(tag_type, 0); - i64 names_offset = type_offset_of(tag_type, 1); - i64 offsets_offset = type_offset_of(tag_type, 2); - i64 usings_offset = type_offset_of(tag_type, 3); - i64 tags_offset = type_offset_of(tag_type, 4); - - i64 is_packed_offset = type_offset_of(tag_type, 5); - i64 is_raw_union_offset = type_offset_of(tag_type, 6); - i64 custom_align_offset = type_offset_of(tag_type, 7); - - i64 equal_offset = type_offset_of(tag_type, 8); - - i64 soa_kind_offset = type_offset_of(tag_type, 9); - i64 soa_base_type_offset = type_offset_of(tag_type, 10); - i64 soa_len_offset = type_offset_of(tag_type, 11); - - // TODO(bill): equal proc stuff - gb_unused(equal_offset); - - i64 count = t->Struct.fields.count; - - cg_set_type_info_member_types(m, global, offset+types_offset, count, t, [](isize i, void *userdata) -> Type * { - Type *t = cast(Type *)userdata; - return t->Struct.fields[i]->type; - }); - - cg_set_type_info_member_names(m, global, offset+names_offset, count, t, [](isize i, void *userdata) -> String { - Type *t = cast(Type *)userdata; - return t->Struct.fields[i]->token.string; - }); - - cg_set_type_info_member_offsets(m, global, offset+offsets_offset, count, t, [](isize i, void *userdata) -> i64 { - Type *t = cast(Type *)userdata; - return t->Struct.offsets[i]; - }); - - cg_set_type_info_member_usings(m, global, offset+usings_offset, count, t, [](isize i, void *userdata) -> bool { - Type *t = cast(Type *)userdata; - return (t->Struct.fields[i]->flags & EntityFlag_Using) != 0; - }); - - cg_set_type_info_member_tags(m, global, offset+tags_offset, count, t, [](isize i, void *userdata) -> String { - Type *t = cast(Type *)userdata; - return t->Struct.tags[i]; - }); - - - set_bool(m, global, offset+is_packed_offset, t->Struct.is_packed); - set_bool(m, global, offset+is_raw_union_offset, t->Struct.is_raw_union); - set_bool(m, global, offset+custom_align_offset, t->Struct.custom_align != 0); - - if (t->Struct.soa_kind != StructSoa_None) { - u8 *kind_ptr = cast(u8 *)tb_global_add_region(m->mod, global, offset+soa_kind_offset, 1); - *kind_ptr = cast(u8)t->Struct.soa_kind; - - cg_global_const_type_info_ptr(m, t->Struct.soa_elem, global, offset+soa_base_type_offset); - - void *soa_len_ptr = tb_global_add_region(m->mod, global, offset+soa_len_offset, build_context.int_size); - cg_write_int_at_ptr(soa_len_ptr, t->Struct.soa_count, t_int); - } - } - break; - case Type_Union: - { - tag_type = t_type_info_union; - - i64 variants_offset = type_offset_of(tag_type, 0); - i64 tag_offset_offset = type_offset_of(tag_type, 1); - i64 tag_type_offset = type_offset_of(tag_type, 2); - - i64 equal_offset = type_offset_of(tag_type, 3); - - i64 custom_align_offset = type_offset_of(tag_type, 4); - i64 no_nil_offset = type_offset_of(tag_type, 5); - i64 shared_nil_offset = type_offset_of(tag_type, 6); - - // TODO(bill): equal procs - gb_unused(equal_offset); - - i64 count = t->Union.variants.count; - - cg_set_type_info_member_types(m, global, offset+variants_offset, count, t, [](isize i, void *userdata) -> Type * { - Type *t = cast(Type *)userdata; - return t->Union.variants[i]; - }); - - void *tag_offset_ptr = tb_global_add_region(m->mod, global, offset+tag_offset_offset, build_context.ptr_size); - cg_write_uint_at_ptr(tag_offset_ptr, t->Union.variant_block_size, t_uintptr); - - cg_global_const_type_info_ptr(m, union_tag_type(t), global, offset+tag_type_offset); - - set_bool(m, global, offset+custom_align_offset, t->Union.custom_align != 0); - set_bool(m, global, offset+no_nil_offset, t->Union.kind == UnionType_no_nil); - set_bool(m, global, offset+shared_nil_offset, t->Union.kind == UnionType_shared_nil); - } - break; - case Type_Map: - { - tag_type = t_type_info_map; - - i64 key_offset = type_offset_of(tag_type, 0); - i64 value_offset = type_offset_of(tag_type, 1); - i64 map_info_offset = type_offset_of(tag_type, 2); - - // TODO(bill): map info - gb_unused(map_info_offset); - - cg_global_const_type_info_ptr(m, t->Map.key, global, offset+key_offset); - cg_global_const_type_info_ptr(m, t->Map.value, global, offset+value_offset); - - } - break; - case Type_BitSet: - { - tag_type = t_type_info_bit_set; - - i64 elem_offset = type_offset_of(tag_type, 0); - i64 underlying_offset = type_offset_of(tag_type, 1); - i64 lower_offset = type_offset_of(tag_type, 2); - i64 upper_offset = type_offset_of(tag_type, 3); - - cg_global_const_type_info_ptr(m, t->BitSet.elem, global, offset+elem_offset); - if (t->BitSet.underlying) { - cg_global_const_type_info_ptr(m, t->BitSet.underlying, global, offset+underlying_offset); - } - - void *lower_ptr = tb_global_add_region(m->mod, global, offset+lower_offset, 8); - void *upper_ptr = tb_global_add_region(m->mod, global, offset+upper_offset, 8); - - cg_write_int_at_ptr(lower_ptr, t->BitSet.lower, t_i64); - cg_write_int_at_ptr(upper_ptr, t->BitSet.upper, t_i64); - } - break; - case Type_SimdVector: - { - tag_type = t_type_info_simd_vector; - - i64 elem_offset = type_offset_of(tag_type, 0); - i64 elem_size_offset = type_offset_of(tag_type, 1); - i64 count_offset = type_offset_of(tag_type, 2); - - cg_global_const_type_info_ptr(m, t->SimdVector.elem, global, offset+elem_offset); - - void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+elem_size_offset, build_context.int_size); - void *count_ptr = tb_global_add_region(m->mod, global, offset+count_offset, build_context.int_size); - - cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->SimdVector.elem), t_int); - cg_write_int_at_ptr(count_ptr, t->SimdVector.count, t_int); - } - break; - - case Type_RelativePointer: - { - tag_type = t_type_info_relative_pointer; - - i64 pointer_offset = type_offset_of(tag_type, 0); - i64 base_integer_offset = type_offset_of(tag_type, 1); - - cg_global_const_type_info_ptr(m, t->RelativePointer.pointer_type, global, offset+pointer_offset); - cg_global_const_type_info_ptr(m, t->RelativePointer.base_integer, global, offset+base_integer_offset); - } - break; - case Type_RelativeMultiPointer: - { - tag_type = t_type_info_relative_multi_pointer; - - i64 pointer_offset = type_offset_of(tag_type, 0); - i64 base_integer_offset = type_offset_of(tag_type, 1); - - cg_global_const_type_info_ptr(m, t->RelativePointer.pointer_type, global, offset+pointer_offset); - cg_global_const_type_info_ptr(m, t->RelativePointer.base_integer, global, offset+base_integer_offset); - } - break; - case Type_Matrix: - { - tag_type = t_type_info_matrix; - - i64 elem_offset = type_offset_of(tag_type, 0); - i64 elem_size_offset = type_offset_of(tag_type, 1); - i64 elem_stride_offset = type_offset_of(tag_type, 2); - i64 row_count_offset = type_offset_of(tag_type, 3); - i64 column_count_offset = type_offset_of(tag_type, 4); - - cg_global_const_type_info_ptr(m, t->Matrix.elem, global, offset+elem_offset); - - void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+elem_size_offset, build_context.int_size); - void *elem_stride_ptr = tb_global_add_region(m->mod, global, offset+elem_stride_offset, build_context.int_size); - void *row_count_ptr = tb_global_add_region(m->mod, global, offset+row_count_offset, build_context.int_size); - void *column_count_ptr = tb_global_add_region(m->mod, global, offset+column_count_offset, build_context.int_size); - - cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Matrix.elem), t_int); - cg_write_int_at_ptr(elem_stride_ptr, matrix_type_stride_in_elems(t), t_int); - cg_write_int_at_ptr(row_count_ptr, t->Matrix.row_count, t_int); - cg_write_int_at_ptr(column_count_ptr, t->Matrix.column_count, t_int); - - } - break; - } - - if (tag_type != nullptr) { - i64 union_index = union_variant_index(type_info_union, tag_type); - GB_ASSERT(union_index != 0); - void *tag_ptr = tb_global_add_region(m->mod, global, offset+union_tag_offset, union_tag_type_size); - cg_write_int_at_ptr(tag_ptr, union_index, ti_union_tag_type); - } - - } -} \ No newline at end of file