diff --git a/core/debug/trace/trace_nil.odin b/core/debug/trace/trace_nil.odin index 8611d7726..ca8bd7817 100644 --- a/core/debug/trace/trace_nil.odin +++ b/core/debug/trace/trace_nil.odin @@ -1,4 +1,6 @@ -//+build !windows !linux !darwin +//+build !windows +//+build !linux +//+build !darwin package debug_trace import "base:runtime" diff --git a/core/flags/errors_nonbsd.odin b/core/flags/errors_nonbsd.odin index a77f12abf..e129aff74 100644 --- a/core/flags/errors_nonbsd.odin +++ b/core/flags/errors_nonbsd.odin @@ -1,4 +1,5 @@ -//+build !netbsd !openbsd +//+build !netbsd +//+build !openbsd package flags import "base:runtime" diff --git a/core/flags/internal_rtti_nonbsd.odin b/core/flags/internal_rtti_nonbsd.odin index 27fdb3b75..0044898d5 100644 --- a/core/flags/internal_rtti_nonbsd.odin +++ b/core/flags/internal_rtti_nonbsd.odin @@ -1,5 +1,6 @@ //+private -//+build !netbsd !openbsd +//+build !netbsd +//+build !openbsd package flags import "core:net" diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index dce9f834a..b1155c22f 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -7,11 +7,11 @@ Parses a boolean value from the input string **Inputs** - s: The input string - - true: "1", "t", "T", "true", "TRUE", "True" - - false: "0", "f", "F", "false", "FALSE", "False" + - true: "1", "t", "T", "true", "TRUE", "True" + - false: "0", "f", "F", "false", "FALSE", "False" - n: An optional pointer to an int to store the length of the parsed substring (default: nil) -**Returns** +**Returns** - result: The parsed boolean value (default: false) - ok: A boolean indicating whether the parsing was successful */ @@ -29,7 +29,7 @@ parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) /* Finds the integer value of the given rune -**Inputs** +**Inputs** - r: The input rune to find the integer value of **Returns** The integer value of the given rune @@ -47,7 +47,7 @@ _digit_value :: proc(r: rune) -> int { /* Parses an integer value from the input string in the given base, without a prefix -**Inputs** +**Inputs** - str: The input string to parse the integer value from - base: The base of the integer value to be parsed (must be between 1 and 16) - n: An optional pointer to an int to store the length of the parsed substring (default: nil) @@ -65,7 +65,7 @@ Output: -1234 false -**Returns** +**Returns** - value: Parses an integer value from a string, in the given base, without a prefix. - ok: ok=false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number. */ @@ -117,12 +117,12 @@ parse_i64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i64, /* Parses an integer value from the input string in base 10, unless there's a prefix -**Inputs** +**Inputs** - str: The input string to parse the integer value from - n: An optional pointer to an int to store the length of the parsed substring (default: nil) Example: - + import "core:fmt" import "core:strconv" parse_i64_maybe_prefixed_example :: proc() { @@ -132,13 +132,13 @@ Example: n, ok = strconv.parse_i64_maybe_prefixed("0xeeee") fmt.println(n,ok) } - + Output: 1234 true 61166 true -**Returns** +**Returns** - value: The parsed integer value - ok: ok=false if a valid integer could not be found, or if the input string contained more than just the number. */ @@ -200,14 +200,14 @@ parse_i64 :: proc{parse_i64_maybe_prefixed, parse_i64_of_base} /* Parses an unsigned 64-bit integer value from the input string without a prefix, using the specified base -**Inputs** +**Inputs** - str: The input string to parse - base: The base of the number system to use for parsing - - Must be between 1 and 16 (inclusive) + - Must be between 1 and 16 (inclusive) - n: An optional pointer to an int to store the length of the parsed substring (default: nil) Example: - + import "core:fmt" import "core:strconv" parse_u64_of_base_example :: proc() { @@ -217,13 +217,13 @@ Example: n, ok = strconv.parse_u64_of_base("5678eee",16) fmt.println(n,ok) } - + Output: 1234 false 90672878 true -**Returns** +**Returns** - value: The parsed uint64 value - ok: A boolean indicating whether the parsing was successful */ @@ -261,15 +261,15 @@ parse_u64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u64, /* Parses an unsigned 64-bit integer value from the input string, using the specified base or inferring the base from a prefix -**Inputs** +**Inputs** - str: The input string to parse - base: The base of the number system to use for parsing (default: 0) - - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal) - - If base is not 0, it will be used for parsing regardless of any prefix in the input string + - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal) + - If base is not 0, it will be used for parsing regardless of any prefix in the input string - n: An optional pointer to an int to store the length of the parsed substring (default: nil) Example: - + import "core:fmt" import "core:strconv" parse_u64_maybe_prefixed_example :: proc() { @@ -279,13 +279,13 @@ Example: n, ok = strconv.parse_u64_maybe_prefixed("0xee") fmt.println(n,ok) } - + Output: 1234 true 238 true -**Returns** +**Returns** - value: The parsed uint64 value - ok: ok=false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number. */ @@ -336,14 +336,14 @@ parse_u64 :: proc{parse_u64_maybe_prefixed, parse_u64_of_base} /* Parses a signed integer value from the input string, using the specified base or inferring the base from a prefix -**Inputs** +**Inputs** - s: The input string to parse - base: The base of the number system to use for parsing (default: 0) - - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal) - - If base is not 0, it will be used for parsing regardless of any prefix in the input string + - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal) + - If base is not 0, it will be used for parsing regardless of any prefix in the input string Example: - + import "core:fmt" import "core:strconv" parse_int_example :: proc() { @@ -356,14 +356,14 @@ Example: n, ok = strconv.parse_int("0xffff") // with prefix and inferred base fmt.println(n,ok) } - + Output: 1234 true 65535 true 65535 true -**Returns** +**Returns** - value: The parsed int value - ok: `false` if no appropriate value could be found, or if the input string contained more than just the number. */ @@ -379,11 +379,11 @@ parse_int :: proc(s: string, base := 0, n: ^int = nil) -> (value: int, ok: bool) /* Parses an unsigned integer value from the input string, using the specified base or inferring the base from a prefix -**Inputs** +**Inputs** - s: The input string to parse - base: The base of the number system to use for parsing (default: 0, inferred) - - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal) - - If base is not 0, it will be used for parsing regardless of any prefix in the input string + - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal) + - If base is not 0, it will be used for parsing regardless of any prefix in the input string Example: @@ -1729,7 +1729,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string { } } - if buf == nil { + if buf == nil || r < 0 { return "" } diff --git a/core/testing/signal_handler_other.odin b/core/testing/signal_handler_other.odin index 6f39205c7..d6d494fa4 100644 --- a/core/testing/signal_handler_other.odin +++ b/core/testing/signal_handler_other.odin @@ -1,5 +1,11 @@ //+private -//+build !windows !linux !darwin !freebsd !openbsd !netbsd !haiku +//+build !windows +//+build !linux +//+build !darwin +//+build !freebsd +//+build !openbsd +//+build !netbsd +//+build !haiku package testing /* diff --git a/src/build_settings.cpp b/src/build_settings.cpp index fe0e478c7..d8b63b947 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2048,10 +2048,11 @@ gb_internal bool init_build_paths(String init_filename) { gbFile output_file_test; const char* output_file_name = (const char*)output_file.text; gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name); - gb_file_close(&output_file_test); - gb_file_remove(output_file_name); - if (output_test_err != 0) { + if (output_test_err == 0) { + gb_file_close(&output_file_test); + gb_file_remove(output_file_name); + } else { String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); defer (gb_free(ha, output_file.text)); gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file)); diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 910e7ffdb..888aa074d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5203,6 +5203,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } + if (sz >= 64) { + if (is_type_unsigned(x.type)) { + add_package_dependency(c, "runtime", "umodti3", true); + add_package_dependency(c, "runtime", "udivti3", true); + } else { + add_package_dependency(c, "runtime", "modti3", true); + add_package_dependency(c, "runtime", "divti3", true); + } + } + operand->type = x.type; operand->mode = Addressing_Value; } diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 5d90dccea..68e1efc1c 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -82,13 +82,36 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) parameter_count += 1; } } - LLVMMetadataRef *parameters = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, parameter_count); - unsigned param_index = 0; - if (type->Proc.result_count == 0) { - parameters[param_index++] = nullptr; - } else { - parameters[param_index++] = lb_debug_procedure_parameters(m, type->Proc.results); + auto parameters = array_make(permanent_allocator(), 0, type->Proc.param_count+type->Proc.result_count+2); + + array_add(¶meters, cast(LLVMMetadataRef)nullptr); + + bool return_is_tuple = false; + if (type->Proc.result_count != 0) { + Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); + if (is_type_proc(single_ret)) { + single_ret = t_rawptr; + } + if (is_type_tuple(single_ret) && is_calling_convention_odin(type->Proc.calling_convention)) { + LLVMTypeRef actual = lb_type_internal_for_procedures_raw(m, type); + actual = LLVMGetReturnType(actual); + if (actual == nullptr) { + // results were passed as a single pointer + parameters[0] = lb_debug_procedure_parameters(m, single_ret); + } else { + LLVMTypeRef possible = lb_type(m, type->Proc.results); + if (possible == actual) { + // results were returned directly + parameters[0] = lb_debug_procedure_parameters(m, single_ret); + } else { + // resulsts were returned separately + return_is_tuple = true; + } + } + } else { + parameters[0] = lb_debug_procedure_parameters(m, single_ret); + } } LLVMMetadataRef file = nullptr; @@ -98,8 +121,22 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) if (e->kind != Entity_Variable) { continue; } - parameters[param_index] = lb_debug_procedure_parameters(m, e->type); - param_index += 1; + array_add(¶meters, lb_debug_procedure_parameters(m, e->type)); + } + + + if (return_is_tuple) { + Type *results = type->Proc.results; + GB_ASSERT(results != nullptr && results->kind == Type_Tuple); + isize count = results->Tuple.variables.count; + parameters[0] = lb_debug_procedure_parameters(m, results->Tuple.variables[count-1]->type); + for (isize i = 0; i < count-1; i++) { + array_add(¶meters, lb_debug_procedure_parameters(m, results->Tuple.variables[i]->type)); + } + } + + if (type->Proc.calling_convention == ProcCC_Odin) { + array_add(¶meters, lb_debug_type(m, t_context_ptr)); } LLVMDIFlags flags = LLVMDIFlagZero; @@ -107,7 +144,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) flags = LLVMDIFlagNoReturn; } - return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags); + return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters.data, cast(unsigned)parameters.count, flags); } gb_internal LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f6b9934ef..f20c52e88 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -705,31 +705,37 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type lbAddr res = lb_add_local_generated(p, type, true); - i64 row_count = mt->Matrix.row_count; - i64 column_count = mt->Matrix.column_count; - TEMPORARY_ALLOCATOR_GUARD(); + GB_ASSERT(type_size_of(type) == type_size_of(m.type)); - auto srcs = array_make(temporary_allocator(), 0, row_count*column_count); - auto dsts = array_make(temporary_allocator(), 0, row_count*column_count); + lbValue m_ptr = lb_address_from_load_or_generate_local(p, m); + lbValue n = lb_const_int(p->module, t_int, type_size_of(type)); + lb_mem_copy_non_overlapping(p, res.addr, m_ptr, n); - for (i64 j = 0; j < column_count; j++) { - for (i64 i = 0; i < row_count; i++) { - lbValue src = lb_emit_matrix_ev(p, m, i, j); - array_add(&srcs, src); - } - } + // i64 row_count = mt->Matrix.row_count; + // i64 column_count = mt->Matrix.column_count; + // TEMPORARY_ALLOCATOR_GUARD(); - for (i64 j = 0; j < column_count; j++) { - for (i64 i = 0; i < row_count; i++) { - lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count); - array_add(&dsts, dst); - } - } + // auto srcs = array_make(temporary_allocator(), 0, row_count*column_count); + // auto dsts = array_make(temporary_allocator(), 0, row_count*column_count); - GB_ASSERT(srcs.count == dsts.count); - for_array(i, srcs) { - lb_emit_store(p, dsts[i], srcs[i]); - } + // for (i64 j = 0; j < column_count; j++) { + // for (i64 i = 0; i < row_count; i++) { + // lbValue src = lb_emit_matrix_ev(p, m, i, j); + // array_add(&srcs, src); + // } + // } + + // for (i64 j = 0; j < column_count; j++) { + // for (i64 i = 0; i < row_count; i++) { + // lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count); + // array_add(&dsts, dst); + // } + // } + + // GB_ASSERT(srcs.count == dsts.count); + // for_array(i, srcs) { + // lb_emit_store(p, dsts[i], srcs[i]); + // } return lb_addr_load(p, res); } diff --git a/src/types.cpp b/src/types.cpp index 63182f5c4..a9a7d6dda 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1474,6 +1474,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { Type *elem = t->Matrix.elem; i64 row_count = gb_max(t->Matrix.row_count, 1); + i64 column_count = gb_max(t->Matrix.column_count, 1); bool pop = type_path_push(tp, elem); if (tp->failure) { @@ -1491,7 +1492,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { // could be maximally aligned but as a compromise, having no padding will be // beneficial to third libraries that assume no padding - i64 total_expected_size = row_count*t->Matrix.column_count*elem_size; + i64 total_expected_size = row_count*column_count*elem_size; // i64 min_alignment = prev_pow2(elem_align * row_count); i64 min_alignment = prev_pow2(total_expected_size); while (total_expected_size != 0 && (total_expected_size % min_alignment) != 0) { @@ -1523,12 +1524,15 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) { i64 stride_in_bytes = 0; // NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding - // It would be better for performance to pad each column so that each column + // It would be better for performance to pad each column/row so that each column/row // could be maximally aligned but as a compromise, having no padding will be // beneficial to third libraries that assume no padding - i64 row_count = t->Matrix.row_count; - stride_in_bytes = elem_size*row_count; - + + if (t->Matrix.is_row_major) { + stride_in_bytes = elem_size*t->Matrix.column_count; + } else { + stride_in_bytes = elem_size*t->Matrix.row_count; + } t->Matrix.stride_in_bytes = stride_in_bytes; return stride_in_bytes; } @@ -4217,7 +4221,11 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { case Type_Matrix: { i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path); - return stride_in_bytes * t->Matrix.column_count; + if (t->Matrix.is_row_major) { + return stride_in_bytes * t->Matrix.row_count; + } else { + return stride_in_bytes * t->Matrix.column_count; + } } case Type_BitField: diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index f38fa11e6..8a9272882 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -10,7 +10,8 @@ A test suite for `core:net` */ -//+build !netbsd !openbsd +//+build !netbsd +//+build !openbsd package test_core_net import "core:testing" diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 299e08791..dcea3d483 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -15,6 +15,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style ..\..\..\odin test ..\test_issue_2615.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 8b4c1e7f2..c3bc00e24 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -16,6 +16,7 @@ $ODIN test ../test_issue_2466.odin $COMMON $ODIN test ../test_issue_2615.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON +$ODIN test ../test_issue_4210.odin $COMMON if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_4210.odin b/tests/issues/test_issue_4210.odin new file mode 100644 index 000000000..f50086a4e --- /dev/null +++ b/tests/issues/test_issue_4210.odin @@ -0,0 +1,85 @@ +// Tests issue #4210 https://github.com/odin-lang/Odin/issues/4210 +package test_issues + +import "core:testing" +import "base:intrinsics" + +@test +test_row_major_matrix :: proc(t: ^testing.T) { + row_major34: #row_major matrix[3,4]int = { + 11,12,13,14, + 21,22,23,24, + 31,32,33,34, + } + row_major34_expected := [?]int{11,12,13,14, 21,22,23,24, 31,32,33,34} + + row_major43: #row_major matrix[4,3]int = { + 11,12,13, + 21,22,23, + 31,32,33, + 41,42,43, + } + row_major43_expected := [?]int{11,12,13, 21,22,23, 31,32,33, 41,42,43} + + major34_flattened := intrinsics.matrix_flatten(row_major34) + major34_from_ptr := intrinsics.unaligned_load((^[3 * 4]int)(&row_major34)) + + for row in 0..<3 { + for column in 0..<4 { + idx := row * 4 + column + testing.expect_value(t, major34_flattened[idx], row_major34_expected[idx]) + testing.expect_value(t, major34_from_ptr [idx], row_major34_expected[idx]) + } + } + + major43_flattened := intrinsics.matrix_flatten(row_major43) + major43_from_ptr := intrinsics.unaligned_load((^[4 * 3]int)(&row_major43)) + + for row in 0..<4 { + for column in 0..<3 { + idx := row * 3 + column + testing.expect_value(t, major43_flattened[idx], row_major43_expected[idx]) + testing.expect_value(t, major43_from_ptr [idx], row_major43_expected[idx]) + } + } +} + +@test +test_row_minor_matrix :: proc(t: ^testing.T) { + row_minor34: matrix[3,4]int = { + 11,12,13,14, + 21,22,23,24, + 31,32,33,34, + } + row_minor34_expected := [?]int{11,21,31, 12,22,32, 13,23,33, 14,24,34} + + row_minor43: matrix[4,3]int = { + 11,12,13, + 21,22,23, + 31,32,33, + 41,42,43, + } + row_minor43_expected := [?]int{11,21,31,41, 12,22,32,42, 13,23,33,43} + + minor34_flattened := intrinsics.matrix_flatten(row_minor34) + minor34_from_ptr := intrinsics.unaligned_load((^[3 * 4]int)(&row_minor34)) + + for row in 0..<3 { + for column in 0..<4 { + idx := row * 4 + column + testing.expect_value(t, minor34_flattened[idx], row_minor34_expected[idx]) + testing.expect_value(t, minor34_from_ptr [idx], row_minor34_expected[idx]) + } + } + + minor43_flattened := intrinsics.matrix_flatten(row_minor43) + minor43_from_ptr := intrinsics.unaligned_load((^[4 * 3]int)(&row_minor43)) + + for row in 0..<4 { + for column in 0..<3 { + idx := row * 3 + column + testing.expect_value(t, minor43_flattened[idx], row_minor43_expected[idx]) + testing.expect_value(t, minor43_from_ptr [idx], row_minor43_expected[idx]) + } + } +} \ No newline at end of file diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin index 691aed9ce..ae4649aed 100644 --- a/vendor/wgpu/wgpu.odin +++ b/vendor/wgpu/wgpu.odin @@ -27,6 +27,8 @@ when ODIN_OS == .Windows { "system:advapi32.lib", "system:user32.lib", "system:gdi32.lib", + "system:ole32.lib", + "system:oleaut32.lib", } } else when ODIN_OS == .Darwin { @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "aarch64" when ODIN_ARCH == .arm64 else #panic("unsupported WGPU Native architecture")