Browse Source

#foreign_library; vector fields (x, y, z, w) for count <= 4

Ginger Bill 8 years ago
parent
commit
0cab083b8f
12 changed files with 296 additions and 198 deletions
  1. 2 2
      build.bat
  2. 4 0
      core/opengl.odin
  3. 6 6
      core/os.odin
  4. 5 0
      core/win32.odin
  5. 1 1
      src/checker/checker.cpp
  6. 15 5
      src/checker/entity.cpp
  7. 20 3
      src/checker/expr.cpp
  8. 2 2
      src/checker/stmt.cpp
  9. 24 1
      src/checker/types.cpp
  10. 2 2
      src/main.cpp
  11. 48 21
      src/parser.cpp
  12. 167 155
      src/ssa.cpp

+ 2 - 2
build.bat

@@ -4,7 +4,7 @@
 set exe_name=odin.exe
 
 :: Debug = 0, Release = 1
-set release_mode=1
+set release_mode=0
 
 set compiler_flags= -nologo -Oi -TP -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
 
@@ -48,7 +48,7 @@ rem pushd %build_dir%
 
 	cl %compiler_settings% "src\main.cpp" ^
 		/link %linker_settings% -OUT:%exe_name% ^
-	&& odin run code/demo.odin
+	&& odin run w:/Freyr/src/main.odin
 	rem odin run code/demo.odin
 
 

+ 4 - 0
core/opengl.odin

@@ -47,3 +47,7 @@ TexParameterf  :: proc(target: i32, pname: i32, param: f32)      #foreign "glTex
 BindTexture    :: proc(target: i32, texture: u32)                #foreign "glBindTexture"
 TexImage2D     :: proc(target, level, internal_format, width, height, border, format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
 
+
+
+
+

+ 6 - 6
core/os.odin

@@ -56,25 +56,25 @@ stderr := ^__std_files[File_Standard.ERROR]
 
 
 
-read_entire_file :: proc(name: string) -> (string, bool) {
+read_entire_file :: proc(name: string) -> ([]byte, bool) {
 	buf: [300]byte
 	copy(buf[:], name as []byte)
 
 	f, file_ok := open(name)
 	if !file_ok {
-		return "", false
+		return nil, false
 	}
 	defer close(^f)
 
 	length: i64
 	file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0
 	if !file_size_ok {
-		return "", false
+		return nil, false
 	}
 
 	data := new_slice(u8, length)
 	if data.data == nil {
-		return "", false
+		return nil, false
 	}
 
 	single_read_length: i32
@@ -93,13 +93,13 @@ read_entire_file :: proc(name: string) -> (string, bool) {
 		win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
 		if single_read_length <= 0 {
 			free(data.data)
-			return "", false
+			return nil, false
 		}
 
 		total_read += single_read_length as i64
 	}
 
-	return data as string, true
+	return data, true
 }
 
 

+ 5 - 0
core/win32.odin

@@ -10,6 +10,7 @@ HCURSOR   :: type HANDLE
 HMENU     :: type HANDLE
 HBRUSH    :: type HANDLE
 HGDIOBJ   :: type HANDLE
+HMODULE   :: type HANDLE
 WPARAM    :: type uint
 LPARAM    :: type int
 LRESULT   :: type int
@@ -208,6 +209,9 @@ StretchDIBits :: proc(hdc: HDC,
 
 
 
+LoadLibraryA   :: proc(c_str: ^u8) -> HMODULE #foreign
+FreeLibrary    :: proc(h: HMODULE) #foreign
+GetProcAddress :: proc(h: HMODULE, c_str: ^u8) -> proc() #foreign
 
 
 
@@ -280,6 +284,7 @@ ReleaseDC         :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
 WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091
 WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092
 WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126
+WGL_CONTEXT_CORE_PROFILE_BIT_ARB          :: 0x0001
 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
 
 wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign #dll_import

+ 1 - 1
src/checker/checker.cpp

@@ -1047,7 +1047,7 @@ void check_parsed_files(Checker *c) {
 			case_ast_node(id, ImportDecl, decl);
 				// NOTE(bill): Handle later
 			case_end;
-			case_ast_node(fsl, ForeignSystemLibrary, decl);
+			case_ast_node(fsl, ForeignLibrary, decl);
 				// NOTE(bill): ignore
 			case_end;
 

+ 15 - 5
src/checker/entity.cpp

@@ -29,11 +29,12 @@ String const entity_strings[] = {
 };
 
 enum EntityFlag : u32 {
-	EntityFlag_Visited   = 1<<0,
-	EntityFlag_Used      = 1<<1,
-	EntityFlag_Anonymous = 1<<2,
-	EntityFlag_Field     = 1<<3,
-	EntityFlag_Param     = 1<<4,
+	EntityFlag_Visited    = 1<<0,
+	EntityFlag_Used       = 1<<1,
+	EntityFlag_Anonymous  = 1<<2,
+	EntityFlag_Field      = 1<<3,
+	EntityFlag_Param      = 1<<4,
+	EntityFlag_VectorElem = 1<<5,
 };
 
 struct Entity {
@@ -141,6 +142,15 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
 	return entity;
 }
 
+Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
+	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->flags |= EntityFlag_Field;
+	entity->flags |= EntityFlag_VectorElem;
+	return entity;
+}
+
 Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type) {
 	Entity *entity = alloc_entity(a, Entity_Procedure, scope, token, signature_type);
 	return entity;

+ 20 - 3
src/checker/expr.cpp

@@ -1429,9 +1429,22 @@ b32 check_is_expr_vector_index(Checker *c, AstNode *expr) {
 	expr = unparen_expr(expr);
 	if (expr->kind == AstNode_IndexExpr) {
 		ast_node(ie, IndexExpr, expr);
-		Type *t = type_of_expr(&c->info, ie->expr);
+		Type *t = type_deref(type_of_expr(&c->info, ie->expr));
 		if (t != NULL) {
-			return is_type_vector(base_type(t));
+			return is_type_vector(t);
+		}
+	}
+	return false;
+}
+
+b32 check_is_vector_elem(Checker *c, AstNode *expr) {
+	// HACK(bill): Handle this correctly. Maybe with a custom AddressingMode
+	expr = unparen_expr(expr);
+	if (expr->kind == AstNode_SelectorExpr) {
+		ast_node(se, SelectorExpr, expr);
+		Type *t = type_deref(type_of_expr(&c->info, se->expr));
+		if (t != NULL && is_type_vector(t)) {
+			return true;
 		}
 	}
 	return false;
@@ -1443,7 +1456,8 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
 	switch (op.kind) {
 	case Token_Pointer: { // Pointer address
 		if (o->mode != Addressing_Variable ||
-		    check_is_expr_vector_index(c, o->expr)) {
+		    check_is_expr_vector_index(c, o->expr) ||
+		    check_is_vector_elem(c, o->expr)) {
 			ast_node(ue, UnaryExpr, node);
 			gbString str = expr_to_string(ue->expr);
 			defer (gb_string_free(str));
@@ -3666,6 +3680,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		switch (t->kind) {
 		case Type_Record: {
 			if (!is_type_struct(t)) {
+				if (cl->elems.count != 0) {
+					error(ast_node_token(node), "Illegal compound literal");
+				}
 				break;
 			}
 			if (cl->elems.count == 0) {

+ 2 - 2
src/checker/stmt.cpp

@@ -438,8 +438,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			isize lhs_count = as->lhs.count;
 			isize rhs_count = operands.count;
 
-			isize operand_index = 0;
-			for_array(i, operands) {
+			isize operand_count = gb_min(as->lhs.count, operands.count);
+			for (isize i = 0; i < operand_count; i++) {
 				AstNode *lhs = as->lhs[i];
 				check_assignment_variable(c, &operands[i], lhs);
 			}

+ 24 - 1
src/checker/types.cpp

@@ -908,6 +908,28 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
 			sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count));
 			return sel;
 		}
+		if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) {
+			// HACK(bill): Memory leak
+			switch (type->Vector.count) {
+			#define _VECTOR_FIELD(_name, length) \
+			case (length): \
+				if (field_name == _name) { \
+					selection_add_index(&sel, (length)-1); \
+					sel.entity = make_entity_field(a, NULL, make_token_ident(make_string(_name)), type->Vector.elem, false, (length)-1); \
+					return sel; \
+				} \
+				/*fallthrough*/
+
+			_VECTOR_FIELD("w", 4);
+			_VECTOR_FIELD("z", 3);
+			_VECTOR_FIELD("y", 2);
+			_VECTOR_FIELD("x", 1);
+			case 0: break;
+
+			#undef _VECTOR_FIELD
+			}
+		}
+
 	} else if (type->kind == Type_Slice) {
 		String data_str     = make_string("data");
 		String count_str    = make_string("count");
@@ -1059,7 +1081,8 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 		switch (t->Record.kind) {
 		case TypeRecord_Struct:
 			if (t->Record.field_count > 0) {
-				if (!t->Record.struct_is_ordered) {
+				// TODO(bill): What is this supposed to be?
+				if (t->Record.struct_is_packed) {
 					i64 max = s.word_size;
 					for (isize i = 1; i < t->Record.field_count; i++) {
 						// NOTE(bill): field zero is null

+ 2 - 2
src/main.cpp

@@ -234,8 +234,8 @@ int main(int argc, char **argv) {
 	gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
 	// defer (gb_string_free(lib_str));
 	char lib_str_buf[1024] = {};
-	for_array(i, parser.system_libraries) {
-		String lib = parser.system_libraries[i];
+	for_array(i, parser.foreign_libraries) {
+		String lib = parser.foreign_libraries[i];
 		isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
 		                        " %.*s.lib", LIT(lib));
 		lib_str = gb_string_appendc(lib_str, lib_str_buf);

+ 48 - 21
src/parser.cpp

@@ -56,7 +56,7 @@ struct Parser {
 	Array<AstFile>      files;
 	Array<ImportedFile> imports;
 	gbAtomic32          import_index;
-	Array<String>       system_libraries;
+	Array<String>       foreign_libraries;
 	isize               total_token_count;
 	gbMutex             mutex;
 };
@@ -261,8 +261,9 @@ AST_NODE_KIND(_DeclBegin,      "", struct{}) \
 		b32 is_load;          \
 		AstNode *note;        \
 	}) \
-	AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { \
+	AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
 		Token token, filepath; \
+		b32 is_system; \
 	}) \
 AST_NODE_KIND(_DeclEnd,   "", struct{}) \
 AST_NODE_KIND(_TypeBegin, "", struct{}) \
@@ -460,8 +461,8 @@ Token ast_node_token(AstNode *node) {
 		return node->TypeDecl.token;
 	case AstNode_ImportDecl:
 		return node->ImportDecl.token;
-	case AstNode_ForeignSystemLibrary:
-		return node->ForeignSystemLibrary.token;
+	case AstNode_ForeignLibrary:
+		return node->ForeignLibrary.token;
 	case AstNode_Parameter: {
 		if (node->Parameter.names.count > 0) {
 			return ast_node_token(node->Parameter.names[0]);
@@ -965,10 +966,11 @@ AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_n
 	return result;
 }
 
-AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) {
-	AstNode *result = make_node(f, AstNode_ForeignSystemLibrary);
-	result->ForeignSystemLibrary.token = token;
-	result->ForeignSystemLibrary.filepath = filepath;
+AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, b32 is_system) {
+	AstNode *result = make_node(f, AstNode_ForeignLibrary);
+	result->ForeignLibrary.token = token;
+	result->ForeignLibrary.filepath = filepath;
+	result->ForeignLibrary.is_system = is_system;
 	return result;
 }
 
@@ -2123,8 +2125,8 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
 	}
 
 	case Token_raw_union: {
-		Token token = expect_token_after(f, Token_OpenBrace, "`raw_union`");
-		Token open = expect_token(f, Token_OpenBrace);
+		Token token = expect_token(f, Token_raw_union);
+		Token open = expect_token_after(f, Token_OpenBrace, "`raw_union`");
 		isize decl_count = 0;
 		AstNodeArray decls = parse_struct_params(f, &decl_count, true);
 		Token close = expect_token(f, Token_CloseBrace);
@@ -2791,10 +2793,17 @@ AstNode *parse_stmt(AstFile *f) {
 		} else if (tag == "foreign_system_library") {
 			Token file_path = expect_token(f, Token_String);
 			if (f->curr_proc == NULL) {
-				return make_foreign_system_library(f, s->TagStmt.token, file_path);
+				return make_foreign_library(f, s->TagStmt.token, file_path, true);
 			}
 			syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope");
 			return make_bad_decl(f, token, file_path);
+		} else if (tag == "foreign_library") {
+			Token file_path = expect_token(f, Token_String);
+			if (f->curr_proc == NULL) {
+				return make_foreign_library(f, s->TagStmt.token, file_path, false);
+			}
+			syntax_error(token, "You cannot use #foreign_library within a procedure. This must be done at the file scope");
+			return make_bad_decl(f, token, file_path);
 		} else if (tag == "thread_local") {
 			AstNode *var_decl = parse_simple_stmt(f);
 			if (var_decl->kind != AstNode_VarDecl) {
@@ -2918,7 +2927,7 @@ void destroy_ast_file(AstFile *f) {
 b32 init_parser(Parser *p) {
 	array_init(&p->files, heap_allocator());
 	array_init(&p->imports, heap_allocator());
-	array_init(&p->system_libraries, heap_allocator());
+	array_init(&p->foreign_libraries, heap_allocator());
 	gb_mutex_init(&p->mutex);
 	return true;
 }
@@ -2935,7 +2944,7 @@ void destroy_parser(Parser *p) {
 #endif
 	array_free(&p->files);
 	array_free(&p->imports);
-	array_free(&p->system_libraries);
+	array_free(&p->foreign_libraries);
 	gb_mutex_destroy(&p->mutex);
 }
 
@@ -2991,17 +3000,17 @@ String get_fullpath_core(gbAllocator a, String path) {
 }
 
 // NOTE(bill): Returns true if it's added
-b32 try_add_foreign_system_library_path(Parser *p, String import_file) {
+b32 try_add_foreign_library_path(Parser *p, String import_file) {
 	gb_mutex_lock(&p->mutex);
 	defer (gb_mutex_unlock(&p->mutex));
 
-	for_array(i, p->system_libraries) {
-		String import = p->system_libraries[i];
+	for_array(i, p->foreign_libraries) {
+		String import = p->foreign_libraries[i];
 		if (import == import_file) {
 			return false;
 		}
 	}
-	array_add(&p->system_libraries, import_file);
+	array_add(&p->foreign_libraries, import_file);
 	return true;
 }
 
@@ -3118,18 +3127,36 @@ void parse_file(Parser *p, AstFile *f) {
 				id->fullpath = import_file;
 				try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
 
-			} else if (node->kind == AstNode_ForeignSystemLibrary) {
-				auto *id = &node->ForeignSystemLibrary;
+			} else if (node->kind == AstNode_ForeignLibrary) {
+				auto *id = &node->ForeignLibrary;
 				String file_str = id->filepath.string;
 
 				if (!is_import_path_valid(file_str)) {
-					syntax_error(ast_node_token(node), "Invalid `foreign_system_library` path");
+					if (id->is_system) {
+						syntax_error(ast_node_token(node), "Invalid `foreign_system_library` path");
+					} else {
+						syntax_error(ast_node_token(node), "Invalid `foreign_library` path");
+					}
 					// NOTE(bill): It's a naughty name
 					f->decls[i] = make_bad_decl(f, id->token, id->token);
 					continue;
 				}
 
-				try_add_foreign_system_library_path(p, file_str);
+				if (!id->is_system) {
+					gbAllocator allocator = heap_allocator(); // TODO(bill): Change this allocator
+
+					String rel_path = get_fullpath_relative(allocator, base_dir, file_str);
+					String import_file = rel_path;
+					if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
+						String abs_path = get_fullpath_core(allocator, file_str);
+						if (gb_file_exists(cast(char *)abs_path.text)) {
+							import_file = abs_path;
+						}
+					}
+					file_str = import_file;
+				}
+
+				try_add_foreign_library_path(p, file_str);
 			}
 		}
 	}

+ 167 - 155
src/ssa.cpp

@@ -811,7 +811,7 @@ ssaValue *ssa_make_instr_array_element_ptr(ssaProcedure *p, ssaValue *address, s
 	Type *t = ssa_type(address);
 	GB_ASSERT(is_type_pointer(t));
 	t = base_type(type_deref(t));
-	GB_ASSERT(is_type_array(t));
+	GB_ASSERT(is_type_array(t) || is_type_vector(t));
 
 	Type *result_type = make_type_pointer(p->module->allocator, t->Array.elem);
 
@@ -1524,7 +1524,7 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, TokenKind op_kind, ssaValue *left, s
 
 ssaValue *ssa_emit_array_ep(ssaProcedure *proc, ssaValue *s, ssaValue *index) {
 	Type *st = base_type(type_deref(ssa_type(s)));
-	GB_ASSERT(is_type_array(st));
+	GB_ASSERT(is_type_array(st) || is_type_vector(st));
 
 	// 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);
@@ -1693,6 +1693,8 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S
 			}
 		} else if (type->kind == Type_Slice) {
 			e = ssa_emit_struct_ep(proc, e, index);
+		} else if (type->kind == Type_Vector) {
+			e = ssa_emit_array_ep(proc, e, index);
 		} else {
 			GB_PANIC("un-gep-able type");
 		}
@@ -1854,9 +1856,11 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
 					return f->token.string;
 				}
 			}
-			String name = lookup_polymorphic_field(info, dst, f->type);
-			if (name.len > 0) {
-				return name;
+			if (is_type_struct(f->type)) {
+				String name = lookup_polymorphic_field(info, dst, f->type);
+				if (name.len > 0) {
+					return name;
+				}
 			}
 		}
 	}
@@ -2673,156 +2677,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 
 	case_ast_node(cl, CompoundLit, expr);
-		ssa_emit_comment(proc, make_string("CompoundLit"));
-		Type *type = type_of_expr(proc->module->info, expr);
-		Type *bt = base_type(type);
-		ssaValue *v = ssa_add_local_generated(proc, type);
-
-		Type *et = NULL;
-		switch (bt->kind) {
-		case Type_Vector: et = bt->Vector.elem; break;
-		case Type_Array:  et = bt->Array.elem;  break;
-		case Type_Slice:  et = bt->Slice.elem;  break;
-		}
-
-		auto is_elem_const = [](ssaModule *m, AstNode *elem, Type *elem_type) -> b32 {
-			if (base_type(elem_type) == t_any) {
-				return false;
-			}
-			if (elem->kind == AstNode_FieldValue) {
-				elem = elem->FieldValue.value;
-			}
-			TypeAndValue *tav = type_and_value_of_expression(m->info, elem);
-			GB_ASSERT(tav != NULL);
-			return tav->value.kind != ExactValue_Invalid;
-		};
-
-		switch (bt->kind) {
-		default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
-
-		case Type_Vector: {
-			ssaValue *result = ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr));
-			for_array(index, cl->elems) {
-				AstNode *elem = cl->elems[index];
-				if (is_elem_const(proc->module, elem, et)) {
-					continue;
-				}
-				ssaValue *field_elem = ssa_build_expr(proc, elem);
-				Type *t = ssa_type(field_elem);
-				GB_ASSERT(t->kind != Type_Tuple);
-				ssaValue *ev = ssa_emit_conv(proc, field_elem, et);
-				ssaValue *i = ssa_make_const_int(proc->module->allocator, index);
-				result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
-			}
-
-			if (cl->elems.count == 1 && bt->Vector.count > 1) {
-				isize index_count = bt->Vector.count;
-				i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
-				for (isize i = 0; i < index_count; i++) {
-					indices[i] = 0;
-				}
-				ssaValue *sv = ssa_emit(proc, ssa_make_instr_vector_shuffle(proc, result, indices, index_count));
-				ssa_emit_store(proc, v, sv);
-				return ssa_emit_load(proc, v);
-			}
-			return result;
-		} break;
-
-		case Type_Record: {
-			GB_ASSERT(is_type_struct(bt));
-			auto *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) {
-					AstNode *elem = cl->elems[field_index];
-
-					ssaValue *field_expr = NULL;
-					Entity *field = NULL;
-					isize index = field_index;
-
-					if (elem->kind == AstNode_FieldValue) {
-						ast_node(fv, FieldValue, elem);
-						Selection sel = lookup_field(proc->module->allocator, bt, fv->field->Ident.string, false);
-						index = sel.index[0];
-						elem = fv->value;
-					} else {
-						TypeAndValue *tav = type_and_value_of_expression(proc->module->info, elem);
-						Selection sel = lookup_field(proc->module->allocator, bt, st->fields_in_src_order[field_index]->token.string, false);
-						index = sel.index[0];
-					}
-
-					field = st->fields[index];
-					if (is_elem_const(proc->module, elem, field->type)) {
-						continue;
-					}
-
-					field_expr = ssa_build_expr(proc, elem);
-
-					GB_ASSERT(ssa_type(field_expr)->kind != Type_Tuple);
-
-
-
-					Type *ft = field->type;
-					ssaValue *fv = ssa_emit_conv(proc, field_expr, ft);
-					ssaValue *gep = ssa_emit_struct_ep(proc, v, index);
-					ssa_emit_store(proc, gep, fv);
-				}
-			}
-		} break;
-		case Type_Array: {
-			if (cl->elems.count > 0) {
-				ssa_emit_store(proc, v, ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
-				for_array(i, cl->elems) {
-					AstNode *elem = cl->elems[i];
-					if (is_elem_const(proc->module, elem, et)) {
-						continue;
-					}
-					ssaValue *field_expr = ssa_build_expr(proc, elem);
-					Type *t = ssa_type(field_expr);
-					GB_ASSERT(t->kind != Type_Tuple);
-					ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
-					ssaValue *gep = ssa_emit_array_ep(proc, v, i);
-					ssa_emit_store(proc, gep, ev);
-				}
-			}
-		} break;
-		case Type_Slice: {
-			if (cl->elems.count > 0) {
-				Type *elem_type = bt->Slice.elem;
-				Type *elem_ptr_type = make_type_pointer(proc->module->allocator, elem_type);
-				Type *elem_ptr_ptr_type = make_type_pointer(proc->module->allocator, elem_ptr_type);
-				Type *t_int_ptr = make_type_pointer(proc->module->allocator, t_int);
-				ssaValue *slice = ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr));
-				GB_ASSERT(slice->kind == ssaValue_ConstantSlice);
-
-				ssaValue *data = ssa_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32);
-
-				for_array(i, cl->elems) {
-					AstNode *elem = cl->elems[i];
-					if (is_elem_const(proc->module, elem, et)) {
-						continue;
-					}
-
-					ssaValue *field_expr = ssa_build_expr(proc, elem);
-					Type *t = ssa_type(field_expr);
-					GB_ASSERT(t->kind != Type_Tuple);
-					ssaValue *ev = ssa_emit_conv(proc, field_expr, elem_type);
-					ssaValue *offset = ssa_emit_ptr_offset(proc, data, ssa_make_const_int(proc->module->allocator, i));
-					ssa_emit_store(proc, offset, ev);
-				}
-
-				ssaValue *gep0 = ssa_emit_struct_ep(proc, v, 0);
-				ssaValue *gep1 = ssa_emit_struct_ep(proc, v, 1);
-				ssaValue *gep2 = ssa_emit_struct_ep(proc, v, 1);
-
-				ssa_emit_store(proc, gep0, data);
-				ssa_emit_store(proc, gep1, ssa_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
-				ssa_emit_store(proc, gep2, ssa_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
-			}
-		} break;
-		}
-
-		return ssa_emit_load(proc, v);
+		return ssa_emit_load(proc, ssa_build_addr(proc, expr).addr);
 	case_end;
 
 
@@ -3630,6 +3485,160 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		ssa_emit_store(proc, v, e);
 		return ssa_make_addr(v, expr);
 	case_end;
+
+
+	case_ast_node(cl, CompoundLit, expr);
+		ssa_emit_comment(proc, make_string("CompoundLit"));
+		Type *type = type_of_expr(proc->module->info, expr);
+		Type *bt = base_type(type);
+		ssaValue *v = ssa_add_local_generated(proc, type);
+
+		Type *et = NULL;
+		switch (bt->kind) {
+		case Type_Vector: et = bt->Vector.elem; break;
+		case Type_Array:  et = bt->Array.elem;  break;
+		case Type_Slice:  et = bt->Slice.elem;  break;
+		}
+
+		auto is_elem_const = [](ssaModule *m, AstNode *elem, Type *elem_type) -> b32 {
+			if (base_type(elem_type) == t_any) {
+				return false;
+			}
+			if (elem->kind == AstNode_FieldValue) {
+				elem = elem->FieldValue.value;
+			}
+			TypeAndValue *tav = type_and_value_of_expression(m->info, elem);
+			GB_ASSERT(tav != NULL);
+			return tav->value.kind != ExactValue_Invalid;
+		};
+
+		switch (bt->kind) {
+		default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
+
+		case Type_Vector: {
+			ssaValue *result = ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr));
+			for_array(index, cl->elems) {
+				AstNode *elem = cl->elems[index];
+				if (is_elem_const(proc->module, elem, et)) {
+					continue;
+				}
+				ssaValue *field_elem = ssa_build_expr(proc, elem);
+				Type *t = ssa_type(field_elem);
+				GB_ASSERT(t->kind != Type_Tuple);
+				ssaValue *ev = ssa_emit_conv(proc, field_elem, et);
+				ssaValue *i = ssa_make_const_int(proc->module->allocator, index);
+				result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
+			}
+
+			if (cl->elems.count == 1 && bt->Vector.count > 1) {
+				isize index_count = bt->Vector.count;
+				i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
+				for (isize i = 0; i < index_count; i++) {
+					indices[i] = 0;
+				}
+				ssaValue *sv = ssa_emit(proc, ssa_make_instr_vector_shuffle(proc, result, indices, index_count));
+				ssa_emit_store(proc, v, sv);
+				return ssa_make_addr(v, expr);
+			}
+			ssa_emit_store(proc, v, result);
+		} break;
+
+		case Type_Record: {
+			GB_ASSERT(is_type_struct(bt));
+			auto *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) {
+					AstNode *elem = cl->elems[field_index];
+
+					ssaValue *field_expr = NULL;
+					Entity *field = NULL;
+					isize index = field_index;
+
+					if (elem->kind == AstNode_FieldValue) {
+						ast_node(fv, FieldValue, elem);
+						Selection sel = lookup_field(proc->module->allocator, bt, fv->field->Ident.string, false);
+						index = sel.index[0];
+						elem = fv->value;
+					} else {
+						TypeAndValue *tav = type_and_value_of_expression(proc->module->info, elem);
+						Selection sel = lookup_field(proc->module->allocator, bt, st->fields_in_src_order[field_index]->token.string, false);
+						index = sel.index[0];
+					}
+
+					field = st->fields[index];
+					if (is_elem_const(proc->module, elem, field->type)) {
+						continue;
+					}
+
+					field_expr = ssa_build_expr(proc, elem);
+
+					GB_ASSERT(ssa_type(field_expr)->kind != Type_Tuple);
+
+					Type *ft = field->type;
+					ssaValue *fv = ssa_emit_conv(proc, field_expr, ft);
+					ssaValue *gep = ssa_emit_struct_ep(proc, v, index);
+					ssa_emit_store(proc, gep, fv);
+				}
+			}
+		} break;
+		case Type_Array: {
+			if (cl->elems.count > 0) {
+				ssa_emit_store(proc, v, ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
+				for_array(i, cl->elems) {
+					AstNode *elem = cl->elems[i];
+					if (is_elem_const(proc->module, elem, et)) {
+						continue;
+					}
+					ssaValue *field_expr = ssa_build_expr(proc, elem);
+					Type *t = ssa_type(field_expr);
+					GB_ASSERT(t->kind != Type_Tuple);
+					ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
+					ssaValue *gep = ssa_emit_array_ep(proc, v, i);
+					ssa_emit_store(proc, gep, ev);
+				}
+			}
+		} break;
+		case Type_Slice: {
+			if (cl->elems.count > 0) {
+				Type *elem_type = bt->Slice.elem;
+				Type *elem_ptr_type = make_type_pointer(proc->module->allocator, elem_type);
+				Type *elem_ptr_ptr_type = make_type_pointer(proc->module->allocator, elem_ptr_type);
+				Type *t_int_ptr = make_type_pointer(proc->module->allocator, t_int);
+				ssaValue *slice = ssa_add_module_constant(proc->module, type, make_exact_value_compound(expr));
+				GB_ASSERT(slice->kind == ssaValue_ConstantSlice);
+
+				ssaValue *data = ssa_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32);
+
+				for_array(i, cl->elems) {
+					AstNode *elem = cl->elems[i];
+					if (is_elem_const(proc->module, elem, et)) {
+						continue;
+					}
+
+					ssaValue *field_expr = ssa_build_expr(proc, elem);
+					Type *t = ssa_type(field_expr);
+					GB_ASSERT(t->kind != Type_Tuple);
+					ssaValue *ev = ssa_emit_conv(proc, field_expr, elem_type);
+					ssaValue *offset = ssa_emit_ptr_offset(proc, data, ssa_make_const_int(proc->module->allocator, i));
+					ssa_emit_store(proc, offset, ev);
+				}
+
+				ssaValue *gep0 = ssa_emit_struct_ep(proc, v, 0);
+				ssaValue *gep1 = ssa_emit_struct_ep(proc, v, 1);
+				ssaValue *gep2 = ssa_emit_struct_ep(proc, v, 1);
+
+				ssa_emit_store(proc, gep0, data);
+				ssa_emit_store(proc, gep1, ssa_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
+				ssa_emit_store(proc, gep2, ssa_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
+			}
+		} break;
+		}
+
+		return ssa_make_addr(v, expr);
+	case_end;
+
+
 	}
 
 	TokenPos token_pos = ast_node_token(expr).pos;
@@ -3777,6 +3786,9 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 			for_array(i, inits) {
+				if (lvals[i].addr == NULL) {
+					continue;
+				}
 				ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_addr_type(lvals[i]));
 				ssa_addr_store(proc, lvals[i], v);
 			}