Part of the iOS/Apple kernel track of #920 (slice 1 of 3).
The Q4_K and Q6_K C kernels (native/src/q4k_matmul.c, q6k_matmul.c) gate their vdotq_s32 bodies on the compile-time SKAINET_HAVE_DOTPROD (__ARM_FEATURE_DOTPROD), which today comes from the TU-level -march=armv8.2-a+fp16+dotprod set for every aarch64 build. That model cannot ship to iOS:
- A Kotlin/Native klib embeds one static archive — the Android trick of shipping baseline + v8.2
.so pairs and picking at load time does not translate.
- Apple A12 (iPhone XS/XR) lacks FEAT_DotProd and is still supported by iOS 18; A13+ and every Apple Silicon Mac have it. Compiling the archive with
+dotprod unconditionally would SIGILL supported devices; compiling baseline-only would leave Q4_K/Q6_K — the formats real GGUFs use — on the scalar path everywhere.
Proposal: per-function runtime dispatch, Apple-only, zero effect on Linux:
- New
skainet_cpu_features.{h,c}: int skainet_cpu_has_dotprod(void) — on __APPLE__ && __aarch64__ a cached sysctlbyname("hw.optional.arm.FEAT_DotProd") probe (key exists since iOS 15/macOS 12; absence → 0 → scalar, always safe); elsewhere a compile-time constant.
skainet_simd.h: SKAINET_DOTPROD_DISPATCH + SKAINET_DOTPROD_TARGET (__attribute__((target("dotprod")))) defined only for Apple arm64 TUs built without __ARM_FEATURE_DOTPROD. Verified against clang: the attribute gates the intrinsic's codegen, and attributed functions are not inlined into baseline callers — the sdot code stays out of the baseline path.
- Q4_K/Q6_K: extract the guarded per-block bodies into
_dp (attributed) / _generic twins; select once per matmul call via a hoisted use_dp. Granularity is one call per block × output row, so the indirect-call overhead is amortized over the block's arithmetic. On Linux (SKAINET_HAVE_DOTPROD set) the call site stays a direct call that inlines back under -O3 — codegen effectively unchanged.
- CMake: aarch64
-march block becomes AND NOT APPLE; Apple builds (including the existing macOS FFM dylib) compile at SDK-default baseline + dispatch. On Apple Silicon the probe returns 1, so the macOS jvmTest CI lane becomes an automatic exerciser of the fast arm.
This is the prerequisite for embedding one universal-per-slice archive into the iosArm64/iosSimulatorArm64/macosArm64 klibs (follow-up issue).
Part of the iOS/Apple kernel track of #920 (slice 1 of 3).
The Q4_K and Q6_K C kernels (
native/src/q4k_matmul.c,q6k_matmul.c) gate theirvdotq_s32bodies on the compile-timeSKAINET_HAVE_DOTPROD(__ARM_FEATURE_DOTPROD), which today comes from the TU-level-march=armv8.2-a+fp16+dotprodset for every aarch64 build. That model cannot ship to iOS:.sopairs and picking at load time does not translate.+dotprodunconditionally would SIGILL supported devices; compiling baseline-only would leave Q4_K/Q6_K — the formats real GGUFs use — on the scalar path everywhere.Proposal: per-function runtime dispatch, Apple-only, zero effect on Linux:
skainet_cpu_features.{h,c}:int skainet_cpu_has_dotprod(void)— on__APPLE__ && __aarch64__a cachedsysctlbyname("hw.optional.arm.FEAT_DotProd")probe (key exists since iOS 15/macOS 12; absence → 0 → scalar, always safe); elsewhere a compile-time constant.skainet_simd.h:SKAINET_DOTPROD_DISPATCH+SKAINET_DOTPROD_TARGET(__attribute__((target("dotprod")))) defined only for Apple arm64 TUs built without__ARM_FEATURE_DOTPROD. Verified against clang: the attribute gates the intrinsic's codegen, and attributed functions are not inlined into baseline callers — thesdotcode stays out of the baseline path._dp(attributed) /_generictwins; select once per matmul call via a hoisteduse_dp. Granularity is one call per block × output row, so the indirect-call overhead is amortized over the block's arithmetic. On Linux (SKAINET_HAVE_DOTPRODset) the call site stays a direct call that inlines back under-O3— codegen effectively unchanged.-marchblock becomesAND NOT APPLE; Apple builds (including the existing macOS FFM dylib) compile at SDK-default baseline + dispatch. On Apple Silicon the probe returns 1, so the macOSjvmTestCI lane becomes an automatic exerciser of the fast arm.This is the prerequisite for embedding one universal-per-slice archive into the iosArm64/iosSimulatorArm64/macosArm64 klibs (follow-up issue).