From 921601766d46c5c05b19ad12e5483bb0a5ae60d1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 19 Mar 2022 13:40:29 +0000 Subject: Begin mocking out `me_build_stmt` --- src/middle_end.cpp | 42 ++++++ src/middle_end.hpp | 10 ++ src/middle_end_core.cpp | 5 +- src/middle_end_expr.cpp | 3 + src/middle_end_stmt.cpp | 389 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 445 insertions(+), 4 deletions(-) create mode 100644 src/middle_end_expr.cpp create mode 100644 src/middle_end_stmt.cpp diff --git a/src/middle_end.cpp b/src/middle_end.cpp index 7de7691f3..63f2c958d 100644 --- a/src/middle_end.cpp +++ b/src/middle_end.cpp @@ -1,5 +1,7 @@ #include "middle_end.hpp" #include "middle_end_core.cpp" +#include "middle_end_stmt.cpp" +#include "middle_end_expr.cpp" void me_module_init(meModule *m, Checker *c) { @@ -250,6 +252,46 @@ void me_procedure_body_end(meProcedure *p) { } +void me_build_nested_proc(meProcedure *p, AstProcLit *pd, Entity *e) { + GB_ASSERT(pd->body != nullptr); + meModule *m = p->module; + auto *min_dep_set = &m->info->minimum_dependency_set; + + if (ptr_set_exists(min_dep_set, e) == false) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + return; + } + + // NOTE(bill): Generate a new name + // parent.name-guid + String original_name = e->token.string; + String pd_name = original_name; + if (e->Procedure.link_name.len > 0) { + pd_name = e->Procedure.link_name; + } + + + isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); + + i32 guid = cast(i32)p->children.count; + name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(pd_name), guid); + String name = make_string(cast(u8 *)name_text, name_len-1); + + e->Procedure.link_name = name; + + meProcedure *nested_proc = me_procedure_create(p->module, e); + e->me_procedure = nested_proc; + + meValue value = me_value(nested_proc); + + me_add_entity(m, e, value); + array_add(&p->children, nested_proc); + array_add(&m->procedures_to_generate, nested_proc); +} + + + void me_generate_procedure(meModule *m, meProcedure *p) { if (p->is_done) { return; diff --git a/src/middle_end.hpp b/src/middle_end.hpp index cf9a7e5cf..1dbcb40ff 100644 --- a/src/middle_end.hpp +++ b/src/middle_end.hpp @@ -286,6 +286,13 @@ struct meDefer { }; }; +enum meDeferExitKind { + meDeferExit_Default, + meDeferExit_Return, + meDeferExit_Branch, +}; + + enum meProcedureFlags : u32 { meProcedureFlag_Foreign = 1<<1, @@ -386,4 +393,7 @@ meValue me_value(meGlobalVariable *global); meValue me_value(meParameter *param); +void me_build_stmt(meProcedure *p, Ast *stmt); +meValue me_build_expr(meProcedure *p, Ast *expr); meValue me_emit_conv(meProcedure *p, meValue value, Type *type); + diff --git a/src/middle_end_core.cpp b/src/middle_end_core.cpp index 4b19b5e55..1f08e6fb7 100644 --- a/src/middle_end_core.cpp +++ b/src/middle_end_core.cpp @@ -386,9 +386,6 @@ void me_block_start(meProcedure *p, meBlock *b) { p->curr_block = b; } -void me_build_stmt(meProcedure *p, Ast *stmt) { - -} meContextData *me_push_context_onto_stack_from_implicit_parameter(meProcedure *p) { // TODO(bill): me_push_context_onto_stack_from_implicit_parameter @@ -881,7 +878,7 @@ meValue me_emit_select(meProcedure *p, meValue cond, meValue left, meValue right return me_value(v); } -meValue me_emit_call(meProcedure *p, meValue proc, Slice const &arguments, u16 instruction_flags) { +meValue me_emit_call(meProcedure *p, meValue proc, Slice const &arguments, u16 instruction_flags = 0) { GB_PANIC("TODO"); return {}; } diff --git a/src/middle_end_expr.cpp b/src/middle_end_expr.cpp new file mode 100644 index 000000000..e31d58925 --- /dev/null +++ b/src/middle_end_expr.cpp @@ -0,0 +1,3 @@ +meValue me_build_expr(meProcedure *p, Ast *expr) { + return {}; +} \ No newline at end of file diff --git a/src/middle_end_stmt.cpp b/src/middle_end_stmt.cpp new file mode 100644 index 000000000..723723e1c --- /dev/null +++ b/src/middle_end_stmt.cpp @@ -0,0 +1,389 @@ +void me_build_nested_proc(meProcedure *p, AstProcLit *pd, Entity *e); + +void me_build_constant_value_decl(meProcedure *p, AstValueDecl *vd) { + if (vd == nullptr || vd->is_mutable) { + return; + } + + auto *min_dep_set = &p->module->info->minimum_dependency_set; + + static i32 global_guid = 0; + + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_TypeName) { + continue; + } + + bool polymorphic_struct = false; + if (e->type != nullptr && e->kind == Entity_TypeName) { + Type *bt = base_type(e->type); + if (bt->kind == Type_Struct) { + polymorphic_struct = bt->Struct.is_polymorphic; + } + } + + if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + continue; + } + + if (e->TypeName.ir_mangled_name.len != 0) { + // NOTE(bill): Already set + continue; + } + + me_set_nested_type_name_ir_mangled_name(e, p); + } + + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Procedure) { + continue; + } + GB_ASSERT (vd->values[i] != nullptr); + + Ast *value = unparen_expr(vd->values[i]); + if (value->kind != Ast_ProcLit) { + continue; // It's an alias + } + + CheckerInfo *info = p->module->info; + DeclInfo *decl = decl_info_of_entity(e); + ast_node(pl, ProcLit, decl->proc_lit); + if (pl->body != nullptr) { + auto *found = map_get(&info->gen_procs, ident); + if (found) { + auto procs = *found; + for_array(i, procs) { + Entity *e = procs[i]; + if (!ptr_set_exists(min_dep_set, e)) { + continue; + } + DeclInfo *d = decl_info_of_entity(e); + me_build_nested_proc(p, &d->proc_lit->ProcLit, e); + } + } else { + me_build_nested_proc(p, pl, e); + } + } else { + + // FFI - Foreign function interace + String original_name = e->token.string; + String name = original_name; + + if (e->Procedure.is_foreign) { + me_add_foreign_library_path(p->module, e->Procedure.foreign_library); + } + + if (e->Procedure.link_name.len > 0) { + name = e->Procedure.link_name; + } + + meValue *prev_value = string_map_get(&p->module->members, name); + if (prev_value != nullptr) { + // NOTE(bill): Don't do mutliple declarations in the IR + return; + } + + e->Procedure.link_name = name; + + meProcedure *nested_proc = me_procedure_create(p->module, e); + + meValue value = me_value(nested_proc); + + array_add(&p->module->procedures_to_generate, nested_proc); + array_add(&p->children, nested_proc); + string_map_set(&p->module->members, name, value); + } + } +} + +void me_build_defer_stmt(meProcedure *p, meDefer const &d) { + if (p->curr_block == nullptr) { + return; + } + // NOTE(bill): The prev block may defer injection before it's terminator + meInstruction *last_instr = me_last_instruction(p->curr_block); + if (last_instr != nullptr && last_instr->op == meOp_Return) { + // NOTE(bill): ReturnStmt defer stuff will be handled previously + return; + } + + isize prev_context_stack_count = p->context_stack.count; + GB_ASSERT(prev_context_stack_count <= p->context_stack.capacity); + defer (p->context_stack.count = prev_context_stack_count); + p->context_stack.count = d.context_stack_count; + + meBlock *b = me_block_create(p, "defer"); + if (last_instr == nullptr || !me_is_instruction_terminator(last_instr->op)) { + me_emit_jump(p, b); + } + + me_block_start(p, b); + if (d.kind == meDefer_Node) { + me_build_stmt(p, d.stmt); + } else if (d.kind == meDefer_Proc) { + me_emit_call(p, d.proc.deferred, slice_from_array(d.proc.result_as_args)); + } +} + +void me_emit_defer_stmts(meProcedure *p, meDeferExitKind kind, meBlock *block) { + isize count = p->defer_stmts.count; + isize i = count; + while (i --> 0) { + meDefer const &d = p->defer_stmts[i]; + + if (kind == meDeferExit_Default) { + if (p->scope_index == d.scope_index && + d.scope_index > 0) { // TODO(bill): Which is correct: > 0 or > 1? + me_build_defer_stmt(p, d); + array_pop(&p->defer_stmts); + continue; + } else { + break; + } + } else if (kind == meDeferExit_Return) { + me_build_defer_stmt(p, d); + } else if (kind == meDeferExit_Branch) { + GB_ASSERT(block != nullptr); + isize lower_limit = block->scope_index; + if (lower_limit < d.scope_index) { + me_build_defer_stmt(p, d); + } + } + } +} + + + + +meBranchBlocks me_lookup_branch_blocks(meProcedure *p, Ast *ident) { + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e->kind == Entity_Label); + for_array(i, p->branch_blocks) { + meBranchBlocks *b = &p->branch_blocks[i]; + if (b->label == e->Label.node) { + return *b; + } + } + + GB_PANIC("Unreachable"); + meBranchBlocks empty = {}; + return empty; +} + + +meTargetList *me_target_list_push(meProcedure *p, Ast *label, meBlock *break_, meBlock *continue_, meBlock *fallthrough_) { + meTargetList *tl = gb_alloc_item(permanent_allocator(), meTargetList); + tl->prev = p->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + p->target_list = tl; + + if (label != nullptr) { // Set label blocks + GB_ASSERT(label->kind == Ast_Label); + + for_array(i, p->branch_blocks) { + meBranchBlocks *b = &p->branch_blocks[i]; + GB_ASSERT(b->label != nullptr && label != nullptr); + GB_ASSERT(b->label->kind == Ast_Label); + if (b->label == label) { + b->break_ = break_; + b->continue_ = continue_; + return tl; + } + } + + GB_PANIC("Unreachable"); + } + + return tl; +} + +void me_target_list_pop(meProcedure *p) { + p->target_list = p->target_list->prev; +} + +void me_scope_open(meProcedure *p, Scope *s) { + p->scope_index += 1; + array_add(&p->scope_stack, s); + +} + +void me_scope_close(meProcedure *p, meDeferExitKind kind, meBlock *block, bool pop_stack=true) { + me_emit_defer_stmts(p, kind, block); + GB_ASSERT(p->scope_index > 0); + + // NOTE(bill): Remove `context`s made in that scope + while (p->context_stack.count > 0) { + meContextData *ctx = &p->context_stack[p->context_stack.count-1]; + if (ctx->scope_index >= p->scope_index) { + array_pop(&p->context_stack); + } else { + break; + } + + } + + p->scope_index -= 1; + array_pop(&p->scope_stack); +} + +void me_build_stmt_list(meProcedure *p, Slice const &stmts) { + for_array(i, stmts) { + Ast *stmt = stmts[i]; + switch (stmt->kind) { + case_ast_node(vd, ValueDecl, stmt); + // me_build_constant_value_decl(p, vd); + case_end; + case_ast_node(fb, ForeignBlockDecl, stmt); + ast_node(block, BlockStmt, fb->body); + me_build_stmt_list(p, block->stmts); + case_end; + } + } + for_array(i, stmts) { + me_build_stmt(p, stmts[i]); + } +} + +void me_build_when_stmt(meProcedure *p, AstWhenStmt *ws) { + TypeAndValue tv = type_and_value_of_expr(ws->cond); + GB_ASSERT(is_type_boolean(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Bool); + if (tv.value.value_bool) { + me_build_stmt_list(p, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case Ast_BlockStmt: + me_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); + break; + case Ast_WhenStmt: + me_build_when_stmt(p, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid 'else' statement in 'when' statement"); + break; + } + } +} + + + +void me_build_stmt(meProcedure *p, Ast *node) { + Ast *prev_stmt = p->curr_stmt; + defer (p->curr_stmt = prev_stmt); + p->curr_stmt = node; + + if (me_is_last_instruction_terminator(p->curr_block)) { + return; + } + + u16 prev_state_flags = p->state_flags; + defer (p->state_flags = prev_state_flags); + + if (node->state_flags != 0) { + u16 in = node->state_flags; + u16 out = p->state_flags; + + if (in & StateFlag_bounds_check) { + out |= StateFlag_bounds_check; + out &= ~StateFlag_no_bounds_check; + } else if (in & StateFlag_no_bounds_check) { + out |= StateFlag_no_bounds_check; + out &= ~StateFlag_bounds_check; + } + if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } else if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } + + p->state_flags = out; + } + + switch (node->kind) { + case_ast_node(bs, EmptyStmt, node); + case_end; + + case_ast_node(us, UsingStmt, node); + case_end; + + case_ast_node(ws, WhenStmt, node); + me_build_when_stmt(p, ws); + case_end; + + case_ast_node(bs, BlockStmt, node); + meBlock *done = nullptr; + if (bs->label != nullptr) { + done = me_block_create(p, "block.done"); + meTargetList *tl = me_target_list_push(p, bs->label, done, nullptr, nullptr); + tl->is_block = true; + } + + me_scope_open(p, bs->scope); + me_build_stmt_list(p, bs->stmts); + me_scope_close(p, meDeferExit_Default, nullptr); + + if (done != nullptr) { + me_emit_jump(p, done); + me_block_start(p, done); + } + + if (bs->label != nullptr) { + me_target_list_pop(p); + } + case_end; + + case_ast_node(bs, BranchStmt, node); + meBlock *block = nullptr; + + if (bs->label != nullptr) { + meBranchBlocks bb = me_lookup_branch_blocks(p, bs->label); + switch (bs->token.kind) { + case Token_break: block = bb.break_; break; + case Token_continue: block = bb.continue_; break; + case Token_fallthrough: + GB_PANIC("fallthrough cannot have a label"); + break; + } + } else { + for (meTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) { + if (t->is_block) { + continue; + } + + switch (bs->token.kind) { + case Token_break: block = t->break_; break; + case Token_continue: block = t->continue_; break; + case Token_fallthrough: block = t->fallthrough_; break; + } + } + } + if (block != nullptr) { + me_emit_defer_stmts(p, meDeferExit_Branch, block); + } + me_emit_jump(p, block); + me_block_start(p, me_block_create(p, "unreachable")); + case_end; + + case_ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + return; + } + + // TODO: ValueDecl + + case_end; + } +} \ No newline at end of file -- cgit v1.2.3