Skip to content

basic support for sparse tensors (2) - #3201

Draft
simeonschaub wants to merge 11 commits into
EnzymeAD:mainfrom
simeonschaub:sds/sparse_csr2
Draft

simeonschaub wants to merge 11 commits into
EnzymeAD:mainfrom
simeonschaub:sds/sparse_csr2

Conversation

@simeonschaub

Copy link
Copy Markdown
Contributor

Companion to EnzymeAD/Enzyme-JAX#2922. Replaces #3198 and moves the lowering to Enzyme-JAX, which gains a sparse.spmm op. I also added support for emitting a single cuSPARSE/hipSPARSE call, even if mul! is called with different alpha and beta (they have to be constant)

simeonschaub and others added 5 commits August 20, 2026 14:31
…ipSPARSE

Introduces an opaque `Reactant.CSRMatrix` (convertible from SparseMatrixCSC
via the SparseArrays ext). Inside traced code `A * x`, `A * B`, and `mul!`
emit `sparse_tensor.assemble` producing a CSR-encoded tensor consumed by
`stablehlo.dot_general`; `Compiler.lower_sparse_ops!` rewrites the pair to
`stablehlo.custom_call @reactant_csr_matmul` on the raw buffers before any
pass pipeline runs, so XLA only ever sees dense types. The custom call is
served by new cuSPARSE ("CUDA") and hipSPARSE ("ROCM") typed-FFI handlers
in ReactantExtra (requires a local jll rebuild for execution).

`@code_hlo optimize=:none` keeps the sparse_tensor IR for inspection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the Julia-side IR rewrite (src/compiler/SparseLowering.jl) with
the new `lower-sparse-csr` MLIR pass in Enzyme-JAX, invoked via
run_pass_pipeline! only when the traced module actually contains
sparse_tensor ops (so older jlls without the pass keep working for
dense code).

Also switches the CSR buffers to 0-based indices as required by the
sparse_tensor dialect; the pass emits index_base = 0 and the FFI
handlers already support both bases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`mul!(C, A, B, alpha, beta)` (and `A * B`) on a CSRMatrix now emit the
semantic `enzymexla.sparse.spmm alpha, A, B, beta, C` op instead of a
bare dot_general, so lower-sparse-csr can fuse constant alpha/beta into
a single accumulating cuSPARSE/hipSPARSE call (reactant_csr_matmul_acc,
with C aliased to the output and copied on-device when XLA does not
donate the buffer). Runtime (traced) alpha/beta keep the unfused
custom_call + multiply/add form, now materialized by the pass instead of
the Julia frontend. The plain handler gains an f64 "alpha" attribute.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ffi::ScratchAllocator is move-only; the entry points were copying it
into the shared impl.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@simeonschaub
simeonschaub force-pushed the sds/sparse_csr2 branch 2 times, most recently from 79fb079 to 74cf002 Compare August 20, 2026 12:46
simeonschaub and others added 2 commits August 20, 2026 14:47
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pre-existing violations on main that make the format-check-cpp job fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
simeonschaub and others added 2 commits August 20, 2026 15:50
Documenter aborted with :missing_docs because the two new sparse
docstrings were not included in any @docs block.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TPUs emulate Float64, so `SparseMatrixCSC(to_rarray(A)) == A` fails
there by a few ULPs. Keep nnz exact and compare values with isapprox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
simeonschaub and others added 2 commits August 21, 2026 10:21
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Local builds (deps/build_local.jl) were still fetching the upstream
Enzyme-JAX pin, which lacks enzymexla.sparse.spmm and the
lower-enzymexla-sparse pass, so the emitted op was unregistered at
compile time. Introduces ENZYMEXLA_REPO so the download URL follows the
pin.

Pinned to simeonschaub/Enzyme-JAX@8508ac2a (sds/sparse_csr), which is
rebased on current EnzymeAD/Enzyme-JAX main (includes 51a4cd6, the pin
on Reactant main) plus the lower-enzymexla-sparse pass,
enzymexla.sparse.spmm, the getSHLOLayout overload disambiguation fix,
and clang-format fixes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant