Browse Source

Slice creation for SliceExpr

gingerBill 9 years ago
parent
commit
0e92166d44

+ 20 - 3
examples/test.ll

@@ -1,6 +1,23 @@
-; ModuleID = '..\examples/test.bc'
-
 define void @main() {
 "entry - 0":
-  ret void
+	%0 = alloca [16 x i64], align 8 ; a
+	store [16 x i64] zeroinitializer, [16 x i64]* %0
+	%1 = alloca {i64*, i64, i64}, align 8 ; b
+	store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %1
+	%2 = sub i64 1, 0
+	%3 = sub i64 2, 0
+	%4 = getelementptr inbounds [16 x i64], [16 x i64]* %0, i64 0, i64 0
+	%5 = getelementptr i64, i64* %4, i64 0
+	%6 = alloca {i64*, i64, i64}, align 8 
+	store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %6
+	%7 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %6, i64 0, i32 0
+	store i64* %5, i64** %7
+	%8 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %6, i64 0, i32 1
+	store i64 %2, i64* %8
+	%9 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %6, i64 0, i32 2
+	store i64 %3, i64* %9
+	%10 = load {i64*, i64, i64}, {i64*, i64, i64}* %6
+	store {i64*, i64, i64} %10, {i64*, i64, i64}* %1
+	ret void
 }
+

+ 3 - 0
examples/test.odin

@@ -1,2 +1,5 @@
 main :: proc() {
+	a : [16]int;
+	b := a[0:1:2];
+
 }

+ 3 - 3
run.bat

@@ -3,6 +3,6 @@
 
 rem del "..\examples\test.bc"
 call ..\bin\odin.exe ..\examples/test.odin && lli ..\examples/test.ll
-call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc
-call llvm-dis ..\examples/test.bc -o ..\examples/test.ll
-call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll
+rem call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc
+rem call llvm-dis ..\examples/test.bc -o ..\examples/test.ll
+rem call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll

+ 5 - 5
src/checker/checker.cpp

@@ -312,16 +312,16 @@ void init_universal_scope(void) {
 	}
 
 // Constants
-	add_global_constant(a, make_string("true"),  &basic_types[Basic_UntypedBool],    make_exact_value_bool(true));
-	add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool],    make_exact_value_bool(false));
-	add_global_constant(a, make_string("null"),  &basic_types[Basic_UntypedPointer], make_exact_value_pointer(NULL));
+	add_global_constant(a, make_string("true"),  t_untyped_bool,    make_exact_value_bool(true));
+	add_global_constant(a, make_string("false"), t_untyped_bool,    make_exact_value_bool(false));
+	add_global_constant(a, make_string("null"),  t_untyped_pointer, make_exact_value_pointer(NULL));
 
 // Builtin Procedures
 	for (isize i = 0; i < gb_count_of(builtin_procedures); i++) {
 		BuiltinProcedureId id = cast(BuiltinProcedureId)i;
 		Token token = {Token_Identifier};
 		token.string = builtin_procedures[i].name;
-		Entity *entity = alloc_entity(a, Entity_Builtin, NULL, token, &basic_types[Basic_Invalid]);
+		Entity *entity = alloc_entity(a, Entity_Builtin, NULL, token, t_invalid);
 		entity->builtin.id = id;
 		add_global_entity(entity);
 	}
@@ -433,7 +433,7 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode
 
 	if (mode == Addressing_Constant) {
 		GB_ASSERT(value.kind != ExactValue_Invalid);
-		GB_ASSERT(type == &basic_types[Basic_Invalid] || is_type_constant_type(type));
+		GB_ASSERT(type == t_invalid || is_type_constant_type(type));
 	}
 
 	TypeAndValue tv = {};

+ 27 - 27
src/checker/expression.cpp

@@ -167,7 +167,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
 	switch (e->kind) {
 	case Entity_Constant:
 		add_declaration_dependency(c, e);
-		if (e->type == &basic_types[Basic_Invalid])
+		if (e->type == t_invalid)
 			return;
 		o->value = e->constant.value;
 		GB_ASSERT(o->value.kind != ExactValue_Invalid);
@@ -177,7 +177,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
 	case Entity_Variable:
 		add_declaration_dependency(c, e);
 		e->variable.used = true;
-		if (e->type == &basic_types[Basic_Invalid])
+		if (e->type == t_invalid)
 			return;
 		o->mode = Addressing_Variable;
 		break;
@@ -306,7 +306,7 @@ Type *check_type_expr_extra(Checker *c, AstNode *e, Type *named_type) {
 		break;
 	}
 
-	Type *t = &basic_types[Basic_Invalid];
+	Type *t = t_invalid;
 	set_base_type(named_type, t);
 	return t;
 }
@@ -396,7 +396,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
 		break;
 	}
 
-	type = &basic_types[Basic_Invalid];
+	type = t_invalid;
 	set_base_type(named_type, type);
 
 end:
@@ -672,7 +672,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
 		// TODO(bill): What should I do?
 	}
 
-	x->type = &basic_types[Basic_UntypedBool];
+	x->type = t_untyped_bool;
 }
 
 void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
@@ -707,8 +707,8 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	}
 
 	if (!are_types_identical(x->type, y->type)) {
-		if (x->type != &basic_types[Basic_Invalid] &&
-		    y->type  != &basic_types[Basic_Invalid]) {
+		if (x->type != t_invalid &&
+		    y->type  != t_invalid) {
 			gbString xt = type_to_string(x->type);
 			gbString yt = type_to_string(y->type);
 			defer (gb_string_free(xt));
@@ -833,7 +833,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
 	GB_ASSERT_NOT_NULL(target_type);
 	if (operand->mode == Addressing_Invalid ||
 	    is_type_typed(operand->type) ||
-	    target_type == &basic_types[Basic_Invalid]) {
+	    target_type == t_invalid) {
 		return;
 	}
 
@@ -883,7 +883,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
 	case Type_Pointer:
 		switch (operand->type->basic.kind) {
 		case Basic_UntypedPointer:
-			target_type = &basic_types[Basic_UntypedPointer];
+			target_type = t_untyped_pointer;
 			break;
 		default:
 			convert_untyped_error(c, operand, target_type);
@@ -907,7 +907,7 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu
 		return false;
 	}
 
-	convert_to_typed(c, &operand, &basic_types[Basic_int]);
+	convert_to_typed(c, &operand, t_int);
 	if (operand.mode == Addressing_Invalid) {
 		if (value) *value = 0;
 		return false;
@@ -1052,7 +1052,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, type));
-		operand->type = &basic_types[Basic_int];
+		operand->type = t_int;
 
 	} break;
 
@@ -1064,7 +1064,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type));
-		operand->type = &basic_types[Basic_int];
+		operand->type = t_int;
 		break;
 
 	case BuiltinProcedure_align_of: {
@@ -1076,7 +1076,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		}
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, type));
-		operand->type = &basic_types[Basic_int];
+		operand->type = t_int;
 	} break;
 
 	case BuiltinProcedure_align_of_val:
@@ -1087,7 +1087,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type));
-		operand->type = &basic_types[Basic_int];
+		operand->type = t_int;
 		break;
 
 	case BuiltinProcedure_offset_of: {
@@ -1118,7 +1118,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_offset_of(c->sizes, c->allocator, type, index));
-		operand->type  = &basic_types[Basic_int];
+		operand->type  = t_int;
 	} break;
 
 	case BuiltinProcedure_offset_of_val: {
@@ -1154,7 +1154,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_offset_of(c->sizes, c->allocator, type, index));
-		operand->type  = &basic_types[Basic_int];
+		operand->type  = t_int;
 	} break;
 
 	case BuiltinProcedure_static_assert:
@@ -1220,7 +1220,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		}
 
 		operand->mode = mode;
-		operand->type = &basic_types[Basic_int];
+		operand->type = t_int;
 		operand->value = value;
 
 	} break;
@@ -1262,7 +1262,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 			return false;
 		}
 
-		operand->type = &basic_types[Basic_int]; // Returns number of elements copied
+		operand->type = t_int; // Returns number of elements copied
 		operand->mode = Addressing_Value;
 	} break;
 
@@ -1507,7 +1507,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 	ExpressionKind kind = Expression_Statement;
 
 	o->mode = Addressing_Invalid;
-	o->type = &basic_types[Basic_Invalid];
+	o->type = t_invalid;
 
 	switch (node->kind) {
 	case_ast_node(be, BadExpr, node)
@@ -1519,16 +1519,16 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 	case_end;
 
 	case_ast_node(bl, BasicLit, node);
-		BasicKind basic_kind = Basic_Invalid;
+		Type *t = t_invalid;
 		switch (bl->kind) {
-		case Token_Integer: basic_kind = Basic_UntypedInteger; break;
-		case Token_Float:   basic_kind = Basic_UntypedFloat;   break;
-		case Token_String:  basic_kind = Basic_UntypedString;  break;
-		case Token_Rune:    basic_kind = Basic_UntypedRune;    break;
+		case Token_Integer: t = t_untyped_integer; break;
+		case Token_Float:   t = t_untyped_float;   break;
+		case Token_String:  t = t_untyped_string;  break;
+		case Token_Rune:    t = t_untyped_rune;    break;
 		default:            GB_PANIC("Unknown literal");       break;
 		}
 		o->mode  = Addressing_Constant;
-		o->type  = &basic_types[basic_kind];
+		o->type  = t;
 		o->value = make_exact_value_from_basic_literal(*bl);
 	case_end;
 
@@ -1684,7 +1684,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 					max_count = o->value.value_string.len;
 				}
 				o->mode = Addressing_Value;
-				o->type = &basic_types[Basic_u8];
+				o->type = t_u8;
 			}
 			break;
 
@@ -1866,7 +1866,7 @@ ExpressionKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type
 	ExactValue value = {ExactValue_Invalid};
 	switch (o->mode) {
 	case Addressing_Invalid:
-		type = &basic_types[Basic_Invalid];
+		type = t_invalid;
 		break;
 	case Addressing_NoValue:
 		type = NULL;

+ 18 - 18
src/checker/statements.cpp

@@ -73,7 +73,7 @@ b32 check_is_terminating(Checker *c, AstNode *node) {
 
 b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
 	if (operand->mode == Addressing_Invalid ||
-	    type == &basic_types[Basic_Invalid]) {
+	    type == t_invalid) {
 		return true;
 	}
 
@@ -166,7 +166,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
 
 Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 	if (op_a->mode == Addressing_Invalid ||
-	    op_a->type == &basic_types[Basic_Invalid]) {
+	    op_a->type == t_invalid) {
 		return NULL;
 	}
 
@@ -200,7 +200,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 	if (e) e->variable.used = used;
 
 	if (op_b.mode == Addressing_Invalid ||
-	    op_b.type == &basic_types[Basic_Invalid]) {
+	    op_b.type == t_invalid) {
 		return NULL;
 	}
 
@@ -233,10 +233,10 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 // NOTE(bill): `content_name` is for debugging
 Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
 	if (operand->mode == Addressing_Invalid ||
-	    operand->type == &basic_types[Basic_Invalid] ||
-	    e->type == &basic_types[Basic_Invalid]) {
+	    operand->type == t_invalid ||
+	    e->type == t_invalid) {
 		if (e->type == NULL)
-			e->type = &basic_types[Basic_Invalid];
+			e->type = t_invalid;
 		return NULL;
 	}
 
@@ -244,9 +244,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
 		// NOTE(bill): Use the type of the operand
 		Type *t = operand->type;
 		if (is_type_untyped(t)) {
-			if (t == &basic_types[Basic_Invalid]) {
+			if (t == t_invalid) {
 				error(&c->error_collector, e->token, "Use of untyped thing in %.*s", LIT(context_name));
-				e->type = &basic_types[Basic_Invalid];
+				e->type = t_invalid;
 				return NULL;
 			}
 			t = default_type(t);
@@ -295,10 +295,10 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNode *in
 
 void check_init_constant(Checker *c, Entity *e, Operand *operand) {
 	if (operand->mode == Addressing_Invalid ||
-	    operand->type == &basic_types[Basic_Invalid] ||
-	    e->type == &basic_types[Basic_Invalid]) {
+	    operand->type == t_invalid ||
+	    e->type == t_invalid) {
 		if (e->type == NULL)
-			e->type = &basic_types[Basic_Invalid];
+			e->type = t_invalid;
 		return;
 	}
 
@@ -307,7 +307,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
 		error(&c->error_collector, ast_node_token(operand->expr),
 		      "`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
 		if (e->type == NULL)
-			e->type = &basic_types[Basic_Invalid];
+			e->type = t_invalid;
 		return;
 	}
 	if (!is_type_constant_type(operand->type)) {
@@ -330,7 +330,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
 	GB_ASSERT(e->type == NULL);
 
 	if (e->variable.visited) {
-		e->type = &basic_types[Basic_Invalid];
+		e->type = t_invalid;
 		return;
 	}
 	e->variable.visited = true;
@@ -342,7 +342,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
 			defer (gb_string_free(str));
 			error(&c->error_collector, ast_node_token(type_expr),
 			      "Invalid constant type `%s`", str);
-			e->type = &basic_types[Basic_Invalid];
+			e->type = t_invalid;
 			return;
 		}
 		e->type = t;
@@ -464,7 +464,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
 	GB_ASSERT(e->kind == Entity_Variable);
 
 	if (e->variable.visited) {
-		e->type = &basic_types[Basic_Invalid];
+		e->type = t_invalid;
 		return;
 	}
 	e->variable.visited = true;
@@ -474,7 +474,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
 
 	if (init_expr == NULL) {
 		if (type_expr == NULL)
-			e->type = &basic_types[Basic_Invalid];
+			e->type = t_invalid;
 		return;
 	}
 
@@ -815,14 +815,14 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			if (vd->type) {
 				init_type = check_type(c, vd->type, NULL);
 				if (init_type == NULL)
-					init_type = &basic_types[Basic_Invalid];
+					init_type = t_invalid;
 			}
 
 			for (isize i = 0; i < entity_count; i++) {
 				Entity *e = entities[i];
 				GB_ASSERT(e != NULL);
 				if (e->variable.visited) {
-					e->type = &basic_types[Basic_Invalid];
+					e->type = t_invalid;
 					continue;
 				}
 				e->variable.visited = true;

+ 23 - 0
src/checker/type.cpp

@@ -246,6 +246,29 @@ gb_global Type basic_type_aliases[] = {
 	{Type_Basic, {Basic_rune, BasicFlag_Integer,                      STR_LIT("rune")}},
 };
 
+gb_global Type *t_invalid         = &basic_types[Basic_Invalid];
+gb_global Type *t_bool            = &basic_types[Basic_bool];
+gb_global Type *t_i8              = &basic_types[Basic_i8];
+gb_global Type *t_i16             = &basic_types[Basic_i16];
+gb_global Type *t_i32             = &basic_types[Basic_i32];
+gb_global Type *t_i64             = &basic_types[Basic_i64];
+gb_global Type *t_u8              = &basic_types[Basic_u8];
+gb_global Type *t_u16             = &basic_types[Basic_u16];
+gb_global Type *t_u32             = &basic_types[Basic_u32];
+gb_global Type *t_u64             = &basic_types[Basic_u64];
+gb_global Type *t_f32             = &basic_types[Basic_f32];
+gb_global Type *t_f64             = &basic_types[Basic_f64];
+gb_global Type *t_int             = &basic_types[Basic_int];
+gb_global Type *t_uint            = &basic_types[Basic_uint];
+gb_global Type *t_rawptr          = &basic_types[Basic_rawptr];
+gb_global Type *t_string          = &basic_types[Basic_string];
+gb_global Type *t_untyped_bool    = &basic_types[Basic_UntypedBool];
+gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
+gb_global Type *t_untyped_float   = &basic_types[Basic_UntypedFloat];
+gb_global Type *t_untyped_pointer = &basic_types[Basic_UntypedPointer];
+gb_global Type *t_untyped_string  = &basic_types[Basic_UntypedString];
+gb_global Type *t_untyped_rune    = &basic_types[Basic_UntypedRune];
+
 
 b32 is_type_named(Type *t) {
 	if (t->kind == Type_Basic)

+ 8 - 0
src/codegen/codegen.cpp

@@ -33,6 +33,14 @@ void ssa_gen_destroy(ssaGen *s) {
 }
 
 void ssa_gen_code(ssaGen *s) {
+	if (v_zero == NULL) {
+		v_zero   = ssa_make_value_constant(gb_heap_allocator(), t_int, make_exact_value_integer(0));
+		v_one    = ssa_make_value_constant(gb_heap_allocator(), t_int, make_exact_value_integer(1));
+		v_zero32 = ssa_make_value_constant(gb_heap_allocator(), t_i32, make_exact_value_integer(0));
+		v_one32  = ssa_make_value_constant(gb_heap_allocator(), t_i32, make_exact_value_integer(1));
+		v_two32  = ssa_make_value_constant(gb_heap_allocator(), t_i32, make_exact_value_integer(2));
+	}
+
 	ssaModule *m = &s->module;
 	CheckerInfo *info = m->info;
 	gbAllocator a = m->allocator;

+ 12 - 9
src/codegen/print.cpp

@@ -104,7 +104,7 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
 	case Type_Slice:
 		ssa_fprintf(f, "{");
 		ssa_print_type(f, s, t->slice.element);
-		ssa_fprintf(f, "*, %lld, %lld}", word_bits, word_bits);
+		ssa_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
 		break;
 	case Type_Structure:
 		ssa_fprintf(f, "{");
@@ -158,7 +158,7 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
 		break;
 	case ExactValue_String: {
 		ssa_fprintf(f, "{");
-		ssa_print_type(f, m->sizes, &basic_types[Basic_i8]);
+		ssa_print_type(f, m->sizes, t_i8);
 		ssa_fprintf(f, "* c\"");
 		// TODO(bill): Make unquote string function
 		String unquoted = value.value_string;
@@ -166,7 +166,7 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
 		unquoted.len -= 2;
 		ssa_print_escape_string(f, unquoted);
 		ssa_fprintf(f, "\", ");
-		ssa_print_type(f, m->sizes, &basic_types[Basic_int]);
+		ssa_print_type(f, m->sizes, t_int);
 		ssa_fprintf(f, " %td}", value.value_string.len);
 	} break;
 	case ExactValue_Integer:
@@ -246,7 +246,11 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "%%%d = alloca ", value->id);
 		ssa_print_type(f, m->sizes, type);
 		ssa_fprintf(f, ", align %lld ", type_align_of(m->sizes, gb_heap_allocator(), type));
-		ssa_fprintf(f, "; %.*s", LIT(instr->local.entity->token.string));
+		{
+			String str = instr->local.entity->token.string;
+			if (str.len > 0)
+			ssa_fprintf(f, "; %.*s", LIT(instr->local.entity->token.string));
+		}
 		ssa_fprintf(f, "\n");
 		ssa_fprintf(f, "\tstore ");
 		ssa_print_type(f, m->sizes, type);
@@ -281,7 +285,6 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 
 	case ssaInstr_GetElementPtr: {
 		Type *et = instr->get_element_ptr.element_type;
-		Type *t_int = &basic_types[Basic_int];
 		ssa_fprintf(f, "%%%d = getelementptr ", value->id);
 		if (instr->get_element_ptr.inbounds)
 		ssa_fprintf(f, "inbounds ");
@@ -292,10 +295,12 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "* ");
 		ssa_print_value(f, m, instr->get_element_ptr.address, et);
 		for (isize i = 0; i < instr->get_element_ptr.index_count; i++) {
+			ssaValue *index = instr->get_element_ptr.indices[i];
+			Type *t = ssa_value_type(index);
 			ssa_fprintf(f, ", ");
-			ssa_print_type(f, m->sizes, t_int);
+			ssa_print_type(f, m->sizes, t);
 			ssa_fprintf(f, " ");
-			ssa_print_value(f, m, instr->get_element_ptr.indices[i], t_int);
+			ssa_print_value(f, m, index, t);
 		}
 		ssa_fprintf(f, "\n");
 	} break;
@@ -303,7 +308,6 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 	case ssaInstr_Br: {
 		ssa_fprintf(f, "br ");
 		if (instr->br.cond != NULL) {
-			Type *t_bool = &basic_types[Basic_bool];
 			ssa_print_type(f, m->sizes, t_bool);
 			ssa_fprintf(f, " ");
 			ssa_print_value(f, m, instr->br.cond, t_bool);
@@ -495,7 +499,6 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
  						ssa_print_instr(f, m, value);
  					}
  				}
-
  				ssa_fprintf(f, "}\n\n");
  			}
 

+ 198 - 47
src/codegen/ssa.cpp

@@ -190,6 +190,12 @@ struct ssaValue {
 	};
 };
 
+gb_global ssaValue *v_zero    = NULL;
+gb_global ssaValue *v_one     = NULL;
+gb_global ssaValue *v_zero32  = NULL;
+gb_global ssaValue *v_one32   = NULL;
+gb_global ssaValue *v_two32   = NULL;
+
 enum ssaLvalueKind {
 	ssaLvalue_Blank,
 	ssaLvalue_Address,
@@ -208,6 +214,10 @@ struct ssaLvalue {
 	};
 };
 
+
+
+
+
 ssaLvalue ssa_make_lvalue_address(ssaValue *value, AstNode *expr) {
 	ssaLvalue lval = {ssaLvalue_Address};
 	lval.address.value = value;
@@ -455,6 +465,7 @@ ssaValue *ssa_make_instr_ret(ssaProcedure *p, ssaValue *value) {
 
 
 
+
 ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
 	ssaValue *v = ssa_alloc_value(a, ssaValue_Constant);
 	v->constant.type  = type;
@@ -525,16 +536,13 @@ b32 ssa_is_blank_ident(AstNode *node) {
 
 
 
-ssaValue *ssa_block_emit(ssaBlock *b, ssaValue *instr) {
+ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) {
+	ssaBlock *b = proc->curr_block;
 	instr->instr.parent = b;
 	if (b) {
 		gb_array_append(b->instrs, instr);
 	}
 	return instr;
-
-}
-ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) {
-	return ssa_block_emit(proc->curr_block, instr);
 }
 ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) {
 	return ssa_emit(p, ssa_make_instr_store(p, address, value));
@@ -785,7 +793,127 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *
 	return ssa_emit(proc, v);
 }
 
+ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offset) {
+	Type *type = ssa_value_type(ptr);
+	ssaValue *gep = NULL;
+	offset = ssa_emit_conv(proc, offset, t_int);
+	gep = ssa_make_instr_get_element_ptr(proc, ptr, offset, NULL, 1, false);
+	gep->instr.get_element_ptr.element_type = type_deref(type);
+	gep->instr.get_element_ptr.result_type  = type;
+	return ssa_emit(proc, gep);
+}
+
+ssaValue *ssa_emit_struct_gep(ssaProcedure *proc, ssaValue *s, ssaValue *index, Type *result_type) {
+	ssaValue *gep = NULL;
+	// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
+	index = ssa_emit_conv(proc, index, t_i32);
+	gep = ssa_make_instr_get_element_ptr(proc, s, v_zero, index, 2, true);
+	gep->instr.get_element_ptr.element_type = ssa_value_type(s);
+	gep->instr.get_element_ptr.result_type = result_type;
+
+	return ssa_emit(proc, gep);
+}
+
+
+ssaValue *ssa_array_elem(ssaProcedure *proc, ssaValue *array) {
+	Type *t = ssa_value_type(array);
+	GB_ASSERT(t->kind == Type_Array);
+	Type *base_type = t->array.element;
+	ssaValue *elem = ssa_make_instr_get_element_ptr(proc, array, v_zero, v_zero, 2, true);
+	Type *result_type = make_type_pointer(proc->module->allocator, base_type);
+	elem->instr.get_element_ptr.element_type = t;
+	elem->instr.get_element_ptr.result_type = result_type;
+	return ssa_emit(proc, elem);
+}
+ssaValue *ssa_array_len(ssaProcedure *proc, ssaValue *array) {
+	Type *t = ssa_value_type(array);
+	GB_ASSERT(t->kind == Type_Array);
+	return ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(t->array.count));
+}
+ssaValue *ssa_array_cap(ssaProcedure *proc, ssaValue *array) {
+	return ssa_array_len(proc, array);
+}
 
+ssaValue *ssa_slice_elem(ssaProcedure *proc, ssaValue *slice) {
+	Type *t = ssa_value_type(slice);
+	GB_ASSERT(t->kind == Type_Slice);
+
+	Type *result_type = make_type_pointer(proc->module->allocator, t->slice.element);
+	return ssa_emit_load(proc, ssa_emit_struct_gep(proc, slice, v_zero32, result_type));
+}
+ssaValue *ssa_slice_len(ssaProcedure *proc, ssaValue *slice) {
+	Type *t = ssa_value_type(slice);
+	GB_ASSERT(t->kind == Type_Slice);
+	return ssa_emit_load(proc, ssa_emit_struct_gep(proc, slice, v_one32, t_int));
+}
+ssaValue *ssa_slice_cap(ssaProcedure *proc, ssaValue *slice) {
+	Type *t = ssa_value_type(slice);
+	GB_ASSERT(t->kind == Type_Slice);
+	return ssa_emit_load(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int));
+}
+
+
+
+
+
+ssaValue *ssa_emit_slice(ssaProcedure *proc, Type *slice_type, ssaValue *base, ssaValue *low, ssaValue *high, ssaValue *max) {
+	// TODO(bill): array bounds checking for slice creation
+	// TODO(bill): check that low < high <= max
+	gbAllocator a = proc->module->allocator;
+	Type *base_type = get_base_type(ssa_value_type(base));
+
+	if (low == NULL) {
+		low = v_zero;
+	}
+	if (high == NULL) {
+		switch (base_type->kind) {
+		case Type_Array:   high = ssa_array_len(proc, base); break;
+		case Type_Slice:   high = ssa_slice_len(proc, base); break;
+		case Type_Pointer: high = v_one;                     break;
+		}
+	}
+	if (max == NULL) {
+		switch (base_type->kind) {
+		case Type_Array:   max = ssa_array_cap(proc, base); break;
+		case Type_Slice:   max = ssa_slice_cap(proc, base); break;
+		case Type_Pointer: max = high;                      break;
+		}
+	}
+	GB_ASSERT(max != NULL);
+
+	Token op_sub = {Token_Sub};
+	ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int);
+	ssaValue *cap = ssa_emit_arith(proc, op_sub, max,  low, t_int);
+
+	ssaValue *elem = NULL;
+	switch (base_type->kind) {
+	case Type_Array:   elem = ssa_array_elem(proc, base); break;
+	case Type_Slice:   elem = ssa_slice_elem(proc, base); break;
+	case Type_Pointer: elem = base;                       break;
+	}
+
+	elem = ssa_emit_ptr_offset(proc, elem, low);
+
+	// NOTE(bill): Just used as dummy entity - never to be used really
+	Entity *slice_entity = make_entity_variable(proc->module->allocator,
+	                                            proc->curr_block->scope,
+	                                            empty_token,
+	                                            slice_type);
+
+	ssaValue *slice = ssa_emit(proc, ssa_make_instr_local(proc, slice_entity));
+
+	ssaValue *gep = NULL;
+	gep = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_value_type(elem));
+	ssa_emit_store(proc, gep, elem);
+
+	gep = ssa_emit_struct_gep(proc, slice, v_one32, t_int);
+	ssa_emit_store(proc, gep, len);
+
+	gep = ssa_emit_struct_gep(proc, slice, v_two32, t_int);
+	ssa_emit_store(proc, gep, cap);
+
+	return ssa_emit_load(proc, slice);
+}
 
 
 ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
@@ -818,6 +946,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		return ssa_lvalue_load(ssa_build_addr(proc, expr), proc);
 	case_end;
 
+	case_ast_node(se, SelectorExpr, expr);
+		return ssa_lvalue_load(ssa_build_addr(proc, expr), proc);
+	case_end;
+
 	case_ast_node(ue, UnaryExpr, expr);
 		switch (ue->op.kind) {
 		case Token_Pointer:
@@ -826,8 +958,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			return ssa_build_expr(proc, ue->expr);
 		case Token_Sub: {
 			// NOTE(bill): -`x` == 0 - `x`
-			ExactValue zero = make_exact_value_integer(0);
-			ssaValue *left = ssa_make_value_constant(proc->module->allocator, tv->type, zero);
+			ssaValue *left = v_zero;
 			ssaValue *right = ssa_build_expr(proc, ue->expr);
 			return ssa_emit_arith(proc, ue->op, left, right, tv->type);
 		} break;
@@ -876,6 +1007,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 		default:
 			GB_PANIC("Invalid binary expression");
+			break;
 		}
 	case_end;
 
@@ -892,7 +1024,25 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 	case_end;
 
 	case_ast_node(se, SliceExpr, expr);
-		GB_PANIC("TODO(bill): ssa_build_single_expr SliceExpr");
+		ssaValue *base = NULL;
+		ssaValue *low  = NULL;
+		ssaValue *high = NULL;
+		ssaValue *max  = NULL;
+		switch (tv->type->kind) {
+		case Type_Slice:
+		case Type_Array:
+			base = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
+			break;
+		case Type_Basic:
+			GB_PANIC("SliceExpr Type_Basic");
+			break;
+		}
+
+		if (se->low  != NULL)    low  = ssa_build_expr(proc, se->low);
+		if (se->high != NULL)    high = ssa_build_expr(proc, se->high);
+		if (se->triple_indexed)  max  = ssa_build_expr(proc, se->max);
+
+		return ssa_emit_slice(proc, tv->type, base, low, high, max);
 	case_end;
 
 	case_ast_node(ie, IndexExpr, expr);
@@ -911,10 +1061,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		} break;
 		}
 	case_end;
-
-	case_ast_node(se, SelectorExpr, expr);
-		return ssa_build_expr(proc, se->selector);
-	case_end;
 	}
 
 	GB_PANIC("Unexpected expression");
@@ -968,59 +1114,67 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	case_end;
 
 	case_ast_node(se, SelectorExpr, expr);
+		AstNode *selector = unparen_expr(se->selector);
+		Type *type = type_of_expr(proc->module->info, se->expr);
+
+		isize index = 0;
+		Entity *entity = lookup_field(type, selector, &index);
+		GB_ASSERT(entity != NULL);
+
+		ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
+
+		if (type->kind == Type_Pointer) {
+			// NOTE(bill): Allow x^.y and x.y to be the same
+			type = type_deref(type);
+			v = ssa_emit_load(proc, v);
+		}
+
+		ssaValue *i0 = v_zero32;
+		ssaValue *i1 = ssa_make_value_constant(proc->module->allocator, t_i32, make_exact_value_integer(index));
+		ssaValue *gep = ssa_make_instr_get_element_ptr(proc, v, i0, i1, 2, true);
+		gep->instr.get_element_ptr.result_type = entity->type;
+		gep->instr.get_element_ptr.element_type = type;
+		v = ssa_emit(proc, gep);
+		return ssa_make_lvalue_address(v, expr);
 	case_end;
 
 	case_ast_node(ie, IndexExpr, expr);
-		Type *t_int = &basic_types[Basic_int];
 		ssaValue *v = NULL;
-		Type *element_type = NULL;
-		Type *t = type_of_expr(proc->module->info, ie->expr);
-		t = get_base_type(t);
+		Type *t = get_base_type(type_of_expr(proc->module->info, ie->expr));
 		switch (t->kind) {
 		case Type_Array: {
-			ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
-			ssaValue *i0 = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(0));
-			ssaValue *i1 = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
-			ssaValue *gep = ssa_make_instr_get_element_ptr(proc, e,
-			                                               i0, i1, 2, true);
-			element_type = t->array.element;
-			v = gep;
+			ssaValue *array = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
+			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
+			ssaValue *elem = ssa_array_elem(proc, array);
+			v = ssa_emit_ptr_offset(proc, elem, index);
 		} break;
 		case Type_Pointer: {
-			ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
-			ssaValue *load = ssa_emit_load(proc, e);
-			gb_printf("load: %s\n", type_to_string(ssa_value_type(load)));
+			ssaValue *ptr = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc));
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
-			ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load,
-			                                               index, NULL, 1, false);
-			element_type = t->pointer.element;
-			gep->instr.get_element_ptr.result_type  = t->pointer.element;
-			gep->instr.get_element_ptr.element_type = t->pointer.element;
-			v = gep;
-			gb_printf("gep: %s\n", type_to_string(ssa_value_type(gep)));
+			v = ssa_emit_ptr_offset(proc, ptr, index);
 		} break;
 		case Type_Slice: {
-			GB_PANIC("ssa_build_addr AstNode_IndexExpression Type_Slice");
+			ssaValue *slice = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
+			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
+			ssaValue *elem = ssa_slice_elem(proc, slice);
+			v = ssa_emit_ptr_offset(proc, elem, index);
 		} break;
 		}
 
-		ssa_value_set_type(v, element_type);
-		return ssa_make_lvalue_address(ssa_emit(proc, v), expr);
+		// NOTE(bill): lvalue address encodes the pointer, thus the deref
+		ssa_value_set_type(v, type_deref(ssa_value_type(v)));
+		return ssa_make_lvalue_address(v, expr);
 	case_end;
 
 	case_ast_node(de, DerefExpr, expr);
-		// TODO(bill): Clean up
-		Type *t = type_of_expr(proc->module->info, de->expr);
-		t = type_deref(get_base_type(t));
-		ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc);
-		ssaValue *load = ssa_emit_load(proc, e);
+		ssaValue *load = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc));
 		ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load, NULL, NULL, 0, false);
+		Type *t = ssa_value_type(load);
+		t = type_deref(get_base_type(t));
 		gep->instr.get_element_ptr.result_type  = t;
 		gep->instr.get_element_ptr.element_type = t;
 		return ssa_make_lvalue_address(ssa_emit(proc, gep), expr);
 	case_end;
-
-	// TODO(bill): Others address
 	}
 
 	GB_PANIC("Unexpected address expression");
@@ -1134,8 +1288,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) {
 			op.kind = Token_Sub;
 		}
 		ssaLvalue lval = ssa_build_addr(proc, ids->expr);
-		ssaValue *one = ssa_make_value_constant(proc->module->allocator, ssa_lvalue_type(lval),
-		                                        make_exact_value_integer(1));
+		ssaValue *one = ssa_emit_conv(proc, v_one, ssa_lvalue_type(lval));
 		ssa_build_assign_op(proc, lval, one, op);
 
 	case_end;
@@ -1323,8 +1476,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) {
 	}
 }
 
-
-
 void ssa_build_proc(ssaValue *value) {
 	ssaProcedure *proc = &value->proc;