mlx-bun 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/README.md +71 -588
  2. package/docs/README.md +91 -0
  3. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  4. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  5. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  6. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  7. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  8. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  9. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  10. package/docs/design/batching.md +569 -0
  11. package/docs/design/decode-speed-program.md +3178 -169
  12. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  13. package/docs/design/generic-model-support.md +579 -334
  14. package/docs/design/kv-cache.md +680 -0
  15. package/docs/design/orpo-training.md +673 -1239
  16. package/docs/design/speculative-decoding.md +1627 -0
  17. package/docs/design/turboquant.md +2102 -0
  18. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  19. package/docs/design/web-chat-redesign.md +666 -1083
  20. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  21. package/docs/planning/release-notes-v0.3.0.md +35 -0
  22. package/docs/planning/video-series.md +2 -2
  23. package/docs/reference/benchmarks.md +1162 -0
  24. package/docs/reference/cli.md +394 -159
  25. package/docs/reference/distribution.md +321 -182
  26. package/docs/reference/environment.md +348 -0
  27. package/docs/reference/glossary.md +39 -0
  28. package/docs/reference/library-api.md +566 -168
  29. package/docs/reference/memory.md +227 -64
  30. package/docs/reference/models.md +104 -6
  31. package/docs/reference/server-api.md +886 -425
  32. package/docs/reference/server-config.md +638 -330
  33. package/docs/reference/training.md +393 -254
  34. package/docs/reference/troubleshooting.md +166 -0
  35. package/package.json +9 -4
  36. package/src/audio/decode.ts +2 -2
  37. package/src/audio/features.ts +2 -2
  38. package/src/backends/mlx/autoregressive.ts +108 -0
  39. package/src/backends/mlx/batch-group.ts +1646 -0
  40. package/src/backends/mlx/diffusion.ts +39 -0
  41. package/src/backends/mlx/draft-target.ts +47 -0
  42. package/src/backends/mlx/evaluation.ts +105 -0
  43. package/src/backends/mlx/fill-append.ts +45 -0
  44. package/src/backends/mlx/gateway-binding.ts +71 -0
  45. package/src/backends/mlx/graph.ts +38 -0
  46. package/src/backends/mlx/memory-client.ts +189 -0
  47. package/src/backends/mlx/memory-guard.ts +40 -0
  48. package/src/backends/mlx/methods.ts +90 -0
  49. package/src/backends/mlx/model-prompt.ts +164 -0
  50. package/src/backends/mlx/model-serving.ts +79 -0
  51. package/src/backends/mlx/prefill.ts +33 -0
  52. package/src/backends/mlx/request-policy.ts +20 -0
  53. package/src/backends/mlx/rollback.ts +51 -0
  54. package/src/backends/mlx/serial-executor.ts +273 -0
  55. package/src/backends/mlx/speculative.ts +114 -0
  56. package/src/backends/mlx/state-views.ts +26 -0
  57. package/src/backends/mlx/text-engine.ts +73 -0
  58. package/src/cli.ts +58 -25
  59. package/src/client.ts +66 -0
  60. package/src/config.ts +21 -4
  61. package/src/contracts/completion.ts +16 -0
  62. package/src/contracts/execution.ts +49 -0
  63. package/src/contracts/generation.ts +103 -0
  64. package/src/contracts/host.ts +7 -0
  65. package/src/contracts/jobs.ts +66 -0
  66. package/src/contracts/pi-provider.ts +30 -0
  67. package/src/contracts/pi.ts +259 -0
  68. package/src/contracts/resources.ts +18 -0
  69. package/src/contracts/scheduling.ts +27 -0
  70. package/src/contracts/tsconfig.json +14 -0
  71. package/src/diffusion/diffusion-generate.ts +218 -153
  72. package/src/embed.ts +1 -1
  73. package/src/engine/admission.ts +59 -0
  74. package/src/engine/cancellation.ts +38 -0
  75. package/src/engine/engine.ts +56 -0
  76. package/src/engine/execution-coordinator.ts +70 -0
  77. package/src/engine/execution-plan.ts +51 -0
  78. package/src/engine/resources.ts +42 -0
  79. package/src/engine/scheduler.ts +67 -0
  80. package/src/engine/session.ts +247 -0
  81. package/src/eval/README.md +44 -1
  82. package/src/eval/kl.ts +236 -3
  83. package/src/eval/reference-logits.ts +207 -0
  84. package/src/eval/runner.ts +8 -96
  85. package/src/fill/echo-index.ts +188 -0
  86. package/src/fill/fill-session.ts +452 -0
  87. package/src/fill/proposal.ts +68 -0
  88. package/src/fill/schema-rows.ts +506 -0
  89. package/src/fill/tool-boundary.ts +103 -0
  90. package/src/fit.ts +1 -1
  91. package/src/generate.ts +656 -268
  92. package/src/grammar.ts +12 -7
  93. package/src/harness-pi.ts +14 -33
  94. package/src/hub-rest.ts +4 -4
  95. package/src/index.ts +7 -0
  96. package/src/inference/denoising.ts +17 -0
  97. package/src/inference/graph.ts +33 -0
  98. package/src/inference/prefill.ts +39 -0
  99. package/src/inference/rollback.ts +7 -0
  100. package/src/jobs/db.ts +4 -0
  101. package/src/jobs/index.ts +2 -0
  102. package/src/jobs/job-entry.ts +12 -12
  103. package/src/jobs/runner.ts +98 -13
  104. package/src/jobs/task-client.ts +19 -0
  105. package/src/jobs/types.ts +2 -58
  106. package/src/kv-store.ts +109 -49
  107. package/src/lab/README.md +18 -0
  108. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  109. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  110. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
  111. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  112. package/src/library.ts +40 -0
  113. package/src/lora.ts +18 -0
  114. package/src/media-fetch.ts +1 -1
  115. package/src/memory/article.ts +1 -1
  116. package/src/memory/chunk.ts +1 -1
  117. package/src/memory/model.ts +30 -169
  118. package/src/memory/prompts.ts +1 -1
  119. package/src/memory/rest.ts +1 -1
  120. package/src/memory/schedule.ts +1 -1
  121. package/src/memory/stages.ts +4 -1
  122. package/src/memory/vault.ts +1 -3
  123. package/src/mlx/array.ts +9 -10
  124. package/src/mlx/compile.ts +12 -2
  125. package/src/mlx/ffi.ts +58 -11
  126. package/src/mlx/materialize.ts +23 -0
  127. package/src/mlx/metal-kernel.ts +10 -11
  128. package/src/mlx/ops.ts +33 -13
  129. package/src/mlx/quantized-rows.ts +36 -0
  130. package/src/mlx/token-bitmask.ts +52 -0
  131. package/src/mlx/turboquant-kv-decode.ts +82 -0
  132. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  133. package/src/mlx/turboquant-ops.ts +33 -3
  134. package/src/mlx/turboquant-tables.ts +2 -2
  135. package/src/model/batched-mask.ts +8 -2
  136. package/src/model/batched-quant.ts +1 -1
  137. package/src/model/batched-rotating-quant.ts +2 -2
  138. package/src/model/batched-rotating.ts +1 -1
  139. package/src/model/compiled-decode.ts +1 -1
  140. package/src/model/diffusion-gemma.ts +8 -8
  141. package/src/model/factory.ts +76 -33
  142. package/src/model/fingerprint.ts +1 -1
  143. package/src/model/flash-attention.ts +3 -3
  144. package/src/model/gemma4-base.ts +26 -9
  145. package/src/model/gemma4.ts +6 -6
  146. package/src/model/generated/gemma4-12b.ts +2 -2
  147. package/src/model/generated/gemma4-26b.ts +2 -2
  148. package/src/model/generated/gemma4-e4b.ts +2 -2
  149. package/src/model/glm52-dsa.ts +13 -9
  150. package/src/model/glm52-memory.ts +1 -1
  151. package/src/model/implementation.ts +69 -0
  152. package/src/model/minicpm5.ts +6 -8
  153. package/src/model/profile.ts +12 -2
  154. package/src/model/qwen-append.ts +12 -0
  155. package/src/model/qwen-conv.ts +52 -0
  156. package/src/model/qwen3_5-checkpoint.ts +164 -0
  157. package/src/model/qwen3_5.ts +140 -56
  158. package/src/model/support.ts +1 -1
  159. package/src/model/trellis-balanced-scatter.ts +51 -0
  160. package/src/model/trellis-linear.ts +672 -0
  161. package/src/model/trellis-shared-m.ts +151 -0
  162. package/src/model/trellis-shared-scatter.ts +144 -0
  163. package/src/model/trellis-splitk-prefill.ts +158 -0
  164. package/src/model/trellis-tiled-prefill.ts +136 -0
  165. package/src/model/trellis-vector-expand.ts +62 -0
  166. package/src/model/trellis-wide-prefill.ts +94 -0
  167. package/src/model/universal/dense.ts +1 -1
  168. package/src/model/universal/modules.ts +8 -1
  169. package/src/native-pack.ts +6 -5
  170. package/src/pi-provider.ts +6 -64
  171. package/src/pi-web.ts +8 -315
  172. package/src/prompt-cache.ts +96 -53
  173. package/src/quantize/allocator.ts +1 -1
  174. package/src/quantize/config-writer.ts +10 -3
  175. package/src/quantize/rotate.ts +4 -4
  176. package/src/quantize/trellis.ts +586 -0
  177. package/src/responses.ts +28 -1
  178. package/src/runtime-config.ts +18 -4
  179. package/src/sampler.ts +4 -4
  180. package/src/serve/batch-scheduler.ts +8 -1671
  181. package/src/serve/chat-request.ts +391 -0
  182. package/src/serve/chat-stage.ts +195 -0
  183. package/src/serve/checkpoint-identity.ts +64 -0
  184. package/src/serve/completion-executor.ts +15 -7
  185. package/src/serve/discovery-routes.ts +12 -13
  186. package/src/serve/generation-gateway.ts +154 -193
  187. package/src/serve/http.ts +159 -0
  188. package/src/serve/inference-request.ts +79 -0
  189. package/src/serve/isolate.ts +297 -105
  190. package/src/serve/lab-routes.ts +3 -0
  191. package/src/serve/lane-registry.ts +2 -1
  192. package/src/serve/model-admin-routes.ts +7 -5
  193. package/src/serve/model-binding.ts +43 -0
  194. package/src/serve/model-host.ts +512 -0
  195. package/src/serve/openai-wire.ts +103 -0
  196. package/src/serve/parent-application.ts +56 -0
  197. package/src/serve/pipeline.ts +33 -0
  198. package/src/serve/preparation.ts +33 -0
  199. package/src/serve/request-plan.ts +19 -15
  200. package/src/serve/request-prep.ts +346 -0
  201. package/src/serve/response-lease.ts +24 -0
  202. package/src/serve/responses-client.ts +69 -0
  203. package/src/serve/session-completion-engine.ts +110 -0
  204. package/src/serve/session-search.ts +1 -1
  205. package/src/serve/static-routes.ts +5 -5
  206. package/src/serve/text-completion-stage.ts +104 -0
  207. package/src/serve/token-streams.ts +519 -0
  208. package/src/server.ts +317 -2649
  209. package/src/spec/assistant-source.ts +10 -44
  210. package/src/spec/deepspec-source.ts +6 -6
  211. package/src/spec/dflash-source.ts +8 -8
  212. package/src/spec/dspark/ab-stats.ts +3 -3
  213. package/src/spec/dspark/calibration.ts +2 -2
  214. package/src/spec/dspark/deepspec-module.ts +2 -2
  215. package/src/spec/dspark/generate-dflash.ts +2 -2
  216. package/src/spec/dspark/generate.ts +2 -2
  217. package/src/spec/dspark/loader.ts +1 -1
  218. package/src/spec/dspark/module-dflash.ts +4 -3
  219. package/src/spec/dspark/module.ts +3 -3
  220. package/src/spec/dspark/quantize-drafter.ts +1 -1
  221. package/src/spec/generate.ts +1 -1
  222. package/src/spec/glm52-mtp-source.ts +1 -1
  223. package/src/spec/ngram-source.ts +1 -1
  224. package/src/spec/prefix-state.ts +45 -0
  225. package/src/spec/qwen-mtp-source.ts +166 -69
  226. package/src/spec/serve-loop.ts +154 -156
  227. package/src/spec/source.ts +42 -10
  228. package/src/spec/two-model.ts +1 -1
  229. package/src/ssd-cache.ts +80 -12
  230. package/src/ssd-durability.ts +25 -13
  231. package/src/tool-call.ts +51 -14
  232. package/src/train/flash-cce.ts +2 -2
  233. package/src/train/forward.ts +6 -0
  234. package/src/train/loss.ts +1 -1
  235. package/src/train/prefix-shared.ts +5 -1
  236. package/src/train/segmented.ts +5 -3
  237. package/src/train/trainer.ts +6 -6
  238. package/src/vision/prompt.ts +1 -1
  239. package/src/vision/qwen3vl-tower.ts +52 -10
  240. package/src/web/app.html +1 -1
  241. package/src/web/app.js +5 -3
  242. package/src/web/src/adapters-panel.ts +3 -3
  243. package/src/web/src/assistant.ts +2 -36
  244. package/src/web/src/chat.ts +4 -4
  245. package/src/web/src/composer.ts +4 -4
  246. package/src/web/src/hub.ts +1 -1
  247. package/src/web/src/markdown.ts +0 -0
  248. package/src/web/src/memory-panel.ts +1 -1
  249. package/src/web/src/model-picker.ts +1 -1
  250. package/src/web/src/palette.ts +1 -1
  251. package/src/web/src/protocol.ts +3 -39
  252. package/src/web/src/sessions.ts +1 -1
  253. package/src/web/src/ui-catalog.ts +4 -18
  254. package/src/web-assets.ts +47 -0
  255. package/src/weights.ts +55 -9
  256. package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
  257. package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
  258. package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
  259. package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
  260. package/docs/archive/investigations/hlg-ab.html +0 -34
  261. package/docs/archive/investigations/hlg-explorer.html +0 -238
  262. package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
  263. package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
  264. package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
  265. package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
  266. package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
  267. package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
  268. package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
  269. package/docs/archive/investigations/hlg-report.html +0 -262
  270. package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
  271. package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  272. package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
  273. package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
  274. package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
  275. package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
  276. package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
  277. package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
  278. package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
  279. package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
  280. package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  281. package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
  282. package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
  283. package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
  284. package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  285. package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  286. package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  287. package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  288. package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  289. package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  290. package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  291. package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
  292. package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
  293. package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
  294. package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
  295. package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
  296. package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  297. package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
  298. package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
  299. package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
  300. package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
  301. package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
  302. package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  303. package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
  304. package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  305. package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  306. package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  307. package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  308. package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  309. package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  310. package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
  311. package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  312. package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
  313. package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  314. package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  315. package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  316. package/docs/archive/mlx-bun-lab-report.html +0 -275
  317. package/docs/archive/wwdc-mlx-bun.html +0 -848
  318. package/docs/design/adapters-end-to-end.md +0 -205
  319. package/docs/design/batching-perf-path.md +0 -255
  320. package/docs/design/batching-v2-plan.md +0 -529
  321. package/docs/design/bucketing-stage.md +0 -197
  322. package/docs/design/compat-cli-surface-design.md +0 -230
  323. package/docs/design/docs-reorg-plan.md +0 -165
  324. package/docs/design/dspark-serving-program.md +0 -371
  325. package/docs/design/dspark-speculative-decoding.md +0 -318
  326. package/docs/design/grammar-spec-batching-integration.md +0 -301
  327. package/docs/design/memory-inference-path.md +0 -422
  328. package/docs/design/memory-synthesis.md +0 -287
  329. package/docs/design/memory-system.md +0 -237
  330. package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
  331. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  332. package/docs/design/omlx-adoption-map.md +0 -98
  333. package/docs/design/orpo-dynamic-lambda.md +0 -220
  334. package/docs/design/orpo-future-enhancements.md +0 -340
  335. package/docs/design/paged-kv-cache.md +0 -214
  336. package/docs/design/parallel-slots.md +0 -567
  337. package/docs/design/parity-tier-dag.md +0 -161
  338. package/docs/design/repo-cleanup-plan.md +0 -231
  339. package/docs/design/runtime-isolation.md +0 -263
  340. package/docs/design/segmented-backward-training.md +0 -543
  341. package/docs/design/spec-decode-larger-targets.md +0 -229
  342. package/docs/design/ssd-kv-cold-tier.md +0 -415
  343. package/docs/design/structured-output.md +0 -484
  344. package/docs/design/tauri-desktop-app.md +0 -127
  345. package/docs/design/the-dreaming-master-plan.md +0 -445
  346. package/docs/design/turboquant-kv.md +0 -235
  347. package/docs/design/turboquant-weights.md +0 -467
  348. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  349. package/docs/design/web-chat-beat-matrix.md +0 -315
  350. package/docs/design/write-pipeline-entity.md +0 -468
  351. package/docs/planning/IDEAS.md +0 -69
  352. package/docs/reference/embedding.md +0 -197
  353. package/docs/reference/features-matrix.md +0 -101
  354. package/docs/reference/orpo-quickstart.md +0 -135
  355. package/src/flags.ts +0 -11
  356. /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
  357. /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
  358. /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
  359. /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
  360. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  361. /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
  362. /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
  363. /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
  364. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,151 @@
1
+ // Experimental small-M trellis kernels (variant 7).
2
+ // Decode each weight once per SIMD group and reuse it across M input vectors.
3
+ // Callers restrict M to 2..4 and pass variant 6's decoder/rounding constants.
4
+ // Each vector keeps the original two-accumulator FMA order and simd_sum;
5
+ // fused gate/up also keeps the original bf16 activation rounding boundaries.
6
+ // Baseline implementation and the shared 1MAD header: trellis-linear.ts.
7
+ // Full-model paired performance and quality gates are required before a default.
8
+
9
+ export const REDUCE_SHARED_M_SOURCE = String.raw`
10
+ threadgroup float lutTG[4096];
11
+ if ((VARIANT) == 2) {
12
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += 128u) lutTG[i] = lut[i];
13
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
14
+ }
15
+ const uint lane = thread_index_in_simdgroup;
16
+ const uint sg = simdgroup_index_in_threadgroup;
17
+ const uint row = thread_position_in_grid.y * (uint)ROWS_TG + sg;
18
+ const uint sample = 0u;
19
+ if (row >= (uint)R || sample >= (uint)M) return;
20
+ const uint wpb = (uint)(BT * K / 32);
21
+ const uint runsPerBlock = (uint)BT / 32u;
22
+ const uint nRuns = (uint)C / 32u;
23
+ const device uint32_t* codeRow = codes + (ulong)row * (ulong)((C / BT) * wpb);
24
+ const float scale = float(scales[row]);
25
+ float acc[M], acc2[M];
26
+ #pragma clang loop unroll(full)
27
+ for (uint m = 0; m < (uint)M; ++m) { acc[m] = 0.0f; acc2[m] = 0.0f; }
28
+ for (uint run = lane; run < nRuns; run += 32u) {
29
+ const uint blk = run / runsPerBlock;
30
+ const uint t0 = (run - blk * runsPerBlock) * 32u;
31
+ const device uint32_t* bw = codeRow + blk * wpb;
32
+ const uint w0 = ((uint)BT - 32u - t0) * (uint)K / 32u;
33
+ uint w[K + 1];
34
+ #pragma clang loop unroll(full)
35
+ for (uint i = 0; i <= (uint)K; ++i) {
36
+ const uint wi = w0 + i;
37
+ w[i] = bw[wi >= wpb ? wi - wpb : wi];
38
+ }
39
+ const uint c0 = blk * (uint)BT + t0;
40
+ #pragma clang loop unroll(full)
41
+ for (uint j4 = 0; j4 < 8u; ++j4) {
42
+ float4 xv[M];
43
+ #pragma clang loop unroll(full)
44
+ for (uint m = 0; m < (uint)M; ++m)
45
+ xv[m] = float4(((const device metal::vec<T, 4>*)(x + (ulong)m * (ulong)C + c0))[j4]);
46
+ #pragma clang loop unroll(full)
47
+ for (uint q = 0; q < 4u; ++q) {
48
+ const uint j = j4 * 4u + q;
49
+ const uint b = (31u - j) * (uint)K;
50
+ const uint wi = b >> 5;
51
+ const uint off = b & 31u;
52
+ uint win = w[wi] >> off;
53
+ if (off + (uint)L > 32u) win |= w[wi + 1] << (32u - off);
54
+ win &= (1u << (uint)L) - 1u;
55
+ const float wv = TRELLIS_ROUND(TRELLIS_DECODE(win, lutTG, lut) * scale);
56
+ #pragma clang loop unroll(full)
57
+ for (uint m = 0; m < (uint)M; ++m) {
58
+ if (q & 1u) acc2[m] = metal::fma(wv, xv[m][q], acc2[m]);
59
+ else acc[m] = metal::fma(wv, xv[m][q], acc[m]);
60
+ }
61
+ }
62
+ }
63
+ }
64
+ #pragma clang loop unroll(full)
65
+ for (uint m = 0; m < (uint)M; ++m) {
66
+ const float v = metal::simd_sum(acc[m] + acc2[m]);
67
+ if (lane == 0u) out[(ulong)m * (ulong)R + row] = T(v);
68
+ }
69
+ `;
70
+
71
+ export const GATEUP_SHARED_M_SOURCE = String.raw`
72
+ threadgroup float lutTG[4096];
73
+ if ((VARIANT) == 2) {
74
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += 128u) lutTG[i] = lut[i];
75
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
76
+ }
77
+ const uint lane = thread_index_in_simdgroup;
78
+ const uint sg = simdgroup_index_in_threadgroup;
79
+ const uint row = thread_position_in_grid.y * (uint)ROWS_TG + sg;
80
+ const uint sample = 0u;
81
+ if (row >= (uint)R || sample >= (uint)M) return;
82
+ const uint wpb = (uint)(BT * K / 32);
83
+ const uint runsPerBlock = (uint)BT / 32u;
84
+ const uint nRuns = (uint)C / 32u;
85
+ const ulong rowWords = (ulong)((C / BT) * wpb);
86
+ const device uint32_t* gRow = gcodes + (ulong)row * rowWords;
87
+ const device uint32_t* uRow = ucodes + (ulong)row * rowWords;
88
+ const float gScale = float(gscales[row]);
89
+ const float uScale = float(uscales[row]);
90
+ float gAcc[M], gAcc2[M], uAcc[M], uAcc2[M];
91
+ #pragma clang loop unroll(full)
92
+ for (uint m = 0; m < (uint)M; ++m) {
93
+ gAcc[m] = 0.0f; gAcc2[m] = 0.0f; uAcc[m] = 0.0f; uAcc2[m] = 0.0f;
94
+ }
95
+ for (uint run = lane; run < nRuns; run += 32u) {
96
+ const uint blk = run / runsPerBlock;
97
+ const uint t0 = (run - blk * runsPerBlock) * 32u;
98
+ const device uint32_t* gw = gRow + blk * wpb;
99
+ const device uint32_t* uw = uRow + blk * wpb;
100
+ const uint w0 = ((uint)BT - 32u - t0) * (uint)K / 32u;
101
+ uint g[K + 1];
102
+ uint u[K + 1];
103
+ #pragma clang loop unroll(full)
104
+ for (uint i = 0; i <= (uint)K; ++i) {
105
+ const uint wi = w0 + i;
106
+ const uint idx = wi >= wpb ? wi - wpb : wi;
107
+ g[i] = gw[idx];
108
+ u[i] = uw[idx];
109
+ }
110
+ const uint c0 = blk * (uint)BT + t0;
111
+ #pragma clang loop unroll(full)
112
+ for (uint j4 = 0; j4 < 8u; ++j4) {
113
+ float4 xv4[M];
114
+ #pragma clang loop unroll(full)
115
+ for (uint m = 0; m < (uint)M; ++m)
116
+ xv4[m] = float4(((const device metal::vec<T, 4>*)(x + (ulong)m * (ulong)C + c0))[j4]);
117
+ #pragma clang loop unroll(full)
118
+ for (uint q = 0; q < 4u; ++q) {
119
+ const uint j = j4 * 4u + q;
120
+ const uint b = (31u - j) * (uint)K;
121
+ const uint wi = b >> 5;
122
+ const uint off = b & 31u;
123
+ uint gwin = g[wi] >> off;
124
+ uint uwin = u[wi] >> off;
125
+ if (off + (uint)L > 32u) { gwin |= g[wi + 1] << (32u - off); uwin |= u[wi + 1] << (32u - off); }
126
+ gwin &= (1u << (uint)L) - 1u;
127
+ uwin &= (1u << (uint)L) - 1u;
128
+ const float gv = TRELLIS_ROUND(TRELLIS_DECODE(gwin, lutTG, lut) * gScale);
129
+ const float uv = TRELLIS_ROUND(TRELLIS_DECODE(uwin, lutTG, lut) * uScale);
130
+ #pragma clang loop unroll(full)
131
+ for (uint m = 0; m < (uint)M; ++m) {
132
+ const float xv = xv4[m][q];
133
+ if (q & 1u) { gAcc2[m] = metal::fma(gv, xv, gAcc2[m]); uAcc2[m] = metal::fma(uv, xv, uAcc2[m]); }
134
+ else { gAcc[m] = metal::fma(gv, xv, gAcc[m]); uAcc[m] = metal::fma(uv, xv, uAcc[m]); }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ #pragma clang loop unroll(full)
140
+ for (uint m = 0; m < (uint)M; ++m) {
141
+ const float gate = metal::simd_sum(gAcc[m] + gAcc2[m]);
142
+ const float up = metal::simd_sum(uAcc[m] + uAcc2[m]);
143
+ if (lane == 0u) {
144
+ const T gateT = T(gate);
145
+ const T upT = T(up);
146
+ const T sigmoidT = T(1.0f / (1.0f + metal::precise::exp(-float(gateT))));
147
+ const T siluT = T(float(gateT) * float(sigmoidT));
148
+ mid[(ulong)m * (ulong)R + row] = T(float(siluT) * float(upT));
149
+ }
150
+ }
151
+ `;
@@ -0,0 +1,144 @@
1
+ // Experimental variant 10: reuse each decoded scatter weight across M=2..4.
2
+ // Both kernels retain each output's ordered row accumulation, split boundaries
3
+ // and the caller's partial reduction/cast. M=1 keeps the incumbent kernel.
4
+ // The balanced path requires k=3 / T=256 / L<=12; the generic path preserves
5
+ // the existing packed-word lane mapping for other supported geometries.
6
+
7
+ export const SCATTER_SHARED_M_SOURCE = String.raw`
8
+ threadgroup float lutTG[4096];
9
+ if ((VARIANT) == 2) {
10
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += 128u) lutTG[i] = lut[i];
11
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
12
+ }
13
+ const uint lane = thread_index_in_simdgroup;
14
+ const uint sg = simdgroup_index_in_threadgroup;
15
+ const uint wpb = (uint)(BT * K / 32);
16
+ const uint nb = 32u / wpb; // blocks per SIMD group
17
+ const uint nBlocks = (uint)C / (uint)BT;
18
+ const uint groups = (nBlocks + nb - 1u) / nb;
19
+ const uint group = thread_position_in_grid.y * (uint)SG_TG + sg;
20
+ const uint zi = thread_position_in_grid.z;
21
+ const uint sample = 0u;
22
+ const uint split = zi;
23
+ const uint bi = lane / wpb;
24
+ const uint wi = lane - bi * wpb;
25
+ const uint blk = group * nb + bi;
26
+ const bool active = (group < groups) && (bi < nb) && (blk < nBlocks) && (sample < (uint)M);
27
+ const uint nbrLane = bi * wpb + ((wi + 1u == wpb) ? 0u : wi + 1u);
28
+ // This lane's positions: symbol offsets p = multiples of K inside [32wi, 32wi+32).
29
+ const uint pBase = 32u * wi;
30
+ const uint p0 = ((pBase + (uint)K - 1u) / (uint)K) * (uint)K;
31
+ uint offs[NP];
32
+ bool valid[NP];
33
+ bool spill[NP];
34
+ uint cols[NP];
35
+ #pragma clang loop unroll(full)
36
+ for (uint i = 0; i < (uint)NP; ++i) {
37
+ const uint p = p0 + i * (uint)K;
38
+ valid[i] = active && (p < pBase + 32u);
39
+ offs[i] = p - pBase;
40
+ spill[i] = offs[i] + (uint)L > 32u;
41
+ const uint t = (uint)BT - 1u - p / (uint)K;
42
+ cols[i] = blk * (uint)BT + t;
43
+ }
44
+ const ulong rowWords = (ulong)(INTERLEAVE ? 2 : nBlocks) * wpb;
45
+ const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
46
+ const uint r0 = split * rowsPer;
47
+ const uint r1 = metal::min((uint)R, r0 + rowsPer);
48
+
49
+ const device uint32_t* col0 = codes + (INTERLEAVE
50
+ ? (ulong)(blk / 2) * R * 2 * wpb + (blk % 2) * wpb : (ulong)blk * wpb) + wi;
51
+ const uint mask = (1u << (uint)L) - 1u;
52
+ float acc[M][NP];
53
+ #pragma clang loop unroll(full)
54
+ for (uint m = 0; m < (uint)M; ++m)
55
+ #pragma clang loop unroll(full)
56
+ for (uint i = 0; i < (uint)NP; ++i) acc[m][i] = 0.0f;
57
+ for (uint r = r0; r < r1; ++r) {
58
+ const uint word = active ? col0[(ulong)r * rowWords] : 0u;
59
+ const uint nxt = metal::simd_shuffle(word, (ushort)nbrLane);
60
+ float xr[M];
61
+ #pragma clang loop unroll(full)
62
+ for (uint m = 0; m < (uint)M; ++m) xr[m] = float(x[(ulong)m * (ulong)R + r]);
63
+ const float sr = float(scales[r]);
64
+ #pragma clang loop unroll(full)
65
+ for (uint i = 0; i < (uint)NP; ++i) {
66
+ uint win = word >> offs[i];
67
+ if (spill[i]) win |= nxt << (32u - offs[i]);
68
+ win &= mask;
69
+ const float weight = TRELLIS_ROUND(TRELLIS_DECODE(win, lutTG, lut) * sr);
70
+ #pragma clang loop unroll(full)
71
+ for (uint m = 0; m < (uint)M; ++m) acc[m][i] = metal::fma(weight, xr[m], acc[m][i]);
72
+ }
73
+ }
74
+ #pragma clang loop unroll(full)
75
+ for (uint m = 0; m < (uint)M; ++m) {
76
+ const ulong outBase = ((ulong)m * (ulong)SPLITS + split) * (ulong)C;
77
+ #pragma clang loop unroll(full)
78
+ for (uint i = 0; i < (uint)NP; ++i)
79
+ if (valid[i]) partial[outBase + cols[i]] = acc[m][i];
80
+ }
81
+ `;
82
+
83
+ export const BALANCED_SCATTER_SHARED_M_SOURCE = String.raw`
84
+ // Model-owned tuning selects this table for measured small-M shapes.
85
+ // Store integers so the reciprocal multiply retains its original rounding.
86
+ threadgroup short codebookY[CODEBOOK ? 4096 : 1];
87
+ if (CODEBOOK) {
88
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += threads_per_threadgroup.x)
89
+ codebookY[i] = (short)trellis_y(i);
90
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
91
+ }
92
+ const uint lane = thread_index_in_simdgroup;
93
+ const uint sg = simdgroup_index_in_threadgroup;
94
+ const uint block = thread_position_in_grid.y * (uint)SG_TG + sg;
95
+ const uint nBlocks = (uint)C / (uint)BT;
96
+ const uint zi = thread_position_in_grid.z;
97
+ const uint sample = 0u;
98
+ const uint split = zi;
99
+ if (block >= nBlocks || sample >= (uint)M) return;
100
+ const uint wpb = (uint)(BT * K / 32);
101
+ const ulong rowWords = (ulong)(INTERLEAVE ? 2 : nBlocks) * wpb;
102
+ const uint pBase = lane * 8u * (uint)K;
103
+ const uint wi = pBase >> 5u;
104
+ const uint off = pBase & 31u;
105
+ const uint next = (wi + 1u == wpb) ? 0u : wi + 1u;
106
+ const device uint32_t* words = codes + (INTERLEAVE
107
+ ? (ulong)(block / 2) * R * 2 * wpb + (block % 2) * wpb : (ulong)block * wpb);
108
+ const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
109
+ const uint r0 = split * rowsPer;
110
+ const uint r1 = metal::min((uint)R, r0 + rowsPer);
111
+ float acc[M][8];
112
+ #pragma clang loop unroll(full)
113
+ for (uint m = 0; m < (uint)M; ++m)
114
+ #pragma clang loop unroll(full)
115
+ for (uint i = 0; i < 8u; ++i) acc[m][i] = 0.0f;
116
+ for (uint r = r0; r < r1; ++r) {
117
+ const uint word = words[(ulong)r * rowWords + wi];
118
+ const uint nxt = words[(ulong)r * rowWords + next];
119
+ const uint lo = off == 0u ? word : (word >> off) | (nxt << (32u - off));
120
+ const uint hi = off == 0u ? nxt : nxt >> off;
121
+ float xr[M];
122
+ #pragma clang loop unroll(full)
123
+ for (uint m = 0; m < (uint)M; ++m) xr[m] = float(x[(ulong)m * (ulong)R + r]);
124
+ const float sr = float(scales[r]);
125
+ #pragma clang loop unroll(full)
126
+ for (uint i = 0; i < 8u; ++i) {
127
+ const uint shift = i * (uint)K;
128
+ uint win = lo >> shift;
129
+ if (shift + (uint)L > 32u) win |= hi << (32u - shift);
130
+ win &= (1u << (uint)L) - 1u;
131
+ const float value = (CODEBOOK ? (float)codebookY[win] : (float)trellis_y(win)) * (1.0f / 147.800537109375f);
132
+ const float weight = value * sr;
133
+ #pragma clang loop unroll(full)
134
+ for (uint m = 0; m < (uint)M; ++m) acc[m][i] = metal::fma(weight, xr[m], acc[m][i]);
135
+ }
136
+ }
137
+ #pragma clang loop unroll(full)
138
+ for (uint m = 0; m < (uint)M; ++m) {
139
+ const ulong outBase = ((ulong)m * (ulong)SPLITS + split) * (ulong)C;
140
+ #pragma clang loop unroll(full)
141
+ for (uint i = 0; i < 8u; ++i)
142
+ partial[outBase + block * (uint)BT + (uint)BT - 1u - lane * 8u - i] = acc[m][i];
143
+ }
144
+ `;
@@ -0,0 +1,158 @@
1
+ // Packed axis-0 prefill with in-tile weight reconstruction and float partials.
2
+ // Partitioning, SIMD fragment layout and ordered accumulation follow MLX 0.31.2
3
+ // (MIT, Apple Inc.): mlx/backend/metal/matmul.cpp and steel/gemm/kernels/
4
+ // steel_gemm_splitk.h. The shared operation preserves that reduction contract.
5
+ import { MlxArray } from "../mlx/array";
6
+ import { Dtype } from "../mlx/ffi";
7
+ import { MetalKernel } from "../mlx/metal-kernel";
8
+ import type { TrellisGeometry } from "./trellis-linear";
9
+
10
+ export function splitKTrellisPrefillEligible(g: TrellisGeometry, m: number, dtype: Dtype): boolean {
11
+ return dtype === Dtype.bfloat16 && m >= 5 && m <= 8 &&
12
+ g.axis === 0 && g.T === 256 && g.L === 12 && [2, 3, 4].includes(g.k) &&
13
+ g.inFeatures === 17408 && g.outFeatures === 5120;
14
+ }
15
+
16
+ let partialKernel: MetalKernel | undefined;
17
+ let reductionKernel: MetalKernel | undefined;
18
+ function kernels(): [MetalKernel, MetalKernel] {
19
+ partialKernel ??= new MetalKernel({ name: "mlx_bun_trellis_splitk_prefill",
20
+ inputNames: ["x", "codes", "scales"], outputNames: ["out"],
21
+ header: "#include <metal_simdgroup_matrix>\n", source: String.raw`
22
+ const uint tid=thread_position_in_threadgroup.x;
23
+ const uint lane=thread_index_in_simdgroup;
24
+ const uint sg=simdgroup_index_in_threadgroup;
25
+ const uint mbase=threadgroup_position_in_grid.y*BM;
26
+ const uint nbase=threadgroup_position_in_grid.x*BN;
27
+ const uint fm=((lane/4)&4)+((lane/2)%4);
28
+ const uint fn=((lane/4)&2)*2+(lane%2)*2;
29
+ // The eligible M=5..8 path needs one row of 8x8 SIMD-group tiles.
30
+ constexpr int WM=BM==8?1:2, WN=4/WM, SM=WM*8, SN=WN*8;
31
+ const uint sm=(sg/WN)*8+fm, sn=(sg%WN)*8+fn;
32
+ constexpr int TM=BM/SM, TN=BN/SN;
33
+ threadgroup T As[BM*BK];
34
+ threadgroup T Bs[BK*BN];
35
+ metal::simdgroup_float8x8 acc[TM][TN];
36
+ #pragma clang loop unroll(full)
37
+ for(uint i=0;i<TM;i++) {
38
+ #pragma clang loop unroll(full)
39
+ for(uint j=0;j<TN;j++) {
40
+ acc[i][j].thread_elements()[0]=0.0f;
41
+ acc[i][j].thread_elements()[1]=0.0f;
42
+ }
43
+ }
44
+ constexpr uint wpb=BT*BITS/32;
45
+ const uint split=threadgroup_position_in_grid.z;
46
+ const uint k0=split*PARTITION;
47
+ const uint k1=split+1==SPLITS?KC:k0+PARTITION;
48
+ for(uint kb=k0;kb<k1;kb+=BK) {
49
+ for(uint a=tid;a<BM*BK;a+=128) {
50
+ const uint m=mbase+a/BK, k=kb+a%BK;
51
+ As[(a/BK)*BK+a%BK]=(m<M && k<KC)?x[(ulong)m*KC+k]:T(0);
52
+ }
53
+ for(uint b=tid;b<BK*BN;b+=128) {
54
+ const uint k=kb+b/BN, n=nbase+b%BN;
55
+ T w=T(0);
56
+ if(k<KC && n<N) {
57
+ const uint row=k;
58
+ const uint col=n;
59
+ const uint block=col/BT, t=col%BT;
60
+ const device uint* bw=codes+(INTERLEAVE
61
+ ? (ulong)(block/2)*KC*2*wpb+(ulong)row*2*wpb+(block%2)*wpb
62
+ : (ulong)row*(C/BT)*wpb+block*wpb);
63
+ const uint pos=(BT-1-t)*BITS, wi=pos>>5, off=pos&31u;
64
+ uint win=bw[wi]>>off;
65
+ if(off+L>32)win|=bw[wi+1==wpb?0:wi+1]<<(32-off);
66
+ win&=(1u<<L)-1;
67
+ const uint z=win*34038481u+76625530u;
68
+ const uint p=(z&0x00FF00FFu)+((z>>8)&0x00FF00FFu);
69
+ const int code=int((p&0xFFFFu)+(p>>16))-510;
70
+ // Expansion consumes the precise host LUT even for variant 6.
71
+ // Refine the reciprocal product before scaling and bf16 rounding.
72
+ const float reciprocal=1.0f/147.800537109375f;
73
+ const float approx=float(code)*reciprocal;
74
+ const float residual=metal::fma(-approx,147.800537109375f,float(code));
75
+ const float value=metal::fma(residual,reciprocal,approx);
76
+ w=T(value*float(scales[row]));
77
+ }
78
+ Bs[(b/BN)*BN+b%BN]=w;
79
+ }
80
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
81
+ #pragma clang loop unroll(full)
82
+ for(uint kk=0;kk<BK;kk+=8) {
83
+ metal::simdgroup_float8x8 a[TM],b[TN];
84
+ #pragma clang loop unroll(full)
85
+ for(uint i=0;i<TM;i++) {
86
+ a[i].thread_elements()[0]=float(As[(sm+i*SM)*BK+kk+fn]);
87
+ a[i].thread_elements()[1]=float(As[(sm+i*SM)*BK+kk+fn+1]);
88
+ }
89
+ #pragma clang loop unroll(full)
90
+ for(uint j=0;j<TN;j++) {
91
+ b[j].thread_elements()[0]=float(Bs[(kk+fm)*BN+sn+j*SN]);
92
+ b[j].thread_elements()[1]=float(Bs[(kk+fm)*BN+sn+j*SN+1]);
93
+ }
94
+ #pragma clang loop unroll(full)
95
+ for(uint i=0;i<TM;i++) {
96
+ #pragma clang loop unroll(full)
97
+ for(uint j=0;j<TN;j++) {
98
+ const uint nj=(i%2)?TN-1-j:j;
99
+ metal::simdgroup_multiply_accumulate(acc[i][nj],a[i],b[nj],acc[i][nj]);
100
+ }
101
+ }
102
+ }
103
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
104
+ }
105
+ #pragma clang loop unroll(full)
106
+ for(uint i=0;i<TM;i++) {
107
+ #pragma clang loop unroll(full)
108
+ for(uint j=0;j<TN;j++) {
109
+ const uint m=mbase+sm+i*SM,n=nbase+sn+j*SN;
110
+ if(m<M && n<N)out[(ulong)split*M*N+(ulong)m*N+n]=acc[i][j].thread_elements()[0];
111
+ if(m<M && n+1<N)out[(ulong)split*M*N+(ulong)m*N+n+1]=acc[i][j].thread_elements()[1];
112
+ }
113
+ }
114
+ ` });
115
+ reductionKernel ??= new MetalKernel({ name: "mlx_bun_trellis_splitk_accumulate",
116
+ inputNames: ["partials"], outputNames: ["out"], source: String.raw`
117
+ const uint i = thread_position_in_grid.x;
118
+ if (i >= SIZE) return;
119
+ float total = 0.0f;
120
+ for (uint s = 0; s < SPLITS; s++) total += partials[(ulong)s * SIZE + i];
121
+ out[i] = T(total);
122
+ ` });
123
+ return [partialKernel, reductionKernel];
124
+ }
125
+
126
+ /** Borrow bf16 [M,K] and axis-0 1MAD weights; return owned lazy [M,N].
127
+ * M=5..8, T=256/L=12, k=2/3/4. Match MLX's non-NAX split-K matrix regime;
128
+ * other shapes and hardware require their own dispatch and full-model gates.
129
+ * Peak workspace is SPLITS*M*N float elements, with no dense weight buffer. */
130
+ export function splitKTrellisPrefill(
131
+ x: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry,
132
+ ): MlxArray {
133
+ const [m, k] = x.shape, n = g.outFeatures;
134
+ if (x.ndim !== 2 || x.dtype !== Dtype.bfloat16 || !m || m < 5 || m > 8 ||
135
+ k !== g.inFeatures || g.axis !== 0 || g.T !== 256 || g.L !== 12 ||
136
+ ![2, 3, 4].includes(g.k) || g.cols % 256 !== 0 || n < 1 ||
137
+ k < 128 || k < n || Math.ceil(m / 16) * Math.ceil(n / 16) > 1024)
138
+ throw new Error("unsupported split-K trellis prefill geometry or dtype");
139
+ const tilesM = Math.ceil(m / 32), tilesN = Math.ceil(n / 32), tilesK = Math.floor(k / 16);
140
+ const ratio = Math.max(1, Math.floor(tilesK / (tilesM * tilesN)));
141
+ const splits = Math.min(32, Math.max(2, 2 ** Math.ceil(Math.log2(ratio))));
142
+ const partition = Math.floor(tilesK / splits) * 16;
143
+ const [partial, reduce] = kernels();
144
+ const [workspace] = partial.apply([x, codes, scales], {
145
+ outputs: [{ shape: [splits, m, n], dtype: Dtype.float32 }],
146
+ grid: [Math.ceil(n / 32) * 128, 1, splits], threadGroup: [128, 1, 1],
147
+ templateDtypes: { T: x.dtype }, templateInts: { M: m, N: n, KC: k, C: g.cols,
148
+ BITS: g.k, L: g.L, BT: g.T, BM: 8, BN: 32, BK: 16, SPLITS: splits,
149
+ PARTITION: partition, INTERLEAVE: g.blockInterleave ?? 0 },
150
+ });
151
+ try {
152
+ return reduce.apply([workspace!], {
153
+ outputs: [{ shape: [m, n], dtype: x.dtype }],
154
+ grid: [m * n, 1, 1], threadGroup: [256, 1, 1], templateDtypes: { T: x.dtype },
155
+ templateInts: { SIZE: m * n, SPLITS: splits },
156
+ })[0]!;
157
+ } finally { workspace!.dispose(); }
158
+ }
@@ -0,0 +1,136 @@
1
+ // Packed axis-1 trellis prefill without a full expanded weight allocation.
2
+ // SIMD-group fragment layout follows MLX steel/gemm/mma.h (MIT, Apple Inc.):
3
+ // https://github.com/ml-explore/mlx/blob/v0.31.2/mlx/backend/metal/kernels/steel/gemm/mma.h
4
+ import { MlxArray } from "../mlx/array";
5
+ import { Dtype } from "../mlx/ffi";
6
+ import { MetalKernel } from "../mlx/metal-kernel";
7
+ import type { TrellisGeometry } from "./trellis-linear";
8
+ import { nativeTrellisWidePrefill } from "./trellis-wide-prefill";
9
+
10
+ /** Dispatch profile measured on Qwen's MLP geometry. No model-name check. */
11
+ export function tiledTrellisPrefillEligible(g: TrellisGeometry, m: number, dtype: Dtype): boolean {
12
+ return dtype === Dtype.bfloat16 && m >= 5 && m <= 32 && !nativeTrellisWidePrefill(m) &&
13
+ g.axis === 1 && g.T === 256 && g.L === 12 && [2, 3, 4].includes(g.k) &&
14
+ g.inFeatures === 5120 && g.outFeatures === 17408;
15
+ }
16
+
17
+ let kernel: MetalKernel | undefined;
18
+ function tiledKernel(): MetalKernel {
19
+ return kernel ??= new MetalKernel({ name: "mlx_bun_trellis_prefill_tile",
20
+ inputNames: ["x", "codes", "scales"], outputNames: ["out"],
21
+ header: "#include <metal_simdgroup_matrix>\n",
22
+ source: String.raw`
23
+ const uint tid=thread_position_in_threadgroup.x;
24
+ const uint lane=thread_index_in_simdgroup;
25
+ const uint sg=simdgroup_index_in_threadgroup;
26
+ const uint mbase=threadgroup_position_in_grid.y*BM;
27
+ const uint nbase=threadgroup_position_in_grid.x*BN;
28
+ const uint fm=((lane/4)&4)+((lane/2)%4);
29
+ const uint fn=((lane/4)&2)*2+(lane%2)*2;
30
+ // An eight-row tile assigns all four SIMD groups to output columns.
31
+ // Each output keeps the same 8x8 products and K accumulation order.
32
+ constexpr int WM=BM==8?1:2, WN=4/WM, SM=WM*8, SN=WN*8;
33
+ const uint sm=(sg/WN)*8+fm, sn=(sg%WN)*8+fn;
34
+ constexpr int TM=BM/SM, TN=BN/SN;
35
+ threadgroup T As[BM*BK];
36
+ threadgroup T Bs[BK*BN];
37
+ metal::simdgroup_float8x8 acc[TM][TN];
38
+ #pragma clang loop unroll(full)
39
+ for(uint i=0;i<TM;i++) {
40
+ #pragma clang loop unroll(full)
41
+ for(uint j=0;j<TN;j++) {
42
+ acc[i][j].thread_elements()[0]=0.0f;
43
+ acc[i][j].thread_elements()[1]=0.0f;
44
+ }
45
+ }
46
+ constexpr uint wpb=BT*BITS/32;
47
+ for(uint kb=0;kb<KC;kb+=BK) {
48
+ for(uint a=tid;a<BM*BK;a+=128) {
49
+ const uint m=mbase+a/BK, k=kb+a%BK;
50
+ As[a]=(m<M && k<KC)?x[(ulong)m*KC+k]:T(0);
51
+ }
52
+ for(uint b=tid;b<BK*BN;b+=128) {
53
+ const uint k=kb+b/BN, n=nbase+b%BN;
54
+ T w=T(0);
55
+ if(k<KC && n<N) {
56
+ const uint row=AXIS==1?n:k;
57
+ const uint col=AXIS==1?k:n;
58
+ const uint block=col/BT, t=col%BT;
59
+ const device uint* bw=codes+(ulong)row*(C/BT)*wpb+block*wpb;
60
+ const uint pos=(BT-1-t)*BITS, wi=pos>>5, off=pos&31u;
61
+ uint win=bw[wi]>>off;
62
+ if(off+L>32)win|=bw[wi+1==wpb?0:wi+1]<<(32-off);
63
+ win&=(1u<<L)-1;
64
+ const uint z=win*34038481u+76625530u;
65
+ const uint p=(z&0x00FF00FFu)+((z>>8)&0x00FF00FFu);
66
+ const int code=int((p&0xFFFFu)+(p>>16))-510;
67
+ // Expansion consumes the precise host LUT even for variant 6.
68
+ // Refine the reciprocal product before scaling and bf16 rounding.
69
+ const float reciprocal=1.0f/147.800537109375f;
70
+ const float approx=float(code)*reciprocal;
71
+ const float residual=metal::fma(-approx,147.800537109375f,float(code));
72
+ const float value=metal::fma(residual,reciprocal,approx);
73
+ w=T(value*float(scales[row]));
74
+ }
75
+ Bs[b]=w;
76
+ }
77
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
78
+ #pragma clang loop unroll(full)
79
+ for(uint kk=0;kk<BK;kk+=8) {
80
+ metal::simdgroup_float8x8 a[TM],b[TN];
81
+ #pragma clang loop unroll(full)
82
+ for(uint i=0;i<TM;i++) {
83
+ a[i].thread_elements()[0]=float(As[(sm+i*SM)*BK+kk+fn]);
84
+ a[i].thread_elements()[1]=float(As[(sm+i*SM)*BK+kk+fn+1]);
85
+ }
86
+ #pragma clang loop unroll(full)
87
+ for(uint j=0;j<TN;j++) {
88
+ b[j].thread_elements()[0]=float(Bs[(kk+fm)*BN+sn+j*SN]);
89
+ b[j].thread_elements()[1]=float(Bs[(kk+fm)*BN+sn+j*SN+1]);
90
+ }
91
+ #pragma clang loop unroll(full)
92
+ for(uint i=0;i<TM;i++) {
93
+ #pragma clang loop unroll(full)
94
+ for(uint j=0;j<TN;j++) {
95
+ const uint nj=(i%2)?TN-1-j:j;
96
+ metal::simdgroup_multiply_accumulate(acc[i][nj],a[i],b[nj],acc[i][nj]);
97
+ }
98
+ }
99
+ }
100
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
101
+ }
102
+ #pragma clang loop unroll(full)
103
+ for(uint i=0;i<TM;i++) {
104
+ #pragma clang loop unroll(full)
105
+ for(uint j=0;j<TN;j++) {
106
+ const uint m=mbase+sm+i*SM,n=nbase+sn+j*SN;
107
+ if(m<M && n<N)out[(ulong)m*N+n]=T(acc[i][j].thread_elements()[0]);
108
+ if(m<M && n+1<N)out[(ulong)m*N+n+1]=T(acc[i][j].thread_elements()[1]);
109
+ }
110
+ }
111
+ ` });
112
+ }
113
+
114
+ /** Shared operation for bf16 [M, K], axis-1 1MAD, T=256/L=12, k=2/3/4.
115
+ * M=5..32. Borrow inputs and return owned [M, N]; caller controls evaluation.
116
+ * Reconstruct the precise LUT value before bf16 weight rounding. The default
117
+ * packed matvec's unrefined f32 code value is a different numerical contract.
118
+ * Other geometries need a measured dispatch profile and model-level gates. */
119
+ export function tiledTrellisPrefill(
120
+ x: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry,
121
+ ): MlxArray {
122
+ const [m, k] = x.shape;
123
+ if (x.ndim !== 2 || x.dtype !== Dtype.bfloat16 || !m || m < 5 || m > 32 ||
124
+ k !== g.inFeatures || g.axis !== 1 || g.T !== 256 || g.L !== 12 ||
125
+ ![2, 3, 4].includes(g.k) || g.cols % 256 !== 0 || g.rows < 1)
126
+ throw new Error("unsupported tiled trellis prefill geometry or dtype");
127
+ const bm = m <= 8 ? 8 : m <= 16 ? 16 : 32, bn = 64, bk = 16;
128
+ const [out] = tiledKernel().apply([x, codes, scales], {
129
+ outputs: [{ shape: [m, g.outFeatures], dtype: x.dtype }],
130
+ grid: [Math.ceil(g.outFeatures / bn) * 128, Math.ceil(m / bm), 1],
131
+ threadGroup: [128, 1, 1], templateDtypes: { T: x.dtype },
132
+ templateInts: { M: m, N: g.outFeatures, KC: g.inFeatures, C: g.cols,
133
+ BITS: g.k, L: g.L, BT: g.T, AXIS: g.axis, BM: bm, BN: bn, BK: bk },
134
+ });
135
+ return out!;
136
+ }
@@ -0,0 +1,62 @@
1
+ // Four adjacent weights share one circular packed-word window. Keep the
2
+ // precise expansion values and MLX's matmul/evaluation boundary unchanged.
3
+ import { MlxArray } from "../mlx/array";
4
+ import { Dtype } from "../mlx/ffi";
5
+ import { MetalKernel } from "../mlx/metal-kernel";
6
+ import type { TrellisGeometry } from "./trellis-linear";
7
+
8
+ const kernel = new MetalKernel({
9
+ name: "mlx_bun_trellis_vector_expand",
10
+ inputNames: ["codes", "scales"], outputNames: ["out"],
11
+ source: String.raw`
12
+ uint c = thread_position_in_grid.x * 4;
13
+ uint r = thread_position_in_grid.y;
14
+ if constexpr (ROW_TILE > 0) {
15
+ constexpr uint groups = C / (BT * 2);
16
+ const uint tg = threadgroup_position_in_grid.x;
17
+ const uint tile = tg / (groups * ROW_TILE), within = tg % (groups * ROW_TILE);
18
+ r = tile * ROW_TILE + within % ROW_TILE;
19
+ c = (within / ROW_TILE) * BT * 2 + thread_position_in_threadgroup.x * 4;
20
+ }
21
+ if (c >= C || r >= R) return;
22
+ constexpr uint wpb = BT * BITS / 32;
23
+ const uint block = c / BT, t = c % BT;
24
+ const device uint* bw = codes + (INTERLEAVE
25
+ ? (ulong)(block / 2) * R * 2 * wpb + (ulong)r * 2 * wpb + (block % 2) * wpb
26
+ : (ulong)r * (C / BT) * wpb + block * wpb);
27
+ const float scale = float(scales[r]);
28
+ // The last of four weights starts the window. Earlier weights occupy
29
+ // its higher bits; a second word also handles the circular block edge.
30
+ const uint pos = (BT - 1 - (t + 3)) * BITS, wi = pos >> 5, off = pos & 31u;
31
+ const ulong window = (ulong(bw[wi]) | (ulong(bw[wi + 1 == wpb ? 0 : wi + 1]) << 32)) >> off;
32
+ #pragma clang loop unroll(full)
33
+ for (uint i = 0; i < 4; i++) {
34
+ const uint s = uint(window >> ((3 - i) * BITS)) & ((1u << L) - 1);
35
+ const uint z = s * 34038481u + 76625530u;
36
+ const uint p = (z & 0x00FF00FFu) + ((z >> 8) & 0x00FF00FFu);
37
+ const float y = float(int((p & 0xFFFFu) + (p >> 16)) - 510);
38
+ // Residual refinement reproduces the host f32 LUT before scaling.
39
+ const float reciprocal = 1.0f / 147.800537109375f;
40
+ const float q = y * reciprocal;
41
+ const float value = metal::fma(metal::fma(-q, 147.800537109375f, y), reciprocal, q);
42
+ out[(ulong)r * C + c + i] = T(value * scale);
43
+ }
44
+ `,
45
+ });
46
+
47
+ export function vectorTrellisExpandEligible(g: TrellisGeometry, dtype: Dtype): boolean {
48
+ return dtype === Dtype.bfloat16 && g.L === 12 && g.T === 256 &&
49
+ (g.k === 2 || g.k === 3 || g.k === 4) && g.rows > 0 && g.cols > 0 && g.cols % 256 === 0;
50
+ }
51
+
52
+ /** Decode the stored matrix; the caller owns the projection's evaluation boundary. */
53
+ export function vectorTrellisExpand(codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
54
+ const rowTile = g.blockInterleave && g.rows % 128 === 0 ? 128 : 0;
55
+ return kernel.apply([codes, scales], {
56
+ outputs: [{ shape: [g.rows, g.cols], dtype: Dtype.bfloat16 }],
57
+ grid: rowTile ? [g.cols / 4 * g.rows, 1, 1] : [g.cols / 4, g.rows, 1], threadGroup: [128, 1, 1],
58
+ templateDtypes: { T: Dtype.bfloat16 },
59
+ templateInts: { R: g.rows, C: g.cols, BT: g.T, BITS: g.k, L: g.L,
60
+ INTERLEAVE: g.blockInterleave ?? 0, ROW_TILE: rowTile },
61
+ })[0]!;
62
+ }