Fix minimal dependency generation for polymorphic structs (related to issue #121)

This commit is contained in:
gingerBill
2017-10-15 11:21:48 +01:00
parent 94762b56f6
commit e05fe1837d
4 changed files with 454 additions and 438 deletions
+4 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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"));
@@ -8524,8 +8075,461 @@ void ir_gen_tree(irGen *s) {
GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t)); GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t));
} }
} }
}
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
View File
@@ -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 "));