Browse Source

Better constant strings for SSA; Fix Type_Info

Ginger Bill 8 years ago
parent
commit
09f39ae2cc
12 changed files with 420 additions and 294 deletions
  1. 3 1
      code/demo.odin
  2. 9 5
      src/checker/checker.cpp
  3. 11 6
      src/checker/expr.cpp
  4. 1 1
      src/checker/stmt.cpp
  5. 3 2
      src/checker/types.cpp
  6. 15 8
      src/common.cpp
  7. 108 24
      src/llvm/ssa_to_text.cpp
  8. 30 101
      src/ssa/build.cpp
  9. 12 15
      src/ssa/codegen.cpp
  10. 59 86
      src/ssa/emit.cpp
  11. 136 33
      src/ssa/make.cpp
  12. 33 12
      src/ssa/ssa.cpp

+ 3 - 1
code/demo.odin

@@ -1,8 +1,10 @@
 #import "fmt.odin"
 
+str := "Hellope"
+
 a: [12]u8
 main :: proc() {
 	v: [4]f32
 	v[0] = 123
-	fmt.println("Hellope!", v, v[0], a)
+	fmt.println(str, v, v[0], a)
 }

+ 9 - 5
src/checker/checker.cpp

@@ -200,7 +200,7 @@ struct CheckerInfo {
 	Map<Entity *>          foreign_procs;   // Key: String
 	Map<AstFile *>         files;           // Key: String (full path)
 	Map<isize>             type_info_map;   // Key: Type *
-	isize                  type_info_index;
+	isize                  type_info_count;
 	Entity *               implicit_values[ImplicitValue_Count];
 };
 
@@ -536,7 +536,7 @@ void init_checker_info(CheckerInfo *i) {
 	map_init(&i->foreign_procs,   a);
 	map_init(&i->type_info_map,   a);
 	map_init(&i->files,           a);
-	i->type_info_index = 0;
+	i->type_info_count = 0;
 
 }
 
@@ -736,19 +736,21 @@ void add_type_info_type(Checker *c, Type *t) {
 		Type *prev_type = cast(Type *)e->key.ptr;
 		if (are_types_identical(t, prev_type)) {
 			// Duplicate entry
-			ti_index = i;
+			ti_index = e->value;
 			break;
 		}
 	}
 	if (ti_index < 0) {
 		// Unique entry
 		// NOTE(bill): map entries grow linearly and in order
-		ti_index = c->info.type_info_index;
-		c->info.type_info_index++;
+		ti_index = c->info.type_info_count;
+		c->info.type_info_count++;
 	}
 	map_set(&c->info.type_info_map, hash_pointer(t), ti_index);
 
 
+
+
 	// Add nested types
 
 	if (t->kind == Type_Named) {
@@ -758,6 +760,8 @@ void add_type_info_type(Checker *c, Type *t) {
 	}
 
 	Type *bt = base_type(t);
+	add_type_info_type(c, bt);
+
 	switch (bt->kind) {
 	case Type_Basic: {
 		switch (bt->Basic.kind) {

+ 11 - 6
src/checker/expr.cpp

@@ -248,16 +248,17 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
                   CycleChecker *cycle_checker, String context) {
 	PROF_PROC();
 
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+	defer (gb_temp_arena_memory_end(tmp));
+
 	Map<Entity *> entity_map = {};
-	map_init(&entity_map, heap_allocator());
-	defer (map_destroy(&entity_map));
+	map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(field_count+other_field_count));
+	// defer (map_destroy(&entity_map));
 
 	isize other_field_index = 0;
 	Entity *using_index_expr = NULL;
 
 
-	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
-	defer (gb_temp_arena_memory_end(tmp));
 	struct Delay {
 		Entity *e;
 		AstNode *t;
@@ -661,9 +662,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 	GB_ASSERT(is_type_enum(enum_type));
 	ast_node(et, EnumType, node);
 
+
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+	defer (gb_temp_arena_memory_end(tmp));
+
 	Map<Entity *> entity_map = {};
-	map_init(&entity_map, heap_allocator());
-	defer (map_destroy(&entity_map));
+	map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count));
+	// defer (map_destroy(&entity_map));
 
 	Type *base_type = t_int;
 	if (et->base_type != NULL) {

+ 1 - 1
src/checker/stmt.cpp

@@ -633,7 +633,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			Token token;
 		};
 
-		Map<TypeAndToken> seen = {}; // Multimap
+		Map<TypeAndToken> seen = {}; // NOTE(bill): Multimap
 		map_init(&seen, heap_allocator());
 		defer (map_destroy(&seen));
 		for_array(i, bs->stmts) {

+ 3 - 2
src/checker/types.cpp

@@ -1347,7 +1347,7 @@ gbString write_type_to_string(gbString str, Type *type) {
 			for (isize i = 1; i < type->Record.field_count; i++) {
 				Entity *f = type->Record.fields[i];
 				GB_ASSERT(f->kind == Entity_TypeName);
-				if (i > 0) {
+				if (i > 1) {
 					str = gb_string_appendc(str, "; ");
 				}
 				str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
@@ -1362,8 +1362,9 @@ gbString write_type_to_string(gbString str, Type *type) {
 			for (isize i = 0; i < type->Record.field_count; i++) {
 				Entity *f = type->Record.fields[i];
 				GB_ASSERT(f->kind == Entity_Variable);
-				if (i > 0)
+				if (i > 0) {
 					str = gb_string_appendc(str, ", ");
+				}
 				str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
 				str = gb_string_appendc(str, ": ");
 				str = write_type_to_string(str, f->type);

+ 15 - 8
src/common.cpp

@@ -215,14 +215,15 @@ struct Map {
 	Array<MapEntry<T> > entries;
 };
 
-template <typename T> void map_init   (Map<T> *h, gbAllocator a);
-template <typename T> void map_destroy(Map<T> *h);
-template <typename T> T *  map_get    (Map<T> *h, HashKey key);
-template <typename T> void map_set    (Map<T> *h, HashKey key, T value);
-template <typename T> void map_remove (Map<T> *h, HashKey key);
-template <typename T> void map_clear  (Map<T> *h);
-template <typename T> void map_grow   (Map<T> *h);
-template <typename T> void map_rehash (Map<T> *h, isize new_count);
+template <typename T> void map_init             (Map<T> *h, gbAllocator a);
+template <typename T> void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity);
+template <typename T> void map_destroy          (Map<T> *h);
+template <typename T> T *  map_get              (Map<T> *h, HashKey key);
+template <typename T> void map_set              (Map<T> *h, HashKey key, T value);
+template <typename T> void map_remove           (Map<T> *h, HashKey key);
+template <typename T> void map_clear            (Map<T> *h);
+template <typename T> void map_grow             (Map<T> *h);
+template <typename T> void map_rehash           (Map<T> *h, isize new_count);
 
 template <typename T> MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key);
 template <typename T> MapEntry<T> *multi_map_find_next (Map<T> *h, MapEntry<T> *e);
@@ -242,6 +243,12 @@ gb_inline void map_init(Map<T> *h, gbAllocator a) {
 	array_init(&h->entries, a);
 }
 
+template <typename T>
+gb_inline void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity) {
+	array_init(&h->hashes,  a, capacity);
+	array_init(&h->entries, a, capacity);
+}
+
 template <typename T>
 gb_inline void map_destroy(Map<T> *h) {
 	array_free(&h->entries);

+ 108 - 24
src/llvm/ssa_to_text.cpp

@@ -1,9 +1,11 @@
 b32 ssa_valid_char(u8 c) {
-	if (c >= 0x80)
+	if (c >= 0x80) {
 		return false;
+	}
 
-	if (gb_char_is_alphanumeric(c))
+	if (gb_char_is_alphanumeric(c)) {
 		return true;
+	}
 
 	switch (c) {
 	case '$':
@@ -20,8 +22,9 @@ void ssa_print_escape_string(ssaFileBuffer *f, String name, b32 print_quotes) {
 	isize extra = 0;
 	for (isize i = 0; i < name.len; i++) {
 		u8 c = name.text[i];
-		if (!ssa_valid_char(c))
+		if (!ssa_valid_char(c)) {
 			extra += 2;
+		}
 	}
 
 	if (extra == 0) {
@@ -185,7 +188,9 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
 		} else {
 			ssa_fprintf(f, "{");
 			for (isize i = 0; i < t->Tuple.variable_count; i++) {
-				if (i > 0) ssa_fprintf(f, ", ");
+				if (i > 0) {
+					ssa_fprintf(f, ", ");
+				}
 				ssa_print_type(f, m, t->Tuple.variables[i]->type);
 			}
 			ssa_fprintf(f, "}");
@@ -225,23 +230,6 @@ void ssa_print_compound_element(ssaFileBuffer *f, ssaModule *m, ExactValue v, Ty
 
 	if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) {
 		ssa_fprintf(f, "zeroinitializer");
-	} else if (v.kind == ExactValue_String) {
-		// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
-		// of the .ll file
-		ssaValue *str_array = ssa_add_global_string_array(m, v.value_string);
-
-		ssa_fprintf(f, "{i8* getelementptr inbounds (");
-		ssa_print_type(f, m, str_array->Global.entity->type);
-		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m, str_array->Global.entity->type);
-		ssa_fprintf(f, "* ");
-		ssa_print_encoded_global(f, str_array->Global.entity->token.string, false);
-		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m, t_int);
-		ssa_fprintf(f, " 0, i32 0), ");
-		ssa_print_type(f, m, t_int);
-		ssa_fprintf(f, " %lld}", cast(i64)v.value_string.len);
-
 	} else {
 		ssa_print_exact_value(f, m, v, elem_type);
 	}
@@ -269,9 +257,33 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
 		ssa_fprintf(f, "%s", (value.value_bool ? "true" : "false"));
 		break;
 	case ExactValue_String: {
-		ssa_fprintf(f, "c\"");
-		ssa_print_escape_string(f, value.value_string, false);
-		ssa_fprintf(f, "\"");
+		String str = value.value_string;
+		if (str.len == 0) {
+			ssa_fprintf(f, "zeroinitializer");
+			break;
+		}
+		if (!is_type_string(type)) {
+			GB_ASSERT(is_type_array(type));
+			ssa_fprintf(f, "c\"");
+			ssa_print_escape_string(f, str, false);
+			ssa_fprintf(f, "\"");
+		} else {
+			// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
+			// of the .ll file
+			ssaValue *str_array = ssa_add_global_string_array(m, str);
+
+			ssa_fprintf(f, "{i8* getelementptr inbounds (");
+			ssa_print_type(f, m, str_array->Global.entity->type);
+			ssa_fprintf(f, ", ");
+			ssa_print_type(f, m, str_array->Global.entity->type);
+			ssa_fprintf(f, "* ");
+			ssa_print_encoded_global(f, str_array->Global.entity->token.string, false);
+			ssa_fprintf(f, ", ");
+			ssa_print_type(f, m, t_int);
+			ssa_fprintf(f, " 0, i32 0), ");
+			ssa_print_type(f, m, t_int);
+			ssa_fprintf(f, " %lld}", cast(i64)str.len);
+		}
 	} break;
 	case ExactValue_Integer: {
 		if (is_type_pointer(type)) {
@@ -954,6 +966,78 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "\n");
 	} break;
 
+	case ssaInstr_BoundsCheck: {
+		auto *bc = &instr->BoundsCheck;
+		ssa_fprintf(f, "call void ");
+		ssa_print_encoded_global(f, make_string("__bounds_check_error"), false);
+		ssa_fprintf(f, "(");
+		ssa_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, bc->index, t_int);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, bc->len, t_int);
+
+		ssa_fprintf(f, ")\n");
+	} break;
+
+	case ssaInstr_SliceBoundsCheck: {
+		auto *bc = &instr->SliceBoundsCheck;
+		ssa_fprintf(f, "call void ");
+		if (bc->is_substring) {
+			ssa_print_encoded_global(f, make_string("__substring_expr_error"), false);
+		} else {
+			ssa_print_encoded_global(f, make_string("__slice_expr_error"), false);
+		}
+
+		ssa_fprintf(f, "(");
+		ssa_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, bc->low, t_int);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, bc->high, t_int);
+
+		if (!bc->is_substring) {
+			ssa_fprintf(f, ", ");
+			ssa_print_type(f, m, t_int);
+			ssa_fprintf(f, " ");
+			ssa_print_value(f, m, bc->max, t_int);
+		}
+
+		ssa_fprintf(f, ")\n");
+	} break;
+
 
 	default: {
 		GB_PANIC("<unknown instr> %d\n", instr->kind);

+ 30 - 101
src/ssa/build.cpp

@@ -85,42 +85,6 @@ void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) {
 }
 
 
-void ssa_array_bounds_check(ssaProcedure *proc, Token token, ssaValue *index, ssaValue *len) {
-	if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
-		return;
-	}
-
-	gbAllocator a = proc->module->allocator;
-	ssaValue **args = gb_alloc_array(a, ssaValue *, 5);
-	args[0] = ssa_emit_global_string(proc, token.pos.file);
-	args[1] = ssa_make_const_int(a, token.pos.line);
-	args[2] = ssa_make_const_int(a, token.pos.column);
-	args[3] = ssa_emit_conv(proc, index, t_int);
-	args[4] = ssa_emit_conv(proc, len, t_int);
-
-	ssa_emit_global_call(proc, "__bounds_check_error", args, 5);
-}
-
-void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) {
-	if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
-		return;
-	}
-
-	gbAllocator a = proc->module->allocator;
-	ssaValue **args = gb_alloc_array(a, ssaValue *, 6);
-	args[0] = ssa_emit_global_string(proc, token.pos.file);
-	args[1] = ssa_make_const_int(a, token.pos.line);
-	args[2] = ssa_make_const_int(a, token.pos.column);
-	args[3] = ssa_emit_conv(proc, low, t_int);
-	args[4] = ssa_emit_conv(proc, high, t_int);
-	args[5] = ssa_emit_conv(proc, max, t_int);
-
-	if (!is_substring) {
-		ssa_emit_global_call(proc, "__slice_expr_error", args, 6);
-	} else {
-		ssa_emit_global_call(proc, "__substring_expr_error", args, 5);
-	}
-}
 
 ssaValue *ssa_find_global_variable(ssaProcedure *proc, String name) {
 	ssaValue **value = map_get(&proc->module->members, hash_string(name));
@@ -498,13 +462,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssaValue *elem_size  = ssa_make_const_int(allocator, s);
 					ssaValue *elem_align = ssa_make_const_int(allocator, a);
 
-					ssaValue *len =ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[1]), t_int);
+					ssaValue *len = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[1]), t_int);
 					ssaValue *cap = len;
 					if (ce->args.count == 3) {
 						cap = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[2]), t_int);
 					}
 
-					ssa_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false);
+					ssa_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false);
 
 					ssaValue *slice_size = ssa_emit_arith(proc, Token_Mul, elem_size, cap, t_int);
 
@@ -548,10 +512,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					expr_str.len = expr_len;
 
 					ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 4);
-					args[0] = ssa_emit_global_string(proc, pos.file);
+					args[0] = ssa_make_const_string(proc->module->allocator, pos.file);
 					args[1] = ssa_make_const_int(proc->module->allocator, pos.line);
 					args[2] = ssa_make_const_int(proc->module->allocator, pos.column);
-					args[3] = ssa_emit_global_string(proc, expr_str);
+					args[3] = ssa_make_const_string(proc->module->allocator, expr_str);
 					ssa_emit_global_call(proc, "__assert", args, 4);
 
 					ssa_emit_jump(proc, done);
@@ -569,7 +533,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					TokenPos pos = token.pos;
 
 					ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 4);
-					args[0] = ssa_emit_global_string(proc, pos.file);
+					args[0] = ssa_make_const_string(proc->module->allocator, pos.file);
 					args[1] = ssa_make_const_int(proc->module->allocator, pos.line);
 					args[2] = ssa_make_const_int(proc->module->allocator, pos.column);
 					args[3] = msg;
@@ -904,16 +868,6 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) {
 	GB_ASSERT_NOT_NULL(tv);
 
 	if (tv->value.kind != ExactValue_Invalid) {
-		if (tv->value.kind == ExactValue_String) {
-			ssa_emit_comment(proc, make_string("Emit string constant"));
-			if (tv->value.value_string.len > 0) {
-				return ssa_emit_global_string(proc, tv->value.value_string);
-			} else {
-				ssaValue *null_string = ssa_add_local_generated(proc, t_string);
-				return ssa_emit_load(proc, null_string);
-			}
-		}
-
 		return ssa_add_module_constant(proc->module, tv->type, tv->value);
 	}
 
@@ -957,21 +911,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		Entity *e = entity_of_ident(proc->module->info, expr);
 		TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(expr));
 
-		if (e->kind == Entity_Constant) {
-			if (base_type(e->type) == t_string) {
-				// HACK TODO(bill): This is lazy but it works
-				String str = e->Constant.value.value_string;
-				ssaValue *global_array = ssa_add_global_string_array(proc->module, str);
-				ssaValue *elem = ssa_array_elem(proc, global_array);
-				ssaValue *len =  ssa_make_const_int(proc->module->allocator, str.len);
-				ssaValue *v = ssa_add_local_generated(proc, e->type);
-				ssaValue *str_elem = ssa_emit_struct_ep(proc, v, 0);
-				ssaValue *str_len = ssa_emit_struct_ep(proc, v, 1);
-				ssa_emit_store(proc, str_elem, elem);
-				ssa_emit_store(proc, str_len, len);
-				return ssa_make_addr(v, expr);
-			}
-		}
+		GB_ASSERT(e->kind != Entity_Constant);
 
 		ssaValue *v = NULL;
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
@@ -1087,7 +1027,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			}
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *len = ssa_make_const_int(a, t->Vector.count);
-			ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len);
+			ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
 			return ssa_make_addr_vector(vector, index, expr);
 		} break;
 
@@ -1104,7 +1044,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *elem = ssa_emit_array_ep(proc, array, index);
 			ssaValue *len = ssa_make_const_int(a, t->Vector.count);
-			ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len);
+			ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
 			return ssa_make_addr(elem, expr);
 		} break;
 
@@ -1121,7 +1061,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			ssaValue *elem = ssa_slice_elem(proc, slice);
 			ssaValue *len = ssa_slice_len(proc, slice);
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
-			ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len);
+			ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
 			ssaValue *v = ssa_emit_ptr_offset(proc, elem, index);
 			return ssa_make_addr(v, expr);
 
@@ -1129,31 +1069,26 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 		case Type_Basic: { // Basic_string
 			TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(ie->expr));
-			ssaValue *elem = NULL;
-			ssaValue *len = NULL;
-			if (tv != NULL && tv->mode == Addressing_Constant) {
-				ssaValue *array = ssa_add_global_string_array(proc->module, tv->value.value_string);
-				elem = ssa_array_elem(proc, array);
-				len = ssa_make_const_int(a, tv->value.value_string.len);
+			ssaValue *str;
+			ssaValue *elem;
+			ssaValue *len;
+			ssaValue *index;
+
+			if (using_addr != NULL) {
+				str = ssa_emit_load(proc, using_addr);
 			} else {
-				ssaValue *str = NULL;
-				if (using_addr != NULL) {
-					str = ssa_emit_load(proc, using_addr);
-				} else {
-					str = ssa_build_expr(proc, ie->expr);
-					if (deref) {
-						str = ssa_emit_load(proc, str);
-					}
+				str = ssa_build_expr(proc, ie->expr);
+				if (deref) {
+					str = ssa_emit_load(proc, str);
 				}
-				elem = ssa_string_elem(proc, str);
-				len = ssa_string_len(proc, str);
 			}
+			elem = ssa_string_elem(proc, str);
+			len = ssa_string_len(proc, str);
 
-			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
-			ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len);
+			index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
+			ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
 
-			ssaValue *v = ssa_emit_ptr_offset(proc, elem, index);
-			return ssa_make_addr(v, expr);
+			return ssa_make_addr(ssa_emit_ptr_offset(proc, elem, index), expr);
 		} break;
 		}
 	case_end;
@@ -1188,7 +1123,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			if (max == NULL)  max  = ssa_slice_cap(proc, base);
 			GB_ASSERT(max != NULL);
 
-			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
+			ssa_emit_slice_bounds_check(proc, se->open, low, high, max, false);
 
 			ssaValue *elem = ssa_slice_elem(proc, base);
 			ssaValue *len  = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
@@ -1212,7 +1147,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 			if (max == NULL)  max  = ssa_array_cap(proc, base);
 			GB_ASSERT(max != NULL);
 
-			ssa_slice_bounds_check(proc, se->open, low, high, max, false);
+			ssa_emit_slice_bounds_check(proc, se->open, low, high, max, false);
 
 			ssaValue *elem = ssa_array_elem(proc, addr);
 			ssaValue *len  = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
@@ -1235,7 +1170,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 				high = ssa_string_len(proc, base);
 			}
 
-			ssa_slice_bounds_check(proc, se->open, low, high, high, true);
+			ssa_emit_slice_bounds_check(proc, se->open, low, high, high, true);
 
 			ssaValue *elem, *len;
 			len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
@@ -1258,7 +1193,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 	case_ast_node(de, DerefExpr, expr);
 		// TODO(bill): Is a ptr copy needed?
-		ssaValue *addr = ssa_emit_ptr_offset(proc, ssa_build_expr(proc, de->expr), v_zero);
+		ssaValue *addr = ssa_build_expr(proc, de->expr);
+		addr = ssa_emit_ptr_offset(proc, addr, v_zero);
 		return ssa_make_addr(addr, expr);
 	case_end;
 
@@ -1268,15 +1204,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		Type *t = default_type(type_of_expr(proc->module->info, expr));
 		GB_ASSERT(is_type_tuple(t));
 
-		Type *elem = ssa_type(maybe);
-		GB_ASSERT(is_type_maybe(elem));
-		elem = base_type(elem)->Maybe.elem;
-
 		ssaValue *result = ssa_add_local_generated(proc, t);
-		ssaValue *gep0 = ssa_emit_struct_ep(proc, result, 0);
-		ssaValue *gep1 = ssa_emit_struct_ep(proc, result, 1);
-		ssa_emit_store(proc, gep0, ssa_emit_struct_ev(proc, maybe, 0));
-		ssa_emit_store(proc, gep1, ssa_emit_struct_ev(proc, maybe, 1));
+		ssa_emit_store(proc, result, maybe);
 
 		return ssa_make_addr(result, expr);
 	case_end;

+ 12 - 15
src/ssa/codegen.cpp

@@ -149,9 +149,9 @@ void ssa_gen_tree(ssaGen *s) {
 				if (tav != NULL) {
 					if (tav->value.kind != ExactValue_Invalid) {
 						ExactValue v = tav->value;
-						if (v.kind != ExactValue_String) {
+						// if (v.kind != ExactValue_String) {
 							g->Global.value = ssa_add_module_constant(m, tav->type, v);
-						}
+						// }
 					}
 				}
 			}
@@ -293,7 +293,9 @@ void ssa_gen_tree(ssaGen *s) {
 			Type *t_string_slice_ptr = make_type_pointer(a, make_type_slice(a, t_string));
 
 			auto get_type_info_ptr = [](ssaProcedure *proc, ssaValue *type_info_data, Type *type) -> ssaValue * {
-				return ssa_emit_array_ep(proc, type_info_data, cast(i32)ssa_type_info_index(proc->module->info, type));
+				i32 index = cast(i32)ssa_type_info_index(proc->module->info, type);
+				// gb_printf_err("%d %s\n", index, type_to_string(type));
+				return ssa_emit_array_ep(proc, type_info_data, index);
 			};
 
 			i32 type_info_member_index = 0;
@@ -319,16 +321,11 @@ void ssa_gen_tree(ssaGen *s) {
 					tag = ssa_add_local_generated(proc, t_type_info_named);
 
 					// TODO(bill): Which is better? The mangled name or actual name?
-					// ssaValue *gsa  = ssa_add_global_string_array(proc, make_exact_value_string(t->Named.name));
-					ssaValue *gsa  = ssa_add_global_string_array(m, t->Named.type_name->token.string);
-					ssaValue *elem = ssa_array_elem(proc, gsa);
-					ssaValue *len  = ssa_array_len(proc, ssa_emit_load(proc, gsa));
-					ssaValue *name = ssa_emit_string(proc, elem, len);
-
-					ssaValue *gep  = get_type_info_ptr(proc, type_info_data, t->Named.base);
+					ssaValue *name = ssa_make_const_string(a, t->Named.type_name->token.string);
+					ssaValue *gtip = get_type_info_ptr(proc, type_info_data, t->Named.base);
 
 					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 0), name);
-					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), gep);
+					ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), gtip);
 				} break;
 
 				case Type_Basic:
@@ -453,7 +450,7 @@ void ssa_gen_tree(ssaGen *s) {
 							ssaValue *offset    = ssa_emit_struct_ep(proc, field, 2);
 
 							if (f->token.string.len > 0) {
-								ssa_emit_store(proc, name, ssa_emit_global_string(proc, f->token.string));
+								ssa_emit_store(proc, name, ssa_make_const_string(a, f->token.string));
 							}
 							ssa_emit_store(proc, type_info, tip);
 							ssa_emit_store(proc, offset, ssa_make_const_int(a, foffset));
@@ -502,7 +499,7 @@ void ssa_gen_tree(ssaGen *s) {
 							ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type);
 
 							if (f->token.string.len > 0) {
-								ssa_emit_store(proc, name, ssa_emit_global_string(proc, f->token.string));
+								ssa_emit_store(proc, name, ssa_make_const_string(a, f->token.string));
 							}
 							ssa_emit_store(proc, type_info, tip);
 							ssa_emit_store(proc, offset, ssa_make_const_int(a, 0));
@@ -571,7 +568,7 @@ void ssa_gen_tree(ssaGen *s) {
 								ssaValue *name_gep  = ssa_emit_struct_ep(proc, name_array, i);
 
 								ssa_emit_store(proc, value_gep, ssa_make_const_i64(a, fields[i]->Constant.value.value_integer));
-								ssa_emit_store(proc, name_gep,  ssa_emit_global_string(proc, fields[i]->token.string));
+								ssa_emit_store(proc, name_gep,  ssa_make_const_string(a, fields[i]->token.string));
 							}
 
 							ssaValue *v_count = ssa_make_const_int(a, count);
@@ -617,7 +614,7 @@ void ssa_gen_tree(ssaGen *s) {
 						ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type);
 
 						if (f->token.string.len > 0) {
-							ssa_emit_store(proc, name, ssa_emit_global_string(proc, f->token.string));
+							ssa_emit_store(proc, name, ssa_make_const_string(a, f->token.string));
 						}
 						ssa_emit_store(proc, type_info, tip);
 					}

+ 59 - 86
src/ssa/emit.cpp

@@ -37,56 +37,6 @@ ssaValue *ssa_emit_comment(ssaProcedure *p, String text) {
 }
 
 
-ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) {
-	ssaBlock *b = proc->decl_block; // all variables must be in the first block
-	ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized);
-	instr->Instr.parent = b;
-	array_add(&b->instrs, instr);
-	array_add(&b->locals, instr);
-
-	// if (zero_initialized) {
-		ssa_emit_zero_init(proc, instr);
-	// }
-
-	return instr;
-}
-
-ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) {
-	Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name));
-	if (found) {
-		Entity *e = *found;
-		ssa_emit_comment(proc, e->token.string);
-		return ssa_add_local(proc, e, zero_initialized);
-	}
-	return NULL;
-}
-
-ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) {
-	GB_ASSERT(type != NULL);
-
-	Scope *scope = NULL;
-	if (proc->curr_block) {
-		scope = proc->curr_block->scope;
-	}
-	Entity *e = make_entity_variable(proc->module->allocator,
-	                                 scope,
-	                                 empty_token,
-	                                 type);
-	return ssa_add_local(proc, e, true);
-}
-
-ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
-	ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e);
-#if 1
-	ssaValue *l = ssa_add_local(proc, e);
-	ssa_emit_store(proc, l, v);
-#else
-	ssa_module_add_value(proc->module, e, v);
-#endif
-	return v;
-}
-
-
 ssaValue *ssa_emit_call(ssaProcedure *p, ssaValue *value, ssaValue **args, isize arg_count) {
 	Type *pt = base_type(ssa_type(value));
 	GB_ASSERT(pt->kind == Type_Proc);
@@ -602,31 +552,6 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba
 	return slice;
 }
 
-
-ssaValue *ssa_add_global_string_array(ssaModule *m, String string) {
-	gbAllocator a = m->allocator;
-
-	isize max_len = 6+8+1;
-	u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len);
-	isize len = gb_snprintf(cast(char *)str, max_len, "__str$%x", m->global_string_index);
-	m->global_string_index++;
-
-	String name = make_string(str, len-1);
-	Token token = {Token_String};
-	token.string = name;
-	Type *type = make_type_array(a, t_u8, string.len);
-	ExactValue ev = make_exact_value_string(string);
-	Entity *entity = make_entity_constant(a, NULL, token, type, ev);
-	ssaValue *g = ssa_make_value_global(a, entity, ssa_add_module_constant(m, type, ev));
-	g->Global.is_private  = true;
-	// g->Global.is_constant = true;
-
-	ssa_module_add_value(m, entity, g);
-	map_set(&m->members, hash_string(name), g);
-
-	return g;
-}
-
 ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) {
 	ssaValue *str = ssa_add_local_generated(proc, t_string);
 	ssaValue *str_elem = ssa_emit_struct_ep(proc, str, 0);
@@ -637,14 +562,6 @@ ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) {
 }
 
 
-ssaValue *ssa_emit_global_string(ssaProcedure *proc, String str) {
-	ssaValue *global_array = ssa_add_global_string_array(proc->module, str);
-	ssaValue *elem = ssa_array_elem(proc, global_array);
-	ssaValue *len =  ssa_make_const_int(proc->module->allocator, str.len);
-	return ssa_emit_string(proc, elem, len);
-}
-
-
 
 
 String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
@@ -1101,10 +1018,15 @@ ssaValue *ssa_type_info(ssaProcedure *proc, Type *type) {
 	ssaValue **found = map_get(&proc->module->members, hash_string(make_string(SSA_TYPE_INFO_DATA_NAME)));
 	GB_ASSERT(found != NULL);
 	ssaValue *type_info_data = *found;
-
 	CheckerInfo *info = proc->module->info;
-	ssaValue *entry_index = ssa_make_const_i32(proc->module->allocator, ssa_type_info_index(info, type));
-	return ssa_emit_array_ep(proc, type_info_data, entry_index);
+
+	type = default_type(type);
+
+	i32 entry_index = ssa_type_info_index(info, type);
+
+	// gb_printf_err("%d %s\n", entry_index, type_to_string(type));
+
+	return ssa_emit_array_ep(proc, type_info_data, ssa_make_const_i32(proc->module->allocator, entry_index));
 }
 
 
@@ -1172,6 +1094,57 @@ ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) {
 }
 
 
+void ssa_emit_bounds_check(ssaProcedure *proc, Token token, ssaValue *index, ssaValue *len) {
+	if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
+		return;
+	}
+
+	index = ssa_emit_conv(proc, index, t_int);
+	len = ssa_emit_conv(proc, len, t_int);
+
+	ssa_emit(proc, ssa_make_instr_bounds_check(proc, token.pos, index, len));
+
+	// gbAllocator a = proc->module->allocator;
+	// ssaValue **args = gb_alloc_array(a, ssaValue *, 5);
+	// args[0] = ssa_emit_global_string(proc, token.pos.file);
+	// args[1] = ssa_make_const_int(a, token.pos.line);
+	// args[2] = ssa_make_const_int(a, token.pos.column);
+	// args[3] = ssa_emit_conv(proc, index, t_int);
+	// args[4] = ssa_emit_conv(proc, len, t_int);
+
+	// ssa_emit_global_call(proc, "__bounds_check_error", args, 5);
+}
+
+void ssa_emit_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) {
+	if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
+		return;
+	}
+
+
+	low  = ssa_emit_conv(proc, low,  t_int);
+	high = ssa_emit_conv(proc, high, t_int);
+	max  = ssa_emit_conv(proc, max,  t_int);
+
+	ssa_emit(proc, ssa_make_instr_slice_bounds_check(proc, token.pos, low, high, max, is_substring));
+
+	// gbAllocator a = proc->module->allocator;
+	// ssaValue **args = gb_alloc_array(a, ssaValue *, 6);
+	// args[0] = ssa_emit_global_string(proc, token.pos.file);
+	// args[1] = ssa_make_const_int(a, token.pos.line);
+	// args[2] = ssa_make_const_int(a, token.pos.column);
+	// args[3] = ssa_emit_conv(proc, low, t_int);
+	// args[4] = ssa_emit_conv(proc, high, t_int);
+	// args[5] = ssa_emit_conv(proc, max, t_int);
+
+	// if (!is_substring) {
+	// 	ssa_emit_global_call(proc, "__slice_expr_error", args, 6);
+	// } else {
+	// 	ssa_emit_global_call(proc, "__substring_expr_error", args, 5);
+	// }
+}
+
+
+
 
 
 

+ 136 - 33
src/ssa/make.cpp

@@ -1,4 +1,8 @@
 void ssa_module_add_value(ssaModule *m, Entity *e, ssaValue *v);
+ssaValue *ssa_emit_zero_init(ssaProcedure *p, ssaValue *address);
+ssaValue *ssa_emit_comment(ssaProcedure *p, String text);
+ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value);
+ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address);
 
 
 ssaValue *ssa_alloc_value(gbAllocator a, ssaValueKind kind) {
@@ -255,6 +259,23 @@ ssaValue *ssa_make_instr_comment(ssaProcedure *p, String text) {
 	return v;
 }
 
+ssaValue *ssa_make_instr_bounds_check(ssaProcedure *p, TokenPos pos, ssaValue *index, ssaValue *len) {
+	ssaValue *v = ssa_alloc_instr(p, ssaInstr_BoundsCheck);
+	v->Instr.BoundsCheck.pos   = pos;
+	v->Instr.BoundsCheck.index = index;
+	v->Instr.BoundsCheck.len   = len;
+	return v;
+}
+ssaValue *ssa_make_instr_slice_bounds_check(ssaProcedure *p, TokenPos pos, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) {
+	ssaValue *v = ssa_alloc_instr(p, ssaInstr_SliceBoundsCheck);
+	v->Instr.SliceBoundsCheck.pos  = pos;
+	v->Instr.SliceBoundsCheck.low  = low;
+	v->Instr.SliceBoundsCheck.high = high;
+	v->Instr.SliceBoundsCheck.max  = max;
+	v->Instr.SliceBoundsCheck.is_substring = is_substring;
+	return v;
+}
+
 
 
 ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
@@ -273,6 +294,14 @@ ssaValue *ssa_make_value_constant_slice(gbAllocator a, Type *type, ssaValue *bac
 	return v;
 }
 
+ssaValue *ssa_make_value_constant_string(gbAllocator a, Type *type, String string) {
+	ssaValue *v = ssa_alloc_value(a, ssaValue_ConstantString);
+	v->ConstantString.type   = type;
+	v->ConstantString.string = string;
+	return v;
+}
+
+
 ssaValue *ssa_make_const_int(gbAllocator a, i64 i) {
 	return ssa_make_value_constant(a, t_int, make_exact_value_integer(i));
 }
@@ -285,41 +314,10 @@ ssaValue *ssa_make_const_i64(gbAllocator a, i64 i) {
 ssaValue *ssa_make_const_bool(gbAllocator a, b32 b) {
 	return ssa_make_value_constant(a, t_bool, make_exact_value_bool(b != 0));
 }
-
-ssaValue *ssa_add_module_constant(ssaModule *m, Type *type, ExactValue value) {
-	if (is_type_slice(type)) {
-		ast_node(cl, CompoundLit, value.value_compound);
-		gbAllocator a = m->allocator;
-
-		isize count = cl->elems.count;
-		if (count > 0) {
-			Type *elem = base_type(type)->Slice.elem;
-			Type *t = make_type_array(a, elem, count);
-			ssaValue *backing_array = ssa_add_module_constant(m, t, value);
-
-
-			isize max_len = 7+8+1;
-			u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len);
-			isize len = gb_snprintf(cast(char *)str, max_len, "__csba$%x", m->global_array_index);
-			m->global_array_index++;
-
-			String name = make_string(str, len-1);
-
-			Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value);
-			ssaValue *g = ssa_make_value_global(a, e, backing_array);
-			ssa_module_add_value(m, e, g);
-			map_set(&m->members, hash_string(name), g);
-
-			return ssa_make_value_constant_slice(a, type, g, count);
-		} else {
-			return ssa_make_value_constant_slice(a, type, NULL, 0);
-		}
-	}
-
-	return ssa_make_value_constant(m->allocator, type, value);
+ssaValue *ssa_make_const_string(gbAllocator a, String s) {
+	return ssa_make_value_constant(a, t_string, make_exact_value_string(s));
 }
 
-
 ssaValue *ssa_make_value_procedure(gbAllocator a, ssaModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) {
 	ssaValue *v = ssa_alloc_value(a, ssaValue_Proc);
 	v->Proc.module = m;
@@ -390,5 +388,110 @@ ssaDefer ssa_add_defer_instr(ssaProcedure *proc, isize scope_index, ssaValue *in
 
 
 
+ssaValue *ssa_add_module_constant(ssaModule *m, Type *type, ExactValue value) {
+	if (is_type_slice(type)) {
+		ast_node(cl, CompoundLit, value.value_compound);
+		gbAllocator a = m->allocator;
 
+		isize count = cl->elems.count;
+		if (count == 0) {
+			return ssa_make_value_nil(a, type);
+		}
+		Type *elem = base_type(type)->Slice.elem;
+		Type *t = make_type_array(a, elem, count);
+		ssaValue *backing_array = ssa_add_module_constant(m, t, value);
 
+
+		isize max_len = 7+8+1;
+		u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len);
+		isize len = gb_snprintf(cast(char *)str, max_len, "__csba$%x", m->global_array_index);
+		m->global_array_index++;
+
+		String name = make_string(str, len-1);
+
+		Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value);
+		ssaValue *g = ssa_make_value_global(a, e, backing_array);
+		ssa_module_add_value(m, e, g);
+		map_set(&m->members, hash_string(name), g);
+
+		return ssa_make_value_constant_slice(a, type, g, count);
+	}
+
+	return ssa_make_value_constant(m->allocator, type, value);
+}
+
+ssaValue *ssa_add_global_string_array(ssaModule *m, String string) {
+	gbAllocator a = m->allocator;
+
+	isize max_len = 6+8+1;
+	u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len);
+	isize len = gb_snprintf(cast(char *)str, max_len, "__str$%x", m->global_string_index);
+	m->global_string_index++;
+
+	String name = make_string(str, len-1);
+	Token token = {Token_String};
+	token.string = name;
+	Type *type = make_type_array(a, t_u8, string.len);
+	ExactValue ev = make_exact_value_string(string);
+	Entity *entity = make_entity_constant(a, NULL, token, type, ev);
+	ssaValue *g = ssa_make_value_global(a, entity, ssa_add_module_constant(m, type, ev));
+	g->Global.is_private  = true;
+	// g->Global.is_constant = true;
+
+	ssa_module_add_value(m, entity, g);
+	map_set(&m->members, hash_string(name), g);
+
+	return g;
+}
+
+
+
+
+ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) {
+	ssaBlock *b = proc->decl_block; // all variables must be in the first block
+	ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized);
+	instr->Instr.parent = b;
+	array_add(&b->instrs, instr);
+	array_add(&b->locals, instr);
+
+	// if (zero_initialized) {
+		ssa_emit_zero_init(proc, instr);
+	// }
+
+	return instr;
+}
+
+ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) {
+	Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name));
+	if (found) {
+		Entity *e = *found;
+		ssa_emit_comment(proc, e->token.string);
+		return ssa_add_local(proc, e, zero_initialized);
+	}
+	return NULL;
+}
+
+ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) {
+	GB_ASSERT(type != NULL);
+
+	Scope *scope = NULL;
+	if (proc->curr_block) {
+		scope = proc->curr_block->scope;
+	}
+	Entity *e = make_entity_variable(proc->module->allocator,
+	                                 scope,
+	                                 empty_token,
+	                                 type);
+	return ssa_add_local(proc, e, true);
+}
+
+ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
+	ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e);
+#if 1
+	ssaValue *l = ssa_add_local(proc, e);
+	ssa_emit_store(proc, l, v);
+#else
+	ssa_module_add_value(proc->module, e, v);
+#endif
+	return v;
+}

+ 33 - 12
src/ssa/ssa.cpp

@@ -169,7 +169,9 @@ struct ssaProcedure {
 	SSA_INSTR_KIND(VectorExtractElement), \
 	SSA_INSTR_KIND(VectorInsertElement), \
 	SSA_INSTR_KIND(VectorShuffle), \
-	SSA_INSTR_KIND(StartupRuntime),
+	SSA_INSTR_KIND(StartupRuntime), \
+	SSA_INSTR_KIND(BoundsCheck), \
+	SSA_INSTR_KIND(SliceBoundsCheck), \
 
 #define SSA_CONV_KINDS \
 	SSA_CONV_KIND(Invalid), \
@@ -319,6 +321,18 @@ struct ssaInstr {
 		} VectorShuffle;
 
 		struct {} StartupRuntime;
+		struct {
+			TokenPos  pos;
+			ssaValue *index;
+			ssaValue *len;
+		} BoundsCheck;
+		struct {
+			TokenPos  pos;
+			ssaValue *low;
+			ssaValue *high;
+			ssaValue *max;
+			b32       is_substring;
+		} SliceBoundsCheck;
 	};
 };
 
@@ -328,6 +342,7 @@ enum ssaValueKind {
 
 	ssaValue_Constant,
 	ssaValue_ConstantSlice,
+	ssaValue_ConstantString,
 	ssaValue_Nil,
 	ssaValue_TypeName,
 	ssaValue_Global,
@@ -349,10 +364,14 @@ struct ssaValue {
 			ExactValue value;
 		} Constant;
 		struct {
-			Type *type;
+			Type *    type;
 			ssaValue *backing_array;
-			i64 count;
+			i64       count;
 		} ConstantSlice;
+		struct {
+			Type * type;
+			String string;
+		} ConstantString;
 		struct {
 			Type *type;
 		} Nil;
@@ -361,18 +380,18 @@ struct ssaValue {
 			Type * type;
 		} TypeName;
 		struct {
-			b32 is_constant;
-			b32 is_private;
-			b32 is_thread_local;
-			Entity *  entity;
-			Type *    type;
-			ssaValue *value;
+			b32               is_constant;
+			b32               is_private;
+			b32               is_thread_local;
+			Entity *          entity;
+			Type *            type;
+			ssaValue *        value;
 			Array<ssaValue *> referrers;
 		} Global;
 		struct {
-			ssaProcedure *parent;
-			Entity *entity;
-			Type *  type;
+			ssaProcedure *    parent;
+			Entity *          entity;
+			Type *            type;
 			Array<ssaValue *> referrers;
 		} Param;
 		ssaProcedure Proc;
@@ -523,6 +542,8 @@ Type *ssa_type(ssaValue *value) {
 		return value->Constant.type;
 	case ssaValue_ConstantSlice:
 		return value->ConstantSlice.type;
+	case ssaValue_ConstantString:
+		return value->ConstantString.type;
 	case ssaValue_Nil:
 		return value->Nil.type;
 	case ssaValue_TypeName: