Browse Source

ret, unreachable, param, deref

gingerBill 9 years ago
parent
commit
41e7cadb8d
11 changed files with 411 additions and 214 deletions
  1. 5 8
      examples/test.c
  2. 4 15
      examples/test.ll
  3. 0 6
      examples/test.odin
  4. 3 4
      run.bat
  5. 10 2
      src/checker/checker.cpp
  6. 4 4
      src/checker/statements.cpp
  7. 3 2
      src/codegen/codegen.cpp
  8. 49 15
      src/codegen/print.cpp
  9. 329 154
      src/codegen/ssa.cpp
  10. 3 3
      src/parser.cpp
  11. 1 1
      src/printer.cpp

+ 5 - 8
examples/test.c

@@ -1,11 +1,8 @@
+void test(void) {
+}
+
 int main() {
 int main() {
-	int x = 15;
-	int y = 4;
-	x = x & (~y);
-	if (x > 0) {
-		x = 123;
-	} else {
-		x = 321;
-	}
+	void (*f)(void) = test;
+
 	return 0;
 	return 0;
 }
 }

+ 4 - 15
examples/test.ll

@@ -1,17 +1,6 @@
+; ModuleID = '..\examples/test.bc'
+
 define void @main() {
 define void @main() {
-entry:
-	%0 = alloca i64, align 8 ; x
-	store i64 zeroinitializer, i64* %0
-	store i64 15, i64* %0
-	%1 = load i64, i64* %0
-	%2 = icmp sgt i64 %1, 0
-	br i1 %2, label %if-then, label %if-else
-if-then:
-	store i64 123, i64* %0
-	br label %if-end
-if-else:
-	store i64 321, i64* %0
-	br label %if-end
-if-end:
-	ret void
+"entry - 0":
+  ret void
 }
 }

+ 0 - 6
examples/test.odin

@@ -1,8 +1,2 @@
 main :: proc() {
 main :: proc() {
-	x : int = 15;
-	if x > 0 {
-		x = 123;
-	} else {
-		x = 321;
-	}
 }
 }

+ 3 - 4
run.bat

@@ -2,8 +2,7 @@
 
 
 
 
 rem del "..\examples\test.bc"
 rem del "..\examples\test.bc"
-call ..\bin\odin.exe ..\examples/test.odin
-call lli ..\examples/test.ll
-rem call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc
-rem call llvm-dis ..\examples/test.bc -o ..\examples/test.ll
+call ..\bin\odin.exe ..\examples/test.odin && lli ..\examples/test.ll
+call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc
+call llvm-dis ..\examples/test.bc -o ..\examples/test.ll
 call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll
 call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll

+ 10 - 2
src/checker/checker.cpp

@@ -101,6 +101,7 @@ struct Scope {
 	Scope *prev, *next;
 	Scope *prev, *next;
 	Scope *first_child, *last_child;
 	Scope *first_child, *last_child;
 	Map<Entity *> elements; // Key: String
 	Map<Entity *> elements; // Key: String
+	gbArray(AstNode *) deferred_stmts;
 };
 };
 
 
 enum ExpressionKind {
 enum ExpressionKind {
@@ -154,13 +155,14 @@ struct CheckerContext {
 	DeclInfo *decl;
 	DeclInfo *decl;
 };
 };
 
 
+// NOTE(bill): Symbol tables
 struct CheckerInfo {
 struct CheckerInfo {
 	Map<TypeAndValue>      types;       // Key: AstNode * | Expression -> Type (and value)
 	Map<TypeAndValue>      types;       // Key: AstNode * | Expression -> Type (and value)
 	Map<Entity *>          definitions; // Key: AstNode * | Identifier -> Entity
 	Map<Entity *>          definitions; // Key: AstNode * | Identifier -> Entity
 	Map<Entity *>          uses;        // Key: AstNode * | Identifier -> Entity
 	Map<Entity *>          uses;        // Key: AstNode * | Identifier -> Entity
 	Map<Scope *>           scopes;      // Key: AstNode * | Node       -> Scope
 	Map<Scope *>           scopes;      // Key: AstNode * | Node       -> Scope
 	Map<ExpressionInfo>    untyped;     // Key: AstNode * | Expression -> ExpressionInfo
 	Map<ExpressionInfo>    untyped;     // Key: AstNode * | Expression -> ExpressionInfo
-	Map<DeclInfo *> entities;    // Key: Entity *
+	Map<DeclInfo *>        entities;    // Key: Entity *
 };
 };
 
 
 struct Checker {
 struct Checker {
@@ -190,6 +192,7 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) {
 	Scope *s = gb_alloc_item(allocator, Scope);
 	Scope *s = gb_alloc_item(allocator, Scope);
 	s->parent = parent;
 	s->parent = parent;
 	map_init(&s->elements, gb_heap_allocator());
 	map_init(&s->elements, gb_heap_allocator());
+	gb_array_init(s->deferred_stmts, gb_heap_allocator());
 	if (parent != NULL && parent != universal_scope) {
 	if (parent != NULL && parent != universal_scope) {
 		DLIST_APPEND(parent->first_child, parent->last_child, s);
 		DLIST_APPEND(parent->first_child, parent->last_child, s);
 	}
 	}
@@ -504,6 +507,12 @@ void check_close_scope(Checker *c) {
 	c->context.scope = c->context.scope->parent;
 	c->context.scope = c->context.scope->parent;
 }
 }
 
 
+void check_add_deferred_stmt(Checker *c, AstNode *stmt) {
+	GB_ASSERT(stmt != NULL);
+	GB_ASSERT(is_ast_node_stmt(stmt));
+	gb_array_append(c->context.scope->deferred_stmts, stmt);
+}
+
 void push_procedure(Checker *c, Type *procedure_type) {
 void push_procedure(Checker *c, Type *procedure_type) {
 	gb_array_append(c->procedure_stack, procedure_type);
 	gb_array_append(c->procedure_stack, procedure_type);
 }
 }
@@ -512,7 +521,6 @@ void pop_procedure(Checker *c) {
 	gb_array_pop(c->procedure_stack);
 	gb_array_pop(c->procedure_stack);
 }
 }
 
 
-
 void add_curr_ast_file(Checker *c, AstFile *file) {
 void add_curr_ast_file(Checker *c, AstFile *file) {
 	gb_zero_item(&c->error_collector);
 	gb_zero_item(&c->error_collector);
 	c->curr_ast_file = file;
 	c->curr_ast_file = file;

+ 4 - 4
src/checker/statements.cpp

@@ -724,7 +724,6 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 	case_end;
 	case_end;
 
 
 	case_ast_node(fs, ForStmt, node);
 	case_ast_node(fs, ForStmt, node);
-		flags |= Statement_BreakAllowed | Statement_ContinueAllowed;
 		check_open_scope(c, node);
 		check_open_scope(c, node);
 		defer (check_close_scope(c));
 		defer (check_close_scope(c));
 
 
@@ -739,9 +738,9 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 				      "Non-boolean condition in `for` statement");
 				      "Non-boolean condition in `for` statement");
 			}
 			}
 		}
 		}
-		if (fs->end != NULL)
-			check_stmt(c, fs->end, 0);
-		check_stmt(c, fs->body, flags);
+		if (fs->post != NULL)
+			check_stmt(c, fs->post, 0);
+		check_stmt(c, fs->body, flags | Statement_BreakAllowed | Statement_ContinueAllowed);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ds, DeferStmt, node);
 	case_ast_node(ds, DeferStmt, node);
@@ -752,6 +751,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			c->in_defer = true;
 			c->in_defer = true;
 			check_stmt(c, ds->stmt, 0);
 			check_stmt(c, ds->stmt, 0);
 			c->in_defer = out_in_defer;
 			c->in_defer = out_in_defer;
+			check_add_deferred_stmt(c, ds->stmt);
 		}
 		}
 	case_end;
 	case_end;
 
 

+ 3 - 2
src/codegen/codegen.cpp

@@ -36,6 +36,7 @@ void ssa_gen_code(ssaGen *s) {
 	ssaModule *m = &s->module;
 	ssaModule *m = &s->module;
 	CheckerInfo *info = m->info;
 	CheckerInfo *info = m->info;
 	gbAllocator a = m->allocator;
 	gbAllocator a = m->allocator;
+
 	gb_for_array(i, info->entities.entries) {
 	gb_for_array(i, info->entities.entries) {
 		auto *entry = &info->entities.entries[i];
 		auto *entry = &info->entities.entries[i];
 		Entity *e = cast(Entity *)cast(uintptr)entry->key;
 		Entity *e = cast(Entity *)cast(uintptr)entry->key;
@@ -66,8 +67,8 @@ void ssa_gen_code(ssaGen *s) {
 	gb_for_array(i, m->members.entries) {
 	gb_for_array(i, m->members.entries) {
 		auto *entry = &m->members.entries[i];
 		auto *entry = &m->members.entries[i];
 		ssaValue *v = entry->value;
 		ssaValue *v = entry->value;
-		if (v->kind == ssaValue_Procedure)
-			ssa_build_procedure(v);
+		if (v->kind == ssaValue_Proc)
+			ssa_build_proc(v);
 	}
 	}
 
 
 	ssa_print_llvm_ir(&s->output_file, &s->module);
 	ssa_print_llvm_ir(&s->output_file, &s->module);

+ 49 - 15
src/codegen/print.cpp

@@ -146,7 +146,7 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
 			if (i > 0) ssa_fprintf(f, ", ");
 			if (i > 0) ssa_fprintf(f, ", ");
 			ssa_print_type(f, s, &t->procedure.params[i]);
 			ssa_print_type(f, s, &t->procedure.params[i]);
 		}
 		}
-		ssa_fprintf(f, ") ");
+		ssa_fprintf(f, ")*");
 		break;
 		break;
 	}
 	}
 }
 }
@@ -201,6 +201,12 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
 	}
 	}
 }
 }
 
 
+void ssa_print_block_name(gbFile *f, ssaBlock *b) {
+	ssa_fprintf(f, "\"");
+	ssa_print_escape_string(f, b->label);
+	ssa_fprintf(f, " - %d", b->id);
+	ssa_fprintf(f, "\"");
+}
 
 
 void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) {
 void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) {
 	if (value == NULL) {
 	if (value == NULL) {
@@ -208,18 +214,21 @@ void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint)
 		return;
 		return;
 	}
 	}
 	switch (value->kind) {
 	switch (value->kind) {
+	case ssaValue_Constant:
+		ssa_print_exact_value(f, m, value->constant.value, type_hint);
+		break;
 	case ssaValue_TypeName:
 	case ssaValue_TypeName:
 		ssa_print_encoded_local(f, value->type_name.entity->token.string);
 		ssa_print_encoded_local(f, value->type_name.entity->token.string);
 		break;
 		break;
 	case ssaValue_Global:
 	case ssaValue_Global:
 		ssa_print_encoded_global(f, value->global.entity->token.string);
 		ssa_print_encoded_global(f, value->global.entity->token.string);
 		break;
 		break;
-	case ssaValue_Procedure:
+	case ssaValue_Param:
+		ssa_print_encoded_local(f, value->param.entity->token.string);
+		break;
+	case ssaValue_Proc:
 		ssa_print_encoded_global(f, value->proc.entity->token.string);
 		ssa_print_encoded_global(f, value->proc.entity->token.string);
 		break;
 		break;
-	case ssaValue_Constant: {
-		ssa_print_exact_value(f, m, value->constant.value, type_hint);
-	} break;
 	case ssaValue_Instr:
 	case ssaValue_Instr:
 		ssa_fprintf(f, "%%%d", value->id);
 		ssa_fprintf(f, "%%%d", value->id);
 		break;
 		break;
@@ -301,12 +310,32 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 			ssa_fprintf(f, ", ", instr->br.cond->id);
 			ssa_fprintf(f, ", ", instr->br.cond->id);
 		}
 		}
 		ssa_fprintf(f, "label ");
 		ssa_fprintf(f, "label ");
-		ssa_print_encoded_local(f, instr->br.true_block->label);
+		ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.true_block);
 		if (instr->br.false_block != NULL) {
 		if (instr->br.false_block != NULL) {
 			ssa_fprintf(f, ", label ");
 			ssa_fprintf(f, ", label ");
-			ssa_print_encoded_local(f, instr->br.false_block->label);
+			ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.false_block);
+		}
+		ssa_fprintf(f, "\n");
+	} break;
+
+	case ssaInstr_Ret: {
+		auto *ret = &instr->ret;
+		ssa_fprintf(f, "ret ");
+		if (ret->value == NULL) {
+			ssa_fprintf(f, "void");
+		} else {
+			Type *t = ssa_value_type(ret->value);
+			ssa_print_type(f, m->sizes, t);
+			ssa_fprintf(f, " ");
+			ssa_print_value(f, m, ret->value, t);
 		}
 		}
+
 		ssa_fprintf(f, "\n");
 		ssa_fprintf(f, "\n");
+
+	} break;
+
+	case ssaInstr_Unreachable: {
+		ssa_fprintf(f, "unreachable\n");
 	} break;
 	} break;
 
 
 	case ssaInstr_BinaryOp: {
 	case ssaInstr_BinaryOp: {
@@ -391,6 +420,10 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 }
 }
 
 
 void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
 void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
+	if (m->layout.len > 0) {
+		ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
+	}
+
 	gb_for_array(member_index, m->members.entries) {
 	gb_for_array(member_index, m->members.entries) {
 		auto *entry = &m->members.entries[member_index];
 		auto *entry = &m->members.entries[member_index];
 		ssaValue *v = entry->value;
 		ssaValue *v = entry->value;
@@ -412,7 +445,7 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
 			ssa_fprintf(f, ", align %td\n", type_align_of(m->sizes, gb_heap_allocator(), g->entity->type));
 			ssa_fprintf(f, ", align %td\n", type_align_of(m->sizes, gb_heap_allocator(), g->entity->type));
 		} break;
 		} break;
 
 
-		case ssaValue_Procedure: {
+		case ssaValue_Proc: {
 			ssaProcedure *proc = &v->proc;
 			ssaProcedure *proc = &v->proc;
 			if (proc->body == NULL) {
 			if (proc->body == NULL) {
 				ssa_fprintf(f, "declare ");
 				ssa_fprintf(f, "declare ");
@@ -450,19 +483,20 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
 				ssa_fprintf(f, "\n");
 				ssa_fprintf(f, "\n");
  			} else {
  			} else {
  				ssa_fprintf(f, "{\n");
  				ssa_fprintf(f, "{\n");
- 				gb_for_array(i, proc->blocks.entries) {
- 					ssaBlock *block = &proc->blocks.entries[i].value->block;
- 					ssa_fprintf(f, "%.*s:\n", LIT(block->label));
+ 				gb_for_array(i, proc->blocks) {
+ 					ssaBlock *block = proc->blocks[i];
+
+ 					if (i > 0) ssa_fprintf(f, "\n");
+ 					ssa_print_block_name(f, block);
+ 					ssa_fprintf(f, ":\n");
+
  					gb_for_array(j, block->instrs) {
  					gb_for_array(j, block->instrs) {
  						ssaValue *value = block->instrs[j];
  						ssaValue *value = block->instrs[j];
  						ssa_print_instr(f, m, value);
  						ssa_print_instr(f, m, value);
  					}
  					}
  				}
  				}
 
 
- 				if (proc_type->result_count == 0) {
- 					ssa_fprintf(f, "\tret void\n");
- 				}
- 				ssa_fprintf(f, "}\n");
+ 				ssa_fprintf(f, "}\n\n");
  			}
  			}
 
 
 		} break;
 		} break;

+ 329 - 154
src/codegen/ssa.cpp

@@ -9,6 +9,8 @@ struct ssaModule {
 	BaseTypeSizes sizes;
 	BaseTypeSizes sizes;
 	gbAllocator allocator;
 	gbAllocator allocator;
 
 
+	String layout;
+
 	Map<ssaValue *> values;  // Key: Entity *
 	Map<ssaValue *> values;  // Key: Entity *
 	Map<ssaValue *> members; // Key: String
 	Map<ssaValue *> members; // Key: String
 	i32 global_string_index;
 	i32 global_string_index;
@@ -26,6 +28,13 @@ struct ssaBlock {
 	gbArray(ssaValue *) values;
 	gbArray(ssaValue *) values;
 };
 };
 
 
+struct ssaTargetList {
+	ssaTargetList *prev;
+	ssaBlock *break_;
+	ssaBlock *continue_;
+	ssaBlock *fallthrough_;
+};
+
 struct ssaProcedure {
 struct ssaProcedure {
 	ssaModule *module;
 	ssaModule *module;
 	String name;
 	String name;
@@ -35,8 +44,10 @@ struct ssaProcedure {
 	AstNode *type_expr;
 	AstNode *type_expr;
 	AstNode *body;
 	AstNode *body;
 
 
-	Map<ssaValue *> blocks;
+	gbArray(ssaBlock *) blocks;
 	ssaBlock *curr_block;
 	ssaBlock *curr_block;
+	ssaTargetList *target_list;
+
 	gbArray(ssaValue *) anonymous_procedures;
 	gbArray(ssaValue *) anonymous_procedures;
 };
 };
 
 
@@ -50,6 +61,8 @@ struct ssaProcedure {
 	SSA_INSTR_KIND(GetElementPtr), \
 	SSA_INSTR_KIND(GetElementPtr), \
 	SSA_INSTR_KIND(Convert), \
 	SSA_INSTR_KIND(Convert), \
 	SSA_INSTR_KIND(Br), \
 	SSA_INSTR_KIND(Br), \
+	SSA_INSTR_KIND(Ret), \
+	SSA_INSTR_KIND(Unreachable), \
 	SSA_INSTR_KIND(BinaryOp), \
 	SSA_INSTR_KIND(BinaryOp), \
 	SSA_INSTR_KIND(Count),
 	SSA_INSTR_KIND(Count),
 
 
@@ -109,12 +122,13 @@ struct ssaInstr {
 			isize     index_count;
 			isize     index_count;
 			b32       inbounds;
 			b32       inbounds;
 		} get_element_ptr;
 		} get_element_ptr;
-
 		struct {
 		struct {
 			ssaValue *cond;
 			ssaValue *cond;
 			ssaBlock *true_block;
 			ssaBlock *true_block;
 			ssaBlock *false_block;
 			ssaBlock *false_block;
 		} br;
 		} br;
+		struct { ssaValue *value; } ret;
+		struct {} unreachable;
 
 
 		struct {
 		struct {
 			Type *type;
 			Type *type;
@@ -137,8 +151,9 @@ enum ssaValueKind {
 	ssaValue_Constant,
 	ssaValue_Constant,
 	ssaValue_TypeName,
 	ssaValue_TypeName,
 	ssaValue_Global,
 	ssaValue_Global,
-	ssaValue_Procedure,
+	ssaValue_Param,
 
 
+	ssaValue_Proc,
 	ssaValue_Block,
 	ssaValue_Block,
 	ssaValue_Instr,
 	ssaValue_Instr,
 
 
@@ -164,9 +179,14 @@ struct ssaValue {
 			Type *    type;
 			Type *    type;
 			ssaValue *value;
 			ssaValue *value;
 		} global;
 		} global;
-		ssaProcedure   proc;
-		ssaBlock       block;
-		ssaInstr instr;
+		struct {
+			ssaProcedure *parent;
+			Entity *entity;
+			Type *  type;
+		} param;
+		ssaProcedure proc;
+		ssaBlock     block;
+		ssaInstr     instr;
 	};
 	};
 };
 };
 
 
@@ -256,14 +276,16 @@ void ssa_instr_set_type(ssaInstr *instr, Type *type) {
 
 
 Type *ssa_value_type(ssaValue *value) {
 Type *ssa_value_type(ssaValue *value) {
 	switch (value->kind) {
 	switch (value->kind) {
+	case ssaValue_Constant:
+		return value->constant.type;
 	case ssaValue_TypeName:
 	case ssaValue_TypeName:
 		return value->type_name.type;
 		return value->type_name.type;
 	case ssaValue_Global:
 	case ssaValue_Global:
 		return value->global.type;
 		return value->global.type;
-	case ssaValue_Procedure:
+	case ssaValue_Param:
+		return value->param.type;
+	case ssaValue_Proc:
 		return value->proc.type;
 		return value->proc.type;
-	case ssaValue_Constant:
-		return value->constant.type;
 	case ssaValue_Instr:
 	case ssaValue_Instr:
 		return ssa_instr_type(&value->instr);
 		return ssa_instr_type(&value->instr);
 	}
 	}
@@ -279,7 +301,7 @@ void ssa_value_set_type(ssaValue *value, Type *type) {
 	case ssaValue_Global:
 	case ssaValue_Global:
 		value->global.type = type;
 		value->global.type = type;
 		break;
 		break;
-	case ssaValue_Procedure:
+	case ssaValue_Proc:
 		value->proc.type = type;
 		value->proc.type = type;
 		break;
 		break;
 	case ssaValue_Constant:
 	case ssaValue_Constant:
@@ -329,7 +351,13 @@ ssaValue *ssa_make_value_global(gbAllocator a, Entity *e, ssaValue *value) {
 	v->global.value = value;
 	v->global.value = value;
 	return v;
 	return v;
 }
 }
-
+ssaValue *ssa_make_value_param(gbAllocator a, ssaProcedure *parent, Entity *e) {
+	ssaValue *v = ssa_alloc_value(a, ssaValue_Param);
+	v->param.parent = parent;
+	v->param.entity = e;
+	v->param.type   = e->type;
+	return v;
+}
 
 
 
 
 ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e) {
 ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e) {
@@ -408,6 +436,25 @@ ssaValue *ssa_make_instr_br(ssaProcedure *p, ssaValue *cond, ssaBlock *true_bloc
 	return v;
 	return v;
 }
 }
 
 
+ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) {
+	ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Unreachable);
+	if (p->curr_block) {
+		gb_array_append(p->curr_block->values, v);
+	}
+	return v;
+}
+
+ssaValue *ssa_make_instr_ret(ssaProcedure *p, ssaValue *value) {
+	ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Ret);
+	v->instr.ret.value = value;
+	if (p->curr_block) {
+		gb_array_append(p->curr_block->values, v);
+	}
+	return v;
+}
+
+
+
 ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
 ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
 	ssaValue *v = ssa_alloc_value(a, ssaValue_Constant);
 	ssaValue *v = ssa_alloc_value(a, ssaValue_Constant);
 	v->constant.type  = type;
 	v->constant.type  = type;
@@ -416,7 +463,7 @@ ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
 }
 }
 
 
 ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclInfo *decl, ssaModule *m) {
 ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclInfo *decl, ssaModule *m) {
-	ssaValue *v = ssa_alloc_value(a, ssaValue_Procedure);
+	ssaValue *v = ssa_alloc_value(a, ssaValue_Proc);
 	v->proc.module = m;
 	v->proc.module = m;
 	v->proc.entity = e;
 	v->proc.entity = e;
 	v->proc.type   = e->type;
 	v->proc.type   = e->type;
@@ -433,7 +480,7 @@ ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope,
 	v->block.parent = proc;
 	v->block.parent = proc;
 
 
 	gb_array_init(v->block.instrs, gb_heap_allocator());
 	gb_array_init(v->block.instrs, gb_heap_allocator());
-	gb_array_init(v->block.values,       gb_heap_allocator());
+	gb_array_init(v->block.values, gb_heap_allocator());
 
 
 	return v;
 	return v;
 }
 }
@@ -467,48 +514,6 @@ ssaValue *ssa_add_global_string(ssaProcedure *proc, ExactValue value) {
 	return g;
 	return g;
 }
 }
 
 
-ssaValue *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) {
-	Scope *scope = NULL;
-	Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
-	if (found) scope = *found;
-
-	// IMPORTANT TODO(bill): Check for duplicate labels and replace in a sane way
-	// if (map_get(&proc->blocks, hash_string(label)) != NULL) {
-	// 	GB_PANIC("Block of name `%.*s` already exists", LIT(label));
-	// }
-
-	ssaValue *block = ssa_make_value_block(proc, node, scope, label);
-	map_set(&proc->blocks, hash_string(label), block);
-	return block;
-}
-
-
-void ssa_begin_procedure_body(ssaProcedure *proc) {
-	map_init(&proc->blocks, gb_heap_allocator());
-	ssaValue *b = ssa_add_block(proc, proc->body, make_string("entry"));
-	proc->curr_block = &b->block;
-}
-
-
-void ssa_end_procedure_body(ssaProcedure *proc) {
-// Number registers
-	i32 reg_id = 0;
-	gb_for_array(i, proc->blocks.entries) {
-		ssaBlock *b = &proc->blocks.entries[i].value->block;
-		gb_for_array(j, b->instrs) {
-			ssaValue *value = b->instrs[j];
-			ssaInstr *instr = &value->instr;
-			switch (instr->kind) {
-			case ssaInstr_Store:
-			case ssaInstr_Br:
-				continue;
-			}
-			value->id = reg_id;
-			reg_id++;
-		}
-	}
-}
-
 
 
 b32 ssa_is_blank_ident(AstNode *node) {
 b32 ssa_is_blank_ident(AstNode *node) {
 	if (node->kind == AstNode_Ident) {
 	if (node->kind == AstNode_Ident) {
@@ -519,15 +524,25 @@ b32 ssa_is_blank_ident(AstNode *node) {
 }
 }
 
 
 
 
+
 ssaValue *ssa_block_emit(ssaBlock *b, ssaValue *instr) {
 ssaValue *ssa_block_emit(ssaBlock *b, ssaValue *instr) {
 	instr->instr.parent = b;
 	instr->instr.parent = b;
-	gb_array_append(b->instrs, instr);
+	if (b) {
+		gb_array_append(b->instrs, instr);
+	}
 	return instr;
 	return instr;
-}
 
 
+}
 ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) {
 ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) {
 	return ssa_block_emit(proc->curr_block, instr);
 	return ssa_block_emit(proc->curr_block, instr);
 }
 }
+ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) {
+	return ssa_emit(p, ssa_make_instr_store(p, address, value));
+}
+ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) {
+	return ssa_emit(p, ssa_make_instr_load(p, address));
+}
+
 
 
 
 
 ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e) {
 ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e) {
@@ -542,14 +557,13 @@ ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name) {
 	return NULL;
 	return NULL;
 }
 }
 
 
-
-ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) {
-	return ssa_emit(p, ssa_make_instr_store(p, address, value));
+ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
+	ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e);
+	ssaValue *l = ssa_add_local(proc, e);
+	ssa_emit_store(proc, l, v);
+	return v;
 }
 }
 
 
-ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) {
-	return ssa_emit(p, ssa_make_instr_load(p, address));
-}
 
 
 ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) {
 ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) {
 	switch (lval.kind) {
 	switch (lval.kind) {
@@ -585,6 +599,128 @@ Type *ssa_lvalue_type(ssaLvalue lval) {
 	return NULL;
 	return NULL;
 }
 }
 
 
+
+void ssa_build_stmt(ssaProcedure *proc, AstNode *s);
+
+void ssa_emit_defer_stmts(ssaProcedure *proc, ssaBlock *block) {
+	if (block == NULL)
+		return;
+
+	// IMPORTANT TODO(bill): ssa defer - Place where needed!!!
+
+	Scope *curr_scope = block->scope;
+	if (curr_scope == NULL) {
+		GB_PANIC("No scope found for deferred statements");
+	}
+
+	for (Scope *s = curr_scope; s != NULL; s = s->parent) {
+		isize count = gb_array_count(s->deferred_stmts);
+		for (isize i = count-1; i >= 0; i--) {
+			ssa_build_stmt(proc, s->deferred_stmts[i]);
+		}
+	}
+}
+
+void ssa_emit_unreachable(ssaProcedure *proc) {
+	ssa_emit(proc, ssa_make_instr_unreachable(proc));
+}
+
+void ssa_emit_ret(ssaProcedure *proc, ssaValue *v) {
+	ssa_emit_defer_stmts(proc, proc->curr_block);
+	ssa_emit(proc, ssa_make_instr_ret(proc, v));
+}
+
+void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block) {
+	ssa_emit(proc, ssa_make_instr_br(proc, NULL, block, NULL));
+	proc->curr_block = NULL;
+}
+
+void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) {
+	ssaValue *br = ssa_make_instr_br(proc, cond, true_block, false_block);
+	ssa_emit(proc, br);
+	proc->curr_block = NULL;
+}
+
+
+
+
+ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) {
+	Scope *scope = NULL;
+	Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
+	if (found) {
+		scope = *found;
+	} else {
+		GB_PANIC("Block scope not found");
+	}
+
+	ssaValue *block = ssa_make_value_block(proc, node, scope, label);
+	return &block->block;
+}
+
+ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) {
+	ssaBlock *block = ssa__make_block(proc, node, label);
+	gb_array_append(proc->blocks, block);
+	return block;
+}
+
+
+void ssa_begin_procedure_body(ssaProcedure *proc) {
+	gb_array_init(proc->blocks, gb_heap_allocator());
+	proc->curr_block = ssa_add_block(proc, proc->type_expr, make_string("entry"));
+
+	if (proc->type->procedure.params != NULL) {
+		auto *params = &proc->type->procedure.params->tuple;
+		for (isize i = 0; i < params->variable_count; i++) {
+			Entity *e = params->variables[i];
+			ssa_add_param(proc, e);
+		}
+	}
+}
+
+void ssa_end_procedure_body(ssaProcedure *proc) {
+	if (proc->type->procedure.result_count == 0) {
+		ssa_emit_ret(proc, NULL);
+	}
+
+// Number blocks and registers
+	i32 reg_id = 0;
+	gb_for_array(i, proc->blocks) {
+		ssaBlock *b = proc->blocks[i];
+		b->id = i;
+		gb_for_array(j, b->instrs) {
+			ssaValue *value = b->instrs[j];
+			GB_ASSERT(value->kind == ssaValue_Instr);
+			ssaInstr *instr = &value->instr;
+			// NOTE(bill): Ignore non-returning instructions
+			switch (instr->kind) {
+			case ssaInstr_Store:
+			case ssaInstr_Br:
+			case ssaInstr_Ret:
+			case ssaInstr_Unreachable:
+				continue;
+			}
+			value->id = reg_id;
+			reg_id++;
+		}
+	}
+}
+
+void ssa_push_target_list(ssaProcedure *proc, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) {
+	ssaTargetList *tl = gb_alloc_item(proc->module->allocator, ssaTargetList);
+	tl->prev          = proc->target_list;
+	tl->break_        = break_;
+	tl->continue_     = continue_;
+	tl->fallthrough_  = fallthrough_;
+	proc->target_list = tl;
+}
+
+void ssa_pop_target_list(ssaProcedure *proc) {
+	proc->target_list = proc->target_list->prev;
+}
+
+
+
+
 ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 	Type *src_type = ssa_value_type(value);
 	Type *src_type = ssa_value_type(value);
 	if (are_types_identical(t, src_type))
 	if (are_types_identical(t, src_type))
@@ -632,18 +768,10 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue
 	return ssa_emit(proc, v);
 	return ssa_emit(proc, v);
 }
 }
 
 
-ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) {
+ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) {
 	Type *a = get_base_type(ssa_value_type(left));
 	Type *a = get_base_type(ssa_value_type(left));
 	Type *b = get_base_type(ssa_value_type(right));
 	Type *b = get_base_type(ssa_value_type(right));
 
 
-	if (op.kind == Token_CmpEq &&
-	    left->kind == ssaValue_Constant && left->constant.value.kind == ExactValue_Bool) {
-		if (left->constant.value.value_bool) {
-			if (is_type_boolean(b))
-				return right;
-		}
-	}
-
 	if (are_types_identical(a, b)) {
 	if (are_types_identical(a, b)) {
 		// NOTE(bill): No need for a conversion
 		// NOTE(bill): No need for a conversion
 	} else if (left->kind == ssaValue_Constant) {
 	} else if (left->kind == ssaValue_Constant) {
@@ -658,21 +786,6 @@ ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValu
 }
 }
 
 
 
 
-void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block) {
-	ssaValue *br = ssa_make_instr_br(proc, NULL, block, NULL);
-	ssa_emit(proc, br);
-	proc->curr_block = NULL;
-}
-
-void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) {
-	ssaValue *br = ssa_make_instr_br(proc, cond, true_block, false_block);
-	ssa_emit(proc, br);
-	proc->curr_block = NULL;
-}
-
-
-
-
 
 
 
 
 ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
 ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
@@ -690,7 +803,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 
 		auto *found = map_get(&proc->module->values, hash_pointer(e));
 		auto *found = map_get(&proc->module->values, hash_pointer(e));
 		if (found) {
 		if (found) {
-			return ssa_emit_load(proc, *found);
+			ssaValue *v = *found;
+			if (v->kind == ssaValue_Proc)
+				return v;
+			return ssa_emit_load(proc, v);
 		}
 		}
 	case_end;
 	case_end;
 
 
@@ -699,9 +815,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 	case_end;
 	case_end;
 
 
 	case_ast_node(de, DerefExpr, expr);
 	case_ast_node(de, DerefExpr, expr);
-		ssaValue *load = ssa_lvalue_load(ssa_build_addr(proc, expr), proc);
-		ssa_value_set_type(load, type_deref(ssa_value_type(load)));
-		return load;
+		return ssa_lvalue_load(ssa_build_addr(proc, expr), proc);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ue, UnaryExpr, expr);
 	case_ast_node(ue, UnaryExpr, expr);
@@ -754,9 +868,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		case Token_LtEq:
 		case Token_LtEq:
 		case Token_Gt:
 		case Token_Gt:
 		case Token_GtEq: {
 		case Token_GtEq: {
-			ssaValue *cmp = ssa_emit_compare(proc, be->op,
-			                                 ssa_build_expr(proc, be->left),
-			                                 ssa_build_expr(proc, be->right));
+			ssaValue *left  = ssa_build_expr(proc, be->left);
+			ssaValue *right = ssa_build_expr(proc, be->right);
+			ssaValue *cmp = ssa_emit_comp(proc, be->op, left, right);
 			return ssa_emit_conv(proc, cmp, default_type(tv->type));
 			return ssa_emit_conv(proc, cmp, default_type(tv->type));
 		} break;
 		} break;
 
 
@@ -789,16 +903,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			// TODO(bill): Strings AstNode_IndexExpression
 			// TODO(bill): Strings AstNode_IndexExpression
 		} break;
 		} break;
 
 
-		case Type_Slice: {
-			ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
-			return ssa_emit_load(proc, v);
-		} break;
-
-		case Type_Array: {
-			ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
-			return ssa_emit_load(proc, v);
-		} break;
-
+		case Type_Slice:
+		case Type_Array:
 		case Type_Pointer: {
 		case Type_Pointer: {
 			ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
 			ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
 			return ssa_emit_load(proc, v);
 			return ssa_emit_load(proc, v);
@@ -807,6 +913,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 	case_end;
 	case_end;
 
 
 	case_ast_node(se, SelectorExpr, expr);
 	case_ast_node(se, SelectorExpr, expr);
+		return ssa_build_expr(proc, se->selector);
 	case_end;
 	case_end;
 	}
 	}
 
 
@@ -846,6 +953,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	case_ast_node(i, Ident, expr);
 	case_ast_node(i, Ident, expr);
 		if (ssa_is_blank_ident(expr)) {
 		if (ssa_is_blank_ident(expr)) {
 			ssaLvalue val = {ssaLvalue_Blank};
 			ssaLvalue val = {ssaLvalue_Blank};
+			return val;
 		}
 		}
 
 
 		Entity *e = entity_of_ident(proc->module->info, expr);
 		Entity *e = entity_of_ident(proc->module->info, expr);
@@ -855,18 +963,10 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		return ssa_make_lvalue_address(v, expr);
 		return ssa_make_lvalue_address(v, expr);
 	case_end;
 	case_end;
 
 
-	case_ast_node(cl, CompoundLit, expr);
-	case_end;
-
 	case_ast_node(pe, ParenExpr, expr);
 	case_ast_node(pe, ParenExpr, expr);
 		return ssa_build_addr(proc, unparen_expr(expr));
 		return ssa_build_addr(proc, unparen_expr(expr));
 	case_end;
 	case_end;
 
 
-	case_ast_node(de, DerefExpr, expr);
-		ssaValue *v = ssa_build_expr(proc, de->expr);
-		return ssa_make_lvalue_address(v, expr);
-	case_end;
-
 	case_ast_node(se, SelectorExpr, expr);
 	case_ast_node(se, SelectorExpr, expr);
 	case_end;
 	case_end;
 
 
@@ -889,6 +989,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		case Type_Pointer: {
 		case Type_Pointer: {
 			ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
 			ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
 			ssaValue *load = ssa_emit_load(proc, e);
 			ssaValue *load = ssa_emit_load(proc, e);
+			gb_printf("load: %s\n", type_to_string(ssa_value_type(load)));
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load,
 			ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load,
 			                                               index, NULL, 1, false);
 			                                               index, NULL, 1, false);
@@ -896,6 +997,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			gep->instr.get_element_ptr.result_type  = t->pointer.element;
 			gep->instr.get_element_ptr.result_type  = t->pointer.element;
 			gep->instr.get_element_ptr.element_type = t->pointer.element;
 			gep->instr.get_element_ptr.element_type = t->pointer.element;
 			v = gep;
 			v = gep;
+			gb_printf("gep: %s\n", type_to_string(ssa_value_type(gep)));
 		} break;
 		} break;
 		case Type_Slice: {
 		case Type_Slice: {
 			GB_PANIC("ssa_build_addr AstNode_IndexExpression Type_Slice");
 			GB_PANIC("ssa_build_addr AstNode_IndexExpression Type_Slice");
@@ -906,6 +1008,18 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		return ssa_make_lvalue_address(ssa_emit(proc, v), expr);
 		return ssa_make_lvalue_address(ssa_emit(proc, v), expr);
 	case_end;
 	case_end;
 
 
+	case_ast_node(de, DerefExpr, expr);
+		// TODO(bill): Clean up
+		Type *t = type_of_expr(proc->module->info, de->expr);
+		t = type_deref(get_base_type(t));
+		ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc);
+		ssaValue *load = ssa_emit_load(proc, e);
+		ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load, NULL, NULL, 0, false);
+		gep->instr.get_element_ptr.result_type  = t;
+		gep->instr.get_element_ptr.element_type = t;
+		return ssa_make_lvalue_address(ssa_emit(proc, gep), expr);
+	case_end;
+
 	// TODO(bill): Others address
 	// TODO(bill): Others address
 	}
 	}
 
 
@@ -938,15 +1052,13 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
 
 
 	case_ast_node(be, BinaryExpr, cond);
 	case_ast_node(be, BinaryExpr, cond);
 		if (be->op.kind == Token_CmpAnd) {
 		if (be->op.kind == Token_CmpAnd) {
-			ssaValue *b = ssa_add_block(proc, NULL, make_string("logical-true"));
-			ssaBlock *block = &b->block;
+			ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-true"));
 			ssa_build_cond(proc, be->left, block, false_block);
 			ssa_build_cond(proc, be->left, block, false_block);
 			proc->curr_block = block;
 			proc->curr_block = block;
 			ssa_build_cond(proc, be->right, true_block, false_block);
 			ssa_build_cond(proc, be->right, true_block, false_block);
 			return;
 			return;
 		} else if (be->op.kind == Token_CmpOr) {
 		} else if (be->op.kind == Token_CmpOr) {
-			ssaValue *b = ssa_add_block(proc, NULL, make_string("logical-false"));
-			ssaBlock *block = &b->block;
+			ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-false"));
 			ssa_build_cond(proc, be->left, true_block, block);
 			ssa_build_cond(proc, be->left, true_block, block);
 			proc->curr_block = block;
 			proc->curr_block = block;
 			ssa_build_cond(proc, be->right, true_block, false_block);
 			ssa_build_cond(proc, be->right, true_block, false_block);
@@ -960,7 +1072,6 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
 }
 }
 
 
 
 
-void ssa_build_stmt(ssaProcedure *proc, AstNode *s);
 
 
 void ssa_build_stmt_list(ssaProcedure *proc, AstNode *list) {
 void ssa_build_stmt_list(ssaProcedure *proc, AstNode *list) {
 	for (AstNode *stmt = list ; stmt != NULL; stmt = stmt->next)
 	for (AstNode *stmt = list ; stmt != NULL; stmt = stmt->next)
@@ -1090,64 +1201,133 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) {
 		ssa_build_expr(proc, es->expr);
 		ssa_build_expr(proc, es->expr);
 	case_end;
 	case_end;
 
 
-	case_ast_node(bs, BlockStmt, s);
+	case_ast_node(bs, BlockStmt, s)
 		ssa_build_stmt_list(proc, bs->list);
 		ssa_build_stmt_list(proc, bs->list);
 	case_end;
 	case_end;
 
 
+	case_ast_node(bs, DeferStmt, s);
+		// NOTE(bill): is already handled with scope
+	case_end;
+
+	case_ast_node(rs, ReturnStmt, s);
+		ssaValue *v = NULL;
+		auto *return_type_tuple  = &proc->type->procedure.results->tuple;
+		isize return_count = proc->type->procedure.result_count;
+		if (rs->result_count == 1 && return_count > 1) {
+			GB_PANIC("ReturnStmt tuple return statement");
+		} else if (return_count == 1) {
+			Entity *e = return_type_tuple->variables[0];
+			v = ssa_emit_conv(proc, ssa_build_expr(proc, rs->result_list), e->type);
+		} else if (return_count == 0) {
+			// No return values
+		} else {
+			// 1:1 multiple return values
+		}
+
+		ssa_emit_ret(proc, v);
+
+	case_end;
+
 	case_ast_node(is, IfStmt, s);
 	case_ast_node(is, IfStmt, s);
 		if (is->init != NULL) {
 		if (is->init != NULL) {
 			ssa_build_stmt(proc, is->init);
 			ssa_build_stmt(proc, is->init);
 		}
 		}
-		ssaValue *then_block = ssa_add_block(proc, is->body, make_string("if-then"));
-		ssaValue *else_block = NULL;
+		ssaBlock *then = ssa_add_block(proc, s, make_string("if.then"));
+		ssaBlock *done = ssa__make_block(proc, s, make_string("if.done"));
+		ssaBlock *else_ = done;
 		if (is->else_stmt != NULL) {
 		if (is->else_stmt != NULL) {
-			else_block = ssa_add_block(proc, is->else_stmt, make_string("if-else"));
-		}
-		ssaValue *end_block = ssa_add_block(proc, is->body, make_string("if-end"));
-		if (else_block == NULL) {
-			else_block = end_block;
+			else_ = ssa_add_block(proc, is->else_stmt, make_string("if.else"));
 		}
 		}
 
 
-		ssa_build_cond(proc, is->cond, &then_block->block, &else_block->block);
-		proc->curr_block = &then_block->block;
+		ssa_build_cond(proc, is->cond, then, else_);
+		proc->curr_block = then;
 		ssa_build_stmt(proc, is->body);
 		ssa_build_stmt(proc, is->body);
-		ssa_emit_jump(proc, &end_block->block);
+		ssa_emit_jump(proc, done);
 
 
 		if (is->else_stmt != NULL) {
 		if (is->else_stmt != NULL) {
-			proc->curr_block = &else_block->block;
+			proc->curr_block = else_;
 			ssa_build_stmt(proc, is->else_stmt);
 			ssa_build_stmt(proc, is->else_stmt);
-			ssa_emit_jump(proc, &end_block->block);
+			ssa_emit_jump(proc, done);
 		}
 		}
-
-		proc->curr_block = &end_block->block;
-	case_end;
-
-	case_ast_node(rs, ReturnStmt, s);
-		GB_PANIC("AstNode_ReturnStmt");
+		gb_array_append(proc->blocks, done);
+		proc->curr_block = done;
 	case_end;
 	case_end;
 
 
 	case_ast_node(fs, ForStmt, s);
 	case_ast_node(fs, ForStmt, s);
-		GB_PANIC("AstNode_ForStmt");
-	case_end;
+		if (fs->init != NULL) {
+			ssa_build_stmt(proc, fs->init);
+		}
+		ssaBlock *body = ssa_add_block(proc, s, make_string("for.body"));
+		ssaBlock *done = ssa__make_block(proc, s, make_string("for.done")); // NOTE(bill): Append later
+
+		ssaBlock *loop = body;
+
+		if (fs->cond != NULL) {
+			loop = ssa_add_block(proc, fs->cond, make_string("for.loop"));
+		}
+		ssaBlock *cont = loop;
+		if (fs->post != NULL) {
+			cont = ssa_add_block(proc, fs->cond, make_string("for.post"));
+		}
+		ssa_emit_jump(proc, loop);
+		proc->curr_block = loop;
+		if (loop != body) {
+			ssa_build_cond(proc, fs->cond, body, done);
+			proc->curr_block = body;
+		}
+
+		ssa_push_target_list(proc, done, cont, NULL);
+		ssa_build_stmt(proc, fs->body);
+		ssa_pop_target_list(proc);
+		ssa_emit_jump(proc, cont);
+
+		if (fs->post != NULL) {
+			proc->curr_block = cont;
+			ssa_build_stmt(proc, fs->post);
+			ssa_emit_jump(proc, loop);
+		}
+		gb_array_append(proc->blocks, done);
+		proc->curr_block = done;
 
 
-	case_ast_node(bs, DeferStmt, s);
-		GB_PANIC("AstNode_DeferStmt");
 	case_end;
 	case_end;
 
 
 	case_ast_node(bs, BranchStmt, s);
 	case_ast_node(bs, BranchStmt, s);
-		GB_PANIC("AstNode_BranchStmt");
+		ssaBlock *block = NULL;
+		switch (bs->token.kind) {
+		case Token_break: {
+			for (ssaTargetList *t = proc->target_list;
+			     t != NULL && block == NULL;
+			     t = t->prev) {
+				block = t->break_;
+			}
+		} break;
+		case Token_continue: {
+			for (ssaTargetList *t = proc->target_list;
+			     t != NULL && block == NULL;
+			     t = t->prev) {
+				block = t->continue_;
+			}
+		} break;
+		case Token_fallthrough: {
+			for (ssaTargetList *t = proc->target_list;
+			     t != NULL && block == NULL;
+			     t = t->prev) {
+				block = t->fallthrough_;
+			}
+		} break;
+		}
+		ssa_emit_jump(proc, block);
+		ssa_emit_unreachable(proc);
 	case_end;
 	case_end;
+
 	}
 	}
 }
 }
 
 
 
 
 
 
-void ssa_build_procedure(ssaValue *value) {
+void ssa_build_proc(ssaValue *value) {
 	ssaProcedure *proc = &value->proc;
 	ssaProcedure *proc = &value->proc;
 
 
-	// gb_printf("Building %.*s: %.*s\n", LIT(entity_strings[proc->entity->kind]), LIT(proc->name));
-
-
 	AstNode *proc_decl = proc->decl->proc_decl;
 	AstNode *proc_decl = proc->decl->proc_decl;
 	switch (proc_decl->kind) {
 	switch (proc_decl->kind) {
 	case_ast_node(pd, ProcDecl, proc_decl);
 	case_ast_node(pd, ProcDecl, proc_decl);
@@ -1158,16 +1338,11 @@ void ssa_build_procedure(ssaValue *value) {
 		return;
 		return;
 	}
 	}
 
 
-	if (proc->body == NULL) {
-		// TODO(bill): External procedure
-		return;
+	if (proc->body != NULL) {
+		ssa_begin_procedure_body(proc);
+		ssa_build_stmt(proc, proc->body);
+		ssa_end_procedure_body(proc);
 	}
 	}
-
-
-	ssa_begin_procedure_body(proc);
-	ssa_build_stmt(proc, proc->body);
-	ssa_end_procedure_body(proc);
-
 }
 }
 
 
 
 

+ 3 - 3
src/parser.cpp

@@ -144,7 +144,7 @@ AST_NODE_KIND(_ComplexStmtBegin, struct{}) \
 	}) \
 	}) \
 	AST_NODE_KIND(ForStmt, struct { \
 	AST_NODE_KIND(ForStmt, struct { \
 		Token token; \
 		Token token; \
-		AstNode *init, *cond, *end; \
+		AstNode *init, *cond, *post; \
 		AstNode *body; \
 		AstNode *body; \
 	}) \
 	}) \
 	AST_NODE_KIND(DeferStmt,  struct { Token token; AstNode *stmt; }) \
 	AST_NODE_KIND(DeferStmt,  struct { Token token; AstNode *stmt; }) \
@@ -638,12 +638,12 @@ gb_inline AstNode *make_return_stmt(AstFile *f, Token token, AstNode *result_lis
 	return result;
 	return result;
 }
 }
 
 
-gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *end, AstNode *body) {
+gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) {
 	AstNode *result = make_node(f, AstNode_ForStmt);
 	AstNode *result = make_node(f, AstNode_ForStmt);
 	result->ForStmt.token = token;
 	result->ForStmt.token = token;
 	result->ForStmt.init = init;
 	result->ForStmt.init = init;
 	result->ForStmt.cond = cond;
 	result->ForStmt.cond = cond;
-	result->ForStmt.end = end;
+	result->ForStmt.post = post;
 	result->ForStmt.body = body;
 	result->ForStmt.body = body;
 	return result;
 	return result;
 }
 }

+ 1 - 1
src/printer.cpp

@@ -124,7 +124,7 @@ void print_ast(AstNode *node, isize indent) {
 		gb_printf("(for)\n");
 		gb_printf("(for)\n");
 		print_ast(node->ForStmt.init, indent+1);
 		print_ast(node->ForStmt.init, indent+1);
 		print_ast(node->ForStmt.cond, indent+1);
 		print_ast(node->ForStmt.cond, indent+1);
-		print_ast(node->ForStmt.end, indent+1);
+		print_ast(node->ForStmt.post, indent+1);
 		print_ast(node->ForStmt.body, indent+1);
 		print_ast(node->ForStmt.body, indent+1);
 		break;
 		break;
 	case AstNode_DeferStmt:
 	case AstNode_DeferStmt: