Browse Source

Mock out `defer` handling logic (before handling `defer` statements)

gingerBill 2 years ago
parent
commit
9abf43b0d2
4 changed files with 177 additions and 62 deletions
  1. 34 21
      src/tilde_backend.hpp
  2. 5 5
      src/tilde_expr.cpp
  3. 16 12
      src/tilde_proc.cpp
  4. 122 24
      src/tilde_stmt.cpp

+ 34 - 21
src/tilde_backend.hpp

@@ -111,7 +111,7 @@ struct cgTargetList {
 	TB_Node *     fallthrough_;
 };
 
-struct cgBranchBlocks {
+struct cgBranchRegions {
 	Ast *    label;
 	TB_Node *break_;
 	TB_Node *continue_;
@@ -123,12 +123,37 @@ enum cgDeferExitKind {
 	cgDeferExit_Branch,
 };
 
+enum cgDeferKind {
+	cgDefer_Node,
+	cgDefer_Proc,
+};
+
+struct cgDefer {
+	cgDeferKind kind;
+	isize       scope_index;
+	isize       context_stack_count;
+	TB_Node *   control_region;
+	union {
+		Ast *stmt;
+		struct {
+			cgValue deferred;
+			Slice<cgValue> result_as_args;
+		} proc;
+	};
+};
+
+
 struct cgContextData {
 	cgAddr ctx;
 	isize scope_index;
 	isize uses;
 };
 
+struct cgControlRegion {
+	TB_Node *control_region;
+	isize    scope_index;
+};
+
 struct cgProcedure {
 	u32 flags;
 	u16 state_flags;
@@ -162,15 +187,18 @@ struct cgProcedure {
 
 	Ast *curr_stmt;
 
-	cgTargetList *        target_list;
-	Array<cgBranchBlocks> branch_blocks;
+	cgTargetList *         target_list;
+	Array<cgDefer>         defer_stack;
+	Array<Scope *>         scope_stack;
+	Array<cgContextData>   context_stack;
+
+	Array<cgControlRegion> control_regions;
+	Array<cgBranchRegions> branch_regions;
 
 	Scope *curr_scope;
 	i32    scope_index;
 	bool   in_multi_assignment;
 
-	Array<Scope *>       scope_stack;
-	Array<cgContextData> context_stack;
 
 	PtrMap<Entity *, cgAddr> variable_map;
 };
@@ -275,20 +303,5 @@ gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgV
 
 gb_internal bool    cg_emit_goto(cgProcedure *p, TB_Node *control_region);
 
-gb_internal TB_Node *tb_inst_region_with_name(TB_Function *f, ptrdiff_t n, char const *name) {
-	#if 1
-	if (n < 0) {
-		n = gb_strlen(name);
-	}
-	static std::atomic<u32> id;
-
-	char *new_name = gb_alloc_array(temporary_allocator(), char, n+12);
-	n = -1 + gb_snprintf(new_name, n+11, "%.*s_%u", cast(int)n, name, 1+id.fetch_add(1));
-
-	name = new_name;
-	#endif
 
-	TB_Node *region = tb_inst_region(f);
-	tb_inst_set_region_name(region, n, name);
-	return region;
-}
+gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name);

+ 5 - 5
src/tilde_expr.cpp

@@ -1850,13 +1850,13 @@ gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block
 
 	case_ast_node(be, BinaryExpr, cond);
 		if (be->op.kind == Token_CmpAnd) {
-			TB_Node *block = tb_inst_region_with_name(p->func, -1, "cmp_and");
+			TB_Node *block = cg_control_region(p, "cmp_and");
 			cg_build_cond(p, be->left, block, false_block);
 			tb_inst_set_control(p->func, block);
 			cg_build_cond(p, be->right, true_block, false_block);
 			return no_comptime_short_circuit;
 		} else if (be->op.kind == Token_CmpOr) {
-			TB_Node *block = tb_inst_region_with_name(p->func, -1, "cmp_or");
+			TB_Node *block = cg_control_region(p, "cmp_or");
 			cg_build_cond(p, be->left, true_block, block);
 			tb_inst_set_control(p->func, block);
 			cg_build_cond(p, be->right, true_block, false_block);
@@ -2048,9 +2048,9 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 		cgValue incoming_values[2] = {};
 		TB_Node *incoming_regions[2] = {};
 
-		TB_Node *then  = tb_inst_region_with_name(p->func, -1, "if_then");
-		TB_Node *done  = tb_inst_region_with_name(p->func, -1, "if_done");
-		TB_Node *else_ = tb_inst_region_with_name(p->func, -1, "if_else");
+		TB_Node *then  = cg_control_region(p, "if_then");
+		TB_Node *done  = cg_control_region(p, "if_done");
+		TB_Node *else_ = cg_control_region(p, "if_else");
 
 		cg_build_cond(p, te->cond, then, else_);
 		tb_inst_set_control(p->func, then);

+ 16 - 12
src/tilde_proc.cpp

@@ -66,13 +66,15 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i
 
 	gbAllocator a = heap_allocator();
 	p->children.allocator      = a;
-	// p->defer_stmts.allocator   = a;
-	// p->blocks.allocator        = a;
-	p->branch_blocks.allocator = a;
-	p->context_stack.allocator = a;
+
+	p->defer_stack.allocator   = a;
 	p->scope_stack.allocator   = a;
+	p->context_stack.allocator = a;
+
+	p->control_regions.allocator = a;
+	p->branch_regions.allocator = a;
+
 	map_init(&p->variable_map);
-	// map_init(&p->tuple_fix_map, 0);
 
 	TB_Linkage linkage = TB_LINKAGE_PRIVATE;
 	if (p->is_export) {
@@ -126,13 +128,15 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li
 
 	gbAllocator a = heap_allocator();
 	p->children.allocator      = a;
-	// p->defer_stmts.allocator   = a;
-	// p->blocks.allocator        = a;
-	p->branch_blocks.allocator = a;
-	p->scope_stack.allocator = a;
+
+	p->defer_stack.allocator   = a;
+	p->scope_stack.allocator   = a;
 	p->context_stack.allocator = a;
+
+	p->control_regions.allocator = a;
+	p->branch_regions.allocator = a;
+
 	map_init(&p->variable_map);
-	// map_init(&p->tuple_fix_map, 0);
 
 
 	TB_Linkage linkage = TB_LINKAGE_PRIVATE;
@@ -170,8 +174,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) {
 	if (decl != nullptr) {
 		for_array(i, decl->labels) {
 			BlockLabel bl = decl->labels[i];
-			cgBranchBlocks bb = {bl.label, nullptr, nullptr};
-			array_add(&p->branch_blocks, bb);
+			cgBranchRegions bb = {bl.label, nullptr, nullptr};
+			array_add(&p->branch_regions, bb);
 		}
 	}
 

+ 122 - 24
src/tilde_stmt.cpp

@@ -6,6 +6,23 @@ gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region) {
 	return false;
 }
 
+gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name) {
+	TEMPORARY_ALLOCATOR_GUARD();
+
+	isize n = gb_strlen(name);
+
+	char *new_name = gb_alloc_array(temporary_allocator(), char, n+12);
+	n = -1 + gb_snprintf(new_name, n+11, "%.*s_%u", cast(int)n, name, p->control_regions.count);
+
+	TB_Node *region = tb_inst_region(p->func);
+	tb_inst_set_region_name(region, n, new_name);
+
+	GB_ASSERT(p->scope_index >= 0);
+	array_add(&p->control_regions, cgControlRegion{region, p->scope_index});
+
+	return region;
+}
+
 gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) {
 	GB_ASSERT(is_type_pointer(ptr.type));
 	Type *type = type_deref(ptr.type);
@@ -604,18 +621,18 @@ gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection
 
 
 
-gb_internal cgBranchBlocks cg_lookup_branch_blocks(cgProcedure *p, Ast *ident) {
+gb_internal cgBranchRegions cg_lookup_branch_regions(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) {
+	for (cgBranchRegions const &b : p->branch_regions) {
 		if (b.label == e->Label.node) {
 			return b;
 		}
 	}
 
 	GB_PANIC("Unreachable");
-	cgBranchBlocks empty = {};
+	cgBranchRegions empty = {};
 	return empty;
 }
 
@@ -630,7 +647,7 @@ gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Nod
 	if (label != nullptr) { // Set label blocks
 		GB_ASSERT(label->kind == Ast_Label);
 
-		for (cgBranchBlocks &b : p->branch_blocks) {
+		for (cgBranchRegions &b : p->branch_regions) {
 			GB_ASSERT(b.label != nullptr && label != nullptr);
 			GB_ASSERT(b.label->kind == Ast_Label);
 			if (b.label == label) {
@@ -701,16 +718,97 @@ gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgVal
 }
 
 
-gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) {
-	// TODO(bill): cg_scope_open
-}
+gb_internal void cg_build_defer_stmt(cgProcedure *p, cgDefer const &d) {
+	TB_Node *curr_region = tb_inst_get_control(p->func);
+	if (curr_region == nullptr) {
+		return;
+	}
+
+	// NOTE(bill): The prev block may defer injection before it's terminator
+	TB_Node *last_instr = nullptr;
+	if (curr_region->input_count) {
+		last_instr = *(curr_region->inputs + curr_region->input_count);
+	}
+	if (last_instr && TB_IS_NODE_TERMINATOR(last_instr->type)) {
+		// NOTE(bill): ReturnStmt defer stuff will be handled previously
+		return;
+	}
 
-gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region, bool pop_stack=true) {
-	// TODO(bill): cg_scope_close
+	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;
+
+	TB_Node *b = cg_control_region(p, "defer");
+	if (last_instr == nullptr) {
+		cg_emit_goto(p, b);
+	}
+
+	tb_inst_set_control(p->func, b);
+	if (d.kind == cgDefer_Node) {
+		cg_build_stmt(p, d.stmt);
+	} else if (d.kind == cgDefer_Proc) {
+		cg_emit_call(p, d.proc.deferred, d.proc.result_as_args);
+	}
 }
 
+
 gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) {
-	// TODO(bill): cg_emit_defer_stmts
+	isize count = p->defer_stack.count;
+	isize i = count;
+	while (i --> 0) {
+		cgDefer const &d = p->defer_stack[i];
+
+		if (kind == cgDeferExit_Default) {
+			if (p->scope_index == d.scope_index &&
+			    d.scope_index > 0) {
+				cg_build_defer_stmt(p, d);
+				array_pop(&p->defer_stack);
+				continue;
+			} else {
+				break;
+			}
+		} else if (kind == cgDeferExit_Return) {
+			cg_build_defer_stmt(p, d);
+		} else if (kind == cgDeferExit_Branch) {
+			GB_PANIC("TODO(bill): cgDeferExit_Branch");
+			GB_ASSERT(control_region != nullptr);
+			isize lower_limit = -1;
+			for (auto const &cr : p->control_regions) {
+				if (cr.control_region == control_region) {
+					lower_limit = cr.scope_index;
+					break;
+				}
+			}
+			GB_ASSERT(lower_limit >= 0);
+			if (lower_limit < d.scope_index) {
+				cg_build_defer_stmt(p, d);
+			}
+		}
+	}
+}
+
+gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) {
+	// TODO(bill): debug scope information
+
+	p->scope_index += 1;
+	array_add(&p->scope_stack, scope);
+}
+
+gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) {
+	cg_emit_defer_stmts(p, kind, control_region);
+	GB_ASSERT(p->scope_index > 0);
+
+	while (p->context_stack.count > 0) {
+		auto *ctx = &p->context_stack[p->context_stack.count-1];
+		if (ctx->scope_index < p->scope_index) {
+			break;
+		}
+		array_pop(&p->context_stack);
+	}
+
+	p->scope_index -= 1;
+	array_pop(&p->scope_stack);
 }
 
 
@@ -864,17 +962,17 @@ gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) {
 	defer (cg_scope_close(p, cgDeferExit_Default, nullptr));
 
 	if (is->init != nullptr) {
-		TB_Node *init = tb_inst_region_with_name(p->func, -1, "if_init");
+		TB_Node *init = cg_control_region(p, "if_init");
 		cg_emit_goto(p, init);
 		tb_inst_set_control(p->func, init);
 		cg_build_stmt(p, is->init);
 	}
 
-	TB_Node *then  = tb_inst_region_with_name(p->func, -1, "if_then");
-	TB_Node *done  = tb_inst_region_with_name(p->func, -1, "if_done");
+	TB_Node *then  = cg_control_region(p, "if_then");
+	TB_Node *done  = cg_control_region(p, "if_done");
 	TB_Node *else_ = done;
 	if (is->else_stmt != nullptr) {
-		else_ = tb_inst_region_with_name(p->func, -1, "if_else");
+		else_ = cg_control_region(p, "if_else");
 	}
 
 	cgValue cond = cg_build_cond(p, is->cond, then, else_);
@@ -916,20 +1014,20 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) {
 	defer (cg_scope_close(p, cgDeferExit_Default, nullptr));
 
 	if (fs->init != nullptr) {
-		TB_Node *init = tb_inst_region_with_name(p->func, -1, "for_init");
+		TB_Node *init = cg_control_region(p, "for_init");
 		cg_emit_goto(p, init);
 		tb_inst_set_control(p->func, init);
 		cg_build_stmt(p, fs->init);
 	}
-	TB_Node *body = tb_inst_region_with_name(p->func, -1, "for_body");
-	TB_Node *done = tb_inst_region_with_name(p->func, -1, "for_done");
+	TB_Node *body = cg_control_region(p, "for_body");
+	TB_Node *done = cg_control_region(p, "for_done");
 	TB_Node *loop = body;
 	if (fs->cond != nullptr) {
-		loop = tb_inst_region_with_name(p->func, -1, "for_loop");
+		loop = cg_control_region(p, "for_loop");
 	}
 	TB_Node *post = loop;
 	if (fs->post != nullptr) {
-		post = tb_inst_region_with_name(p->func, -1, "for_post");
+		post = cg_control_region(p, "for_post");
 	}
 
 	cg_emit_goto(p, loop);
@@ -1018,7 +1116,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) {
 		tag = cg_const_bool(p, t_bool, true);
 	}
 
-	TB_Node *done = tb_inst_region_with_name(p->func, -1, "switch_done");
+	TB_Node *done = cg_control_region(p, "switch_done");
 
 	ast_node(body, BlockStmt, ss->body);
 
@@ -1036,7 +1134,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) {
 		Ast *clause = body->stmts[i];
 		ast_node(cc, CaseClause, clause);
 
-		body_regions[i] = tb_inst_region_with_name(p->func, -1, cc->list.count == 0 ? "switch_default_body" : "switch_case_body");
+		body_regions[i] = cg_control_region(p, cc->list.count == 0 ? "switch_default_body" : "switch_case_body");
 		body_scopes[i] = cc->scope;
 		if (cc->list.count == 0) {
 			default_block = body_regions[i];
@@ -1110,7 +1208,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) {
 		if (!is_trivial) for (Ast *expr : cc->list) {
 			expr = unparen_expr(expr);
 
-			next_cond = tb_inst_region_with_name(p->func, -1, "switch_case_next");
+			next_cond = cg_control_region(p, "switch_case_next");
 
 			cgValue cond = {};
 			if (is_ast_range(expr)) {
@@ -1231,7 +1329,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) {
 	case_ast_node(bs, BlockStmt, node);
 		TB_Node *done = nullptr;
 		if (bs->label != nullptr) {
-			done = tb_inst_region_with_name(p->func, -1, "block_done");
+			done = cg_control_region(p, "block_done");
 			cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr);
 			tl->is_block = true;
 		}
@@ -1316,7 +1414,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) {
  		TB_Node *block = nullptr;
 
 		if (bs->label != nullptr) {
-			cgBranchBlocks bb = cg_lookup_branch_blocks(p, bs->label);
+			cgBranchRegions bb = cg_lookup_branch_regions(p, bs->label);
 			switch (bs->token.kind) {
 			case Token_break:    block = bb.break_;    break;
 			case Token_continue: block = bb.continue_; break;