From 208c57f4da8c63f7e0f3b9c069af963e5972d854 Mon Sep 17 00:00:00 2001 From: arrow <130365147+merkalev@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:55:09 +0700 Subject: [PATCH] Fix macOS Intel wheel: AppleClang rejects '#pragma GCC target', use per-function target attribute --- .github/workflows/ci.yml | 5 ++++- src/v2_simd.hpp | 2 +- src/v2_simd_avx2.cpp | 28 ++++++++++++++-------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09f1118..486bf70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,10 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + # macos-15-intel compiles the AVX2 kernels with AppleClang, the only + # toolchain that rejects '#pragma GCC target' - it guards the exact + # wheel-build configuration used by the macOS Intel release job. + os: [ubuntu-latest, windows-latest, macos-latest, macos-15-intel] steps: - uses: actions/checkout@v7 - name: Configure MSVC diff --git a/src/v2_simd.hpp b/src/v2_simd.hpp index d4bd868..d31b84b 100644 --- a/src/v2_simd.hpp +++ b/src/v2_simd.hpp @@ -4,7 +4,7 @@ // Instruction-set-specific kernels are isolated in dedicated translation // units so vector code can never leak into baseline compilation: // -// v2_simd_avx2.cpp x86-64 AVX2 kernels (in-source '#pragma GCC target', +// v2_simd_avx2.cpp x86-64 AVX2 kernels (per-function target attribute, // or MSVC '/arch:AVX2' scoped to that file) // v2_simd_neon.cpp AArch64 NEON kernels (baseline ISA, no flags needed) // v2_simd_crc.cpp AArch64 CRC-32 extension (optional, runtime-probed) diff --git a/src/v2_simd_avx2.cpp b/src/v2_simd_avx2.cpp index 47c0132..64cd0fd 100644 --- a/src/v2_simd_avx2.cpp +++ b/src/v2_simd_avx2.cpp @@ -1,10 +1,13 @@ // WIMF v2 AVX2 kernels. // -// GCC/Clang enable AVX2 in-source via '#pragma GCC target' so no global -// compiler flag is needed and other translation units stay baseline-portable. -// MSVC has no per-function ISA selection, so the build system must compile -// this file with '/arch:AVX2' (CMake scopes that flag to this file only). -// The whole unit is skipped unless WIMF_SIMD_ENABLE_AVX2 is defined. +// GCC, Clang, and AppleClang enable AVX2 per function via +// '__attribute__((target("avx2")))' so no global compiler flag is needed and +// other translation units stay baseline-portable. AppleClang rejects the +// GCC-style '#pragma GCC target' form, which is why the attribute is applied +// to each kernel directly. MSVC has no per-function ISA selection, so the +// build system must compile this file with '/arch:AVX2' (CMake scopes that +// flag to this file only). The whole unit is skipped unless +// WIMF_SIMD_ENABLE_AVX2 is defined. #include "v2_simd.hpp" @@ -14,16 +17,17 @@ #error "WIMF_SIMD_ENABLE_AVX2 requires /arch:AVX2 when compiling with MSVC" #endif -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC push_options -#pragma GCC target("avx2") +#if defined(_MSC_VER) +#define WIMF_AVX2_TARGET +#else +#define WIMF_AVX2_TARGET __attribute__((target("avx2"))) #endif #include namespace wimf::v2::simd::avx2 { -uint64_t left_filter_cost(const uint8_t* row, size_t width) noexcept { +WIMF_AVX2_TARGET uint64_t left_filter_cost(const uint8_t* row, size_t width) noexcept { if (width == 0) return 0; uint64_t cost = row[0] <= 128 ? row[0] : 256u - row[0]; const __m256i zero = _mm256_setzero_si256(); @@ -50,7 +54,7 @@ uint64_t left_filter_cost(const uint8_t* row, size_t width) noexcept { return cost; } -void left_filter_emit(const uint8_t* row, uint8_t* out, size_t width) noexcept { +WIMF_AVX2_TARGET void left_filter_emit(const uint8_t* row, uint8_t* out, size_t width) noexcept { if (width == 0) return; out[0] = row[0]; size_t x = 1; @@ -64,8 +68,4 @@ void left_filter_emit(const uint8_t* row, uint8_t* out, size_t width) noexcept { } // namespace wimf::v2::simd::avx2 -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC pop_options -#endif - #endif // WIMF_AVX2_KERNELS