Support macOS 15 and Swift 6.1 while keeping the Metal 4 prefill path - #32
Open
cwlls wants to merge 5 commits into
Open
Support macOS 15 and Swift 6.1 while keeping the Metal 4 prefill path#32cwlls wants to merge 5 commits into
cwlls wants to merge 5 commits into
Conversation
… symbol MTLLanguageVersion.version4_0 and MTLGPUFamily.apple10 are declared only in the macOS 26 SDK, so naming them pinned the package to that SDK even though nothing else in the tree needed it. Both are integer-backed NS_ENUMs, so look them up by raw value: the lookup yields nil on an older SDK and the real case on a newer one. Shader compiles now pick MSL 4.0 only when the SDK knows the case and the host is on macOS 26, falling back to 3.2 otherwise. The shader sources already guard their MPP kernels behind __HAVE_TENSOR__, so those kernels simply drop out of the library at 3.2 and their Swift callers take the existing non-tensor path. Also narrow the TensorOps prefill preconditionFailure to devices that actually advertise Apple10 support, where a missing pipeline is a build bug. On hosts that cannot provide the kernel at all, fall back to causal-tiled rather than trapping. No behavior change on macOS 26 with Xcode 26. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing in the package required the macOS 26 / Swift 6.2 baseline it declared. There are no Swift 6.2 language or stdlib features anywhere in the tree, the SwiftUI layer tops out at WindowDragGesture, and every dependency resolves against Swift 6.1 or earlier (swift-transformers 1.3.3, swift-huggingface 0.9.0, swift-nio 2.99.0). The only macOS 26 symbols were the two Metal enum cases handled in the previous commit. macOS 15 / iOS 18 is the real floor, set by Synchronization.Mutex and WindowDragGesture. Building with Xcode 26 still compiles the shaders at MSL 4.0 and keeps the Metal 4 tensor-ops prefill path on Apple10 GPUs, so this costs nothing on the previously supported configuration. CI now builds both macos-15 and macos-26 so the older toolchain cannot regress; the Markdown link check moves to its own job so it runs once rather than per matrix leg. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The MSL version shims degrade silently by design: when they resolve to MSL 3.2 every kernel guarded by __HAVE_TENSOR__ leaves the shader library, prefill falls back to causal-tiled, and the build, the tests, and the output all stay correct. Only throughput changes. The existing TensorOps tests return early when the path is unavailable, so they would stay green through exactly that regression. Cover the two ways it can happen. MetalSDKCompatibilityTests pins the (major << 16) + minor raw-value encoding against cases the macOS 15 SDK declares, checks that init?(rawValue:) still rejects undeclared values, and requires the MSL 4.0 and Apple10 lookups to agree since both ship in the same SDK. That last one catches a bad raw value on any macOS 26 build rather than only on Apple10 hardware. PrefillAttentionTests then asserts that a device reporting Apple10 MPP tensor support actually gets the pipeline, via a new internal accessor. It still skips elsewhere, because a build against an SDK with no Apple10 family cannot tell Apple10 hardware apart from anything else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MetalSDKCompatibilityTests claimed init?(rawValue:) rejects values the SDK does not declare. The macos-26 CI leg proved otherwise: Metal's enums import as non-frozen, so the initializer constructs unknown values instead. Both MTLLanguageVersion(rawValue: 99 << 16) and MTLGPUFamily(rawValue: 9999) come back non-nil. No behavior changes, because the runtime never depended on that. Every shim value is passed straight to Metal and answered by the running OS: supportsFamily reports false for a family the system does not know, and shaderLanguageVersion's #available check is what keeps MSL 4.0 off macOS 15. Both paths are confirmed working — the shader library compiles at 3.2 on macOS 15 and at 4.0 on the macos-26 runner. What was wrong was the documentation, which described nil-ness as the detection mechanism, and two assertions built on it. Restate the contract, invert the assertion to pin the real behavior, and note in both files that the #available guard is load-bearing rather than belt-and-braces. Drop metal4ShimsResolveTogether, which could never fail once both lookups always succeed, and the unused apple10IfAvailable alias. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Author
|
This apparently addresses issue #19 |
NeelM0906
added a commit
to NeelM0906/Mference
that referenced
this pull request
Aug 1, 2026
The macOS 26 requirement was never earned. No Swift 6.2 language or stdlib features are used, the SwiftUI layer tops out at `WindowDragGesture`, and dependencies resolve unchanged against Swift 6.1. The only macOS 26 symbols were `MTLLanguageVersion.version4_0` and `MTLGPUFamily.apple10`. macOS 15 / iOS 18 is the real floor, set by `Synchronization.Mutex` and `WindowDragGesture`. A new `MetalSDKCompatibility.swift` passes those two Metal symbols by raw value instead of naming the cases, so one source tree builds against both SDKs. MSL 4.0 is selected behind an `#available(macOS 26.0, *)` check; the shader library is compiled from source at startup, so the choice is made at runtime and a single binary covers both worlds. Below macOS 26 shaders compile at MSL 3.2 and the kernels guarded by `__HAVE_TENSOR__` drop out of the library on their own, with Swift callers already written to fall back. Verified on an Apple10 host that the combined production library compiles at MSL 3.2 with every kernel except `attention_prefill_full_tensorops_2d_validity_v2` intact — including all eight GDN (gated-DeltaNet) kernels behind the Qwen 3.6 path — and that all 59 remaining functions create pipeline states at the floor. CI now builds on both macos-15 and macos-26. Ports drumih/turbo-fieldfare#32 by @cwlls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lower the package baseline from macOS 26 / Swift 6.2 to macOS 15 / Swift 6.1
without giving up the Metal 4 tensor-ops prefill path.
The macOS 26 requirement was not earned by the code. There are no Swift 6.2
language or stdlib features anywhere in the tree, the SwiftUI layer tops out at
WindowDragGesture, and every dependency resolves against Swift 6.1 or earlier.The only macOS 26 symbols were
MTLLanguageVersion.version4_0andMTLGPUFamily.apple10, both named in two files. macOS 15 / iOS 18 is the realfloor, set by
Synchronization.MutexandWindowDragGesture.MetalSDKCompatibility.swiftpasses those two symbols to Metal by raw valueinstead of naming the cases, so one source tree builds on both SDKs. MSL 4.0 is
selected behind an
#available(macOS 26.0, *)check; below that the shaderscompile at 3.2 and the kernels already guarded by
__HAVE_TENSOR__drop out ofthe library on their own. Their Swift callers were already written to fall back,
so no call site changed behavior.
Building with Xcode 26 still compiles at MSL 4.0 and still builds the Apple10
tensor-ops pipeline. The
preconditionFailurefor an explicitly requestedTensorOps path is narrowed to devices that actually advertise Apple10 support,
where a missing pipeline is a build bug rather than a platform limit.
CI now builds and tests both
macos-15andmacos-26so the floor toolchaincannot regress.
Validation
swift build -c releaseon macOS 15, Swift 6.1.2 (arm64-apple-macosx15.0).Scripts/test.shin CI onmacos-15andmacos-26: 519 tests, 109 suites,green on both legs.
ruby Scripts/check_markdown_links.rbin CI.context lengths and expert-cache slot counts. Responses were coherent.
The Metal suites construct a
MetalContext, which compiles the combined shaderlibrary, so the MSL 3.2 compile is covered by CI independently of any one
machine.
An earlier revision of
MetalSDKCompatibilityTestsasserted thatinit?(rawValue:)rejects values the SDK does not declare. CI disproved it onboth legs: Metal's enums import as non-frozen and construct unknown values. The
runtime never depended on that —
supportsFamilyis answered by the running OS,and the
#availablecheck is what gates MSL 4.0 — so only the documentation andthe assertion were wrong. Both are corrected in
beb84e1.Memory and performance
Bounded-memory behavior is unchanged. This touches shader-library language
selection and compute-pipeline selection only. No buffer, allocation, expert
streaming, KV cache, or installer path is modified.
MetalContextstill compilesone library and
PrefillAttentionstill holds one optional pipeline.No before/after measurements are included because no code path that executes on
previously supported hardware changed:
tensor-ops pipeline. Identical dispatch.
supportsFamily(.apple10)gate and alreadyran
attention_prefill_causal_tiled. Identical dispatch.MSL 4.0, because
#availableis a runtime check and the raw value is correct.That gains the fast path rather than losing it.
MPPPrefillInt4QMMcontinues to degrade to a nil pipeline when its library willnot compile, falling through to
prefillQMMand the per-row INT4 path.Remaining limitations
No Apple10 hardware ran this. GitHub runners have no M5, so the tensor-ops
prefill kernels are still uncovered, and
MPPPrefillInt4QMMTestsskips threecases with "Requires runtime MPP TensorOps support".
apple10DevicesMustProvideTheTensorOpsPipelineis added to fail loudly thefirst time this meets real hardware, but it has never fired.
The
#available(macOS 26.0, *)check inMetalContext.shaderLanguageVersionis load-bearing, not defensive.
MTLLanguageVersion.msl4_0is non-nil on everySDK, so removing the check would hand MSL 4.0 to the macOS 15 Metal compiler
and fail the entire shader library. Both files say so.
Package.resolvedis toolchain-dependent. Swift 6.2 prunes dependencies gatedbehind swift-huggingface's disabled
Xettrait; Swift 6.1 does not, so thefile carries 16 extra transitive pins. The superset is committed because 6.1 is
the declared floor. Expect it to show as dirty on an Xcode 26 machine; both CI
legs build either way.
macOS 14 was not attempted. It would require replacing six
Mutexuses andWindowDragGesture.docs/BENCHMARKS.mdstill records macOS 26.5.1 / Swift 6.3.3, which is theenvironment those measurements actually ran in and should not be rewritten.
The frozen README copy inside
docs/benchmark-prompts/real-generation-v1/long-synthesis.jsonis a benchmarkinput and is deliberately left stale.
Running
swift testlocally can fail with aPreviewsMacrosplugin error ifxcode-selectpoints at CommandLineTools, because the#Previewblocks inOutputPaneView.swiftare inside#if DEBUGand are skipped by releasebuilds. This is pre-existing and environmental; CI runners have full Xcode.
The change does not load a complete checkpoint, shard, or large model
tensor into Swift heap memory.
Logs and artifacts contain no credentials, private paths, or model
weights.