Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
222 commits
Select commit Hold shift + click to select a range
b7c3dd6
[CUDA][Improvement] RMSNorm forward speed up (#3850)
nastya236 Jul 17, 2026
ce30733
Fix captured random state in compile (#3828)
angeloskath Jul 20, 2026
353440c
Fix JIT preamble header filter matching project paths containing "Xco…
apocryphx Jul 21, 2026
30a19f7
Document default value of p in dropout layer docstrings (#3870)
ayaangazali Jul 21, 2026
8f64abc
[WIP] [CUDA] fsdp (#3768)
nastya236 Jul 21, 2026
de82b17
Fix triplet_loss docstring to document the reduced output shape (#3884)
ayaangazali Jul 21, 2026
0c537a4
Zero-copy CPU import: mx.array(host_buffer, copy=False) on unified me…
HaoXuAI Jul 21, 2026
8462ad9
Round MLX_SDPA_BLOCKS up to a multiple of 32 (#3875)
pierre427 Jul 22, 2026
291e909
Reuse Metal WAR tracking hash tables (#3882)
neilmehta24 Jul 22, 2026
3541c66
Use unroll_count(4) for the NAX attention Q@K.T loop (#3843)
wyanzhao Jul 22, 2026
0ebcee8
metal: add gemv_wide for fp16/bf16 matmuls of a few rows (#3888)
jessegross Jul 22, 2026
6cae670
Fix broken docstring rendering in Linear and RNN (#3890)
ayaangazali Jul 22, 2026
33c03c4
Fix Adamax betas docstring and MultiOptimizer filters type (#3889)
ayaangazali Jul 22, 2026
6c0ea7f
Fix incorrect nvfp4 quantized_matmul through the split-K path (#3854)
metascroy Jul 22, 2026
7c92ce1
[Metal] Avoid regex in custom kernel name generation (#3869)
aleroot Jul 23, 2026
9b40c9d
Fix prod dtype promotion when reducing a size-1 axis (#3898)
eyupcanakman Jul 23, 2026
973e27f
[CUDA] Fix grid overflow in gemm conv unfold kernels for >= 65,536 ou…
AdamDLuz Jul 24, 2026
e6134a8
[CUDA] columnwise quantize with tma (#3157)
nastya236 Jul 29, 2026
b400c6c
metal: reduce NVFP4 scales per 16-lane group (#3934)
jessegross Jul 30, 2026
bfd6d0d
Update homebrew in CI (#3946)
angeloskath Jul 30, 2026
8d9d906
Make index autodiff errors explicitly recommend stop_gradient (#3820)
dogukanveziroglu Jul 30, 2026
85e3fb3
Making JACCL coordinator optional (#3899)
angeloskath Jul 30, 2026
2263a6b
Fix docstring mismatches in the Python bindings (#3948)
ayaangazali Jul 30, 2026
2ad0d4d
Raise a clear error for an invalid quantization mode in nn layers (#3…
ayaangazali Jul 31, 2026
fb5133e
Fix incorrect examples and outputs in the usage docs (#3956)
ayaangazali Jul 31, 2026
121df05
Skip test_gather_qmm_sorted cpu test on M1 mac (#3973)
zcbenz Aug 3, 2026
12b5eb9
Fixes an axis mismatch bug in matrix norm for case -1 and 1 (#3827)
danlee2002 Aug 3, 2026
43c9e03
Fix BatchNorm running variance estimator (#3817)
ishtihoss Aug 3, 2026
b6faa91
Fix build error caused by TMA macro guard (#3988)
zcbenz Aug 3, 2026
ddb8162
Fix Glorot/He uniform init docstrings to label the uniform bound, not…
vineethsaivs Aug 4, 2026
697828f
Fix custom metal kernel cache collision for same name, different sour…
katlun-lgtm Aug 4, 2026
c0d916b
Fix log_cosh_loss docstring to document the element-wise loss (#3846)
winklemad Aug 4, 2026
a2fa537
Fix step activation docstring to match >= threshold behavior (#3902)
ayaangazali Aug 4, 2026
0b5e91f
docs: document the reduced-precision float32 default and MLX_ENABLE_T…
stoyoda0012-cyber Aug 4, 2026
f75ee50
Fix InstanceNorm Shape docstring to require at least 3 dimensions (#3…
ayaangazali Aug 4, 2026
cff8e0f
Fix filter_and_map docstring argument order for filter_fn and is_leaf…
ayaangazali Aug 4, 2026
2448298
Export C++20 requirement to CMake consumers (#3971)
PhysicistJohn Aug 4, 2026
ef5fc0f
Fix implicit `thread` address space qualifier becoming explicit in me…
louen Aug 4, 2026
a136dc8
Fix Transformer ignoring a custom encoder or decoder with no paramete…
ayaangazali Aug 4, 2026
e50c0f2
docs: remove references to removed --no-verify-script launch flag (#3…
latent-9 Aug 4, 2026
255f953
Add eye(0) support (#3952)
aaishwarymishra Aug 4, 2026
022ea8c
Refactor the JACCL ring and add threads for the multiple rings (#3900)
angeloskath Aug 4, 2026
6dfd814
Fix shapeless matmul with dynamic batch dimensions (#3813)
varshneydevansh Aug 4, 2026
b34e332
Fix JIT build with old macOS SDK (#3853)
metascroy Aug 4, 2026
1c98450
chore: Fix cholesky_inv arg name (#3950)
ayaangazali Aug 4, 2026
9a1e04d
docs: Add new_thread_unsafe_stream (#3968)
ayaangazali Aug 4, 2026
a79332d
Add gather_qqmm (#3757)
zcbenz Aug 4, 2026
bd813fb
docs: Fix missing printoptions page (#3985)
ayaangazali Aug 5, 2026
a681f8b
docs: ThreadLocalStream and iinfo (#3986)
ayaangazali Aug 5, 2026
0268c81
Make "stop" optional in arange (#3982)
aaishwarymishra Aug 5, 2026
5391a8e
docs: Add softsign to the nn functions (#3989)
ayaangazali Aug 5, 2026
7c293d1
docs: Fix broken all_sum and Group references (#3996)
ayaangazali Aug 5, 2026
f99e1dc
docs: Fix ast.metal_kernel typo (#3997)
ayaangazali Aug 5, 2026
391e140
chore: Fix unresolved mx.array docstring (#3990)
ayaangazali Aug 5, 2026
36e891e
python: fix bfloat16 buffer format itemsize mismatch (#3975)
reckylurker Aug 5, 2026
c4111f8
Template Metal complex scalar lanes (#3970)
PhysicistJohn Aug 5, 2026
8584610
Pad 2D conv input channels to reach the specialized Metal kernel (#3904)
eyupcanakman Aug 5, 2026
ab946f9
Support head dimension 96 in Metal full attention (#3943)
dhiltgen Aug 5, 2026
2c46b95
Fix mx.remainder floored-mod for float16/bfloat16 on CPU (#3976)
sashko-zakharchuk Aug 5, 2026
268ecd6
Fix sorted gather_mm activation row stride (#3960)
metascroy Aug 5, 2026
fe92a05
Fix state corruption when a primitive throws during eval (#3675)
WindChimeRan Aug 5, 2026
49ee726
python: added __complex__ support (#3984)
aaishwarymishra Aug 5, 2026
25e449d
python: Validate freeze and unfreeze keys against the whole model whe…
ayaangazali Aug 6, 2026
eac436b
Fix mlx.launch --python: flag is parsed but never forwarded to the la…
jonathan308 Aug 6, 2026
f0eade3
chore: Fix broken fully_shard reference docstring (#4007)
ayaangazali Aug 6, 2026
679f3ef
chore: Use the current interpreter in the comparative benchmark runne…
ayaangazali Aug 6, 2026
752738d
docs: Document MLX environment variables (#4000)
XXXXRT666 Aug 6, 2026
4652b00
Fix CUDA batched GEMV grid overflow (#3929)
jasp-nerd Aug 6, 2026
26db505
chore: Fix all_gather benchmark collapsing its input to a scalar (#4017)
ayaangazali Aug 6, 2026
f59b34d
Check threadgroup size in the 1-pass sdpa_vector dispatch (#4018)
apocryphx Aug 6, 2026
e534e1a
chore: Align example projects with the Python 3.10 minimum (#4024)
ayaangazali Aug 6, 2026
4462e87
Fix C++ benchmarks failing to build on overloaded astype (#4025)
ayaangazali Aug 6, 2026
074a6bf
Fix conv_transpose maxBufferLength failures on Metal via tiled unfold…
eyupcanakman Aug 6, 2026
d2275d5
chore: Give each host a unique rank in Hostfile.from_list (#4027)
ayaangazali Aug 6, 2026
32df751
Fix crash when reporting partial rings in mlx.distributed_config (#4026)
ayaangazali Aug 6, 2026
f1c5bcd
docs: Do not pass MLX_METAL_FAST_SYNCH=1 by default (#4005)
katlun-lgtm Aug 6, 2026
7e9c3f6
Fix signed-integer overflow in convolution shape arithmetic (#3938)
eyupcanakman Aug 6, 2026
39d9a8a
Template Metal C2C FFT scalar lanes (#3969)
PhysicistJohn Aug 6, 2026
f754f31
Fix segfault in expand_dims for out of bounds negative axes (#4021)
Gusanidas Aug 7, 2026
d9bd3c2
Add optional dtype parameter to zeros_like and ones_like (#4028)
reckylurker Aug 7, 2026
1070373
Fix mx.longsumexp output shape issue. (#4030)
JasonHonKL Aug 7, 2026
0d5bc64
Treat backend and envs as optional when parsing a hostfile (#4039)
ayaangazali Aug 7, 2026
d32978b
chore: Report bad hostfiles as CLI errors in mlx.launch (#4040)
ayaangazali Aug 7, 2026
158118b
chore: Fix ceil error message to say ceil instead of floor (#4042)
PhysicistJohn Aug 7, 2026
447bb0f
Fix installed static MLX package on Windows (#3848)
yingjiacai Aug 7, 2026
8056817
Derive the qmv fast path K alignment from bits (#3965)
jlee5814 Aug 7, 2026
383fe16
Fix eigh UPLO and zero-size eigh/svd on the CPU (#3834)
kapellirohith Aug 7, 2026
3dc6e9b
Add metadata to exported functions (#3855)
eyupcanakman Aug 8, 2026
ed116d2
Fix empty matrix case in cholesky (#4033)
prady0t Aug 8, 2026
2b64179
chore: Reject a negative max_norm in clip_grad_norm (#4058)
ayaangazali Aug 8, 2026
5139a86
Build extensions with the interpreter running the build (#4057)
ayaangazali Aug 8, 2026
11fa2c8
chore: Reject negative dimensions in broadcast_to and random shapes (…
ayaangazali Aug 8, 2026
f3d0c1a
chore: Report bad host arguments as CLI errors instead of tracebacks …
ayaangazali Aug 8, 2026
47bbfe8
Fix Metal FFT for sizes above 2**20 (#4013)
adityasingh2400 Aug 8, 2026
e190d04
Request MSL 4.1 from the runtime compiler on macOS 27 (#4052)
magnuslundstedt Aug 8, 2026
f599c02
Fix concurrent Metal kernel cache lookup (#4043)
kitty-eu-org Aug 8, 2026
2ab4d27
chore: Use dispatch_all_types in ArgReduce::eval_cpu (#4066)
PhysicistJohn Aug 8, 2026
361883c
chore: Use dispatch_all_types in NumberOfElements::eval (#4064)
PhysicistJohn Aug 8, 2026
456216e
chore: Use dispatch_all_types in CPU select_op (#4065)
PhysicistJohn Aug 8, 2026
e7838d5
Raise qmv batch limit for large matrices on M5-class GPUs (#3791)
pierre427 Aug 8, 2026
a88d454
Enable half-precision complex Metal FFT kernels (#3981)
PhysicistJohn Aug 8, 2026
9700e9d
Fix mx.distributed.sum_scatter crashes on a scalar (#4071)
JasonHonKL Aug 8, 2026
b24b79f
Return an empty result from pinv for zero-size inputs (#4069)
ayaangazali Aug 8, 2026
6539d18
Handle zero-size inputs in eig and qr on the CPU (#4068)
ayaangazali Aug 8, 2026
8d66629
Normalize biases before encoding in gather_qmm_rhs (#4056)
dudududukim Aug 8, 2026
5bc4628
Keep randint samples inside [low, high) (#4012)
adityasingh2400 Aug 9, 2026
1f9fed2
chore: Allow saving empty arrays to npy and safetensors (#4080)
ayaangazali Aug 9, 2026
6a0dd0f
Fix DeviceType annotations for device and stream arguments (#4059)
XXXXRT666 Aug 9, 2026
aadcba1
chore: Use dispatch_all_types in DivMod::eval_cpu (#4088)
PhysicistJohn Aug 9, 2026
62e2508
chore: Use dispatch_all_types in SegmentedMM::eval_cpu (#4087)
PhysicistJohn Aug 9, 2026
0c53491
chore: Use dispatch_all_types in Arange::eval_cpu (#4085)
PhysicistJohn Aug 9, 2026
e2aa0d0
Fix Device and Stream lexicographic ordering (#4086)
wgu9 Aug 9, 2026
b0c3562
Enable complex64 scatter addition on GPU (#4078)
PhysicistJohn Aug 9, 2026
5a1e44c
Optimize large NVFP4 QMV on M5 Max (#3961)
dhiltgen Aug 9, 2026
8c28c38
Fix ring hanging on peer disconnect (#4060)
erwinzhang7 Aug 9, 2026
7eb3d85
Propagate NaN in cummax and curmin (#4047)
JasonHonKL Aug 9, 2026
313ae18
chore: Use dispatch_inexact_types in Equal::eval_cpu (#4095)
PhysicistJohn Aug 10, 2026
78c5b28
chore: Use dispatch_inexact_types in Matmul::eval_cpu (#4103)
PhysicistJohn Aug 10, 2026
bca2a79
chore: Use dispatch_all_types in Gather::eval_cpu (#4105)
PhysicistJohn Aug 10, 2026
d64537c
chore: Use dispatch_all_types in CPU unary (#4106)
PhysicistJohn Aug 10, 2026
b00b34b
chore: Use dispatch_all_types in binary_op_cpu (#4107)
PhysicistJohn Aug 10, 2026
5b59a9c
chore: Validate pooling kernel size, stride and padding (#4101)
ayaangazali Aug 10, 2026
40e9b57
chore: Fix reducing 0-size array with non-empty axis in min/max (#4079)
ayaangazali Aug 10, 2026
bcfced9
Fix SinusoidalPositionalEncoding ignoring scale=0.0 (#4098)
YassineMA03 Aug 10, 2026
bf56142
Fix any and all treating -0.0 as nonzero (#4090)
ayaangazali Aug 10, 2026
a9735eb
chore: Fix Eigh CPU dtype error message (#4130)
PhysicistJohn Aug 10, 2026
f94d4e9
chore: Fix random distribution dtype error messages (#4131)
PhysicistJohn Aug 10, 2026
3a67a1b
chore: Fix safetensors dtype error formatting (#4132)
PhysicistJohn Aug 10, 2026
53087cd
chore: Fix no-GPU synchronize error formatting (#4133)
PhysicistJohn Aug 10, 2026
5146055
Fix mx.isinf not considering imaginary plane (#4092)
JasonHonKL Aug 10, 2026
386a554
chore: Use dispatch_all_types in cpu copy (#4104)
PhysicistJohn Aug 10, 2026
07c9366
chore: Use dispatch_all_types in dispatch_gather_axis (#4109)
PhysicistJohn Aug 10, 2026
bcf1b57
chore: Use dispatch_inexact_types in CPU unary_fp (#4111)
PhysicistJohn Aug 10, 2026
e0f1134
chore: Use dispatch_all_types in comparison_op_cpu (#4112)
PhysicistJohn Aug 10, 2026
93e8b0d
chore: Use dispatch_all_types in RingGroup (#4120)
PhysicistJohn Aug 10, 2026
94c29ee
chore: Use dispatch_all_types in ArgSort::eval_cpu (#4123)
PhysicistJohn Aug 10, 2026
1b312a9
chore: Use dispatch_all_types in Softmax::eval_cpu (#4127)
PhysicistJohn Aug 10, 2026
e78d894
chore: Use dispatch_all_types in Arange::eval_gpu (#4128)
PhysicistJohn Aug 10, 2026
a076a63
Pick BM from rows per expert in gather_qmm_rhs_nax (#4023)
dwijenpatel Aug 10, 2026
98a6ec8
Enable complex64 take_along_axis backward on Metal (#4094)
PhysicistJohn Aug 10, 2026
5ec30ac
Add mx.searchsorted with CPU, Metal and CUDA kernels (#4035)
erwinzhang7 Aug 10, 2026
47a1bd6
Stop integer power from hanging on a negative exponent (#4100)
ayaangazali Aug 11, 2026
3236476
Fix second order gradients for sort, partition, topk and cummax/cummi…
Adityaj0 Aug 11, 2026
5c12b6d
Fix segfault on negative out of bounds axes in take_along_axis/put_al…
Adityaj0 Aug 11, 2026
fc27acd
chore: Deduplicate slow CPU convolution dtype dispatch (#4126)
PhysicistJohn Aug 11, 2026
63e98d8
chore: chore: Use dispatch_all_types in print_constant (#4129)
PhysicistJohn Aug 11, 2026
0eaaec9
chore: Fix set_printoptions example (#4140)
PhysicistJohn Aug 11, 2026
4bc4fec
chore: Fix export_function error message (#4141)
PhysicistJohn Aug 11, 2026
f8c45f0
Fix integer keys collision in tree_unflatten (#3878)
Solaris-star Aug 11, 2026
7e8b4cc
Fix fence tracking for donated dynamic slice offsets (#4099)
michaelellis003 Aug 11, 2026
199178a
chore: Deduplicate distributed all-reduce (#4144)
PhysicistJohn Aug 11, 2026
c6c809b
chore: Deduplicate TCPSocket error throw (#4145)
PhysicistJohn Aug 11, 2026
191d724
chore: Simplify BitwiseBinary::eval_gpu (#4147)
PhysicistJohn Aug 11, 2026
4be2e0e
chore: Deduplicate metal_kernel validation (#4149)
PhysicistJohn Aug 11, 2026
c489fe2
chore: Simplify dtype_to_compute_type (#4151)
PhysicistJohn Aug 11, 2026
d4936ab
chore: Use dispatch_all_types in Scatter::eval_cpu (#4155)
PhysicistJohn Aug 11, 2026
f66bcc9
chore: Improve LUF/SVD error messages (#4167)
devteamaegis Aug 11, 2026
067462b
chore: Use dispatch_all_types in ArgPartition::eval_cpu (#4156)
PhysicistJohn Aug 11, 2026
a9ab0f6
chore: Add complex to python scalar type (#4168)
aaishwarymishra Aug 11, 2026
249ea07
chore: Use dispatch_all_types in copy_inplace_dispatch (#4170)
PhysicistJohn Aug 11, 2026
9d47fa6
chore: Simplify scan_gpu_inplace (#4154)
PhysicistJohn Aug 11, 2026
66a0407
Skip empty NAX GEMM output groups (#3941)
XXXXRT666 Aug 11, 2026
cd5b92c
docs: fix stale CLI invocations in LLM inference example (#4172)
deBrian07 Aug 11, 2026
596dc79
Increase ccache size in CI (#3999)
zcbenz Aug 11, 2026
9562ea7
Fix metal hadamard_transform for n = m with no power-of-2 factor (#4054)
axiom-of-choice Aug 11, 2026
ec3ad74
chore: Use dispatch_all_types in Partition::eval_cpu (#4175)
PhysicistJohn Aug 11, 2026
9e37e5b
chore: Use dispatch_all_types in ScatterAxis::eval_cpu (#4176)
PhysicistJohn Aug 11, 2026
fb0818f
docs: document softmax's `precise` argument (#4178)
apocryphx Aug 11, 2026
64d392d
Send out of range trig arguments to libm (#4157)
ayaangazali Aug 11, 2026
9f35f77
Add reflect and symmetric padding modes to mx.pad (#3608)
katlun-lgtm Aug 11, 2026
2ddcb6f
docs: Writing a Fast KV Cache (#4019)
apocryphx Aug 12, 2026
d04e5db
Fix and enable non-transposed NAX qmm (#4051)
gordofreemo Aug 12, 2026
31b5cbb
Add scatter reduce for JACCL (#3901)
angeloskath Aug 12, 2026
56c26e8
Fix diag for zero-size input (#4165)
devteamaegis Aug 12, 2026
13e7968
Add an inverse-CDF path to categorical sampling (#4177)
deescondrillas Aug 12, 2026
307692c
Fail when a requested RDMA device is not found (#4180)
erwinzhang7 Aug 12, 2026
ae8e9a7
Bound GGUF tensor data offsets against the file mapping (#4179)
robertomeroni Aug 12, 2026
d935276
Shift by the max in log_softmax (#4169)
ayaangazali Aug 12, 2026
74c9acd
Shift by the max in cross_entropy (#4188)
ayaangazali Aug 12, 2026
152baf4
Fix linalg.norm(x, keepdims=True) not keeping dims (#4166)
devteamaegis Aug 12, 2026
a435674
chore: Use dispatch_inexact_types in binary_float_op_cpu (#4194)
PhysicistJohn Aug 12, 2026
36fde27
Implement batched matmul for large 1D dot products (#3580)
Ved235 Aug 12, 2026
01d4e12
Re-disable qmm_n_nax and fix group_size < 64 (#4202)
PhilipJohnBasile Aug 12, 2026
d34f630
chore: shell-quote the working directory in the distributed launch sc…
bunlongheng Aug 12, 2026
21d897d
Report when no usable GID is found (#4191)
erwinzhang7 Aug 12, 2026
3abd0fd
Keep double precision for python floats in float64 operations (#4173)
nileshpatil6 Aug 12, 2026
e3d389e
Jaccl ring multi wire fix (#4193)
angeloskath Aug 12, 2026
52960f8
Report why creating a queue pair failed (#4209)
erwinzhang7 Aug 12, 2026
210a1e2
Add antialias support to nn.Upsample for linear and cubic modes (#3677)
lyonsno Aug 13, 2026
9f43f8c
chore: Require pytorch 2.12 for metal dlpack tests (#4206)
zcbenz Aug 13, 2026
bb6d960
chore: Remove std::optional<bool> in C++ public interface (#4207)
zcbenz Aug 13, 2026
7729d58
Fix SliceUpdate JVPs with one traced input (#4200)
PhysicistJohn Aug 13, 2026
3f2e4a3
Raise instead of hanging when reflect/symmetric pad gets an empty axi…
codeAnqiang-ma Aug 13, 2026
d56ed24
Reuse Stockham twiddles in large batched Bluestein FFTs (#4084)
PhysicistJohn Aug 13, 2026
c6ef1eb
chore: Validate decay_steps and step_size in the schedulers (#4217)
ayaangazali Aug 13, 2026
fd7f023
chore: Add runnable distributed examples (#4219)
erwinzhang7 Aug 13, 2026
09ebe73
Break monolithic MTLResidencySet into smaller sets (#4211)
JamesMcCarthy44 Aug 13, 2026
a8e24f2
[CUDA][Improvement] RMSNorm backward (#3881)
nastya236 Aug 13, 2026
77a0c1e
Fix MultiOptimizer on models containing empty modules (#4215)
erenmenges Aug 13, 2026
9b6575c
Return tuple in meshgrid (#4229)
JasonHonKL Aug 13, 2026
1d717bd
Add endpoint parameter to linspace (#4184)
AKnassa Aug 14, 2026
306bdcd
Fix vmap of partition/argpartition dropping the kth argument (#4116)
Adityaj0 Aug 14, 2026
d9ad465
Fix nan_to_num replacing inf with 0 for float16 and bfloat16 (#4222)
codeAnqiang-ma Aug 14, 2026
bd5c3a2
Fix einsum not broadcasting batch dimensions in batched tensordot (#4…
Adityaj0 Aug 14, 2026
d2d7138
Add 1-bit affine quantization support
khosravipasha Feb 24, 2026
5743cb8
Guard fast-path Metal kernel dispatch for 1-bit quantization
khosravipasha Mar 7, 2026
3e0fa1f
metal: 1-bit qmv_fast use 1 pack/thread for occupancy (#3)
bri-prism Jun 5, 2026
564c116
Disable NAX on generation 17 for low-bit correctness
a-github-name Jul 23, 2026
629f091
Route affine qmv_wide by bit-width and batch size
bri-prism Jul 13, 2026
3ebf620
Add native affine 1-bit CUDA QMV
a-github-name Jul 17, 2026
dde9c83
Format rebased low-bit changes
a-github-name Jul 23, 2026
f8afc8b
Route low-bit CUDA matmuls through native QMV
a-github-name Jul 26, 2026
d285f72
Keep global CUDA streams alive through process exit
a-github-name Jul 26, 2026
9190776
Expose quantized headers to custom Metal kernels
a-github-name Jul 27, 2026
4d88c9d
Speed up NVFP4 block-loader staging
a-github-name Jul 29, 2026
0dfe6cb
Tune large H3 GEMMs on M4 Max
a-github-name Aug 5, 2026
3a0382c
Align 1-bit qmv fast dispatch geometry
a-github-name Aug 14, 2026
b34c235
Format refreshed MLX patches
a-github-name Aug 14, 2026
2ccca66
Link quantized custom-kernel sources in AOT builds
a-github-name Aug 14, 2026
1fb504c
Make generated NAX optimizations source-reproducible
a-github-name Aug 14, 2026
3f6e772
Fix affine and fallback QMV template dispatch
a-github-name Aug 14, 2026
b57bd76
Fix Swift 6.0 Linux matmul compilation
a-github-name Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ runs:
shell: bash
run: |
echo "::group::Install macOS dependencies"
brew update
brew install openmpi
xcodebuild -showComponent MetalToolchain
sysctl -a | grep machdep.cpu
echo "::endgroup::"

- name: Setup Windows environment
Expand Down Expand Up @@ -90,15 +92,16 @@ runs:
key: v7-${{ inputs.ccache-key }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.ccache-toolkit || inputs.toolkit }}
max-size: |-
${{ case(inputs.ccache-key == 'release',
case(startsWith(inputs.toolkit, 'cuda'), '150MB',
case(startsWith(inputs.toolkit, 'cuda'),
case(runner.os == 'Linux', '300MB',
'160MB'),
'60MB'),
case(startsWith(inputs.toolkit, 'cuda'),
case(runner.os == 'Linux' && runner.arch == 'x64', '500MB',
runner.os == 'Linux', '240MB',
'120MB'),
runner.os == 'macOS' && inputs.toolkit == 'metal', '200MB',
runner.os == 'macOS', '150MB',
'60MB'))
case(runner.os == 'Linux' && runner.arch == 'x64', '600MB',
runner.os == 'Linux', '400MB',
'320MB'),
runner.os == 'macOS' && inputs.toolkit == 'metal', '300MB',
'200MB'))
}}
save: ${{ !startsWith(github.ref, 'refs/pull/') && (inputs.ccache-save != 'false') }}
# ccache-action bug: running "apt-get update" fails on large arm runner.
Expand Down
2 changes: 2 additions & 0 deletions ACKNOWLEDGMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ MLX was developed with contributions from the following individuals:
- Paul Paczuski: Improved stability of BCE loss calculation
- Max-Heinrich Laves: Added `conv_transpose1d`, `conv_transpose2d`, and `conv_transpose3d` ops.
- Gökdeniz Gülmez: Added the `Muon (MomentUm Orthogonalized by Newton-schulz)` optimizer, and the `ReLU²` activation function.
- katlun-lgtm: Added `reflect` and `symmetric` padding modes.
- Erwin Zhang: Added `searchsorted`. Fixed the ring backend hanging when a peer disconnects. Improved JACCL error reporting.

<a href="https://github.com/ml-explore/mlx/graphs/contributors">
<img class="dark-light" src="https://contrib.rocks/image?repo=ml-explore/mlx&anon=0&columns=20&max=100&r=true" />
Expand Down
15 changes: 12 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ cmake_policy(SET CMP0135 NEW)

add_library(mlx)

target_compile_features(mlx INTERFACE cxx_std_20)
target_compile_options(mlx PUBLIC ${SANITIZER_COMPILE_FLAGS})
target_link_options(mlx PUBLIC ${SANITIZER_LINK_FLAGS})

Expand Down Expand Up @@ -261,7 +262,8 @@ if(WIN32)
FetchContent_MakeAvailable(dlfcn-win32)
endblock()
target_include_directories(mlx PRIVATE "${dlfcn-win32_SOURCE_DIR}/src")
target_link_libraries(mlx PRIVATE dl)
target_sources(mlx PRIVATE "${dlfcn-win32_SOURCE_DIR}/src/dlfcn.c")
target_link_libraries(mlx PRIVATE Psapi.lib)
endif()

if(MLX_BUILD_CPU)
Expand Down Expand Up @@ -296,10 +298,15 @@ if(MLX_BUILD_CPU)
URL "https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.33/${OPENBLAS_ZIP}"
)
FetchContent_MakeAvailable(openblas)
target_link_libraries(
mlx PRIVATE "${openblas_SOURCE_DIR}/lib/${OPENBLAS_LIB}.lib")
target_include_directories(mlx
PRIVATE "${openblas_SOURCE_DIR}/${OPENBLAS_INC}")
# Make openblas importable by dependencies when built as static library.
set(OPENBLAS_IMPORT_LIBRARY
"${openblas_SOURCE_DIR}/lib/${OPENBLAS_LIB}.lib")
add_library(MLX::OpenBLAS UNKNOWN IMPORTED GLOBAL)
set_target_properties(MLX::OpenBLAS PROPERTIES IMPORTED_LOCATION
"${OPENBLAS_IMPORT_LIBRARY}")
target_link_libraries(mlx PRIVATE MLX::OpenBLAS)
# Make sure the DLL file is placed in the same dir with executables.
set(OPENBLAS_DLL_FILE "${openblas_SOURCE_DIR}/bin/${OPENBLAS_LIB}.dll")
add_custom_command(
Expand Down Expand Up @@ -417,6 +424,8 @@ if(WIN32)
if(MLX_BUILD_CPU)
# Install OpenBLAS.
install(FILES ${OPENBLAS_DLL_FILE} TYPE BIN)
install(FILES ${OPENBLAS_IMPORT_LIBRARY}
DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
endif()

Expand Down
16 changes: 11 additions & 5 deletions benchmarks/cpp/irregular_strides.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

namespace mx = mlx::core;

// mx::astype is overloaded, so it cannot be passed directly to the timing
// helpers. Wrap the three argument form instead.
auto astype = [](const mx::array& a, mx::Dtype dtype, mx::StreamOrDevice s) {
return mx::astype(a, dtype, s);
};

void time_irregular_binary_ops_1D() {
auto device = mx::default_device();
int size = 1000000;
Expand Down Expand Up @@ -164,7 +170,7 @@ void time_irregular_astype_1D() {
int step = 2;
auto a = mx::random::uniform({size});
a = slice(a, {0}, {size}, {step});
TIMEM("1D strided", mx::astype, a, mx::int32, device);
TIMEM("1D strided", astype, a, mx::int32, device);
}

void time_irregular_astype_2D() {
Expand All @@ -173,16 +179,16 @@ void time_irregular_astype_2D() {
mx::Shape shape = {size, size};

auto a = mx::random::uniform(shape);
TIMEM("2D regular", mx::astype, a, mx::int32, device);
TIMEM("2D regular", astype, a, mx::int32, device);

a = mx::transpose(a);
TIMEM("2D mx::transpose", mx::astype, a, mx::int32, device);
TIMEM("2D mx::transpose", astype, a, mx::int32, device);

a = mx::broadcast_to(mx::random::uniform({size}), shape);
TIMEM("2D broadcast dim 0", mx::astype, a, mx::int32, device);
TIMEM("2D broadcast dim 0", astype, a, mx::int32, device);

a = mx::broadcast_to(mx::random::uniform({size, 1}), shape);
TIMEM("2D broadcast dim 1", mx::astype, a, mx::int32, device);
TIMEM("2D broadcast dim 1", astype, a, mx::int32, device);
}

int main(int argc, char** argv) {
Expand Down
18 changes: 12 additions & 6 deletions benchmarks/cpp/single_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

namespace mx = mlx::core;

// mx::astype is overloaded, so it cannot be passed directly to the timing
// helpers. Wrap the three argument form instead.
auto astype = [](const mx::array& a, mx::Dtype dtype, mx::StreamOrDevice s) {
return mx::astype(a, dtype, s);
};

void time_creation_ops() {
int M = 2000;
int N = 500;
Expand All @@ -28,18 +34,18 @@ void time_type_conversions() {

auto a = mx::zeros(shape, mx::float32);
mx::eval(a);
TIMEM("mx::float32 to mx::int32", mx::astype, a, mx::int32, device);
TIMEM("mx::float32 to mx::uint32", mx::astype, a, mx::uint32, device);
TIMEM("mx::float32 to mx::int32", astype, a, mx::int32, device);
TIMEM("mx::float32 to mx::uint32", astype, a, mx::uint32, device);

a = mx::zeros(shape, mx::int32);
mx::eval(a);
TIMEM("mx::int32 to mx::float32", mx::astype, a, mx::float32, device);
TIMEM("mx::int32 to mx::float32", astype, a, mx::float32, device);

a = mx::zeros(shape, mx::bool_);
mx::eval(a);
TIMEM("bool to mx::float32", mx::astype, a, mx::float32, device);
TIMEM("bool to mx::int32", mx::astype, a, mx::int32, device);
TIMEM("bool to mx::uint32", mx::astype, a, mx::uint32, device);
TIMEM("bool to mx::float32", astype, a, mx::float32, device);
TIMEM("bool to mx::int32", astype, a, mx::int32, device);
TIMEM("bool to mx::uint32", astype, a, mx::uint32, device);
}

void time_random_generation() {
Expand Down
31 changes: 30 additions & 1 deletion benchmarks/python/comparative/bench_mlx.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,17 @@ def _quant_matmul(x, w, s, b, transpose, group_size, bits):


quant_matmul = {
"quant_matmul_32_1": partial(_quant_matmul, transpose=False, group_size=32, bits=1),
"quant_matmul_32_2": partial(_quant_matmul, transpose=False, group_size=32, bits=2),
"quant_matmul_32_4": partial(_quant_matmul, transpose=False, group_size=32, bits=4),
"quant_matmul_32_8": partial(_quant_matmul, transpose=False, group_size=32, bits=8),
"quant_matmul_64_1": partial(_quant_matmul, transpose=False, group_size=64, bits=1),
"quant_matmul_64_2": partial(_quant_matmul, transpose=False, group_size=64, bits=2),
"quant_matmul_64_4": partial(_quant_matmul, transpose=False, group_size=64, bits=4),
"quant_matmul_64_8": partial(_quant_matmul, transpose=False, group_size=64, bits=8),
"quant_matmul_128_1": partial(
_quant_matmul, transpose=False, group_size=128, bits=1
),
"quant_matmul_128_2": partial(
_quant_matmul, transpose=False, group_size=128, bits=2
),
Expand All @@ -87,6 +92,9 @@ def _quant_matmul(x, w, s, b, transpose, group_size, bits):
"quant_matmul_128_8": partial(
_quant_matmul, transpose=False, group_size=128, bits=8
),
"quant_matmul_t_32_1": partial(
_quant_matmul, transpose=True, group_size=32, bits=1
),
"quant_matmul_t_32_2": partial(
_quant_matmul, transpose=True, group_size=32, bits=2
),
Expand All @@ -96,6 +104,9 @@ def _quant_matmul(x, w, s, b, transpose, group_size, bits):
"quant_matmul_t_32_8": partial(
_quant_matmul, transpose=True, group_size=32, bits=8
),
"quant_matmul_t_64_1": partial(
_quant_matmul, transpose=True, group_size=64, bits=1
),
"quant_matmul_t_64_2": partial(
_quant_matmul, transpose=True, group_size=64, bits=2
),
Expand All @@ -105,6 +116,9 @@ def _quant_matmul(x, w, s, b, transpose, group_size, bits):
"quant_matmul_t_64_8": partial(
_quant_matmul, transpose=True, group_size=64, bits=8
),
"quant_matmul_t_128_1": partial(
_quant_matmul, transpose=True, group_size=128, bits=1
),
"quant_matmul_t_128_2": partial(
_quant_matmul, transpose=True, group_size=128, bits=2
),
Expand Down Expand Up @@ -420,7 +434,22 @@ def selu(x):
print(bench(matmul, *xs))

elif args.benchmark.startswith("quant_matmul"):
print(bench(quant_matmul[args.benchmark], *xs))
# Parse group_size and bits from the benchmark name, e.g.
# "quant_matmul_128_4" or "quant_matmul_t_128_4"
fn = quant_matmul[args.benchmark]
gs = fn.keywords["group_size"]
bits = fn.keywords["bits"]
transpose = fn.keywords["transpose"]

# xs[0] = activation x, xs[1] = original (float) weight matrix
# Quantize the weight internally so the caller only needs:
# --size MxK --size NxK (transpose=True) or --size MxK --size KxN
w_float = xs[1].astype(mx.float16)
w_q, scales, biases = mx.quantize(w_float, group_size=gs, bits=bits)
mx.eval(w_q, scales, biases)
x_input = xs[0].astype(mx.float16)
mx.eval(x_input)
print(bench(_quant_matmul, x_input, w_q, scales, biases, transpose, gs, bits))

elif args.benchmark == "linear":
if args.fused:
Expand Down
44 changes: 40 additions & 4 deletions benchmarks/python/comparative/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import argparse
import re
import sys
from pathlib import Path
from subprocess import run

Expand All @@ -22,15 +23,27 @@ def run_or_raise(*args, **kwargs):


def compare(args):
t_mlx = run_or_raise(["python", BENCH_MLX] + args)
t_torch = run_or_raise(["python", BENCH_TORCH] + args)
t_mlx = run_or_raise([sys.executable, BENCH_MLX] + args)
t_torch = run_or_raise([sys.executable, BENCH_TORCH] + args)

print((t_torch - t_mlx) / t_torch, " ".join(args), sep="\t")


def compare_mlx_quant(args_base, bits_list):
"""Compare quantized matmul across bit widths (MLX only, no PyTorch)."""
results = {}
for bits in bits_list:
bench_args = args_base.replace("{bits}", str(bits)).split()
results[bits] = run_or_raise(["python", BENCH_MLX] + bench_args)
baseline = max(results.values())
for bits in bits_list:
speedup = (baseline - results[bits]) / baseline if baseline > 0 else 0
print(f"{speedup:.4f}\t{args_base.replace('{bits}', str(bits))}")


def compare_mlx_dtypes(args, dt1, dt2):
t_mlx_dt1 = run_or_raise(["python", BENCH_MLX] + args + ["--dtype", dt1])
t_mlx_dt2 = run_or_raise(["python", BENCH_MLX] + args + ["--dtype", dt2])
t_mlx_dt1 = run_or_raise([sys.executable, BENCH_MLX] + args + ["--dtype", dt1])
t_mlx_dt2 = run_or_raise([sys.executable, BENCH_MLX] + args + ["--dtype", dt2])

print((t_mlx_dt2 - t_mlx_dt1) / t_mlx_dt2, " ".join(args), sep="\t")

Expand Down Expand Up @@ -282,3 +295,26 @@ def predicate(x):
compare_filtered("topk --size 32768x128 --axis 1")
compare_filtered("topk --size 128x128 --axis 0 --cpu")
compare_filtered("topk --size 128x128 --axis 1 --cpu")

# Quantized matmul ops (MLX only — compare across bit widths)
# qmv path (M=1, token generation, memory-bandwidth bound)
for gs in [64, 128]:
compare_mlx_quant(
f"quant_matmul_t_{gs}_{{bits}} --size 1x4096 --size 4096x4096",
[1, 2, 4, 8],
)
compare_mlx_quant(
f"quant_matmul_t_{gs}_{{bits}} --size 1x4096 --size 11008x4096",
[1, 2, 4, 8],
)
# qmm path (prompt processing, more compute bound)
for gs in [64, 128]:
for M in [32, 512]:
compare_mlx_quant(
f"quant_matmul_t_{gs}_{{bits}} --size {M}x4096 --size 4096x4096",
[1, 2, 4, 8],
)
compare_mlx_quant(
f"quant_matmul_t_{gs}_{{bits}} --size {M}x4096 --size 11008x4096",
[1, 2, 4, 8],
)
21 changes: 21 additions & 0 deletions benchmarks/python/gather_qmm_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,26 @@ def equivalent_matmul(x, w1, w2):
time_fn(equivalent_matmul, x, w1, w2)


def time_gather_qmm_short_runs():
# Many experts and few tokens, so each expert gets N * I / E = 16 rows.
N, E, I = 512, 256, 8
x = mx.random.normal((N, 1, 1, D)) / 1024**0.5
w1 = mx.random.normal((E, M, D)) / 1024**0.5
w2 = mx.random.normal((E, D, M)) / 1024**0.5
w1 = mx.quantize(w1)
w2 = mx.quantize(w2)
indices = (mx.random.uniform(shape=(N, I)) * E).astype(mx.uint32)
mx.eval(x, w1, w2, indices)

def gather_mm(x, w1, w2, indices):
x, idx, inv_order = gather_sort(x, indices)
x = mx.gather_qmm(x, *w1, transpose=True, rhs_indices=idx, sorted_indices=True)
x = mx.gather_qmm(x, *w2, transpose=True, rhs_indices=idx, sorted_indices=True)
return scatter_unsort(x, inv_order, indices.shape)

time_fn(gather_mm, x, w1, w2, indices)


if __name__ == "__main__":
time_gather_qmm()
time_gather_qmm_short_runs()
11 changes: 10 additions & 1 deletion benchmarks/python/sdpa_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ def get_gflop_count(B, M, N, K):
( 1, 2048, 32121, 80, 32, 8),
)

shapes_96 = (
# ( B, qsl, ksl, head_dim, n_qh, n_kvh)
( 1, 1024, 1024, 96, 32, 8),
( 1, 2048, 2048, 96, 32, 8),
( 1, 4096, 4096, 96, 32, 8),
( 1, 4096, 5000, 96, 32, 8),
( 1, 2048, 32121, 96, 32, 8),
)

shapes_128 = (
# ( B, qsl, ksl, head_dim, n_qh, n_kvh)
( 1, 1024, 1024, 128, 32, 8),
Expand All @@ -199,7 +208,7 @@ def get_gflop_count(B, M, N, K):
)
# fmt: on

shapes = shapes_64 + shapes_80 + shapes_128
shapes = shapes_64 + shapes_80 + shapes_96 + shapes_128

masks = [None, "bool", "causal"]

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/python/synchronize_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def all_gather_benchmark():

def fn(x):
for _ in range(its_per_eval):
x = mx.distributed.all_gather(x)[0]
x = mx.distributed.all_gather(x)[: a.shape[0]]
return x

ms = timeit(fn, a) / its_per_eval
Expand Down
3 changes: 2 additions & 1 deletion cmake/extension.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ macro(mlx_build_metallib)
set(MTLLIB_BUILD_TARGET "${MTLLIB_OUTPUT_DIRECTORY}/${MTLLIB_TITLE}.metallib")

# Collect compile options
set(MTLLIB_COMPILE_OPTIONS -Wall -Wextra -fno-fast-math -Wno-c++17-extensions)
set(MTLLIB_COMPILE_OPTIONS -Wall -Wextra -fno-fast-math -Wno-c++17-extensions
-Wmetal-addr-spaces)
if(MLX_METAL_DEBUG OR MTLLIB_DEBUG)
set(MTLLIB_COMPILE_OPTIONS ${MTLLIB_COMPILE_OPTIONS} -gline-tables-only
-frecord-sources)
Expand Down
5 changes: 4 additions & 1 deletion docs/src/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@

python_use_unqualified_type_names = True
autosummary_generate = True
autosummary_filename_map = {"mlx.core.Stream": "stream_class"}
autosummary_filename_map = {
"mlx.core.Stream": "stream_class",
"mlx.core.PrintOptions": "printoptions_class",
}

intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
Expand Down
Loading