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); } } 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/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++) { 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: { diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c1e231390..c7bb99374 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -88,6 +88,13 @@ $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 +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 popd diff --git a/tests/issues/test_issue_5640.c b/tests/issues/test_issue_5640.c new file mode 100644 index 000000000..838f4dd3e --- /dev/null +++ b/tests/issues/test_issue_5640.c @@ -0,0 +1,19 @@ +// Tests issue: https://github.com/odin-lang/Odin/issues/5640 + +#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..efe638b3a --- /dev/null +++ b/tests/issues/test_issue_5640.odin @@ -0,0 +1,41 @@ +// Tests issue: https://github.com/odin-lang/Odin/issues/5640 + +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) +}