Browse Source

Begin work on building statements

gingerBill 2 years ago
parent
commit
2a10c8fe5c
3 changed files with 344 additions and 8 deletions
  1. 23 8
      src/tilde_backend.cpp
  2. 34 0
      src/tilde_backend.hpp
  3. 287 0
      src/tilde_stmt.cpp

+ 23 - 8
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]);
 	}
 
 

+ 34 - 0
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);

+ 287 - 0
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;
+		}
+	}
+}
+