mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-06 06:38:20 +00:00
Merge pull request #6483 from odin-lang/bill/remove-tilde
Remove Tilde Backend
This commit is contained in:
10
build.bat
10
build.bat
@@ -107,16 +107,6 @@ set libs= ^
|
||||
set odin_res=misc\odin.res
|
||||
set odin_rc=misc\odin.rc
|
||||
|
||||
rem DO NOT TOUCH!
|
||||
rem THIS TILDE STUFF IS FOR DEVELOPMENT ONLY!
|
||||
set tilde_backend=0
|
||||
if %tilde_backend% EQU 1 (
|
||||
set libs=%libs% src\tilde\tb.lib
|
||||
set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND
|
||||
)
|
||||
rem DO NOT TOUCH!
|
||||
|
||||
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console -MANIFEST:EMBED
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
|
||||
@@ -607,8 +607,6 @@ struct BuildContext {
|
||||
|
||||
isize max_error_count;
|
||||
|
||||
bool tilde_backend;
|
||||
|
||||
|
||||
u32 cmd_doc_flags;
|
||||
Array<String> extra_packages;
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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;
|
||||
|
||||
50
src/main.cpp
50
src/main.cpp
@@ -76,16 +76,6 @@ gb_global Timings global_timings = {0};
|
||||
#include "linker.cpp"
|
||||
#include "bundle_command.cpp"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND)
|
||||
#define ALLOW_TILDE 1
|
||||
#else
|
||||
#define ALLOW_TILDE 0
|
||||
#endif
|
||||
|
||||
#if ALLOW_TILDE
|
||||
#include "tilde.cpp"
|
||||
#endif
|
||||
|
||||
#include "llvm_backend.cpp"
|
||||
|
||||
#include "bug_report.cpp"
|
||||
@@ -414,8 +404,6 @@ enum BuildFlagKind {
|
||||
BuildFlag_InternalLLVMMem2Reg,
|
||||
BuildFlag_InternalEnableRVO,
|
||||
|
||||
BuildFlag_Tilde,
|
||||
|
||||
BuildFlag_Sanitize,
|
||||
BuildFlag_LTO,
|
||||
|
||||
@@ -647,9 +635,6 @@ gb_internal bool parse_build_flags(Array<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)) {
|
||||
|
||||
842
src/tilde.cpp
842
src/tilde.cpp
@@ -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
|
||||
386
src/tilde.hpp
386
src/tilde.hpp
@@ -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 ¶m_value, TokenPos const &pos);
|
||||
|
||||
gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value);
|
||||
gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x);
|
||||
gb_internal cgValue cg_builtin_map_info(cgProcedure *p, Type *map_type);
|
||||
gb_internal cgValue cg_builtin_map_cell_info(cgProcedure *p, Type *type);
|
||||
gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos);
|
||||
gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Ast *node);
|
||||
|
||||
|
||||
gb_internal cgValue cg_internal_dynamic_map_get_ptr(cgProcedure *p, cgValue const &map_ptr, cgValue const &key);
|
||||
gb_internal void cg_internal_dynamic_map_set(cgProcedure *p, cgValue const &map_ptr, Type *map_type,
|
||||
cgValue const &map_key, cgValue const &map_value, Ast *node);
|
||||
1309
src/tilde/tb.h
1309
src/tilde/tb.h
File diff suppressed because it is too large
Load Diff
BIN
src/tilde/tb.lib
BIN
src/tilde/tb.lib
Binary file not shown.
@@ -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);
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
1049
src/tilde_const.cpp
1049
src/tilde_const.cpp
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
3961
src/tilde_expr.cpp
3961
src/tilde_expr.cpp
File diff suppressed because it is too large
Load Diff
1327
src/tilde_proc.cpp
1327
src/tilde_proc.cpp
File diff suppressed because it is too large
Load Diff
2889
src/tilde_stmt.cpp
2889
src/tilde_stmt.cpp
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user