Metal: expand vector reductions into scalar chains - #962
Open
timesselens wants to merge 1 commit into
Open
timesselens wants to merge 1 commit into
timesselens wants to merge 1 commit into
Conversation
AIR has no vector reductions, and Apple's back-end fails on `llvm.vector.reduce.*` (which LLVM's vectorizers form, e.g. from `prod(size(A))`) or crashes its compiler service. `ExpandReductions` only ran with the legacy pass manager, so from LLVM 17 on (Julia 1.12) nothing expanded them. Expand each reduction into a chain of its scalar operation over the lanes, in lane order: that is how the ordered `fadd`/`fmul` reductions are defined, and a valid order for the others. Min/max chain the scalar intrinsic, which the per-call lowering maps to AIR (`and`/`or` on `i1` lanes). This replaces the legacy `expand_reductions!` call, so every LLVM version takes the same path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #962 +/- ##
==========================================
+ Coverage 86.65% 86.75% +0.09%
==========================================
Files 29 29
Lines 5786 5807 +21
==========================================
+ Hits 5014 5038 +24
+ Misses 772 769 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
AIR has no vector reductions, and from Julia 1.12 (LLVM 17 and later) nothing expands
llvm.vector.reduce.*before Apple's back-end, which then fails or crashes its compiler service:lower_air!runsExpandReductionsonly with the legacy pass manager. This PR proposes expanding each reduction inlower_llvm_intrinsics!, on every LLVM version.Before / after
The intrinsic came up in an Enzyme reverse-mode kernel. Enzyme.jl ran LLVM's vectorizers over the differentiated module, which GPUCompiler doesn't do for Metal, and the SLP vectorizer turned the
lengthof a 4-D array intollvm.vector.reduce.mul.v4i64; that kernel crashed Apple's compiler service (XPC_ERROR_CONNECTION_INTERRUPTED). EnzymeAD/Enzyme.jl#3659 stops that at the source. This PR still covers reductions from other sources, as #549 did.Proposed change
expand_vector_reductions!, next toscalarize_vector_minmax!, replaces each reduction with a chain of its scalar operation over the lanes, in lane order: that is how the orderedfadd/fmulreductions are defined (from their start value), and a valid order for the others. Min/max chain the scalar intrinsic, which the per-call lowering then maps to AIR; oni1lanes they becomeand/or. The reduction's fast-math flags carry over. The legacyexpand_reductions!call goes, so every LLVM version takes the same path. LLVM's own pass can't take over there: the new pass manager doesn't know it (unknown function pass 'expand-reductions'on LLVM 18 and 20).Tests
"vector reduction lowering" in
test/metal.jl, at the IR level: every reduction on 3 and 4 lanes (andsmaxoni1lanes) leaves nollvm.*call afterlower_llvm_intrinsics!; the orderedfaddcontinues from its start value with the call's fast-math flags;fminbecomesair.fmin.f32; andcode_nativeofllvm.vector.reduce.mul.v4i64gives threemul i64. Onmainthe new set fails.Open questions
i1lanes that Julia's optimizer turns intobitcast <4 x i1> to i4+icmp(e.g.anyover<4 x i1>) still fail, with or without this PR, because Apple's back-end rejects thei4. Is odd-width integer legalization already on your list?Related
ExpandReductionscall this PR replaces.fencecrashes the AGX back-end compiler (XPC_ERROR_CONNECTION_INTERRUPTED) Metal.jl#968: the same compiler-service crash, from bare fences.Verification
Pkg.test(test_args=["metal"])on macOS aarch64: Julia 1.10.12 and 1.11.9 (also with--opaque-pointers), 1.12.7 and 1.13.0 all pass.