Mercurial > vec
changeset 31:bf6ad516f1e6
Backed out changeset c6c99ab1088a
author | Paper <paper@tflc.us> |
---|---|
date | Fri, 25 Apr 2025 17:40:33 -0400 |
parents | 641d8c79b1da |
children | 0de48dc864ea |
files | CMakeLists.txt include/vec/cpu.h include/vec/impl/gcc.h include/vec/impl/generic.h include/vec/impl/ppc/altivec.h include/vec/impl/x86/avx512bw.h include/vec/impl/x86/avx512dq.h include/vec/impl/x86/avx512f.h include/vec/impl/x86/sse2.h include/vec/impl/x86/sse3.h include/vec/impl/x86/sse41.h include/vec/impl/x86/sse42.h include/vec/vec.h src/cpu.c src/impl/arm/neon.c src/impl/fallback.c src/impl/gcc.c src/impl/generic.c src/impl/ppc/altivec.c src/impl/x86/avx2.c src/impl/x86/avx512bw.c src/impl/x86/avx512dq.c src/impl/x86/avx512f.c src/impl/x86/mmx.c src/impl/x86/sse2.c src/impl/x86/sse3.c src/impl/x86/sse41.c src/impl/x86/sse42.c src/vec.c test/test_arith.h |
diffstat | 30 files changed, 943 insertions(+), 2347 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Fri Apr 25 17:40:30 2025 -0400 +++ b/CMakeLists.txt Fri Apr 25 17:40:33 2025 -0400 @@ -2,13 +2,7 @@ project(vec VERSION 3.0.0 DESCRIPTION "a tiny C99 SIMD vector library" LANGUAGES C) -add_library(vec "src/vec.c") - -target_sources(vec PRIVATE - "src/cpu.c" - "src/impl/generic.c" - # "src/impl/fallback.c" -- deadcode -) +add_library(vec SHARED "src/vec.c;src/cpu.c;src/impl/generic.c;src/impl/fallback.c") include(CheckCCompilerFlag) @@ -55,18 +49,10 @@ if(COMPILER_HAS_SSE2) set(COMPILER_SSE2_FLAGS "-msse2") endif() - check_c_compiler_flag("-msse3" COMPILER_HAS_SSE3) - if(COMPILER_HAS_SSE3) - set(COMPILER_SSE3_FLAGS "-msse3") - endif() check_c_compiler_flag("-msse4.1" COMPILER_HAS_SSE41) if(COMPILER_HAS_SSE41) set(COMPILER_SSE41_FLAGS "-msse4.1") endif() - check_c_compiler_flag("-msse4.2" COMPILER_HAS_SSE42) - if(COMPILER_HAS_SSE42) - set(COMPILER_SSE42_FLAGS "-msse4.2") - endif() check_c_compiler_flag("-mavx2" COMPILER_HAS_AVX2) if(COMPILER_HAS_AVX2) set(COMPILER_AVX2_FLAGS "-mavx2") @@ -75,14 +61,6 @@ if(COMPILER_HAS_AVX512F) set(COMPILER_AVX512F_FLAGS "-mavx512f") endif() - check_c_compiler_flag("-mavx512bw" COMPILER_HAS_AVX512BW) - if(COMPILER_HAS_AVX512BW) - set(COMPILER_AVX512BW_FLAGS "-mavx512bw") - endif() - check_c_compiler_flag("-mavx512dq" COMPILER_HAS_AVX512DQ) - if(COMPILER_HAS_AVX512DQ) - set(COMPILER_AVX512DQ_FLAGS "-mavx512dq") - endif() endif() if(COMPILER_HAS_ALTIVEC) @@ -109,24 +87,12 @@ target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_SSE2") endif() -if(COMPILER_HAS_SSE3) - target_sources(vec PRIVATE "src/impl/x86/sse3.c") - set_source_files_properties("src/impl/x86/sse3.c" PROPERTIES COMPILE_FLAGS "${COMPILER_SSE3_FLAGS}") - target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_SSE3") -endif() - if(COMPILER_HAS_SSE41) target_sources(vec PRIVATE "src/impl/x86/sse41.c") set_source_files_properties("src/impl/x86/sse41.c" PROPERTIES COMPILE_FLAGS "${COMPILER_SSE41_FLAGS}") target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_SSE41") endif() -if(COMPILER_HAS_SSE42) - target_sources(vec PRIVATE "src/impl/x86/sse42.c") - set_source_files_properties("src/impl/x86/sse42.c" PROPERTIES COMPILE_FLAGS "${COMPILER_SSE42_FLAGS}") - target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_SSE42") -endif() - if(COMPILER_HAS_AVX2) target_sources(vec PRIVATE "src/impl/x86/avx2.c") set_source_files_properties("src/impl/x86/avx2.c" PROPERTIES COMPILE_FLAGS "${COMPILER_AVX2_FLAGS}") @@ -139,17 +105,6 @@ target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_AVX512F") endif() -if(COMPILER_HAS_AVX512BW) - target_sources(vec PRIVATE "src/impl/x86/avx512bw.c") - set_source_files_properties("src/impl/x86/avx512bw.c" PROPERTIES COMPILE_FLAGS "${COMPILER_AVX512BW_FLAGS}") - target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_AVX512BW") -endif() - -if(COMPILER_HAS_AVX512DQ) - target_sources(vec PRIVATE "src/impl/x86/avx512dq.c") - set_source_files_properties("src/impl/x86/avx512dq.c" PROPERTIES COMPILE_FLAGS "${COMPILER_AVX512DQ_FLAGS}") - target_compile_definitions(vec PRIVATE "-DVEC_COMPILER_HAS_AVX512DQ") -endif() ######################################################################### # integer types; it's nice to accommodate for older broken systems that
--- a/include/vec/cpu.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/cpu.h Fri Apr 25 17:40:33 2025 -0400 @@ -42,8 +42,6 @@ VEC_CPU_HAS_AVX2 = (1 << 9), VEC_CPU_HAS_AVX512F = (1 << 10), VEC_CPU_HAS_NEON = (1 << 11), - VEC_CPU_HAS_AVX512BW = (1 << 12), - VEC_CPU_HAS_AVX512DQ = (1 << 13), }; // NOT thread-safe.
--- a/include/vec/impl/gcc.h Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/** - * vec - a tiny SIMD vector library in plain C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -/* Generic array-based implementation. */ - -#ifndef VEC_IMPL_GENERIC_H_ -#define VEC_IMPL_GENERIC_H_ - -#include "vec/vec.h" - -// 16-bit -extern const vint8x2_impl vint8x2_impl_generic; -extern const vuint8x2_impl vuint8x2_impl_generic; - -// 32-bit -extern const vint8x4_impl vint8x4_impl_generic; -extern const vuint8x4_impl vuint8x4_impl_generic; -extern const vint16x2_impl vint16x2_impl_generic; -extern const vuint16x2_impl vuint16x2_impl_generic; - -// 64-bit -extern const vint8x8_impl vint8x8_impl_generic; -extern const vuint8x8_impl vuint8x8_impl_generic; -extern const vint16x4_impl vint16x4_impl_generic; -extern const vuint16x4_impl vuint16x4_impl_generic; -extern const vint32x2_impl vint32x2_impl_generic; -extern const vuint32x2_impl vuint32x2_impl_generic; - -// 128-bit -extern const vint8x16_impl vint8x16_impl_generic; -extern const vuint8x16_impl vuint8x16_impl_generic; -extern const vint16x8_impl vint16x8_impl_generic; -extern const vuint16x8_impl vuint16x8_impl_generic; -extern const vint32x4_impl vint32x4_impl_generic; -extern const vuint32x4_impl vuint32x4_impl_generic; -extern const vint64x2_impl vint64x2_impl_generic; -extern const vuint64x2_impl vuint64x2_impl_generic; - -// 256-bit -extern const vint8x32_impl vint8x32_impl_generic; -extern const vuint8x32_impl vuint8x32_impl_generic; -extern const vint16x16_impl vint16x16_impl_generic; -extern const vuint16x16_impl vuint16x16_impl_generic; -extern const vint32x8_impl vint32x8_impl_generic; -extern const vuint32x8_impl vuint32x8_impl_generic; -extern const vint64x4_impl vint64x4_impl_generic; -extern const vuint64x4_impl vuint64x4_impl_generic; - -// 512-bit -extern const vint8x64_impl vint8x64_impl_generic; -extern const vuint8x64_impl vuint8x64_impl_generic; -extern const vint16x32_impl vint16x32_impl_generic; -extern const vuint16x32_impl vuint16x32_impl_generic; -extern const vint32x16_impl vint32x16_impl_generic; -extern const vuint32x16_impl vuint32x16_impl_generic; -extern const vint64x8_impl vint64x8_impl_generic; -extern const vuint64x8_impl vuint64x8_impl_generic; - -#endif /* VEC_IMPL_GENERIC_H_ */
--- a/include/vec/impl/generic.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/impl/generic.h Fri Apr 25 17:40:33 2025 -0400 @@ -29,6 +29,65 @@ #include "vec/vec.h" +#define VEC_DEFINE_GENERIC_OPERATIONS_SIGN(sign, csign, bits, size) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load(const vec_##sign##int##bits in[size]); \ + void v##sign##int##bits##x##size##_generic_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_not(v##sign##int##bits##x##size vec); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); + +#define VEC_DEFINE_GENERIC_OPERATIONS(bits, size) \ + VEC_DEFINE_GENERIC_OPERATIONS_SIGN( , , bits, size) \ + VEC_DEFINE_GENERIC_OPERATIONS_SIGN(u, U, bits, size) + +// 16-bit +VEC_DEFINE_GENERIC_OPERATIONS(8, 2) + +// 32-bit +VEC_DEFINE_GENERIC_OPERATIONS(8, 4) +VEC_DEFINE_GENERIC_OPERATIONS(16, 2) + +// 64-bit +VEC_DEFINE_GENERIC_OPERATIONS(8, 8) +VEC_DEFINE_GENERIC_OPERATIONS(16, 4) +VEC_DEFINE_GENERIC_OPERATIONS(32, 2) + +// 128-bit +VEC_DEFINE_GENERIC_OPERATIONS(8, 16) +VEC_DEFINE_GENERIC_OPERATIONS(16, 8) +VEC_DEFINE_GENERIC_OPERATIONS(32, 4) +VEC_DEFINE_GENERIC_OPERATIONS(64, 2) + +// 256-bit +VEC_DEFINE_GENERIC_OPERATIONS(8, 32) +VEC_DEFINE_GENERIC_OPERATIONS(16, 16) +VEC_DEFINE_GENERIC_OPERATIONS(32, 8) +VEC_DEFINE_GENERIC_OPERATIONS(64, 4) + +// 512-bit +VEC_DEFINE_GENERIC_OPERATIONS(8, 64) +VEC_DEFINE_GENERIC_OPERATIONS(16, 32) +VEC_DEFINE_GENERIC_OPERATIONS(32, 16) +VEC_DEFINE_GENERIC_OPERATIONS(64, 8) + +#undef VEC_DEFINE_GENERIC_OPERATIONS +#undef VEC_DEFINE_GENERIC_OPERATIONS_SIGN + // 16-bit extern const vint8x2_impl vint8x2_impl_generic; extern const vuint8x2_impl vuint8x2_impl_generic;
--- a/include/vec/impl/ppc/altivec.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/impl/ppc/altivec.h Fri Apr 25 17:40:33 2025 -0400 @@ -22,6 +22,8 @@ * SOFTWARE. **/ +/* Altivec vector support. */ + #ifndef VEC_IMPL_PPC_ALTIVEC_H_ #define VEC_IMPL_PPC_ALTIVEC_H_
--- a/include/vec/impl/x86/avx512bw.h Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#ifndef VEC_IMPL_X86_AVX512BW_H_ -#define VEC_IMPL_X86_AVX512BW_H_ - -#include "vec/vec.h" - -extern const vint8x64_impl vint8x64_impl_avx512bw; -extern const vint16x32_impl vint16x32_impl_avx512bw; -extern const vuint8x64_impl vuint8x64_impl_avx512bw; -extern const vuint16x32_impl vuint16x32_impl_avx512bw; - -#endif /* VEC_IMPL_X86_AVX512BW_H_ */
--- a/include/vec/impl/x86/avx512dq.h Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#ifndef VEC_IMPL_X86_AVX512DQ_H_ -#define VEC_IMPL_X86_AVX512DQ_H_ - -#include "vec/vec.h" - -extern const vint64x8_impl vint64x8_impl_avx512dq; -extern const vuint64x8_impl vuint64x8_impl_avx512dq; - -#endif /* VEC_IMPL_X86_AVX512DQ_H_ */
--- a/include/vec/impl/x86/avx512f.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/impl/x86/avx512f.h Fri Apr 25 17:40:33 2025 -0400 @@ -27,8 +27,12 @@ #include "vec/vec.h" +extern const vint8x64_impl vint8x64_impl_avx512f; +extern const vint16x32_impl vint16x32_impl_avx512f; extern const vint32x16_impl vint32x16_impl_avx512f; extern const vint64x8_impl vint64x8_impl_avx512f; +extern const vuint8x64_impl vuint8x64_impl_avx512f; +extern const vuint16x32_impl vuint16x32_impl_avx512f; extern const vuint32x16_impl vuint32x16_impl_avx512f; extern const vuint64x8_impl vuint64x8_impl_avx512f;
--- a/include/vec/impl/x86/sse2.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/impl/x86/sse2.h Fri Apr 25 17:40:33 2025 -0400 @@ -27,6 +27,33 @@ #include "vec/vec.h" +// These are only extern because the SSE 4.1 translation unit needs to access it. +#define VEC_DEFINE_SSE2_OPERATIONS_SIGN(sign, csign, bits, size) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_splat(vec_##sign##int##bits x); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load_aligned(const vec_##sign##int##bits in[size]); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load(const vec_##sign##int##bits in[size]); \ + void v##sign##int##bits##x##size##_sse2_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]); \ + void v##sign##int##bits##x##size##_sse2_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); + +#define VEC_DEFINE_SSE2_OPERATIONS(bits, size) \ + VEC_DEFINE_SSE2_OPERATIONS_SIGN( , , bits, size) \ + VEC_DEFINE_SSE2_OPERATIONS_SIGN(u, U, bits, size) + +VEC_DEFINE_SSE2_OPERATIONS(8, 16) +VEC_DEFINE_SSE2_OPERATIONS(16, 8) +VEC_DEFINE_SSE2_OPERATIONS(32, 4) +VEC_DEFINE_SSE2_OPERATIONS(64, 2) + +#undef VEC_DEFINE_SSE2_OPERATIONS +#undef VEC_DEFINE_SSE2_OPERATIONS_SIGN + extern const vint8x16_impl vint8x16_impl_sse2; extern const vint16x8_impl vint16x8_impl_sse2; extern const vint32x4_impl vint32x4_impl_sse2;
--- a/include/vec/impl/x86/sse3.h Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#ifndef VEC_IMPL_X86_SSE3_H_ -#define VEC_IMPL_X86_SSE3_H_ - -#include "vec/vec.h" - -extern const vint8x16_impl vint8x16_impl_sse3; -extern const vint16x8_impl vint16x8_impl_sse3; -extern const vint32x4_impl vint32x4_impl_sse3; -extern const vint64x2_impl vint64x2_impl_sse3; -extern const vuint8x16_impl vuint8x16_impl_sse3; -extern const vuint16x8_impl vuint16x8_impl_sse3; -extern const vuint32x4_impl vuint32x4_impl_sse3; -extern const vuint64x2_impl vuint64x2_impl_sse3; - -#endif /* VEC_IMPL_X86_SSE3_H_ */
--- a/include/vec/impl/x86/sse41.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/impl/x86/sse41.h Fri Apr 25 17:40:33 2025 -0400 @@ -27,13 +27,7 @@ #include "vec/vec.h" -extern const vint8x16_impl vint8x16_impl_sse41; -extern const vint16x8_impl vint16x8_impl_sse41; -extern const vint32x4_impl vint32x4_impl_sse41; -extern const vint64x2_impl vint64x2_impl_sse41; -extern const vuint8x16_impl vuint8x16_impl_sse41; -extern const vuint16x8_impl vuint16x8_impl_sse41; +extern const vint32x4_impl vint32x4_impl_sse41; extern const vuint32x4_impl vuint32x4_impl_sse41; -extern const vuint64x2_impl vuint64x2_impl_sse41; #endif /* VEC_IMPL_X86_SSE41_H_ */
--- a/include/vec/impl/x86/sse42.h Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#ifndef VEC_IMPL_X86_SSE42_H_ -#define VEC_IMPL_X86_SSE42_H_ - -#include "vec/vec.h" - -extern const vint64x2_impl vint64x2_impl_sse42; -extern const vuint64x2_impl vuint64x2_impl_sse42; - -#endif /* VEC_IMPL_X86_SSE42_H_ */
--- a/include/vec/vec.h Fri Apr 25 17:40:30 2025 -0400 +++ b/include/vec/vec.h Fri Apr 25 17:40:33 2025 -0400 @@ -84,16 +84,6 @@ [!!sizeof (struct { int __error_if_negative: (x) ? 2 : -1; })] #endif -#if VEC_GNUC_HAS_ATTRIBUTE(__always_inline__, 3, 1, 1) -# define VEC_ALWAYS_INLINE __attribute__((__always_inline__)) -#elif VEC_MSVC_ATLEAST(12, 0, 0) -# define VEC_ALWAYS_INLINE __forceinline -#else -# define VEC_ALWAYS_INLINE -#endif - -#define VEC_FUNC_IMPL static inline VEC_ALWAYS_INLINE - ////////////////////////////////////////////////////////////////////////////// // Detect compiler SIMD support @@ -685,6 +675,7 @@ v##sign##int##bits##x##size (*band)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ v##sign##int##bits##x##size (*bor)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ v##sign##int##bits##x##size (*bxor)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + v##sign##int##bits##x##size (*bnot)(v##sign##int##bits##x##size vec); \ v##sign##int##bits##x##size (*lshift)(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ v##sign##int##bits##x##size (*rshift)(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ v##sign##int##bits##x##size (*lrshift)(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ @@ -693,8 +684,6 @@ v##sign##int##bits##x##size (*cmpeq)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ v##sign##int##bits##x##size (*cmpge)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ v##sign##int##bits##x##size (*cmpgt)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ - v##sign##int##bits##x##size (*min)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ - v##sign##int##bits##x##size (*max)(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ } v##sign##int##bits##x##size##_impl; #define VEC_DEFINE_IMPL_STRUCT(bits, size) \ @@ -734,56 +723,53 @@ #undef VEC_DEFINE_IMPL_STRUCT #undef VEC_DEFINE_IMPL_STRUCT_SIGN -/* these are generally read only, unless you REALLY know - * exactly what you're doing. */ - // 16-bit -extern vint8x2_impl vint8x2_impl_cpu; -extern vuint8x2_impl vuint8x2_impl_cpu; +extern const vint8x2_impl *vint8x2_impl_cpu; +extern const vuint8x2_impl *vuint8x2_impl_cpu; // 32-bit -extern vint8x4_impl vint8x4_impl_cpu; -extern vuint8x4_impl vuint8x4_impl_cpu; -extern vint16x2_impl vint16x2_impl_cpu; -extern vuint16x2_impl vuint16x2_impl_cpu; +extern const vint8x4_impl *vint8x4_impl_cpu; +extern const vuint8x4_impl *vuint8x4_impl_cpu; +extern const vint16x2_impl *vint16x2_impl_cpu; +extern const vuint16x2_impl *vuint16x2_impl_cpu; // 64-bit -extern vint8x8_impl vint8x8_impl_cpu; -extern vuint8x8_impl vuint8x8_impl_cpu; -extern vint16x4_impl vint16x4_impl_cpu; -extern vuint16x4_impl vuint16x4_impl_cpu; -extern vint32x2_impl vint32x2_impl_cpu; -extern vuint32x2_impl vuint32x2_impl_cpu; +extern const vint8x8_impl *vint8x8_impl_cpu; +extern const vuint8x8_impl *vuint8x8_impl_cpu; +extern const vint16x4_impl *vint16x4_impl_cpu; +extern const vuint16x4_impl *vuint16x4_impl_cpu; +extern const vint32x2_impl *vint32x2_impl_cpu; +extern const vuint32x2_impl *vuint32x2_impl_cpu; // 128-bit -extern vint8x16_impl vint8x16_impl_cpu; -extern vuint8x16_impl vuint8x16_impl_cpu; -extern vint16x8_impl vint16x8_impl_cpu; -extern vuint16x8_impl vuint16x8_impl_cpu; -extern vint32x4_impl vint32x4_impl_cpu; -extern vuint32x4_impl vuint32x4_impl_cpu; -extern vint64x2_impl vint64x2_impl_cpu; -extern vuint64x2_impl vuint64x2_impl_cpu; +extern const vint8x16_impl *vint8x16_impl_cpu; +extern const vuint8x16_impl *vuint8x16_impl_cpu; +extern const vint16x8_impl *vint16x8_impl_cpu; +extern const vuint16x8_impl *vuint16x8_impl_cpu; +extern const vint32x4_impl *vint32x4_impl_cpu; +extern const vuint32x4_impl *vuint32x4_impl_cpu; +extern const vint64x2_impl *vint64x2_impl_cpu; +extern const vuint64x2_impl *vuint64x2_impl_cpu; // 256-bit -extern vint8x32_impl vint8x32_impl_cpu; -extern vuint8x32_impl vuint8x32_impl_cpu; -extern vint16x16_impl vint16x16_impl_cpu; -extern vuint16x16_impl vuint16x16_impl_cpu; -extern vint32x8_impl vint32x8_impl_cpu; -extern vuint32x8_impl vuint32x8_impl_cpu; -extern vint64x4_impl vint64x4_impl_cpu; -extern vuint64x4_impl vuint64x4_impl_cpu; +extern const vint8x32_impl *vint8x32_impl_cpu; +extern const vuint8x32_impl *vuint8x32_impl_cpu; +extern const vint16x16_impl *vint16x16_impl_cpu; +extern const vuint16x16_impl *vuint16x16_impl_cpu; +extern const vint32x8_impl *vint32x8_impl_cpu; +extern const vuint32x8_impl *vuint32x8_impl_cpu; +extern const vint64x4_impl *vint64x4_impl_cpu; +extern const vuint64x4_impl *vuint64x4_impl_cpu; // 512-bit -extern vint8x64_impl vint8x64_impl_cpu; -extern vuint8x64_impl vuint8x64_impl_cpu; -extern vint16x32_impl vint16x32_impl_cpu; -extern vuint16x32_impl vuint16x32_impl_cpu; -extern vint32x16_impl vint32x16_impl_cpu; -extern vuint32x16_impl vuint32x16_impl_cpu; -extern vint64x8_impl vint64x8_impl_cpu; -extern vuint64x8_impl vuint64x8_impl_cpu; +extern const vint8x64_impl *vint8x64_impl_cpu; +extern const vuint8x64_impl *vuint8x64_impl_cpu; +extern const vint16x32_impl *vint16x32_impl_cpu; +extern const vuint16x32_impl *vuint16x32_impl_cpu; +extern const vint32x16_impl *vint32x16_impl_cpu; +extern const vuint32x16_impl *vuint32x16_impl_cpu; +extern const vint64x8_impl *vint64x8_impl_cpu; +extern const vuint64x8_impl *vuint64x8_impl_cpu; ////////////////////////////////////////////////////////////////////////////// // declared as inline for ! performance : ) @@ -791,122 +777,112 @@ #define VEC_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_splat(vec_##sign##int##bits x) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.splat(x); \ + return v##sign##int##bits##x##size##_impl_cpu->splat(x); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_load_aligned(const vec_##sign##int##bits in[size]) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.load_aligned(in); \ + return v##sign##int##bits##x##size##_impl_cpu->load_aligned(in); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_load(const vec_##sign##int##bits in[size]) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.load(in); \ + return v##sign##int##bits##x##size##_impl_cpu->load(in); \ } \ \ inline void v##sign##int##bits##x##size##_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ - v##sign##int##bits##x##size##_impl_cpu.store_aligned(vec, out); \ + v##sign##int##bits##x##size##_impl_cpu->store_aligned(vec, out); \ } \ \ inline void v##sign##int##bits##x##size##_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.store(vec, out); \ + return v##sign##int##bits##x##size##_impl_cpu->store(vec, out); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.add(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->add(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.sub(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->sub(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.mul(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->mul(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.div(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->div(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.avg(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->avg(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.band(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->band(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.bor(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->bor(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.bxor(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->bxor(vec1, vec2); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size vec) \ + inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size vec) \ { \ - return v##sign##int##bits##x##size##_xor(vec, v##sign##int##bits##x##size##_splat((vec_##sign##int##bits)VEC_UINT##bits##_MAX)); \ + return v##sign##int##bits##x##size##_impl_cpu->bnot(vec); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.cmplt(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->cmplt(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.cmple(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->cmple(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.cmpeq(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->cmpeq(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.cmpge(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->cmpge(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.cmpgt(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->cmpgt(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.lshift(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->lshift(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.rshift(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->rshift(vec1, vec2); \ } \ \ inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_impl_cpu.lrshift(vec1, vec2); \ - } \ - \ - inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - return v##sign##int##bits##x##size##_impl_cpu.min(vec1, vec2); \ - } \ - \ - inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - return v##sign##int##bits##x##size##_impl_cpu.max(vec1, vec2); \ + return v##sign##int##bits##x##size##_impl_cpu->lrshift(vec1, vec2); \ } #define VEC_DEFINE_OPERATIONS(bits, size) \
--- a/src/cpu.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/cpu.c Fri Apr 25 17:40:33 2025 -0400 @@ -362,29 +362,7 @@ if (vec_CPU_OSSavesYMM && (vec_CPU_CPUIDMaxFunction >= 7)) { int a, b, c, d; VEC_CPU_CPUID(7, a, b, c, d); - return b & 0x00010000; - (void)a, (void)c, (void)d; - } - return 0; -} - -static inline int vec_CPU_have_AVX512DQ(void) -{ - if (vec_CPU_OSSavesYMM && (vec_CPU_CPUIDMaxFunction >= 7)) { - int a, b, c, d; - VEC_CPU_CPUID(7, a, b, c, d); - return b & 0x00020000; - (void)a, (void)c, (void)d; - } - return 0; -} - -static inline int vec_CPU_have_AVX512BW(void) -{ - if (vec_CPU_OSSavesYMM && (vec_CPU_CPUIDMaxFunction >= 7)) { - int a, b, c, d; - VEC_CPU_CPUID(7, a, b, c, d); - return b & 0x40000000; + return b & 0x00000020; (void)a, (void)c, (void)d; } return 0; @@ -513,10 +491,6 @@ vec_CPU_features |= VEC_CPU_HAS_AVX2; if (vec_CPU_have_AVX512F()) vec_CPU_features |= VEC_CPU_HAS_AVX512F; - if (vec_CPU_have_AVX512BW()) - vec_CPU_features |= VEC_CPU_HAS_AVX512BW; - if (vec_CPU_have_AVX512DQ()) - vec_CPU_features |= VEC_CPU_HAS_AVX512DQ; if (vec_CPU_have_NEON()) vec_CPU_features |= VEC_CPU_HAS_NEON; }
--- a/src/impl/arm/neon.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/arm/neon.c Fri Apr 25 17:40:33 2025 -0400 @@ -39,19 +39,19 @@ VEC_STATIC_ASSERT(VEC_ALIGNOF(sign##int##bits##x##size##_t) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ VEC_STATIC_ASSERT(sizeof(sign##int##bits##x##size##_t) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.neon = vld1_##sign##bits(in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ vstore_lane_##bits(sign, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->neon, out); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -60,7 +60,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -69,7 +69,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -78,7 +78,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -87,7 +87,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -96,7 +96,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -105,7 +105,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -114,18 +114,29 @@ return vec1d->vec; \ } \ \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \ - .load = v##sign##int##bits##x##size##_neon_load_aligned, \ - .load_aligned = v##sign##int##bits##x##size##_neon_load_aligned, \ - .store = v##sign##int##bits##x##size##_neon_store_aligned, \ - .store_aligned = v##sign##int##bits##x##size##_neon_store_aligned, \ - .add = v##sign##int##bits##x##size##_neon_add, \ - .sub = v##sign##int##bits##x##size##_neon_sub, \ - .mul = v##sign##int##bits##x##size##_neon_mul, \ - .band = v##sign##int##bits##x##size##_neon_and, \ - .bor = v##sign##int##bits##x##size##_neon_or, \ - .bxor = v##sign##int##bits##x##size##_neon_xor, \ - .lshift = v##sign##int##bits##x##size##_neon_lshift, \ + static v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \ + v##sign##int##bits##x##size##_fallback_splat, \ + v##sign##int##bits##x##size##_neon_load_aligned, \ + v##sign##int##bits##x##size##_neon_load_aligned, \ + v##sign##int##bits##x##size##_neon_store_aligned, \ + v##sign##int##bits##x##size##_neon_store_aligned, \ + v##sign##int##bits##x##size##_neon_add, \ + v##sign##int##bits##x##size##_neon_sub, \ + v##sign##int##bits##x##size##_neon_mul, \ + v##sign##int##bits##x##size##_fallback_div, \ + v##sign##int##bits##x##size##_fallback_avg, \ + v##sign##int##bits##x##size##_neon_and, \ + v##sign##int##bits##x##size##_neon_or, \ + v##sign##int##bits##x##size##_neon_xor, \ + v##sign##int##bits##x##size##_fallback_not, \ + v##sign##int##bits##x##size##_neon_lshift, \ + v##sign##int##bits##x##size##_fallback_rshift, \ + v##sign##int##bits##x##size##_fallback_lrshift, \ + v##sign##int##bits##x##size##_fallback_cmplt, \ + v##sign##int##bits##x##size##_fallback_cmple, \ + v##sign##int##bits##x##size##_fallback_cmpeq, \ + v##sign##int##bits##x##size##_fallback_cmpge, \ + v##sign##int##bits##x##size##_fallback_cmpgt, \ }; #define VEC_DEFINE_OPERATIONS(bits, size) \ @@ -233,7 +244,7 @@ // NEON doesn't have native 64-bit multiplication, so we have // to do it ourselves -VEC_FUNC_IMPL int64x2_t vmulq_s64(const int64x2_t a, const int64x2_t b) +static inline int64x2_t vmulq_s64(const int64x2_t a, const int64x2_t b) { const uint32x2_t ac = vreinterpret_u32_s32(vmovn_s64(a)); const uint32x2_t pr = vreinterpret_u32_s32(vmovn_s64(b)); @@ -243,7 +254,7 @@ return vreinterpretq_s64_u64(vmlal_u32(vreinterpretq_u64_s64(vshlq_n_s64(vreinterpretq_s64_u64(vpaddlq_u32(vreinterpretq_u32_s32(hi))), 32)), ac, pr)); } -VEC_FUNC_IMPL uint64x2_t vmulq_u64(const uint64x2_t a, const uint64x2_t b) +static inline uint64x2_t vmulq_u64(const uint64x2_t a, const uint64x2_t b) { const uint32x2_t ac = vmovn_u64(a); const uint32x2_t pr = vmovn_u64(b);
--- a/src/impl/fallback.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/fallback.c Fri Apr 25 17:40:33 2025 -0400 @@ -1,27 +1,3 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - #include "vec/impl/fallback.h" #include <string.h> @@ -31,8 +7,8 @@ // memory is unknown or yields incorrect results from the generic functions. // This is *extremely* unlikely; for x86 the layout is exactly the same in // memory as the generic functions (i.e. it is literally stored as an array of -// integers). This is also true for AltiVec. This is likely true for NEON as well, -// but that isn't tested for now. +// integers). This is likely true for AltiVec and NEON as well, but those +// aren't tested for now. #define VEC_FALLBACK_OPERATION(op, sign, csign, bits, size) \ do { \
--- a/src/impl/gcc.c Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,517 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#include "vec/impl/gcc.h" - -// ----------------------------------------------------------------- - -#define VEC_GENERIC_OPERATION(op, sign, csign, bits, size) \ - do { \ - for (int i = 0; i < size; i++) \ - ((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] = (op); \ - \ - return vec1; \ - } while (0) - -#define VEC_GENERIC_BUILTIN_OPERATION(op, sign, csign, bits, size) \ - VEC_GENERIC_OPERATION(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] op ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i], sign, csign, bits, size) - -#define VEC_GENERIC_CMP(op, sign, csign, bits, size) \ - VEC_GENERIC_OPERATION((((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] op ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]) ? VEC_UINT##bits##_MAX : 0, sign, csign, bits, size) - -// TODO implement these so we don't waste stack space by doing the -// generics -#define VEC_GENERIC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - vec_##sign##int##bits impl[size]; \ - }; \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \ - { \ - v##sign##int##bits##x##size vec; \ - for (int i = 0; i < size; i++) \ - ((union v##sign##int##bits##x##size##_impl_data *)&vec)->impl[i] = x; \ - return vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \ - { \ - v##sign##int##bits##x##size vec; \ - memcpy(&vec, in, sizeof(vec_##sign##int##bits) * size); \ - return vec; \ - } \ - \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ - { \ - memcpy(out, &vec, sizeof(vec_##sign##int##bits) * size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_BUILTIN_OPERATION(+, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_BUILTIN_OPERATION(-, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_BUILTIN_OPERATION(*, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_OPERATION(((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i] ? (((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] / ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]) : 0, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - for (int i = 0; i < size; i++) \ - vec1d->impl[i] = vec_##sign##avg(vec1d->impl[i], vec2d->impl[i]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_BUILTIN_OPERATION(&, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_BUILTIN_OPERATION(|, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_BUILTIN_OPERATION(^, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_CMP(<, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - return v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size##_cmpgt(vec1, vec2)); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_CMP(==, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - return v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size##_cmplt(vec1, vec2)); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - VEC_GENERIC_CMP(>, sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - VEC_GENERIC_OPERATION(vec_##sign##lshift(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i], ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - VEC_GENERIC_OPERATION(vec_##sign##rshift(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i], ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - VEC_GENERIC_OPERATION(vec_lrshift((vec_uint##bits)(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i]), ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - v##sign##int##bits##x##size cmplt = v##sign##int##bits##x##size##_cmplt(vec1, vec2); \ - \ - v##sign##int##bits##x##size a = v##sign##int##bits##x##size##_and(vec1, cmplt); \ - v##sign##int##bits##x##size b = v##sign##int##bits##x##size##_and(vec2, v##sign##int##bits##x##size##_not(cmplt)); \ - \ - return v##sign##int##bits##x##size##_or(a, b); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - v##sign##int##bits##x##size cmplt = v##sign##int##bits##x##size##_cmpgt(vec1, vec2); \ - \ - v##sign##int##bits##x##size a = v##sign##int##bits##x##size##_and(vec1, cmplt); \ - v##sign##int##bits##x##size b = v##sign##int##bits##x##size##_and(vec2, v##sign##int##bits##x##size##_not(cmplt)); \ - \ - return v##sign##int##bits##x##size##_or(a, b); \ - } \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_generic = { \ - .splat = v##sign##int##bits##x##size##_generic_splat, \ - .load_aligned = v##sign##int##bits##x##size##_generic_load_aligned, \ - .load = v##sign##int##bits##x##size##_generic_load_aligned, \ - .store_aligned = v##sign##int##bits##x##size##_generic_store_aligned, \ - .store = v##sign##int##bits##x##size##_generic_store_aligned, \ - .add = v##sign##int##bits##x##size##_generic_add, \ - .sub = v##sign##int##bits##x##size##_generic_sub, \ - .mul = v##sign##int##bits##x##size##_generic_mul, \ - .div = v##sign##int##bits##x##size##_generic_div, \ - .avg = v##sign##int##bits##x##size##_generic_avg, \ - .band = v##sign##int##bits##x##size##_generic_and, \ - .bor = v##sign##int##bits##x##size##_generic_or, \ - .bxor = v##sign##int##bits##x##size##_generic_xor, \ - .lshift = v##sign##int##bits##x##size##_generic_lshift, \ - .rshift = v##sign##int##bits##x##size##_generic_rshift, \ - .lrshift = v##sign##int##bits##x##size##_generic_lrshift, \ - .cmplt = v##sign##int##bits##x##size##_generic_cmplt, \ - .cmple = v##sign##int##bits##x##size##_generic_cmple, \ - .cmpeq = v##sign##int##bits##x##size##_generic_cmpeq, \ - .cmpge = v##sign##int##bits##x##size##_generic_cmpge, \ - .cmpgt = v##sign##int##bits##x##size##_generic_cmpgt, \ - .min = v##sign##int##bits##x##size##_generic_min, \ - .max = v##sign##int##bits##x##size##_generic_max, \ - }; - -#define VEC_GENERIC_DEFINE_OPERATIONS(bits, size) \ - VEC_GENERIC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \ - VEC_GENERIC_DEFINE_OPERATIONS_SIGN( , , bits, size) - -VEC_GENERIC_DEFINE_OPERATIONS(8, 2) -VEC_GENERIC_DEFINE_OPERATIONS(16, 2) -VEC_GENERIC_DEFINE_OPERATIONS(32, 2) -VEC_GENERIC_DEFINE_OPERATIONS(64, 2) - -#undef VEC_GENERIC_DEFINE_OPERATIONS -#undef VEC_GENERIC_DEFINE_OPERATIONS_SIGN - -// ----------------------------------------------------------------- -// now we can just keep doubling the same implementation - -#define VEC_GENERIC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size, halfsize) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - v##sign##int##bits##x##halfsize impl[2]; \ - }; \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \ - { \ - union v##sign##int##bits##x##size##_impl_data vec; \ - vec.impl[0] = v##sign##int##bits##x##halfsize##_splat(x); \ - vec.impl[1] = v##sign##int##bits##x##halfsize##_splat(x); \ - return vec.vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \ - { \ - union v##sign##int##bits##x##size##_impl_data vec; \ - vec.impl[0] = v##sign##int##bits##x##halfsize##_load_aligned(in); \ - vec.impl[1] = v##sign##int##bits##x##halfsize##_load_aligned(in + halfsize); \ - return vec.vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load(const vec_##sign##int##bits in[size]) \ - { \ - union v##sign##int##bits##x##size##_impl_data vec; \ - vec.impl[0] = v##sign##int##bits##x##halfsize##_load(in); \ - vec.impl[1] = v##sign##int##bits##x##halfsize##_load(in + halfsize); \ - return vec.vec; \ - } \ - \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vecd = (union v##sign##int##bits##x##size##_impl_data *)&vec; \ - \ - v##sign##int##bits##x##halfsize##_store_aligned(vecd->impl[0], out); \ - v##sign##int##bits##x##halfsize##_store_aligned(vecd->impl[1], out + halfsize); \ - } \ - \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vecd = (union v##sign##int##bits##x##size##_impl_data *)&vec; \ - \ - v##sign##int##bits##x##halfsize##_store(vecd->impl[0], out); \ - v##sign##int##bits##x##halfsize##_store(vecd->impl[1], out + halfsize); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_add(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_add(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_sub(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_sub(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_mul(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_mul(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_div(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_div(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_avg(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_avg(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_and(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_and(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_or(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_or(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_xor(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_xor(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_lshift(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_lshift(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_rshift(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_rshift(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_lrshift(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_lrshift(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmplt(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmplt(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmple(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmple(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmpeq(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmpeq(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmpge(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmpge(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmpgt(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmpgt(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_min(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_min(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_max(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_max(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_generic = { \ - .splat = v##sign##int##bits##x##size##_generic_splat, \ - .load_aligned = v##sign##int##bits##x##size##_generic_load_aligned, \ - .load = v##sign##int##bits##x##size##_generic_load, \ - .store_aligned = v##sign##int##bits##x##size##_generic_store_aligned, \ - .store = v##sign##int##bits##x##size##_generic_store, \ - .add = v##sign##int##bits##x##size##_generic_add, \ - .sub = v##sign##int##bits##x##size##_generic_sub, \ - .mul = v##sign##int##bits##x##size##_generic_mul, \ - .div = v##sign##int##bits##x##size##_generic_div, \ - .avg = v##sign##int##bits##x##size##_generic_avg, \ - .band = v##sign##int##bits##x##size##_generic_and, \ - .bor = v##sign##int##bits##x##size##_generic_or, \ - .bxor = v##sign##int##bits##x##size##_generic_xor, \ - .lshift = v##sign##int##bits##x##size##_generic_lshift, \ - .rshift = v##sign##int##bits##x##size##_generic_rshift, \ - .lrshift = v##sign##int##bits##x##size##_generic_lrshift, \ - .cmplt = v##sign##int##bits##x##size##_generic_cmplt, \ - .cmple = v##sign##int##bits##x##size##_generic_cmple, \ - .cmpeq = v##sign##int##bits##x##size##_generic_cmpeq, \ - .cmpge = v##sign##int##bits##x##size##_generic_cmpge, \ - .cmpgt = v##sign##int##bits##x##size##_generic_cmpgt, \ - .min = v##sign##int##bits##x##size##_generic_min, \ - .max = v##sign##int##bits##x##size##_generic_max, \ - }; - -#define VEC_GENERIC_DEFINE_OPERATIONS(bits, size, halfsize) \ - VEC_GENERIC_DEFINE_OPERATIONS_SIGN(u, U, bits, size, halfsize) \ - VEC_GENERIC_DEFINE_OPERATIONS_SIGN( , , bits, size, halfsize) - -// 32-bit -VEC_GENERIC_DEFINE_OPERATIONS(8, 4, 2) - -// 64-bit -VEC_GENERIC_DEFINE_OPERATIONS(8, 8, 4) -VEC_GENERIC_DEFINE_OPERATIONS(16, 4, 2) - -// 128-bit -VEC_GENERIC_DEFINE_OPERATIONS(8, 16, 8) -VEC_GENERIC_DEFINE_OPERATIONS(16, 8, 4) -VEC_GENERIC_DEFINE_OPERATIONS(32, 4, 2) - -// 256-bit -VEC_GENERIC_DEFINE_OPERATIONS(8, 32, 16) -VEC_GENERIC_DEFINE_OPERATIONS(16, 16, 8) -VEC_GENERIC_DEFINE_OPERATIONS(32, 8, 4) -VEC_GENERIC_DEFINE_OPERATIONS(64, 4, 2) - -// 512-bit -VEC_GENERIC_DEFINE_OPERATIONS(8, 64, 32) -VEC_GENERIC_DEFINE_OPERATIONS(16, 32, 16) -VEC_GENERIC_DEFINE_OPERATIONS(32, 16, 8) -VEC_GENERIC_DEFINE_OPERATIONS(64, 8, 4) - -#undef VEC_GENERIC_DEFINE_OPERATIONS -#undef VEC_GENERIC_DEFINE_OPERATIONS_SIGN
--- a/src/impl/generic.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/generic.c Fri Apr 25 17:40:33 2025 -0400 @@ -1,27 +1,3 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - #include "vec/impl/generic.h" #include <string.h> @@ -50,7 +26,7 @@ vec_##sign##int##bits impl[size]; \ }; \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \ { \ v##sign##int##bits##x##size vec; \ for (int i = 0; i < size; i++) \ @@ -58,39 +34,39 @@ return vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \ { \ v##sign##int##bits##x##size vec; \ memcpy(&vec, in, sizeof(vec_##sign##int##bits) * size); \ return vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ memcpy(out, &vec, sizeof(vec_##sign##int##bits) * size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_BUILTIN_OPERATION(+, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_BUILTIN_OPERATION(-, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_BUILTIN_OPERATION(*, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_OPERATION(((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i] ? (((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] / ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]) : 0, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -101,105 +77,89 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_BUILTIN_OPERATION(&, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_BUILTIN_OPERATION(|, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_BUILTIN_OPERATION(^, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_not(v##sign##int##bits##x##size vec) \ + { \ + return v##sign##int##bits##x##size##_generic_xor(vec, v##sign##int##bits##x##size##_generic_splat((vec_##sign##int##bits)VEC_UINT##bits##_MAX)); \ + } \ + \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_CMP(<, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size##_cmpgt(vec1, vec2)); \ + VEC_GENERIC_CMP(<=, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_CMP(==, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ - return v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size##_cmplt(vec1, vec2)); \ + VEC_GENERIC_CMP(>=, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_GENERIC_CMP(>, sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ VEC_GENERIC_OPERATION(vec_##sign##lshift(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i], ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ VEC_GENERIC_OPERATION(vec_##sign##rshift(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i], ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ VEC_GENERIC_OPERATION(vec_lrshift((vec_uint##bits)(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i]), ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - v##sign##int##bits##x##size cmplt = v##sign##int##bits##x##size##_cmplt(vec1, vec2); \ - \ - v##sign##int##bits##x##size a = v##sign##int##bits##x##size##_and(vec1, cmplt); \ - v##sign##int##bits##x##size b = v##sign##int##bits##x##size##_and(vec2, v##sign##int##bits##x##size##_not(cmplt)); \ - \ - return v##sign##int##bits##x##size##_or(a, b); \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - v##sign##int##bits##x##size cmplt = v##sign##int##bits##x##size##_cmpgt(vec1, vec2); \ - \ - v##sign##int##bits##x##size a = v##sign##int##bits##x##size##_and(vec1, cmplt); \ - v##sign##int##bits##x##size b = v##sign##int##bits##x##size##_and(vec2, v##sign##int##bits##x##size##_not(cmplt)); \ - \ - return v##sign##int##bits##x##size##_or(a, b); \ - } \ - \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_generic = { \ - .splat = v##sign##int##bits##x##size##_generic_splat, \ - .load_aligned = v##sign##int##bits##x##size##_generic_load_aligned, \ - .load = v##sign##int##bits##x##size##_generic_load_aligned, \ - .store_aligned = v##sign##int##bits##x##size##_generic_store_aligned, \ - .store = v##sign##int##bits##x##size##_generic_store_aligned, \ - .add = v##sign##int##bits##x##size##_generic_add, \ - .sub = v##sign##int##bits##x##size##_generic_sub, \ - .mul = v##sign##int##bits##x##size##_generic_mul, \ - .div = v##sign##int##bits##x##size##_generic_div, \ - .avg = v##sign##int##bits##x##size##_generic_avg, \ - .band = v##sign##int##bits##x##size##_generic_and, \ - .bor = v##sign##int##bits##x##size##_generic_or, \ - .bxor = v##sign##int##bits##x##size##_generic_xor, \ - .lshift = v##sign##int##bits##x##size##_generic_lshift, \ - .rshift = v##sign##int##bits##x##size##_generic_rshift, \ - .lrshift = v##sign##int##bits##x##size##_generic_lrshift, \ - .cmplt = v##sign##int##bits##x##size##_generic_cmplt, \ - .cmple = v##sign##int##bits##x##size##_generic_cmple, \ - .cmpeq = v##sign##int##bits##x##size##_generic_cmpeq, \ - .cmpge = v##sign##int##bits##x##size##_generic_cmpge, \ - .cmpgt = v##sign##int##bits##x##size##_generic_cmpgt, \ - .min = v##sign##int##bits##x##size##_generic_min, \ - .max = v##sign##int##bits##x##size##_generic_max, \ + v##sign##int##bits##x##size##_generic_splat, \ + v##sign##int##bits##x##size##_generic_load_aligned, \ + v##sign##int##bits##x##size##_generic_load_aligned, \ + v##sign##int##bits##x##size##_generic_store_aligned, \ + v##sign##int##bits##x##size##_generic_store_aligned, \ + v##sign##int##bits##x##size##_generic_add, \ + v##sign##int##bits##x##size##_generic_sub, \ + v##sign##int##bits##x##size##_generic_mul, \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_generic_avg, \ + v##sign##int##bits##x##size##_generic_and, \ + v##sign##int##bits##x##size##_generic_or, \ + v##sign##int##bits##x##size##_generic_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_generic_lshift, \ + v##sign##int##bits##x##size##_generic_rshift, \ + v##sign##int##bits##x##size##_generic_lrshift, \ + v##sign##int##bits##x##size##_generic_cmplt, \ + v##sign##int##bits##x##size##_generic_cmple, \ + v##sign##int##bits##x##size##_generic_cmpeq, \ + v##sign##int##bits##x##size##_generic_cmpge, \ + v##sign##int##bits##x##size##_generic_cmpgt, \ }; #define VEC_GENERIC_DEFINE_OPERATIONS(bits, size) \ @@ -223,7 +183,7 @@ v##sign##int##bits##x##halfsize impl[2]; \ }; \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.impl[0] = v##sign##int##bits##x##halfsize##_splat(x); \ @@ -231,7 +191,7 @@ return vec.vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.impl[0] = v##sign##int##bits##x##halfsize##_load_aligned(in); \ @@ -239,7 +199,7 @@ return vec.vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load(const vec_##sign##int##bits in[size]) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.impl[0] = v##sign##int##bits##x##halfsize##_load(in); \ @@ -247,7 +207,7 @@ return vec.vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ union v##sign##int##bits##x##size##_impl_data *vecd = (union v##sign##int##bits##x##size##_impl_data *)&vec; \ \ @@ -255,7 +215,7 @@ v##sign##int##bits##x##halfsize##_store_aligned(vecd->impl[1], out + halfsize); \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + void v##sign##int##bits##x##size##_generic_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ union v##sign##int##bits##x##size##_impl_data *vecd = (union v##sign##int##bits##x##size##_impl_data *)&vec; \ \ @@ -263,7 +223,7 @@ v##sign##int##bits##x##halfsize##_store(vecd->impl[1], out + halfsize); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -274,7 +234,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -285,7 +245,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -296,7 +256,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -307,7 +267,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -318,7 +278,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -329,7 +289,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -340,7 +300,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -351,7 +311,17 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_not(v##sign##int##bits##x##size vec1) \ + { \ + union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ + \ + vec1d->impl[0] = v##sign##int##bits##x##halfsize##_not(vec1d->impl[0]); \ + vec1d->impl[1] = v##sign##int##bits##x##halfsize##_not(vec1d->impl[1]); \ + \ + return vec1d->vec; \ + } \ + \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -362,7 +332,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -373,7 +343,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -384,7 +354,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -395,7 +365,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -406,7 +376,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -417,7 +387,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -428,7 +398,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -439,52 +409,29 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_min(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_min(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->impl[0] = v##sign##int##bits##x##halfsize##_max(vec1d->impl[0], vec2d->impl[0]); \ - vec1d->impl[1] = v##sign##int##bits##x##halfsize##_max(vec1d->impl[1], vec2d->impl[1]); \ - \ - return vec1d->vec; \ - } \ - \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_generic = { \ - .splat = v##sign##int##bits##x##size##_generic_splat, \ - .load_aligned = v##sign##int##bits##x##size##_generic_load_aligned, \ - .load = v##sign##int##bits##x##size##_generic_load, \ - .store_aligned = v##sign##int##bits##x##size##_generic_store_aligned, \ - .store = v##sign##int##bits##x##size##_generic_store, \ - .add = v##sign##int##bits##x##size##_generic_add, \ - .sub = v##sign##int##bits##x##size##_generic_sub, \ - .mul = v##sign##int##bits##x##size##_generic_mul, \ - .div = v##sign##int##bits##x##size##_generic_div, \ - .avg = v##sign##int##bits##x##size##_generic_avg, \ - .band = v##sign##int##bits##x##size##_generic_and, \ - .bor = v##sign##int##bits##x##size##_generic_or, \ - .bxor = v##sign##int##bits##x##size##_generic_xor, \ - .lshift = v##sign##int##bits##x##size##_generic_lshift, \ - .rshift = v##sign##int##bits##x##size##_generic_rshift, \ - .lrshift = v##sign##int##bits##x##size##_generic_lrshift, \ - .cmplt = v##sign##int##bits##x##size##_generic_cmplt, \ - .cmple = v##sign##int##bits##x##size##_generic_cmple, \ - .cmpeq = v##sign##int##bits##x##size##_generic_cmpeq, \ - .cmpge = v##sign##int##bits##x##size##_generic_cmpge, \ - .cmpgt = v##sign##int##bits##x##size##_generic_cmpgt, \ - .min = v##sign##int##bits##x##size##_generic_min, \ - .max = v##sign##int##bits##x##size##_generic_max, \ + v##sign##int##bits##x##size##_generic_splat, \ + v##sign##int##bits##x##size##_generic_load_aligned, \ + v##sign##int##bits##x##size##_generic_load, \ + v##sign##int##bits##x##size##_generic_store_aligned, \ + v##sign##int##bits##x##size##_generic_store, \ + v##sign##int##bits##x##size##_generic_add, \ + v##sign##int##bits##x##size##_generic_sub, \ + v##sign##int##bits##x##size##_generic_mul, \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_generic_avg, \ + v##sign##int##bits##x##size##_generic_and, \ + v##sign##int##bits##x##size##_generic_or, \ + v##sign##int##bits##x##size##_generic_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_generic_lshift, \ + v##sign##int##bits##x##size##_generic_rshift, \ + v##sign##int##bits##x##size##_generic_lrshift, \ + v##sign##int##bits##x##size##_generic_cmplt, \ + v##sign##int##bits##x##size##_generic_cmple, \ + v##sign##int##bits##x##size##_generic_cmpeq, \ + v##sign##int##bits##x##size##_generic_cmpge, \ + v##sign##int##bits##x##size##_generic_cmpgt, \ }; #define VEC_GENERIC_DEFINE_OPERATIONS(bits, size, halfsize) \
--- a/src/impl/ppc/altivec.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/ppc/altivec.c Fri Apr 25 17:40:33 2025 -0400 @@ -48,7 +48,7 @@ /* GCC 4.2.1 on Mac OS X doesn't have these for some reason */ #ifdef vec_mul # define VEC_ALTIVEC_DEFINE_MUL(sign, csign, bits, size) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -57,34 +57,34 @@ return vec1d->vec; \ } # define VEC_ALTIVEC_STRUCT_MUL(sign, csign, bits, size) \ - .mul = v##sign##int##bits##x##size##_altivec_mul, + v##sign##int##bits##x##size##_altivec_mul #else # define VEC_ALTIVEC_DEFINE_MUL(sign, csign, bits, size) # define VEC_ALTIVEC_STRUCT_MUL(sign, csign, bits, size) \ - /* nothing */ + v##sign##int##bits##x##size##_generic_mul #endif #ifdef vec_splats # define VEC_ALTIVEC_DEFINE_SPLAT(sign, csign, bits, size) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_splat(vec_##sign##int##bits x) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_splat(vec_##sign##int##bits x) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.altivec = vec_splats(x); \ return vec.vec; \ } # define VEC_ALTIVEC_STRUCT_SPLAT(sign, csign, bits, size) \ - .splat = v##sign##int##bits##x##size##_altivec_splat, + v##sign##int##bits##x##size##_altivec_splat #else # define VEC_ALTIVEC_DEFINE_SPLAT(sign, csign, bits, size) # define VEC_ALTIVEC_STRUCT_SPLAT(sign, csign, bits, size) \ - /* nothing */ + v##sign##int##bits##x##size##_generic_splat #endif #define VEC_ALTIVEC_uRSHIFT vec_sr #define VEC_ALTIVEC_RSHIFT vec_sra #define VEC_ALTIVEC_DEFINE_uLRSHIFT(sign, csign, bits, size) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_lrshift(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_lrshift(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -93,10 +93,11 @@ return vec1d->vec; \ } #define VEC_ALTIVEC_STRUCT_uLRSHIFT(sign, csign, bits, size) \ - .lrshift = v##sign##int##bits##x##size##_altivec_lrshift, + v##sign##int##bits##x##size##_altivec_lrshift #define VEC_ALTIVEC_DEFINE_LRSHIFT(sign, csign, bits, size) -#define VEC_ALTIVEC_STRUCT_LRSHIFT(sign, csign, bits, size) /* nothing */ +#define VEC_ALTIVEC_STRUCT_LRSHIFT(sign, csign, bits, size) \ + v##sign##int##bits##x##size##_generic_lrshift #define VEC_ALTIVEC_CAST_BOOL_8 (vector signed char) #define VEC_ALTIVEC_CAST_BOOL_U8 (vector unsigned char) @@ -108,26 +109,26 @@ /* Since altivec conveniently made their API super user friendly, we can just use * one giant macro to define literally everything */ #define VEC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_load_aligned(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_load_aligned(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.altivec = vec_ld(0, in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_load(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_load(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.altivec = vec_perm(vec_ld(0, in), vec_ld(15, in), vec_lvsl(0, in)); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_altivec_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_altivec_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ vec_st(((union v##sign##int##bits##x##size##_impl_data *)&vec)->altivec, 0, out); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -136,7 +137,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -147,25 +148,7 @@ \ VEC_ALTIVEC_DEFINE_MUL(sign, csign, bits, size) \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_min(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->altivec = vec_min(vec1d->altivec, vec2d->altivec); \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_max(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->altivec = vec_max(vec1d->altivec, vec2d->altivec); \ - return vec1d->vec; \ - } \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -174,7 +157,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ @@ -185,7 +168,7 @@ \ VEC_ALTIVEC_DEFINE_##sign##LRSHIFT(sign, csign, bits, size) \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -194,7 +177,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -203,7 +186,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -212,7 +195,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -223,7 +206,7 @@ \ VEC_ALTIVEC_DEFINE_SPLAT(sign, csign, bits, size) \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -232,7 +215,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -241,7 +224,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -250,7 +233,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -259,7 +242,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_altivec_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -269,25 +252,28 @@ } \ \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_altivec = { \ - VEC_ALTIVEC_STRUCT_SPLAT(sign, csign, bits, size) \ - .load_aligned = v##sign##int##bits##x##size##_altivec_load_aligned, \ - .load = v##sign##int##bits##x##size##_altivec_load, \ - .store_aligned = v##sign##int##bits##x##size##_altivec_store_aligned, \ - .add = v##sign##int##bits##x##size##_altivec_add, \ - .sub = v##sign##int##bits##x##size##_altivec_sub, \ - VEC_ALTIVEC_STRUCT_MUL(sign, csign, bits, size) \ - .avg = v##sign##int##bits##x##size##_altivec_avg, \ - .band = v##sign##int##bits##x##size##_altivec_and, \ - .bor = v##sign##int##bits##x##size##_altivec_or, \ - .bxor = v##sign##int##bits##x##size##_altivec_xor, \ - .lshift = v##sign##int##bits##x##size##_altivec_lshift, \ - .rshift = v##sign##int##bits##x##size##_altivec_rshift, \ - VEC_ALTIVEC_STRUCT_##sign##LRSHIFT(sign, csign, bits, size) \ - .cmplt = v##sign##int##bits##x##size##_altivec_cmplt, \ - .cmple = v##sign##int##bits##x##size##_altivec_cmple, \ - .cmpeq = v##sign##int##bits##x##size##_altivec_cmpeq, \ - .cmpge = v##sign##int##bits##x##size##_altivec_cmpge, \ - .cmpgt = v##sign##int##bits##x##size##_altivec_cmpgt, \ + VEC_ALTIVEC_STRUCT_SPLAT(sign, csign, bits, size), \ + v##sign##int##bits##x##size##_altivec_load_aligned, \ + v##sign##int##bits##x##size##_altivec_load, \ + v##sign##int##bits##x##size##_altivec_store_aligned, \ + v##sign##int##bits##x##size##_generic_store, \ + v##sign##int##bits##x##size##_altivec_add, \ + v##sign##int##bits##x##size##_altivec_sub, \ + VEC_ALTIVEC_STRUCT_MUL(sign, csign, bits, size), \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_altivec_avg, \ + v##sign##int##bits##x##size##_altivec_and, \ + v##sign##int##bits##x##size##_altivec_or, \ + v##sign##int##bits##x##size##_altivec_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_altivec_lshift, \ + v##sign##int##bits##x##size##_altivec_rshift, \ + VEC_ALTIVEC_STRUCT_##sign##LRSHIFT(sign, csign, bits, size), \ + v##sign##int##bits##x##size##_altivec_cmplt, \ + v##sign##int##bits##x##size##_altivec_cmple, \ + v##sign##int##bits##x##size##_altivec_cmpeq, \ + v##sign##int##bits##x##size##_altivec_cmpge, \ + v##sign##int##bits##x##size##_altivec_cmpgt, \ }; #define VEC_DEFINE_OPERATIONS(bits, size) \
--- a/src/impl/x86/avx2.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/x86/avx2.c Fri Apr 25 17:40:33 2025 -0400 @@ -23,88 +23,70 @@ **/ #include "vec/impl/x86/avx2.h" +#include "vec/impl/generic.h" #include <immintrin.h> -/* ------------------------------------------------------------------------ */ -/* min/max */ - -#define VEC_AVX2_MINMAX_TEMPLATE(SIGN, BITS, SIZE, INTLSIGN, OP) \ - VEC_FUNC_IMPL v##SIGN##int##BITS##x##SIZE v##SIGN##int##BITS##x##SIZE##_avx2_##OP(v##SIGN##int##BITS##x##SIZE vec1, v##SIGN##int##BITS##x##SIZE vec2) \ - { \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec1d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec1; \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec2d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec2; \ - \ - vec1d->avx2 = _mm256_##OP##_ep##INTLSIGN##BITS(vec1d->avx2, vec2d->avx2); \ +// this does NOT handle sign bits properly, use with caution +#define VEC_AVX2_OPERATION_8x32_16x16(op, sign) \ + do { \ + union v##sign##int8x32_impl_data *vec1d = (union v##sign##int8x32_impl_data *)&vec1; \ + union v##sign##int8x32_impl_data *vec2d = (union v##sign##int8x32_impl_data *)&vec2; \ \ + /* unpack and multiply */ \ + __m256i dst_even = _mm256_##op##_epi16(vec1d->avx2, vec2d->avx2); \ + __m256i dst_odd = _mm256_##op##_epi16(_mm256_srli_epi16(vec1d->avx2, 8), _mm256_srli_epi16(vec2d->avx2, 8)); \ + \ + /* repack */ \ + vec1d->avx2 = _mm256_or_si256( \ + _mm256_slli_epi16(dst_odd, 8), \ + _mm256_srli_epi16(_mm256_slli_epi16(dst_even, 8), 8) \ + ); \ return vec1d->vec; \ - } - -#define VEC_AVX2_MINMAX_8x32(OP) VEC_AVX2_MINMAX_TEMPLATE( , 8, 32, i, OP) -#define VEC_AVX2_MINMAX_u8x32(OP) VEC_AVX2_MINMAX_TEMPLATE(u, 8, 32, u, OP) -#define VEC_AVX2_MINMAX_16x16(OP) VEC_AVX2_MINMAX_TEMPLATE( , 16, 16, i, OP) -#define VEC_AVX2_MINMAX_u16x16(OP) VEC_AVX2_MINMAX_TEMPLATE(u, 16, 16, u, OP) -#define VEC_AVX2_MINMAX_32x8(OP) VEC_AVX2_MINMAX_TEMPLATE( , 32, 8, i, OP) -#define VEC_AVX2_MINMAX_u32x8(OP) VEC_AVX2_MINMAX_TEMPLATE(u, 32, 8, u, OP) -#define VEC_AVX2_MINMAX_64x4(OP) /* nothing */ -#define VEC_AVX2_MINMAX_u64x4(OP) /* nothing */ + } while (0) -#define VEC_AVX2_STRUCT_MINMAX_8x32(OP, SIGN) v##SIGN##int8x32_avx2_##OP -#define VEC_AVX2_STRUCT_MINMAX_16x16(OP, SIGN) v##SIGN##int16x16_avx2_##OP -#define VEC_AVX2_STRUCT_MINMAX_32x8(OP, SIGN) v##SIGN##int32x8_avx2_##OP -#define VEC_AVX2_STRUCT_MINMAX_64x4(OP, SIGN) NULL - -/* reused this for avg */ - -#define VEC_AVX2_AVG_8x32 /* nothing */ -#define VEC_AVX2_AVG_16x16 /* nothing */ -#define VEC_AVX2_AVG_32x8 /* nothing */ -#define VEC_AVX2_AVG_64x4 /* nothing */ - -#define VEC_AVX2_AVG_u8x32 VEC_AVX2_MINMAX_TEMPLATE(u, 8, 32, u, avg) -#define VEC_AVX2_AVG_u16x16 VEC_AVX2_MINMAX_TEMPLATE(u, 16, 16, u, avg) -#define VEC_AVX2_AVG_u32x8 /* nothing */ -#define VEC_AVX2_AVG_u64x4 /* nothing */ - -#define VEC_AVX2_STRUCT_AVG_8x32 NULL -#define VEC_AVX2_STRUCT_AVG_16x16 NULL -#define VEC_AVX2_STRUCT_AVG_32x8 NULL -#define VEC_AVX2_STRUCT_AVG_64x4 NULL - -#define VEC_AVX2_STRUCT_AVG_u8x32 vuint8x32_avx2_avg -#define VEC_AVX2_STRUCT_AVG_u16x16 vuint16x16_avx2_avg -#define VEC_AVX2_STRUCT_AVG_u32x8 NULL -#define VEC_AVX2_STRUCT_AVG_u64x4 NULL - -/* ------------------------------------------------------------------------ */ +#define VEC_AVX2_OPERATION_16x16(op, sign) \ + do { \ + union v##sign##int16x16_impl_data *vec1d = (union v##sign##int16x16_impl_data *)&vec1; \ + union v##sign##int16x16_impl_data *vec2d = (union v##sign##int16x16_impl_data *)&vec2; \ + \ + /* unpack and multiply */ \ + __m256i dst_even = _mm256_##op##_epi32(vec1d->avx2, vec2d->avx2); \ + __m256i dst_odd = _mm256_##op##_epi32(_mm256_srli_epi32(vec1d->avx2, 16), _mm256_srli_epi32(vec2d->avx2, 16)); \ + \ + /* repack */ \ + vec1d->avx2 = _mm256_or_si256( \ + _mm256_slli_epi32(dst_odd, 16), \ + _mm256_srli_epi32(_mm256_slli_epi16(dst_even, 16), 16) \ + ); \ + return vec1d->vec; \ + } while (0) // multiplication -#define VEC_AVX2_MUL_8x32(sign) /* nothing */ +#define VEC_AVX2_MUL_8x32(sign) \ + VEC_AVX2_OPERATION_8x32_16x16(mullo, sign) #define VEC_AVX2_MUL_16x16(sign) \ - VEC_FUNC_IMPL v##sign##int16x16 v##sign##int16x16_avx2_mul(v##sign##int16x16 vec1, v##sign##int16x16 vec2) \ - { \ + do { \ union v##sign##int16x16_impl_data *vec1d = (union v##sign##int16x16_impl_data *)&vec1; \ union v##sign##int16x16_impl_data *vec2d = (union v##sign##int16x16_impl_data *)&vec2; \ \ vec1d->avx2 = _mm256_mullo_epi16(vec1d->avx2, vec2d->avx2); \ return vec1d->vec; \ - } + } while (0) #define VEC_AVX2_MUL_32x8(sign) \ - VEC_FUNC_IMPL v##sign##int32x8 v##sign##int32x8_avx2_mul(v##sign##int32x8 vec1, v##sign##int32x8 vec2) \ - { \ + do { \ union v##sign##int32x8_impl_data *vec1d = (union v##sign##int32x8_impl_data *)&vec1; \ union v##sign##int32x8_impl_data *vec2d = (union v##sign##int32x8_impl_data *)&vec2; \ \ vec1d->avx2 = _mm256_mullo_epi32(vec1d->avx2, vec2d->avx2); \ return vec1d->vec; \ - } + } while (0) #define VEC_AVX2_MUL_64x4(sign) \ - VEC_FUNC_IMPL v##sign##int64x4 v##sign##int64x4_avx2_mul(v##sign##int64x4 vec1, v##sign##int64x4 vec2) \ - { \ + do { \ union v##sign##int64x4_impl_data *vec1d = (union v##sign##int64x4_impl_data *)&vec1; \ union v##sign##int64x4_impl_data *vec2d = (union v##sign##int64x4_impl_data *)&vec2; \ \ @@ -118,12 +100,7 @@ \ vec1d->avx2 = _mm256_add_epi64(hi, ac); \ return vec1d->vec; \ - } - -#define VEC_AVX2_STRUCT_MUL_8x32(SIGN) NULL -#define VEC_AVX2_STRUCT_MUL_16x16(SIGN) v##SIGN##int16x16_avx2_mul -#define VEC_AVX2_STRUCT_MUL_32x8(SIGN) v##SIGN##int32x8_avx2_mul -#define VEC_AVX2_STRUCT_MUL_64x4(SIGN) v##SIGN##int64x4_avx2_mul + } while (0) // operations @@ -136,31 +113,31 @@ VEC_STATIC_ASSERT(VEC_ALIGNOF(__m256i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ VEC_STATIC_ASSERT(sizeof(__m256i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_load_aligned(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_load_aligned(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.avx2 = _mm256_load_si256((const __m256i *)in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_load(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_load(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.avx2 = _mm256_loadu_si256((const __m256i *)in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_avx2_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_avx2_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ _mm256_store_si256((__m256i *)out, ((union v##sign##int##bits##x##size##_impl_data*)&vec)->avx2); \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_avx2_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_avx2_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ _mm256_storeu_si256((__m256i *)out, ((union v##sign##int##bits##x##size##_impl_data*)&vec)->avx2); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -169,7 +146,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -178,9 +155,12 @@ return vec1d->vec; \ } \ \ - VEC_AVX2_MUL_##bits##x##size(sign) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + { \ + VEC_AVX2_MUL_##bits##x##size(sign); \ + } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -189,7 +169,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -198,7 +178,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx2_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -207,25 +187,29 @@ return vec1d->vec; \ } \ \ - VEC_AVX2_AVG_##sign##bits##x##size \ - \ - VEC_AVX2_MINMAX_##sign##bits##x##size(min) \ - VEC_AVX2_MINMAX_##sign##bits##x##size(max) \ - \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_avx2 = { \ - .load_aligned = v##sign##int##bits##x##size##_avx2_load_aligned, \ - .load = v##sign##int##bits##x##size##_avx2_load, \ - .store_aligned = v##sign##int##bits##x##size##_avx2_store_aligned, \ - .store = v##sign##int##bits##x##size##_avx2_store, \ - .add = v##sign##int##bits##x##size##_avx2_add, \ - .sub = v##sign##int##bits##x##size##_avx2_sub, \ - .mul = VEC_AVX2_STRUCT_MUL_##bits##x##size(sign), \ - .band = v##sign##int##bits##x##size##_avx2_and, \ - .bor = v##sign##int##bits##x##size##_avx2_or, \ - .bxor = v##sign##int##bits##x##size##_avx2_xor, \ - .min = VEC_AVX2_STRUCT_MINMAX_##bits##x##size(min, sign), \ - .max = VEC_AVX2_STRUCT_MINMAX_##bits##x##size(max, sign), \ - .avg = VEC_AVX2_STRUCT_AVG_##sign##bits##x##size, \ + v##sign##int##bits##x##size##_generic_splat, \ + v##sign##int##bits##x##size##_avx2_load_aligned, \ + v##sign##int##bits##x##size##_avx2_load, \ + v##sign##int##bits##x##size##_avx2_store_aligned, \ + v##sign##int##bits##x##size##_avx2_store, \ + v##sign##int##bits##x##size##_avx2_add, \ + v##sign##int##bits##x##size##_avx2_sub, \ + v##sign##int##bits##x##size##_avx2_mul, \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_generic_avg, \ + v##sign##int##bits##x##size##_avx2_and, \ + v##sign##int##bits##x##size##_avx2_or, \ + v##sign##int##bits##x##size##_avx2_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_generic_lshift, \ + v##sign##int##bits##x##size##_generic_rshift, \ + v##sign##int##bits##x##size##_generic_lrshift, \ + v##sign##int##bits##x##size##_generic_cmplt, \ + v##sign##int##bits##x##size##_generic_cmple, \ + v##sign##int##bits##x##size##_generic_cmpeq, \ + v##sign##int##bits##x##size##_generic_cmpge, \ + v##sign##int##bits##x##size##_generic_cmpgt, \ }; #define VEC_AVX2_DEFINE_OPERATIONS(bits, size) \
--- a/src/impl/x86/avx512bw.c Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#include "vec/impl/x86/avx512bw.h" - -#include <immintrin.h> - -/* ------------------------------------------------------------------------ */ - -#define VEC_AVX512BW_MINMAX_TEMPLATE(SIGN, BITS, SIZE, INTLSIGN, OP) \ - VEC_FUNC_IMPL v##SIGN##int##BITS##x##SIZE v##SIGN##int##BITS##x##SIZE##_avx512bw_##OP(v##SIGN##int##BITS##x##SIZE vec1, v##SIGN##int##BITS##x##SIZE vec2) \ - { \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec1d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec1; \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec2d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec2; \ - \ - vec1d->avx512bw = _mm512_##OP##_ep##INTLSIGN##BITS(vec1d->avx512bw, vec2d->avx512bw); \ - \ - return vec1d->vec; \ - } - -#define VEC_AVX512BW_MINMAX_8x64(OP) VEC_AVX512BW_MINMAX_TEMPLATE( , 8, 64, i, OP) -#define VEC_AVX512BW_MINMAX_u8x64(OP) VEC_AVX512BW_MINMAX_TEMPLATE(u, 8, 64, u, OP) -#define VEC_AVX512BW_MINMAX_16x32(OP) VEC_AVX512BW_MINMAX_TEMPLATE( , 16, 32, i, OP) -#define VEC_AVX512BW_MINMAX_u16x32(OP) VEC_AVX512BW_MINMAX_TEMPLATE(u, 16, 32, u, OP) - -#define VEC_AVX512BW_STRUCT_MINMAX_8x64(OP, SIGN) v##SIGN##int8x64_avx512bw_##OP -#define VEC_AVX512BW_STRUCT_MINMAX_16x32(OP, SIGN) v##SIGN##int16x32_avx512bw_##OP - -/* ------------------------------------------------------------------------ */ - -#define VEC_AVX512BW_OPERATION_EX(name, op, sign, bits, size, secondsign) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512bw_##name(v##sign##int##bits##x##size vec1, v##secondsign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##secondsign##int##bits##x##size##_impl_data *vec2d = (union v##secondsign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->avx512bw = _mm512_##op##_epi##bits(vec1d->avx512bw, vec2d->avx512bw); \ - \ - return vec1d->vec; \ - } - -#define VEC_AVX512BW_OPERATION(name, op, sign, bits, size) \ - VEC_AVX512BW_OPERATION_EX(name, op, sign, bits, size, sign) - -#define VEC_AVX512BW_OPERATION_SHIFT(name, op, sign, bits, size) \ - VEC_AVX512BW_OPERATION_EX(name, op, sign, bits, size, u) - -#define VEC_AVX512BW_ADD_8x64(sign) VEC_AVX512BW_OPERATION(add, add, sign, 8, 64) -#define VEC_AVX512BW_ADD_16x32(sign) VEC_AVX512BW_OPERATION(add, add, sign, 16, 32) - -#define VEC_AVX512BW_SUB_8x64(sign) VEC_AVX512BW_OPERATION(sub, sub, sign, 8, 64) -#define VEC_AVX512BW_SUB_16x32(sign) VEC_AVX512BW_OPERATION(sub, sub, sign, 16, 32) - -#define VEC_AVX512BW_MUL_8x64(sign) /* nothing */ -#define VEC_AVX512BW_MUL_16x32(sign) VEC_AVX512BW_OPERATION(mul, mullo, sign, 16, 32) - -#define VEC_AVX512BW_LSHIFT_8x64(sign) /* nothing */ -#define VEC_AVX512BW_LSHIFT_16x32(sign) VEC_AVX512BW_OPERATION_SHIFT(lshift, sllv, sign, 16, 32) - -#define VEC_AVX512BW_XRSHIFT(name, bits, size, sign, aORl) \ - VEC_AVX512BW_OPERATION_SHIFT(name, sr##aORl##v, sign, bits, size) - -/* always the same, regardless of signedness */ -#define VEC_AVX512BW_LRSHIFT_8x64(sign) /* nothing */ -#define VEC_AVX512BW_LRSHIFT_16x32(sign) VEC_AVX512BW_XRSHIFT(lrshift, 16, 32, sign, l) - -#define VEC_AVX512BW_RSHIFT_8x64(sign) /* nothing */ -#define VEC_AVX512BW_RSHIFT_16x32(sign) VEC_AVX512BW_XRSHIFT(rshift, 16, 32, sign, a) - -#define VEC_AVX512BW_uRSHIFT_8x64(sign) /* nothing */ -#define VEC_AVX512BW_uRSHIFT_16x32(sign) VEC_AVX512BW_XRSHIFT(rshift, 16, 32, sign, l) - -/* ok */ -#define VEC_AVX512BW_STRUCT_ADDSUB_8x64(OP, SIGN) v##SIGN##int8x64_avx512bw_##OP -#define VEC_AVX512BW_STRUCT_ADDSUB_16x32(OP, SIGN) v##SIGN##int16x32_avx512bw_##OP - -#define VEC_AVX512BW_STRUCT_OPERATION_8x64(OP, SIGN) NULL -#define VEC_AVX512BW_STRUCT_OPERATION_16x32(OP, SIGN) v##SIGN##int16x32_avx512bw_##OP - -/* ------------------------------------------------------------------------ */ - -#define VEC_AVX512BW_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - __m512i avx512bw; \ - }; \ - \ - VEC_STATIC_ASSERT(VEC_ALIGNOF(__m512i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ - VEC_STATIC_ASSERT(sizeof(__m512i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ - \ - VEC_AVX512BW_ADD_##bits##x##size(sign) \ - VEC_AVX512BW_SUB_##bits##x##size(sign) \ - VEC_AVX512BW_MUL_##bits##x##size(sign) \ - \ - VEC_AVX512BW_LSHIFT_##bits##x##size(sign); \ - VEC_AVX512BW_##sign##RSHIFT_##bits##x##size(sign); \ - VEC_AVX512BW_LRSHIFT_##bits##x##size(sign); \ - \ - VEC_AVX512BW_MINMAX_##sign##bits##x##size(min) \ - VEC_AVX512BW_MINMAX_##sign##bits##x##size(max) \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_avx512bw = { \ - .add = VEC_AVX512BW_STRUCT_ADDSUB_##bits##x##size(add, sign), \ - .sub = VEC_AVX512BW_STRUCT_ADDSUB_##bits##x##size(sub, sign), \ - .mul = VEC_AVX512BW_STRUCT_OPERATION_##bits##x##size(mul, sign), \ - .lshift = VEC_AVX512BW_STRUCT_OPERATION_##bits##x##size(lshift, sign), \ - .rshift = VEC_AVX512BW_STRUCT_OPERATION_##bits##x##size(rshift, sign), \ - .lrshift = VEC_AVX512BW_STRUCT_OPERATION_##bits##x##size(lrshift, sign), \ - .min = VEC_AVX512BW_STRUCT_MINMAX_##bits##x##size(min, sign), \ - .max = VEC_AVX512BW_STRUCT_MINMAX_##bits##x##size(max, sign), \ - }; - -#define VEC_AVX512BW_DEFINE_OPERATIONS(bits, size) \ - VEC_AVX512BW_DEFINE_OPERATIONS_SIGN(u, bits, size) \ - VEC_AVX512BW_DEFINE_OPERATIONS_SIGN( , bits, size) - -VEC_AVX512BW_DEFINE_OPERATIONS(8, 64) -VEC_AVX512BW_DEFINE_OPERATIONS(16, 32)
--- a/src/impl/x86/avx512dq.c Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#include "vec/impl/x86/avx512dq.h" - -#include <immintrin.h> - -/* ------------------------------------------------------------------------ */ - -#define VEC_AVX512DQ_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - __m512i avx512dq; \ - }; \ - \ - VEC_STATIC_ASSERT(VEC_ALIGNOF(__m512i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ - VEC_STATIC_ASSERT(sizeof(__m512i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512dq_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - \ - vec1d->avx512dq = _mm512_mullo_epi64(vec1d->avx512dq, vec2d->avx512dq); \ - return vec1d->vec; \ - } \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_avx512dq = { \ - .mul = v##sign##int##bits##x##size##_avx512dq_mul, \ - }; - -#define VEC_AVX512DQ_DEFINE_OPERATIONS(bits, size) \ - VEC_AVX512DQ_DEFINE_OPERATIONS_SIGN(u, bits, size) \ - VEC_AVX512DQ_DEFINE_OPERATIONS_SIGN( , bits, size) - -VEC_AVX512DQ_DEFINE_OPERATIONS(64, 8)
--- a/src/impl/x86/avx512f.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/x86/avx512f.c Fri Apr 25 17:40:33 2025 -0400 @@ -23,79 +23,202 @@ **/ #include "vec/impl/x86/avx512f.h" +#include "vec/impl/generic.h" #include <immintrin.h> -/* ------------------------------------------------------------------------ */ - -#define VEC_AVX512F_MINMAX_TEMPLATE(SIGN, BITS, SIZE, INTLSIGN, OP) \ - VEC_FUNC_IMPL v##SIGN##int##BITS##x##SIZE v##SIGN##int##BITS##x##SIZE##_avx512f_##OP(v##SIGN##int##BITS##x##SIZE vec1, v##SIGN##int##BITS##x##SIZE vec2) \ - { \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec1d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec1; \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec2d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec2; \ - \ - vec1d->avx512f = _mm512_##OP##_ep##INTLSIGN##BITS(vec1d->avx512f, vec2d->avx512f); \ +// this is a stupid amount of work just to do these operations, is it really worth it ? +// also same note in avx2.c applies here, these do not handle sign bits properly, which +// isn't that big of a deal for regular arithmetic operations, but matters quite a bit +// when doing things like arithmetic shifts. +#define VEC_AVX512F_OPERATION_8x64(op, sign) \ + do { \ + union v##sign##int8x64_impl_data *vec1d = (union v##sign##int8x64_impl_data *)&vec1; \ + union v##sign##int8x64_impl_data *vec2d = (union v##sign##int8x64_impl_data *)&vec2; \ \ - return vec1d->vec; \ - } - -#define VEC_AVX512F_MINMAX_32x16(OP) VEC_AVX512F_MINMAX_TEMPLATE( , 32, 16, i, OP) -#define VEC_AVX512F_MINMAX_u32x16(OP) VEC_AVX512F_MINMAX_TEMPLATE(u, 32, 16, u, OP) -#define VEC_AVX512F_MINMAX_64x8(OP) VEC_AVX512F_MINMAX_TEMPLATE( , 64, 8, i, OP) -#define VEC_AVX512F_MINMAX_u64x8(OP) VEC_AVX512F_MINMAX_TEMPLATE(u, 64, 8, u, OP) - -#define VEC_AVX512F_STRUCT_MINMAX_32x16(OP, SIGN) v##SIGN##int32x16_avx512f_##OP -#define VEC_AVX512F_STRUCT_MINMAX_64x8(OP, SIGN) v##SIGN##int64x8_avx512f_##OP - -/* ------------------------------------------------------------------------ */ - -#define VEC_AVX512F_OPERATION_EX(name, op, sign, bits, size, secondsign) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_##name(v##sign##int##bits##x##size vec1, v##secondsign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##secondsign##int##bits##x##size##_impl_data *vec2d = (union v##secondsign##int##bits##x##size##_impl_data *)&vec2; \ + /* unpack and operate */ \ + __m512i dst_1 = _mm512_##op##_epi32(_mm512_srli_epi32(_mm512_slli_epi32(vec1d->avx512f, 24), 24), _mm512_srli_epi32(_mm512_slli_epi32(vec2d->avx512f, 24), 24)); \ + __m512i dst_2 = _mm512_##op##_epi32(_mm512_srli_epi32(_mm512_slli_epi32(vec1d->avx512f, 16), 24), _mm512_srli_epi32(_mm512_slli_epi32(vec2d->avx512f, 16), 24)); \ + __m512i dst_3 = _mm512_##op##_epi32(_mm512_srli_epi32(_mm512_slli_epi32(vec1d->avx512f, 8), 24), _mm512_srli_epi32(_mm512_slli_epi32(vec2d->avx512f, 8), 24)); \ + __m512i dst_4 = _mm512_##op##_epi32(_mm512_srli_epi32(vec1d->avx512f, 24), _mm512_srli_epi32(vec2d->avx512f, 24)); \ \ - vec1d->avx512f = _mm512_##op##_epi##bits(vec1d->avx512f, vec2d->avx512f); \ + /* repack */ \ + vec1d->avx512f = _mm512_or_si512( \ + _mm512_or_si512( \ + _mm512_srli_epi32(_mm512_slli_epi32(dst_1, 24), 24), \ + _mm512_srli_epi32(_mm512_slli_epi32(dst_2, 24), 16) \ + ), \ + _mm512_or_si512( \ + _mm512_srli_epi32(_mm512_slli_epi32(dst_3, 24), 8), \ + _mm512_slli_epi32(dst_4, 24) \ + ) \ + ); \ \ return vec1d->vec; \ - } + } while (0) -#define VEC_AVX512F_OPERATION(name, op, sign, bits, size) \ - VEC_AVX512F_OPERATION_EX(name, op, sign, bits, size, sign) +#define VEC_AVX512F_OPERATION_16x32(op, sign) \ + do { \ + union v##sign##int16x32_impl_data *vec1d = (union v##sign##int16x32_impl_data *)&vec1; \ + union v##sign##int16x32_impl_data *vec2d = (union v##sign##int16x32_impl_data *)&vec2; \ + \ + /* unpack and operate; it would be nice if we had an _m512_andi_epi32... */ \ + __m512i dst_1 = _mm512_##op##_epi32(_mm512_srli_epi32(_mm512_slli_epi32(vec1d->avx512f, 16), 16), _mm512_srli_epi32(_mm512_slli_epi32(vec2d->avx512f, 16), 16)); \ + __m512i dst_2 = _mm512_##op##_epi32(_mm512_srli_epi32(vec1d->avx512f, 16), _mm512_srli_epi32(vec2d->avx512f, 16)); \ + \ + /* repack */ \ + vec1d->avx512f = _mm512_or_si512( \ + _mm512_srli_epi32(_mm512_slli_epi32(dst_1, 16), 16), \ + _mm512_slli_epi32(dst_2, 16) \ + ); \ + return vec1d->vec; \ + } while (0) -#define VEC_AVX512F_OPERATION_SHIFT(name, op, sign, bits, size) \ - VEC_AVX512F_OPERATION_EX(name, op, sign, bits, size, u) +#define VEC_AVX512F_ADD_8x64(sign) \ + VEC_AVX512F_OPERATION_8x64(add, sign) + +#define VEC_AVX512F_ADD_16x32(sign) \ + VEC_AVX512F_OPERATION_16x32(add, sign) + +#define VEC_AVX512F_ADD_32x16(sign) \ + do { \ + union v##sign##int32x16_impl_data *vec1d = (union v##sign##int32x16_impl_data *)&vec1; \ + union v##sign##int32x16_impl_data *vec2d = (union v##sign##int32x16_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_add_epi32(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) -#define VEC_AVX512F_ADD_32x16(sign) VEC_AVX512F_OPERATION(add, add, sign, 32, 16) -#define VEC_AVX512F_ADD_64x8(sign) VEC_AVX512F_OPERATION(add, add, sign, 64, 8) +#define VEC_AVX512F_ADD_64x8(sign) \ + do { \ + union v##sign##int64x8_impl_data *vec1d = (union v##sign##int64x8_impl_data *)&vec1; \ + union v##sign##int64x8_impl_data *vec2d = (union v##sign##int64x8_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_add_epi64(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) + +#define VEC_AVX512F_SUB_8x64(sign) \ + VEC_AVX512F_OPERATION_8x64(sub, sign) + +#define VEC_AVX512F_SUB_16x32(sign) \ + VEC_AVX512F_OPERATION_16x32(sub, sign) + +#define VEC_AVX512F_SUB_32x16(sign) \ + do { \ + union v##sign##int32x16_impl_data *vec1d = (union v##sign##int32x16_impl_data *)&vec1; \ + union v##sign##int32x16_impl_data *vec2d = (union v##sign##int32x16_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_sub_epi32(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) -#define VEC_AVX512F_SUB_32x16(sign) VEC_AVX512F_OPERATION(sub, sub, sign, 32, 16) -#define VEC_AVX512F_SUB_64x8(sign) VEC_AVX512F_OPERATION(sub, sub, sign, 64, 8) +#define VEC_AVX512F_SUB_64x8(sign) \ + do { \ + union v##sign##int64x8_impl_data *vec1d = (union v##sign##int64x8_impl_data *)&vec1; \ + union v##sign##int64x8_impl_data *vec2d = (union v##sign##int64x8_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_sub_epi64(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) + +#define VEC_AVX512F_MUL_8x64(sign) \ + VEC_AVX512F_OPERATION_8x64(mullo, sign) -#define VEC_AVX512F_MUL_32x16(sign) VEC_AVX512F_OPERATION(mul, mullo, sign, 32, 16) -#define VEC_AVX512F_MUL_64x8(sign) VEC_AVX512F_OPERATION(mul, mullox, sign, 64, 8) +#define VEC_AVX512F_MUL_16x32(sign) \ + VEC_AVX512F_OPERATION_16x32(mullo, sign) + +#define VEC_AVX512F_MUL_32x16(sign) \ + do { \ + union v##sign##int32x16_impl_data *vec1d = (union v##sign##int32x16_impl_data *)&vec1; \ + union v##sign##int32x16_impl_data *vec2d = (union v##sign##int32x16_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_mullo_epi32(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) -#define VEC_AVX512F_LSHIFT_32x16(sign) VEC_AVX512F_OPERATION_SHIFT(lshift, sllv, sign, 32, 16) -#define VEC_AVX512F_LSHIFT_64x8(sign) VEC_AVX512F_OPERATION_SHIFT(lshift, sllv, sign, 64, 8) +#define VEC_AVX512F_MUL_64x8(sign) \ + do { \ + union v##sign##int64x8_impl_data *vec1d = (union v##sign##int64x8_impl_data *)&vec1; \ + union v##sign##int64x8_impl_data *vec2d = (union v##sign##int64x8_impl_data *)&vec2; \ + \ + __m512i ac = _mm512_mul_epu32(vec1d->avx512f, vec2d->avx512f); \ + __m512i b = _mm512_srli_epi64(vec1d->avx512f, 32); \ + __m512i bc = _mm512_mul_epu32(b, vec2d->avx512f); \ + __m512i d = _mm512_srli_epi64(vec2d->avx512f, 32); \ + __m512i ad = _mm512_mul_epu32(vec1d->avx512f, d); \ + __m512i hi = _mm512_add_epi64(bc, ad); \ + hi = _mm512_slli_epi64(hi, 32); \ + \ + vec1d->avx512f = _mm512_add_epi64(hi, ac); \ + return vec1d->vec; \ + } while (0) + +#define VEC_AVX512F_LSHIFT_8x64(sign) \ + VEC_AVX512F_OPERATION_8x64(sllv, sign) -#define VEC_AVX512F_XRSHIFT(name, bits, size, sign, aORl) \ - VEC_AVX512F_OPERATION_SHIFT(name, sr##aORl##v, sign, bits, size) +#define VEC_AVX512F_LSHIFT_16x32(sign) \ + VEC_AVX512F_OPERATION_16x32(sllv, sign) -/* always the same, regardless of signedness */ -#define VEC_AVX512F_LRSHIFT_32x16(sign) VEC_AVX512F_XRSHIFT(lrshift, 32, 16, sign, l) -#define VEC_AVX512F_LRSHIFT_64x8(sign) VEC_AVX512F_XRSHIFT(lrshift, 64, 8, sign, l) +#define VEC_AVX512F_LSHIFT_32x16(sign) \ + do { \ + union v##sign##int32x16_impl_data *vec1d = (union v##sign##int32x16_impl_data *)&vec1; \ + union v##sign##int32x16_impl_data *vec2d = (union v##sign##int32x16_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_sllv_epi32(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) + +#define VEC_AVX512F_LSHIFT_64x8(sign) \ + do { \ + union v##sign##int64x8_impl_data *vec1d = (union v##sign##int64x8_impl_data *)&vec1; \ + union v##sign##int64x8_impl_data *vec2d = (union v##sign##int64x8_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_sllv_epi64(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) -#define VEC_AVX512F_RSHIFT_32x16(sign) VEC_AVX512F_XRSHIFT(rshift, 32, 16, sign, a) -#define VEC_AVX512F_RSHIFT_64x8(sign) VEC_AVX512F_XRSHIFT(rshift, 64, 8, sign, a) +#define VEC_AVX512F_lRSHIFT_8x64(sign) \ + VEC_AVX512F_OPERATION_8x64(srlv, sign) + +#define VEC_AVX512F_lRSHIFT_16x32(sign) \ + VEC_AVX512F_OPERATION_16x32(srlv, sign) -#define VEC_AVX512F_uRSHIFT_32x16(sign) VEC_AVX512F_XRSHIFT(rshift, 32, 16, sign, l) -#define VEC_AVX512F_uRSHIFT_64x8(sign) VEC_AVX512F_XRSHIFT(rshift, 64, 8, sign, l) +#define VEC_AVX512F_aRSHIFT_8x64(sign) \ + do { \ + return v##sign##int8x64_generic_rshift(vec1, vec2); \ + } while (0) + +#define VEC_AVX512F_aRSHIFT_16x32(sign) \ + do { \ + return v##sign##int16x32_generic_rshift(vec1, vec2); \ + } while (0) + +#define VEC_AVX512F_RSHIFT_8x64(sign, aORl) VEC_AVX512F_##aORl##RSHIFT_8x64(sign) +#define VEC_AVX512F_RSHIFT_16x32(sign, aORl) VEC_AVX512F_##aORl##RSHIFT_16x32(sign) -/* ok */ -#define VEC_AVX512F_STRUCT_OPERATION_32x16(OP, SIGN) v##SIGN##int32x16_avx512f_##OP -#define VEC_AVX512F_STRUCT_OPERATION_64x8(OP, SIGN) v##SIGN##int64x8_avx512f_##OP +#define VEC_AVX512F_RSHIFT_32x16(sign, aORl) \ + do { \ + union v##sign##int32x16_impl_data *vec1d = (union v##sign##int32x16_impl_data *)&vec1; \ + union v##sign##int32x16_impl_data *vec2d = (union v##sign##int32x16_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_sr##aORl##v_epi32(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) -/* ------------------------------------------------------------------------ */ +#define VEC_AVX512F_RSHIFT_64x8(sign, aORl) \ + do { \ + union v##sign##int64x8_impl_data *vec1d = (union v##sign##int64x8_impl_data *)&vec1; \ + union v##sign##int64x8_impl_data *vec2d = (union v##sign##int64x8_impl_data *)&vec2; \ + \ + vec1d->avx512f = _mm512_sr##aORl##v_epi64(vec1d->avx512f, vec2d->avx512f); \ + return vec1d->vec; \ + } while (0) + +#define VEC_AVX512F_uRSHIFT_8x64(sign, aORl) VEC_AVX512F_RSHIFT_8x64(sign, l) +#define VEC_AVX512F_uRSHIFT_16x32(sign, aORl) VEC_AVX512F_RSHIFT_16x32(sign, l) +#define VEC_AVX512F_uRSHIFT_32x16(sign, aORl) VEC_AVX512F_RSHIFT_32x16(sign, l) +#define VEC_AVX512F_uRSHIFT_64x8(sign, aORl) VEC_AVX512F_RSHIFT_64x8(sign, l) #define VEC_AVX512F_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ union v##sign##int##bits##x##size##_impl_data { \ @@ -106,35 +229,46 @@ VEC_STATIC_ASSERT(VEC_ALIGNOF(__m512i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ VEC_STATIC_ASSERT(sizeof(__m512i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_load_aligned(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_load_aligned(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.avx512f = _mm512_load_si512((const __m512i *)in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_load(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_load(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.avx512f = _mm512_loadu_si512((const __m512i *)in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_avx512f_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_avx512f_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ _mm512_store_si512((__m512i *)out, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->avx512f); \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_avx512f_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_avx512f_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ _mm512_storeu_si512((__m512i *)out, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->avx512f); \ } \ \ - VEC_AVX512F_ADD_##bits##x##size(sign) \ - VEC_AVX512F_SUB_##bits##x##size(sign) \ - VEC_AVX512F_MUL_##bits##x##size(sign) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + { \ + VEC_AVX512F_ADD_##bits##x##size(sign); \ + } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + { \ + VEC_AVX512F_SUB_##bits##x##size(sign); \ + } \ + \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + { \ + VEC_AVX512F_MUL_##bits##x##size(sign); \ + } \ + \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -143,7 +277,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -152,7 +286,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -161,34 +295,51 @@ return vec1d->vec; \ } \ \ - VEC_AVX512F_LSHIFT_##bits##x##size(sign); \ - VEC_AVX512F_##sign##RSHIFT_##bits##x##size(sign); \ - VEC_AVX512F_LRSHIFT_##bits##x##size(sign); \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + { \ + VEC_AVX512F_LSHIFT_##bits##x##size(sign); \ + } \ \ - VEC_AVX512F_MINMAX_##sign##bits##x##size(min) \ - VEC_AVX512F_MINMAX_##sign##bits##x##size(max) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + { \ + VEC_AVX512F_##sign##RSHIFT_##bits##x##size(sign, a); \ + } \ + \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_avx512f_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ + { \ + VEC_AVX512F_RSHIFT_##bits##x##size(sign, l); \ + } \ \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_avx512f = { \ - .load_aligned = v##sign##int##bits##x##size##_avx512f_load_aligned, \ - .load = v##sign##int##bits##x##size##_avx512f_load, \ - .store_aligned = v##sign##int##bits##x##size##_avx512f_store_aligned, \ - .store = v##sign##int##bits##x##size##_avx512f_store, \ - .add = VEC_AVX512F_STRUCT_OPERATION_##bits##x##size(add, sign), \ - .sub = VEC_AVX512F_STRUCT_OPERATION_##bits##x##size(sub, sign), \ - .mul = VEC_AVX512F_STRUCT_OPERATION_##bits##x##size(mul, sign), \ - .band = v##sign##int##bits##x##size##_avx512f_and, \ - .bor = v##sign##int##bits##x##size##_avx512f_or, \ - .bxor = v##sign##int##bits##x##size##_avx512f_xor, \ - .lshift = VEC_AVX512F_STRUCT_OPERATION_##bits##x##size(lshift, sign), \ - .rshift = VEC_AVX512F_STRUCT_OPERATION_##bits##x##size(rshift, sign), \ - .lrshift = VEC_AVX512F_STRUCT_OPERATION_##bits##x##size(lrshift, sign), \ - .min = VEC_AVX512F_STRUCT_MINMAX_##bits##x##size(min, sign), \ - .max = VEC_AVX512F_STRUCT_MINMAX_##bits##x##size(max, sign), \ + v##sign##int##bits##x##size##_generic_splat, \ + v##sign##int##bits##x##size##_avx512f_load_aligned, \ + v##sign##int##bits##x##size##_avx512f_load, \ + v##sign##int##bits##x##size##_avx512f_store_aligned, \ + v##sign##int##bits##x##size##_avx512f_store, \ + v##sign##int##bits##x##size##_avx512f_add, \ + v##sign##int##bits##x##size##_avx512f_sub, \ + v##sign##int##bits##x##size##_avx512f_mul, \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_generic_avg, \ + v##sign##int##bits##x##size##_avx512f_and, \ + v##sign##int##bits##x##size##_avx512f_or, \ + v##sign##int##bits##x##size##_avx512f_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_avx512f_lshift, \ + v##sign##int##bits##x##size##_avx512f_rshift, \ + v##sign##int##bits##x##size##_avx512f_lrshift, \ + v##sign##int##bits##x##size##_generic_cmplt, \ + v##sign##int##bits##x##size##_generic_cmple, \ + v##sign##int##bits##x##size##_generic_cmpeq, \ + v##sign##int##bits##x##size##_generic_cmpge, \ + v##sign##int##bits##x##size##_generic_cmpgt, \ }; #define VEC_AVX512F_DEFINE_OPERATIONS(bits, size) \ VEC_AVX512F_DEFINE_OPERATIONS_SIGN(u, bits, size) \ VEC_AVX512F_DEFINE_OPERATIONS_SIGN( , bits, size) +VEC_AVX512F_DEFINE_OPERATIONS(8, 64) +VEC_AVX512F_DEFINE_OPERATIONS(16, 32) VEC_AVX512F_DEFINE_OPERATIONS(32, 16) VEC_AVX512F_DEFINE_OPERATIONS(64, 8)
--- a/src/impl/x86/mmx.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/x86/mmx.c Fri Apr 25 17:40:33 2025 -0400 @@ -24,67 +24,46 @@ #include "vec/vec.h" #include "vec/impl/x86/mmx.h" +#include "vec/impl/generic.h" #include <mmintrin.h> #include <string.h> -/* ------------------------------------------------------------------------ */ +#define VEC_MMX_OPERATION_8x8(op, sign) \ + do { \ + /* unpack and multiply */ \ + union v##sign##int8x8_impl_data *vec1d = (union v##sign##int8x8_impl_data *)&vec1; \ + union v##sign##int8x8_impl_data *vec2d = (union v##sign##int8x8_impl_data *)&vec2; \ + \ + __m64 dst_even = _mm_##op##_pi16(vec1d->mmx, vec2d->mmx); \ + __m64 dst_odd = _mm_##op##_pi16(_mm_srli_pi16(vec1d->mmx, 8), _mm_srli_pi16(vec2d->mmx, 8)); \ + \ + /* repack */ \ + vec1d->mmx = _mm_or_si64( \ + _mm_slli_pi16(dst_odd, 8), \ + _mm_srli_pi16(_mm_slli_pi16(dst_even, 8), 8) \ + ); \ + return vec1d->vec; \ + } while (0) -#define VEC_MMX_MUL_8x8(sign) /* nothing */ +// shared between MMX variations +#define VEC_MMX_MUL_8x8(sign) \ + VEC_MMX_OPERATION_8x8(mullo, sign) + #define VEC_MMX_MUL_16x4(sign) \ - VEC_FUNC_IMPL v##sign##int16x4 v##sign##int16x4_mmx_mul(v##sign##int16x4 vec1, v##sign##int16x4 vec2) \ - { \ + do { \ union v##sign##int16x4_impl_data *vec1d = (union v##sign##int16x4_impl_data *)&vec1; \ union vuint16x4_impl_data *vec2d = (union vuint16x4_impl_data *)&vec2; \ \ vec1d->mmx = _mm_mullo_pi16(vec1d->mmx, vec2d->mmx); \ return vec1d->vec; \ - } -#define VEC_MMX_MUL_32x2(sign) /* nothing */ - -#define VEC_MMX_STRUCT_MUL_8x8(sign) NULL -#define VEC_MMX_STRUCT_MUL_16x4(sign) v##sign##int16x4_mmx_mul -#define VEC_MMX_STRUCT_MUL_32x8(sign) NULL - -/* ------------------------------------------------------------------------ */ -/* comparison */ + } while (0) -/* helper funcs */ -#define VEC_xMMX_CMP(name, op, sign, bits, size, first, second, VARS, TRANS1, TRANS2) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_##name(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - VARS \ - \ - TRANS1 \ - \ - vec1d->mmx = _mm_##op##_pi##bits(vec##first##d->mmx, vec##second##d->mmx); \ - \ - TRANS2 \ - \ - return vec1d->vec; \ - } - -#define VEC_MMX_CMP(name, op, bits, size, first, second) \ - VEC_xMMX_CMP(name, op, /* nothing */, bits, size, first, second, /* nothing */, /* nothing */, /* nothing */) - -#define VEC_uMMX_CMP(name, op, bits, size, first, second) \ - VEC_xMMX_CMP(name, op, u, bits, size, first, second, \ - __m64 xor_val = _mm_set1_pi##bits(1u << (bits - 1)); \ - , { \ - vec1d->mmx = _mm_xor_si64(vec1d->mmx, xor_val); \ - vec2d->mmx = _mm_xor_si64(vec2d->mmx, xor_val); \ - }, \ - { \ - /* nothing */ \ - }) - -#define VEC_MMX_CMPEQ(sign, bits, size) VEC_xMMX_CMP(cmpeq, cmpeq, sign, bits, size, 1, 2, , ,) -#define VEC_MMX_CMPLT(sign, bits, size) VEC_##sign##MMX_CMP(cmplt, cmpgt, bits, size, 2, 1) -#define VEC_MMX_CMPGT(sign, bits, size) VEC_##sign##MMX_CMP(cmpgt, cmpgt, bits, size, 1, 2) - -/* ------------------------------------------------------------------------ */ +#define VEC_MMX_MUL_32x2(sign) \ + /* TODO implement this for real */ \ + do { \ + return v##sign##int32x2_generic_mul(vec1, vec2); \ + } while (0) #define VEC_MMX_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ union v##sign##int##bits##x##size##_impl_data { \ @@ -95,19 +74,19 @@ VEC_STATIC_ASSERT(VEC_ALIGNOF(__m64) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ VEC_STATIC_ASSERT(sizeof(__m64) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_load_aligned(const vec_##sign##int##bits in[size]) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_load_aligned(const vec_##sign##int##bits in[size]) \ { \ v##sign##int##bits##x##size vec; \ memcpy(&vec, in, sizeof(vec)); \ return vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_mmx_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + static void v##sign##int##bits##x##size##_mmx_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ memcpy(out, &vec, sizeof(vec)); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -117,7 +96,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -127,9 +106,12 @@ return vec1d->vec; \ } \ \ - VEC_MMX_MUL_##bits##x##size(sign) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + { \ + VEC_MMX_MUL_##bits##x##size(sign); \ + } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -139,7 +121,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -149,7 +131,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -159,22 +141,29 @@ return vec1d->vec; \ } \ \ - VEC_MMX_CMPEQ(sign, bits, size) \ - VEC_MMX_CMPLT(sign, bits, size) \ - VEC_MMX_CMPGT(sign, bits, size) \ - \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_mmx = { \ - .load_aligned = v##sign##int##bits##x##size##_mmx_load_aligned, \ - .load = v##sign##int##bits##x##size##_mmx_load_aligned, \ - .store_aligned = v##sign##int##bits##x##size##_mmx_store_aligned, \ - .store = v##sign##int##bits##x##size##_mmx_store_aligned, \ - .add = v##sign##int##bits##x##size##_mmx_add, \ - .sub = v##sign##int##bits##x##size##_mmx_sub, \ - .mul = VEC_MMX_STRUCT_MUL_8x8(sign), \ - .band = v##sign##int##bits##x##size##_mmx_and, \ - .bor = v##sign##int##bits##x##size##_mmx_or, \ - .bxor = v##sign##int##bits##x##size##_mmx_xor, \ - .cmpeq = v##sign##int##bits##x##size##_mmx_cmpeq, \ + v##sign##int##bits##x##size##_generic_splat, \ + v##sign##int##bits##x##size##_mmx_load_aligned, \ + v##sign##int##bits##x##size##_mmx_load_aligned, \ + v##sign##int##bits##x##size##_mmx_store_aligned, \ + v##sign##int##bits##x##size##_mmx_store_aligned, \ + v##sign##int##bits##x##size##_mmx_add, \ + v##sign##int##bits##x##size##_mmx_sub, \ + v##sign##int##bits##x##size##_mmx_mul, \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_generic_avg, \ + v##sign##int##bits##x##size##_mmx_and, \ + v##sign##int##bits##x##size##_mmx_or, \ + v##sign##int##bits##x##size##_mmx_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_generic_lshift, \ + v##sign##int##bits##x##size##_generic_rshift, \ + v##sign##int##bits##x##size##_generic_lrshift, \ + v##sign##int##bits##x##size##_generic_cmplt, \ + v##sign##int##bits##x##size##_generic_cmple, \ + v##sign##int##bits##x##size##_generic_cmpeq, \ + v##sign##int##bits##x##size##_generic_cmpge, \ + v##sign##int##bits##x##size##_generic_cmpgt, \ }; #define VEC_MMX_DEFINE_OPERATIONS(bits, size) \
--- a/src/impl/x86/sse2.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/x86/sse2.c Fri Apr 25 17:40:33 2025 -0400 @@ -23,110 +23,10 @@ **/ #include "vec/impl/x86/sse2.h" +#include "vec/impl/generic.h" #include <emmintrin.h> -#define VEC_SSE2_DEFINE_IMPL_DATA(sign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - __m128i sse; \ - }; \ - \ - VEC_STATIC_ASSERT(VEC_ALIGNOF(__m128i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ - VEC_STATIC_ASSERT(sizeof(__m128i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); - -VEC_SSE2_DEFINE_IMPL_DATA( , 8, 16) -VEC_SSE2_DEFINE_IMPL_DATA(u, 8, 16) -VEC_SSE2_DEFINE_IMPL_DATA( , 16, 8) -VEC_SSE2_DEFINE_IMPL_DATA(u, 16, 8) -VEC_SSE2_DEFINE_IMPL_DATA( , 32, 4) -VEC_SSE2_DEFINE_IMPL_DATA(u, 32, 4) -VEC_SSE2_DEFINE_IMPL_DATA( , 64, 2) -VEC_SSE2_DEFINE_IMPL_DATA(u, 64, 2) - -/* eh */ -#define MM_SET1_8(x) _mm_set1_epi8(x) -#define MM_SET1_16(x) _mm_set1_epi16(x) -#define MM_SET1_32(x) _mm_set1_epi32(x) -#define MM_SET1_64(x) _mm_set1_epi64x(x) - -/* ------------------------------------------------------------------------ */ - -/* unfortunately doing this for SSE2 is PREPROCESSOR HELL */ -#define VEC_SSE2_MINMAX_8x16_TEMPLATE(SIGN, OP, VALS, ADDITIONAL1, ADDITIONAL2) \ - VEC_FUNC_IMPL v##SIGN##int8x16 v##SIGN##int8x16_sse2_##OP(v##SIGN##int8x16 vec1, v##SIGN##int8x16 vec2) \ - { \ - union v##SIGN##int8x16_impl_data *vec1d = (union v##SIGN##int8x16_impl_data *)&vec1; \ - union v##SIGN##int8x16_impl_data *vec2d = (union v##SIGN##int8x16_impl_data *)&vec2; \ - VALS \ - \ - ADDITIONAL1 \ - \ - vec1d->sse = _mm_##OP##_epu8(vec1d->sse, vec2d->sse); \ - \ - ADDITIONAL2 \ - \ - return vec1d->vec; \ - } - -/* conveniently, this looks like K&R C ;) */ -#define VEC_SSE2_MINMAX_8x16(OP) \ - VEC_SSE2_MINMAX_8x16_TEMPLATE(/* nothing */, OP, \ - __m128i xor_val = _mm_set1_epi8(0x80u); \ - , { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - vec2d->sse = _mm_xor_si128(vec2d->sse, xor_val); \ - }, \ - { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - }) - -#define VEC_SSE2_MINMAX_u8x16(OP) \ - VEC_SSE2_MINMAX_8x16_TEMPLATE(u, OP, /* nothing */, /* nothing */, /* nothing */) - -#define VEC_SSE2_MINMAX_16x8_TEMPLATE(SIGN, OP, VALS, ADDITIONAL1, ADDITIONAL2) \ - VEC_FUNC_IMPL v##SIGN##int16x8 v##SIGN##int16x8_sse2_##OP(v##SIGN##int16x8 vec1, v##SIGN##int16x8 vec2) \ - { \ - union v##SIGN##int16x8_impl_data *vec1d = (union v##SIGN##int16x8_impl_data *)&vec1; \ - union v##SIGN##int16x8_impl_data *vec2d = (union v##SIGN##int16x8_impl_data *)&vec2; \ - VALS \ - \ - ADDITIONAL1 \ - \ - vec1d->sse = _mm_##OP##_epi16(vec1d->sse, vec2d->sse); \ - \ - ADDITIONAL2 \ - \ - return vec1d->vec; \ - } - -#define VEC_SSE2_MINMAX_16x8(OP) \ - VEC_SSE2_MINMAX_16x8_TEMPLATE(/* nothing */, OP, /* nothing */, /* nothing */, /* nothing */) - -#define VEC_SSE2_MINMAX_u16x8(OP) \ - VEC_SSE2_MINMAX_16x8_TEMPLATE(u, OP, \ - __m128i xor_val = _mm_set1_epi16(0x8000u); \ - , { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - vec2d->sse = _mm_xor_si128(vec2d->sse, xor_val); \ - }, \ - { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - }) - -#define VEC_SSE2_MINMAX_32x4(OP) /* none */ -#define VEC_SSE2_MINMAX_64x2(OP) /* none */ -#define VEC_SSE2_MINMAX_u32x4(OP) /* none */ -#define VEC_SSE2_MINMAX_u64x2(OP) /* none */ - -#define VEC_SSE2_STRUCT_MINMAX_8x16(OP, SIGN) v##SIGN##int8x16_sse2_##OP -#define VEC_SSE2_STRUCT_MINMAX_16x8(OP, SIGN) v##SIGN##int16x8_sse2_##OP -#define VEC_SSE2_STRUCT_MINMAX_32x4(OP, SIGN) NULL -#define VEC_SSE2_STRUCT_MINMAX_64x2(OP, SIGN) NULL - -/* ------------------------------------------------------------------------ */ -/* multiplication */ - #define VEC_SSE2_OPERATION_8x16(op, sign) \ do { \ /* unpack and multiply */ \ @@ -192,58 +92,45 @@ return vec1d->vec; \ } while (0) -/* ------------------------------------------------------------------------ */ -/* comparison */ - -/* helper funcs */ -#define VEC_xSSE2_CMP(name, op, sign, bits, size, first, second, VARS, TRANS1, TRANS2) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_##name(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - VARS \ +#define VEC_SSE2_CMPEQ_8x16(sign) \ + do { \ + union v##sign##int8x16_impl_data *vec1d = (union v##sign##int8x16_impl_data *)&vec1; \ + union v##sign##int8x16_impl_data *vec2d = (union v##sign##int8x16_impl_data *)&vec2; \ \ - TRANS1 \ - \ - vec1d->sse = _mm_##op##_epi##bits(vec##first##d->sse, vec##second##d->sse); \ - \ - TRANS2 \ + vec1d->sse = _mm_cmpeq_epi8(vec1d->sse, vec2d->sse); \ + return vec1d->vec; \ + } while (0) + +#define VEC_SSE2_CMPEQ_16x8(sign) \ + do { \ + union v##sign##int16x8_impl_data *vec1d = (union v##sign##int16x8_impl_data *)&vec1; \ + union v##sign##int16x8_impl_data *vec2d = (union v##sign##int16x8_impl_data *)&vec2; \ \ + vec1d->sse = _mm_cmpeq_epi16(vec1d->sse, vec2d->sse); \ return vec1d->vec; \ - } - -#define VEC_SSE2_CMP(name, op, bits, size, first, second) \ - VEC_xSSE2_CMP(name, op, /* nothing */, bits, size, first, second, /* nothing */, /* nothing */, /* nothing */) + } while (0) -#define VEC_uSSE2_CMP(name, op, bits, size, first, second) \ - VEC_xSSE2_CMP(name, op, u, bits, size, first, second, \ - __m128i xor_val = MM_SET1_##bits(1u << (bits - 1)); \ - , { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - vec2d->sse = _mm_xor_si128(vec2d->sse, xor_val); \ - }, \ - { \ - /* nothing */ \ - }) +#define VEC_SSE2_CMPEQ_32x4(sign) \ + do { \ + union v##sign##int32x4_impl_data *vec1d = (union v##sign##int32x4_impl_data *)&vec1; \ + union v##sign##int32x4_impl_data *vec2d = (union v##sign##int32x4_impl_data *)&vec2; \ + \ + vec1d->sse = _mm_cmpeq_epi32(vec1d->sse, vec2d->sse); \ + return vec1d->vec; \ + } while (0) -/* these are the same for unsigned and signed, for obvious reasons. */ -#define VEC_SSE2_CMPEQ_8x16(sign) VEC_xSSE2_CMP(cmpeq, cmpeq, sign, 8, 16, 1, 2, , ,) -#define VEC_SSE2_CMPEQ_16x8(sign) VEC_xSSE2_CMP(cmpeq, cmpeq, sign, 16, 8, 1, 2, , ,) -#define VEC_SSE2_CMPEQ_32x4(sign) VEC_xSSE2_CMP(cmpeq, cmpeq, sign, 32, 4, 1, 2, , ,) - -/* SSE2 doesn't have an intrinsic for 64x2 equality comparison, - * so how can we take a 32x4 comparison result and turn it into - * a 64x2 comparison result? - * - * well, Intel conveniently provided an operation where we can - * shuffle around 32-bit integers (_mm_shuffle_epi32). - * - * this means all we have to do is simply do the 32-bit operation, - * shuffle the parts, and then return a bitwise AND of the result. */ +// SSE2 doesn't have an intrinsic for 64x2 equality comparison, +// so how can we take a 32x4 comparison result and turn it into +// a 64x2 comparison result? +// +// well, Intel conveniently provided an operation where we can +// shuffle around 32-bit integers (_mm_shuffle_epi32). +// +// this means all we have to do is simply do the 32-bit operation, +// shuffle the parts, and then return a bitwise AND of the result. #define VEC_SSE2_CMPEQ_64x2(sign) \ - VEC_FUNC_IMPL v##sign##int64x2 v##sign##int64x2_sse2_cmpeq(v##sign##int64x2 vec1, v##sign##int64x2 vec2) \ - { \ + do { \ union v##sign##int64x2_impl_data *vec1d = (union v##sign##int64x2_impl_data *)&vec1; \ union v##sign##int64x2_impl_data *vec2d = (union v##sign##int64x2_impl_data *)&vec2; \ \ @@ -253,60 +140,42 @@ vec1d->sse = _mm_and_si128(vec1d->sse, vec2d->sse); \ \ return vec1d->vec; \ - } - -/* ------------------------------------------------------------------------ */ - -#define VEC_SSE2_CMPLT_8x16(sign) VEC_##sign##SSE2_CMP(cmplt, cmpgt, 8, 16, 2, 1) -#define VEC_SSE2_CMPLT_16x8(sign) VEC_##sign##SSE2_CMP(cmplt, cmpgt, 16, 8, 2, 1) -#define VEC_SSE2_CMPLT_32x4(sign) VEC_##sign##SSE2_CMP(cmplt, cmpgt, 32, 4, 2, 1) -#define VEC_SSE2_CMPLT_64x2(sign) /* nothing */ - -#define VEC_SSE2_CMPGT_8x16(sign) VEC_##sign##SSE2_CMP(cmpgt, cmpgt, 8, 16, 1, 2) -#define VEC_SSE2_CMPGT_16x8(sign) VEC_##sign##SSE2_CMP(cmpgt, cmpgt, 16, 8, 1, 2) -#define VEC_SSE2_CMPGT_32x4(sign) VEC_##sign##SSE2_CMP(cmpgt, cmpgt, 32, 4, 1, 2) -#define VEC_SSE2_CMPGT_64x2(sign) /* nothing */ - -#define VEC_SSE2_STRUCT_CMP_8x16(name, sign) v##sign##int8x16_sse2_##name -#define VEC_SSE2_STRUCT_CMP_16x8(name, sign) v##sign##int16x8_sse2_##name -#define VEC_SSE2_STRUCT_CMP_32x4(name, sign) v##sign##int32x4_sse2_##name -#define VEC_SSE2_STRUCT_CMP_64x2(name, sign) NULL - -/* ------------------------------------------------------------------------ */ + } while (0) #define VEC_SSE2_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_splat(vec_##sign##int##bits x) \ - { \ - union v##sign##int##bits##x##size##_impl_data vec; \ - vec.sse = MM_SET1_##bits(x); \ - return vec.vec; \ - } \ + union v##sign##int##bits##x##size##_impl_data { \ + v##sign##int##bits##x##size vec; \ + __m128i sse; \ + }; \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load_aligned(const vec_##sign##int##bits in[size]) \ + VEC_STATIC_ASSERT(VEC_ALIGNOF(__m128i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ + VEC_STATIC_ASSERT(sizeof(__m128i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ + \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load_aligned(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.sse = _mm_load_si128((const __m128i *)in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load(const vec_##sign##int##bits in[size]) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load(const vec_##sign##int##bits in[size]) \ { \ union v##sign##int##bits##x##size##_impl_data vec; \ vec.sse = _mm_loadu_si128((const __m128i *)in); \ return vec.vec; \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_sse2_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + void v##sign##int##bits##x##size##_sse2_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ _mm_store_si128((__m128i *)out, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->sse); \ } \ \ - VEC_FUNC_IMPL void v##sign##int##bits##x##size##_sse2_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ + void v##sign##int##bits##x##size##_sse2_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ { \ _mm_storeu_si128((__m128i *)out, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->sse); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -315,7 +184,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -324,12 +193,12 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ VEC_SSE2_MUL_##bits##x##size(sign); \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -338,7 +207,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -347,7 +216,7 @@ return vec1d->vec; \ } \ \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ { \ union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ @@ -356,30 +225,34 @@ return vec1d->vec; \ } \ \ - VEC_SSE2_CMPEQ_##bits##x##size(sign); \ - VEC_SSE2_CMPLT_##bits##x##size(sign); \ - VEC_SSE2_CMPGT_##bits##x##size(sign); \ - \ - VEC_SSE2_MINMAX_##sign##bits##x##size(min) \ - VEC_SSE2_MINMAX_##sign##bits##x##size(max) \ + v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ + { \ + VEC_SSE2_CMPEQ_##bits##x##size(sign); \ + } \ \ const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_sse2 = { \ - .splat = v##sign##int##bits##x##size##_sse2_splat, \ - .load_aligned = v##sign##int##bits##x##size##_sse2_load_aligned, \ - .load = v##sign##int##bits##x##size##_sse2_load, \ - .store_aligned = v##sign##int##bits##x##size##_sse2_store_aligned, \ - .store = v##sign##int##bits##x##size##_sse2_store, \ - .add = v##sign##int##bits##x##size##_sse2_add, \ - .sub = v##sign##int##bits##x##size##_sse2_sub, \ - .mul = v##sign##int##bits##x##size##_sse2_mul, \ - .band = v##sign##int##bits##x##size##_sse2_and, \ - .bor = v##sign##int##bits##x##size##_sse2_or, \ - .bxor = v##sign##int##bits##x##size##_sse2_xor, \ - .cmpeq = v##sign##int##bits##x##size##_sse2_cmpeq, \ - .cmplt = VEC_SSE2_STRUCT_CMP_##bits##x##size(cmplt, sign), \ - .cmpgt = VEC_SSE2_STRUCT_CMP_##bits##x##size(cmpgt, sign), \ - .min = VEC_SSE2_STRUCT_MINMAX_##bits##x##size(min, sign), \ - .max = VEC_SSE2_STRUCT_MINMAX_##bits##x##size(max, sign), \ + v##sign##int##bits##x##size##_generic_splat, \ + v##sign##int##bits##x##size##_sse2_load_aligned, \ + v##sign##int##bits##x##size##_sse2_load, \ + v##sign##int##bits##x##size##_sse2_store_aligned, \ + v##sign##int##bits##x##size##_sse2_store, \ + v##sign##int##bits##x##size##_sse2_add, \ + v##sign##int##bits##x##size##_sse2_sub, \ + v##sign##int##bits##x##size##_sse2_mul, \ + v##sign##int##bits##x##size##_generic_div, \ + v##sign##int##bits##x##size##_generic_avg, \ + v##sign##int##bits##x##size##_sse2_and, \ + v##sign##int##bits##x##size##_sse2_or, \ + v##sign##int##bits##x##size##_sse2_xor, \ + v##sign##int##bits##x##size##_generic_not, \ + v##sign##int##bits##x##size##_generic_lshift, \ + v##sign##int##bits##x##size##_generic_rshift, \ + v##sign##int##bits##x##size##_generic_lrshift, \ + v##sign##int##bits##x##size##_generic_cmplt, \ + v##sign##int##bits##x##size##_generic_cmple, \ + v##sign##int##bits##x##size##_sse2_cmpeq, \ + v##sign##int##bits##x##size##_generic_cmpge, \ + v##sign##int##bits##x##size##_generic_cmpgt, \ }; #define VEC_SSE2_DEFINE_OPERATIONS(bits, size) \
--- a/src/impl/x86/sse3.c Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#include "vec/impl/x86/sse3.h" - -#include <pmmintrin.h> - -/* SSE3 has a slightly more optimized load function */ - -#define VEC_SSE2_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - __m128i sse; \ - }; \ - \ - VEC_STATIC_ASSERT(VEC_ALIGNOF(__m128i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \ - VEC_STATIC_ASSERT(sizeof(__m128i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \ - \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse2_load(const vec_##sign##int##bits in[size]) \ - { \ - union v##sign##int##bits##x##size##_impl_data vec; \ - vec.sse = _mm_lddqu_si128((const __m128i *)in); \ - return vec.vec; \ - } \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_sse3 = { \ - .load = v##sign##int##bits##x##size##_sse2_load, \ - }; - -#define VEC_SSE2_DEFINE_OPERATIONS(bits, size) \ - VEC_SSE2_DEFINE_OPERATIONS_SIGN(u, bits, size) \ - VEC_SSE2_DEFINE_OPERATIONS_SIGN( , bits, size) - -VEC_SSE2_DEFINE_OPERATIONS(8, 16) -VEC_SSE2_DEFINE_OPERATIONS(16, 8) -VEC_SSE2_DEFINE_OPERATIONS(32, 4) -VEC_SSE2_DEFINE_OPERATIONS(64, 2)
--- a/src/impl/x86/sse41.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/impl/x86/sse41.c Fri Apr 25 17:40:33 2025 -0400 @@ -23,138 +23,54 @@ **/ #include "vec/impl/x86/sse41.h" +#include "vec/impl/x86/sse2.h" #include "vec/impl/generic.h" #include <immintrin.h> -/* ------------------------------------------------------------------------ */ - -#define VEC_SSE41_MINMAX_TEMPLATE(SIGN, BITS, SIZE, INTLSIGN, OP) \ - VEC_FUNC_IMPL v##SIGN##int##BITS##x##SIZE v##SIGN##int##BITS##x##SIZE##_sse41_##OP(v##SIGN##int##BITS##x##SIZE vec1, v##SIGN##int##BITS##x##SIZE vec2) \ - { \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec1d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec1; \ - union v##SIGN##int##BITS##x##SIZE##_impl_data *vec2d = (union v##SIGN##int##BITS##x##SIZE##_impl_data *)&vec2; \ - \ - vec1d->sse = _mm_##OP##_ep##INTLSIGN##BITS(vec1d->sse, vec2d->sse); \ +// SSE 4.1 provides a real _mm_mullo_epi32 +#define VEC_SSE41_DEFINE_OPERATIONS(sign) \ + union v##sign##int32x4_impl_data { \ + v##sign##int32x4 vec; \ + __m128i sse; \ + }; \ \ - return vec1d->vec; \ - } - -#define VEC_SSE41_MINMAX_8x16(OP) VEC_SSE41_MINMAX_TEMPLATE( , 8, 16, i, OP) -#define VEC_SSE41_MINMAX_u8x16(OP) VEC_SSE41_MINMAX_TEMPLATE(u, 8, 16, u, OP) -#define VEC_SSE41_MINMAX_16x8(OP) VEC_SSE41_MINMAX_TEMPLATE( , 16, 8, i, OP) -#define VEC_SSE41_MINMAX_u16x8(OP) VEC_SSE41_MINMAX_TEMPLATE(u, 16, 8, u, OP) -#define VEC_SSE41_MINMAX_32x4(OP) VEC_SSE41_MINMAX_TEMPLATE( , 32, 4, i, OP) -#define VEC_SSE41_MINMAX_u32x4(OP) VEC_SSE41_MINMAX_TEMPLATE(u, 32, 4, u, OP) -#define VEC_SSE41_MINMAX_64x2(OP) /* nothing */ -#define VEC_SSE41_MINMAX_u64x2(OP) /* nothing */ - -#define VEC_SSE41_STRUCT_MINMAX_8x16(OP, SIGN) v##SIGN##int8x16_sse41_##OP -#define VEC_SSE41_STRUCT_MINMAX_16x8(OP, SIGN) v##SIGN##int16x8_sse41_##OP -#define VEC_SSE41_STRUCT_MINMAX_32x4(OP, SIGN) v##SIGN##int32x4_sse41_##OP -#define VEC_SSE41_STRUCT_MINMAX_64x2(OP, SIGN) NULL - -/* ------------------------------------------------------------------------ */ -/* multiplication */ - -#define VEC_SSE41_MUL_8x16(sign) -#define VEC_SSE41_MUL_16x8(sign) -#define VEC_SSE41_MUL_32x4(sign) \ - VEC_FUNC_IMPL v##sign##int32x4 v##sign##int32x4_sse41_mul(v##sign##int32x4 vec1, v##sign##int32x4 vec2) \ + VEC_STATIC_ASSERT(VEC_ALIGNOF(__m128i) <= VEC_ALIGNOF(v##sign##int32x4), "vec: v" #sign "int32x4 alignment needs to be expanded to fit intrinsic type size"); \ + VEC_STATIC_ASSERT(sizeof(__m128i) <= sizeof(v##sign##int32x4), "vec: v" #sign "int32x4 needs to be expanded to fit intrinsic type size"); \ + \ + static v##sign##int32x4 v##sign##int32x4_sse41_mul(v##sign##int32x4 vec1, v##sign##int32x4 vec2) \ { \ union v##sign##int32x4_impl_data *vec1d = (union v##sign##int32x4_impl_data *)&vec1; \ union v##sign##int32x4_impl_data *vec2d = (union v##sign##int32x4_impl_data *)&vec2; \ \ vec1d->sse = _mm_mullo_epi32(vec1d->sse, vec2d->sse); \ return vec1d->vec; \ - } -#define VEC_SSE41_MUL_64x2(sign) - -#define VEC_SSE41_STRUCT_MUL_8x16(SIGN) NULL -#define VEC_SSE41_STRUCT_MUL_16x8(SIGN) NULL -#define VEC_SSE41_STRUCT_MUL_32x4(SIGN) v##SIGN##int32x4_sse41_mul -#define VEC_SSE41_STRUCT_MUL_64x2(SIGN) NULL - -/* ------------------------------------------------------------------------ */ -/* comparison */ - -#define MM_SET1_64(x) _mm_set1_epi64x(x) - -/* helper funcs */ -#define VEC_xSSE41_CMP(name, op, sign, bits, size, first, second, VARS, TRANS1, TRANS2) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse41_##name(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - VARS \ - \ - TRANS1 \ - \ - vec1d->sse = _mm_##op##_epi##bits(vec##first##d->sse, vec##second##d->sse); \ - \ - TRANS2 \ + } \ \ - return vec1d->vec; \ - } - -#define VEC_SSE41_CMP(name, op, bits, size, first, second) \ - VEC_xSSE41_CMP(name, op, /* nothing */, bits, size, first, second, /* nothing */, /* nothing */, /* nothing */) - -#define VEC_uSSE41_CMP(name, op, bits, size, first, second) \ - VEC_xSSE41_CMP(name, op, u, bits, size, first, second, \ - __m128i xor_val = MM_SET1_##bits(UINT64_C(1) << (bits - 1)); \ - , { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - vec2d->sse = _mm_xor_si128(vec2d->sse, xor_val); \ - }, \ - { \ - /* nothing */ \ - }) - -/* these are the same for unsigned and signed, for obvious reasons. */ -#define VEC_SSE41_CMPEQ_8x16(sign) /* nothing */ -#define VEC_SSE41_CMPEQ_16x8(sign) /* nothing */ -#define VEC_SSE41_CMPEQ_32x4(sign) /* nothing */ -#define VEC_SSE41_CMPEQ_64x2(sign) VEC_xSSE41_CMP(cmpeq, cmpeq, sign, 64, 2, 1, 2, , ,) - -/* ------------------------------------------------------------------------ */ - -#define VEC_SSE41_STRUCT_CMP_8x16(name, sign) NULL -#define VEC_SSE41_STRUCT_CMP_16x8(name, sign) NULL -#define VEC_SSE41_STRUCT_CMP_32x4(name, sign) NULL -#define VEC_SSE41_STRUCT_CMP_64x2(name, sign) v##sign##int64x2_sse41_##name - -/* ------------------------------------------------------------------------ */ - -// SSE 4.1 provides a real _mm_mullo_epi32 -#define VEC_SSE41_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - __m128i sse; \ - }; \ - \ - VEC_STATIC_ASSERT(VEC_ALIGNOF(__m128i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int32x4 alignment needs to be expanded to fit intrinsic type size"); \ - VEC_STATIC_ASSERT(sizeof(__m128i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int32x4 needs to be expanded to fit intrinsic type size"); \ - \ - VEC_SSE41_MUL_##bits##x##size(sign) \ - \ - VEC_SSE41_MINMAX_##sign##bits##x##size(min) \ - VEC_SSE41_MINMAX_##sign##bits##x##size(max) \ - \ - VEC_SSE41_CMPEQ_##bits##x##size(sign); \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_sse41 = { \ - .mul = VEC_SSE41_STRUCT_MUL_##bits##x##size(sign), \ - .min = VEC_SSE41_STRUCT_MINMAX_##bits##x##size(min, sign), \ - .max = VEC_SSE41_STRUCT_MINMAX_##bits##x##size(max, sign), \ - .cmpeq = VEC_SSE41_STRUCT_CMP_##bits##x##size(cmpeq, sign), \ + const v##sign##int32x4_impl v##sign##int32x4_impl_sse41 = { \ + v##sign##int32x4_generic_splat, \ + v##sign##int32x4_sse2_load_aligned, \ + v##sign##int32x4_sse2_load, \ + v##sign##int32x4_sse2_store_aligned, \ + v##sign##int32x4_sse2_store, \ + v##sign##int32x4_sse2_add, \ + v##sign##int32x4_sse2_sub, \ + v##sign##int32x4_sse41_mul, \ + v##sign##int32x4_generic_div, \ + v##sign##int32x4_generic_avg, \ + v##sign##int32x4_sse2_and, \ + v##sign##int32x4_sse2_or, \ + v##sign##int32x4_sse2_xor, \ + v##sign##int32x4_generic_not, \ + v##sign##int32x4_generic_lshift, \ + v##sign##int32x4_generic_rshift, \ + v##sign##int32x4_generic_lrshift, \ + v##sign##int32x4_generic_cmplt, \ + v##sign##int32x4_generic_cmple, \ + v##sign##int32x4_sse2_cmpeq, \ + v##sign##int32x4_generic_cmpge, \ + v##sign##int32x4_generic_cmpgt, \ }; -#define VEC_SSE41_DEFINE_OPERATIONS(bits, size) \ - VEC_SSE41_DEFINE_OPERATIONS_SIGN(u, bits, size) \ - VEC_SSE41_DEFINE_OPERATIONS_SIGN( , bits, size) - -VEC_SSE41_DEFINE_OPERATIONS(8, 16) -VEC_SSE41_DEFINE_OPERATIONS(16, 8) -VEC_SSE41_DEFINE_OPERATIONS(32, 4) -VEC_SSE41_DEFINE_OPERATIONS(64, 2) +VEC_SSE41_DEFINE_OPERATIONS() +VEC_SSE41_DEFINE_OPERATIONS(u)
--- a/src/impl/x86/sse42.c Fri Apr 25 17:40:30 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/** - * vec - a tiny SIMD vector library in C99 - * - * Copyright (c) 2024 Paper - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -**/ - -#include "vec/impl/x86/sse42.h" -#include "vec/impl/generic.h" - -#include <immintrin.h> - -/* ------------------------------------------------------------------------ */ -/* comparison */ - -#define MM_SET1_64(x) _mm_set1_epi64x(x) - -/* helper funcs */ -#define VEC_xSSE42_CMP(name, op, sign, bits, size, first, second, VARS, TRANS1, TRANS2) \ - VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_sse42_##name(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ - { \ - union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ - union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ - VARS \ - \ - TRANS1 \ - \ - vec1d->sse = _mm_##op##_epi##bits(vec##first##d->sse, vec##second##d->sse); \ - \ - TRANS2 \ - \ - return vec1d->vec; \ - } - -#define VEC_SSE42_CMP(name, op, bits, size, first, second) \ - VEC_xSSE42_CMP(name, op, /* nothing */, bits, size, first, second, /* nothing */, /* nothing */, /* nothing */) - -#define VEC_uSSE42_CMP(name, op, bits, size, first, second) \ - VEC_xSSE42_CMP(name, op, u, bits, size, first, second, \ - __m128i xor_val = MM_SET1_##bits(UINT64_C(1) << (bits - 1)); \ - , { \ - vec1d->sse = _mm_xor_si128(vec1d->sse, xor_val); \ - vec2d->sse = _mm_xor_si128(vec2d->sse, xor_val); \ - }, \ - { \ - /* nothing */ \ - }) - -/* these are the same for unsigned and signed, for obvious reasons. */ -#define VEC_SSE42_CMPEQ_64x2(sign) VEC_xSSE42_CMP(cmpeq, cmpeq, sign, 64, 2, 1, 2, , ,) - -/* ------------------------------------------------------------------------ */ - -#define VEC_SSE42_CMPLT_64x2(sign) VEC_##sign##SSE42_CMP(cmplt, cmpgt, 64, 2, 2, 1) -#define VEC_SSE42_CMPGT_64x2(sign) VEC_##sign##SSE42_CMP(cmpgt, cmpgt, 64, 2, 1, 2) - -#define VEC_SSE42_STRUCT_CMP_64x2(name, sign) v##sign##int64x2_sse42_##name - -/* ------------------------------------------------------------------------ */ - -// SSE 4.1 provides a real _mm_mullo_epi32 -#define VEC_SSE42_DEFINE_OPERATIONS_SIGN(sign, bits, size) \ - union v##sign##int##bits##x##size##_impl_data { \ - v##sign##int##bits##x##size vec; \ - __m128i sse; \ - }; \ - \ - VEC_STATIC_ASSERT(VEC_ALIGNOF(__m128i) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int32x4 alignment needs to be expanded to fit intrinsic type size"); \ - VEC_STATIC_ASSERT(sizeof(__m128i) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int32x4 needs to be expanded to fit intrinsic type size"); \ - \ - VEC_SSE42_CMPLT_##bits##x##size(sign); \ - VEC_SSE42_CMPGT_##bits##x##size(sign); \ - \ - const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_sse42 = { \ - .cmplt = VEC_SSE42_STRUCT_CMP_##bits##x##size(cmplt, sign), \ - .cmpgt = VEC_SSE42_STRUCT_CMP_##bits##x##size(cmpgt, sign), \ - }; - -#define VEC_SSE42_DEFINE_OPERATIONS(bits, size) \ - VEC_SSE42_DEFINE_OPERATIONS_SIGN(u, bits, size) \ - VEC_SSE42_DEFINE_OPERATIONS_SIGN( , bits, size) - -VEC_SSE42_DEFINE_OPERATIONS(64, 2)
--- a/src/vec.c Fri Apr 25 17:40:30 2025 -0400 +++ b/src/vec.c Fri Apr 25 17:40:33 2025 -0400 @@ -32,27 +32,15 @@ #ifdef VEC_COMPILER_HAS_SSE2 # include "vec/impl/x86/sse2.h" #endif -#ifdef VEC_COMPILER_HAS_SSE3 -# include "vec/impl/x86/sse3.h" -#endif #ifdef VEC_COMPILER_HAS_SSE41 # include "vec/impl/x86/sse41.h" #endif -#ifdef VEC_COMPILER_HAS_SSE42 -# include "vec/impl/x86/sse42.h" -#endif #ifdef VEC_COMPILER_HAS_AVX2 # include "vec/impl/x86/avx2.h" #endif #ifdef VEC_COMPILER_HAS_AVX512F # include "vec/impl/x86/avx512f.h" #endif -#ifdef VEC_COMPILER_HAS_AVX512BW -# include "vec/impl/x86/avx512bw.h" -#endif -#ifdef VEC_COMPILER_HAS_AVX512DQ -# include "vec/impl/x86/avx512dq.h" -#endif #ifdef VEC_COMPILER_HAS_ALTIVEC # include "vec/impl/ppc/altivec.h" #endif @@ -71,284 +59,166 @@ extern inline vec_uintmax vec_uavg(vec_uintmax x, vec_uintmax y); // 16-bit -vint8x2_impl vint8x2_impl_cpu = {0}; -vuint8x2_impl vuint8x2_impl_cpu = {0}; +const vint8x2_impl *vint8x2_impl_cpu = &vint8x2_impl_generic; +const vuint8x2_impl *vuint8x2_impl_cpu = &vuint8x2_impl_generic; // 32-bit -vint8x4_impl vint8x4_impl_cpu = {0}; -vuint8x4_impl vuint8x4_impl_cpu = {0}; -vint16x2_impl vint16x2_impl_cpu = {0}; -vuint16x2_impl vuint16x2_impl_cpu = {0}; +const vint8x4_impl *vint8x4_impl_cpu = &vint8x4_impl_generic; +const vuint8x4_impl *vuint8x4_impl_cpu = &vuint8x4_impl_generic; +const vint16x2_impl *vint16x2_impl_cpu = &vint16x2_impl_generic; +const vuint16x2_impl *vuint16x2_impl_cpu = &vuint16x2_impl_generic; // 64-bit -vint8x8_impl vint8x8_impl_cpu = {0}; -vuint8x8_impl vuint8x8_impl_cpu = {0}; -vint16x4_impl vint16x4_impl_cpu = {0}; -vuint16x4_impl vuint16x4_impl_cpu = {0}; -vint32x2_impl vint32x2_impl_cpu = {0}; -vuint32x2_impl vuint32x2_impl_cpu = {0}; +const vint8x8_impl *vint8x8_impl_cpu = &vint8x8_impl_generic; +const vuint8x8_impl *vuint8x8_impl_cpu = &vuint8x8_impl_generic; +const vint16x4_impl *vint16x4_impl_cpu = &vint16x4_impl_generic; +const vuint16x4_impl *vuint16x4_impl_cpu = &vuint16x4_impl_generic; +const vint32x2_impl *vint32x2_impl_cpu = &vint32x2_impl_generic; +const vuint32x2_impl *vuint32x2_impl_cpu = &vuint32x2_impl_generic; // 128-bit -vint8x16_impl vint8x16_impl_cpu = {0}; -vuint8x16_impl vuint8x16_impl_cpu = {0}; -vint16x8_impl vint16x8_impl_cpu = {0}; -vuint16x8_impl vuint16x8_impl_cpu = {0}; -vint32x4_impl vint32x4_impl_cpu = {0}; -vuint32x4_impl vuint32x4_impl_cpu = {0}; -vint64x2_impl vint64x2_impl_cpu = {0}; -vuint64x2_impl vuint64x2_impl_cpu = {0}; +const vint8x16_impl *vint8x16_impl_cpu = &vint8x16_impl_generic; +const vuint8x16_impl *vuint8x16_impl_cpu = &vuint8x16_impl_generic; +const vint16x8_impl *vint16x8_impl_cpu = &vint16x8_impl_generic; +const vuint16x8_impl *vuint16x8_impl_cpu = &vuint16x8_impl_generic; +const vint32x4_impl *vint32x4_impl_cpu = &vint32x4_impl_generic; +const vuint32x4_impl *vuint32x4_impl_cpu = &vuint32x4_impl_generic; +const vint64x2_impl *vint64x2_impl_cpu = &vint64x2_impl_generic; +const vuint64x2_impl *vuint64x2_impl_cpu = &vuint64x2_impl_generic; // 256-bit -vint8x32_impl vint8x32_impl_cpu = {0}; -vuint8x32_impl vuint8x32_impl_cpu = {0}; -vint16x16_impl vint16x16_impl_cpu = {0}; -vuint16x16_impl vuint16x16_impl_cpu = {0}; -vint32x8_impl vint32x8_impl_cpu = {0}; -vuint32x8_impl vuint32x8_impl_cpu = {0}; -vint64x4_impl vint64x4_impl_cpu = {0}; -vuint64x4_impl vuint64x4_impl_cpu = {0}; +const vint8x32_impl *vint8x32_impl_cpu = &vint8x32_impl_generic; +const vuint8x32_impl *vuint8x32_impl_cpu = &vuint8x32_impl_generic; +const vint16x16_impl *vint16x16_impl_cpu = &vint16x16_impl_generic; +const vuint16x16_impl *vuint16x16_impl_cpu = &vuint16x16_impl_generic; +const vint32x8_impl *vint32x8_impl_cpu = &vint32x8_impl_generic; +const vuint32x8_impl *vuint32x8_impl_cpu = &vuint32x8_impl_generic; +const vint64x4_impl *vint64x4_impl_cpu = &vint64x4_impl_generic; +const vuint64x4_impl *vuint64x4_impl_cpu = &vuint64x4_impl_generic; // 512-bit -vint8x64_impl vint8x64_impl_cpu = {0}; -vuint8x64_impl vuint8x64_impl_cpu = {0}; -vint16x32_impl vint16x32_impl_cpu = {0}; -vuint16x32_impl vuint16x32_impl_cpu = {0}; -vint32x16_impl vint32x16_impl_cpu = {0}; -vuint32x16_impl vuint32x16_impl_cpu = {0}; -vint64x8_impl vint64x8_impl_cpu = {0}; -vuint64x8_impl vuint64x8_impl_cpu = {0}; +const vint8x64_impl *vint8x64_impl_cpu = &vint8x64_impl_generic; +const vuint8x64_impl *vuint8x64_impl_cpu = &vuint8x64_impl_generic; +const vint16x32_impl *vint16x32_impl_cpu = &vint16x32_impl_generic; +const vuint16x32_impl *vuint16x32_impl_cpu = &vuint16x32_impl_generic; +const vint32x16_impl *vint32x16_impl_cpu = &vint32x16_impl_generic; +const vuint32x16_impl *vuint32x16_impl_cpu = &vuint32x16_impl_generic; +const vint64x8_impl *vint64x8_impl_cpu = &vint64x8_impl_generic; +const vuint64x8_impl *vuint64x8_impl_cpu = &vuint64x8_impl_generic; static int vec_init_spinner = 0; -#define FILL_GIVEN_FUNC_PTR(cpu, impl, func) \ - do { \ - if (!(cpu).func && (impl).func) \ - (cpu).func = (impl).func; \ - } while (0) - -#define FILL_GIVEN_FUNC_PTRS_EX(cpu, impl) \ - do { \ - FILL_GIVEN_FUNC_PTR(cpu, impl, splat); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, load_aligned); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, load); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, store_aligned); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, store); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, add); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, sub); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, mul); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, div); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, avg); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, band); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, bor); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, bxor); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, lshift); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, rshift); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, lrshift); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, cmplt); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, cmple); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, cmpeq); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, cmpge); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, cmpgt); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, min); \ - FILL_GIVEN_FUNC_PTR(cpu, impl, max); \ - } while (0) - -#define FILL_GIVEN_FUNC_PTRS(sign, bits, size, impl) \ - FILL_GIVEN_FUNC_PTRS_EX(v##sign##int##bits##x##size##_impl_cpu, v##sign##int##bits##x##size##_impl_##impl) - // returns 0 or a negative error code on failure int vec_init(void) { // This function is NOT thread safe. However, once vec // is initialized, all of the vector functions are thread-safe. + // + // In fact, it's possible to use vec without calling + // vec_init() at all, but it would be completely useless since + // it would just use a generic implementation without any + // vectorization whatsoever (unless maybe the compiler is + // smart enough to optimize it into vectors) if (vec_init_spinner) return 0; // already initialized, do nothing vec_uint32 cpu = vec_get_CPU_features(); - /* Okay, this might be a little confusing: - * The way we do this is because of x86. For weird reasons, - * Intel decided to extend their prior CPU extensions to - * where SSE4.1 has some extended features of SSE2, AVX2 - * has some extended features that should've been in SSE - * in general, etc. - * - * For this, I've just decided to keep the function - * definitions private, and fill in as we go, with newer - * intrinsics preferred. Others are arbitrary and are - * mutually exclusive (i.e. Altivec vs NEON). This is simply - * the easiest way to go about it :) */ - - /* --- 512-bit */ -#ifdef VEC_COMPILER_HAS_AVX512DQ - if (cpu & VEC_CPU_HAS_AVX512DQ) { - /* these give us native multiply instructions */ - FILL_GIVEN_FUNC_PTRS( , 64, 8, avx512dq); - FILL_GIVEN_FUNC_PTRS(u, 64, 8, avx512dq); - } +#ifdef VEC_COMPILER_HAS_ALTIVEC + if (cpu & VEC_CPU_HAS_ALTIVEC) { + vint8x16_impl_cpu = &vint8x16_impl_altivec; + vuint8x16_impl_cpu = &vuint8x16_impl_altivec; + vint16x8_impl_cpu = &vint16x8_impl_altivec; + vuint16x8_impl_cpu = &vuint16x8_impl_altivec; + vint32x4_impl_cpu = &vint32x4_impl_altivec; + vuint32x4_impl_cpu = &vuint32x4_impl_altivec; +#ifdef VEC_COMPILER_HAS_ALTIVEC_VSX + if (cpu & VEC_CPU_HAS_ALTIVEC_VSX) { + vint64x2_impl_cpu = &vint64x2_impl_altivec; + vuint64x2_impl_cpu = &vuint64x2_impl_altivec; + } #endif -#ifdef VEC_COMPILER_HAS_AVX512BW - if (cpu & VEC_CPU_HAS_AVX512BW) { - FILL_GIVEN_FUNC_PTRS( , 8, 64, avx512bw); - FILL_GIVEN_FUNC_PTRS(u, 8, 64, avx512bw); - FILL_GIVEN_FUNC_PTRS( , 16, 32, avx512bw); - FILL_GIVEN_FUNC_PTRS(u, 16, 32, avx512bw); } #endif #ifdef VEC_COMPILER_HAS_AVX512F if (cpu & VEC_CPU_HAS_AVX512F) { - FILL_GIVEN_FUNC_PTRS( , 32, 16, avx512f); - FILL_GIVEN_FUNC_PTRS(u, 32, 16, avx512f); - FILL_GIVEN_FUNC_PTRS( , 64, 8, avx512f); - FILL_GIVEN_FUNC_PTRS(u, 64, 8, avx512f); - } -#endif - - /* --- 256-bit */ -#ifdef VEC_COMPILER_HAS_AVX2 - if (cpu & VEC_CPU_HAS_AVX2) { - FILL_GIVEN_FUNC_PTRS( , 8, 32, avx2); - FILL_GIVEN_FUNC_PTRS(u, 8, 32, avx2); - FILL_GIVEN_FUNC_PTRS( , 16, 16, avx2); - FILL_GIVEN_FUNC_PTRS(u, 16, 16, avx2); - FILL_GIVEN_FUNC_PTRS( , 32, 8, avx2); - FILL_GIVEN_FUNC_PTRS(u, 32, 8, avx2); - FILL_GIVEN_FUNC_PTRS( , 64, 4, avx2); - FILL_GIVEN_FUNC_PTRS(u, 64, 4, avx2); + vint8x64_impl_cpu = &vint8x64_impl_avx512f; + vuint8x64_impl_cpu = &vuint8x64_impl_avx512f; + vint16x32_impl_cpu = &vint16x32_impl_avx512f; + vuint16x32_impl_cpu = &vuint16x32_impl_avx512f; + vint32x16_impl_cpu = &vint32x16_impl_avx512f; + vuint32x16_impl_cpu = &vuint32x16_impl_avx512f; + vint64x8_impl_cpu = &vint64x8_impl_avx512f; + vuint64x8_impl_cpu = &vuint64x8_impl_avx512f; } #endif - - /* --- 128-bit */ -#ifdef VEC_COMPILER_HAS_SSE42 - if (cpu & VEC_CPU_HAS_SSE41) { - FILL_GIVEN_FUNC_PTRS( , 64, 2, sse42); - FILL_GIVEN_FUNC_PTRS(u, 64, 2, sse42); - } -#endif -#ifdef VEC_COMPILER_HAS_SSE41 - if (cpu & VEC_CPU_HAS_SSE41) { - FILL_GIVEN_FUNC_PTRS( , 8, 16, sse41); - FILL_GIVEN_FUNC_PTRS(u, 8, 16, sse41); - FILL_GIVEN_FUNC_PTRS( , 16, 8, sse41); - FILL_GIVEN_FUNC_PTRS(u, 16, 8, sse41); - FILL_GIVEN_FUNC_PTRS( , 32, 4, sse41); - FILL_GIVEN_FUNC_PTRS(u, 32, 4, sse41); - FILL_GIVEN_FUNC_PTRS( , 64, 2, sse41); - FILL_GIVEN_FUNC_PTRS(u, 64, 2, sse41); - } -#endif -#ifdef VEC_COMPILER_HAS_SSE3 - if (cpu & VEC_CPU_HAS_SSE3) { - FILL_GIVEN_FUNC_PTRS( , 8, 16, sse3); - FILL_GIVEN_FUNC_PTRS(u, 8, 16, sse3); - FILL_GIVEN_FUNC_PTRS( , 16, 8, sse3); - FILL_GIVEN_FUNC_PTRS(u, 16, 8, sse3); - FILL_GIVEN_FUNC_PTRS( , 32, 4, sse3); - FILL_GIVEN_FUNC_PTRS(u, 32, 4, sse3); - FILL_GIVEN_FUNC_PTRS( , 64, 2, sse3); - FILL_GIVEN_FUNC_PTRS(u, 64, 2, sse3); +#ifdef VEC_COMPILER_HAS_AVX2 + if (cpu & VEC_CPU_HAS_AVX2) { + vint8x32_impl_cpu = &vint8x32_impl_avx2; + vuint8x32_impl_cpu = &vuint8x32_impl_avx2; + vint16x16_impl_cpu = &vint16x16_impl_avx2; + vuint16x16_impl_cpu = &vuint16x16_impl_avx2; + vint32x8_impl_cpu = &vint32x8_impl_avx2; + vuint32x8_impl_cpu = &vuint32x8_impl_avx2; + vint64x4_impl_cpu = &vint64x4_impl_avx2; + vuint64x4_impl_cpu = &vuint64x4_impl_avx2; } #endif #ifdef VEC_COMPILER_HAS_SSE2 if (cpu & VEC_CPU_HAS_SSE2) { - FILL_GIVEN_FUNC_PTRS( , 8, 16, sse2); - FILL_GIVEN_FUNC_PTRS(u, 8, 16, sse2); - FILL_GIVEN_FUNC_PTRS( , 16, 8, sse2); - FILL_GIVEN_FUNC_PTRS(u, 16, 8, sse2); - FILL_GIVEN_FUNC_PTRS( , 32, 4, sse2); - FILL_GIVEN_FUNC_PTRS(u, 32, 4, sse2); - FILL_GIVEN_FUNC_PTRS( , 64, 2, sse2); - FILL_GIVEN_FUNC_PTRS(u, 64, 2, sse2); + vint8x16_impl_cpu = &vint8x16_impl_sse2; + vuint8x16_impl_cpu = &vuint8x16_impl_sse2; + vint16x8_impl_cpu = &vint16x8_impl_sse2; + vuint16x8_impl_cpu = &vuint16x8_impl_sse2; +# ifdef VEC_COMPILER_HAS_SSE41 + if (cpu & VEC_CPU_HAS_SSE41) { + vint32x4_impl_cpu = &vint32x4_impl_sse41; + vuint32x4_impl_cpu = &vuint32x4_impl_sse41; + } else +# endif + { + vint32x4_impl_cpu = &vint32x4_impl_sse2; + vuint32x4_impl_cpu = &vuint32x4_impl_sse2; + } + vint64x2_impl_cpu = &vint64x2_impl_sse2; + vuint64x2_impl_cpu = &vuint64x2_impl_sse2; } #endif -#ifdef VEC_COMPILER_HAS_NEON - if (cpu & VEC_CPU_HAS_NEON) { - FILL_GIVEN_FUNC_PTRS( , 8, 16, neon); - FILL_GIVEN_FUNC_PTRS(u, 8, 16, neon); - FILL_GIVEN_FUNC_PTRS( , 16, 8, neon); - FILL_GIVEN_FUNC_PTRS(u, 16, 8, neon); - FILL_GIVEN_FUNC_PTRS( , 32, 4, neon); - FILL_GIVEN_FUNC_PTRS(u, 32, 4, neon); - FILL_GIVEN_FUNC_PTRS( , 64, 2, neon); - FILL_GIVEN_FUNC_PTRS(u, 64, 2, neon); - } -#endif -#ifdef VEC_COMPILER_HAS_ALTIVEC - if (cpu & VEC_CPU_HAS_ALTIVEC) { - FILL_GIVEN_FUNC_PTRS( , 8, 16, altivec); - FILL_GIVEN_FUNC_PTRS(u, 8, 16, altivec); - FILL_GIVEN_FUNC_PTRS( , 16, 8, altivec); - FILL_GIVEN_FUNC_PTRS(u, 16, 8, altivec); - FILL_GIVEN_FUNC_PTRS( , 32, 4, altivec); - FILL_GIVEN_FUNC_PTRS(u, 32, 4, altivec); - } -#endif - - /* --- 64-bit */ #ifdef VEC_COMPILER_HAS_MMX if (cpu & VEC_CPU_HAS_MMX) { - FILL_GIVEN_FUNC_PTRS( , 8, 8, mmx); - FILL_GIVEN_FUNC_PTRS(u, 8, 8, mmx); - FILL_GIVEN_FUNC_PTRS( , 16, 4, mmx); - FILL_GIVEN_FUNC_PTRS(u, 16, 4, mmx); - FILL_GIVEN_FUNC_PTRS( , 32, 2, mmx); - FILL_GIVEN_FUNC_PTRS(u, 32, 2, mmx); + vint8x8_impl_cpu = &vint8x8_impl_mmx; + vuint8x8_impl_cpu = &vuint8x8_impl_mmx; + vint16x4_impl_cpu = &vint16x4_impl_mmx; + vuint16x4_impl_cpu = &vuint16x4_impl_mmx; + vint32x2_impl_cpu = &vint32x2_impl_mmx; + vuint32x2_impl_cpu = &vuint32x2_impl_mmx; } #endif #ifdef VEC_COMPILER_HAS_NEON if (cpu & VEC_CPU_HAS_NEON) { - FILL_GIVEN_FUNC_PTRS( , 8, 8, neon); - FILL_GIVEN_FUNC_PTRS(u, 8, 8, neon); - FILL_GIVEN_FUNC_PTRS( , 16, 4, neon); - FILL_GIVEN_FUNC_PTRS(u, 16, 4, neon); - FILL_GIVEN_FUNC_PTRS( , 32, 2, neon); - FILL_GIVEN_FUNC_PTRS(u, 32, 2, neon); + // 64-bit + vint8x8_impl_cpu = &vint8x8_impl_neon; + vuint8x8_impl_cpu = &vuint8x8_impl_neon; + vint16x4_impl_cpu = &vint16x4_impl_neon; + vuint16x4_impl_cpu = &vuint16x4_impl_neon; + vint32x2_impl_cpu = &vint32x2_impl_neon; + vuint32x2_impl_cpu = &vuint32x2_impl_neon; + + // 128-bit + vint8x16_impl_cpu = &vint8x16_impl_neon; + vuint8x16_impl_cpu = &vuint8x16_impl_neon; + vint16x8_impl_cpu = &vint16x8_impl_neon; + vuint16x8_impl_cpu = &vuint16x8_impl_neon; + vint32x4_impl_cpu = &vint32x4_impl_neon; + vuint32x4_impl_cpu = &vuint32x4_impl_neon; + vint64x2_impl_cpu = &vint64x2_impl_neon; + vuint64x2_impl_cpu = &vuint64x2_impl_neon; } #endif - - /* fill any remaining function pointers with generics */ - FILL_GIVEN_FUNC_PTRS( , 8, 64, generic); - FILL_GIVEN_FUNC_PTRS(u, 8, 64, generic); - FILL_GIVEN_FUNC_PTRS( , 16, 32, generic); - FILL_GIVEN_FUNC_PTRS(u, 16, 32, generic); - FILL_GIVEN_FUNC_PTRS( , 32, 16, generic); - FILL_GIVEN_FUNC_PTRS(u, 32, 16, generic); - FILL_GIVEN_FUNC_PTRS( , 64, 8, generic); - FILL_GIVEN_FUNC_PTRS(u, 64, 8, generic); - - FILL_GIVEN_FUNC_PTRS( , 8, 32, generic); - FILL_GIVEN_FUNC_PTRS(u, 8, 32, generic); - FILL_GIVEN_FUNC_PTRS( , 16, 16, generic); - FILL_GIVEN_FUNC_PTRS(u, 16, 16, generic); - FILL_GIVEN_FUNC_PTRS( , 32, 8, generic); - FILL_GIVEN_FUNC_PTRS(u, 32, 8, generic); - FILL_GIVEN_FUNC_PTRS( , 64, 4, generic); - FILL_GIVEN_FUNC_PTRS(u, 64, 4, generic); - - FILL_GIVEN_FUNC_PTRS( , 8, 16, generic); - FILL_GIVEN_FUNC_PTRS(u, 8, 16, generic); - FILL_GIVEN_FUNC_PTRS( , 16, 8, generic); - FILL_GIVEN_FUNC_PTRS(u, 16, 8, generic); - FILL_GIVEN_FUNC_PTRS( , 32, 4, generic); - FILL_GIVEN_FUNC_PTRS(u, 32, 4, generic); - FILL_GIVEN_FUNC_PTRS( , 64, 2, generic); - FILL_GIVEN_FUNC_PTRS(u, 64, 2, generic); - - FILL_GIVEN_FUNC_PTRS( , 8, 8, generic); - FILL_GIVEN_FUNC_PTRS(u, 8, 8, generic); - FILL_GIVEN_FUNC_PTRS( , 16, 4, generic); - FILL_GIVEN_FUNC_PTRS(u, 16, 4, generic); - FILL_GIVEN_FUNC_PTRS( , 32, 2, generic); - FILL_GIVEN_FUNC_PTRS(u, 32, 2, generic); - - FILL_GIVEN_FUNC_PTRS( , 8, 4, generic); - FILL_GIVEN_FUNC_PTRS(u, 8, 4, generic); - FILL_GIVEN_FUNC_PTRS( , 16, 2, generic); - FILL_GIVEN_FUNC_PTRS(u, 16, 2, generic); - - FILL_GIVEN_FUNC_PTRS( , 8, 2, generic); - FILL_GIVEN_FUNC_PTRS(u, 8, 2, generic); + { + // do nothing, they're already set to generics + } vec_init_spinner++; @@ -371,6 +241,7 @@ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ + extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size vec); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ @@ -378,9 +249,7 @@ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ - extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); \ - extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); \ - extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2); + extern inline v##sign##int##bits##x##size v##sign##int##bits##x##size##_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2); #define VEC_DEFINE_OPERATIONS(bits, size) \ VEC_DEFINE_OPERATIONS_SIGN( , bits, size) \
--- a/test/test_arith.h Fri Apr 25 17:40:30 2025 -0400 +++ b/test/test_arith.h Fri Apr 25 17:40:33 2025 -0400 @@ -65,9 +65,7 @@ CREATE_TEST(sign, psign, csign, bits, size, avg, vec_##sign##avg(orig_a[i], orig_b[i])) \ CREATE_TEST_SHIFT(sign, psign, csign, bits, size, rshift, vec_##sign##rshift(orig_a[i], orig_b[i])) \ CREATE_TEST_SHIFT(sign, psign, csign, bits, size, lshift, vec_##sign##lshift(orig_a[i], orig_b[i])) \ - CREATE_TEST_SHIFT(sign, psign, csign, bits, size, lrshift, vec_lrshift((vec_uint##bits)orig_a[i], orig_b[i])) \ - CREATE_TEST(sign, psign, csign, bits, size, min, (orig_a[i] < orig_b[i]) ? (orig_a[i]) : (orig_b[i])) \ - CREATE_TEST(sign, psign, csign, bits, size, max, (orig_a[i] > orig_b[i]) ? (orig_a[i]) : (orig_b[i])) + CREATE_TEST_SHIFT(sign, psign, csign, bits, size, lrshift, vec_lrshift((vec_uint##bits)orig_a[i], orig_b[i])) #define CREATE_TESTS(bits, size) \ CREATE_TESTS_SIGN(, d, , bits, size) \ @@ -119,8 +117,6 @@ ret |= test_arith_v##sign##int##bits##x##size##_or(a, b); \ ret |= test_arith_v##sign##int##bits##x##size##_xor(a, b); \ ret |= test_arith_v##sign##int##bits##x##size##_avg(a, b); \ - ret |= test_arith_v##sign##int##bits##x##size##_min(a, b); \ - ret |= test_arith_v##sign##int##bits##x##size##_max(a, b); \ } \ } \ \