Browse Source

Basic `context` creation

gingerBill 2 years ago
parent
commit
ccb736411b
5 changed files with 451 additions and 293 deletions
  1. 0 289
      src/tilde_backend.cpp
  2. 14 2
      src/tilde_backend.hpp
  3. 146 1
      src/tilde_expr.cpp
  4. 290 0
      src/tilde_proc.cpp
  5. 1 1
      src/tilde_stmt.cpp

+ 0 - 289
src/tilde_backend.cpp

@@ -446,295 +446,6 @@ struct cgGlobalVariable {
 	bool is_initialized;
 };
 
-
-gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) {
-	GB_ASSERT(type != nullptr);
-	type = base_type(type);
-	GB_ASSERT(type->kind == Type_Proc);
-	TypeProc *pt = &type->Proc;
-
-	auto params = array_make<TB_PrototypeParam>(heap_allocator(), 0, pt->param_count);
-	if (pt->params) for (Entity *e : pt->params->Tuple.variables) {
-		TB_PrototypeParam param = {};
-
-		Type *t = core_type(e->type);
-		i64 sz = type_size_of(t);
-		switch (t->kind) {
-		case Type_Basic:
-			switch (t->Basic.kind) {
-			case Basic_bool:
-			case Basic_b8:
-			case Basic_b16:
-			case Basic_b32:
-			case Basic_b64:
-			case Basic_i8:
-			case Basic_u8:
-			case Basic_i16:
-			case Basic_u16:
-			case Basic_i32:
-			case Basic_u32:
-			case Basic_i64:
-			case Basic_u64:
-			case Basic_i128:
-			case Basic_u128:
-			case Basic_rune:
-			case Basic_int:
-			case Basic_uint:
-			case Basic_uintptr:
-				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
-				break;
-
-			case Basic_f16: param.dt = TB_TYPE_I16; break;
-			case Basic_f32: param.dt = TB_TYPE_F32; break;
-			case Basic_f64: param.dt = TB_TYPE_F64; break;
-
-			case Basic_complex32:
-			case Basic_complex64:
-			case Basic_complex128:
-			case Basic_quaternion64:
-			case Basic_quaternion128:
-			case Basic_quaternion256:
-				param.dt = TB_TYPE_PTR;
-				break;
-
-
-			case Basic_rawptr:
-				param.dt = TB_TYPE_PTR;
-				break;
-			case Basic_string:  // ^u8 + int
-				param.dt = TB_TYPE_PTR;
-				break;
-			case Basic_cstring: // ^u8
-				param.dt = TB_TYPE_PTR;
-				break;
-			case Basic_any:     // rawptr + ^Type_Info
-				param.dt = TB_TYPE_PTR;
-				break;
-
-			case Basic_typeid:
-				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
-				break;
-
-			// Endian Specific Types
-			case Basic_i16le:
-			case Basic_u16le:
-			case Basic_i32le:
-			case Basic_u32le:
-			case Basic_i64le:
-			case Basic_u64le:
-			case Basic_i128le:
-			case Basic_u128le:
-			case Basic_i16be:
-			case Basic_u16be:
-			case Basic_i32be:
-			case Basic_u32be:
-			case Basic_i64be:
-			case Basic_u64be:
-			case Basic_i128be:
-			case Basic_u128be:
-				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
-				break;
-
-			case Basic_f16le: param.dt = TB_TYPE_I16; break;
-			case Basic_f32le: param.dt = TB_TYPE_F32; break;
-			case Basic_f64le: param.dt = TB_TYPE_F64; break;
-
-			case Basic_f16be: param.dt = TB_TYPE_I16; break;
-			case Basic_f32be: param.dt = TB_TYPE_F32; break;
-			case Basic_f64be: param.dt = TB_TYPE_F64; break;
-			}
-
-		case Type_Pointer:
-		case Type_MultiPointer:
-		case Type_Proc:
-			param.dt = TB_TYPE_PTR;
-			break;
-
-		default:
-			switch (sz) {
-			case 1: param.dt = TB_TYPE_I8;  break;
-			case 2: param.dt = TB_TYPE_I16; break;
-			case 4: param.dt = TB_TYPE_I32; break;
-			case 8: param.dt = TB_TYPE_I64; break;
-			default:
-				param.dt = TB_TYPE_PTR;
-				break;
-			}
-		}
-
-		if (param.dt.width != 0) {
-			if (is_blank_ident(e->token)) {
-				param.name = alloc_cstring(temporary_allocator(), e->token.string);
-			}
-			array_add(&params, param);
-		}
-	}
-
-	auto results = array_make<TB_PrototypeParam>(heap_allocator(), 0, pt->result_count);
-	// if (pt->results) for (Entity *e : pt->params->Tuple.variables) {
-	// 	// TODO(bill):
-	// }
-
-
-	return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg);
-}
-
-gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false) {
-	GB_ASSERT(entity != nullptr);
-	GB_ASSERT(entity->kind == Entity_Procedure);
-	if (!entity->Procedure.is_foreign) {
-		if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) {
-			GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false));
-		}
-	}
-
-	String link_name = cg_get_entity_name(m, entity);
-
-	cgProcedure *p = nullptr;
-	{
-		StringHashKey key = string_hash_string(link_name);
-		cgValue *found = string_map_get(&m->members, key);
-		if (found) {
-			cg_add_entity(m, entity, *found);
-			p = string_map_must_get(&m->procedures, key);
-			if (!ignore_body && p->func != nullptr) {
-				return nullptr;
-			}
-		}
-	}
-
-	if (p == nullptr) {
-		p = gb_alloc_item(permanent_allocator(), cgProcedure);
-	}
-
-	p->module = m;
-	p->entity = entity;
-	p->name = link_name;
-
-	DeclInfo *decl = entity->decl_info;
-
-	ast_node(pl, ProcLit, decl->proc_lit);
-	Type *pt = base_type(entity->type);
-	GB_ASSERT(pt->kind == Type_Proc);
-
-	p->type           = entity->type;
-	p->type_expr      = decl->type_expr;
-	p->body           = pl->body;
-	p->inlining       = pl->inlining;
-	p->is_foreign     = entity->Procedure.is_foreign;
-	p->is_export      = entity->Procedure.is_export;
-	p->is_entry_point = false;
-
-	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->scope_stack.allocator   = a;
-	// map_init(&p->tuple_fix_map, 0);
-
-	TB_Linkage linkage = TB_LINKAGE_PRIVATE;
-	if (p->is_export) {
-		linkage = TB_LINKAGE_PUBLIC;
-	} else if (p->is_foreign || ignore_body) {
-		if (ignore_body) {
-			linkage = TB_LINKAGE_PUBLIC;
-		}
-		p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL);
-	}
-
-	if (p->symbol == nullptr)  {
-		p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
-		tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena());
-		p->symbol = cast(TB_Symbol *)p->func;
-	}
-
-	cgValue proc_value = cg_value(p->symbol, p->type);
-	cg_add_entity(m, entity, proc_value);
-	cg_add_member(m, p->name, proc_value);
-	cg_add_procedure_value(m, p);
-
-
-	return p;
-}
-
-gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &link_name, Type *type) {
-	auto *prev_found = string_map_get(&m->members, link_name);
-	GB_ASSERT_MSG(prev_found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name));
-
-	cgProcedure *p = gb_alloc_item(permanent_allocator(), cgProcedure);
-
-	p->module = m;
-	p->name = link_name;
-
-	p->type           = type;
-	p->type_expr      = nullptr;
-	p->body           = nullptr;
-	p->tags           = 0;
-	p->inlining       = ProcInlining_none;
-	p->is_foreign     = false;
-	p->is_export      = false;
-	p->is_entry_point = false;
-
-	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;
-	// map_init(&p->tuple_fix_map, 0);
-
-
-	TB_Linkage linkage = TB_LINKAGE_PRIVATE;
-
-	p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
-	tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena());
-	p->symbol = cast(TB_Symbol *)p->func;
-
-	cgValue proc_value = cg_value(p->symbol, p->type);
-	cg_add_member(m, p->name, proc_value);
-	cg_add_procedure_value(m, p);
-
-	return p;
-}
-
-gb_internal void cg_procedure_begin(cgProcedure *p) {
-	if (p == nullptr || p->func == nullptr) {
-		return;
-	}
-}
-
-gb_internal void cg_procedure_end(cgProcedure *p) {
-	if (p == nullptr || p->func == nullptr) {
-		return;
-	}
-	tb_inst_ret(p->func, 0, nullptr);
-	if (p->name == "main") {
-		TB_Arena *arena = tb_default_arena();
-		defer (arena->free(arena));
-		TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena);
-		defer (tb_funcopt_exit(opt));
-		tb_funcopt_print(opt);
-	}
-	tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST);
-}
-
-gb_internal void cg_procedure_generate(cgProcedure *p) {
-	if (p->body == nullptr) {
-		return;
-	}
-	cg_procedure_begin(p);
-	defer (cg_procedure_end(p));
-
-	if (p->name != "bug.main" &&
-	    p->name != "main") {
-		return;
-	}
-	cg_build_stmt(p, p->body);
-}
-
-
 #include "tilde_const.cpp"
 #include "tilde_expr.cpp"
 #include "tilde_proc.cpp"

+ 14 - 2
src/tilde_backend.hpp

@@ -113,7 +113,11 @@ enum cgDeferExitKind {
 	cgDeferExit_Branch,
 };
 
-
+struct cgContextData {
+	cgAddr ctx;
+	isize scope_index;
+	isize uses;
+};
 
 struct cgProcedure {
 	u32 flags;
@@ -144,6 +148,12 @@ struct cgProcedure {
 
 	cgTargetList *        target_list;
 	Array<cgBranchBlocks> branch_blocks;
+
+	Scope *curr_scope;
+	i32    scope_index;
+
+	Array<Scope *>       scope_stack;
+	Array<cgContextData> context_stack;
 };
 
 
@@ -214,4 +224,6 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero
 
 gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr);
 
-gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e);
+gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e);
+
+gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type);

+ 146 - 1
src/tilde_expr.cpp

@@ -1,3 +1,89 @@
+gb_internal cgContextData *cg_push_context_onto_stack(cgProcedure *p, cgAddr ctx) {
+	ctx.kind = cgAddr_Context;
+	cgContextData *cd = array_add_and_get(&p->context_stack);
+	cd->ctx = ctx;
+	cd->scope_index = p->scope_index;
+	return cd;
+}
+
+gb_internal cgAddr cg_find_or_generate_context_ptr(cgProcedure *p) {
+	if (p->context_stack.count > 0) {
+		return p->context_stack[p->context_stack.count-1].ctx;
+	}
+
+	Type *pt = base_type(p->type);
+	GB_ASSERT(pt->kind == Type_Proc);
+	GB_ASSERT(pt->Proc.calling_convention != ProcCC_Odin);
+
+	cgAddr c = cg_add_local(p, t_context, nullptr, true);
+	tb_node_append_attrib(c.addr.node, tb_function_attrib_variable(p->func, -1, "context", cg_debug_type(p->module, t_context)));
+	c.kind = cgAddr_Context;
+	// lb_emit_init_context(p, c);
+	cg_push_context_onto_stack(p, c);
+	// lb_add_debug_context_variable(p, c);
+
+	return c;
+}
+
+gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e) {
+	e = strip_entity_wrapping(e);
+	GB_ASSERT(e != nullptr);
+
+	GB_ASSERT(e->token.string != "_");
+
+	if (e->kind == Entity_Procedure) {
+		return cg_find_procedure_value_from_entity(m, e);
+	}
+
+	cgValue *found = nullptr;
+	rw_mutex_shared_lock(&m->values_mutex);
+	found = map_get(&m->values, e);
+	rw_mutex_shared_unlock(&m->values_mutex);
+	if (found) {
+		return *found;
+	}
+
+	// GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string));
+	return {};
+}
+
+gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *expr) {
+	GB_ASSERT(e != nullptr);
+	if (e->kind == Entity_Constant) {
+		Type *t = default_type(type_of_expr(expr));
+		cgValue v = cg_const_value(p, t, e->Constant.value);
+		GB_PANIC("TODO(bill): cg_add_global_generated");
+		// return cg_add_global_generated(p->module, t, v);
+		return {};
+	}
+
+
+	cgValue v = {};
+
+	cgModule *m = p->module;
+
+	rw_mutex_lock(&m->values_mutex);
+	cgValue *found = map_get(&m->values, e);
+	rw_mutex_unlock(&m->values_mutex);
+	if (found) {
+		v = *found;
+	} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
+		GB_PANIC("TODO(bill): cg_get_using_variable");
+		// NOTE(bill): Calculate the using variable every time
+		// v = cg_get_using_variable(p, e);
+	} else if (e->flags & EntityFlag_SoaPtrField) {
+		GB_PANIC("TODO(bill): cg_get_soa_variable_addr");
+		// return cg_get_soa_variable_addr(p, e);
+	}
+
+
+	if (v.node == nullptr) {
+		return cg_addr(cg_find_value_from_entity(m, e));
+	}
+
+	return cg_addr(v);
+}
+
 gb_internal cgValue cg_typeid(cgModule *m, Type *t) {
 	GB_ASSERT("TODO(bill): cg_typeid");
 	return {};
@@ -248,6 +334,65 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 }
 
 
+gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr);
 gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr) {
-	return {};
+	expr = unparen_expr(expr);
+
+	// IMPORTANT NOTE(bill):
+	// Selector Call Expressions (foo->bar(...))
+	// must only evaluate `foo` once as it gets transformed into
+	// `foo.bar(foo, ...)`
+	// And if `foo` is a procedure call or something more complex, storing the value
+	// once is a very good idea
+	// If a stored value is found, it must be removed from the cache
+	if (expr->state_flags & StateFlag_SelectorCallExpr) {
+		// lbAddr *pp = map_get(&p->selector_addr, expr);
+		// if (pp != nullptr) {
+		// 	lbAddr res = *pp;
+		// 	map_remove(&p->selector_addr, expr);
+		// 	return res;
+		// }
+	}
+	cgAddr addr = cg_build_addr_internal(p, expr);
+	if (expr->state_flags & StateFlag_SelectorCallExpr) {
+		// map_set(&p->selector_addr, expr, addr);
+	}
+	return addr;
 }
+
+
+gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) {
+	switch (expr->kind) {
+	case_ast_node(i, Implicit, expr);
+		cgAddr v = {};
+		switch (i->kind) {
+		case Token_context:
+			v = cg_find_or_generate_context_ptr(p);
+			break;
+		}
+
+		GB_ASSERT(v.addr.node != nullptr);
+		return v;
+	case_end;
+
+	case_ast_node(i, Ident, expr);
+		if (is_blank_ident(expr)) {
+			cgAddr val = {};
+			return val;
+		}
+		String name = i->token.string;
+		Entity *e = entity_of_node(expr);
+		return cg_build_addr_from_entity(p, e, expr);
+	case_end;
+	}
+
+	TokenPos token_pos = ast_token(expr).pos;
+	GB_PANIC("Unexpected address expression\n"
+	         "\tAst: %.*s @ "
+	         "%s\n",
+	         LIT(ast_strings[expr->kind]),
+	         token_pos_to_string(token_pos));
+
+
+	return {};
+}

+ 290 - 0
src/tilde_proc.cpp

@@ -1,3 +1,293 @@
+gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) {
+	GB_ASSERT(type != nullptr);
+	type = base_type(type);
+	GB_ASSERT(type->kind == Type_Proc);
+	TypeProc *pt = &type->Proc;
+
+	auto params = array_make<TB_PrototypeParam>(heap_allocator(), 0, pt->param_count);
+	if (pt->params) for (Entity *e : pt->params->Tuple.variables) {
+		TB_PrototypeParam param = {};
+
+		Type *t = core_type(e->type);
+		i64 sz = type_size_of(t);
+		switch (t->kind) {
+		case Type_Basic:
+			switch (t->Basic.kind) {
+			case Basic_bool:
+			case Basic_b8:
+			case Basic_b16:
+			case Basic_b32:
+			case Basic_b64:
+			case Basic_i8:
+			case Basic_u8:
+			case Basic_i16:
+			case Basic_u16:
+			case Basic_i32:
+			case Basic_u32:
+			case Basic_i64:
+			case Basic_u64:
+			case Basic_i128:
+			case Basic_u128:
+			case Basic_rune:
+			case Basic_int:
+			case Basic_uint:
+			case Basic_uintptr:
+				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
+				break;
+
+			case Basic_f16: param.dt = TB_TYPE_I16; break;
+			case Basic_f32: param.dt = TB_TYPE_F32; break;
+			case Basic_f64: param.dt = TB_TYPE_F64; break;
+
+			case Basic_complex32:
+			case Basic_complex64:
+			case Basic_complex128:
+			case Basic_quaternion64:
+			case Basic_quaternion128:
+			case Basic_quaternion256:
+				param.dt = TB_TYPE_PTR;
+				break;
+
+
+			case Basic_rawptr:
+				param.dt = TB_TYPE_PTR;
+				break;
+			case Basic_string:  // ^u8 + int
+				param.dt = TB_TYPE_PTR;
+				break;
+			case Basic_cstring: // ^u8
+				param.dt = TB_TYPE_PTR;
+				break;
+			case Basic_any:     // rawptr + ^Type_Info
+				param.dt = TB_TYPE_PTR;
+				break;
+
+			case Basic_typeid:
+				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
+				break;
+
+			// Endian Specific Types
+			case Basic_i16le:
+			case Basic_u16le:
+			case Basic_i32le:
+			case Basic_u32le:
+			case Basic_i64le:
+			case Basic_u64le:
+			case Basic_i128le:
+			case Basic_u128le:
+			case Basic_i16be:
+			case Basic_u16be:
+			case Basic_i32be:
+			case Basic_u32be:
+			case Basic_i64be:
+			case Basic_u64be:
+			case Basic_i128be:
+			case Basic_u128be:
+				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
+				break;
+
+			case Basic_f16le: param.dt = TB_TYPE_I16; break;
+			case Basic_f32le: param.dt = TB_TYPE_F32; break;
+			case Basic_f64le: param.dt = TB_TYPE_F64; break;
+
+			case Basic_f16be: param.dt = TB_TYPE_I16; break;
+			case Basic_f32be: param.dt = TB_TYPE_F32; break;
+			case Basic_f64be: param.dt = TB_TYPE_F64; break;
+			}
+
+		case Type_Pointer:
+		case Type_MultiPointer:
+		case Type_Proc:
+			param.dt = TB_TYPE_PTR;
+			break;
+
+		default:
+			switch (sz) {
+			case 1: param.dt = TB_TYPE_I8;  break;
+			case 2: param.dt = TB_TYPE_I16; break;
+			case 4: param.dt = TB_TYPE_I32; break;
+			case 8: param.dt = TB_TYPE_I64; break;
+			default:
+				param.dt = TB_TYPE_PTR;
+				break;
+			}
+		}
+
+		if (param.dt.width != 0) {
+			if (is_blank_ident(e->token)) {
+				param.name = alloc_cstring(temporary_allocator(), e->token.string);
+			}
+			array_add(&params, param);
+		}
+	}
+
+	auto results = array_make<TB_PrototypeParam>(heap_allocator(), 0, pt->result_count);
+	// if (pt->results) for (Entity *e : pt->params->Tuple.variables) {
+	// 	// TODO(bill):
+	// }
+
+
+	return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg);
+}
+
+gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false) {
+	GB_ASSERT(entity != nullptr);
+	GB_ASSERT(entity->kind == Entity_Procedure);
+	if (!entity->Procedure.is_foreign) {
+		if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) {
+			GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false));
+		}
+	}
+
+	String link_name = cg_get_entity_name(m, entity);
+
+	cgProcedure *p = nullptr;
+	{
+		StringHashKey key = string_hash_string(link_name);
+		cgValue *found = string_map_get(&m->members, key);
+		if (found) {
+			cg_add_entity(m, entity, *found);
+			p = string_map_must_get(&m->procedures, key);
+			if (!ignore_body && p->func != nullptr) {
+				return nullptr;
+			}
+		}
+	}
+
+	if (p == nullptr) {
+		p = gb_alloc_item(permanent_allocator(), cgProcedure);
+	}
+
+	p->module = m;
+	p->entity = entity;
+	p->name = link_name;
+
+	DeclInfo *decl = entity->decl_info;
+
+	ast_node(pl, ProcLit, decl->proc_lit);
+	Type *pt = base_type(entity->type);
+	GB_ASSERT(pt->kind == Type_Proc);
+
+	p->type           = entity->type;
+	p->type_expr      = decl->type_expr;
+	p->body           = pl->body;
+	p->inlining       = pl->inlining;
+	p->is_foreign     = entity->Procedure.is_foreign;
+	p->is_export      = entity->Procedure.is_export;
+	p->is_entry_point = false;
+
+	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->scope_stack.allocator   = a;
+	// map_init(&p->tuple_fix_map, 0);
+
+	TB_Linkage linkage = TB_LINKAGE_PRIVATE;
+	if (p->is_export) {
+		linkage = TB_LINKAGE_PUBLIC;
+	} else if (p->is_foreign || ignore_body) {
+		if (ignore_body) {
+			linkage = TB_LINKAGE_PUBLIC;
+		}
+		p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL);
+	}
+
+	if (p->symbol == nullptr)  {
+		p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
+		tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena());
+		p->symbol = cast(TB_Symbol *)p->func;
+	}
+
+	cgValue proc_value = cg_value(p->symbol, p->type);
+	cg_add_entity(m, entity, proc_value);
+	cg_add_member(m, p->name, proc_value);
+	cg_add_procedure_value(m, p);
+
+
+	return p;
+}
+
+gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &link_name, Type *type) {
+	auto *prev_found = string_map_get(&m->members, link_name);
+	GB_ASSERT_MSG(prev_found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name));
+
+	cgProcedure *p = gb_alloc_item(permanent_allocator(), cgProcedure);
+
+	p->module = m;
+	p->name = link_name;
+
+	p->type           = type;
+	p->type_expr      = nullptr;
+	p->body           = nullptr;
+	p->tags           = 0;
+	p->inlining       = ProcInlining_none;
+	p->is_foreign     = false;
+	p->is_export      = false;
+	p->is_entry_point = false;
+
+	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->context_stack.allocator = a;
+	// map_init(&p->tuple_fix_map, 0);
+
+
+	TB_Linkage linkage = TB_LINKAGE_PRIVATE;
+
+	p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
+	tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena());
+	p->symbol = cast(TB_Symbol *)p->func;
+
+	cgValue proc_value = cg_value(p->symbol, p->type);
+	cg_add_member(m, p->name, proc_value);
+	cg_add_procedure_value(m, p);
+
+	return p;
+}
+
+gb_internal void cg_procedure_begin(cgProcedure *p) {
+	if (p == nullptr || p->func == nullptr) {
+		return;
+	}
+}
+
+gb_internal void cg_procedure_end(cgProcedure *p) {
+	if (p == nullptr || p->func == nullptr) {
+		return;
+	}
+	tb_inst_ret(p->func, 0, nullptr);
+	if (p->name == "main") {
+		TB_Arena *arena = tb_default_arena();
+		defer (arena->free(arena));
+		TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena);
+		defer (tb_funcopt_exit(opt));
+		tb_funcopt_print(opt);
+	}
+	tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST);
+}
+
+gb_internal void cg_procedure_generate(cgProcedure *p) {
+	if (p->body == nullptr) {
+		return;
+	}
+	cg_procedure_begin(p);
+	defer (cg_procedure_end(p));
+
+	if (p->name != "bug.main" &&
+	    p->name != "main") {
+		return;
+	}
+	cg_build_stmt(p, p->body);
+}
+
+
+
 gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e) {
 	GB_ASSERT(is_type_proc(e->type));
 	e = strip_entity_wrapping(e);

+ 1 - 1
src/tilde_stmt.cpp

@@ -549,7 +549,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) {
 	case_end;
 
 	case_ast_node(as, AssignStmt, node);
-		// cg_build_assign_stmt(p, as);
+		cg_build_assign_stmt(p, as);
 	case_end;
 
 	case_ast_node(rs, ReturnStmt, node);