Merge pull request #6483 from odin-lang/bill/remove-tilde

Remove Tilde Backend
This commit is contained in:
gingerBill
2026-03-26 12:07:25 +00:00
committed by GitHub
21 changed files with 3 additions and 14714 deletions

View File

@@ -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

View File

@@ -607,8 +607,6 @@ struct BuildContext {
isize max_error_count;
bool tilde_backend;
u32 cmd_doc_flags;
Array<String> extra_packages;

View File

@@ -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"),

View File

@@ -184,14 +184,8 @@ struct Entity {
Entity * aliased_of;
union {
std::atomic<struct lbModule *> code_gen_module;
struct cgModule *cg_module;
};
union {
std::atomic<struct lbProcedure *> code_gen_procedure;
struct cgProcedure *cg_procedure;
};
std::atomic<struct lbModule *> code_gen_module;
std::atomic<struct lbProcedure *> code_gen_procedure;
u64 order_in_src;
String deprecated_message;

View File

@@ -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<String> 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<String> 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<lbGenerator>();
if (!lb_init_generator(gen, checker)) {

View File

@@ -1,842 +0,0 @@
#include "tilde.hpp"
gb_global Slice<TB_Arena> 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<TB_Arena>(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<cgValue> 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<cgValue>(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<cgGlobalVariable> *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<cgGlobalVariable>(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<cgGlobalVariable> *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<u32> 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<cgGlobalVariable> 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<cgProcedure *> 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

View File

@@ -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<cgValue> 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<i32> 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<cgValue> 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<cgProcedure *> 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<cgDefer> defer_stack;
Array<Scope *> scope_stack;
Array<cgContextData> context_stack;
Array<cgControlRegion> control_regions;
Array<cgBranchRegions> branch_regions;
Scope *curr_scope;
i32 scope_index;
bool in_multi_assignment;
isize split_returns_index;
bool return_by_ptr;
PtrMap<Entity *, cgAddr> variable_map;
PtrMap<Entity *, cgAddr> soa_values_map;
};
struct cgModule {
TB_Module * mod;
Checker * checker;
CheckerInfo *info;
LinkerData * linker_data;
bool do_threading;
Array<cgProcedure *> single_threaded_procedure_queue;
RwMutex values_mutex;
PtrMap<Entity *, cgValue> values;
PtrMap<Entity *, TB_Symbol *> symbols;
StringMap<cgValue> members;
StringMap<cgProcedure *> procedures;
PtrMap<TB_Function *, Entity *> procedure_values;
RecursiveMutex debug_type_mutex;
PtrMap<Type *, TB_DebugType *> debug_type_map;
PtrMap<Type *, TB_DebugType *> proc_debug_type_map; // not pointer to
RecursiveMutex proc_proto_mutex;
PtrMap<Type *, TB_FunctionPrototype *> proc_proto_map;
BlockingMutex anonymous_proc_lits_mutex;
PtrMap<Ast *, cgProcedure *> anonymous_proc_lits_map;
RecursiveMutex generated_procs_mutex;
PtrMap<Type *, cgProcedure *> equal_procs;
PtrMap<Type *, cgProcedure *> hasher_procs;
PtrMap<Type *, cgProcedure *> map_get_procs;
PtrMap<Type *, cgProcedure *> map_set_procs;
RecursiveMutex map_info_mutex;
PtrMap<Type *, TB_Symbol *> map_info_map;
PtrMap<Type *, TB_Symbol *> map_cell_info_map;
// NOTE(bill): no need to protect this with a mutex
PtrMap<uintptr, TB_SourceFile *> file_id_map; // Key: AstFile.id (i32 cast to uintptr)
std::atomic<u32> nested_type_name_guid;
std::atomic<u32> 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<Ast *> 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<Ast *> const &return_results);
gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice<cgValue> 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<cgValue> const &args);
gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice<cgValue> 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<cgValue> *dst_values, cgValue src_value);
gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const &param_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);

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,79 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdbool.h>
#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);

View File

@@ -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 <common.h>
#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

View File

@@ -1,170 +0,0 @@
#ifndef TB_ELF_H
#define TB_ELF_H
#include <stdint.h>
#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 */

View File

@@ -1,132 +0,0 @@
// This handles the generalized executable/object format parsing stuff
#ifndef TB_OBJECT_H
#define TB_OBJECT_H
#include <stdint.h>
#include <stddef.h>
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

View File

@@ -1,105 +0,0 @@
#ifndef TB_X64_H
#define TB_X64_H
#include <stdint.h>
#include <stdbool.h>
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 */

View File

@@ -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<cgValue>(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 {};
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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<bool>(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);
}
}
}