Browse Source

Remove auto

Ginger Bill 8 years ago
parent
commit
ef8563a818
12 changed files with 608 additions and 667 deletions
  1. 1 17
      src/checker/checker.cpp
  2. 9 9
      src/checker/decl.cpp
  3. 1 1
      src/checker/expr.cpp
  4. 2 2
      src/checker/stmt.cpp
  5. 78 92
      src/checker/types.cpp
  6. 0 303
      src/common.cpp
  7. 301 0
      src/map.c
  8. 5 5
      src/old_vm.cpp
  9. 6 5
      src/parser.cpp
  10. 182 211
      src/ssa.cpp
  11. 2 2
      src/ssa_opt.cpp
  12. 21 20
      src/ssa_print.cpp

+ 1 - 17
src/checker/checker.cpp

@@ -473,22 +473,6 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 
 void check_scope_usage(Checker *c, Scope *scope) {
 	// TODO(bill): Use this?
-#if 0
-	for_array(i, scope->elements.entries) {
-		auto *entry = scope->elements.entries + i;
-		Entity *e = entry->value;
-		if (e->kind == Entity_Variable) {
-			auto *v = &e->Variable;
-			if (!v->is_field && !v->used) {
-				warning(e->token, "Unused variable: %.*s", LIT(e->token.string));
-			}
-		}
-	}
-
-	for (Scope *child = scope->first_child; child != NULL; child = child->next) {
-		check_scope_usage(c, child);
-	}
-#endif
 }
 
 
@@ -961,7 +945,7 @@ void init_preload_types(Checker *c) {
 		t_type_info = e->type;
 		t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
 		GB_ASSERT(is_type_union(e->type));
-		auto *record = &base_type(e->type)->Record;
+		TypeRecord *record = &base_type(e->type)->Record;
 
 		t_type_info_member = record->other_fields[0]->type;
 		t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);

+ 9 - 9
src/checker/decl.cpp

@@ -74,7 +74,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
 		if (o.type->kind != Type_Tuple) {
 			array_add(&operands, o);
 		} else {
-			auto *tuple = &o.type->Tuple;
+			TypeTuple *tuple = &o.type->Tuple;
 			for (isize j = 0; j < tuple->variable_count; j++) {
 				o.type = tuple->variables[j]->type;
 				array_add(&operands, o);
@@ -315,8 +315,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle
 bool are_signatures_similar_enough(Type *a_, Type *b_) {
 	GB_ASSERT(a_->kind == Type_Proc);
 	GB_ASSERT(b_->kind == Type_Proc);
-	auto *a = &a_->Proc;
-	auto *b = &b_->Proc;
+	TypeProc *a = &a_->Proc;
+	TypeProc *b = &b_->Proc;
 
 	if (a->param_count != b->param_count) {
 		return false;
@@ -368,7 +368,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	if ((d->scope->is_file || d->scope->is_global) &&
 	    str_eq(e->token.string, str_lit("main"))) {
 		if (proc_type != NULL) {
-			auto *pt = &proc_type->Proc;
+			TypeProc *pt = &proc_type->Proc;
 			if (pt->param_count != 0 ||
 			    pt->result_count) {
 				gbString str = type_to_string(proc_type);
@@ -402,8 +402,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	}
 
 	if (is_foreign) {
-		auto *fp = &c->info.foreign_procs;
-		auto *proc_decl = &d->proc_decl->ProcDecl;
+		MapEntity *fp = &c->info.foreign_procs;
+		AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
 		String name = proc_decl->name->Ident.string;
 		if (proc_decl->foreign_name.len > 0) {
 			name = proc_decl->foreign_name;
@@ -425,8 +425,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 			map_entity_set(fp, key, e);
 		}
 	} else if (is_link_name) {
-		auto *fp = &c->info.foreign_procs;
-		auto *proc_decl = &d->proc_decl->ProcDecl;
+		MapEntity *fp = &c->info.foreign_procs;
+		AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
 		String name = proc_decl->link_name;
 
 		HashKey key = hash_string(name);
@@ -492,7 +492,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
 
 	GB_ASSERT(type->kind == Type_Proc);
 	if (type->Proc.param_count > 0) {
-		auto *params = &type->Proc.params->Tuple;
+		TypeTuple *params = &type->Proc.params->Tuple;
 		for (isize i = 0; i < params->variable_count; i++) {
 			Entity *e = params->variables[i];
 			GB_ASSERT(e->kind == Entity_Variable);

+ 1 - 1
src/checker/expr.cpp

@@ -3401,7 +3401,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
 		if (o.type->kind != Type_Tuple) {
 			array_add(&operands, o);
 		} else {
-			auto *tuple = &o.type->Tuple;
+			TypeTuple *tuple = &o.type->Tuple;
 			if (variadic && i >= param_count) {
 				error(ast_node_token(ce->args.e[i]),
 				      "`..` in a variadic procedure cannot be applied to a %td-valued expression", tuple->variable_count);

+ 2 - 2
src/checker/stmt.cpp

@@ -441,7 +441,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 				if (o.type->kind != Type_Tuple) {
 					array_add(&operands, o);
 				} else {
-					auto *tuple = &o.type->Tuple;
+					TypeTuple *tuple = &o.type->Tuple;
 					for (isize j = 0; j < tuple->variable_count; j++) {
 						o.type = tuple->variables[j]->type;
 						array_add(&operands, o);
@@ -553,7 +553,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		if (result_count > 0) {
 			Entity **variables = NULL;
 			if (proc_type->Proc.results != NULL) {
-				auto *tuple = &proc_type->Proc.results->Tuple;
+				TypeTuple *tuple = &proc_type->Proc.results->Tuple;
 				variables = tuple->variables;
 			}
 			if (rs->results.count == 0) {

+ 78 - 92
src/checker/types.cpp

@@ -58,114 +58,100 @@ typedef struct BasicType {
 	String    name;
 } BasicType;
 
+typedef enum TypeRecordKind {
+	TypeRecord_Invalid,
 
+	TypeRecord_Struct,
+	TypeRecord_Enum,
+	TypeRecord_RawUnion,
+	TypeRecord_Union, // Tagged
+
+	TypeRecord_Count,
+} TypeRecordKind;
+
+typedef struct TypeRecord {
+	TypeRecordKind kind;
+
+	// All record types
+	// Theses are arrays
+	Entity **fields;      // Entity_Variable (otherwise Entity_TypeName if union)
+	i32      field_count; // == offset_count is struct
+	AstNode *node;
+
+	union { // NOTE(bill): Reduce size_of Type
+		struct { // enum only
+			Type *   enum_base; // Default is `int`
+			Entity * enum_count;
+			Entity * min_value;
+			Entity * max_value;
+		};
+		struct { // struct only
+			i64 *    struct_offsets;
+			bool      struct_are_offsets_set;
+			bool      struct_is_packed;
+			bool      struct_is_ordered;
+			Entity **fields_in_src_order; // Entity_Variable
+		};
+	};
+
+	// Entity_Constant or Entity_TypeName
+	Entity **other_fields;
+	i32      other_field_count;
+} TypeRecord;
 
 #define TYPE_KINDS \
-	TYPE_KIND(Invalid), \
-	TYPE_KIND(Basic), \
-	TYPE_KIND(Pointer), \
-	TYPE_KIND(Array), \
-	TYPE_KIND(Vector), \
-	TYPE_KIND(Slice), \
-	TYPE_KIND(Maybe), \
-	TYPE_KIND(Record), \
-	TYPE_KIND(Named), \
-	TYPE_KIND(Tuple), \
-	TYPE_KIND(Proc), \
-	TYPE_KIND(Count),
+	TYPE_KIND(Basic,   BasicType) \
+	TYPE_KIND(Pointer, struct { Type *elem; }) \
+	TYPE_KIND(Array,   struct { Type *elem; i64 count; }) \
+	TYPE_KIND(Vector,  struct { Type *elem; i64 count; }) \
+	TYPE_KIND(Slice,   struct { Type *elem; }) \
+	TYPE_KIND(Maybe,   struct { Type *elem; }) \
+	TYPE_KIND(Record,  TypeRecord) \
+	TYPE_KIND(Named, struct { \
+		String  name; \
+		Type *  base; \
+		Entity *type_name; /* Entity_TypeName */ \
+	}) \
+	TYPE_KIND(Tuple, struct { \
+		Entity **variables; /* Entity_Variable */ \
+		i32      variable_count; \
+		bool     are_offsets_set; \
+		i64 *    offsets; \
+	}) \
+	TYPE_KIND(Proc, struct { \
+		Scope *scope; \
+		Type * params;  /* Type_Tuple */ \
+		Type * results; /* Type_Tuple */ \
+		i32    param_count; \
+		i32    result_count; \
+		bool   variadic; \
+	})
 
 typedef enum TypeKind {
-#define TYPE_KIND(k, ...) GB_JOIN2(Type_, k)
+	Type_Invalid,
+#define TYPE_KIND(k, ...) GB_JOIN2(Type_, k),
 	TYPE_KINDS
 #undef TYPE_KIND
+	Type_Count,
 } TypeKind;
 
 String const type_strings[] = {
-#define TYPE_KIND(k, ...) {cast(u8 *)#k, gb_size_of(#k)-1}
+	{cast(u8 *)"Invalid", gb_size_of("Invalid")},
+#define TYPE_KIND(k, ...) {cast(u8 *)#k, gb_size_of(#k)-1},
 	TYPE_KINDS
 #undef TYPE_KIND
 };
 
-typedef enum TypeRecordKind {
-	TypeRecord_Invalid,
-
-	TypeRecord_Struct,
-	TypeRecord_Enum,
-	TypeRecord_RawUnion,
-	TypeRecord_Union, // Tagged
-
-	TypeRecord_Count,
-} TypeRecordKind;
+#define TYPE_KIND(k, ...) typedef __VA_ARGS__ GB_JOIN2(Type, k);
+	TYPE_KINDS
+#undef TYPE_KIND
 
 typedef struct Type {
 	TypeKind kind;
 	union {
-		BasicType Basic;
-		struct {
-			Type *elem;
-		} Pointer;
-		struct {
-			Type *elem;
-			i64 count;
-		} Array;
-		struct {
-			Type *elem;
-			i64 count;
-		} Vector;
-		struct {
-			Type *elem;
-		} Slice;
-		struct {
-			Type *elem;
-		} Maybe;
-		struct {
-			TypeRecordKind kind;
-
-			// All record types
-			// Theses are arrays
-			Entity **fields;      // Entity_Variable (otherwise Entity_TypeName if union)
-			i32      field_count; // == offset_count is struct
-			AstNode *node;
-
-			union { // NOTE(bill): Reduce size_of Type
-				struct { // enum only
-					Type *   enum_base; // Default is `int`
-					Entity * enum_count;
-					Entity * min_value;
-					Entity * max_value;
-				};
-				struct { // struct only
-					i64 *    struct_offsets;
-					bool      struct_are_offsets_set;
-					bool      struct_is_packed;
-					bool      struct_is_ordered;
-					Entity **fields_in_src_order; // Entity_Variable
-				};
-			};
-
-			// Entity_Constant or Entity_TypeName
-			Entity **other_fields;
-			i32      other_field_count;
-		} Record;
-		struct {
-			String  name;
-			Type *  base;
-			Entity *type_name; // Entity_TypeName
-		} Named;
-		struct {
-			Entity **variables; // Entity_Variable
-			i32      variable_count;
-			bool      are_offsets_set;
-			i64 *    offsets;
-		} Tuple;
-		struct {
-			Scope *scope;
-			Type * params;  // Type_Tuple
-			Type * results; // Type_Tuple
-			i32    param_count;
-			i32    result_count;
-			bool    variadic;
-		} Proc;
+#define TYPE_KIND(k, ...) GB_JOIN2(Type, k) k;
+	TYPE_KINDS
+#undef TYPE_KIND
 	};
 } Type;
 
@@ -186,9 +172,9 @@ typedef Array(isize) Array_isize;
 typedef struct Selection {
 	Entity *    entity;
 	Array_isize index;
-	bool         indirect; // Set if there was a pointer deref anywhere down the line
+	bool        indirect; // Set if there was a pointer deref anywhere down the line
 } Selection;
-Selection empty_selection = {};
+Selection empty_selection = {0};
 
 Selection make_selection(Entity *entity, Array_isize index, bool indirect) {
 	Selection s = {entity, index, indirect};

+ 0 - 303
src/common.cpp

@@ -246,306 +246,3 @@ i16 f32_to_f16(f32 value) {
 #define MAP_FUNC map_isize_
 #define MAP_NAME MapIsize
 #include "map.c"
-
-
-#if 0
-#ifndef MAP_FIND_RESULT
-#define MAP_FIND_RESULT
-typedef struct MapFindResult {
-	isize hash_index;
-	isize entry_prev;
-	isize entry_index;
-} MapFindResult;
-#endif
-
-
-template <typename T>
-struct MapEntry {
-	HashKey key;
-	isize   next;
-	T       value;
-};
-
-template <typename T>
-struct Map {
-	Array(isize)       hashes;
-	Array(MapEntry<T>) entries;
-};
-
-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);
-
-template <typename T> isize multi_map_count     (Map<T> *h, HashKey key);
-template <typename T> void  multi_map_get_all   (Map<T> *h, HashKey key, T *items);
-template <typename T> void  multi_map_insert    (Map<T> *h, HashKey key, T value);
-template <typename T> void  multi_map_remove    (Map<T> *h, HashKey key, MapEntry<T> *e);
-template <typename T> void  multi_map_remove_all(Map<T> *h, HashKey key);
-
-
-
-
-template <typename T>
-gb_inline void map_init(Map<T> *h, gbAllocator a) {
-	array_init(&h->hashes,  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_reserve(&h->hashes,  a, capacity);
-	array_init_reserve(&h->entries, a, capacity);
-}
-
-template <typename T>
-gb_inline void map_destroy(Map<T> *h) {
-	array_free(&h->entries);
-	array_free(&h->hashes);
-}
-
-template <typename T>
-gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
-	MapEntry<T> e = {};
-	e.key = key;
-	e.next = -1;
-	array_add(&h->entries, e);
-	return h->entries.count-1;
-}
-
-template <typename T>
-gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
-	MapFindResult fr = {-1, -1, -1};
-	if (h->hashes.count > 0) {
-		fr.hash_index  = key.key % h->hashes.count;
-		fr.entry_index = h->hashes.e[fr.hash_index];
-		while (fr.entry_index >= 0) {
-			if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) {
-				return fr;
-			}
-			fr.entry_prev = fr.entry_index;
-			fr.entry_index = h->entries.e[fr.entry_index].next;
-		}
-	}
-	return fr;
-}
-
-template <typename T>
-gb_internal MapFindResult map__find(Map<T> *h, MapEntry<T> *e) {
-	MapFindResult fr = {-1, -1, -1};
-	if (h->hashes.count > 0) {
-		fr.hash_index  = e->key.key % h->hashes.count;
-		fr.entry_index = h->hashes.e[fr.hash_index];
-		while (fr.entry_index >= 0) {
-			if (&h->entries.e[fr.entry_index] == e) {
-				return fr;
-			}
-			fr.entry_prev = fr.entry_index;
-			fr.entry_index = h->entries.e[fr.entry_index].next;
-		}
-	}
-	return fr;
-}
-
-
-template <typename T>
-gb_internal bool map__full(Map<T> *h) {
-	return 0.75f * h->hashes.count <= h->entries.count;
-}
-
-template <typename T>
-gb_inline void map_grow(Map<T> *h) {
-	isize new_count = GB_ARRAY_GROW_FORMULA(h->entries.count);
-	map_rehash(h, new_count);
-}
-
-template <typename T>
-void map_rehash(Map<T> *h, isize new_count) {
-	isize i, j;
-	Map<T> nh = {0};
-	map_init(&nh, h->hashes.allocator);
-	array_resize(&nh.hashes, new_count);
-	array_reserve(&nh.entries, h->entries.count);
-	for (i = 0; i < new_count; i++) {
-		nh.hashes.e[i] = -1;
-	}
-	for (i = 0; i < h->entries.count; i++) {
-		MapEntry<T> *e = &h->entries.e[i];
-		MapFindResult fr;
-		if (nh.hashes.count == 0) {
-			map_grow(&nh);
-		}
-		fr = map__find(&nh, e->key);
-		j = map__add_entry(&nh, e->key);
-		if (fr.entry_prev < 0) {
-			nh.hashes.e[fr.hash_index] = j;
-		} else {
-			nh.entries.e[fr.entry_prev].next = j;
-		}
-		nh.entries.e[j].next = fr.entry_index;
-		nh.entries.e[j].value = e->value;
-		if (map__full(&nh)) {
-			map_grow(&nh);
-		}
-	}
-	map_destroy(h);
-	*h = nh;
-}
-
-template <typename T>
-gb_inline T *map_get(Map<T> *h, HashKey key) {
-	isize index = map__find(h, key).entry_index;
-	if (index >= 0)
-		return &h->entries.e[index].value;
-	return NULL;
-}
-
-template <typename T>
-void map_set(Map<T> *h, HashKey key, T value) {
-	isize index;
-	MapFindResult fr;
-	if (h->hashes.count == 0)
-		map_grow(h);
-	fr = map__find(h, key);
-	if (fr.entry_index >= 0) {
-		index = fr.entry_index;
-	} else {
-		index = map__add_entry(h, key);
-		if (fr.entry_prev >= 0) {
-			h->entries.e[fr.entry_prev].next = index;
-		} else {
-			h->hashes.e[fr.hash_index] = index;
-		}
-	}
-	h->entries.e[index].value = value;
-
-	if (map__full(h))
-		map_grow(h);
-}
-
-
-
-template <typename T>
-void map__erase(Map<T> *h, MapFindResult fr) {
-	if (fr.entry_prev < 0) {
-		h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next;
-	} else {
-		h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next;
-	}
-	if (fr.entry_index == h->entries.count-1) {
-		array_pop(&h->entries);
-		return;
-	}
-	h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1];
-	MapFindResult last = map__find(h, h->entries.e[fr.entry_index].key);
-	if (last.entry_prev >= 0) {
-		h->entries.e[last.entry_prev].next = fr.entry_index;
-	} else {
-		h->hashes.e[last.hash_index] = fr.entry_index;
-	}
-}
-
-template <typename T>
-void map_remove(Map<T> *h, HashKey key) {
-	MapFindResult fr = map__find(h, key);
-	if (fr.entry_index >= 0) {
-		map__erase(h, fr);
-	}
-}
-
-template <typename T>
-gb_inline void map_clear(Map<T> *h) {
-	gb_array_clear(h->hashes);
-	gb_array_clear(h->entries);
-}
-
-
-
-template <typename T>
-MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
-	isize i = map__find(h, key).entry_index;
-	if (i < 0) {
-		return NULL;
-	}
-	return &h->entries.e[i];
-}
-
-template <typename T>
-MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
-	isize i = e->next;
-	while (i >= 0) {
-		if (hash_key_equal(h->entries.e[i].key, e->key)) {
-			return &h->entries.e[i];
-		}
-		i = h->entries.e[i].next;
-	}
-	return NULL;
-}
-
-template <typename T>
-isize multi_map_count(Map<T> *h, HashKey key) {
-	isize count = 0;
-	auto *e = multi_map_find_first(h, key);
-	while (e != NULL) {
-		count++;
-		e = multi_map_find_next(h, e);
-	}
-	return count;
-}
-
-template <typename T>
-void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
-	isize i = 0;
-	auto *e = multi_map_find_first(h, key);
-	while (e != NULL) {
-		items[i++] = e->value;
-		e = multi_map_find_next(h, e);
-	}
-}
-
-template <typename T>
-void multi_map_insert(Map<T> *h, HashKey key, T value) {
-	if (h->hashes.count == 0) {
-		map_grow(h);
-	}
-	MapFindResult fr = map__find(h, key);
-	isize i = map__add_entry(h, key);
-	if (fr.entry_prev < 0) {
-		h->hashes.e[fr.hash_index] = i;
-	} else {
-		h->entries.e[fr.entry_prev].next = i;
-	}
-	h->entries.e[i].next = fr.entry_index;
-	h->entries.e[i].value = value;
-	if (map__full(h)) {
-		map_grow(h);
-	}
-}
-
-template <typename T>
-void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
-	MapFindResult fr = map__find(h, e);
-	if (fr.entry_index >= 0) {
-		map__erase(h, fr);
-	}
-}
-
-template <typename T>
-void multi_map_remove_all(Map<T> *h, HashKey key) {
-	while (map_get(h, key) != NULL) {
-		map_remove(h, key);
-	}
-}
-
-
-
-
-#endif

+ 301 - 0
src/map.c

@@ -0,0 +1,301 @@
+/*
+	Example of usage:
+
+	#define MAP_TYPE String
+	#define MAP_FUNC map_string_
+	#define MAP_NAME MapString
+	#include "map.c"
+*/
+
+#ifndef MAP_FIND_RESULT
+#define MAP_FIND_RESULT
+// NOTE(bill): This is the same for every `Map`
+typedef struct MapFindResult {
+	isize hash_index;
+	isize entry_prev;
+	isize entry_index;
+} MapFindResult;
+#endif
+
+#define _J2(a,b) GB_JOIN2(a,b)
+
+/*
+MAP_TYPE - Entry type
+MAP_FUNC - Function prefix (e.g. entity_map_)
+MAP_NAME - Name of Map (e.g. EntityMap)
+*/
+#define MAP_ENTRY _J2(MAP_NAME,Entry)
+
+typedef struct MAP_ENTRY {
+	HashKey  key;
+	isize    next;
+	MAP_TYPE value;
+} MAP_ENTRY;
+
+typedef struct MAP_NAME {
+	Array(isize)     hashes;
+	Array(MAP_ENTRY) entries;
+} MAP_NAME;
+
+void      _J2(MAP_FUNC,init)             (MAP_NAME *h, gbAllocator a);
+void      _J2(MAP_FUNC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity);
+void      _J2(MAP_FUNC,destroy)          (MAP_NAME *h);
+MAP_TYPE *_J2(MAP_FUNC,get)              (MAP_NAME *h, HashKey key);
+void      _J2(MAP_FUNC,set)              (MAP_NAME *h, HashKey key, MAP_TYPE value);
+void      _J2(MAP_FUNC,remove)           (MAP_NAME *h, HashKey key);
+void      _J2(MAP_FUNC,clear)            (MAP_NAME *h);
+void      _J2(MAP_FUNC,grow)             (MAP_NAME *h);
+void      _J2(MAP_FUNC,rehash)           (MAP_NAME *h, isize new_count);
+
+#if 1
+MAP_ENTRY *_J2(MAP_FUNC,multi_find_first)(MAP_NAME *h, HashKey key);
+MAP_ENTRY *_J2(MAP_FUNC,multi_find_next) (MAP_NAME *h, MAP_ENTRY *e);
+
+isize _J2(MAP_FUNC,multi_count)     (MAP_NAME *h, HashKey key);
+void  _J2(MAP_FUNC,multi_get_all)   (MAP_NAME *h, HashKey key, MAP_TYPE *items);
+void  _J2(MAP_FUNC,multi_insert)    (MAP_NAME *h, HashKey key, MAP_TYPE value);
+void  _J2(MAP_FUNC,multi_remove)    (MAP_NAME *h, HashKey key, MAP_ENTRY *e);
+void  _J2(MAP_FUNC,multi_remove_all)(MAP_NAME *h, HashKey key);
+#endif
+
+
+
+gb_inline void _J2(MAP_FUNC,init)(MAP_NAME *h, gbAllocator a) {
+	array_init(&h->hashes,  a);
+	array_init(&h->entries, a);
+}
+
+gb_inline void _J2(MAP_FUNC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) {
+	array_init_reserve(&h->hashes,  a, capacity);
+	array_init_reserve(&h->entries, a, capacity);
+}
+
+gb_inline void _J2(MAP_FUNC,destroy)(MAP_NAME *h) {
+	array_free(&h->entries);
+	array_free(&h->hashes);
+}
+
+gb_internal isize _J2(MAP_FUNC,_add_entry)(MAP_NAME *h, HashKey key) {
+	MAP_ENTRY e = {};
+	e.key = key;
+	e.next = -1;
+	array_add(&h->entries, e);
+	return h->entries.count-1;
+}
+
+gb_internal MapFindResult _J2(MAP_FUNC,_find)(MAP_NAME *h, HashKey key) {
+	MapFindResult fr = {-1, -1, -1};
+	if (h->hashes.count > 0) {
+		fr.hash_index  = key.key % h->hashes.count;
+		fr.entry_index = h->hashes.e[fr.hash_index];
+		while (fr.entry_index >= 0) {
+			if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) {
+				return fr;
+			}
+			fr.entry_prev = fr.entry_index;
+			fr.entry_index = h->entries.e[fr.entry_index].next;
+		}
+	}
+	return fr;
+}
+
+gb_internal MapFindResult _J2(MAP_FUNC,_find)(MAP_NAME *h, MAP_ENTRY *e) {
+	MapFindResult fr = {-1, -1, -1};
+	if (h->hashes.count > 0) {
+		fr.hash_index  = e->key.key % h->hashes.count;
+		fr.entry_index = h->hashes.e[fr.hash_index];
+		while (fr.entry_index >= 0) {
+			if (&h->entries.e[fr.entry_index] == e) {
+				return fr;
+			}
+			fr.entry_prev = fr.entry_index;
+			fr.entry_index = h->entries.e[fr.entry_index].next;
+		}
+	}
+	return fr;
+}
+
+
+gb_internal b32 _J2(MAP_FUNC,_full)(MAP_NAME *h) {
+	return 0.75f * h->hashes.count <= h->entries.count;
+}
+
+gb_inline void _J2(MAP_FUNC,grow)(MAP_NAME *h) {
+	isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
+	_J2(MAP_FUNC,rehash)(h, new_count);
+}
+
+void _J2(MAP_FUNC,rehash)(MAP_NAME *h, isize new_count) {
+	isize i, j;
+	MAP_NAME nh = {0};
+	_J2(MAP_FUNC,init)(&nh, h->hashes.allocator);
+	array_resize(&nh.hashes, new_count);
+	array_reserve(&nh.entries, h->entries.count);
+	for (i = 0; i < new_count; i++) {
+		nh.hashes.e[i] = -1;
+	}
+	for (i = 0; i < h->entries.count; i++) {
+		MAP_ENTRY *e = &h->entries.e[i];
+		MapFindResult fr;
+		if (nh.hashes.count == 0) {
+			_J2(MAP_FUNC,grow)(&nh);
+		}
+		fr = _J2(MAP_FUNC,_find)(&nh, e->key);
+		j = _J2(MAP_FUNC,_add_entry)(&nh, e->key);
+		if (fr.entry_prev < 0) {
+			nh.hashes.e[fr.hash_index] = j;
+		} else {
+			nh.entries.e[fr.entry_prev].next = j;
+		}
+		nh.entries.e[j].next = fr.entry_index;
+		nh.entries.e[j].value = e->value;
+		if (_J2(MAP_FUNC,_full)(&nh)) {
+			_J2(MAP_FUNC,grow)(&nh);
+		}
+	}
+	_J2(MAP_FUNC,destroy)(h);
+	*h = nh;
+}
+
+gb_inline MAP_TYPE *_J2(MAP_FUNC,get)(MAP_NAME *h, HashKey key) {
+	isize index = _J2(MAP_FUNC,_find)(h, key).entry_index;
+	if (index >= 0) {
+		return &h->entries.e[index].value;
+	}
+	return NULL;
+}
+
+void _J2(MAP_FUNC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
+	isize index;
+	MapFindResult fr;
+	if (h->hashes.count == 0)
+		_J2(MAP_FUNC,grow)(h);
+	fr = _J2(MAP_FUNC,_find)(h, key);
+	if (fr.entry_index >= 0) {
+		index = fr.entry_index;
+	} else {
+		index = _J2(MAP_FUNC,_add_entry)(h, key);
+		if (fr.entry_prev >= 0) {
+			h->entries.e[fr.entry_prev].next = index;
+		} else {
+			h->hashes.e[fr.hash_index] = index;
+		}
+	}
+	h->entries.e[index].value = value;
+
+	if (_J2(MAP_FUNC,_full)(h)) {
+		_J2(MAP_FUNC,grow)(h);
+	}
+}
+
+
+
+void _J2(MAP_FUNC,_erase)(MAP_NAME *h, MapFindResult fr) {
+	if (fr.entry_prev < 0) {
+		h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next;
+	} else {
+		h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next;
+	}
+	if (fr.entry_index == h->entries.count-1) {
+		array_pop(&h->entries);
+		return;
+	}
+	h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1];
+	MapFindResult last = _J2(MAP_FUNC,_find)(h, h->entries.e[fr.entry_index].key);
+	if (last.entry_prev >= 0) {
+		h->entries.e[last.entry_prev].next = fr.entry_index;
+	} else {
+		h->hashes.e[last.hash_index] = fr.entry_index;
+	}
+}
+
+void _J2(MAP_FUNC,remove)(MAP_NAME *h, HashKey key) {
+	MapFindResult fr = _J2(MAP_FUNC,_find)(h, key);
+	if (fr.entry_index >= 0) {
+		_J2(MAP_FUNC,_erase)(h, fr);
+	}
+}
+
+gb_inline void _J2(MAP_FUNC,clear)(MAP_NAME *h) {
+	array_clear(&h->hashes);
+	array_clear(&h->entries);
+}
+
+
+#if 1
+MAP_ENTRY *_J2(MAP_FUNC,multi_find_first)(MAP_NAME *h, HashKey key) {
+	isize i = _J2(MAP_FUNC,_find)(h, key).entry_index;
+	if (i < 0) {
+		return NULL;
+	}
+	return &h->entries.e[i];
+}
+
+MAP_ENTRY *_J2(MAP_FUNC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) {
+	isize i = e->next;
+	while (i >= 0) {
+		if (hash_key_equal(h->entries.e[i].key, e->key)) {
+			return &h->entries.e[i];
+		}
+		i = h->entries.e[i].next;
+	}
+	return NULL;
+}
+
+isize _J2(MAP_FUNC,multi_count)(MAP_NAME *h, HashKey key) {
+	isize count = 0;
+	auto *e = _J2(MAP_FUNC,multi_find_first)(h, key);
+	while (e != NULL) {
+		count++;
+		e = _J2(MAP_FUNC,multi_find_next)(h, e);
+	}
+	return count;
+}
+
+void _J2(MAP_FUNC,multi_get_all)(MAP_NAME *h, HashKey key, MAP_TYPE *items) {
+	isize i = 0;
+	auto *e = _J2(MAP_FUNC,multi_find_first)(h, key);
+	while (e != NULL) {
+		items[i++] = e->value;
+		e = _J2(MAP_FUNC,multi_find_next)(h, e);
+	}
+}
+
+void _J2(MAP_FUNC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
+	if (h->hashes.count == 0) {
+		_J2(MAP_FUNC,grow)(h);
+	}
+	MapFindResult fr = _J2(MAP_FUNC,_find)(h, key);
+	isize i = _J2(MAP_FUNC,_add_entry)(h, key);
+	if (fr.entry_prev < 0) {
+		h->hashes.e[fr.hash_index] = i;
+	} else {
+		h->entries.e[fr.entry_prev].next = i;
+	}
+	h->entries.e[i].next = fr.entry_index;
+	h->entries.e[i].value = value;
+	if (_J2(MAP_FUNC,_full)(h)) {
+		_J2(MAP_FUNC,grow)(h);
+	}
+}
+
+void _J2(MAP_FUNC,multi_remove)(MAP_NAME *h, HashKey key, MAP_ENTRY *e) {
+	MapFindResult fr = _J2(MAP_FUNC,_find)(h, e);
+	if (fr.entry_index >= 0) {
+		_J2(MAP_FUNC,_erase)(h, fr);
+	}
+}
+
+void _J2(MAP_FUNC,multi_remove_all)(MAP_NAME *h, HashKey key) {
+	while (_J2(MAP_FUNC,get)(h, key) != NULL) {
+		_J2(MAP_FUNC,remove)(h, key);
+	}
+}
+#endif
+
+
+#undef _J2
+#undef MAP_TYPE
+#undef MAP_FUNC
+#undef MAP_NAME
+#undef MAP_ENTRY

+ 5 - 5
src/old_vm.cpp

@@ -430,7 +430,7 @@ vmValue vm_operand_value(VirtualMachine *vm, ssaValue *value) {
 		v = vm_exact_value(vm, value, value->Constant.value, value->Constant.type);
 	} break;
 	case ssaValue_ConstantSlice: {
-		auto *cs = &value->ConstantSlice;
+		ssaValueConstant *cs = &value->ConstantSlice;
 		v = vm_make_value_comp(ssa_type(value), vm->stack_allocator, 3);
 		v.val_comp[0] = vm_operand_value(vm, cs->backing_array);
 		v.val_comp[1] = vm_make_value_int(t_int, cs->count);
@@ -1120,7 +1120,7 @@ void vm_exec_instr(VirtualMachine *vm, ssaValue *value) {
 	} break;
 
 	case ssaInstr_BinaryOp: {
-		auto *bo = &instr->BinaryOp;
+		ssaInstrBinaryOp *bo = &instr->BinaryOp;
 		Type *type = ssa_type(bo->left);
 		vmValue lhs = vm_operand_value(vm, bo->left);
 		vmValue rhs = vm_operand_value(vm, bo->right);
@@ -1171,7 +1171,7 @@ void vm_exec_instr(VirtualMachine *vm, ssaValue *value) {
 	} break;
 
 	case ssaInstr_VectorShuffle: {
-		auto *vs = &instr->VectorShuffle;
+		ssaValueVectorShuffle *vs = &instr->VectorShuffle;
 		vmValue old_vector = vm_operand_value(vm, instr->VectorShuffle.vector);
 		vmValue new_vector = vm_make_value_comp(ssa_type(value), vm->stack_allocator, vs->index_count);
 
@@ -1183,7 +1183,7 @@ void vm_exec_instr(VirtualMachine *vm, ssaValue *value) {
 	} break;
 
 	case ssaInstr_BoundsCheck: {
-		auto *bc = &instr->BoundsCheck;
+		ssaInstrBoundsCheck *bc = &instr->BoundsCheck;
 		Array<vmValue> args = {};
 		array_init(&args, vm->stack_allocator, 5);
 		array_add(&args, vm_exact_value(vm, NULL, make_exact_value_string(bc->pos.file), t_string));
@@ -1196,7 +1196,7 @@ void vm_exec_instr(VirtualMachine *vm, ssaValue *value) {
 	} break;
 
 	case ssaInstr_SliceBoundsCheck: {
-		auto *bc = &instr->SliceBoundsCheck;
+		ssaInstrSliceBoundsCheck *bc = &instr->SliceBoundsCheck;
 		Array<vmValue> args = {};
 
 		array_init(&args, vm->stack_allocator, 7);

+ 6 - 5
src/parser.cpp

@@ -101,7 +101,6 @@ AstNodeArray make_ast_node_array(AstFile *f) {
 
 
 #define AST_NODE_KINDS \
-	AST_NODE_KIND(Invalid,  "invalid node",  struct{}) \
 	AST_NODE_KIND(BasicLit, "basic literal", Token) \
 	AST_NODE_KIND(Ident,    "identifier",    Token) \
 	AST_NODE_KIND(Ellipsis, "ellipsis", struct { \
@@ -317,16 +316,18 @@ AST_NODE_KIND(_TypeBegin, "", struct{}) \
 		AstNode *base_type; \
 		AstNodeArray fields; \
 	}) \
-AST_NODE_KIND(_TypeEnd,  "", struct{}) \
-	AST_NODE_KIND(Count, "", struct{})
+AST_NODE_KIND(_TypeEnd,  "", struct{})
 
 typedef enum AstNodeKind {
+	AstNode_Invalid,
 #define AST_NODE_KIND(_kind_name_, ...) GB_JOIN2(AstNode_, _kind_name_),
 	AST_NODE_KINDS
 #undef AST_NODE_KIND
+	AstNode_Count,
 } AstNodeKind;
 
 String const ast_node_strings[] = {
+	{cast(u8 *)"invalid node", gb_size_of("invalid node")},
 #define AST_NODE_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
 	AST_NODE_KINDS
 #undef AST_NODE_KIND
@@ -3101,7 +3102,7 @@ void parse_file(Parser *p, AstFile *f) {
 			syntax_error(ast_node_token(node), "Only declarations are allowed at file scope");
 		} else {
 			if (node->kind == AstNode_ImportDecl) {
-				auto *id = &node->ImportDecl;
+				AstNodeImportDecl *id = &node->ImportDecl;
 				String file_str = id->relpath.string;
 
 				if (!is_import_path_valid(file_str)) {
@@ -3130,7 +3131,7 @@ void parse_file(Parser *p, AstFile *f) {
 				try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
 
 			} else if (node->kind == AstNode_ForeignLibrary) {
-				auto *id = &node->ForeignLibrary;
+				AstNodeForeignLibrary *id = &node->ForeignLibrary;
 				String file_str = id->filepath.string;
 
 				if (!is_import_path_valid(file_str)) {

+ 182 - 211
src/ssa.cpp

@@ -131,73 +131,152 @@ struct ssaProcedure {
 
 
 #define SSA_INSTR_KINDS \
-	SSA_INSTR_KIND(Invalid), \
-	SSA_INSTR_KIND(Comment), \
-	SSA_INSTR_KIND(Local), \
-	SSA_INSTR_KIND(ZeroInit), \
-	SSA_INSTR_KIND(Store), \
-	SSA_INSTR_KIND(Load), \
-	SSA_INSTR_KIND(PtrOffset), \
-	SSA_INSTR_KIND(ArrayElementPtr), \
-	SSA_INSTR_KIND(StructElementPtr), \
-	SSA_INSTR_KIND(ArrayExtractValue), \
-	SSA_INSTR_KIND(StructExtractValue), \
-	SSA_INSTR_KIND(UnionTagPtr), \
-	SSA_INSTR_KIND(UnionTagValue), \
-	SSA_INSTR_KIND(Conv), \
-	SSA_INSTR_KIND(Jump), \
-	SSA_INSTR_KIND(If), \
-	SSA_INSTR_KIND(Return), \
-	SSA_INSTR_KIND(Select), \
-	SSA_INSTR_KIND(Phi), \
-	SSA_INSTR_KIND(Unreachable), \
-	SSA_INSTR_KIND(BinaryOp), \
-	SSA_INSTR_KIND(Call), \
-	SSA_INSTR_KIND(VectorExtractElement), \
-	SSA_INSTR_KIND(VectorInsertElement), \
-	SSA_INSTR_KIND(VectorShuffle), \
-	SSA_INSTR_KIND(StartupRuntime), \
-	SSA_INSTR_KIND(BoundsCheck), \
-	SSA_INSTR_KIND(SliceBoundsCheck), \
+	SSA_INSTR_KIND(Comment, struct { String text; }) \
+	SSA_INSTR_KIND(Local,   struct { \
+		Entity *      entity; \
+		Type *        type; \
+		bool          zero_initialized; \
+		ssaValueArray referrers; \
+	}) \
+	SSA_INSTR_KIND(ZeroInit, struct { ssaValue *address; }) \
+	SSA_INSTR_KIND(Store,    struct { ssaValue *address, *value; }) \
+	SSA_INSTR_KIND(Load,     struct { Type *type; ssaValue *address; }) \
+	SSA_INSTR_KIND(PtrOffset, struct { \
+		ssaValue *address; \
+		ssaValue *offset; \
+	}) \
+	SSA_INSTR_KIND(ArrayElementPtr, struct { \
+		ssaValue *address; \
+		Type *    result_type; \
+		ssaValue *elem_index; \
+	}) \
+	SSA_INSTR_KIND(StructElementPtr, struct {  \
+		ssaValue *address; \
+		Type *    result_type; \
+		i32       elem_index; \
+	}) \
+	SSA_INSTR_KIND(ArrayExtractValue, struct { \
+		ssaValue *address; \
+		Type *    result_type; \
+		i32       index; \
+	}) \
+	SSA_INSTR_KIND(StructExtractValue, struct { \
+		ssaValue *address; \
+		Type *    result_type; \
+		i32       index; \
+	}) \
+	SSA_INSTR_KIND(UnionTagPtr, struct { \
+		ssaValue *address; \
+		Type     *type; /* ^int */  \
+	}) \
+	SSA_INSTR_KIND(UnionTagValue, struct { \
+		ssaValue *address; \
+		Type     *type; /* int */ \
+	}) \
+	SSA_INSTR_KIND(Conv, struct { \
+		ssaConvKind kind; \
+		ssaValue *value; \
+		Type *from, *to; \
+	}) \
+	SSA_INSTR_KIND(Jump, struct { ssaBlock *block; }) \
+	SSA_INSTR_KIND(If, struct { \
+		ssaValue *cond; \
+		ssaBlock *true_block; \
+		ssaBlock *false_block; \
+	}) \
+	SSA_INSTR_KIND(Return, struct { ssaValue *value; }) \
+	SSA_INSTR_KIND(Select, struct { \
+		ssaValue *cond; \
+		ssaValue *true_value; \
+		ssaValue *false_value; \
+	}) \
+	SSA_INSTR_KIND(Phi, struct { ssaValueArray edges; Type *type; }) \
+	SSA_INSTR_KIND(Unreachable, struct {}) \
+	SSA_INSTR_KIND(BinaryOp, struct { \
+		Type *    type; \
+		TokenKind op; \
+		ssaValue *left, *right; \
+	}) \
+	SSA_INSTR_KIND(Call, struct { \
+		Type *    type; /* return type */  \
+		ssaValue *value; \
+		ssaValue **args; \
+		isize      arg_count; \
+	}) \
+	SSA_INSTR_KIND(VectorExtractElement, struct { \
+		ssaValue *vector; \
+		ssaValue *index; \
+	}) \
+	SSA_INSTR_KIND(VectorInsertElement, struct { \
+		ssaValue *vector; \
+		ssaValue *elem; \
+		ssaValue *index; \
+	}) \
+	SSA_INSTR_KIND(VectorShuffle, struct { \
+		ssaValue *vector; \
+		i32 *     indices; \
+		i32       index_count; \
+		Type *    type; \
+	}) \
+	SSA_INSTR_KIND(StartupRuntime, struct {}) \
+	SSA_INSTR_KIND(BoundsCheck, struct { \
+		TokenPos  pos; \
+		ssaValue *index; \
+		ssaValue *len; \
+	}) \
+	SSA_INSTR_KIND(SliceBoundsCheck, struct { \
+		TokenPos  pos; \
+		ssaValue *low; \
+		ssaValue *high; \
+		ssaValue *max; \
+		bool      is_substring; \
+	})
 
 #define SSA_CONV_KINDS \
-	SSA_CONV_KIND(Invalid), \
-	SSA_CONV_KIND(trunc), \
-	SSA_CONV_KIND(zext), \
-	SSA_CONV_KIND(fptrunc), \
-	SSA_CONV_KIND(fpext), \
-	SSA_CONV_KIND(fptoui), \
-	SSA_CONV_KIND(fptosi), \
-	SSA_CONV_KIND(uitofp), \
-	SSA_CONV_KIND(sitofp), \
-	SSA_CONV_KIND(ptrtoint), \
-	SSA_CONV_KIND(inttoptr), \
-	SSA_CONV_KIND(bitcast),
+	SSA_CONV_KIND(trunc) \
+	SSA_CONV_KIND(zext) \
+	SSA_CONV_KIND(fptrunc) \
+	SSA_CONV_KIND(fpext) \
+	SSA_CONV_KIND(fptoui) \
+	SSA_CONV_KIND(fptosi) \
+	SSA_CONV_KIND(uitofp) \
+	SSA_CONV_KIND(sitofp) \
+	SSA_CONV_KIND(ptrtoint) \
+	SSA_CONV_KIND(inttoptr) \
+	SSA_CONV_KIND(bitcast)
 
 typedef enum ssaInstrKind {
-#define SSA_INSTR_KIND(x) GB_JOIN2(ssaInstr_, x)
+	ssaInstr_Invalid,
+#define SSA_INSTR_KIND(x, ...) GB_JOIN2(ssaInstr_, x),
 	SSA_INSTR_KINDS
 #undef SSA_INSTR_KIND
 } ssaInstrKind;
 
 String const ssa_instr_strings[] = {
-#define SSA_INSTR_KIND(x) {cast(u8 *)#x, gb_size_of(#x)-1}
+	{cast(u8 *)"Invalid", gb_size_of("Invalid")-1},
+#define SSA_INSTR_KIND(x, ...) {cast(u8 *)#x, gb_size_of(#x)-1},
 	SSA_INSTR_KINDS
 #undef SSA_INSTR_KIND
 };
 
 typedef enum ssaConvKind {
-#define SSA_CONV_KIND(x) GB_JOIN2(ssaConv_, x)
+	ssaConv_Invalid,
+#define SSA_CONV_KIND(x) GB_JOIN2(ssaConv_, x),
 	SSA_CONV_KINDS
 #undef SSA_CONV_KIND
 } ssaConvKind;
 
 String const ssa_conv_strings[] = {
-#define SSA_CONV_KIND(x) {cast(u8 *)#x, gb_size_of(#x)-1}
+	{cast(u8 *)"Invalid", gb_size_of("Invalid")-1},
+#define SSA_CONV_KIND(x) {cast(u8 *)#x, gb_size_of(#x)-1},
 	SSA_CONV_KINDS
 #undef SSA_CONV_KIND
 };
 
+#define SSA_INSTR_KIND(k, ...) typedef __VA_ARGS__ GB_JOIN2(ssaInstr, k);
+	SSA_INSTR_KINDS
+#undef SSA_INSTR_KIND
+
 typedef struct ssaInstr ssaInstr;
 struct ssaInstr {
 	ssaInstrKind kind;
@@ -206,129 +285,9 @@ struct ssaInstr {
 	Type *type;
 
 	union {
-		struct {
-			String text;
-		} Comment;
-		struct {
-			Entity *          entity;
-			Type *            type;
-			bool               zero_initialized;
-			ssaValueArray referrers;
-		} Local;
-		struct {
-			ssaValue *address;
-		} ZeroInit;
-		struct {
-			ssaValue *address;
-			ssaValue *value;
-		} Store;
-		struct {
-			Type *type;
-			ssaValue *address;
-		} Load;
-		struct {
-			ssaValue *address;
-			Type *    result_type;
-			ssaValue *elem_index;
-		} ArrayElementPtr;
-		struct {
-			ssaValue *address;
-			Type *    result_type;
-			i32       elem_index;
-		} StructElementPtr;
-		struct {
-			ssaValue *address;
-			ssaValue *offset;
-		} PtrOffset;
-		struct {
-			ssaValue *address;
-			Type *    result_type;
-			i32       index;
-		} ArrayExtractValue;
-		struct {
-			ssaValue *address;
-			Type *    result_type;
-			i32       index;
-		} StructExtractValue;
-		struct {
-			ssaValue *address;
-			Type     *type; // ^int
-		} UnionTagPtr;
-		struct {
-			ssaValue *address;
-			Type     *type; // int
-		} UnionTagValue;
-		struct {
-			ssaValue *value;
-			ssaValue *elem;
-			i32       index;
-		} InsertValue;
-		struct {
-			ssaConvKind kind;
-			ssaValue *value;
-			Type *from, *to;
-		} Conv;
-		struct {
-			ssaBlock *block;
-		} Jump;
-		struct {
-			ssaValue *cond;
-			ssaBlock *true_block;
-			ssaBlock *false_block;
-		} If;
-		struct {
-			ssaValue *value;
-		} Return;
-		struct {} Unreachable;
-		struct {
-			ssaValue *cond;
-			ssaValue *true_value;
-			ssaValue *false_value;
-		} Select;
-		struct {
-			ssaValueArray edges;
-			Type *type;
-		} Phi;
-		struct {
-			Type *type;
-			TokenKind op;
-			ssaValue *left, *right;
-		} BinaryOp;
-		struct {
-			Type *type; // return type
-			ssaValue *value;
-			ssaValue **args;
-			isize arg_count;
-		} Call;
-		struct {
-			ssaValue *vector;
-			ssaValue *index;
-		} VectorExtractElement;
-		struct {
-			ssaValue *vector;
-			ssaValue *elem;
-			ssaValue *index;
-		} VectorInsertElement;
-		struct {
-			ssaValue *vector;
-			i32 *indices;
-			i32 index_count;
-			Type *type;
-		} VectorShuffle;
-
-		struct {} StartupRuntime;
-		struct {
-			TokenPos  pos;
-			ssaValue *index;
-			ssaValue *len;
-		} BoundsCheck;
-		struct {
-			TokenPos  pos;
-			ssaValue *low;
-			ssaValue *high;
-			ssaValue *max;
-			bool       is_substring;
-		} SliceBoundsCheck;
+#define SSA_INSTR_KIND(k, ...) GB_JOIN2(ssaInstr, k) k;
+	SSA_INSTR_KINDS
+#undef SSA_INSTR_KIND
 	};
 };
 
@@ -350,45 +309,57 @@ typedef enum ssaValueKind {
 	ssaValue_Count,
 } ssaValueKind;
 
+typedef struct ssaValueConstant {
+	Type *     type;
+	ExactValue value;
+} ssaValueConstant;
+
+typedef struct ssaValueConstantSlice {
+	Type *    type;
+	ssaValue *backing_array;
+	i64       count;
+} ssaValueConstantSlice;
+
+typedef struct ssaValueNil {
+	Type *type;
+} ssaValueNil;
+
+typedef struct ssaValueTypeName {
+	Type * type;
+	String name;
+} ssaValueTypeName;
+
+typedef struct ssaValueGlobal {
+	Entity *      entity;
+	Type *        type;
+	ssaValue *    value;
+	ssaValueArray referrers;
+	bool          is_constant;
+	bool          is_private;
+	bool          is_thread_local;
+	bool          is_unnamed_addr;
+} ssaValueGlobal;
+
+typedef struct ssaValueParam {
+	ssaProcedure *parent;
+	Entity *      entity;
+	Type *        type;
+	ssaValueArray referrers;
+} ssaValueParam;
+
 typedef struct ssaValue {
 	ssaValueKind kind;
 	i32 index;
 	union {
-		struct {
-			Type *     type;
-			ExactValue value;
-		} Constant;
-		struct {
-			Type *    type;
-			ssaValue *backing_array;
-			i64       count;
-		} ConstantSlice;
-		struct {
-			Type *type;
-		} Nil;
-		struct {
-			Type * type;
-			String name;
-		} TypeName;
-		struct {
-			Entity *      entity;
-			Type *        type;
-			ssaValue *    value;
-			ssaValueArray referrers;
-			bool          is_constant;
-			bool          is_private;
-			bool          is_thread_local;
-			bool          is_unnamed_addr;
-		} Global;
-		struct {
-			ssaProcedure *    parent;
-			Entity *          entity;
-			Type *            type;
-			ssaValueArray referrers;
-		} Param;
-		ssaProcedure Proc;
-		ssaBlock     Block;
-		ssaInstr     Instr;
+		ssaValueConstant      Constant;
+		ssaValueConstantSlice ConstantSlice;
+		ssaValueNil           Nil;
+		ssaValueTypeName      TypeName;
+		ssaValueGlobal        Global;
+		ssaValueParam         Param;
+		ssaProcedure          Proc;
+		ssaBlock              Block;
+		ssaInstr              Instr;
 	};
 } ssaValue;
 
@@ -2547,14 +2518,14 @@ void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name) {
 
 	Type *bt = base_type(e->type);
 	if (bt->kind == Type_Record) {
-		auto *s = &bt->Record;
+		TypeRecord *s = &bt->Record;
 		for (isize j = 0; j < s->other_field_count; j++) {
 			ssa_mangle_sub_type_name(m, s->other_fields[j], name);
 		}
 	}
 
 	if (is_type_union(bt)) {
-		auto *s = &bt->Record;
+		TypeRecord *s = &bt->Record;
 		// NOTE(bill): Zeroth entry is null (for `match type` stmts)
 		for (isize j = 1; j < s->field_count; j++) {
 			ssa_mangle_sub_type_name(m, s->fields[j], name);
@@ -3135,7 +3106,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		ssaValue *value = ssa_build_expr(proc, ce->proc);
 		Type *proc_type_ = base_type(ssa_type(value));
 		GB_ASSERT(proc_type_->kind == Type_Proc);
-		auto *type = &proc_type_->Proc;
+		TypeProc *type = &proc_type_->Proc;
 
 		isize arg_index = 0;
 
@@ -3167,7 +3138,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			}
 		}
 
-		auto *pt = &type->params->Tuple;
+		TypeTuple *pt = &type->params->Tuple;
 
 		if (variadic) {
 			isize i = 0;
@@ -3213,7 +3184,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			}
 
 			if (args[0]->kind == ssaValue_Constant) {
-				auto *c = &args[0]->Constant;
+				ssaValueConstant *c = &args[0]->Constant;
 				gb_printf_err("%s %d\n", type_to_string(c->type), c->value.kind);
 			}
 
@@ -3657,7 +3628,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 		case Type_Record: {
 			GB_ASSERT(is_type_struct(bt));
-			auto *st = &bt->Record;
+			TypeRecord *st = &bt->Record;
 			if (cl->elems.count > 0) {
 				ssa_emit_store(proc, v, ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
 				for_array(field_index, cl->elems) {
@@ -4121,7 +4092,7 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
 	case_ast_node(rs, ReturnStmt, node);
 		ssa_emit_comment(proc, str_lit("ReturnStmt"));
 		ssaValue *v = NULL;
-		auto *return_type_tuple  = &proc->type->Proc.results->Tuple;
+		TypeTuple *return_type_tuple  = &proc->type->Proc.results->Tuple;
 		isize return_count = proc->type->Proc.result_count;
 		if (return_count == 0) {
 			// No return values
@@ -4569,7 +4540,7 @@ void ssa_begin_procedure_body(ssaProcedure *proc) {
 	proc->curr_block  = proc->entry_block;
 
 	if (proc->type->Proc.params != NULL) {
-		auto *params = &proc->type->Proc.params->Tuple;
+		TypeTuple *params = &proc->type->Proc.params->Tuple;
 		for (isize i = 0; i < params->variable_count; i++) {
 			Entity *e = params->variables[i];
 			ssaValue *param = ssa_add_param(proc, e);
@@ -4938,7 +4909,7 @@ void ssa_gen_tree(ssaGen *s) {
 		} break;
 
 		case Entity_Procedure: {
-			auto *pd = &decl->proc_decl->ProcDecl;
+			AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
 			String original_name = name;
 			AstNode *body = pd->body;
 			if (pd->tags & ProcTag_foreign) {

+ 2 - 2
src/ssa_opt.cpp

@@ -149,7 +149,7 @@ void ssa_remove_pred(ssaBlock *b, ssaBlock *p) {
 		if (pred != p) {
 			b->preds.e[i] = b->preds.e[j];
 			for_array(k, phis) {
-				auto *phi = &phis.e[k]->Instr.Phi;
+				ssaInstrPhi *phi = &phis.e[k]->Instr.Phi;
 				phi->edges.e[i] = phi->edges.e[j];
 			}
 			i++;
@@ -157,7 +157,7 @@ void ssa_remove_pred(ssaBlock *b, ssaBlock *p) {
 	}
 	b->preds.count = i;
 	for_array(k, phis) {
-		auto *phi = &phis.e[k]->Instr.Phi;
+		ssaInstrPhi *phi = &phis.e[k]->Instr.Phi;
 		phi->edges.count = i;
 	}
 

+ 21 - 20
src/ssa_print.cpp

@@ -268,7 +268,7 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
 			ssa_print_type(f, m, t->Proc.results);
 		}
 		ssa_fprintf(f, " (");
-		auto *params = &t->Proc.params->Tuple;
+		TypeTuple *params = &t->Proc.params->Tuple;
 		for (isize i = 0; i < t->Proc.param_count; i++) {
 			if (i > 0) {
 				ssa_fprintf(f, ", ");
@@ -580,7 +580,7 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type
 		break;
 
 	case ssaValue_ConstantSlice: {
-		auto *cs = &value->ConstantSlice;
+		ssaValueConstantSlice *cs = &value->ConstantSlice;
 		if (cs->backing_array == NULL || cs->count == 0) {
 			ssa_fprintf(f, "zeroinitializer");
 		} else {
@@ -835,7 +835,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_Return: {
-		auto *ret = &instr->Return;
+		ssaInstrReturn *ret = &instr->Return;
 		ssa_fprintf(f, "ret ");
 		if (ret->value == NULL) {
 			ssa_fprintf(f, "void");
@@ -851,7 +851,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_Conv: {
-		auto *c = &instr->Conv;
+		ssaInstrConv *c = &instr->Conv;
 		ssa_fprintf(f, "%%%d = %.*s ", value->index, LIT(ssa_conv_strings[c->kind]));
 		ssa_print_type(f, m, c->from);
 		ssa_fprintf(f, " ");
@@ -867,7 +867,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_BinaryOp: {
-		auto *bo = &value->Instr.BinaryOp;
+		ssaInstrBinaryOp *bo = &value->Instr.BinaryOp;
 		Type *type = base_type(ssa_type(bo->left));
 		Type *elem_type = type;
 		while (elem_type->kind == Type_Vector) {
@@ -975,7 +975,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_Call: {
-		auto *call = &instr->Call;
+		ssaInstrCall *call = &instr->Call;
 		Type *result_type = call->type;
 		if (result_type) {
 			ssa_fprintf(f, "%%%d = ", value->index);
@@ -994,7 +994,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		if (call->arg_count > 0) {
 			Type *proc_type = base_type(ssa_type(call->value));
 			GB_ASSERT(proc_type->kind == Type_Proc);
-			auto *params = &proc_type->Proc.params->Tuple;
+			TypeTuple *params = &proc_type->Proc.params->Tuple;
 			for (isize i = 0; i < call->arg_count; i++) {
 				Entity *e = params->variables[i];
 				GB_ASSERT(e != NULL);
@@ -1042,7 +1042,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_VectorInsertElement: {
-		auto *ie = &instr->VectorInsertElement;
+		ssaInstrVectorInsertElement *ie = &instr->VectorInsertElement;
 		Type *vt = ssa_type(ie->vector);
 		ssa_fprintf(f, "%%%d = insertelement ", value->index);
 
@@ -1064,7 +1064,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_VectorShuffle: {
-		auto *sv = &instr->VectorShuffle;
+		ssaInstrVectorShuffle *sv = &instr->VectorShuffle;
 		Type *vt = ssa_type(sv->vector);
 		ssa_fprintf(f, "%%%d = shufflevector ", value->index);
 
@@ -1090,7 +1090,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_BoundsCheck: {
-		auto *bc = &instr->BoundsCheck;
+		ssaInstrBoundsCheck *bc = &instr->BoundsCheck;
 		ssa_fprintf(f, "call void ");
 		ssa_print_encoded_global(f, str_lit("__bounds_check_error"), false);
 		ssa_fprintf(f, "(");
@@ -1120,7 +1120,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	} break;
 
 	case ssaInstr_SliceBoundsCheck: {
-		auto *bc = &instr->SliceBoundsCheck;
+		ssaInstrSliceBoundsCheck *bc = &instr->SliceBoundsCheck;
 		ssa_fprintf(f, "call void ");
 		if (bc->is_substring) {
 			ssa_print_encoded_global(f, str_lit("__substring_expr_error"), false);
@@ -1188,7 +1188,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 		ssa_fprintf(f, "cc 65 ");
 	}
 
-	auto *proc_type = &proc->type->Proc;
+	TypeProc *proc_type = &proc->type->Proc;
 
 	if (proc_type->result_count == 0) {
 		ssa_fprintf(f, "void");
@@ -1201,7 +1201,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	ssa_fprintf(f, "(");
 
 	if (proc_type->param_count > 0) {
-		auto *params = &proc_type->params->Tuple;
+		TypeTuple *params = &proc_type->params->Tuple;
 		for (isize i = 0; i < params->variable_count; i++) {
 			Entity *e = params->variables[i];
 			if (i > 0) {
@@ -1296,7 +1296,7 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 
 
 	for_array(member_index, m->members.entries) {
-		auto *entry = &m->members.entries.e[member_index];
+		MapSsaValueEntry *entry = &m->members.entries.e[member_index];
 		ssaValue *v = entry->value;
 		if (v->kind != ssaValue_TypeName) {
 			continue;
@@ -1307,7 +1307,7 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 	ssa_fprintf(f, "\n");
 
 	for_array(member_index, m->members.entries) {
-		auto *entry = &m->members.entries.e[member_index];
+		MapSsaValueEntry *entry = &m->members.entries.e[member_index];
 		ssaValue *v = entry->value;
 		if (v->kind != ssaValue_Proc) {
 			continue;
@@ -1318,7 +1318,7 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 	}
 
 	for_array(member_index, m->members.entries) {
-		auto *entry = &m->members.entries.e[member_index];
+		MapSsaValueEntry *entry = &m->members.entries.e[member_index];
 		ssaValue *v = entry->value;
 		if (v->kind != ssaValue_Proc) {
 			continue;
@@ -1330,12 +1330,12 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 
 
 	for_array(member_index, m->members.entries) {
-		auto *entry = &m->members.entries.e[member_index];
+		MapSsaValueEntry *entry = &m->members.entries.e[member_index];
 		ssaValue *v = entry->value;
 		if (v->kind != ssaValue_Global) {
 			continue;
 		}
-		auto *g = &v->Global;
+		ssaValueGlobal *g = &v->Global;
 		Scope *scope = g->entity->scope;
 		bool in_global_scope = false;
 		if (scope != NULL) {
@@ -1371,12 +1371,13 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 	}
 
 
+#if 0
 	if (m->generate_debug_info) {
 		ssa_fprintf(f, "\n");
 		ssa_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
 
 		for_array(di_index, m->debug_info.entries) {
-			auto *entry = &m->debug_info.entries.e[di_index];
+			MapSsaDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
 			ssaDebugInfo *di = entry->value;
 			ssa_fprintf(f, "!%d = ", di->id);
 
@@ -1433,6 +1434,6 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 			ssa_fprintf(f, "\n");
 		}
 	}
-
+#endif
 	ssa_file_buffer_destroy(f);
 }