diff options
| author | gingerBill <bill@gingerbill.org> | 2023-07-14 13:01:17 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2023-07-14 13:01:17 +0100 |
| commit | 2a10c8fe5c9d27e1a110346ef423c1cadc95daa3 (patch) | |
| tree | eac791bd5256f65844fc0a304ef1dfb0c2b53f8d /src | |
| parent | 7cd2d14b6410a17783020cea390f2be9534fa432 (diff) | |
Begin work on building statements
Diffstat (limited to 'src')
| -rw-r--r-- | src/tilde_backend.cpp | 31 | ||||
| -rw-r--r-- | src/tilde_backend.hpp | 34 | ||||
| -rw-r--r-- | src/tilde_stmt.cpp | 287 |
3 files changed, 344 insertions, 8 deletions
diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index abaf0b825..dd3c8e537 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -187,12 +187,23 @@ cgModule *cg_module_create(Checker *c) { map_init(&m->values); array_init(&m->procedures_to_generate, heap_allocator()); + map_init(&m->file_id_map); + + + for_array(id, global_files) { + if (AstFile *f = global_files[id]) { + char const *path = alloc_cstring(permanent_allocator(), f->fullpath); + map_set(&m->file_id_map, cast(uintptr)id, tb_file_create(m->mod, path)); + } + } + return m; } void cg_module_destroy(cgModule *m) { map_destroy(&m->values); array_free(&m->procedures_to_generate); + map_destroy(&m->file_id_map); tb_module_destroy(m->mod); } @@ -601,15 +612,24 @@ gb_internal void cg_procedure_end(cgProcedure *p) { tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); } -gb_internal void cg_procedure_build_body(cgProcedure *p) { +gb_internal void cg_procedure_generate(cgProcedure *p) { if (p->body == nullptr) { return; } + cg_procedure_begin(p); + defer (cg_procedure_end(p)); - // TODO(bill): + if (p->name != "bug.main") { + return; + } + if (p->body != nullptr) { + cg_build_stmt(p, p->body); + } } +#include "tilde_stmt.cpp" + gb_internal bool cg_generate_code(Checker *c) { TIME_SECTION("Tilde Module Initializtion"); @@ -699,12 +719,7 @@ gb_internal bool cg_generate_code(Checker *c) { for (isize i = 0; i < m->procedures_to_generate.count; i++) { - cgProcedure *p = m->procedures_to_generate[i]; - cg_procedure_begin(p); - if (p->name == "main") { - cg_procedure_build_body(p); - } - cg_procedure_end(p); + cg_procedure_generate(m->procedures_to_generate[i]); } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 56b3bcb74..6e4f792a7 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -88,6 +88,29 @@ struct cgAddr { }; +struct cgTargetList { + cgTargetList *prev; + bool is_block; + // control regions + TB_Node * break_; + TB_Node * continue_; + TB_Node * fallthrough_; +}; + +struct cgBranchBlocks { + Ast * label; + TB_Node *break_; + TB_Node *continue_; +}; + +enum cgDeferExitKind { + cgDeferExit_Default, + cgDeferExit_Return, + cgDeferExit_Branch, +}; + + + struct cgProcedure { u32 flags; u16 state_flags; @@ -113,6 +136,10 @@ struct cgProcedure { cgValue value; + Ast *curr_stmt; + + cgTargetList * target_list; + Array<cgBranchBlocks> branch_blocks; }; @@ -129,6 +156,8 @@ struct cgModule { PtrMap<TB_Function *, Entity *> procedure_values; Array<cgProcedure *> procedures_to_generate; + PtrMap<uintptr, TB_FileID> file_id_map; // Key: AstFile.id (i32 cast to uintptr) + std::atomic<u32> nested_type_name_guid; }; @@ -158,3 +187,8 @@ gb_internal cgValue cg_value(TB_Node * node, Type *type); gb_internal cgAddr cg_addr(cgValue const &value); + + +gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); +gb_internal void cg_build_stmt_list(cgProcedure *p, Slice<Ast *> const &stmts); +gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws);
\ No newline at end of file diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp new file mode 100644 index 000000000..c277eae03 --- /dev/null +++ b/src/tilde_stmt.cpp @@ -0,0 +1,287 @@ +gb_internal cgBranchBlocks cg_lookup_branch_blocks(cgProcedure *p, Ast *ident) { + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e->kind == Entity_Label); + for (cgBranchBlocks const &b : p->branch_blocks) { + if (b.label == e->Label.node) { + return b; + } + } + + GB_PANIC("Unreachable"); + cgBranchBlocks empty = {}; + return empty; +} + +gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Node *break_, TB_Node *continue_, TB_Node *fallthrough_) { + cgTargetList *tl = gb_alloc_item(permanent_allocator(), cgTargetList); + 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 (cgBranchBlocks &b : p->branch_blocks) { + 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; +} + +gb_internal void cg_pop_target_list(cgProcedure *p) { + p->target_list = p->target_list->prev; +} + +gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init) { + char const *name = ""; + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + name = alloc_cstring(permanent_allocator(), e->token.string); + } + + isize size = type_size_of(type); + TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); + if (is_type_matrix(type)) { + alignment *= 2; // NOTE(bill): Just in case + } + + TB_Node *local = tb_inst_local(p->func, cast(u32)size, alignment); + + if (zero_init) { + bool is_volatile = false; + TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); + TB_Node *count = tb_inst_uint(p->func, TB_TYPE_I32, cast(u64)size); + tb_inst_memset(p->func, local, zero, count, alignment, is_volatile); + } + + return cg_addr(cg_value(local, alloc_type_pointer(type))); +} + + +gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { + // TODO(bill): cg_scope_open +} + +gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region, bool pop_stack=true) { + // TODO(bill): cg_scope_close +} + +gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { + // TODO(bill): cg_emit_defer_stmts +} + +gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { + Ast *prev_stmt = p->curr_stmt; + defer (p->curr_stmt = prev_stmt); + p->curr_stmt = node; + + // TODO(bill): check if last instruction was a terminating one or not + + { + TokenPos pos = ast_token(node).pos; + TB_FileID *file_id = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id); + if (file_id) { + tb_inst_set_location(p->func, *file_id, pos.line); + } + } + + 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); + cg_build_when_stmt(p, ws); + case_end; + + case_ast_node(bs, BlockStmt, node); + TB_Node *done = nullptr; + if (bs->label != nullptr) { + done = tb_inst_region(p->func); + tb_inst_set_region_name(done, -1, "block.done"); + cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr); + tl->is_block = true; + } + + cg_scope_open(p, bs->scope); + cg_build_stmt_list(p, bs->stmts); + cg_scope_close(p, cgDeferExit_Default, nullptr); + + if (done != nullptr) { + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, done); + } + + if (bs->label != nullptr) { + cg_pop_target_list(p); + } + case_end; + + case_ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + return; + } + + bool is_static = false; + if (vd->names.count > 0) { + for (Ast *name : vd->names) { + if (!is_blank_ident(name)) { + GB_ASSERT(name->kind == Ast_Ident); + Entity *e = entity_of_node(name); + TokenPos pos = ast_token(name).pos; + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; + break; + } + } + } + } + if (is_static) { + GB_PANIC("TODO(bill): build static variables"); + return; + } + + TEMPORARY_ALLOCATOR_GUARD(); + + auto const &values = vd->values; + if (values.count == 0) { + for (Ast *name : vd->names) { + if (!is_blank_ident(name)) { + Entity *e = entity_of_node(name); + bool zero_init = true; + cgAddr addr = cg_add_local(p, e->type, e, zero_init); + gb_unused(addr); + } + } + } else { + GB_PANIC("TODO multiple variables"); + } + case_end; + + case_ast_node(bs, BranchStmt, node); + TB_Node *prev_block = tb_inst_get_control(p->func); + + TB_Node *block = nullptr; + + if (bs->label != nullptr) { + cgBranchBlocks bb = cg_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 (cgTargetList *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) { + cg_emit_defer_stmts(p, cgDeferExit_Branch, block); + } + + + tb_inst_goto(p->func, block); + tb_inst_set_control(p->func, block); + tb_inst_unreachable(p->func); + + tb_inst_set_control(p->func, prev_block); + case_end; + + default: + GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); + break; + } +} + + +gb_internal void cg_build_stmt_list(cgProcedure *p, Slice<Ast *> const &stmts) { + for (Ast *stmt : stmts) { + switch (stmt->kind) { + case_ast_node(vd, ValueDecl, stmt); + // TODO(bill) + // cg_build_constant_value_decl(p, vd); + case_end; + case_ast_node(fb, ForeignBlockDecl, stmt); + ast_node(block, BlockStmt, fb->body); + cg_build_stmt_list(p, block->stmts); + case_end; + } + } + for (Ast *stmt : stmts) { + cg_build_stmt(p, stmt); + } +} + + +gb_internal void cg_build_when_stmt(cgProcedure *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) { + cg_build_stmt_list(p, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case Ast_BlockStmt: + cg_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); + break; + case Ast_WhenStmt: + cg_build_when_stmt(p, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid 'else' statement in 'when' statement"); + break; + } + } +} + |