diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 8f27ca674..7ad3ef1d6 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -177,6 +177,10 @@ Type_Info_Matrix :: struct { row_count: int, column_count: int, // Total element count = column_count * elem_stride + layout: enum u8 { + Column_Major, // array of column vectors + Row_Major, // array of row vectors + }, } Type_Info_Soa_Pointer :: struct { elem: ^Type_Info, diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 02803f882..6f9801bc8 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2396,7 +2396,11 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - offset := (row + col*info.elem_stride)*info.elem_size + offset: int + switch info.layout { + case .Column_Major: offset = (row + col*info.elem_stride)*info.elem_size + case .Row_Major: offset = (col + row*info.elem_stride)*info.elem_size + } data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) @@ -2410,7 +2414,11 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - offset := (row + col*info.elem_stride)*info.elem_size + offset: int + switch info.layout { + case .Column_Major: offset = (row + col*info.elem_stride)*info.elem_size + case .Row_Major: offset = (col + row*info.elem_stride)*info.elem_size + } data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index fc7a2c792..ab723e145 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2947,6 +2947,7 @@ parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit { } p.expr_level -= 1 + skip_possible_newline(p) close := expect_token_after(p, .Close_Brace, "compound literal") pos := type.pos if type != nil else open.pos diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 2b96dd4fb..9cff46a00 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -173,6 +173,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Matrix) or_return if x.row_count != y.row_count { return false } if x.column_count != y.column_count { return false } + if x.layout != y.layout { return false } return are_types_identical(x.elem, y.elem) case Type_Info_Bit_Field: @@ -689,6 +690,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - write_type(w, info.pointer, &n) or_return case Type_Info_Matrix: + if info.layout == .Row_Major { + io.write_string(w, "#row_major ", &n) or_return + } io.write_string(w, "matrix[", &n) or_return io.write_i64(w, i64(info.row_count), 10, &n) or_return io.write_string(w, ", ", &n) or_return diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index 4316b2ade..e8006d175 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -517,9 +517,14 @@ macos_release_map: map[string]Darwin_To_Release = { "23A344" = {{23, 0, 0}, "macOS", {"Sonoma", {14, 0, 0}}}, "23B74" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 0}}}, "23B81" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}}, + "23B2082" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}}, "23B92" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}}, + "23B2091" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}}, "23C64" = {{23, 2, 0}, "macOS", {"Sonoma", {14, 2, 0}}}, "23C71" = {{23, 2, 0}, "macOS", {"Sonoma", {14, 2, 1}}}, + "23D56" = {{23, 3, 0}, "macOS", {"Sonoma", {14, 3, 0}}}, + "23D60" = {{23, 3, 0}, "macOS", {"Sonoma", {14, 3, 1}}}, + "23E214" = {{23, 4, 0}, "macOS", {"Sonoma", {14, 4, 0}}}, } @(private) diff --git a/src/bug_report.cpp b/src/bug_report.cpp index b58d14bbf..7b4999943 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -880,9 +880,14 @@ gb_internal void report_os_info() { {"23A344", {23, 0, 0}, "macOS", {"Sonoma", {14, 0, 0}}}, {"23B74", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 0}}}, {"23B81", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}}, + {"23B2082", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}}, {"23B92", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}}, + {"23B2091", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}}, {"23C64", {23, 2, 0}, "macOS", {"Sonoma", {14, 2, 0}}}, {"23C71", {23, 2, 0}, "macOS", {"Sonoma", {14, 2, 1}}}, + {"23D56", {23, 3, 0}, "macOS", {"Sonoma", {14, 3, 0}}}, + {"23D60", {23, 3, 0}, "macOS", {"Sonoma", {14, 3, 1}}}, + {"23E214", {23, 4, 0}, "macOS", {"Sonoma", {14, 4, 0}}}, }; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 58b5c9170..3c822e295 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1191,13 +1191,24 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) { char *p; mutex_lock(&fullpath_mutex); p = realpath(cast(char *)s.text, 0); + defer (free(p)); mutex_unlock(&fullpath_mutex); if(p == nullptr) { if (ok_) *ok_ = false; - return String{}; + + // Path doesn't exist or is malformed, Windows's `GetFullPathNameW` does not check for + // existence of the file where `realpath` does, which causes different behaviour between platforms. + // Two things could be done here: + // 1. clean the path and resolve it manually, just like the Windows function does, + // probably requires porting `filepath.clean` from Odin and doing some more processing. + // 2. just return a copy of the original path. + // + // I have opted for 2 because it is much simpler + we already return `ok = false` + further + // checks and processes will use the path and cause errors (which we want). + return copy_string(a, s); } if (ok_) *ok_ = true; - return make_string_c(p); + return copy_string(a, make_string_c(p)); } #else #error Implement system @@ -1947,6 +1958,18 @@ gb_internal bool init_build_paths(String init_filename) { } } + if (build_context.no_crt && !build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR && !build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { + switch (build_context.metrics.os) { + case TargetOs_linux: + case TargetOs_darwin: + case TargetOs_essence: + case TargetOs_freebsd: + case TargetOs_openbsd: + case TargetOs_haiku: + gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present because the default allocator requires crt\n"); + return false; + } + } if (bc->target_features_string.len != 0) { enable_target_feature({}, bc->target_features_string); diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 6de3b27f2..d3158961e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3488,7 +3488,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } else { GB_ASSERT(t->kind == Type_Matrix); - operand->type = alloc_type_matrix(t->Matrix.elem, t->Matrix.column_count, t->Matrix.row_count); + operand->type = alloc_type_matrix(t->Matrix.elem, t->Matrix.column_count, t->Matrix.row_count, nullptr, nullptr, t->Matrix.is_row_major); } operand->type = check_matrix_type_hint(operand->type, type_hint); break; @@ -3556,7 +3556,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } operand->mode = Addressing_Value; - operand->type = alloc_type_matrix(elem, xt->Array.count, yt->Array.count); + operand->type = alloc_type_matrix(elem, xt->Array.count, yt->Array.count, nullptr, nullptr, false); operand->type = check_matrix_type_hint(operand->type, type_hint); break; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f359d5a54..e9a6f5122 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3397,6 +3397,13 @@ gb_internal Type *check_matrix_type_hint(Type *matrix, Type *type_hint) { Type *th = base_type(type_hint); if (are_types_identical(th, xt)) { return type_hint; + } else if (xt->kind == Type_Matrix && th->kind == Type_Matrix) { + if (!are_types_identical(xt->Matrix.elem, th->Matrix.elem)) { + // ignore + } if (xt->Matrix.row_count == th->Matrix.row_count && + xt->Matrix.column_count == th->Matrix.column_count) { + return type_hint; + } } else if (xt->kind == Type_Matrix && th->kind == Type_Array) { if (!are_types_identical(xt->Matrix.elem, th->Array.elem)) { // ignore @@ -3431,6 +3438,11 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand if (xt->Matrix.column_count != yt->Matrix.row_count) { goto matrix_error; } + + if (xt->Matrix.is_row_major != yt->Matrix.is_row_major) { + goto matrix_error; + } + x->mode = Addressing_Value; if (are_types_identical(xt, yt)) { if (!is_type_named(x->type) && is_type_named(y->type)) { @@ -3438,7 +3450,8 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand x->type = y->type; } } else { - x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count); + bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; + x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); } goto matrix_success; } else if (yt->kind == Type_Array) { @@ -3452,10 +3465,10 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // Treat arrays as column vectors x->mode = Addressing_Value; - if (type_hint == nullptr && xt->Matrix.row_count == yt->Array.count) { + if (xt->Matrix.row_count == yt->Array.count) { x->type = y->type; } else { - x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, 1); + x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, 1, nullptr, nullptr, xt->Matrix.is_row_major); } goto matrix_success; } @@ -3483,10 +3496,10 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // Treat arrays as row vectors x->mode = Addressing_Value; - if (type_hint == nullptr && yt->Matrix.column_count == xt->Array.count) { + if (yt->Matrix.column_count == xt->Array.count) { x->type = x->type; } else { - x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count); + x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count, nullptr, nullptr, yt->Matrix.is_row_major); } goto matrix_success; } else if (are_types_identical(yt->Matrix.elem, xt)) { diff --git a/src/check_type.cpp b/src/check_type.cpp index d5cf187a4..3fe633892 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2658,7 +2658,7 @@ gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) } type_assign:; - *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column); + *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column, mt->is_row_major); return; } diff --git a/src/error.cpp b/src/error.cpp index 8d550e969..b96719420 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -670,6 +670,7 @@ gb_internal void print_all_errors(void) { escape_char(f, file.text[k]); } gb_fprintf(f, "\",\n"); + gb_fprintf(f, "\t\t\t\t\"offset\": %d,\n", ev.pos.offset); gb_fprintf(f, "\t\t\t\t\"line\": %d,\n", ev.pos.line); gb_fprintf(f, "\t\t\t\t\"column\": %d,\n", ev.pos.column); i32 end_column = gb_max(ev.end.column, ev.pos.column); diff --git a/src/linker.cpp b/src/linker.cpp index 0cdeaf8d9..9d7f16f1d 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -376,6 +376,10 @@ gb_internal i32 linker_stage(LinkerData *gen) { LIT(obj_file), LIT(build_context.extra_assembler_flags) ); + if (!result) { + gb_printf_err("executing `nasm` to assemble foreing import of %.*s failed.\n\tSuggestion: `nasm` does not ship with the compiler and should be installed with your system's package manager.\n", LIT(asm_file)); + return result; + } } array_add(&gen->output_object_paths, obj_file); } else { @@ -383,9 +387,13 @@ gb_internal i32 linker_stage(LinkerData *gen) { continue; } - // NOTE(zangent): Sometimes, you have to use -framework on MacOS. - // This allows you to specify '-f' in a #foreign_system_library, - // without having to implement any new syntax specifically for MacOS. + // Do not add libc again, this is added later already, and omitted with + // the `-no-crt` flag, not skipping here would cause duplicate library + // warnings when linking on darwin and might link libc silently even with `-no-crt`. + if (lib == str_lit("System.framework") || lib == str_lit("c")) { + continue; + } + if (build_context.metrics.os == TargetOs_darwin) { if (string_ends_with(lib, str_lit(".framework"))) { // framework thingie diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 857b255f3..24e86fa64 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1145,14 +1145,9 @@ namespace lbAbiArm64 { i64 size = lb_sizeof(return_type); if (size <= 16) { LLVMTypeRef cast_type = nullptr; - if (size <= 1) { - cast_type = LLVMInt8TypeInContext(c); - } else if (size <= 2) { - cast_type = LLVMInt16TypeInContext(c); - } else if (size <= 4) { - cast_type = LLVMInt32TypeInContext(c); - } else if (size <= 8) { - cast_type = LLVMInt64TypeInContext(c); + + if (size <= 8) { + cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8)); } else { unsigned count = cast(unsigned)((size+7)/8); cast_type = llvm_array_type(LLVMInt64TypeInContext(c), count); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 2291f24ac..bbb0b8387 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1302,11 +1302,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT_MSG(elem_count == max_count, "%td != %td", elem_count, max_count); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)total_count); - for_array(i, cl->elems) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - i64 offset = matrix_row_major_index_to_offset(type, i); + i64 offset = 0; + offset = matrix_row_major_index_to_offset(type, i); values[offset] = lb_const_value(m, elem_type, tav.value, allow_local).value; } for (isize i = 0; i < total_count; i++) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 98618798b..12949f0ab 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -684,12 +684,6 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - // TODO(bill): Determine why this fails on Windows sometimes - if (false && lb_is_matrix_simdable(mt)) { - LLVMValueRef vector = lb_matrix_to_trimmed_vector(p, m); - return lb_matrix_cast_vector_to_type(p, vector, type); - } - lbAddr res = lb_add_local_generated(p, type, true); i64 row_count = mt->Matrix.row_count; @@ -763,6 +757,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, GB_ASSERT(is_type_matrix(yt)); GB_ASSERT(xt->Matrix.column_count == yt->Matrix.row_count); GB_ASSERT(are_types_identical(xt->Matrix.elem, yt->Matrix.elem)); + GB_ASSERT(xt->Matrix.is_row_major == yt->Matrix.is_row_major); Type *elem = xt->Matrix.elem; @@ -770,7 +765,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, unsigned inner = cast(unsigned)xt->Matrix.column_count; unsigned outer_columns = cast(unsigned)yt->Matrix.column_count; - if (lb_is_matrix_simdable(xt)) { + if (!xt->Matrix.is_row_major && lb_is_matrix_simdable(xt)) { unsigned x_stride = cast(unsigned)matrix_type_stride_in_elems(xt); unsigned y_stride = cast(unsigned)matrix_type_stride_in_elems(yt); @@ -812,7 +807,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, return lb_addr_load(p, res); } - { + if (!xt->Matrix.is_row_major) { lbAddr res = lb_add_local_generated(p, type, true); auto inners = slice_make(permanent_allocator(), inner); @@ -835,6 +830,30 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, } } + return lb_addr_load(p, res); + } else { + lbAddr res = lb_add_local_generated(p, type, true); + + auto inners = slice_make(permanent_allocator(), inner); + + for (unsigned i = 0; i < outer_rows; i++) { + for (unsigned j = 0; j < outer_columns; j++) { + lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j); + for (unsigned k = 0; k < inner; k++) { + inners[k][0] = lb_emit_matrix_ev(p, lhs, i, k); + inners[k][1] = lb_emit_matrix_ev(p, rhs, k, j); + } + + lbValue sum = lb_const_nil(p->module, elem); + for (unsigned k = 0; k < inner; k++) { + lbValue a = inners[k][0]; + lbValue b = inners[k][1]; + sum = lb_emit_mul_add(p, a, b, sum, elem); + } + lb_emit_store(p, dst, sum); + } + } + return lb_addr_load(p, res); } } @@ -855,7 +874,7 @@ gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbVal Type *elem = mt->Matrix.elem; - if (lb_is_matrix_simdable(mt)) { + if (!mt->Matrix.is_row_major && lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; @@ -924,7 +943,7 @@ gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbVal Type *elem = mt->Matrix.elem; - if (lb_is_matrix_simdable(mt)) { + if (!mt->Matrix.is_row_major && lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; @@ -3971,12 +3990,21 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { } lbValue index = lb_build_expr(p, ie->index); index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); + + isize bounds_len = 0; + lbValue elem = {}; + if (t->Matrix.is_row_major) { + bounds_len = t->Matrix.row_count; + elem = lb_emit_matrix_ep(p, matrix, index, lb_const_int(p->module, t_int, 0)); + } else { + bounds_len = t->Matrix.column_count; + elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); + } elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); auto index_tv = type_and_value_of_expr(ie->index); if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); + lbValue len = lb_const_int(p->module, t_int, bounds_len); lb_emit_bounds_check(p, ast_token(ie->index), index, len); } return lb_addr(elem); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index aec1fb201..de83f5058 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -979,12 +979,13 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ tag_type = t_type_info_matrix; i64 ez = type_size_of(t->Matrix.elem); - LLVMValueRef vals[5] = { + LLVMValueRef vals[6] = { get_type_info_ptr(m, t->Matrix.elem), lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value, lb_const_int(m, t_int, t->Matrix.row_count).value, lb_const_int(m, t_int, t->Matrix.column_count).value, + lb_const_int(m, t_u8, cast(u8)t->Matrix.is_row_major).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index f18aa5521..fb61c41c3 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1464,14 +1464,16 @@ gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isi Type *t = s.type; GB_ASSERT(is_type_pointer(t)); Type *mt = base_type(type_deref(t)); - if (column == 0) { - GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); - return lb_emit_epi(p, s, row); - } else if (row == 0 && is_type_array_like(mt)) { - return lb_emit_epi(p, s, column); + + if (!mt->Matrix.is_row_major) { + if (column == 0) { + GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); + return lb_emit_epi(p, s, row); + } else if (row == 0 && is_type_array_like(mt)) { + return lb_emit_epi(p, s, column); + } } - GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); isize offset = matrix_indices_to_offset(mt, row, column); @@ -1491,7 +1493,13 @@ gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lb row = lb_emit_conv(p, row, t_int); column = lb_emit_conv(p, column, t_int); - LLVMValueRef index = LLVMBuildAdd(p->builder, row.value, LLVMBuildMul(p->builder, column.value, stride_elems, ""), ""); + LLVMValueRef index = nullptr; + + if (mt->Matrix.is_row_major) { + index = LLVMBuildAdd(p->builder, column.value, LLVMBuildMul(p->builder, row.value, stride_elems, ""), ""); + } else { + index = LLVMBuildAdd(p->builder, row.value, LLVMBuildMul(p->builder, column.value, stride_elems, ""), ""); + } LLVMValueRef indices[2] = { LLVMConstInt(lb_type(p->module, t_int), 0, false), diff --git a/src/parser.cpp b/src/parser.cpp index 1aa40ccbf..eb9e73342 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2329,6 +2329,19 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { break; } return original_type; + } else if (name.string == "row_major" || + name.string == "column_major") { + Ast *original_type = parse_type(f); + Ast *type = unparen_expr(original_type); + switch (type->kind) { + case Ast_MatrixType: + type->MatrixType.is_row_major = (name.string == "row_major"); + break; + default: + syntax_error(type, "Expected a matrix type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); + break; + } + return original_type; } else if (name.string == "partial") { Ast *tag = ast_basic_directive(f, token, name); Ast *original_expr = parse_expr(f, lhs); diff --git a/src/parser.hpp b/src/parser.hpp index f5997c4bd..ff3c5eb34 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -772,6 +772,7 @@ AST_KIND(_TypeBegin, "", bool) \ Ast *row_count; \ Ast *column_count; \ Ast *elem; \ + bool is_row_major; \ }) \ AST_KIND(_TypeEnd, "", bool) diff --git a/src/types.cpp b/src/types.cpp index 5a3ad5d6b..c2358056b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -281,6 +281,7 @@ struct TypeProc { Type *generic_row_count; \ Type *generic_column_count; \ i64 stride_in_bytes; \ + bool is_row_major; \ }) \ TYPE_KIND(BitField, struct { \ Scope * scope; \ @@ -1002,7 +1003,7 @@ gb_internal Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = return t; } -gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, Type *generic_row_count = nullptr, Type *generic_column_count = nullptr) { +gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, Type *generic_row_count, Type *generic_column_count, bool is_row_major) { if (generic_row_count != nullptr || generic_column_count != nullptr) { Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; @@ -1010,12 +1011,14 @@ gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, t->Matrix.column_count = column_count; t->Matrix.generic_row_count = generic_row_count; t->Matrix.generic_column_count = generic_column_count; + t->Matrix.is_row_major = is_row_major; return t; } Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; t->Matrix.row_count = row_count; t->Matrix.column_count = column_count; + t->Matrix.is_row_major = is_row_major; return t; } @@ -1512,14 +1515,18 @@ gb_internal i64 matrix_indices_to_offset(Type *t, i64 row_index, i64 column_inde GB_ASSERT(0 <= row_index && row_index < t->Matrix.row_count); GB_ASSERT(0 <= column_index && column_index < t->Matrix.column_count); i64 stride_elems = matrix_type_stride_in_elems(t); - // NOTE(bill): Column-major layout internally - return row_index + stride_elems*column_index; + if (t->Matrix.is_row_major) { + return column_index + stride_elems*row_index; + } else { + // NOTE(bill): Column-major layout internally + return row_index + stride_elems*column_index; + } } gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + i64 row_index = index/t->Matrix.column_count; i64 column_index = index%t->Matrix.column_count; return matrix_indices_to_offset(t, row_index, column_index); @@ -2690,6 +2697,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Matrix: return x->Matrix.row_count == y->Matrix.row_count && x->Matrix.column_count == y->Matrix.column_count && + x->Matrix.is_row_major == y->Matrix.is_row_major && are_types_identical(x->Matrix.elem, y->Matrix.elem); case Type_DynamicArray: @@ -4735,6 +4743,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha break; case Type_Matrix: + if (type->Matrix.is_row_major) { + str = gb_string_appendc(str, "#row_major "); + } str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); str = write_type_to_string(str, type->Matrix.elem); break; diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 51b43c565..07e07730b 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -213,17 +213,17 @@ MAGENTA :: Color{ 255, 0, 255, 255 } // Magenta RAYWHITE :: Color{ 245, 245, 245, 255 } // My own White (raylib logo) // Vector2 type -Vector2 :: linalg.Vector2f32 +Vector2 :: [2]f32 // Vector3 type -Vector3 :: linalg.Vector3f32 +Vector3 :: [3]f32 // Vector4 type -Vector4 :: linalg.Vector4f32 +Vector4 :: [4]f32 // Quaternion type -Quaternion :: linalg.Quaternionf32 +Quaternion :: quaternion128 -// Matrix type (OpenGL style 4x4 - right handed, stored column major) -Matrix :: linalg.Matrix4x4f32 +// Matrix type (right handed, stored row major) +Matrix :: #row_major matrix[4, 4]f32 // Color, 4 components, R8G8B8A8 (32bit) diff --git a/vendor/raylib/raymath.odin b/vendor/raylib/raymath.odin index c657152c1..beeda7989 100644 --- a/vendor/raylib/raymath.odin +++ b/vendor/raylib/raymath.odin @@ -590,74 +590,79 @@ MatrixMultiply :: proc "c" (left, right: Matrix) -> Matrix { // Get translation matrix @(require_results) MatrixTranslate :: proc "c" (x, y, z: f32) -> Matrix { - return linalg.matrix4_translate(Vector3{x, y, z}) + return { + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1, + } } // Create rotation matrix from axis and angle // NOTE: Angle should be provided in radians @(require_results) MatrixRotate :: proc "c" (axis: Vector3, angle: f32) -> Matrix { - return linalg.matrix4_rotate(angle, axis) + return auto_cast linalg.matrix4_rotate(angle, axis) } // Get x-rotation matrix // NOTE: Angle must be provided in radians @(require_results) MatrixRotateX :: proc "c" (angle: f32) -> Matrix { - return linalg.matrix4_rotate(angle, Vector3{1, 0, 0}) + return auto_cast linalg.matrix4_rotate(angle, Vector3{1, 0, 0}) } // Get y-rotation matrix // NOTE: Angle must be provided in radians @(require_results) MatrixRotateY :: proc "c" (angle: f32) -> Matrix { - return linalg.matrix4_rotate(angle, Vector3{0, 1, 0}) + return auto_cast linalg.matrix4_rotate(angle, Vector3{0, 1, 0}) } // Get z-rotation matrix // NOTE: Angle must be provided in radians @(require_results) MatrixRotateZ :: proc "c" (angle: f32) -> Matrix { - return linalg.matrix4_rotate(angle, Vector3{0, 0, 1}) + return auto_cast linalg.matrix4_rotate(angle, Vector3{0, 0, 1}) } // Get xyz-rotation matrix // NOTE: Angle must be provided in radians @(require_results) MatrixRotateXYZ :: proc "c" (angle: Vector3) -> Matrix { - return linalg.matrix4_from_euler_angles_xyz(angle.x, angle.y, angle.z) + return auto_cast linalg.matrix4_from_euler_angles_xyz(angle.x, angle.y, angle.z) } // Get zyx-rotation matrix // NOTE: Angle must be provided in radians @(require_results) MatrixRotateZYX :: proc "c" (angle: Vector3) -> Matrix { - return linalg.matrix4_from_euler_angles_zyx(angle.x, angle.y, angle.z) + return auto_cast linalg.matrix4_from_euler_angles_zyx(angle.x, angle.y, angle.z) } // Get scaling matrix @(require_results) MatrixScale :: proc "c" (x, y, z: f32) -> Matrix { - return linalg.matrix4_scale(Vector3{x, y, z}) + return auto_cast linalg.matrix4_scale(Vector3{x, y, z}) } // Get orthographic projection matrix @(require_results) MatrixOrtho :: proc "c" (left, right, bottom, top, near, far: f32) -> Matrix { - return linalg.matrix_ortho3d(left, right, bottom, top, near, far) + return auto_cast linalg.matrix_ortho3d(left, right, bottom, top, near, far) } // Get perspective projection matrix // NOTE: Fovy angle must be provided in radians @(require_results) MatrixPerspective :: proc "c" (fovY, aspect, nearPlane, farPlane: f32) -> Matrix { - return linalg.matrix4_perspective(fovY, aspect, nearPlane, farPlane) + return auto_cast linalg.matrix4_perspective(fovY, aspect, nearPlane, farPlane) } // Get camera look-at matrix (view matrix) @(require_results) MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix { - return linalg.matrix4_look_at(eye, target, up) + return auto_cast linalg.matrix4_look_at(eye, target, up) } // Get float array of matrix data @@ -755,12 +760,12 @@ QuaternionFromVector3ToVector3 :: proc "c" (from, to: Vector3) -> Quaternion { // Get a quaternion for a given rotation matrix @(require_results) QuaternionFromMatrix :: proc "c" (mat: Matrix) -> Quaternion { - return linalg.quaternion_from_matrix4(mat) + return linalg.quaternion_from_matrix4(linalg.Matrix4f32(mat)) } // Get a matrix for a given quaternion @(require_results) QuaternionToMatrix :: proc "c" (q: Quaternion) -> Matrix { - return linalg.matrix4_from_quaternion(q) + return auto_cast linalg.matrix4_from_quaternion(q) } // Get rotation quaternion for an angle and axis NOTE: Angle must be provided in radians @(require_results)