mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
Fix minimal dependency generation for polymorphic structs (related to issue #121)
This commit is contained in:
+4
-2
@@ -4867,8 +4867,10 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
AstNode *s = ident->SelectorExpr.selector;
|
AstNode *s = ident->SelectorExpr.selector;
|
||||||
ident = s;
|
ident = s;
|
||||||
}
|
}
|
||||||
add_entity_use(c, ident, entity_of_ident(&c->info, ident));
|
Type *ot = operand->type; GB_ASSERT(ot->kind == Type_Named);
|
||||||
add_type_and_value(&c->info, call, Addressing_Type, operand->type, empty_exact_value);
|
Entity *e = ot->Named.type_name;
|
||||||
|
add_entity_use(c, ident, e);
|
||||||
|
add_type_and_value(&c->info, call, Addressing_Type, ot, empty_exact_value);
|
||||||
} else {
|
} else {
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
operand->type = t_invalid;
|
operand->type = t_invalid;
|
||||||
|
|||||||
+11
-3
@@ -818,8 +818,8 @@ void add_declaration_dependency(Checker *c, Entity *e) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (c->context.decl != nullptr) {
|
if (c->context.decl != nullptr) {
|
||||||
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
// DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||||
if (decl) add_dependency(c->context.decl, e);
|
add_dependency(c->context.decl, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1213,6 +1213,9 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
|
|||||||
if (identifier->kind != AstNode_Ident) {
|
if (identifier->kind != AstNode_Ident) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (entity->identifier == nullptr) {
|
||||||
|
entity->identifier = identifier;
|
||||||
|
}
|
||||||
HashKey key = hash_node(identifier);
|
HashKey key = hash_node(identifier);
|
||||||
map_set(&c->info.uses, key, entity);
|
map_set(&c->info.uses, key, entity);
|
||||||
add_declaration_dependency(c, entity); // TODO(bill): Should this be here?
|
add_declaration_dependency(c, entity); // TODO(bill): Should this be here?
|
||||||
@@ -1435,10 +1438,14 @@ void add_dependency_to_map(PtrSet<Entity *> *map, CheckerInfo *info, Entity *ent
|
|||||||
if (entity == nullptr) {
|
if (entity == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String name = entity->token.string;
|
||||||
|
|
||||||
if (entity->type != nullptr &&
|
if (entity->type != nullptr &&
|
||||||
is_type_polymorphic(entity->type)) {
|
is_type_polymorphic(entity->type)) {
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(info, entity);
|
DeclInfo *decl = decl_info_of_entity(info, entity);
|
||||||
if (decl->gen_proc_type == nullptr) {
|
if (decl != nullptr && decl->gen_proc_type == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1447,6 +1454,7 @@ void add_dependency_to_map(PtrSet<Entity *> *map, CheckerInfo *info, Entity *ent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ptr_set_add(map, entity);
|
ptr_set_add(map, entity);
|
||||||
DeclInfo *decl = decl_info_of_entity(info, entity);
|
DeclInfo *decl = decl_info_of_entity(info, entity);
|
||||||
if (decl != nullptr) {
|
if (decl != nullptr) {
|
||||||
|
|||||||
+470
-466
@@ -3752,13 +3752,18 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
|
|||||||
auto found = map_get(&m->info->gen_types, hash_pointer(e->type));
|
auto found = map_get(&m->info->gen_types, hash_pointer(e->type));
|
||||||
if (found != nullptr) {
|
if (found != nullptr) {
|
||||||
for_array(i, *found) {
|
for_array(i, *found) {
|
||||||
Entity *e = (*found)[i];
|
Entity *sub = (*found)[i];
|
||||||
ir_mangle_add_sub_type_name(m, e, name);
|
// gb_printf_err("--> %.*s\n", LIT(sub->token.string));
|
||||||
|
if (ptr_set_exists(&m->min_dep_set, sub)) {
|
||||||
|
ir_mangle_add_sub_type_name(m, sub, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ptr_set_exists(&m->min_dep_set, e)) return;
|
||||||
|
|
||||||
irValue *t = ir_value_type_name(m->allocator, name, e->type);
|
irValue *t = ir_value_type_name(m->allocator, name, e->type);
|
||||||
ir_module_add_value(m, e, t);
|
ir_module_add_value(m, e, t);
|
||||||
map_set(&m->members, hash_string(name), t);
|
map_set(&m->members, hash_string(name), t);
|
||||||
@@ -5890,7 +5895,6 @@ void ir_build_poly_proc(irProcedure *proc, AstNodeProcLit *pd, Entity *e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) {
|
void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) {
|
||||||
if (vd == nullptr || vd->is_mutable) {
|
if (vd == nullptr || vd->is_mutable) {
|
||||||
return;
|
return;
|
||||||
@@ -5909,8 +5913,6 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String entity_name = e->token.string;
|
|
||||||
|
|
||||||
if (e->kind == Entity_TypeName) {
|
if (e->kind == Entity_TypeName) {
|
||||||
bool polymorphic_struct = false;
|
bool polymorphic_struct = false;
|
||||||
if (e->type != nullptr && e->kind == Entity_TypeName) {
|
if (e->type != nullptr && e->kind == Entity_TypeName) {
|
||||||
@@ -5926,19 +5928,18 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) {
|
|||||||
|
|
||||||
// NOTE(bill): Generate a new name
|
// NOTE(bill): Generate a new name
|
||||||
// parent_proc.name-guid
|
// parent_proc.name-guid
|
||||||
String ts_name = entity_name;
|
String ts_name = e->token.string;
|
||||||
|
|
||||||
|
irModule *m = proc->module;
|
||||||
isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
|
isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
|
||||||
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
|
u8 *name_text = gb_alloc_array(m->allocator, u8, name_len);
|
||||||
i32 guid = cast(i32)proc->module->members.entries.count;
|
i32 guid = cast(i32)m->members.entries.count;
|
||||||
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
|
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
|
||||||
String name = make_string(name_text, name_len-1);
|
String name = make_string(name_text, name_len-1);
|
||||||
|
|
||||||
irValue *value = ir_value_type_name(proc->module->allocator,
|
irValue *value = ir_value_type_name(m->allocator, name, e->type);
|
||||||
name, e->type);
|
map_set(&m->entity_names, hash_entity(e), name);
|
||||||
map_set(&proc->module->entity_names, hash_entity(e), name);
|
ir_gen_global_type_name(m, e, name);
|
||||||
ir_gen_global_type_name(proc->module, e, name);
|
|
||||||
|
|
||||||
} else if (e->kind == Entity_Procedure) {
|
} else if (e->kind == Entity_Procedure) {
|
||||||
CheckerInfo *info = proc->module->info;
|
CheckerInfo *info = proc->module->info;
|
||||||
DeclInfo *decl = decl_info_of_entity(info, e);
|
DeclInfo *decl = decl_info_of_entity(info, e);
|
||||||
@@ -7655,460 +7656,10 @@ void ir_add_foreign_library_path(irModule *m, Entity *e) {
|
|||||||
array_add(&m->foreign_library_paths, library_path);
|
array_add(&m->foreign_library_paths, library_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info data
|
||||||
void ir_gen_tree(irGen *s) {
|
irModule *m = proc->module;
|
||||||
irModule *m = &s->module;
|
|
||||||
CheckerInfo *info = m->info;
|
|
||||||
gbAllocator a = m->allocator;
|
gbAllocator a = m->allocator;
|
||||||
|
CheckerInfo *info = m->info;
|
||||||
if (v_zero == nullptr) {
|
|
||||||
v_zero = ir_const_int (m->allocator, 0);
|
|
||||||
v_one = ir_const_int (m->allocator, 1);
|
|
||||||
v_zero32 = ir_const_i32 (m->allocator, 0);
|
|
||||||
v_one32 = ir_const_i32 (m->allocator, 1);
|
|
||||||
v_two32 = ir_const_i32 (m->allocator, 2);
|
|
||||||
v_false = ir_const_bool(m->allocator, false);
|
|
||||||
v_true = ir_const_bool(m->allocator, true);
|
|
||||||
v_raw_nil = ir_value_constant(m->allocator, t_rawptr, exact_value_pointer(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
isize global_variable_max_count = 0;
|
|
||||||
Entity *entry_point = info->entry_point;
|
|
||||||
bool has_dll_main = false;
|
|
||||||
bool has_win_main = false;
|
|
||||||
|
|
||||||
for_array(i, info->entities.entries) {
|
|
||||||
auto *entry = &info->entities.entries[i];
|
|
||||||
Entity *e = cast(Entity *)entry->key.ptr;
|
|
||||||
String name = e->token.string;
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
global_variable_max_count++;
|
|
||||||
} else if (e->kind == Entity_Procedure && !e->scope->is_global) {
|
|
||||||
if (e->scope->is_init && name == "main") {
|
|
||||||
GB_ASSERT(e == entry_point);
|
|
||||||
// entry_point = e;
|
|
||||||
}
|
|
||||||
if ((e->Procedure.tags & ProcTag_export) != 0 ||
|
|
||||||
(e->Procedure.link_name.len > 0) ||
|
|
||||||
(e->scope->is_file && e->Procedure.link_name.len > 0)) {
|
|
||||||
if (!has_dll_main && name == "DllMain") {
|
|
||||||
has_dll_main = true;
|
|
||||||
} else if (!has_win_main && name == "WinMain") {
|
|
||||||
has_win_main = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Add global default context
|
|
||||||
m->global_default_context = ir_add_global_generated(m, t_context, nullptr);
|
|
||||||
}
|
|
||||||
struct irGlobalVariable {
|
|
||||||
irValue *var, *init;
|
|
||||||
DeclInfo *decl;
|
|
||||||
};
|
|
||||||
Array<irGlobalVariable> global_variables;
|
|
||||||
array_init(&global_variables, m->tmp_allocator, global_variable_max_count);
|
|
||||||
|
|
||||||
m->entry_point_entity = entry_point;
|
|
||||||
m->min_dep_set = info->minimum_dependency_set;
|
|
||||||
|
|
||||||
for_array(i, info->variable_init_order) {
|
|
||||||
DeclInfo *d = info->variable_init_order[i];
|
|
||||||
|
|
||||||
for (isize j = 0; j < d->entity_count; j++) {
|
|
||||||
Entity *e = d->entities[j];
|
|
||||||
|
|
||||||
if (!e->scope->is_file) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ptr_set_exists(&m->min_dep_set, e)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DeclInfo *decl = decl_info_of_entity(info, e);
|
|
||||||
if (decl == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = e->token.string;
|
|
||||||
String original_name = name;
|
|
||||||
if (!e->scope->is_global) {
|
|
||||||
name = ir_mangle_name(s, e->token.pos.file, e);
|
|
||||||
}
|
|
||||||
ir_add_entity_name(m, e, name);
|
|
||||||
|
|
||||||
irValue *g = ir_value_global(a, e, nullptr);
|
|
||||||
g->Global.name = name;
|
|
||||||
g->Global.is_thread_local = e->Variable.is_thread_local;
|
|
||||||
|
|
||||||
|
|
||||||
irGlobalVariable var = {};
|
|
||||||
var.var = g;
|
|
||||||
var.decl = decl;
|
|
||||||
|
|
||||||
if (e->type->kind == Type_Struct && e->type->Struct.has_proc_default_values) {
|
|
||||||
for_array(i, e->type->Struct.fields) {
|
|
||||||
Entity *f = e->type->Struct.fields[i];
|
|
||||||
if (f->kind == Entity_Variable && f->Variable.default_value.kind == ExactValue_Procedure) {
|
|
||||||
AstNode *expr = f->Variable.default_value.value_procedure;
|
|
||||||
GB_ASSERT(expr != nullptr);
|
|
||||||
if (expr->kind == AstNode_ProcLit) {
|
|
||||||
ir_gen_anonymous_proc_lit(m, e->token.string, expr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decl->init_expr != nullptr) {
|
|
||||||
if (is_type_any(e->type)) {
|
|
||||||
} else {
|
|
||||||
TypeAndValue tav = type_and_value_of_expr(info, decl->init_expr);
|
|
||||||
if (tav.mode != Addressing_Invalid) {
|
|
||||||
if (tav.value.kind != ExactValue_Invalid) {
|
|
||||||
ExactValue v = tav.value;
|
|
||||||
g->Global.value = ir_add_module_constant(m, tav.type, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (g->Global.value == nullptr) {
|
|
||||||
array_add(&global_variables, var);
|
|
||||||
// }
|
|
||||||
|
|
||||||
ir_module_add_value(m, e, g);
|
|
||||||
map_set(&m->members, hash_string(name), g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, info->entities.entries) {
|
|
||||||
auto *entry = &info->entities.entries[i];
|
|
||||||
Entity *e = cast(Entity *)entry->key.ptr;
|
|
||||||
String name = e->token.string;
|
|
||||||
DeclInfo *decl = entry->value;
|
|
||||||
Scope *scope = e->scope;
|
|
||||||
|
|
||||||
if (!scope->is_file) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
// NOTE(bill): Handled above as it requires a specific load order
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool polymorphic_struct = false;
|
|
||||||
if (e->type != nullptr && e->kind == Entity_TypeName) {
|
|
||||||
Type *bt = base_type(e->type);
|
|
||||||
if (bt->kind == Type_Struct) {
|
|
||||||
polymorphic_struct = bt->Struct.is_polymorphic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!polymorphic_struct && !ptr_set_exists(&m->min_dep_set, e)) {
|
|
||||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String original_name = name;
|
|
||||||
|
|
||||||
if (!scope->is_global || polymorphic_struct || is_type_polymorphic(e->type)) {
|
|
||||||
if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
|
|
||||||
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
|
|
||||||
// Handle later
|
|
||||||
// } else if (scope->is_init && e->kind == Entity_Procedure && name == "main") {
|
|
||||||
} else {
|
|
||||||
name = ir_mangle_name(s, e->token.pos.file, e);
|
|
||||||
}
|
|
||||||
} else if (check_is_entity_overloaded(e)) {
|
|
||||||
name = ir_mangle_name(s, e->token.pos.file, e);
|
|
||||||
}
|
|
||||||
ir_add_entity_name(m, e, name);
|
|
||||||
|
|
||||||
switch (e->kind) {
|
|
||||||
case Entity_TypeName:
|
|
||||||
GB_ASSERT(e->type->kind == Type_Named);
|
|
||||||
ir_gen_global_type_name(m, e, name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Entity_Procedure: {
|
|
||||||
ast_node(pl, ProcLit, decl->proc_lit);
|
|
||||||
String original_name = name;
|
|
||||||
AstNode *body = pl->body;
|
|
||||||
|
|
||||||
if (e->Procedure.is_foreign) {
|
|
||||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
|
||||||
ir_add_foreign_library_path(m, e->Procedure.foreign_library);
|
|
||||||
}
|
|
||||||
if (pl->link_name.len > 0) {
|
|
||||||
name = pl->link_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *type_expr = pl->type;
|
|
||||||
|
|
||||||
irValue *p = ir_value_procedure(a, m, e, e->type, type_expr, body, name);
|
|
||||||
p->Proc.tags = pl->tags;
|
|
||||||
|
|
||||||
ir_module_add_value(m, e, p);
|
|
||||||
HashKey hash_name = hash_string(name);
|
|
||||||
if (map_get(&m->members, hash_name) == nullptr) {
|
|
||||||
multi_map_insert(&m->members, hash_name, p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, m->members.entries) {
|
|
||||||
auto *entry = &m->members.entries[i];
|
|
||||||
irValue *v = entry->value;
|
|
||||||
if (v->kind == irValue_Proc) {
|
|
||||||
ir_build_proc(v, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irDebugInfo *compile_unit = m->debug_info.entries[0].value;
|
|
||||||
GB_ASSERT(compile_unit->kind == irDebugInfo_CompileUnit);
|
|
||||||
irDebugInfo *all_procs = ir_alloc_debug_info(m->allocator, irDebugInfo_AllProcs);
|
|
||||||
|
|
||||||
isize all_proc_max_count = 0;
|
|
||||||
for_array(i, m->debug_info.entries) {
|
|
||||||
auto *entry = &m->debug_info.entries[i];
|
|
||||||
irDebugInfo *di = entry->value;
|
|
||||||
di->id = cast(i32)i;
|
|
||||||
if (di->kind == irDebugInfo_Proc) {
|
|
||||||
all_proc_max_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
array_init(&all_procs->AllProcs.procs, m->allocator, all_proc_max_count);
|
|
||||||
map_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped
|
|
||||||
compile_unit->CompileUnit.all_procs = all_procs;
|
|
||||||
|
|
||||||
|
|
||||||
for_array(i, m->debug_info.entries) {
|
|
||||||
auto *entry = &m->debug_info.entries[i];
|
|
||||||
irDebugInfo *di = entry->value;
|
|
||||||
if (di->kind == irDebugInfo_Proc) {
|
|
||||||
array_add(&all_procs->AllProcs.procs, di);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
|
||||||
if (build_context.is_dll && !has_dll_main) {
|
|
||||||
// DllMain :: proc(inst: rawptr, reason: u32, reserved: rawptr) -> i32
|
|
||||||
String name = str_lit("DllMain");
|
|
||||||
Type *proc_params = make_type_tuple(a);
|
|
||||||
Type *proc_results = make_type_tuple(a);
|
|
||||||
|
|
||||||
Scope *proc_scope = gb_alloc_item(a, Scope);
|
|
||||||
|
|
||||||
array_init_count(&proc_params->Tuple.variables, a, 3);
|
|
||||||
array_init_count(&proc_results->Tuple.variables, a, 1);
|
|
||||||
|
|
||||||
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
|
|
||||||
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
|
|
||||||
proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
|
|
||||||
|
|
||||||
|
|
||||||
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
|
|
||||||
|
|
||||||
|
|
||||||
Type *proc_type = make_type_proc(a, proc_scope,
|
|
||||||
proc_params, 3,
|
|
||||||
proc_results, 1, false, ProcCC_Std);
|
|
||||||
|
|
||||||
// TODO(bill): make this more robust
|
|
||||||
proc_type->Proc.abi_compat_params = gb_alloc_array(a, Type *, proc_params->Tuple.variables.count);
|
|
||||||
for_array(i, proc_params->Tuple.variables) {
|
|
||||||
proc_type->Proc.abi_compat_params[i] = proc_params->Tuple.variables[i]->type;
|
|
||||||
}
|
|
||||||
proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
|
|
||||||
|
|
||||||
AstNode *body = gb_alloc_item(a, AstNode);
|
|
||||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
|
||||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
|
||||||
|
|
||||||
map_set(&m->values, hash_entity(e), p);
|
|
||||||
map_set(&m->members, hash_string(name), p);
|
|
||||||
|
|
||||||
irProcedure *proc = &p->Proc;
|
|
||||||
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
|
||||||
e->Procedure.link_name = name;
|
|
||||||
|
|
||||||
ir_begin_procedure_body(proc);
|
|
||||||
|
|
||||||
// NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
|
|
||||||
// DLL_PROCESS_ATTACH == 1
|
|
||||||
|
|
||||||
irAddr reason_addr = ir_build_addr_from_entity(proc, proc_params->Tuple.variables[1], nullptr);
|
|
||||||
irValue *cond = ir_emit_comp(proc, Token_CmpEq, ir_addr_load(proc, reason_addr), v_one32);
|
|
||||||
irBlock *then = ir_new_block(proc, nullptr, "if.then");
|
|
||||||
irBlock *done = ir_new_block(proc, nullptr, "if.done"); // NOTE(bill): Append later
|
|
||||||
ir_emit_if(proc, cond, then, done);
|
|
||||||
ir_start_block(proc, then);
|
|
||||||
|
|
||||||
{
|
|
||||||
irValue **found = map_get(&m->values, hash_entity(entry_point));
|
|
||||||
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
|
||||||
if (found != nullptr) {
|
|
||||||
ir_emit_call(proc, *found, nullptr, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_emit_jump(proc, done);
|
|
||||||
ir_start_block(proc, done);
|
|
||||||
|
|
||||||
ir_emit_return(proc, v_one32);
|
|
||||||
|
|
||||||
|
|
||||||
ir_end_procedure_body(proc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!(build_context.is_dll && !has_dll_main)) {
|
|
||||||
// main :: proc(argc: i32, argv: ^^u8) -> i32
|
|
||||||
String name = str_lit("main");
|
|
||||||
Type *proc_params = make_type_tuple(a);
|
|
||||||
Type *proc_results = make_type_tuple(a);
|
|
||||||
|
|
||||||
Scope *proc_scope = gb_alloc_item(a, Scope);
|
|
||||||
|
|
||||||
array_init_count(&proc_params->Tuple.variables, a, 2);
|
|
||||||
array_init_count(&proc_results->Tuple.variables, a, 1);
|
|
||||||
|
|
||||||
Type *char_ptr_ptr = make_type_pointer(a, make_type_pointer(a, t_u8));
|
|
||||||
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argc")), t_i32, false, false);
|
|
||||||
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argv")), char_ptr_ptr, false, false);
|
|
||||||
|
|
||||||
|
|
||||||
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
|
|
||||||
|
|
||||||
|
|
||||||
Type *proc_type = make_type_proc(a, proc_scope,
|
|
||||||
proc_params, 2,
|
|
||||||
proc_results, 1, false, ProcCC_C);
|
|
||||||
|
|
||||||
// TODO(bill): make this more robust
|
|
||||||
proc_type->Proc.abi_compat_params = gb_alloc_array(a, Type *, proc_params->Tuple.variables.count);
|
|
||||||
for_array(i, proc_params->Tuple.variables) {
|
|
||||||
proc_type->Proc.abi_compat_params[i] = proc_params->Tuple.variables[i]->type;
|
|
||||||
}
|
|
||||||
proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
|
|
||||||
|
|
||||||
AstNode *body = gb_alloc_item(a, AstNode);
|
|
||||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
|
||||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
|
||||||
|
|
||||||
map_set(&m->values, hash_entity(e), p);
|
|
||||||
map_set(&m->members, hash_string(name), p);
|
|
||||||
|
|
||||||
irProcedure *proc = &p->Proc;
|
|
||||||
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
|
||||||
e->Procedure.link_name = name;
|
|
||||||
|
|
||||||
ir_begin_procedure_body(proc);
|
|
||||||
|
|
||||||
// NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
|
|
||||||
// DLL_PROCESS_ATTACH == 1
|
|
||||||
|
|
||||||
irValue *argc = ir_emit_load(proc, *map_get(&proc->module->values, hash_entity(proc_params->Tuple.variables[0])));
|
|
||||||
irValue *argv = ir_emit_load(proc, *map_get(&proc->module->values, hash_entity(proc_params->Tuple.variables[1])));
|
|
||||||
|
|
||||||
irValue *global_argc = ir_find_global_variable(proc, str_lit("__argc__"));
|
|
||||||
irValue *global_argv = ir_find_global_variable(proc, str_lit("__argv__"));
|
|
||||||
|
|
||||||
ir_emit_store(proc, global_argc, argc);
|
|
||||||
ir_emit_store(proc, global_argv, argv);
|
|
||||||
|
|
||||||
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
|
||||||
{
|
|
||||||
irValue **found = map_get(&proc->module->values, hash_entity(entry_point));
|
|
||||||
if (found != nullptr) {
|
|
||||||
ir_emit_call(proc, *found, nullptr, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_emit_return(proc, v_zero32);
|
|
||||||
ir_end_procedure_body(proc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 && defined(GB_SYSTEM_WINDOWS)
|
|
||||||
if (!m->build_context->is_dll && !has_win_main) {
|
|
||||||
// proc WinMain(inst, prev: rawptr, cmd_line: ^byte, cmd_show: i32) -> i32
|
|
||||||
String name = str_lit("WinMain");
|
|
||||||
Type *proc_params = make_type_tuple(a);
|
|
||||||
Type *proc_results = make_type_tuple(a);
|
|
||||||
|
|
||||||
Scope *proc_scope = gb_alloc_item(a, Scope);
|
|
||||||
|
|
||||||
proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 4);
|
|
||||||
proc_params->Tuple.variable_count = 4;
|
|
||||||
|
|
||||||
proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
|
|
||||||
proc_results->Tuple.variable_count = 1;
|
|
||||||
|
|
||||||
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
|
|
||||||
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
|
|
||||||
proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_u8_ptr, false);
|
|
||||||
proc_params->Tuple.variables[3] = make_entity_param(a, proc_scope, blank_token, t_i32, false);
|
|
||||||
|
|
||||||
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false);
|
|
||||||
|
|
||||||
|
|
||||||
Type *proc_type = make_type_proc(a, proc_scope,
|
|
||||||
proc_params, 4,
|
|
||||||
proc_results, 1, false, ProcCC_Std);
|
|
||||||
|
|
||||||
AstNode *body = gb_alloc_item(a, AstNode);
|
|
||||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
|
||||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
|
||||||
|
|
||||||
m->entry_point_entity = e;
|
|
||||||
|
|
||||||
map_set(&m->values, hash_entity(e), p);
|
|
||||||
map_set(&m->members, hash_string(name), p);
|
|
||||||
|
|
||||||
irProcedure *proc = &p->Proc;
|
|
||||||
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
|
||||||
e->Procedure.link_name = name;
|
|
||||||
|
|
||||||
ir_begin_procedure_body(proc);
|
|
||||||
ir_emit_global_call(proc, "main", nullptr, 0);
|
|
||||||
ir_emit_return(proc, v_one32);
|
|
||||||
ir_end_procedure_body(proc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
{ // Startup Runtime
|
|
||||||
// Cleanup(bill): probably better way of doing code insertion
|
|
||||||
String name = str_lit(IR_STARTUP_RUNTIME_PROC_NAME);
|
|
||||||
Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope),
|
|
||||||
nullptr, 0,
|
|
||||||
nullptr, 0, false,
|
|
||||||
ProcCC_Contextless);
|
|
||||||
AstNode *body = gb_alloc_item(a, AstNode);
|
|
||||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
|
||||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
|
||||||
|
|
||||||
map_set(&m->values, hash_entity(e), p);
|
|
||||||
map_set(&m->members, hash_string(name), p);
|
|
||||||
|
|
||||||
|
|
||||||
irProcedure *proc = &p->Proc;
|
|
||||||
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
|
||||||
|
|
||||||
ir_begin_procedure_body(proc);
|
|
||||||
|
|
||||||
{
|
|
||||||
irValue **args = gb_alloc_array(a, irValue *, 1);
|
|
||||||
args[0] = m->global_default_context;
|
|
||||||
ir_emit_global_call(proc, "__init_context", args, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ // NOTE(bill): Setup type_info data
|
|
||||||
CheckerInfo *info = proc->module->info;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
irValue *global_type_table = ir_find_global_variable(proc, str_lit("__type_table"));
|
irValue *global_type_table = ir_find_global_variable(proc, str_lit("__type_table"));
|
||||||
@@ -8526,6 +8077,459 @@ void ir_gen_tree(irGen *s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ir_gen_tree(irGen *s) {
|
||||||
|
irModule *m = &s->module;
|
||||||
|
CheckerInfo *info = m->info;
|
||||||
|
gbAllocator a = m->allocator;
|
||||||
|
|
||||||
|
if (v_zero == nullptr) {
|
||||||
|
v_zero = ir_const_int (m->allocator, 0);
|
||||||
|
v_one = ir_const_int (m->allocator, 1);
|
||||||
|
v_zero32 = ir_const_i32 (m->allocator, 0);
|
||||||
|
v_one32 = ir_const_i32 (m->allocator, 1);
|
||||||
|
v_two32 = ir_const_i32 (m->allocator, 2);
|
||||||
|
v_false = ir_const_bool(m->allocator, false);
|
||||||
|
v_true = ir_const_bool(m->allocator, true);
|
||||||
|
v_raw_nil = ir_value_constant(m->allocator, t_rawptr, exact_value_pointer(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
isize global_variable_max_count = 0;
|
||||||
|
Entity *entry_point = info->entry_point;
|
||||||
|
bool has_dll_main = false;
|
||||||
|
bool has_win_main = false;
|
||||||
|
|
||||||
|
for_array(i, info->entities.entries) {
|
||||||
|
auto *entry = &info->entities.entries[i];
|
||||||
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
|
String name = e->token.string;
|
||||||
|
if (e->kind == Entity_Variable) {
|
||||||
|
global_variable_max_count++;
|
||||||
|
} else if (e->kind == Entity_Procedure && !e->scope->is_global) {
|
||||||
|
if (e->scope->is_init && name == "main") {
|
||||||
|
GB_ASSERT(e == entry_point);
|
||||||
|
// entry_point = e;
|
||||||
|
}
|
||||||
|
if ((e->Procedure.tags & ProcTag_export) != 0 ||
|
||||||
|
(e->Procedure.link_name.len > 0) ||
|
||||||
|
(e->scope->is_file && e->Procedure.link_name.len > 0)) {
|
||||||
|
if (!has_dll_main && name == "DllMain") {
|
||||||
|
has_dll_main = true;
|
||||||
|
} else if (!has_win_main && name == "WinMain") {
|
||||||
|
has_win_main = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Add global default context
|
||||||
|
m->global_default_context = ir_add_global_generated(m, t_context, nullptr);
|
||||||
|
}
|
||||||
|
struct irGlobalVariable {
|
||||||
|
irValue *var, *init;
|
||||||
|
DeclInfo *decl;
|
||||||
|
};
|
||||||
|
Array<irGlobalVariable> global_variables;
|
||||||
|
array_init(&global_variables, m->tmp_allocator, global_variable_max_count);
|
||||||
|
|
||||||
|
m->entry_point_entity = entry_point;
|
||||||
|
m->min_dep_set = info->minimum_dependency_set;
|
||||||
|
|
||||||
|
for_array(i, info->variable_init_order) {
|
||||||
|
DeclInfo *d = info->variable_init_order[i];
|
||||||
|
|
||||||
|
for (isize j = 0; j < d->entity_count; j++) {
|
||||||
|
Entity *e = d->entities[j];
|
||||||
|
|
||||||
|
if (!e->scope->is_file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ptr_set_exists(&m->min_dep_set, e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DeclInfo *decl = decl_info_of_entity(info, e);
|
||||||
|
if (decl == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = e->token.string;
|
||||||
|
String original_name = name;
|
||||||
|
if (!e->scope->is_global) {
|
||||||
|
name = ir_mangle_name(s, e->token.pos.file, e);
|
||||||
|
}
|
||||||
|
ir_add_entity_name(m, e, name);
|
||||||
|
|
||||||
|
irValue *g = ir_value_global(a, e, nullptr);
|
||||||
|
g->Global.name = name;
|
||||||
|
g->Global.is_thread_local = e->Variable.is_thread_local;
|
||||||
|
|
||||||
|
|
||||||
|
irGlobalVariable var = {};
|
||||||
|
var.var = g;
|
||||||
|
var.decl = decl;
|
||||||
|
|
||||||
|
if (e->type->kind == Type_Struct && e->type->Struct.has_proc_default_values) {
|
||||||
|
for_array(i, e->type->Struct.fields) {
|
||||||
|
Entity *f = e->type->Struct.fields[i];
|
||||||
|
if (f->kind == Entity_Variable && f->Variable.default_value.kind == ExactValue_Procedure) {
|
||||||
|
AstNode *expr = f->Variable.default_value.value_procedure;
|
||||||
|
GB_ASSERT(expr != nullptr);
|
||||||
|
if (expr->kind == AstNode_ProcLit) {
|
||||||
|
ir_gen_anonymous_proc_lit(m, e->token.string, expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decl->init_expr != nullptr) {
|
||||||
|
if (is_type_any(e->type)) {
|
||||||
|
} else {
|
||||||
|
TypeAndValue tav = type_and_value_of_expr(info, decl->init_expr);
|
||||||
|
if (tav.mode != Addressing_Invalid) {
|
||||||
|
if (tav.value.kind != ExactValue_Invalid) {
|
||||||
|
ExactValue v = tav.value;
|
||||||
|
g->Global.value = ir_add_module_constant(m, tav.type, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (g->Global.value == nullptr) {
|
||||||
|
array_add(&global_variables, var);
|
||||||
|
// }
|
||||||
|
|
||||||
|
ir_module_add_value(m, e, g);
|
||||||
|
map_set(&m->members, hash_string(name), g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_array(i, info->entities.entries) {
|
||||||
|
auto *entry = &info->entities.entries[i];
|
||||||
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
|
String name = e->token.string;
|
||||||
|
DeclInfo *decl = entry->value;
|
||||||
|
Scope *scope = e->scope;
|
||||||
|
|
||||||
|
if (!scope->is_file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->kind == Entity_Variable) {
|
||||||
|
// NOTE(bill): Handled above as it requires a specific load order
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool polymorphic_struct = false;
|
||||||
|
if (e->type != nullptr && e->kind == Entity_TypeName) {
|
||||||
|
Type *bt = base_type(e->type);
|
||||||
|
if (bt->kind == Type_Struct) {
|
||||||
|
polymorphic_struct = is_type_polymorphic(bt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!polymorphic_struct && !ptr_set_exists(&m->min_dep_set, e)) {
|
||||||
|
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String original_name = name;
|
||||||
|
|
||||||
|
if (!scope->is_global || polymorphic_struct || is_type_polymorphic(e->type)) {
|
||||||
|
if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
|
||||||
|
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
|
||||||
|
// Handle later
|
||||||
|
// } else if (scope->is_init && e->kind == Entity_Procedure && name == "main") {
|
||||||
|
} else {
|
||||||
|
name = ir_mangle_name(s, e->token.pos.file, e);
|
||||||
|
}
|
||||||
|
} else if (check_is_entity_overloaded(e)) {
|
||||||
|
name = ir_mangle_name(s, e->token.pos.file, e);
|
||||||
|
}
|
||||||
|
ir_add_entity_name(m, e, name);
|
||||||
|
|
||||||
|
switch (e->kind) {
|
||||||
|
case Entity_TypeName:
|
||||||
|
GB_ASSERT(e->type->kind == Type_Named);
|
||||||
|
ir_gen_global_type_name(m, e, name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Entity_Procedure: {
|
||||||
|
ast_node(pl, ProcLit, decl->proc_lit);
|
||||||
|
String original_name = name;
|
||||||
|
AstNode *body = pl->body;
|
||||||
|
|
||||||
|
if (e->Procedure.is_foreign) {
|
||||||
|
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||||
|
ir_add_foreign_library_path(m, e->Procedure.foreign_library);
|
||||||
|
}
|
||||||
|
if (pl->link_name.len > 0) {
|
||||||
|
name = pl->link_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode *type_expr = pl->type;
|
||||||
|
|
||||||
|
irValue *p = ir_value_procedure(a, m, e, e->type, type_expr, body, name);
|
||||||
|
p->Proc.tags = pl->tags;
|
||||||
|
|
||||||
|
ir_module_add_value(m, e, p);
|
||||||
|
HashKey hash_name = hash_string(name);
|
||||||
|
if (map_get(&m->members, hash_name) == nullptr) {
|
||||||
|
multi_map_insert(&m->members, hash_name, p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_array(i, m->members.entries) {
|
||||||
|
auto *entry = &m->members.entries[i];
|
||||||
|
irValue *v = entry->value;
|
||||||
|
if (v->kind == irValue_Proc) {
|
||||||
|
ir_build_proc(v, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irDebugInfo *compile_unit = m->debug_info.entries[0].value;
|
||||||
|
GB_ASSERT(compile_unit->kind == irDebugInfo_CompileUnit);
|
||||||
|
irDebugInfo *all_procs = ir_alloc_debug_info(m->allocator, irDebugInfo_AllProcs);
|
||||||
|
|
||||||
|
isize all_proc_max_count = 0;
|
||||||
|
for_array(i, m->debug_info.entries) {
|
||||||
|
auto *entry = &m->debug_info.entries[i];
|
||||||
|
irDebugInfo *di = entry->value;
|
||||||
|
di->id = cast(i32)i;
|
||||||
|
if (di->kind == irDebugInfo_Proc) {
|
||||||
|
all_proc_max_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array_init(&all_procs->AllProcs.procs, m->allocator, all_proc_max_count);
|
||||||
|
map_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped
|
||||||
|
compile_unit->CompileUnit.all_procs = all_procs;
|
||||||
|
|
||||||
|
|
||||||
|
for_array(i, m->debug_info.entries) {
|
||||||
|
auto *entry = &m->debug_info.entries[i];
|
||||||
|
irDebugInfo *di = entry->value;
|
||||||
|
if (di->kind == irDebugInfo_Proc) {
|
||||||
|
array_add(&all_procs->AllProcs.procs, di);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
if (build_context.is_dll && !has_dll_main) {
|
||||||
|
// DllMain :: proc(inst: rawptr, reason: u32, reserved: rawptr) -> i32
|
||||||
|
String name = str_lit("DllMain");
|
||||||
|
Type *proc_params = make_type_tuple(a);
|
||||||
|
Type *proc_results = make_type_tuple(a);
|
||||||
|
|
||||||
|
Scope *proc_scope = gb_alloc_item(a, Scope);
|
||||||
|
|
||||||
|
array_init_count(&proc_params->Tuple.variables, a, 3);
|
||||||
|
array_init_count(&proc_results->Tuple.variables, a, 1);
|
||||||
|
|
||||||
|
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
|
||||||
|
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
|
||||||
|
proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
|
||||||
|
|
||||||
|
|
||||||
|
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
|
||||||
|
|
||||||
|
|
||||||
|
Type *proc_type = make_type_proc(a, proc_scope,
|
||||||
|
proc_params, 3,
|
||||||
|
proc_results, 1, false, ProcCC_Std);
|
||||||
|
|
||||||
|
// TODO(bill): make this more robust
|
||||||
|
proc_type->Proc.abi_compat_params = gb_alloc_array(a, Type *, proc_params->Tuple.variables.count);
|
||||||
|
for_array(i, proc_params->Tuple.variables) {
|
||||||
|
proc_type->Proc.abi_compat_params[i] = proc_params->Tuple.variables[i]->type;
|
||||||
|
}
|
||||||
|
proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
|
||||||
|
|
||||||
|
AstNode *body = gb_alloc_item(a, AstNode);
|
||||||
|
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||||
|
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||||
|
|
||||||
|
map_set(&m->values, hash_entity(e), p);
|
||||||
|
map_set(&m->members, hash_string(name), p);
|
||||||
|
|
||||||
|
irProcedure *proc = &p->Proc;
|
||||||
|
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
||||||
|
e->Procedure.link_name = name;
|
||||||
|
|
||||||
|
ir_begin_procedure_body(proc);
|
||||||
|
|
||||||
|
// NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
|
||||||
|
// DLL_PROCESS_ATTACH == 1
|
||||||
|
|
||||||
|
irAddr reason_addr = ir_build_addr_from_entity(proc, proc_params->Tuple.variables[1], nullptr);
|
||||||
|
irValue *cond = ir_emit_comp(proc, Token_CmpEq, ir_addr_load(proc, reason_addr), v_one32);
|
||||||
|
irBlock *then = ir_new_block(proc, nullptr, "if.then");
|
||||||
|
irBlock *done = ir_new_block(proc, nullptr, "if.done"); // NOTE(bill): Append later
|
||||||
|
ir_emit_if(proc, cond, then, done);
|
||||||
|
ir_start_block(proc, then);
|
||||||
|
|
||||||
|
{
|
||||||
|
irValue **found = map_get(&m->values, hash_entity(entry_point));
|
||||||
|
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
||||||
|
if (found != nullptr) {
|
||||||
|
ir_emit_call(proc, *found, nullptr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_emit_jump(proc, done);
|
||||||
|
ir_start_block(proc, done);
|
||||||
|
|
||||||
|
ir_emit_return(proc, v_one32);
|
||||||
|
|
||||||
|
|
||||||
|
ir_end_procedure_body(proc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!(build_context.is_dll && !has_dll_main)) {
|
||||||
|
// main :: proc(argc: i32, argv: ^^u8) -> i32
|
||||||
|
String name = str_lit("main");
|
||||||
|
Type *proc_params = make_type_tuple(a);
|
||||||
|
Type *proc_results = make_type_tuple(a);
|
||||||
|
|
||||||
|
Scope *proc_scope = gb_alloc_item(a, Scope);
|
||||||
|
|
||||||
|
array_init_count(&proc_params->Tuple.variables, a, 2);
|
||||||
|
array_init_count(&proc_results->Tuple.variables, a, 1);
|
||||||
|
|
||||||
|
Type *char_ptr_ptr = make_type_pointer(a, make_type_pointer(a, t_u8));
|
||||||
|
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argc")), t_i32, false, false);
|
||||||
|
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argv")), char_ptr_ptr, false, false);
|
||||||
|
|
||||||
|
|
||||||
|
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
|
||||||
|
|
||||||
|
|
||||||
|
Type *proc_type = make_type_proc(a, proc_scope,
|
||||||
|
proc_params, 2,
|
||||||
|
proc_results, 1, false, ProcCC_C);
|
||||||
|
|
||||||
|
// TODO(bill): make this more robust
|
||||||
|
proc_type->Proc.abi_compat_params = gb_alloc_array(a, Type *, proc_params->Tuple.variables.count);
|
||||||
|
for_array(i, proc_params->Tuple.variables) {
|
||||||
|
proc_type->Proc.abi_compat_params[i] = proc_params->Tuple.variables[i]->type;
|
||||||
|
}
|
||||||
|
proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
|
||||||
|
|
||||||
|
AstNode *body = gb_alloc_item(a, AstNode);
|
||||||
|
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||||
|
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||||
|
|
||||||
|
map_set(&m->values, hash_entity(e), p);
|
||||||
|
map_set(&m->members, hash_string(name), p);
|
||||||
|
|
||||||
|
irProcedure *proc = &p->Proc;
|
||||||
|
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
||||||
|
e->Procedure.link_name = name;
|
||||||
|
|
||||||
|
ir_begin_procedure_body(proc);
|
||||||
|
|
||||||
|
// NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
|
||||||
|
// DLL_PROCESS_ATTACH == 1
|
||||||
|
|
||||||
|
irValue *argc = ir_emit_load(proc, *map_get(&proc->module->values, hash_entity(proc_params->Tuple.variables[0])));
|
||||||
|
irValue *argv = ir_emit_load(proc, *map_get(&proc->module->values, hash_entity(proc_params->Tuple.variables[1])));
|
||||||
|
|
||||||
|
irValue *global_argc = ir_find_global_variable(proc, str_lit("__argc__"));
|
||||||
|
irValue *global_argv = ir_find_global_variable(proc, str_lit("__argv__"));
|
||||||
|
|
||||||
|
ir_emit_store(proc, global_argc, argc);
|
||||||
|
ir_emit_store(proc, global_argv, argv);
|
||||||
|
|
||||||
|
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
||||||
|
{
|
||||||
|
irValue **found = map_get(&proc->module->values, hash_entity(entry_point));
|
||||||
|
if (found != nullptr) {
|
||||||
|
ir_emit_call(proc, *found, nullptr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_emit_return(proc, v_zero32);
|
||||||
|
ir_end_procedure_body(proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 && defined(GB_SYSTEM_WINDOWS)
|
||||||
|
if (!m->build_context->is_dll && !has_win_main) {
|
||||||
|
// proc WinMain(inst, prev: rawptr, cmd_line: ^byte, cmd_show: i32) -> i32
|
||||||
|
String name = str_lit("WinMain");
|
||||||
|
Type *proc_params = make_type_tuple(a);
|
||||||
|
Type *proc_results = make_type_tuple(a);
|
||||||
|
|
||||||
|
Scope *proc_scope = gb_alloc_item(a, Scope);
|
||||||
|
|
||||||
|
proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 4);
|
||||||
|
proc_params->Tuple.variable_count = 4;
|
||||||
|
|
||||||
|
proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
|
||||||
|
proc_results->Tuple.variable_count = 1;
|
||||||
|
|
||||||
|
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
|
||||||
|
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
|
||||||
|
proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_u8_ptr, false);
|
||||||
|
proc_params->Tuple.variables[3] = make_entity_param(a, proc_scope, blank_token, t_i32, false);
|
||||||
|
|
||||||
|
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false);
|
||||||
|
|
||||||
|
|
||||||
|
Type *proc_type = make_type_proc(a, proc_scope,
|
||||||
|
proc_params, 4,
|
||||||
|
proc_results, 1, false, ProcCC_Std);
|
||||||
|
|
||||||
|
AstNode *body = gb_alloc_item(a, AstNode);
|
||||||
|
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||||
|
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||||
|
|
||||||
|
m->entry_point_entity = e;
|
||||||
|
|
||||||
|
map_set(&m->values, hash_entity(e), p);
|
||||||
|
map_set(&m->members, hash_string(name), p);
|
||||||
|
|
||||||
|
irProcedure *proc = &p->Proc;
|
||||||
|
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
||||||
|
e->Procedure.link_name = name;
|
||||||
|
|
||||||
|
ir_begin_procedure_body(proc);
|
||||||
|
ir_emit_global_call(proc, "main", nullptr, 0);
|
||||||
|
ir_emit_return(proc, v_one32);
|
||||||
|
ir_end_procedure_body(proc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
{ // Startup Runtime
|
||||||
|
// Cleanup(bill): probably better way of doing code insertion
|
||||||
|
String name = str_lit(IR_STARTUP_RUNTIME_PROC_NAME);
|
||||||
|
Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope),
|
||||||
|
nullptr, 0,
|
||||||
|
nullptr, 0, false,
|
||||||
|
ProcCC_Contextless);
|
||||||
|
AstNode *body = gb_alloc_item(a, AstNode);
|
||||||
|
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||||
|
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||||
|
|
||||||
|
map_set(&m->values, hash_entity(e), p);
|
||||||
|
map_set(&m->members, hash_string(name), p);
|
||||||
|
|
||||||
|
|
||||||
|
irProcedure *proc = &p->Proc;
|
||||||
|
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
||||||
|
|
||||||
|
ir_begin_procedure_body(proc);
|
||||||
|
|
||||||
|
{
|
||||||
|
irValue **args = gb_alloc_array(a, irValue *, 1);
|
||||||
|
args[0] = m->global_default_context;
|
||||||
|
ir_emit_global_call(proc, "__init_context", args, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ir_setup_type_info_data(proc);
|
||||||
|
|
||||||
|
|
||||||
for_array(i, global_variables) {
|
for_array(i, global_variables) {
|
||||||
irGlobalVariable *var = &global_variables[i];
|
irGlobalVariable *var = &global_variables[i];
|
||||||
if (var->decl->init_expr != nullptr) {
|
if (var->decl->init_expr != nullptr) {
|
||||||
|
|||||||
+3
-1
@@ -356,8 +356,9 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
ir_print_encoded_local(f, *found);
|
ir_print_encoded_local(f, *found);
|
||||||
} else {
|
} else {
|
||||||
// TODO(bill): Is this correct behaviour?!
|
// TODO(bill): Is this correct behaviour?!
|
||||||
|
GB_ASSERT_MSG(found != nullptr, "%.*s %p", LIT(t->Named.name), t->Named.type_name);
|
||||||
|
// gb_printf_err("%.*s %p\n", LIT(t->Named.name), t->Named.type_name);
|
||||||
ir_print_type(f, m, base_type(t));
|
ir_print_type(f, m, base_type(t));
|
||||||
// GB_ASSERT_MSG(found != nullptr, "%.*s %p", LIT(t->Named.name), t->Named.type_name);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1795,6 +1796,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
||||||
GB_ASSERT(v->kind == irValue_TypeName);
|
GB_ASSERT(v->kind == irValue_TypeName);
|
||||||
Type *t = base_type(v->TypeName.type);
|
Type *t = base_type(v->TypeName.type);
|
||||||
|
|
||||||
ir_print_encoded_local(f, v->TypeName.name);
|
ir_print_encoded_local(f, v->TypeName.name);
|
||||||
ir_write_string(f, str_lit(" = type "));
|
ir_write_string(f, str_lit(" = type "));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user