2
0
Ginger Bill 8 жил өмнө
parent
commit
3ec67853e1

+ 1 - 6
code/demo.odin

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

+ 1 - 1
src/checker/checker.cpp

@@ -301,7 +301,7 @@ void destroy_scope(Scope *scope) {
 	for_array(i, scope->elements.entries) {
 		Entity *e =scope->elements.entries[i].value;
 		if (e->kind == Entity_Variable) {
-			if (!e->Variable.used) {
+			if (!(e->flags & EntityFlag_Used)) {
 #if 0
 				warning(e->token, "Unused variable `%.*s`", LIT(e->token.string));
 #endif

+ 7 - 7
src/checker/decl.cpp

@@ -198,11 +198,11 @@ void check_var_decl_node(Checker *c, AstNode *node) {
 	for (isize i = 0; i < entity_count; i++) {
 		Entity *e = entities[i];
 		GB_ASSERT(e != NULL);
-		if (e->Variable.visited) {
+		if (e->flags & EntityFlag_Visited) {
 			e->type = t_invalid;
 			continue;
 		}
-		e->Variable.visited = true;
+		e->flags |= EntityFlag_Visited;
 
 		if (e->type == NULL)
 			e->type = init_type;
@@ -270,11 +270,11 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
 
 	GB_ASSERT(e->type == NULL);
 
-	if (e->Variable.visited) {
+	if (e->flags & EntityFlag_Visited) {
 		e->type = t_invalid;
 		return;
 	}
-	e->Variable.visited = true;
+	e->flags |= EntityFlag_Visited;
 
 	if (type_expr) {
 		Type *t = check_type(c, type_expr);
@@ -463,11 +463,11 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
 	GB_ASSERT(e->type == NULL);
 	GB_ASSERT(e->kind == Entity_Variable);
 
-	if (e->Variable.visited) {
+	if (e->flags & EntityFlag_Visited) {
 		e->type = t_invalid;
 		return;
 	}
-	e->Variable.visited = true;
+	e->flags |= EntityFlag_Visited;
 
 	if (type_expr != NULL)
 		e->type = check_type(c, type_expr, NULL);
@@ -511,7 +511,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
 		for (isize i = 0; i < params->variable_count; i++) {
 			Entity *e = params->variables[i];
 			GB_ASSERT(e->kind == Entity_Variable);
-			if (!e->Variable.anonymous) {
+			if (!(e->flags & EntityFlag_Anonymous)) {
 				continue;
 			}
 			String name = e->token.string;

+ 18 - 19
src/checker/entity.cpp

@@ -28,10 +28,19 @@ String const entity_strings[] = {
 #undef ENTITY_KIND
 };
 
+enum EntityFlag : u32 {
+	EntityFlag_Visited   = 1<<0,
+	EntityFlag_Used      = 1<<1,
+	EntityFlag_Anonymous = 1<<2,
+	EntityFlag_Field     = 1<<3,
+	EntityFlag_Param     = 1<<4,
+};
+
 struct Entity {
 	EntityKind kind;
-	Scope *    scope;
+	u32        flags;
 	Token      token;
+	Scope *    scope;
 	Type *     type;
 	AstNode *  identifier; // Can be NULL
 
@@ -44,21 +53,11 @@ struct Entity {
 			ExactValue value;
 		} Constant;
 		struct {
-			b8  visited;
-			b8  used;
-			b8  anonymous;
-			b8  field;
-			b8  param;
-
 			i32 field_index;
 			i32 field_src_index;
 		} Variable;
-		struct {
-			b32 used;
-		} TypeName;
-		struct {
-			b32 used;
-		} Procedure;
+		struct {} TypeName;
+		struct {} Procedure;
 		struct {
 			BuiltinProcId id;
 		} Builtin;
@@ -109,7 +108,7 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
 	GB_ASSERT(parent != NULL);
 	Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
 	entity->using_parent = parent;
-	entity->Variable.anonymous = true;
+	entity->flags |= EntityFlag_Anonymous;
 	return entity;
 }
 
@@ -127,9 +126,9 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
 
 Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, b32 anonymous) {
 	Entity *entity = make_entity_variable(a, scope, token, type);
-	entity->Variable.used = true;
-	entity->Variable.anonymous = cast(b8)anonymous;
-	entity->Variable.param = true;
+	entity->flags |= EntityFlag_Used;
+	entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
+	entity->flags |= EntityFlag_Param;
 	return entity;
 }
 
@@ -137,8 +136,8 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
 	Entity *entity = make_entity_variable(a, scope, token, type);
 	entity->Variable.field_src_index = field_src_index;
 	entity->Variable.field_index = field_src_index;
-	entity->Variable.field  = true;
-	entity->Variable.anonymous = cast(b8)anonymous;
+	entity->flags |= EntityFlag_Field;
+	entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
 	return entity;
 }
 

+ 8 - 8
src/checker/expr.cpp

@@ -26,7 +26,7 @@ b32 check_is_assignable_to_using_subtype(Type *dst, Type *src) {
 	if (is_type_struct(src)) {
 		for (isize i = 0; i < src->Record.field_count; i++) {
 			Entity *f = src->Record.fields[i];
-			if (f->kind == Entity_Variable && f->Variable.anonymous) {
+			if (f->kind == Entity_Variable && (f->flags & EntityFlag_Anonymous)) {
 				if (are_types_identical(dst, f->type)) {
 					return true;
 				}
@@ -231,7 +231,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
 			} else {
 				map_set(entity_map, key, f);
 				add_entity(c, c->context.scope, NULL, f);
-				if (f->Variable.anonymous) {
+				if (f->flags & EntityFlag_Anonymous) {
 					populate_using_entity_map(c, node, f->type, entity_map);
 				}
 			}
@@ -435,7 +435,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 						b32 ok = true;
 						for_array(emi, entity_map.entries) {
 							Entity *e = entity_map.entries[emi].value;
-							if (e->kind == Entity_Variable && e->Variable.anonymous) {
+							if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
 								if (is_type_indexable(e->type)) {
 									if (e->identifier != vd->names[0]) {
 										ok = false;
@@ -448,7 +448,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 						if (ok) {
 							using_index_expr = fields[field_index-1];
 						} else {
-							fields[field_index-1]->Variable.anonymous = false;
+							fields[field_index-1]->flags &= ~EntityFlag_Anonymous;
 							error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string));
 						}
 					} else {
@@ -936,7 +936,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
 		break;
 
 	case Entity_Variable:
-		e->Variable.used = true;
+		e->flags |= EntityFlag_Used;
 		if (type == t_invalid) {
 			o->type = t_invalid;
 			return;
@@ -1748,8 +1748,8 @@ String check_down_cast_name(Type *dst_, Type *src_) {
 	GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s));
 	for (isize i = 0; i < dst_s->Record.field_count; i++) {
 		Entity *f = dst_s->Record.fields[i];
-		GB_ASSERT(f->kind == Entity_Variable && f->Variable.field);
-		if (f->Variable.anonymous) {
+		GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
+		if (f->flags & EntityFlag_Anonymous) {
 			if (are_types_identical(f->type, src_)) {
 				return f->token.string;
 			}
@@ -3490,7 +3490,7 @@ Entity *find_using_index_expr(Type *t) {
 	for (isize i = 0; i < t->Record.field_count; i++) {
 		Entity *f = t->Record.fields[i];
 		if (f->kind == Entity_Variable &&
-		    f->Variable.field && f->Variable.anonymous) {
+		    f->flags & (EntityFlag_Anonymous|EntityFlag_Field)) {
 			if (is_type_indexable(f->type)) {
 				return f;
 			}

+ 5 - 3
src/checker/stmt.cpp

@@ -252,14 +252,16 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 		ast_node(i, Ident, node);
 		e = scope_lookup_entity(c->context.scope, i->string);
 		if (e != NULL && e->kind == Entity_Variable) {
-			used = e->Variable.used; // TODO(bill): Make backup just in case
+			used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case
 		}
 	}
 
 
 	Operand op_b = {Addressing_Invalid};
 	check_expr(c, &op_b, lhs);
-	if (e) e->Variable.used = used;
+	if (e) {
+		e->flags |= EntityFlag_Used*used;
+	}
 
 	if (op_b.mode == Addressing_Invalid ||
 	    op_b.type == t_invalid) {
@@ -829,7 +831,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 				// NOTE(bill): Dummy type
 				Type *tag_ptr_type = make_type_pointer(c->allocator, tag_type);
 				Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tag_ptr_type);
-				tag_var->Variable.used = true;
+				tag_var->flags |= EntityFlag_Used;
 				add_entity(c, c->context.scope, ms->var, tag_var);
 				add_entity_use(c, ms->var, tag_var);
 			}

+ 32 - 34
src/checker/types.cpp

@@ -94,7 +94,6 @@ enum TypeRecordKind {
 
 struct Type {
 	TypeKind kind;
-	u32 flags; // See parser.cpp `enum TypeFlag`
 	union {
 		BasicType Basic;
 		struct {
@@ -120,7 +119,7 @@ struct Type {
 			// All record types
 			// Theses are arrays
 			Entity **fields;      // Entity_Variable (otherwise Entity_TypeName if union)
-			isize    field_count; // == offset_count is struct
+			i32      field_count; // == offset_count is struct
 			AstNode *node;
 
 			union { // NOTE(bill): Reduce size_of Type
@@ -141,7 +140,7 @@ struct Type {
 
 			// Entity_Constant or Entity_TypeName
 			Entity **other_fields;
-			isize    other_field_count;
+			i32      other_field_count;
 		} Record;
 		struct {
 			String  name;
@@ -150,14 +149,14 @@ struct Type {
 		} Named;
 		struct {
 			Entity **variables; // Entity_Variable
-			isize    variable_count;
+			i32      variable_count;
 		} Tuple;
 		struct {
 			Scope *scope;
 			Type * params;  // Type_Tuple
 			Type * results; // Type_Tuple
-			isize  param_count;
-			isize  result_count;
+			i32    param_count;
+			i32    result_count;
 			b32    variadic;
 		} Proc;
 	};
@@ -306,34 +305,34 @@ Type *type_deref(Type *t) {
 
 #define STR_LIT(x) {cast(u8 *)(x), gb_size_of(x)-1}
 gb_global Type basic_types[] = {
-	{Type_Basic, 0, {Basic_Invalid,        0,                                      STR_LIT("invalid type")}},
-	{Type_Basic, 0, {Basic_bool,           BasicFlag_Boolean,                      STR_LIT("bool")}},
-	{Type_Basic, 0, {Basic_i8,             BasicFlag_Integer,                      STR_LIT("i8")}},
-	{Type_Basic, 0, {Basic_u8,             BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}},
-	{Type_Basic, 0, {Basic_i16,            BasicFlag_Integer,                      STR_LIT("i16")}},
-	{Type_Basic, 0, {Basic_u16,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}},
-	{Type_Basic, 0, {Basic_i32,            BasicFlag_Integer,                      STR_LIT("i32")}},
-	{Type_Basic, 0, {Basic_u32,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}},
-	{Type_Basic, 0, {Basic_i64,            BasicFlag_Integer,                      STR_LIT("i64")}},
-	{Type_Basic, 0, {Basic_u64,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}},
-	{Type_Basic, 0, {Basic_f32,            BasicFlag_Float,                        STR_LIT("f32")}},
-	{Type_Basic, 0, {Basic_f64,            BasicFlag_Float,                        STR_LIT("f64")}},
-	{Type_Basic, 0, {Basic_int,            BasicFlag_Integer,                      STR_LIT("int")}},
-	{Type_Basic, 0, {Basic_uint,           BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}},
-	{Type_Basic, 0, {Basic_rawptr,         BasicFlag_Pointer,                      STR_LIT("rawptr")}},
-	{Type_Basic, 0, {Basic_string,         BasicFlag_String,                       STR_LIT("string")}},
-	{Type_Basic, 0, {Basic_any,            0,                                      STR_LIT("any")}},
-	{Type_Basic, 0, {Basic_UntypedBool,    BasicFlag_Boolean | BasicFlag_Untyped,  STR_LIT("untyped bool")}},
-	{Type_Basic, 0, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped,  STR_LIT("untyped integer")}},
-	{Type_Basic, 0, {Basic_UntypedFloat,   BasicFlag_Float   | BasicFlag_Untyped,  STR_LIT("untyped float")}},
-	{Type_Basic, 0, {Basic_UntypedString,  BasicFlag_String  | BasicFlag_Untyped,  STR_LIT("untyped string")}},
-	{Type_Basic, 0, {Basic_UntypedRune,    BasicFlag_Integer | BasicFlag_Untyped,  STR_LIT("untyped rune")}},
-	{Type_Basic, 0, {Basic_UntypedNil,     BasicFlag_Untyped,                      STR_LIT("untyped nil")}},
+	{Type_Basic, {Basic_Invalid,        0,                                      STR_LIT("invalid type")}},
+	{Type_Basic, {Basic_bool,           BasicFlag_Boolean,                      STR_LIT("bool")}},
+	{Type_Basic, {Basic_i8,             BasicFlag_Integer,                      STR_LIT("i8")}},
+	{Type_Basic, {Basic_u8,             BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}},
+	{Type_Basic, {Basic_i16,            BasicFlag_Integer,                      STR_LIT("i16")}},
+	{Type_Basic, {Basic_u16,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}},
+	{Type_Basic, {Basic_i32,            BasicFlag_Integer,                      STR_LIT("i32")}},
+	{Type_Basic, {Basic_u32,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}},
+	{Type_Basic, {Basic_i64,            BasicFlag_Integer,                      STR_LIT("i64")}},
+	{Type_Basic, {Basic_u64,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}},
+	{Type_Basic, {Basic_f32,            BasicFlag_Float,                        STR_LIT("f32")}},
+	{Type_Basic, {Basic_f64,            BasicFlag_Float,                        STR_LIT("f64")}},
+	{Type_Basic, {Basic_int,            BasicFlag_Integer,                      STR_LIT("int")}},
+	{Type_Basic, {Basic_uint,           BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}},
+	{Type_Basic, {Basic_rawptr,         BasicFlag_Pointer,                      STR_LIT("rawptr")}},
+	{Type_Basic, {Basic_string,         BasicFlag_String,                       STR_LIT("string")}},
+	{Type_Basic, {Basic_any,            0,                                      STR_LIT("any")}},
+	{Type_Basic, {Basic_UntypedBool,    BasicFlag_Boolean | BasicFlag_Untyped,  STR_LIT("untyped bool")}},
+	{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped,  STR_LIT("untyped integer")}},
+	{Type_Basic, {Basic_UntypedFloat,   BasicFlag_Float   | BasicFlag_Untyped,  STR_LIT("untyped float")}},
+	{Type_Basic, {Basic_UntypedString,  BasicFlag_String  | BasicFlag_Untyped,  STR_LIT("untyped string")}},
+	{Type_Basic, {Basic_UntypedRune,    BasicFlag_Integer | BasicFlag_Untyped,  STR_LIT("untyped rune")}},
+	{Type_Basic, {Basic_UntypedNil,     BasicFlag_Untyped,                      STR_LIT("untyped nil")}},
 };
 
 gb_global Type basic_type_aliases[] = {
-	{Type_Basic, 0, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}},
-	{Type_Basic, 0, {Basic_rune, BasicFlag_Integer,                      STR_LIT("rune")}},
+	{Type_Basic, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}},
+	{Type_Basic, {Basic_rune, BasicFlag_Integer,                      STR_LIT("rune")}},
 };
 
 gb_global Type *t_invalid         = &basic_types[Basic_Invalid];
@@ -970,7 +969,7 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
 	} else if (!is_type_enum(type) && !is_type_union(type)) {
 		for (isize i = 0; i < type->Record.field_count; i++) {
 			Entity *f = type->Record.fields[i];
-			GB_ASSERT(f->kind == Entity_Variable && f->Variable.field);
+			GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
 			String str = f->token.string;
 			if (field_name == str) {
 				selection_add_index(&sel, i);  // HACK(bill): Leaky memory
@@ -978,7 +977,7 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
 				return sel;
 			}
 
-			if (f->Variable.anonymous) {
+			if (f->flags & EntityFlag_Anonymous) {
 				isize prev_count = sel.index.count;
 				selection_add_index(&sel, i); // HACK(bill): Leaky memory
 
@@ -1121,7 +1120,6 @@ b32 type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 
 i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 	t = base_type(t);
-
 	switch (t->kind) {
 	case Type_Basic: {
 		GB_ASSERT(is_type_typed(t));

+ 8 - 2
src/llvm/ssa_to_text.cpp

@@ -1177,6 +1177,8 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) {
 		ssa_print_type_name(f, m, v);
 	}
 
+	ssa_fprintf(f, "\n");
+
 	for_array(member_index, m->members.entries) {
 		auto *entry = &m->members.entries[member_index];
 		ssaValue *v = entry->value;
@@ -1217,9 +1219,13 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) {
 		if (g->is_thread_local) {
 			ssa_fprintf(f, "thread_local ");
 		}
+
+		if (g->is_private) {
+			ssa_fprintf(f, "private ");
+		}
 		if (g->is_constant) {
-			if (g->is_private) {
-				ssa_fprintf(f, "private ");
+			if (g->is_unnamed_addr) {
+				ssa_fprintf(f, "unnamed_addr ");
 			}
 			ssa_fprintf(f, "constant ");
 		} else {

+ 0 - 1
src/main.cpp

@@ -113,7 +113,6 @@ int main(int argc, char **argv) {
 	init_string_buffer_memory();
 	init_global_error_collector();
 
-
 	String module_dir = get_module_dir();
 
 	init_universal_scope();

+ 23 - 13
src/parser.cpp

@@ -226,34 +226,44 @@ AST_NODE_KIND(_StmtEnd,        "", struct{}) \
 AST_NODE_KIND(_DeclBegin,      "", struct{}) \
 	AST_NODE_KIND(BadDecl,  "bad declaration", struct { Token begin, end; }) \
 	AST_NODE_KIND(VarDecl,  "variable declaration", struct { \
-			u64      tags; \
-			b32      is_using; \
+			u64          tags; \
+			b32          is_using; \
 			AstNodeArray names; \
-			AstNode *type; \
+			AstNode *    type; \
 			AstNodeArray values; \
+			AstNode *    note; \
 	}) \
 	AST_NODE_KIND(ConstDecl,  "constant declaration", struct { \
-			u64      tags; \
+			u64          tags; \
 			AstNodeArray names; \
-			AstNode *type; \
+			AstNode *    type; \
 			AstNodeArray values; \
+			AstNode *    note; \
 	}) \
 	AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \
-			AstNode *name;        \
-			AstNode *type;        \
-			AstNode *body;        \
-			u64     tags;         \
-			String  foreign_name; \
-			String  link_name;    \
+			AstNode *name;         \
+			AstNode *type;         \
+			AstNode *body;         \
+			u64      tags;         \
+			String   foreign_name; \
+			String   link_name;    \
+			AstNode *note;          \
+	}) \
+	AST_NODE_KIND(TypeDecl,   "type declaration",   struct { \
+		Token token; \
+		AstNode *name, *type; \
+		AstNode *note; \
 	}) \
-	AST_NODE_KIND(TypeDecl,   "type declaration",   struct { Token token; AstNode *name, *type; }) \
 	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
 		Token token, relpath; \
 		String fullpath;      \
 		Token import_name;    \
 		b32 is_load;          \
+		AstNode *note;        \
+	}) \
+	AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { \
+		Token token, filepath; \
 	}) \
-	AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
 AST_NODE_KIND(_DeclEnd,   "", struct{}) \
 AST_NODE_KIND(_TypeBegin, "", struct{}) \
 	AST_NODE_KIND(Parameter, "parameter", struct { \

+ 2 - 2
src/ssa/build.cpp

@@ -882,7 +882,7 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) {
 }
 
 ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
-	GB_ASSERT(e->kind == Entity_Variable && e->Variable.anonymous);
+	GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous);
 	String name = e->token.string;
 	Entity *parent = e->using_parent;
 	Selection sel = lookup_field(proc->module->allocator, parent->type, name, false);
@@ -917,7 +917,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
 		if (found) {
 			v = *found;
-		} else if (e->kind == Entity_Variable && e->Variable.anonymous) {
+		} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
 			v = ssa_add_using_variable(proc, e);
 		} else if (e->kind == Entity_ImplicitValue) {
 			// TODO(bill): Should a copy be made?

+ 1 - 1
src/ssa/codegen.cpp

@@ -442,7 +442,7 @@ void ssa_gen_tree(ssaGen *s) {
 							Entity *f = t->Record.fields_in_src_order[source_index];
 							ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type);
 							i64 foffset = t->Record.struct_offsets[f->Variable.field_index];
-							GB_ASSERT(f->kind == Entity_Variable && f->Variable.field);
+							GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
 
 							ssaValue *field     = ssa_emit_ptr_offset(proc, memory, ssa_make_const_int(a, source_index));
 							ssaValue *name      = ssa_emit_struct_ep(proc, field, 0);

+ 3 - 3
src/ssa/emit.cpp

@@ -575,7 +575,7 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
 	GB_ASSERT(is_type_struct(src));
 	for (isize i = 0; i < src->Record.field_count; i++) {
 		Entity *f = src->Record.fields[i];
-		if (f->kind == Entity_Variable && f->Variable.anonymous) {
+		if (f->kind == Entity_Variable && f->flags & EntityFlag_Anonymous) {
 			if (are_types_identical(dst, f->type)) {
 				return f->token.string;
 			}
@@ -675,8 +675,8 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 
 	// float -> float
 	if (is_type_float(src) && is_type_float(dst)) {
-		i64 sz = basic_type_sizes[src->Basic.kind];
-		i64 dz = basic_type_sizes[dst->Basic.kind];
+		i64 sz = type_size_of(proc->module->sizes, proc->module->allocator, src);
+		i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst);
 		ssaConvKind kind = ssaConv_fptrunc;
 		if (dz >= sz) {
 			kind = ssaConv_fpext;

+ 18 - 18
src/ssa/make.cpp

@@ -13,6 +13,7 @@ ssaValue *ssa_alloc_value(gbAllocator a, ssaValueKind kind) {
 ssaValue *ssa_alloc_instr(ssaProcedure *proc, ssaInstrKind kind) {
 	ssaValue *v = ssa_alloc_value(proc->module->allocator, ssaValue_Instr);
 	v->Instr.kind = kind;
+	proc->instr_count++;
 	return v;
 }
 ssaDebugInfo *ssa_alloc_debug_info(gbAllocator a, ssaDebugInfoKind kind) {
@@ -330,9 +331,19 @@ ssaValue *ssa_make_value_procedure(gbAllocator a, ssaModule *m, Entity *entity,
 	return v;
 }
 
-ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope, String label) {
+ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, char *label) {
+	Scope *scope = NULL;
+	if (node != NULL) {
+		Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
+		if (found) {
+			scope = *found;
+		} else {
+			GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind]));
+		}
+	}
+
 	ssaValue *v = ssa_alloc_value(proc->module->allocator, ssaValue_Block);
-	v->Block.label  = label;
+	v->Block.label  = make_string(label);
 	v->Block.node   = node;
 	v->Block.scope  = scope;
 	v->Block.parent = proc;
@@ -343,23 +354,11 @@ ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope,
 	array_init(&v->Block.preds,  heap_allocator());
 	array_init(&v->Block.succs,  heap_allocator());
 
-	return v;
-}
+	ssaBlock *block = &v->Block;
 
-ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, char *label) {
-	Scope *scope = NULL;
-	if (node != NULL) {
-		Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
-		if (found) {
-			scope = *found;
-		} else {
-			GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind]));
-		}
-	}
-
-	ssaValue *value = ssa_make_value_block(proc, node, scope, make_string(label));
-	ssaBlock *block = &value->Block;
 	array_add(&proc->blocks, block);
+	proc->block_count++;
+
 	return block;
 }
 
@@ -435,7 +434,8 @@ ssaValue *ssa_add_global_string_array(ssaModule *m, String string) {
 	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_private      = true;
+	// g->Global.is_unnamed_addr = true;
 	// g->Global.is_constant = true;
 
 	ssa_module_add_value(m, entity, g);

+ 31 - 17
src/ssa/opt.cpp

@@ -1,4 +1,6 @@
-void ssa_add_operands(Array<ssaValue *> *ops, ssaInstr *i) {
+// Optimizations for the SSA code
+
+void ssa_opt_add_operands(Array<ssaValue *> *ops, ssaInstr *i) {
 	switch (i->kind) {
 	case ssaInstr_Comment:
 		break;
@@ -110,16 +112,6 @@ b32 ssa_block_has_phi(ssaBlock *b) {
 
 
 
-void ssa_optimize_blocks(ssaProcedure *proc);
-void ssa_build_referrers(ssaProcedure *proc);
-void ssa_build_dom_tree (ssaProcedure *proc);
-void ssa_opt_mem2reg    (ssaProcedure *proc);
-
-
-
-
-
-
 
 
 
@@ -245,7 +237,7 @@ b32 ssa_opt_block_fusion(ssaProcedure *proc, ssaBlock *a) {
 	return true;
 }
 
-void ssa_optimize_blocks(ssaProcedure *proc) {
+void ssa_opt_blocks(ssaProcedure *proc) {
 	ssa_remove_unreachable_blocks(proc);
 
 #if 1
@@ -269,7 +261,7 @@ void ssa_optimize_blocks(ssaProcedure *proc) {
 
 	ssa_remove_dead_blocks(proc);
 }
-void ssa_build_referrers(ssaProcedure *proc) {
+void ssa_opt_build_referrers(ssaProcedure *proc) {
 	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
 	defer (gb_temp_arena_memory_end(tmp));
 
@@ -280,7 +272,7 @@ void ssa_build_referrers(ssaProcedure *proc) {
 		for_array(j, b->instrs) {
 			ssaValue *instr = b->instrs[j];
 			array_clear(&ops);
-			ssa_add_operands(&ops, &instr->Instr);
+			ssa_opt_add_operands(&ops, &instr->Instr);
 			for_array(k, ops) {
 				ssaValue *op = ops[k];
 				if (op == NULL) {
@@ -358,8 +350,8 @@ void ssa_number_dom_tree(ssaBlock *v, i32 pre, i32 post, i32 *pre_out, i32 *post
 }
 
 
-// NOTE(bill): Requires `ssa_optimize_blocks` to be called before this
-void ssa_build_dom_tree(ssaProcedure *proc) {
+// NOTE(bill): Requires `ssa_opt_blocks` to be called before this
+void ssa_opt_build_dom_tree(ssaProcedure *proc) {
 	// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
 
 	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
@@ -448,5 +440,27 @@ void ssa_build_dom_tree(ssaProcedure *proc) {
 }
 
 void ssa_opt_mem2reg(ssaProcedure *proc) {
-	// TODO(bill):
+	// TODO(bill): ssa_opt_mem2reg
+}
+
+
+void ssa_opt_proc(ssaProcedure *proc) {
+	ssa_opt_blocks(proc);
+#if 1
+	ssa_opt_build_referrers(proc);
+	ssa_opt_build_dom_tree(proc);
+
+	// TODO(bill): ssa optimization
+	// [ ] cse (common-subexpression) elim
+	// [ ] copy elim
+	// [ ] dead code elim
+	// [ ] dead store/load elim
+	// [ ] phi elim
+	// [ ] short circuit elim
+	// [ ] bounds check elim
+	// [ ] lift/mem2reg
+	// [ ] lift/mem2reg
+
+	ssa_opt_mem2reg(proc);
+#endif
 }

+ 1 - 12
src/ssa/proc.cpp

@@ -29,18 +29,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
 	proc->curr_block = proc->decl_block;
 	ssa_emit_jump(proc, proc->entry_block);
 
-#if 0
-	ssa_optimize_blocks(proc);
-	ssa_build_referrers(proc);
-	ssa_build_dom_tree(proc);
-
-	// TODO(bill): mem2reg optimization
-	// [ ] Local never loaded? Eliminate
-	// [ ] Local never stored? Replace all loads with `Nil`
-	// [ ] Local stored once?  Replace loads with dominating store
-	// [ ] Convert to phi nodes
-	ssa_opt_mem2reg(proc);
-#endif
+	ssa_opt_proc(proc);
 
 // Number registers
 	i32 reg_index = 0;

+ 137 - 43
src/ssa/ssa.cpp

@@ -1,44 +1,7 @@
 struct ssaProcedure;
 struct ssaBlock;
 struct ssaValue;
-
-enum ssaDebugInfoKind {
-	ssaDebugInfo_Invalid,
-
-	ssaDebugInfo_CompileUnit,
-	ssaDebugInfo_File,
-	ssaDebugInfo_Proc,
-	ssaDebugInfo_AllProcs,
-
-	ssaDebugInfo_Count,
-};
-
-struct ssaDebugInfo {
-	ssaDebugInfoKind kind;
-	i32 id;
-
-	union {
-		struct {
-			AstFile *     file;
-			String        producer;
-			ssaDebugInfo *all_procs;
-		} CompileUnit;
-		struct {
-			AstFile *file;
-			String   filename;
-			String   directory;
-		} File;
-		struct {
-			Entity *      entity;
-			String        name;
-			ssaDebugInfo *file;
-			TokenPos      pos;
-		} Proc;
-		struct {
-			Array<ssaDebugInfo *> procs;
-		} AllProcs;
-	};
-};
+struct ssaDebugInfo;
 
 struct ssaModule {
 	CheckerInfo * info;
@@ -130,14 +93,17 @@ struct ssaProcedure {
 	AstNode *             body;
 	u64                   tags;
 
-	isize                 scope_index;
 	Array<ssaDefer>       defer_stmts;
 	Array<ssaBlock *>     blocks;
+	i32                   scope_index;
 	ssaBlock *            decl_block;
 	ssaBlock *            entry_block;
 	ssaBlock *            curr_block;
 	ssaTargetList *       target_list;
 	Array<ssaValue *>     referrers;
+
+	i32                   instr_count;
+	i32                   block_count;
 };
 
 #define SSA_STARTUP_RUNTIME_PROC_NAME  "__$startup_runtime"
@@ -376,17 +342,18 @@ struct ssaValue {
 			Type *type;
 		} Nil;
 		struct {
-			String name;
 			Type * type;
+			String name;
 		} TypeName;
 		struct {
-			b32               is_constant;
-			b32               is_private;
-			b32               is_thread_local;
 			Entity *          entity;
 			Type *            type;
 			ssaValue *        value;
 			Array<ssaValue *> referrers;
+			b8                is_constant;
+			b8                is_private;
+			b8                is_thread_local;
+			b8                is_unnamed_addr;
 		} Global;
 		struct {
 			ssaProcedure *    parent;
@@ -433,6 +400,133 @@ ssaAddr ssa_make_addr_vector(ssaValue *addr, ssaValue *index, AstNode *expr) {
 	return v;
 }
 
+
+
+enum ssaDebugEncoding {
+	ssaDebugBasicEncoding_Invalid       = 0,
+
+	ssaDebugBasicEncoding_address       = 1,
+	ssaDebugBasicEncoding_boolean       = 2,
+	ssaDebugBasicEncoding_float         = 3,
+	ssaDebugBasicEncoding_signed        = 4,
+	ssaDebugBasicEncoding_signed_char   = 5,
+	ssaDebugBasicEncoding_unsigned      = 6,
+	ssaDebugBasicEncoding_unsigned_char = 7,
+
+	ssaDebugBasicEncoding_member       = 13,
+	ssaDebugBasicEncoding_pointer_type = 15,
+	ssaDebugBasicEncoding_typedef      = 22,
+
+	ssaDebugBasicEncoding_array_type       = 1,
+	ssaDebugBasicEncoding_enumeration_type = 4,
+	ssaDebugBasicEncoding_structure_type   = 19,
+	ssaDebugBasicEncoding_union_type       = 23,
+
+};
+
+enum ssaDebugInfoKind {
+	ssaDebugInfo_Invalid,
+
+	ssaDebugInfo_CompileUnit,
+	ssaDebugInfo_File,
+	ssaDebugInfo_Scope,
+	ssaDebugInfo_Proc,
+	ssaDebugInfo_AllProcs,
+
+	ssaDebugInfo_BasicType,      // basic types
+	ssaDebugInfo_ProcType,
+	ssaDebugInfo_DerivedType,    // pointer, typedef
+	ssaDebugInfo_CompositeType,  // array, struct, enum, (raw_)union
+	ssaDebugInfo_Enumerator,     // For ssaDebugInfo_CompositeType if enum
+	ssaDebugInfo_GlobalVariable,
+	ssaDebugInfo_LocalVariable,
+
+
+	ssaDebugInfo_Count,
+};
+
+struct ssaDebugInfo {
+	ssaDebugInfoKind kind;
+	i32 id;
+
+	union {
+		struct {
+			AstFile *     file;
+			String        producer;
+			ssaDebugInfo *all_procs;
+		} CompileUnit;
+		struct {
+			AstFile *file;
+			String   filename;
+			String   directory;
+		} File;
+		struct {
+			ssaDebugInfo *parent;
+			ssaDebugInfo *file;
+			TokenPos      pos;
+			Scope *       scope; // Actual scope
+		} Scope;
+		struct {
+			Entity *      entity;
+			String        name;
+			ssaDebugInfo *file;
+			TokenPos      pos;
+		} Proc;
+		struct {
+			Array<ssaDebugInfo *> procs;
+		} AllProcs;
+
+
+		struct {
+			String           name;
+			i32              size;
+			i32              align;
+			ssaDebugEncoding encoding;
+		} BasicType;
+		struct {
+			ssaDebugInfo *        return_type;
+			Array<ssaDebugInfo *> param_types;
+		} ProcType;
+		struct {
+			ssaDebugInfo *   base_type;
+			ssaDebugEncoding encoding;
+		} DerivedType;
+		struct {
+			ssaDebugEncoding      encoding;
+			String                name;
+			String                identifier;
+			ssaDebugInfo *        file;
+			TokenPos              pos;
+			i32                   size;
+			i32                   align;
+			Array<ssaDebugInfo *> elements;
+		} CompositeType;
+		struct {
+			String name;
+			i64    value;
+		} Enumerator;
+		struct {
+			String        name;
+			String        linkage_name;
+			ssaDebugInfo *scope;
+			ssaDebugInfo *file;
+			TokenPos      pos;
+			ssaValue     *variable;
+			ssaDebugInfo *declaration;
+		} GlobalVariable;
+		struct {
+			String        name;
+			ssaDebugInfo *scope;
+			ssaDebugInfo *file;
+			TokenPos      pos;
+			i32           arg; // Non-zero if proc parameter
+			ssaDebugInfo *type;
+		} LocalVariable;
+	};
+};
+
+
+
 struct ssaFileBuffer {
 	gbVirtualMemory vm;
 	isize offset;

+ 2 - 1
src/tokenizer.cpp

@@ -128,7 +128,8 @@ String const token_strings[] = {
 
 struct TokenPos {
 	String file;
-	isize line, column;
+	isize  line;
+	isize  column;
 };
 
 i32 token_pos_cmp(TokenPos a, TokenPos b) {