diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 4e340b907f7..3ede3da1a8f 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -3379,6 +3379,10 @@ createInterop("cvalues") { it.defFile 'interop/basics/cvalues.def' } +createInterop("cvectors") { + it.defFile 'interop/basics/cvectors.def' +} + createInterop("cstructs") { it.defFile 'interop/basics/cstructs.def' } @@ -3560,6 +3564,20 @@ interopTest("interop_types") { interop = 'ctypes' } +interopTest("interop_vectors") { + disabled = (project.testTarget == 'wasm32') // No interop for wasm yet. + source = "interop/basics/vectors.kt" + interop = 'cvectors' +} + +interopTest("interop_vectors_mimalloc") { + disabled = (project.testTarget == 'wasm32') // No interop for wasm yet. + source = "interop/basics/vectors.kt" + interop = 'cvectors' + flags = [ "-Xallocator=mimalloc" ] + arguments = [ "mimalloc" ] +} + interopTest("interop_mangling") { disabled = (project.testTarget == 'wasm32') // No interop for wasm yet. source = "interop/basics/mangling.kt" diff --git a/backend.native/tests/interop/basics/cstructs.def b/backend.native/tests/interop/basics/cstructs.def index b5e35bf6e59..7535243dcb7 100644 --- a/backend.native/tests/interop/basics/cstructs.def +++ b/backend.native/tests/interop/basics/cstructs.def @@ -1,6 +1,4 @@ --- -typedef float __attribute__ ((__vector_size__ (16))) KVector4f; - typedef struct { int i; } Trivial; @@ -11,7 +9,6 @@ enum E { struct Complex { unsigned int ui; - KVector4f vec4f; Trivial t; struct Complex* next; enum E e; @@ -19,15 +16,12 @@ struct Complex { }; struct Complex produceComplex() { - struct Complex complex; - complex.ui = 128; - KVector4f vec = { 1.0, 1.0, 1.0, 1.0 }; - complex.vec4f = vec; - Trivial t = { .i = 1 }; - complex.t = t; - complex.next = 0; - complex.e = R; - complex.arr[0] = -51; - complex.arr[1] = -19; + struct Complex complex = { + .ui = 128, + .t = {1}, + .next = 0, + .e = R, + .arr = {-51, -19} + }; return complex; }; \ No newline at end of file diff --git a/backend.native/tests/interop/basics/ctypes.def b/backend.native/tests/interop/basics/ctypes.def index a153a95ebd9..8fdf6942216 100644 --- a/backend.native/tests/interop/basics/ctypes.def +++ b/backend.native/tests/interop/basics/ctypes.def @@ -87,15 +87,3 @@ enum EnumExplicitChar : char { EnumExplicitCharB = 'b', EnumExplicitCharDup = 'a' }; - -typedef float __attribute__ ((__vector_size__ (16))) KVector4f; -typedef int __attribute__ ((__vector_size__ (16))) KVector4i32; - -static float sendV4F(KVector4f v) { - return v[0] + 2 * v[1] + 4 * v[2] + 8 * v[3]; -} - -static int sendV4I(KVector4i32 v) { - return v[0] + 2 * v[1] + 4 * v[2] + 8 * v[3]; -} - diff --git a/backend.native/tests/interop/basics/cvectors.def b/backend.native/tests/interop/basics/cvectors.def new file mode 100644 index 00000000000..9c303835d44 --- /dev/null +++ b/backend.native/tests/interop/basics/cvectors.def @@ -0,0 +1,28 @@ +--- +typedef float __attribute__ ((__vector_size__ (16))) KVector4f; +typedef int __attribute__ ((__vector_size__ (16))) KVector4i32; + +struct Complex { + unsigned int ui; + KVector4f vec4f; + struct Complex* next; + int arr[2]; +}; + +struct Complex produceComplex() { + struct Complex complex = { + .ui = 128, + .vec4f = {1.0, 1.0, 1.0, 1.0}, + .next = 0, + .arr = {-51, -19} + }; + return complex; +}; + +static float sendV4F(KVector4f v) { + return v[0] + 2 * v[1] + 4 * v[2] + 8 * v[3]; +} + +static int sendV4I(KVector4i32 v) { + return v[0] + 2 * v[1] + 4 * v[2] + 8 * v[3]; +} diff --git a/backend.native/tests/interop/basics/structs.kt b/backend.native/tests/interop/basics/structs.kt index ad20163caaf..4057db967d9 100644 --- a/backend.native/tests/interop/basics/structs.kt +++ b/backend.native/tests/interop/basics/structs.kt @@ -19,10 +19,6 @@ fun main() { next = null assertEquals(next, null) - assertEquals(vec4f, vectorOf(1.0f, 1.0f, 1.0f, 1.0f)) - vec4f = vectorOf(0.0f, 0.0f, 0.0f, 0.0f) - assertEquals(vec4f, vectorOf(0.0f, 0.0f, 0.0f, 0.0f)) - assertEquals(e, E.R) e = E.G assertEquals(e, E.G) diff --git a/backend.native/tests/interop/basics/types.kt b/backend.native/tests/interop/basics/types.kt index 3779223169b..46300f26cb5 100644 --- a/backend.native/tests/interop/basics/types.kt +++ b/backend.native/tests/interop/basics/types.kt @@ -27,18 +27,5 @@ fun main() { assertEquals('a'.toByte(), EnumExplicitCharA) assertEquals('b'.toByte(), EnumExplicitCharB) assertEquals(EnumExplicitCharA, EnumExplicitCharDup) - - // FIXME: KT-36285 - if (Platform.osFamily != OsFamily.LINUX && Platform.cpuArchitecture != CpuArchitecture.ARM32) { - assertEquals(49, sendV4I(vectorOf(1, 2, 3, 4))) - } - assertEquals(49, (sendV4F(vectorOf(1f, 2f, 3f, 4f)) + 0.00001).toInt()) - - memScoped { - val vector = alloc().also { - it.value = vectorOf(1, 2, 3, 4) - } - assertEquals(vector.value, vectorOf(1, 2, 3, 4)) - } } diff --git a/backend.native/tests/interop/basics/vectors.kt b/backend.native/tests/interop/basics/vectors.kt new file mode 100644 index 00000000000..52b1f294693 --- /dev/null +++ b/backend.native/tests/interop/basics/vectors.kt @@ -0,0 +1,35 @@ +import kotlinx.cinterop.* +import kotlin.native.* +import kotlin.test.* +import cvectors.* + +fun isWin32() = Platform.osFamily == OsFamily.WINDOWS && Platform.cpuArchitecture == CpuArchitecture.X86 + +fun main(args: Array) { + val mimalloc = args.takeIf { it.size == 1 }?.get(0) == "mimalloc" + + // See KT-37272. Fixed in mimalloc + if (mimalloc || !isWin32()) { + produceComplex().useContents { + assertEquals(vec4f, vectorOf(1.0f, 1.0f, 1.0f, 1.0f)) + vec4f = vectorOf(0.0f, 0.0f, 0.0f, 0.0f) + assertEquals(vec4f, vectorOf(0.0f, 0.0f, 0.0f, 0.0f)) + } + } + + // FIXME: KT-36285 + if (Platform.osFamily != OsFamily.LINUX || Platform.cpuArchitecture != CpuArchitecture.ARM32) { + assertEquals(49, sendV4I(vectorOf(1, 2, 3, 4))) + } + assertEquals(49, (sendV4F(vectorOf(1f, 2f, 3f, 4f)) + 0.00001).toInt()) + + if (mimalloc || !isWin32()) { + memScoped { + val vector = alloc().also { + it.value = vectorOf(1, 2, 3, 4) + } + assertEquals(vector.value, vectorOf(1, 2, 3, 4)) + } + } +} + diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index edcbc1e2880..d194bd7f524 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -53,7 +53,7 @@ void* Kotlin_interop_malloc(KLong size, KInt align) { return nullptr; } - void* result = konan::calloc(1, size); + void* result = konan::calloc_aligned(1, size, align); if ((reinterpret_cast(result) & (align - 1)) != 0) { // Unaligned! RuntimeAssert(false, "unsupported alignment"); diff --git a/runtime/src/main/cpp/Porting.cpp b/runtime/src/main/cpp/Porting.cpp index 43321a03082..c2736a1e977 100644 --- a/runtime/src/main/cpp/Porting.cpp +++ b/runtime/src/main/cpp/Porting.cpp @@ -236,17 +236,25 @@ extern "C" void* dlcalloc(size_t, size_t); extern "C" void dlfree(void*); #define calloc_impl dlcalloc #define free_impl dlfree +#define calloc_aligned_impl(count, size, alignment) dlcalloc(count, size) + #else extern "C" void* konan_calloc_impl(size_t, size_t); extern "C" void konan_free_impl(void*); +extern "C" void* konan_calloc_aligned_impl(size_t count, size_t size, size_t alignment); #define calloc_impl konan_calloc_impl #define free_impl konan_free_impl +#define calloc_aligned_impl konan_calloc_aligned_impl #endif void* calloc(size_t count, size_t size) { return calloc_impl(count, size); } +void* calloc_aligned(size_t count, size_t size, size_t alignment) { + return calloc_aligned_impl(count, size, alignment); +} + void free(void* pointer) { free_impl(pointer); } diff --git a/runtime/src/main/cpp/Porting.h b/runtime/src/main/cpp/Porting.h index 32a1677883a..80327e28e64 100644 --- a/runtime/src/main/cpp/Porting.h +++ b/runtime/src/main/cpp/Porting.h @@ -76,6 +76,7 @@ void *memset(void *b, int c, size_t len); // Memory operations. void* calloc(size_t count, size_t size); +void* calloc_aligned(size_t count, size_t size, size_t alignment); void free(void* ptr); // Time operations. diff --git a/runtime/src/opt_alloc/cpp/AllocImpl.cpp b/runtime/src/opt_alloc/cpp/AllocImpl.cpp index 1bdb93f4d66..c44d7a52fb7 100644 --- a/runtime/src/opt_alloc/cpp/AllocImpl.cpp +++ b/runtime/src/opt_alloc/cpp/AllocImpl.cpp @@ -8,9 +8,16 @@ extern "C" { void* mi_calloc(size_t, size_t); void mi_free(void*); +void* mi_calloc_aligned(size_t count, size_t size, size_t alignment); + void* konan_calloc_impl(size_t n_elements, size_t elem_size) { return mi_calloc(n_elements, elem_size); } + +void* konan_calloc_aligned_impl(size_t count, size_t size, size_t alignment) { + return mi_calloc_aligned(count, size, alignment); +} + void konan_free_impl (void* mem) { mi_free(mem); } diff --git a/runtime/src/std_alloc/cpp/AllocImpl.cpp b/runtime/src/std_alloc/cpp/AllocImpl.cpp index ce85a81ecbb..c3a165e44d6 100644 --- a/runtime/src/std_alloc/cpp/AllocImpl.cpp +++ b/runtime/src/std_alloc/cpp/AllocImpl.cpp @@ -8,8 +8,14 @@ extern "C" { // Memory operations. void* konan_calloc_impl(size_t n_elements, size_t elem_size) { - return calloc(n_elements, elem_size); + return calloc(n_elements, elem_size); } + +void* konan_calloc_aligned_impl(size_t count, size_t size, size_t alignment) { + // alignment is not supported by std alloc - use mimalloc + return calloc(count, size); +} + void konan_free_impl (void* mem) { free(mem); }