From 38788c03485229197ccb7378f99e6c6fe34e5a7e Mon Sep 17 00:00:00 2001 From: Urjasvi Suthar Date: Tue, 14 Jul 2026 21:33:39 +0530 Subject: [PATCH 1/6] Fix arm64 argument alignment abi for composite type of size <= 16 bytes --- src/llvm_abi.cpp | 16 +------------ tests/issues/run.sh | 3 +++ tests/issues/test_issue_5640.c | 17 ++++++++++++++ tests/issues/test_issue_5640.odin | 39 +++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 tests/issues/test_issue_5640.c create mode 100644 tests/issues/test_issue_5640.odin diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index f1a23a95c..528ddca88 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1342,22 +1342,8 @@ namespace lbAbiArm64 { } else if (size <= 8) { cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8)); } else { - unsigned count = cast(unsigned)((size+7)/8); - LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64); - LLVMTypeRef *types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, count); - - i64 size_copy = size; - for (unsigned i = 0; i < count; i++) { - if (size_copy >= 8) { - types[i] = llvm_i64; - } else { - types[i] = LLVMIntTypeInContext(c, 8*cast(unsigned)size_copy); - } - size_copy -= 8; - } - GB_ASSERT(size_copy <= 0); - cast_type = LLVMStructTypeInContext(c, types, count, true); + cast_type = llvm_array_type(llvm_i64, 2); } args[i] = lb_arg_type_direct(type, cast_type, nullptr, nullptr); } else { diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c1e231390..c8fa80183 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -88,6 +88,9 @@ $ODIN test ../test_issue_7010.odin $COMMON clang -c ../test_issue_6809_6816.c -o test_issue_6809_6816_c.o -O3 $ODIN test ../test_issue_6809_6816.odin -o:speed $COMMON +clang -c ../test_issue_5640.c -o test_issue_5640_c.o +$ODIN test ../test_issue_5640.odin -o:none --sanitize:address $COMMON + set +x popd diff --git a/tests/issues/test_issue_5640.c b/tests/issues/test_issue_5640.c new file mode 100644 index 000000000..58cbff688 --- /dev/null +++ b/tests/issues/test_issue_5640.c @@ -0,0 +1,17 @@ +#include +#include + +typedef struct { + uint32_t a; + uint32_t b; + uint32_t c; +} MyStruct; + +bool test_stack_next( + int64_t r0, int64_t r1, int64_t r2, int64_t r3, + int64_t r4, int64_t r5, int64_t r6, int64_t r7, + MyStruct s, + int32_t next_arg +) { + return next_arg == 999; +} diff --git a/tests/issues/test_issue_5640.odin b/tests/issues/test_issue_5640.odin new file mode 100644 index 000000000..d25c68976 --- /dev/null +++ b/tests/issues/test_issue_5640.odin @@ -0,0 +1,39 @@ +package test_issues + +import "core:testing" + +MyStruct :: struct { + a: u32, + b: u32, + c: u32, +} + +Foo :: struct { + x: [15]u8, // errors with 11, 13, 14, 15 +} + + +myfunc :: #force_no_inline proc( f: Foo ) -> bool { + return f.x[0] == 45 && f.x[14] == 67 +} + +foreign import test_lib "build/test_issue_5640_c.o" + +foreign test_lib { + test_stack_next :: proc( + r0, r1, r2, r3, r4, r5, r6, r7: i64, + s: MyStruct, + next_arg: i32, + ) -> bool --- +} + +@test +test_stack_parameter_alignment_arm64_abi :: proc(t: ^testing.T) { + s := MyStruct{ a = 42, b = 1337, c = 342 } + + res := test_stack_next(0, 1, 2, 3, 4, 5, 6, 7, s, 999) + testing.expect(t, res == true) + + res_2 := myfunc({{45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67}}) + testing.expect(t, res_2 == true) +} From 3a9aa4c1697a7d5ec15d13363cf173ddfb44afbb Mon Sep 17 00:00:00 2001 From: Urjasvi Suthar Date: Tue, 14 Jul 2026 21:36:06 +0530 Subject: [PATCH 2/6] Add issue link to code --- tests/issues/test_issue_5640.c | 2 ++ tests/issues/test_issue_5640.odin | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/issues/test_issue_5640.c b/tests/issues/test_issue_5640.c index 58cbff688..838f4dd3e 100644 --- a/tests/issues/test_issue_5640.c +++ b/tests/issues/test_issue_5640.c @@ -1,3 +1,5 @@ +// Tests issue: https://github.com/odin-lang/Odin/issues/5640 + #include #include diff --git a/tests/issues/test_issue_5640.odin b/tests/issues/test_issue_5640.odin index d25c68976..efe638b3a 100644 --- a/tests/issues/test_issue_5640.odin +++ b/tests/issues/test_issue_5640.odin @@ -1,3 +1,5 @@ +// Tests issue: https://github.com/odin-lang/Odin/issues/5640 + package test_issues import "core:testing" From d8c984d75101379db67b444ef5d8a5d71034c231 Mon Sep 17 00:00:00 2001 From: Urjasvi Suthar Date: Tue, 14 Jul 2026 22:12:57 +0530 Subject: [PATCH 3/6] skip -sanitize:address for NetBSD --- tests/issues/run.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c8fa80183..c7bb99374 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -89,7 +89,11 @@ clang -c ../test_issue_6809_6816.c -o test_issue_6809_6816_c.o -O3 $ODIN test ../test_issue_6809_6816.odin -o:speed $COMMON clang -c ../test_issue_5640.c -o test_issue_5640_c.o -$ODIN test ../test_issue_5640.odin -o:none --sanitize:address $COMMON +if [[ "$(uname)" != "NetBSD" ]]; then + $ODIN test ../test_issue_5640.odin -o:none --sanitize:address $COMMON +else + $ODIN test ../test_issue_5640.odin -o:none $COMMON +fi set +x From 43923eb3cb59a0b725bc189b4dec5d6a034fc7c3 Mon Sep 17 00:00:00 2001 From: Isabella Basso Date: Tue, 14 Jul 2026 18:44:02 -0300 Subject: [PATCH 4/6] compiler: fix constant aggregate rebuild fixes: #7005 --- src/llvm_backend_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index d85f0d564..3fc65a34f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -463,7 +463,7 @@ gb_internal LLVMValueRef llvm_const_insert_value_with_rebuild(lbModule *m, LLVMV GB_ASSERT(count > 0); unsigned value_count = LLVMCountStructElementTypes(LLVMTypeOf(agg)); - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, count); + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, value_count); defer (gb_free(heap_allocator(), values)); for (unsigned i = 0; i < value_count; i++) { From ca878a1de7e90ba62d146fd091ff918b8d65e334 Mon Sep 17 00:00:00 2001 From: Isabella Basso Date: Thu, 21 May 2026 02:26:27 -0300 Subject: [PATCH 5/6] checker: keep polymorphic probes read-only Overload candidate checks pass modify_type=false, but generic array counts still specialized their candidate Type and scope entity. Parallel probes could then observe and mutate the same partial specialization. Resolve generic dimensions in local state and commit them only when specializing. Keep array-like and map cache updates out of probe mode. --- src/check_expr.cpp | 89 +++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7b95da1ad..0bad86a8c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1386,22 +1386,22 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ } } -gb_internal bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source_count) { +gb_internal bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source_count, bool modify_type) { Type *gt = *gt_; - GB_ASSERT(gt->kind == Type_Generic); Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name, 0); GB_ASSERT(e != nullptr); if (e->kind == Entity_TypeName) { - *gt_ = nullptr; *dst_count = source_count; - e->kind = Entity_Constant; - e->Constant.value = exact_value_i64(source_count); - e->type = t_untyped_integer; + if (modify_type) { + *gt_ = nullptr; + e->kind = Entity_Constant; + e->Constant.value = exact_value_i64(source_count); + e->type = t_untyped_integer; + } return true; } else if (e->kind == Entity_Constant) { - *gt_ = nullptr; if (e->Constant.value.kind != ExactValue_Integer) { return false; } @@ -1410,6 +1410,9 @@ gb_internal bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source return false; } *dst_count = source_count; + if (modify_type) { + *gt_ = nullptr; + } return true; } return false; @@ -1490,12 +1493,18 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T case Type_Array: if (source->kind == Type_Array) { - if (poly->Array.generic_count != nullptr) { - if (!polymorphic_assign_index(&poly->Array.generic_count, &poly->Array.count, source->Array.count)) { + Type *generic_count = poly->Array.generic_count; + i64 count = poly->Array.count; + if (generic_count != nullptr) { + if (!polymorphic_assign_index(&generic_count, &count, source->Array.count, modify_type)) { return false; } + if (modify_type) { + poly->Array.generic_count = generic_count; + poly->Array.count = count; + } } - if (poly->Array.count == source->Array.count) { + if (count == source->Array.count) { return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type); } } else if (source->kind == Type_EnumeratedArray) { @@ -1510,6 +1519,9 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T if (it->kind != Type_Enum) { return false; } + if (!modify_type) { + return is_polymorphic_type_assignable(c, poly->Array.elem, source->EnumeratedArray.elem, true, false); + } poly->kind = Type_EnumeratedArray; poly->cached_size = -1; @@ -1565,14 +1577,18 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T case Type_FixedCapacityDynamicArray: if (source->kind == Type_FixedCapacityDynamicArray) { - if (poly->FixedCapacityDynamicArray.generic_capacity != nullptr) { - if (!polymorphic_assign_index(&poly->FixedCapacityDynamicArray.generic_capacity, - &poly->FixedCapacityDynamicArray.capacity, - source->FixedCapacityDynamicArray.capacity)) { + Type *generic_capacity = poly->FixedCapacityDynamicArray.generic_capacity; + i64 capacity = poly->FixedCapacityDynamicArray.capacity; + if (generic_capacity != nullptr) { + if (!polymorphic_assign_index(&generic_capacity, &capacity, source->FixedCapacityDynamicArray.capacity, modify_type)) { return false; } + if (modify_type) { + poly->FixedCapacityDynamicArray.generic_capacity = generic_capacity; + poly->FixedCapacityDynamicArray.capacity = capacity; + } } - if (poly->FixedCapacityDynamicArray.capacity == source->FixedCapacityDynamicArray.capacity) { + if (capacity == source->FixedCapacityDynamicArray.capacity) { return is_polymorphic_type_assignable(c, poly->FixedCapacityDynamicArray.elem, source->FixedCapacityDynamicArray.elem, true, modify_type); } } @@ -1723,8 +1739,10 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type); bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type); if (key || value) { - poly->Map.lookup_result_type = nullptr; - init_map_internal_types(poly); + if (modify_type) { + poly->Map.lookup_result_type = nullptr; + init_map_internal_types(poly); + } return true; } } @@ -1732,20 +1750,29 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T case Type_Matrix: if (source->kind == Type_Matrix) { - if (poly->Matrix.generic_row_count != nullptr) { - poly->Matrix.stride_in_bytes = 0; - if (!polymorphic_assign_index(&poly->Matrix.generic_row_count, &poly->Matrix.row_count, source->Matrix.row_count)) { + Type *generic_row_count = poly->Matrix.generic_row_count; + Type *generic_column_count = poly->Matrix.generic_column_count; + i64 row_count = poly->Matrix.row_count; + i64 column_count = poly->Matrix.column_count; + if (generic_row_count != nullptr) { + if (!polymorphic_assign_index(&generic_row_count, &row_count, source->Matrix.row_count, modify_type)) { return false; } } - if (poly->Matrix.generic_column_count != nullptr) { - poly->Matrix.stride_in_bytes = 0; - if (!polymorphic_assign_index(&poly->Matrix.generic_column_count, &poly->Matrix.column_count, source->Matrix.column_count)) { + if (generic_column_count != nullptr) { + if (!polymorphic_assign_index(&generic_column_count, &column_count, source->Matrix.column_count, modify_type)) { return false; } } - if (poly->Matrix.row_count == source->Matrix.row_count && - poly->Matrix.column_count == source->Matrix.column_count) { + if (modify_type && (poly->Matrix.generic_row_count != nullptr || poly->Matrix.generic_column_count != nullptr)) { + poly->Matrix.generic_row_count = generic_row_count; + poly->Matrix.generic_column_count = generic_column_count; + poly->Matrix.row_count = row_count; + poly->Matrix.column_count = column_count; + poly->Matrix.stride_in_bytes = 0; + } + if (row_count == source->Matrix.row_count && + column_count == source->Matrix.column_count) { return is_polymorphic_type_assignable(c, poly->Matrix.elem, source->Matrix.elem, true, modify_type); } } @@ -1753,12 +1780,18 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T case Type_SimdVector: if (source->kind == Type_SimdVector) { - if (poly->SimdVector.generic_count != nullptr) { - if (!polymorphic_assign_index(&poly->SimdVector.generic_count, &poly->SimdVector.count, source->SimdVector.count)) { + Type *generic_count = poly->SimdVector.generic_count; + i64 count = poly->SimdVector.count; + if (generic_count != nullptr) { + if (!polymorphic_assign_index(&generic_count, &count, source->SimdVector.count, modify_type)) { return false; } + if (modify_type) { + poly->SimdVector.generic_count = generic_count; + poly->SimdVector.count = count; + } } - if (poly->SimdVector.count == source->SimdVector.count) { + if (count == source->SimdVector.count) { return is_polymorphic_type_assignable(c, poly->SimdVector.elem, source->SimdVector.elem, true, modify_type); } } From 727b5043e583b2fef6155e0262b69c0ddec54426 Mon Sep 17 00:00:00 2001 From: FourteenBrush <74827262+FourteenBrush@users.noreply.github.com> Date: Wed, 15 Jul 2026 14:13:53 +0200 Subject: [PATCH 6/6] Fix switch fallthrough in lb_emit_struct_ev --- src/llvm_backend_utility.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index e00254bc5..c71d16122 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1496,6 +1496,7 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { case 0: result_type = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break; case 1: result_type = t_int; break; } + break; case Type_Map: {