Browse Source

SSA Phi Node Support

Ginger Bill 8 years ago
parent
commit
e299c3693e
4 changed files with 260 additions and 143 deletions
  1. 1 1
      code/demo.odin
  2. 0 6
      src/codegen/codegen.cpp
  3. 40 10
      src/codegen/print_llvm.cpp
  4. 219 126
      src/codegen/ssa.cpp

+ 1 - 1
code/demo.odin

@@ -1,6 +1,6 @@
 #import "fmt.odin"
 #import "fmt.odin"
 
 
 main :: proc() {
 main :: proc() {
-	x := ?123
+	fmt.println(123)
 }
 }
 
 

+ 0 - 6
src/codegen/codegen.cpp

@@ -69,7 +69,6 @@ String ssa_mangle_name(ssaGen *s, String path, String name) {
 
 
 
 
 void ssa_gen_tree(ssaGen *s) {
 void ssa_gen_tree(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;
@@ -677,12 +676,7 @@ void ssa_gen_tree(ssaGen *s) {
 		ssa_build_proc(m->procs[i], m->procs[i]->Proc.parent);
 		ssa_build_proc(m->procs[i], m->procs[i]->Proc.parent);
 	}
 	}
 
 
-
-
-
 	// m->layout = make_string("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
 	// m->layout = make_string("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
-
-
 }
 }
 
 
 
 

+ 40 - 10
src/codegen/print_llvm.cpp

@@ -500,8 +500,12 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
 }
 }
 
 
 void ssa_print_block_name(ssaFileBuffer *f, ssaBlock *b) {
 void ssa_print_block_name(ssaFileBuffer *f, ssaBlock *b) {
-	ssa_print_escape_string(f, b->label, false);
-	ssa_fprintf(f, "-%d", b->id);
+	if (b != NULL) {
+		ssa_print_escape_string(f, b->label, false);
+		ssa_fprintf(f, "-%td", b->index);
+	} else {
+		ssa_fprintf(f, "<INVALID-BLOCK>");
+	}
 }
 }
 
 
 void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint) {
 void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint) {
@@ -648,6 +652,32 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "\n");
 		ssa_fprintf(f, "\n");
 	} break;
 	} break;
 
 
+	case ssaInstr_Phi: {
+		ssa_fprintf(f, "%%%d = phi ", value->id);
+		ssa_print_type(f, m, instr->Phi.type);
+		ssa_fprintf(f, " ", value->id);
+
+		for (isize i = 0; i < instr->Phi.edges.count; i++) {
+			ssaValue *edge = instr->Phi.edges[i];
+			if (i > 0) {
+				ssa_fprintf(f, ", ");
+			}
+
+			ssaBlock *block = NULL;
+			if (instr->parent != NULL &&
+			    i < instr->parent->preds.count) {
+				block = instr->parent->preds[i];
+			}
+
+			ssa_fprintf(f, "[ ");
+			ssa_print_value(f, m, edge, instr->Phi.type);
+			ssa_fprintf(f, ", %%");
+			ssa_print_block_name(f, block);
+			ssa_fprintf(f, " ]");
+		}
+		ssa_fprintf(f, "\n");
+	} break;
+
 	case ssaInstr_ExtractValue: {
 	case ssaInstr_ExtractValue: {
 		Type *et = instr->ExtractValue.elem_type;
 		Type *et = instr->ExtractValue.elem_type;
 		ssa_fprintf(f, "%%%d = extractvalue ", value->id);
 		ssa_fprintf(f, "%%%d = extractvalue ", value->id);
@@ -721,12 +751,12 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 
 
 		ssa_fprintf(f, "%%%d = ", value->id);
 		ssa_fprintf(f, "%%%d = ", value->id);
 
 
-		if (gb_is_between(bo->op.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
+		if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
 			if (is_type_string(elem_type)) {
 			if (is_type_string(elem_type)) {
 				ssa_fprintf(f, "call ");
 				ssa_fprintf(f, "call ");
 				ssa_print_type(f, m, t_bool);
 				ssa_print_type(f, m, t_bool);
 				char *runtime_proc = "";
 				char *runtime_proc = "";
-				switch (bo->op.kind) {
+				switch (bo->op) {
 				case Token_CmpEq: runtime_proc = "__string_eq"; break;
 				case Token_CmpEq: runtime_proc = "__string_eq"; break;
 				case Token_NotEq: runtime_proc = "__string_ne"; break;
 				case Token_NotEq: runtime_proc = "__string_ne"; break;
 				case Token_Lt:    runtime_proc = "__string_lt"; break;
 				case Token_Lt:    runtime_proc = "__string_lt"; break;
@@ -750,7 +780,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 
 
 			} else if (is_type_float(elem_type)) {
 			} else if (is_type_float(elem_type)) {
 				ssa_fprintf(f, "fcmp ");
 				ssa_fprintf(f, "fcmp ");
-				switch (bo->op.kind) {
+				switch (bo->op) {
 				case Token_CmpEq: ssa_fprintf(f, "oeq"); break;
 				case Token_CmpEq: ssa_fprintf(f, "oeq"); break;
 				case Token_NotEq: ssa_fprintf(f, "one"); break;
 				case Token_NotEq: ssa_fprintf(f, "one"); break;
 				case Token_Lt:    ssa_fprintf(f, "olt"); break;
 				case Token_Lt:    ssa_fprintf(f, "olt"); break;
@@ -760,15 +790,15 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 				}
 				}
 			} else {
 			} else {
 				ssa_fprintf(f, "icmp ");
 				ssa_fprintf(f, "icmp ");
-				if (bo->op.kind != Token_CmpEq &&
-				    bo->op.kind != Token_NotEq) {
+				if (bo->op != Token_CmpEq &&
+				    bo->op != Token_NotEq) {
 					if (is_type_unsigned(elem_type)) {
 					if (is_type_unsigned(elem_type)) {
 						ssa_fprintf(f, "u");
 						ssa_fprintf(f, "u");
 					} else {
 					} else {
 						ssa_fprintf(f, "s");
 						ssa_fprintf(f, "s");
 					}
 					}
 				}
 				}
-				switch (bo->op.kind) {
+				switch (bo->op) {
 				case Token_CmpEq: ssa_fprintf(f, "eq"); break;
 				case Token_CmpEq: ssa_fprintf(f, "eq"); break;
 				case Token_NotEq: ssa_fprintf(f, "ne"); break;
 				case Token_NotEq: ssa_fprintf(f, "ne"); break;
 				case Token_Lt:    ssa_fprintf(f, "lt"); break;
 				case Token_Lt:    ssa_fprintf(f, "lt"); break;
@@ -781,7 +811,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 			if (is_type_float(elem_type))
 			if (is_type_float(elem_type))
 				ssa_fprintf(f, "f");
 				ssa_fprintf(f, "f");
 
 
-			switch (bo->op.kind) {
+			switch (bo->op) {
 			case Token_Add:    ssa_fprintf(f, "add");  break;
 			case Token_Add:    ssa_fprintf(f, "add");  break;
 			case Token_Sub:    ssa_fprintf(f, "sub");  break;
 			case Token_Sub:    ssa_fprintf(f, "sub");  break;
 			case Token_And:    ssa_fprintf(f, "and");  break;
 			case Token_And:    ssa_fprintf(f, "and");  break;
@@ -800,7 +830,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 					else                             ssa_fprintf(f, "s");
 					else                             ssa_fprintf(f, "s");
 				}
 				}
 
 
-				switch (bo->op.kind) {
+				switch (bo->op) {
 				case Token_Quo: ssa_fprintf(f, "div"); break;
 				case Token_Quo: ssa_fprintf(f, "div"); break;
 				case Token_Mod: ssa_fprintf(f, "rem"); break;
 				case Token_Mod: ssa_fprintf(f, "rem"); break;
 				}
 				}

+ 219 - 126
src/codegen/ssa.cpp

@@ -69,7 +69,7 @@ struct ssaModule {
 
 
 
 
 struct ssaBlock {
 struct ssaBlock {
-	i32 id;
+	isize index;
 	AstNode *node;
 	AstNode *node;
 	Scope *scope;
 	Scope *scope;
 	isize scope_index;
 	isize scope_index;
@@ -266,12 +266,12 @@ struct ssaInstr {
 			ssaValue *false_value;
 			ssaValue *false_value;
 		} Select;
 		} Select;
 		struct {
 		struct {
-			String comment;
 			Array<ssaValue *> edges;
 			Array<ssaValue *> edges;
+			Type *type;
 		} Phi;
 		} Phi;
 		struct {
 		struct {
 			Type *type;
 			Type *type;
-			Token op;
+			TokenKind op;
 			ssaValue *left, *right;
 			ssaValue *left, *right;
 		} BinaryOp;
 		} BinaryOp;
 		struct {
 		struct {
@@ -513,6 +513,8 @@ Type *ssa_type(ssaInstr *instr) {
 		return instr->Load.type;
 		return instr->Load.type;
 	case ssaInstr_GetElementPtr:
 	case ssaInstr_GetElementPtr:
 		return instr->GetElementPtr.result_type;
 		return instr->GetElementPtr.result_type;
+	case ssaInstr_Phi:
+		return instr->Phi.type;
 	case ssaInstr_ExtractValue:
 	case ssaInstr_ExtractValue:
 		return instr->ExtractValue.result_type;
 		return instr->ExtractValue.result_type;
 	case ssaInstr_InsertValue:
 	case ssaInstr_InsertValue:
@@ -742,7 +744,7 @@ ssaValue *ssa_make_instr_insert_value(ssaProcedure *p, ssaValue *value, ssaValue
 }
 }
 
 
 
 
-ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, Token op, ssaValue *left, ssaValue *right, Type *type) {
+ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp);
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp);
 	ssaInstr *i = &v->Instr;
 	ssaInstr *i = &v->Instr;
 	i->BinaryOp.op = op;
 	i->BinaryOp.op = op;
@@ -761,6 +763,14 @@ ssaValue *ssa_make_instr_br(ssaProcedure *p, ssaValue *cond, ssaBlock *true_bloc
 	return v;
 	return v;
 }
 }
 
 
+ssaValue *ssa_make_instr_phi(ssaProcedure *p, Array<ssaValue *> edges, Type *type) {
+	ssaValue *v = ssa_alloc_instr(p, ssaInstr_Phi);
+	ssaInstr *i = &v->Instr;
+	i->Phi.edges = edges;
+	i->Phi.type = type;
+	return v;
+}
+
 ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) {
 ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) {
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_Unreachable);
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_Unreachable);
 	return v;
 	return v;
@@ -1065,7 +1075,7 @@ Type *ssa_addr_type(ssaAddr lval) {
 	return NULL;
 	return NULL;
 }
 }
 
 
-ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) {
+ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, char *label) {
 	Scope *scope = NULL;
 	Scope *scope = NULL;
 	if (node != NULL) {
 	if (node != NULL) {
 		Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
 		Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
@@ -1076,12 +1086,8 @@ ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) {
 		}
 		}
 	}
 	}
 
 
-	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);
+	ssaValue *value = ssa_make_value_block(proc, node, scope, make_string(label));
+	ssaBlock *block = &value->Block;
 	array_add(&proc->blocks, block);
 	array_add(&proc->blocks, block);
 	return block;
 	return block;
 }
 }
@@ -1091,13 +1097,12 @@ void ssa_emit_no_op(ssaProcedure *proc);
 void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block);
 void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block);
 
 
 void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) {
 void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) {
-	ssaBlock *b = ssa__make_block(proc, NULL, make_string("defer"));
+	ssaBlock *b = ssa_add_block(proc, NULL, "defer");
 	// NOTE(bill): The prev block may defer injection before it's terminator
 	// NOTE(bill): The prev block may defer injection before it's terminator
 	ssaInstr *last_instr = ssa_get_last_instr(proc->curr_block);
 	ssaInstr *last_instr = ssa_get_last_instr(proc->curr_block);
 	if (last_instr == NULL || !ssa_is_instr_terminating(last_instr)) {
 	if (last_instr == NULL || !ssa_is_instr_terminating(last_instr)) {
 		ssa_emit_jump(proc, b);
 		ssa_emit_jump(proc, b);
 	}
 	}
-	array_add(&proc->blocks, b);
 	proc->curr_block = b;
 	proc->curr_block = b;
 	ssa_emit_comment(proc, make_string("defer"));
 	ssa_emit_comment(proc, make_string("defer"));
 	if (d.kind == ssaDefer_Node) {
 	if (d.kind == ssaDefer_Node) {
@@ -1228,8 +1233,8 @@ void ssa_begin_procedure_body(ssaProcedure *proc) {
 	array_init(&proc->defer_stmts, gb_heap_allocator());
 	array_init(&proc->defer_stmts, gb_heap_allocator());
 	array_init(&proc->children,    gb_heap_allocator());
 	array_init(&proc->children,    gb_heap_allocator());
 
 
-	proc->decl_block  = ssa_add_block(proc, proc->type_expr, make_string("decls"));
-	proc->entry_block = ssa_add_block(proc, proc->type_expr, make_string("entry"));
+	proc->decl_block  = ssa_add_block(proc, proc->type_expr, "decls");
+	proc->entry_block = ssa_add_block(proc, proc->type_expr, "entry");
 	proc->curr_block  = proc->entry_block;
 	proc->curr_block  = proc->entry_block;
 
 
 	if (proc->type->Proc.params != NULL) {
 	if (proc->type->Proc.params != NULL) {
@@ -1241,6 +1246,92 @@ void ssa_begin_procedure_body(ssaProcedure *proc) {
 	}
 	}
 }
 }
 
 
+void ssa_remove_pred(ssaBlock *a, ssaBlock *b) {
+
+}
+
+void ssa_remove_dead_blocks(ssaProcedure *proc) {
+	isize j = 0;
+	for_array(i, proc->blocks) {
+		ssaBlock *b = proc->blocks[i];
+		if (b != NULL) {
+			// NOTE(bill): Swap order
+			b->index = j;
+			proc->blocks[j] = b;
+			j++;
+		}
+	}
+
+	proc->blocks.count = j;
+}
+
+void ssa_mark_reachable(ssaBlock *b) {
+	isize const WHITE =  0;
+	isize const BLACK = -1;
+	b->index = BLACK;
+	for_array(i, b->succs) {
+		ssaBlock *succ = b->succs[i];
+		if (succ->index == WHITE) {
+			ssa_mark_reachable(succ);
+		}
+	}
+}
+
+void ssa_remove_unreachable_blocks(ssaProcedure *proc) {
+	isize const WHITE =  0;
+	isize const BLACK = -1;
+	for_array(i, proc->blocks) {
+		proc->blocks[i]->index = WHITE;
+	}
+
+	ssa_mark_reachable(proc->blocks[0]);
+
+	for_array(i, proc->blocks) {
+		ssaBlock *b = proc->blocks[i];
+		if (b->index == WHITE) {
+			for_array(j, b->succs) {
+				ssaBlock *c = b->succs[j];
+				if (c->index == BLACK) {
+					// ssa_remove_pred(c, b);
+				}
+			}
+			// NOTE(bill): Mark as empty but don't actually free it
+			// As it's been allocated with an arena
+			proc->blocks[i] = NULL;
+		}
+	}
+	ssa_remove_dead_blocks(proc);
+}
+
+
+void ssa_optimize_blocks(ssaProcedure *proc) {
+	ssa_remove_unreachable_blocks(proc);
+
+#if 0
+	b32 changed = false;
+	do {
+		for_array(i, proc->blocks) {
+			ssaBlock *b = proc->blocks[i];
+			if (b == NULL) {
+				continue;
+			}
+
+			// if (ssa_fuse_blocks(proc, b)) {
+			// 	changed = true;
+			// }
+
+			if (ssa_jump_threading(proc, b)) {
+				// x -> y -> z becomes x -> z if y is just a jump
+				changed = true;
+				continue;
+			}
+		}
+	} while (changed);
+#endif
+
+	ssa_remove_dead_blocks(proc);
+}
+
 void ssa_end_procedure_body(ssaProcedure *proc) {
 void ssa_end_procedure_body(ssaProcedure *proc) {
 	if (proc->type->Proc.result_count == 0) {
 	if (proc->type->Proc.result_count == 0) {
 		ssa_emit_ret(proc, NULL);
 		ssa_emit_ret(proc, NULL);
@@ -1253,12 +1344,13 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
 	proc->curr_block = proc->decl_block;
 	proc->curr_block = proc->decl_block;
 	ssa_emit_jump(proc, proc->entry_block);
 	ssa_emit_jump(proc, proc->entry_block);
 
 
+	ssa_optimize_blocks(proc);
+
 
 
 // Number blocks and registers
 // Number blocks and registers
 	i32 reg_id = 0;
 	i32 reg_id = 0;
 	for_array(i, proc->blocks) {
 	for_array(i, proc->blocks) {
 		ssaBlock *b = proc->blocks[i];
 		ssaBlock *b = proc->blocks[i];
-		b->id = i;
 		for_array(j, b->instrs) {
 		for_array(j, b->instrs) {
 			ssaValue *value = b->instrs[j];
 			ssaValue *value = b->instrs[j];
 			GB_ASSERT(value->kind == ssaValue_Instr);
 			GB_ASSERT(value->kind == ssaValue_Instr);
@@ -1300,17 +1392,17 @@ void ssa_pop_target_list(ssaProcedure *proc) {
 
 
 
 
 
 
-ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right, Type *type) {
-	switch (op.kind) {
+ssaValue *ssa_emit_arith(ssaProcedure *proc, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
+	switch (op) {
 	case Token_AndNot: {
 	case Token_AndNot: {
 		// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
 		// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
 		// NOTE(bill): "not" `x` == `x` "xor" `-1`
 		// NOTE(bill): "not" `x` == `x` "xor" `-1`
 		ssaValue *neg = ssa_add_module_constant(proc->module, type, make_exact_value_integer(-1));
 		ssaValue *neg = ssa_add_module_constant(proc->module, type, make_exact_value_integer(-1));
-		op.kind = Token_Xor;
+		op = Token_Xor;
 		right = ssa_emit_arith(proc, op, right, neg, type);
 		right = ssa_emit_arith(proc, op, right, neg, type);
 		GB_ASSERT(right->Instr.kind == ssaInstr_BinaryOp);
 		GB_ASSERT(right->Instr.kind == ssaInstr_BinaryOp);
 		right->Instr.BinaryOp.type = type;
 		right->Instr.BinaryOp.type = type;
-		op.kind = Token_And;
+		op = Token_And;
 	} /* fallthrough */
 	} /* fallthrough */
 	case Token_Add:
 	case Token_Add:
 	case Token_Sub:
 	case Token_Sub:
@@ -1328,7 +1420,7 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue
 	return ssa_emit(proc, ssa_make_instr_binary_op(proc, op, left, right, type));
 	return ssa_emit(proc, ssa_make_instr_binary_op(proc, op, left, right, type));
 }
 }
 
 
-ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) {
+ssaValue *ssa_emit_comp(ssaProcedure *proc, TokenKind op_kind, ssaValue *left, ssaValue *right) {
 	Type *a = base_type(ssa_type(left));
 	Type *a = base_type(ssa_type(left));
 	Type *b = base_type(ssa_type(right));
 	Type *b = base_type(ssa_type(right));
 
 
@@ -1344,7 +1436,7 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *
 	if (is_type_vector(a)) {
 	if (is_type_vector(a)) {
 		result = make_type_vector(proc->module->allocator, t_bool, a->Vector.count);
 		result = make_type_vector(proc->module->allocator, t_bool, a->Vector.count);
 	}
 	}
-	return ssa_emit(proc, ssa_make_instr_binary_op(proc, op, left, right, result));
+	return ssa_emit(proc, ssa_make_instr_binary_op(proc, op_kind, left, right, result));
 }
 }
 
 
 ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offset) {
 ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offset) {
@@ -1601,9 +1693,8 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba
 	}
 	}
 	GB_ASSERT(max != NULL);
 	GB_ASSERT(max != NULL);
 
 
-	Token op_sub = {Token_Sub};
-	ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int);
-	ssaValue *cap = ssa_emit_arith(proc, op_sub, max,  low, t_int);
+	ssaValue *len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
+	ssaValue *cap = ssa_emit_arith(proc, Token_Sub, max,  low, t_int);
 
 
 	ssaValue *elem = NULL;
 	ssaValue *elem = NULL;
 	switch (bt->kind) {
 	switch (bt->kind) {
@@ -1779,8 +1870,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 
 
 	// integer -> boolean
 	// integer -> boolean
 	if (is_type_integer(src) && is_type_boolean(dst)) {
 	if (is_type_integer(src) && is_type_boolean(dst)) {
-		Token op = {Token_NotEq};
-		return ssa_emit_comp(proc, op, value, v_zero);
+		return ssa_emit_comp(proc, Token_NotEq, value, v_zero);
 	}
 	}
 
 
 
 
@@ -2013,9 +2103,10 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
 
 
 ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) {
 ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) {
 	ast_node(be, BinaryExpr, expr);
 	ast_node(be, BinaryExpr, expr);
-	ssaBlock *true_   = ssa_add_block(proc, NULL, make_string("logical.cmp.true"));
-	ssaBlock *false_  = ssa_add_block(proc, NULL, make_string("logical.cmp.false"));
-	ssaBlock *done  = ssa__make_block(proc, NULL, make_string("logical.cmp.done"));
+#if 0
+	ssaBlock *true_   = ssa_add_block(proc, NULL, "logical.cmp.true");
+	ssaBlock *false_  = ssa_add_block(proc, NULL, "logical.cmp.false");
+	ssaBlock *done  = ssa_add_block(proc, NULL, "logical.cmp.done");
 
 
 	ssaValue *result = ssa_add_local_generated(proc, t_bool);
 	ssaValue *result = ssa_add_local_generated(proc, t_bool);
 	ssa_build_cond(proc, expr, true_, false_);
 	ssa_build_cond(proc, expr, true_, false_);
@@ -2028,10 +2119,48 @@ ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) {
 	ssa_emit_store(proc, result, v_false);
 	ssa_emit_store(proc, result, v_false);
 	ssa_emit_jump(proc, done);
 	ssa_emit_jump(proc, done);
 
 
-	array_add(&proc->blocks, done);
 	proc->curr_block = done;
 	proc->curr_block = done;
 
 
 	return ssa_emit_load(proc, result);
 	return ssa_emit_load(proc, result);
+#else
+	ssaBlock *rhs = ssa_add_block(proc, NULL, "logical.cmp.rhs");
+	ssaBlock *done = ssa_add_block(proc, NULL, "logical.cmp.done");
+
+	Type *type = type_of_expr(proc->module->info, expr);
+	type = default_type(type);
+
+	ssaValue *short_circuit = NULL;
+	if (be->op.kind == Token_CmpAnd) {
+		ssa_build_cond(proc, be->left, rhs, done);
+		short_circuit = v_false;
+	} else if (be->op.kind == Token_CmpOr) {
+		ssa_build_cond(proc, be->left, done, rhs);
+		short_circuit = v_true;
+	}
+
+	if (rhs->preds.count == 0) {
+		proc->curr_block = done;
+		return short_circuit;
+	}
+
+	if (done->preds.count == 0) {
+		proc->curr_block = rhs;
+		return ssa_build_expr(proc, be->right);
+	}
+
+	Array<ssaValue *> edges = {};
+	array_init(&edges, proc->module->allocator, done->preds.count+1);
+	for_array(i, done->preds) {
+		array_add(&edges, short_circuit);
+	}
+
+	proc->curr_block = rhs;
+	array_add(&edges, ssa_build_expr(proc, be->right));
+	ssa_emit_jump(proc, done);
+	proc->curr_block = done;
+
+	return ssa_emit(proc, ssa_make_instr_phi(proc, edges, type));
+#endif
 }
 }
 
 
 
 
@@ -2125,14 +2254,14 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			return ssa_build_expr(proc, ue->expr);
 			return ssa_build_expr(proc, ue->expr);
 
 
 		case Token_Sub: // NOTE(bill): -`x` == 0 - `x`
 		case Token_Sub: // NOTE(bill): -`x` == 0 - `x`
-			return ssa_emit_arith(proc, ue->op, v_zero, ssa_build_expr(proc, ue->expr), tv->type);
+			return ssa_emit_arith(proc, ue->op.kind, v_zero, ssa_build_expr(proc, ue->expr), tv->type);
 
 
 		case Token_Not:   // Boolean not
 		case Token_Not:   // Boolean not
 		case Token_Xor: { // Bitwise not
 		case Token_Xor: { // Bitwise not
 			// NOTE(bill): "not" `x` == `x` "xor" `-1`
 			// NOTE(bill): "not" `x` == `x` "xor" `-1`
 			ssaValue *left = ssa_build_expr(proc, ue->expr);
 			ssaValue *left = ssa_build_expr(proc, ue->expr);
 			ssaValue *right = ssa_add_module_constant(proc->module, tv->type, make_exact_value_integer(-1));
 			ssaValue *right = ssa_add_module_constant(proc->module, tv->type, make_exact_value_integer(-1));
-			return ssa_emit_arith(proc, ue->op,
+			return ssa_emit_arith(proc, ue->op.kind,
 			                      left, right,
 			                      left, right,
 			                      tv->type);
 			                      tv->type);
 		} break;
 		} break;
@@ -2152,7 +2281,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		case Token_AndNot:
 		case Token_AndNot:
 		case Token_Shl:
 		case Token_Shl:
 		case Token_Shr:
 		case Token_Shr:
-			return ssa_emit_arith(proc, be->op,
+			return ssa_emit_arith(proc, be->op.kind,
 			                      ssa_build_expr(proc, be->left),
 			                      ssa_build_expr(proc, be->left),
 			                      ssa_build_expr(proc, be->right),
 			                      ssa_build_expr(proc, be->right),
 			                      tv->type);
 			                      tv->type);
@@ -2167,7 +2296,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			ssaValue *left  = ssa_build_expr(proc, be->left);
 			ssaValue *left  = ssa_build_expr(proc, be->left);
 			ssaValue *right = ssa_build_expr(proc, be->right);
 			ssaValue *right = ssa_build_expr(proc, be->right);
 
 
-			ssaValue *cmp = ssa_emit_comp(proc, be->op, left, right);
+			ssaValue *cmp = ssa_emit_comp(proc, be->op.kind, left, right);
 			return ssa_emit_conv(proc, cmp, default_type(tv->type));
 			return ssa_emit_conv(proc, cmp, default_type(tv->type));
 		} break;
 		} break;
 
 
@@ -2420,8 +2549,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 
 					ssa_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false);
 					ssa_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false);
 
 
-					Token mul = {Token_Mul};
-					ssaValue *slice_size = ssa_emit_arith(proc, mul, elem_size, cap, t_int);
+					ssaValue *slice_size = ssa_emit_arith(proc, Token_Mul, elem_size, cap, t_int);
 
 
 					ssaValue **args = gb_alloc_array(allocator, ssaValue *, 2);
 					ssaValue **args = gb_alloc_array(allocator, ssaValue *, 2);
 					args[0] = slice_size;
 					args[0] = slice_size;
@@ -2445,10 +2573,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssaValue *cond = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *cond = ssa_build_expr(proc, ce->args[0]);
 					GB_ASSERT(is_type_boolean(ssa_type(cond)));
 					GB_ASSERT(is_type_boolean(ssa_type(cond)));
 
 
-					Token eq = {Token_CmpEq};
-					cond = ssa_emit_comp(proc, eq, cond, v_false);
-					ssaBlock *err  = ssa_add_block(proc, NULL, make_string("builtin.assert.err"));
-					ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.assert.done"));
+					cond = ssa_emit_comp(proc, Token_CmpEq, cond, v_false);
+					ssaBlock *err  = ssa_add_block(proc, NULL, "builtin.assert.err");
+					ssaBlock *done = ssa_add_block(proc, NULL, "builtin.assert.done");
 
 
 					ssa_emit_if(proc, cond, err, done);
 					ssa_emit_if(proc, cond, err, done);
 					proc->curr_block = err;
 					proc->curr_block = err;
@@ -2471,7 +2598,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssa_emit_global_call(proc, "__assert", args, 4);
 					ssa_emit_global_call(proc, "__assert", args, 4);
 
 
 					ssa_emit_jump(proc, done);
 					ssa_emit_jump(proc, done);
-					array_add(&proc->blocks, done);
 					proc->curr_block = done;
 					proc->curr_block = done;
 
 
 					return NULL;
 					return NULL;
@@ -2515,12 +2641,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssaValue *len_dst = ssa_slice_len(proc, dst_slice);
 					ssaValue *len_dst = ssa_slice_len(proc, dst_slice);
 					ssaValue *len_src = ssa_slice_len(proc, src_slice);
 					ssaValue *len_src = ssa_slice_len(proc, src_slice);
 
 
-					Token lt = {Token_Lt};
-					ssaValue *cond = ssa_emit_comp(proc, lt, len_dst, len_src);
+					ssaValue *cond = ssa_emit_comp(proc, Token_Lt, len_dst, len_src);
 					ssaValue *len = ssa_emit_select(proc, cond, len_dst, len_src);
 					ssaValue *len = ssa_emit_select(proc, cond, len_dst, len_src);
-					Token mul = {Token_Mul};
+
 					ssaValue *elem_size = ssa_make_const_int(proc->module->allocator, size_of_elem);
 					ssaValue *elem_size = ssa_make_const_int(proc->module->allocator, size_of_elem);
-					ssaValue *byte_count = ssa_emit_arith(proc, mul, len, elem_size, t_int);
+					ssaValue *byte_count = ssa_emit_arith(proc, Token_Mul, len, elem_size, t_int);
 
 
 					ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 3);
 					ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 3);
 					args[0] = dst;
 					args[0] = dst;
@@ -2553,10 +2678,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 
 
 
 					// NOTE(bill): Check if can append is possible
 					// NOTE(bill): Check if can append is possible
-					Token lt = {Token_Lt};
-					ssaValue *cond = ssa_emit_comp(proc, lt, len, cap);
-					ssaBlock *able = ssa_add_block(proc, NULL, make_string("builtin.append.able"));
-					ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.append.done"));
+					ssaValue *cond = ssa_emit_comp(proc, Token_Lt, len, cap);
+					ssaBlock *able = ssa_add_block(proc, NULL, "builtin.append.able");
+					ssaBlock *done = ssa_add_block(proc, NULL, "builtin.append.done");
 
 
 					ssa_emit_if(proc, cond, able, done);
 					ssa_emit_if(proc, cond, able, done);
 					proc->curr_block = able;
 					proc->curr_block = able;
@@ -2579,13 +2703,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssa_emit_global_call(proc, "__mem_copy", args, 3);
 					ssa_emit_global_call(proc, "__mem_copy", args, 3);
 
 
 					// Increment slice length
 					// Increment slice length
-					Token add = {Token_Add};
-					ssaValue *new_len = ssa_emit_arith(proc, add, len, v_one, t_int);
+					ssaValue *new_len = ssa_emit_arith(proc, Token_Add, len, v_one, t_int);
 					ssaValue *gep = ssa_emit_struct_gep(proc, slice_ptr, v_one32, t_int);
 					ssaValue *gep = ssa_emit_struct_gep(proc, slice_ptr, v_one32, t_int);
 					ssa_emit_store(proc, gep, new_len);
 					ssa_emit_store(proc, gep, new_len);
 
 
 					ssa_emit_jump(proc, done);
 					ssa_emit_jump(proc, done);
-					array_add(&proc->blocks, done);
 					proc->curr_block = done;
 					proc->curr_block = done;
 
 
 					return ssa_emit_conv(proc, cond, t_bool, true);
 					return ssa_emit_conv(proc, cond, t_bool, true);
@@ -2627,12 +2749,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					Type *ptr_type = base_type(ssa_type(ptr_a));
 					Type *ptr_type = base_type(ssa_type(ptr_a));
 					GB_ASSERT(ptr_type->kind == Type_Pointer);
 					GB_ASSERT(ptr_type->kind == Type_Pointer);
 					isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem);
 					isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem);
-					Token sub = {Token_Sub};
-					ssaValue *v = ssa_emit_arith(proc, sub, ptr_a, ptr_b, t_int);
+
+					ssaValue *v = ssa_emit_arith(proc, Token_Sub, ptr_a, ptr_b, t_int);
 					if (elem_size > 1) {
 					if (elem_size > 1) {
-						Token quo = {Token_Quo};
 						ssaValue *ez = ssa_make_const_int(proc->module->allocator, elem_size);
 						ssaValue *ez = ssa_make_const_int(proc->module->allocator, elem_size);
-						v = ssa_emit_arith(proc, quo, v, ez, t_int);
+						v = ssa_emit_arith(proc, Token_Quo, v, ez, t_int);
 					}
 					}
 
 
 					return v;
 					return v;
@@ -2665,8 +2786,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *y = ssa_build_expr(proc, ce->args[1]);
 					ssaValue *y = ssa_build_expr(proc, ce->args[1]);
 					Type *t = base_type(ssa_type(x));
 					Type *t = base_type(ssa_type(x));
-					Token lt = {Token_Lt};
-					ssaValue *cond = ssa_emit_comp(proc, lt, x, y);
+					ssaValue *cond = ssa_emit_comp(proc, Token_Lt, x, y);
 					return ssa_emit_select(proc, cond, x, y);
 					return ssa_emit_select(proc, cond, x, y);
 				} break;
 				} break;
 
 
@@ -2675,21 +2795,18 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *y = ssa_build_expr(proc, ce->args[1]);
 					ssaValue *y = ssa_build_expr(proc, ce->args[1]);
 					Type *t = base_type(ssa_type(x));
 					Type *t = base_type(ssa_type(x));
-					Token gt = {Token_Gt};
-					ssaValue *cond = ssa_emit_comp(proc, gt, x, y);
+					ssaValue *cond = ssa_emit_comp(proc, Token_Gt, x, y);
 					return ssa_emit_select(proc, cond, x, y);
 					return ssa_emit_select(proc, cond, x, y);
 				} break;
 				} break;
 
 
 				case BuiltinProc_abs: {
 				case BuiltinProc_abs: {
 					ssa_emit_comment(proc, make_string("abs"));
 					ssa_emit_comment(proc, make_string("abs"));
-					Token lt = {Token_Lt};
-					Token sub = {Token_Sub};
 
 
 					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					Type *t = ssa_type(x);
 					Type *t = ssa_type(x);
 
 
-					ssaValue *neg_x = ssa_emit_arith(proc, sub, v_zero, x, t);
-					ssaValue *cond = ssa_emit_comp(proc, lt, x, v_zero);
+					ssaValue *neg_x = ssa_emit_arith(proc, Token_Sub, v_zero, x, t);
+					ssaValue *cond = ssa_emit_comp(proc, Token_Lt, x, v_zero);
 					return ssa_emit_select(proc, cond, neg_x, x);
 					return ssa_emit_select(proc, cond, neg_x, x);
 				} break;
 				} break;
 
 
@@ -3117,10 +3234,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 
 			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
 			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
 
 
-			Token op_sub = {Token_Sub};
 			ssaValue *elem = ssa_slice_elem(proc, base);
 			ssaValue *elem = ssa_slice_elem(proc, base);
-			ssaValue *len  = ssa_emit_arith(proc, op_sub, high, low, t_int);
-			ssaValue *cap  = ssa_emit_arith(proc, op_sub, max,  low, t_int);
+			ssaValue *len  = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
+			ssaValue *cap  = ssa_emit_arith(proc, Token_Sub, max,  low, t_int);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
 
 
 			ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(elem));
 			ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(elem));
@@ -3142,10 +3258,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 
 			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
 			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
 
 
-			Token op_sub = {Token_Sub};
 			ssaValue *elem = ssa_array_elem(proc, addr);
 			ssaValue *elem = ssa_array_elem(proc, addr);
-			ssaValue *len  = ssa_emit_arith(proc, op_sub, high, low, t_int);
-			ssaValue *cap  = ssa_emit_arith(proc, op_sub, max,  low, t_int);
+			ssaValue *len  = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
+			ssaValue *cap  = ssa_emit_arith(proc, Token_Sub, max,  low, t_int);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
 			ssaValue *slice = ssa_add_local_generated(proc, slice_type);
 
 
 			ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(elem));
 			ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(elem));
@@ -3166,9 +3281,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 
 			ssa_slice_bounds_check(proc, se->open, low, high, high, true);
 			ssa_slice_bounds_check(proc, se->open, low, high, high, true);
 
 
-			Token op_sub = {Token_Sub};
 			ssaValue *elem, *len;
 			ssaValue *elem, *len;
-			len = ssa_emit_arith(proc, op_sub, high, low, t_int);
+			len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
 
 
 			elem = ssa_string_elem(proc, base);
 			elem = ssa_string_elem(proc, base);
 			elem = ssa_emit_ptr_offset(proc, elem, low);
 			elem = ssa_emit_ptr_offset(proc, elem, low);
@@ -3231,7 +3345,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	return ssa_make_addr(NULL, NULL);
 	return ssa_make_addr(NULL, NULL);
 }
 }
 
 
-void ssa_build_assign_op(ssaProcedure *proc, ssaAddr lhs, ssaValue *value, Token op) {
+void ssa_build_assign_op(ssaProcedure *proc, ssaAddr lhs, ssaValue *value, TokenKind op) {
 	ssaValue *old_value = ssa_lvalue_load(proc, lhs);
 	ssaValue *old_value = ssa_lvalue_load(proc, lhs);
 	Type *type = ssa_type(old_value);
 	Type *type = ssa_type(old_value);
 	ssaValue *change = ssa_emit_conv(proc, value, type);
 	ssaValue *change = ssa_emit_conv(proc, value, type);
@@ -3255,13 +3369,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) {
-			ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp.and"));
+			ssaBlock *block = ssa_add_block(proc, NULL, "cmp.and");
 			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) {
-			ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp.or"));
+			ssaBlock *block = ssa_add_block(proc, NULL, "cmp.or");
 			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);
@@ -3497,11 +3611,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 	case_ast_node(ids, IncDecStmt, node);
 	case_ast_node(ids, IncDecStmt, node);
 		ssa_emit_comment(proc, make_string("IncDecStmt"));
 		ssa_emit_comment(proc, make_string("IncDecStmt"));
-		Token op = ids->op;
-		if (op.kind == Token_Increment) {
-			op.kind = Token_Add;
-		} else if (op.kind == Token_Decrement) {
-			op.kind = Token_Sub;
+		TokenKind op = ids->op.kind;
+		if (op == Token_Increment) {
+			op = Token_Add;
+		} else if (op == Token_Decrement) {
+			op = Token_Sub;
 		}
 		}
 		ssaAddr lval = ssa_build_addr(proc, ids->expr);
 		ssaAddr lval = ssa_build_addr(proc, ids->expr);
 		ssaValue *one = ssa_emit_conv(proc, v_one, ssa_addr_type(lval));
 		ssaValue *one = ssa_emit_conv(proc, v_one, ssa_addr_type(lval));
@@ -3577,13 +3691,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		default: {
 		default: {
 			// NOTE(bill): Only 1 += 1 is allowed, no tuples
 			// NOTE(bill): Only 1 += 1 is allowed, no tuples
 			// +=, -=, etc
 			// +=, -=, etc
-			Token op = as->op;
-			i32 kind = op.kind;
-			kind += Token_Add - Token_AddEq; // Convert += to +
-			op.kind = cast(TokenKind)kind;
+			i32 op = cast(i32)as->op.kind;
+			op += Token_Add - Token_AddEq; // Convert += to +
 			ssaAddr lhs = ssa_build_addr(proc, as->lhs[0]);
 			ssaAddr lhs = ssa_build_addr(proc, as->lhs[0]);
 			ssaValue *value = ssa_build_expr(proc, as->rhs[0]);
 			ssaValue *value = ssa_build_expr(proc, as->rhs[0]);
-			ssa_build_assign_op(proc, lhs, value, op);
+			ssa_build_assign_op(proc, lhs, value, cast(TokenKind)op);
 		} break;
 		} break;
 		}
 		}
 	case_end;
 	case_end;
@@ -3658,16 +3770,16 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 	case_ast_node(is, IfStmt, node);
 	case_ast_node(is, IfStmt, node);
 		ssa_emit_comment(proc, make_string("IfStmt"));
 		ssa_emit_comment(proc, make_string("IfStmt"));
 		if (is->init != NULL) {
 		if (is->init != NULL) {
-			ssaBlock *init = ssa_add_block(proc, node, make_string("if.init"));
+			ssaBlock *init = ssa_add_block(proc, node, "if.init");
 			ssa_emit_jump(proc, init);
 			ssa_emit_jump(proc, init);
 			proc->curr_block = init;
 			proc->curr_block = init;
 			ssa_build_stmt(proc, is->init);
 			ssa_build_stmt(proc, is->init);
 		}
 		}
-		ssaBlock *then = ssa_add_block(proc, node, make_string("if.then"));
-		ssaBlock *done = ssa__make_block(proc, node, make_string("if.done")); // NOTE(bill): Append later
+		ssaBlock *then = ssa_add_block(proc, node, "if.then");
+		ssaBlock *done = ssa_add_block(proc, node, "if.done"); // NOTE(bill): Append later
 		ssaBlock *else_ = done;
 		ssaBlock *else_ = done;
 		if (is->else_stmt != NULL) {
 		if (is->else_stmt != NULL) {
-			else_ = ssa_add_block(proc, is->else_stmt, make_string("if.else"));
+			else_ = ssa_add_block(proc, is->else_stmt, "if.else");
 		}
 		}
 
 
 		ssa_build_cond(proc, is->cond, then, else_);
 		ssa_build_cond(proc, is->cond, then, else_);
@@ -3688,29 +3800,28 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 			ssa_emit_jump(proc, done);
 			ssa_emit_jump(proc, done);
 		}
 		}
-		array_add(&proc->blocks, done);
 		proc->curr_block = done;
 		proc->curr_block = done;
 	case_end;
 	case_end;
 
 
 	case_ast_node(fs, ForStmt, node);
 	case_ast_node(fs, ForStmt, node);
 		ssa_emit_comment(proc, make_string("ForStmt"));
 		ssa_emit_comment(proc, make_string("ForStmt"));
 		if (fs->init != NULL) {
 		if (fs->init != NULL) {
-			ssaBlock *init = ssa_add_block(proc, node, make_string("for.init"));
+			ssaBlock *init = ssa_add_block(proc, node, "for.init");
 			ssa_emit_jump(proc, init);
 			ssa_emit_jump(proc, init);
 			proc->curr_block = init;
 			proc->curr_block = init;
 			ssa_build_stmt(proc, fs->init);
 			ssa_build_stmt(proc, fs->init);
 		}
 		}
-		ssaBlock *body = ssa_add_block(proc, node, make_string("for.body"));
-		ssaBlock *done = ssa__make_block(proc, node, make_string("for.done")); // NOTE(bill): Append later
+		ssaBlock *body = ssa_add_block(proc, node, "for.body");
+		ssaBlock *done = ssa_add_block(proc, node, "for.done"); // NOTE(bill): Append later
 
 
 		ssaBlock *loop = body;
 		ssaBlock *loop = body;
 
 
 		if (fs->cond != NULL) {
 		if (fs->cond != NULL) {
-			loop = ssa_add_block(proc, node, make_string("for.loop"));
+			loop = ssa_add_block(proc, node, "for.loop");
 		}
 		}
 		ssaBlock *cont = loop;
 		ssaBlock *cont = loop;
 		if (fs->post != NULL) {
 		if (fs->post != NULL) {
-			cont = ssa_add_block(proc, node, make_string("for.post"));
+			cont = ssa_add_block(proc, node, "for.post");
 
 
 		}
 		}
 		ssa_emit_jump(proc, loop);
 		ssa_emit_jump(proc, loop);
@@ -3736,7 +3847,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		}
 		}
 
 
 
 
-		array_add(&proc->blocks, done);
 		proc->curr_block = done;
 		proc->curr_block = done;
 
 
 	case_end;
 	case_end;
@@ -3750,11 +3860,10 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		if (ms->tag != NULL) {
 		if (ms->tag != NULL) {
 			tag = ssa_build_expr(proc, ms->tag);
 			tag = ssa_build_expr(proc, ms->tag);
 		}
 		}
-		ssaBlock *done = ssa__make_block(proc, node, make_string("match.done")); // NOTE(bill): Append later
+		ssaBlock *done = ssa_add_block(proc, node, "match.done"); // NOTE(bill): Append later
 
 
 		ast_node(body, BlockStmt, ms->body);
 		ast_node(body, BlockStmt, ms->body);
 
 
-
 		AstNodeArray default_stmts = {};
 		AstNodeArray default_stmts = {};
 		ssaBlock *default_fall = NULL;
 		ssaBlock *default_fall = NULL;
 		ssaBlock *default_block = NULL;
 		ssaBlock *default_block = NULL;
@@ -3766,28 +3875,24 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		for_array(i, body->stmts) {
 		for_array(i, body->stmts) {
 			AstNode *clause = body->stmts[i];
 			AstNode *clause = body->stmts[i];
 			ssaBlock *body = fall;
 			ssaBlock *body = fall;
-			b32 append_body = false;
-
 
 
 			ast_node(cc, CaseClause, clause);
 			ast_node(cc, CaseClause, clause);
 
 
 			if (body == NULL) {
 			if (body == NULL) {
-				append_body = true;
 				if (cc->list.count == 0) {
 				if (cc->list.count == 0) {
-					body = ssa__make_block(proc, clause, make_string("match.dflt.body"));
+					body = ssa_add_block(proc, clause, "match.dflt.body");
 				} else {
 				} else {
-					body = ssa__make_block(proc, clause, make_string("match.case.body"));
+					body = ssa_add_block(proc, clause, "match.case.body");
 				}
 				}
 			}
 			}
 			if (append_fall && body == fall) {
 			if (append_fall && body == fall) {
 				append_fall = false;
 				append_fall = false;
-				append_body = true;
 			}
 			}
 
 
 			fall = done;
 			fall = done;
 			if (i+1 < case_count) {
 			if (i+1 < case_count) {
 				append_fall = true;
 				append_fall = true;
-				fall = ssa__make_block(proc, clause, make_string("match.fall.body"));
+				fall = ssa_add_block(proc, clause, "match.fall.body");
 			}
 			}
 
 
 			if (cc->list.count == 0) {
 			if (cc->list.count == 0) {
@@ -3799,19 +3904,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			}
 			}
 
 
 			ssaBlock *next_cond = NULL;
 			ssaBlock *next_cond = NULL;
-			Token eq = {Token_CmpEq};
 			for_array(j, cc->list) {
 			for_array(j, cc->list) {
 				AstNode *expr = cc->list[j];
 				AstNode *expr = cc->list[j];
-				next_cond = ssa__make_block(proc, clause, make_string("match.case.next"));
+				next_cond = ssa_add_block(proc, clause, "match.case.next");
 
 
-				ssaValue *cond = ssa_emit_comp(proc, eq, tag, ssa_build_expr(proc, expr));
+				ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag, ssa_build_expr(proc, expr));
 				ssa_emit_if(proc, cond, body, next_cond);
 				ssa_emit_if(proc, cond, body, next_cond);
-				array_add(&proc->blocks, next_cond);
 				proc->curr_block = next_cond;
 				proc->curr_block = next_cond;
 			}
 			}
-			if (append_body) {
-				array_add(&proc->blocks, body);
-			}
 			proc->curr_block = body;
 			proc->curr_block = body;
 
 
 			ssa_push_target_list(proc, done, NULL, fall);
 			ssa_push_target_list(proc, done, NULL, fall);
@@ -3826,7 +3926,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 		if (default_block != NULL) {
 		if (default_block != NULL) {
 			ssa_emit_jump(proc, default_block);
 			ssa_emit_jump(proc, default_block);
-			array_add(&proc->blocks, default_block);
 			proc->curr_block = default_block;
 			proc->curr_block = default_block;
 
 
 			ssa_push_target_list(proc, done, NULL, default_fall);
 			ssa_push_target_list(proc, done, NULL, default_fall);
@@ -3837,7 +3936,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		}
 		}
 
 
 		ssa_emit_jump(proc, done);
 		ssa_emit_jump(proc, done);
-		array_add(&proc->blocks, done);
 		proc->curr_block = done;
 		proc->curr_block = done;
 	case_end;
 	case_end;
 
 
@@ -3856,11 +3954,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 		ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
 		ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
 
 
-		ssaBlock *start_block = ssa_add_block(proc, node, make_string("type-match.case.first"));
+		ssaBlock *start_block = ssa_add_block(proc, node, "type-match.case.first");
 		ssa_emit_jump(proc, start_block);
 		ssa_emit_jump(proc, start_block);
 		proc->curr_block = start_block;
 		proc->curr_block = start_block;
 
 
-		ssaBlock *done = ssa__make_block(proc, node, make_string("type-match.done")); // NOTE(bill): Append later
+		ssaBlock *done = ssa_add_block(proc, node, "type-match.done"); // NOTE(bill): Append later
 
 
 		ast_node(body, BlockStmt, ms->body);
 		ast_node(body, BlockStmt, ms->body);
 
 
@@ -3878,12 +3976,12 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			if (cc->list.count == 0) {
 			if (cc->list.count == 0) {
 				// default case
 				// default case
 				default_stmts = cc->stmts;
 				default_stmts = cc->stmts;
-				default_block = ssa__make_block(proc, clause, make_string("type-match.dflt.body"));
+				default_block = ssa_add_block(proc, clause, "type-match.dflt.body");
 				continue;
 				continue;
 			}
 			}
 
 
 
 
-			ssaBlock *body = ssa__make_block(proc, clause, make_string("type-match.case.body"));
+			ssaBlock *body = ssa_add_block(proc, clause, "type-match.case.body");
 
 
 			Scope *scope = *map_get(&proc->module->info->scopes, hash_pointer(clause));
 			Scope *scope = *map_get(&proc->module->info->scopes, hash_pointer(clause));
 			Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
 			Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
@@ -3907,14 +4005,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			}
 			}
 			GB_ASSERT(index != NULL);
 			GB_ASSERT(index != NULL);
 
 
-			ssaBlock *next_cond = ssa__make_block(proc, clause, make_string("type-match.case.next"));
-			Token eq = {Token_CmpEq};
-			ssaValue *cond = ssa_emit_comp(proc, eq, tag_index, index);
+			ssaBlock *next_cond = ssa_add_block(proc, clause, "type-match.case.next");
+			ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag_index, index);
 			ssa_emit_if(proc, cond, body, next_cond);
 			ssa_emit_if(proc, cond, body, next_cond);
-			array_add(&proc->blocks, next_cond);
 			proc->curr_block = next_cond;
 			proc->curr_block = next_cond;
 
 
-			array_add(&proc->blocks, body);
 			proc->curr_block = body;
 			proc->curr_block = body;
 
 
 			ssa_push_target_list(proc, done, NULL, NULL);
 			ssa_push_target_list(proc, done, NULL, NULL);
@@ -3929,7 +4024,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 		if (default_block != NULL) {
 		if (default_block != NULL) {
 			ssa_emit_jump(proc, default_block);
 			ssa_emit_jump(proc, default_block);
-			array_add(&proc->blocks, default_block);
 			proc->curr_block = default_block;
 			proc->curr_block = default_block;
 
 
 			ssa_push_target_list(proc, done, NULL, NULL);
 			ssa_push_target_list(proc, done, NULL, NULL);
@@ -3940,7 +4034,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		}
 		}
 
 
 		ssa_emit_jump(proc, done);
 		ssa_emit_jump(proc, done);
-		array_add(&proc->blocks, done);
 		proc->curr_block = done;
 		proc->curr_block = done;
 	case_end;
 	case_end;