diff --git a/build.bat b/build.bat index ed4442851..4b5c1cacf 100644 --- a/build.bat +++ b/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 diff --git a/core/opengl.odin b/core/opengl.odin index 59f0b6480..6f30286a1 100644 --- a/core/opengl.odin +++ b/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" + + + + diff --git a/core/os.odin b/core/os.odin index 4a98491c7..92ff61a8c 100644 --- a/core/os.odin +++ b/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 } diff --git a/core/win32.odin b/core/win32.odin index 893da6a2b..724bc6a73 100644 --- a/core/win32.odin +++ b/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 diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 355b8cac7..a2eb0c2b1 100644 --- a/src/checker/checker.cpp +++ b/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; diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index 3a0bee3df..44c32bece 100644 --- a/src/checker/entity.cpp +++ b/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; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 50367e027..c42040ad5 100644 --- a/src/checker/expr.cpp +++ b/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) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 54ae39ba3..8f651184e 100644 --- a/src/checker/stmt.cpp +++ b/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); } diff --git a/src/checker/types.cpp b/src/checker/types.cpp index 071cd0fa3..ba1ace5ff 100644 --- a/src/checker/types.cpp +++ b/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 diff --git a/src/main.cpp b/src/main.cpp index 0c6ab2c25..55b115a64 100644 --- a/src/main.cpp +++ b/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); diff --git a/src/parser.cpp b/src/parser.cpp index 4c390932b..d794f86eb 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -56,7 +56,7 @@ struct Parser { Array files; Array imports; gbAtomic32 import_index; - Array system_libraries; + Array 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); } } } diff --git a/src/ssa.cpp b/src/ssa.cpp index 6d0969e46..060be979c 100644 --- a/src/ssa.cpp +++ b/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); }