Browse Source

Tagged unions memory layout change; begin demo 002

Ginger Bill 9 years ago
parent
commit
ae72b3c5bd
7 changed files with 137 additions and 78 deletions
  1. 34 23
      src/checker/expr.cpp
  2. 7 12
      src/checker/stmt.cpp
  3. 3 3
      src/checker/type.cpp
  4. 5 2
      src/codegen/codegen.cpp
  5. 1 1
      src/codegen/print_llvm.cpp
  6. 55 36
      src/codegen/ssa.cpp
  7. 32 1
      src/main.cpp

+ 34 - 23
src/checker/expr.cpp

@@ -1934,9 +1934,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 	switch (id) {
 	case BuiltinProc_new: {
 		// new :: proc(Type) -> ^Type
-		Type *type = check_type(c, ce->arg_list);
-		if (type == NULL || type == t_invalid) {
-			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `size_of`");
+		Operand op = {};
+		check_expr_or_type(c, &op, ce->arg_list);
+		Type *type = op.type;
+		if (op.mode != Addressing_Type && type == NULL || type == t_invalid) {
+			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `new`");
 			return false;
 		}
 		operand->mode = Addressing_Value;
@@ -1944,16 +1946,17 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 	} break;
 	case BuiltinProc_new_slice: {
 		// new_slice :: proc(Type, len: int[, cap: int]) -> []Type
-		Type *type = check_type(c, ce->arg_list);
-		if (type == NULL || type == t_invalid) {
-			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `size_of`");
+		Operand op = {};
+		check_expr_or_type(c, &op, ce->arg_list);
+		Type *type = op.type;
+		if (op.mode != Addressing_Type && type == NULL || type == t_invalid) {
+			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `new_slice`");
 			return false;
 		}
 
 		AstNode *len = ce->arg_list->next;
 		AstNode *cap = len->next;
 
-		Operand op = {};
 		check_expr(c, &op, len);
 		if (op.mode == Addressing_Invalid)
 			return false;
@@ -1967,7 +1970,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		}
 
 		if (cap != NULL) {
-			check_expr(c, &op, len);
+			check_expr(c, &op, cap);
 			if (op.mode == Addressing_Invalid)
 				return false;
 			if (!is_type_integer(op.type)) {
@@ -2006,7 +2009,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 	case BuiltinProc_size_of: {
 		// size_of :: proc(Type) -> int
-		Type *type = check_type(c, ce->arg_list);
+		Operand op = {};
+		check_expr_or_type(c, &op, ce->arg_list);
+		Type *type = op.type;
 		if (!type) {
 			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `size_of`");
 			return false;
@@ -2031,7 +2036,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 	case BuiltinProc_align_of: {
 		// align_of :: proc(Type) -> int
-		Type *type = check_type(c, ce->arg_list);
+		Operand op = {};
+		check_expr_or_type(c, &op, ce->arg_list);
+		Type *type = op.type;
 		if (!type) {
 			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `align_of`");
 			return false;
@@ -2054,18 +2061,22 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 	case BuiltinProc_offset_of: {
 		// offset_val :: proc(Type, field) -> int
-		Type *type = get_base_type(check_type(c, ce->arg_list));
+		Operand op = {};
+		check_expr_or_type(c, &op, ce->arg_list);
+		Type *type = get_base_type(op.type);
 		AstNode *field_arg = unparen_expr(ce->arg_list->next);
-		if (type) {
-			if (!is_type_struct(type)) {
-				error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a structure type for `offset_of`");
-				return false;
-			}
-			if (field_arg == NULL ||
-			    field_arg->kind != AstNode_Ident) {
-				error(&c->error_collector, ast_node_token(field_arg), "Expected an identifier for field argument");
-				return false;
-			}
+		if (type != NULL) {
+			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `offset_of`");
+			return false;
+		}
+		if (!is_type_struct(type)) {
+			error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a structure type for `offset_of`");
+			return false;
+		}
+		if (field_arg == NULL ||
+		    field_arg->kind != AstNode_Ident) {
+			error(&c->error_collector, ast_node_token(field_arg), "Expected an identifier for field argument");
+			return false;
 		}
 
 
@@ -2145,7 +2156,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 			gbString str = expr_to_string(ce->arg_list);
 			defer (gb_string_free(str));
 			error(&c->error_collector, ast_node_token(call),
-			      "Static assertion: `%s`", str);
+			      "Compile time assertion: `%s`", str);
 			return true;
 		}
 		if (operand->mode != Addressing_Constant) {
@@ -2468,7 +2479,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		}
 
 		if (cap != NULL) {
-			check_expr(c, &op, len);
+			check_expr(c, &op, cap);
 			if (op.mode == Addressing_Invalid)
 				return false;
 			if (!is_type_integer(op.type)) {

+ 7 - 12
src/checker/stmt.cpp

@@ -1238,21 +1238,19 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			switch (e->kind) {
 			case Entity_TypeName: {
 				Type *t = get_base_type(e->type);
-				if (is_type_enum(t)) {
+				if (is_type_struct(t) || is_type_enum(t)) {
 					for (isize i = 0; i < t->Record.other_field_count; i++) {
 						Entity *f = t->Record.other_fields[i];
 						Entity *found = scope_insert_entity(c->context.scope, f);
 						if (found != NULL) {
-							error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of the constant: %.*s", expr_str, LIT(found->token.string));
+							error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
 							return;
 						}
 						f->using_parent = e;
 					}
-				} else if (is_type_struct(t)) {
-					Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
-					GB_ASSERT(found != NULL);
-					gb_for_array(i, (*found)->elements.entries) {
-						Entity *f = (*found)->elements.entries[i].value;
+				} else if (is_type_union(t)) {
+					for (isize i = 0; i < t->Record.field_count; i++) {
+						Entity *f = t->Record.fields[i];
 						Entity *found = scope_insert_entity(c->context.scope, f);
 						if (found != NULL) {
 							error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
@@ -1260,11 +1258,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 						}
 						f->using_parent = e;
 					}
-				} else if (is_type_union(t)) {
-					Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
-					GB_ASSERT(found != NULL);
-					gb_for_array(i, (*found)->elements.entries) {
-						Entity *f = (*found)->elements.entries[i].value;
+					for (isize i = 0; i < t->Record.other_field_count; i++) {
+						Entity *f = t->Record.other_fields[i];
 						Entity *found = scope_insert_entity(c->context.scope, f);
 						if (found != NULL) {
 							error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));

+ 3 - 3
src/checker/type.cpp

@@ -117,8 +117,8 @@ struct Type {
 
 			// All record types
 			// Theses are arrays
-			Entity **fields; // Entity_Variable
-			isize    field_count; // == offset_count
+			Entity **fields;      // Entity_Variable (otherwise Entity_TypeName if union)
+			isize    field_count; // == offset_count is struct
 			AstNode *node;
 
 			// enum only
@@ -909,7 +909,7 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 				if (max < size)
 					max = size;
 			}
-			return type_size_of(s, allocator, t_int) + max;
+			return align_formula(max, s.max_align) + type_size_of(s, allocator, t_int);
 		} break;
 
 		case TypeRecord_RawUnion: {

+ 5 - 2
src/codegen/codegen.cpp

@@ -65,7 +65,7 @@ struct ssaGlobalVariable {
 	DeclInfo *decl;
 };
 
-void ssa_gen_code(ssaGen *s) {
+void ssa_gen_tree(ssaGen *s) {
 	if (v_zero == NULL) {
 		v_zero   = ssa_make_value_constant(gb_heap_allocator(), t_int,  make_exact_value_integer(0));
 		v_one    = ssa_make_value_constant(gb_heap_allocator(), t_int,  make_exact_value_integer(1));
@@ -203,7 +203,10 @@ void ssa_gen_code(ssaGen *s) {
 
 	// 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");
 
-	ssa_print_llvm_ir(&s->output_file, &s->module);
+
 }
 
 
+void ssa_gen_ir(ssaGen *s) {
+	ssa_print_llvm_ir(&s->output_file, &s->module);
+}

+ 1 - 1
src/codegen/print_llvm.cpp

@@ -160,7 +160,7 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
 			break;
 		case TypeRecord_Union: {
 			i64 size_of_union = type_size_of(s, gb_heap_allocator(), t) - s.word_size;
-			ssa_fprintf(f, "{i%lld, [%lld x i8]}", word_bits, size_of_union);
+			ssa_fprintf(f, "{[%lld x i8], i%lld}", size_of_union, word_bits);
 		} break;
 		case TypeRecord_RawUnion:
 			ssa_fprintf(f, "[%lld x i8]", type_size_of(s, gb_heap_allocator(), t));

+ 55 - 36
src/codegen/ssa.cpp

@@ -313,8 +313,8 @@ void ssa_module_init(ssaModule *m, Checker *c) {
 	m->info = &c->info;
 	m->sizes = c->sizes;
 
-	map_init(&m->values,  m->allocator);
-	map_init(&m->members, m->allocator);
+	map_init(&m->values,  gb_heap_allocator());
+	map_init(&m->members, gb_heap_allocator());
 }
 
 void ssa_module_destroy(ssaModule *m) {
@@ -1394,20 +1394,13 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 				gbAllocator allocator = proc->module->allocator;
 				ssaValue *parent = ssa_add_local_generated(proc, t);
 				ssaValue *tag = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(i));
-				ssa_emit_store(proc, ssa_emit_struct_gep(proc, parent, v_zero32, t_int), tag);
+				ssa_emit_store(proc, ssa_emit_struct_gep(proc, parent, v_one32, t_int), tag);
 
-				i64 tag_size = proc->module->sizes.word_size;
-				i64 underlying_array_size = type_size_of(proc->module->sizes, allocator, t);
-				underlying_array_size -= tag_size;
-				Type *array_type = make_type_array(allocator, t_u8, underlying_array_size);
-				Type *array_type_ptr = make_type_pointer(allocator, array_type);
-				ssaValue *data = ssa_emit_struct_gep(proc, parent, v_one32, array_type_ptr);
-				data = ssa_array_elem(proc, data);
+				ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
 
 				Type *tag_type = src_type;
-				Type *t_u8_ptr = make_type_pointer(allocator, t_u8);
 				Type *tag_type_ptr = make_type_pointer(allocator, tag_type);
-				ssaValue *underlying = ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, data, t_u8_ptr, tag_type_ptr));
+				ssaValue *underlying = ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, data, t_rawptr, tag_type_ptr));
 				ssa_emit_store(proc, underlying, value);
 
 				return ssa_emit_load(proc, parent);
@@ -1534,14 +1527,13 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) {
 	GB_ASSERT(is_type_pointer(ssa_type(value)));
 	gbAllocator allocator = proc->module->allocator;
 
-	// String field_name = check_down_cast_name(t, ssa_type(value));
 	String field_name = check_down_cast_name(t, type_deref(ssa_type(value)));
 	GB_ASSERT(field_name.len > 0);
 	Selection sel = lookup_field(t, field_name, false);
 	Type *t_u8_ptr = make_type_pointer(allocator, t_u8);
 	ssaValue *bytes = ssa_emit_conv(proc, value, t_u8_ptr);
 
-	// IMPORTANT TODO(bill): THIS ONLY DOES ONE LAY DEEP!!! FUCKING HELL THIS IS NOT WHAT I SIGNED UP FOR!
+	// IMPORTANT TODO(bill): THIS ONLY DOES ONE LAYER DEEP!!! FUCKING HELL THIS IS NOT WHAT I SIGNED UP FOR!
 
 	i64 offset_ = type_offset_of_from_selection(proc->module->sizes, allocator, type_deref(t), sel);
 	ssaValue *offset = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(-offset_));
@@ -1549,6 +1541,32 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) {
 	return ssa_emit_conv(proc, head, t);
 }
 
+void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssaBlock *false_block);
+
+ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *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"));
+
+	ssaValue *result = ssa_add_local_generated(proc, t_bool);
+	ssa_build_cond(proc, expr, true_, false_);
+
+	proc->curr_block = true_;
+	ssa_emit_store(proc, result, v_true);
+	ssa_emit_jump(proc, done);
+
+	proc->curr_block = false_;
+	ssa_emit_store(proc, result, v_false);
+	ssa_emit_jump(proc, done);
+
+	gb_array_append(proc->blocks, done);
+	proc->curr_block = done;
+
+	return ssa_emit_load(proc, result);
+}
+
+
 
 ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
 	switch (expr->kind) {
@@ -1644,6 +1662,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			return ssa_emit_conv(proc, cmp, default_type(tv->type));
 		} break;
 
+		case Token_CmpAnd:
+		case Token_CmpOr:
+			return ssa_emit_logical_binary_expr(proc, expr);
+
 		case Token_as:
 			ssa_emit_comment(proc, make_string("cast - as"));
 			return ssa_emit_conv(proc, ssa_build_expr(proc, be->left), tv->type);
@@ -1917,13 +1939,15 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					err_len += 2;
 					// HACK(bill): memory leaks
 					u8 *err_str = gb_alloc_array(gb_heap_allocator(), u8, err_len);
-					isize len = gb_snprintf(cast(char *)err_str, err_len,
-					                        "%.*s(%td:%td) Runtime assertion: %s\n",
-					                        LIT(pos.file), pos.line, pos.column, expr);
+					err_len = gb_snprintf(cast(char *)err_str, err_len,
+					                      "%.*s(%td:%td) Runtime assertion: %s\n",
+					                      LIT(pos.file), pos.line, pos.column, expr);
+					err_len--;
 
-					ssaValue *array = ssa_add_global_string_array(proc, make_exact_value_string(make_string(err_str, len-1)));
+					ssaValue *array = ssa_add_global_string_array(proc, make_exact_value_string(make_string(err_str, err_len)));
 					ssaValue *elem = ssa_array_elem(proc, array);
-					ssaValue *string = ssa_emit_load(proc, ssa_emit_string(proc, elem, ssa_array_len(proc, array)));
+					ssaValue *len = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(err_len));
+					ssaValue *string = ssa_emit_string(proc, elem, len);
 
 					ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 1);
 					args[0] = string;
@@ -2224,8 +2248,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssa_emit_store(proc, addr, args[i]);
 				}
 
-				ssaValue *base_elem = ssa_emit_struct_gep(proc, base_array, v_zero32, elem_type);
-				ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_zero32, elem_ptr_type), base_elem);
+				ssaValue *base_elem  = ssa_emit_struct_gep(proc, base_array, v_zero32, elem_ptr_type);
+				ssaValue *slice_elem = ssa_emit_struct_gep(proc, slice,      v_zero32, elem_ptr_type);
+				ssa_emit_store(proc, slice_elem, base_elem);
 				ssaValue *len = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(slice_len));
 				ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_one32, t_int), len);
 				ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int), len);
@@ -2425,7 +2450,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			}
 		} break;
 		case Type_Pointer: {
-			ssaValue *array = ssa_emit_load(proc, ssa_build_expr(proc, ie->expr));
+			ssaValue *array = ssa_build_expr(proc, ie->expr);
 			elem = ssa_array_elem(proc, array);
 		} break;
 		}
@@ -2545,13 +2570,13 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
 
 	case_ast_node(be, BinaryExpr, cond);
 		if (be->op.kind == Token_CmpAnd) {
-			ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp-and"));
+			ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp.and"));
 			ssa_build_cond(proc, be->left, block, false_block);
 			proc->curr_block = block;
 			ssa_build_cond(proc, be->right, true_block, false_block);
 			return;
 		} 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, make_string("cmp.or"));
 			ssa_build_cond(proc, be->left, true_block, block);
 			proc->curr_block = block;
 			ssa_build_cond(proc, be->right, true_block, false_block);
@@ -3123,18 +3148,12 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		Type *union_type = type_deref(ssa_type(parent));
 		GB_ASSERT(is_type_union(union_type));
 
-		ssaValue *tag_index = ssa_emit_struct_gep(proc, parent, v_zero32, make_type_pointer(allocator, t_int));
+		ssaValue *tag_index = ssa_emit_struct_gep(proc, parent, v_one32, make_type_pointer(allocator, t_int));
 		tag_index = ssa_emit_load(proc, tag_index);
 
-		i64 tag_size = proc->module->sizes.word_size;
-		i64 underlying_array_size = type_size_of(proc->module->sizes, allocator, union_type);
-		underlying_array_size -= tag_size;
-		Type *array_type = make_type_array(allocator, t_u8, underlying_array_size);
-		Type *array_type_ptr = make_type_pointer(allocator, array_type);
-		ssaValue *data = ssa_emit_struct_gep(proc, parent, v_one32, array_type_ptr);
-		data = ssa_array_elem(proc, data);
+		ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
 
-		ssaBlock *done = ssa__make_block(proc, node, make_string("type.match.done")); // NOTE(bill): Append later
+		ssaBlock *done = ssa__make_block(proc, node, make_string("type-match.done")); // NOTE(bill): Append later
 
 		ast_node(body, BlockStmt, ms->body);
 
@@ -3157,9 +3176,9 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			if (body == NULL) {
 				append_body = true;
 				if (cc->list == NULL) {
-					body = ssa__make_block(proc, clause, make_string("type.match.dflt.body"));
+					body = ssa__make_block(proc, clause, make_string("type-match.dflt.body"));
 				} else {
-					body = ssa__make_block(proc, clause, make_string("type.match.case.body"));
+					body = ssa__make_block(proc, clause, make_string("type-match.case.body"));
 				}
 			}
 
@@ -3189,7 +3208,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 			}
 			GB_ASSERT(index != NULL);
 
-			ssaBlock *next_cond = ssa__make_block(proc, clause, make_string("type.match.case.next"));
+			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);
 			ssa_emit_if(proc, cond, body, next_cond);

+ 32 - 1
src/main.cpp

@@ -46,6 +46,9 @@ int main(int argc, char **argv) {
 		return 1;
 	}
 
+	u64 start_time, end_time;
+	start_time = gb_utc_time_now();
+
 	init_universal_scope();
 
 	char *init_filename = argv[1];
@@ -64,6 +67,10 @@ int main(int argc, char **argv) {
 	if (parse_files(&parser, init_filename) != ParseFile_None)
 		return 1;
 
+	end_time = gb_utc_time_now();
+	gb_printf_err("Parser: %lld ms\n", (end_time - start_time)/1000);
+	start_time = gb_utc_time_now();
+
 	// print_ast(parser.files[0].decls, 0);
 
 	Checker checker = {};
@@ -73,13 +80,30 @@ int main(int argc, char **argv) {
 
 	check_parsed_files(&checker);
 
+
+	// end_time = gb_utc_time_now();
+	// gb_printf_err("Checker: %lld ms\n", (end_time - start_time)/1000);
+	// start_time = gb_utc_time_now();
+
 #if 1
 	ssaGen ssa = {};
 	if (!ssa_gen_init(&ssa, &checker))
 		return 1;
 	defer (ssa_gen_destroy(&ssa));
 
-	ssa_gen_code(&ssa);
+	ssa_gen_tree(&ssa);
+
+	// end_time = gb_utc_time_now();
+	// gb_printf_err("ssa tree: %lld ms\n", (end_time - start_time)/1000);
+	// start_time = gb_utc_time_now();
+
+	// TODO(bill): Speedup writing to file for IR code
+	ssa_gen_ir(&ssa);
+
+	// end_time = gb_utc_time_now();
+	// gb_printf_err("ssa ir: %lld ms\n", (end_time - start_time)/1000);
+	// start_time = gb_utc_time_now();
+
 
 	char const *output_name = ssa.output_file.filename;
 	isize base_name_len = gb_path_extension(output_name)-1 - output_name;
@@ -93,6 +117,10 @@ int main(int argc, char **argv) {
 	if (exit_code != 0)
 		return exit_code;
 
+	// end_time = gb_utc_time_now();
+	// gb_printf_err("llvm-opt: %lld ms\n", (end_time - start_time)/1000);
+	// start_time = gb_utc_time_now();
+
 	gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib");
 	char lib_str_buf[1024] = {};
 	gb_for_array(i, parser.system_libraries) {
@@ -116,6 +144,9 @@ int main(int argc, char **argv) {
 	if (exit_code != 0)
 		return exit_code;
 
+	// end_time = gb_utc_time_now();
+	// gb_printf_err("clang: %lld ms\n\n\n", (end_time - start_time)/1000);
+
 	if (run_output) {
 		win32_exec_command_line_app("%.*s.exe", cast(int)base_name_len, output_name);
 	}