@@ -1555,6 +1555,50 @@ func moeArriveZeroBuffer() metal.MTLBuffer {
15551555// the lane (a silent gate regression reads as zero, not as a perf blur).
15561556var moeConcurrentBlocks atomic.Int64
15571557
1558+ // geluFoldDispatches counts MoE blocks that ran the gelu-fused down kernels
1559+ // (#341 phase 1) instead of the gelu-dispatch + plain-down chain. Engagement
1560+ // counter for the A/B tests.
1561+ var geluFoldDispatches atomic.Int64
1562+
1563+ type lthnGeluQMVKey struct {
1564+ groupSize , bits int
1565+ }
1566+
1567+ var (
1568+ lthnGeluQMVPSOMu sync.Mutex
1569+ lthnGeluQMVPSOCache = map [lthnGeluQMVKey ]metal.MTLComputePipelineState {}
1570+ )
1571+
1572+ // lthnGeluQMVPipeline resolves (and caches, including failures) the local-down
1573+ // variant with the MLP gate fused into its x-load (lthn_gelu_qmv, #341 phase
1574+ // 1). A miss — custom library absent, or a gs/bits pair outside the
1575+ // instantiated set — caches nil so the block falls back to the gelu-dispatch +
1576+ // plain-qmv chain without re-probing.
1577+ func lthnGeluQMVPipeline (groupSize , bits int ) (metal.MTLComputePipelineState , bool ) {
1578+ key := lthnGeluQMVKey {groupSize : groupSize , bits : bits }
1579+ lthnGeluQMVPSOMu .Lock ()
1580+ defer lthnGeluQMVPSOMu .Unlock ()
1581+ if pso , ok := lthnGeluQMVPSOCache [key ]; ok {
1582+ return pso , pso != nil
1583+ }
1584+ if customLibrary == nil || customLibrary .GetID () == 0 {
1585+ lthnGeluQMVPSOCache [key ] = nil
1586+ return nil , false
1587+ }
1588+ fn := customLibrary .NewFunctionWithName (core .Sprintf ("lthn_gelu_qmv_bfloat16_t_gs_%d_b_%d" , groupSize , bits ))
1589+ if fn == nil || fn .GetID () == 0 {
1590+ lthnGeluQMVPSOCache [key ] = nil
1591+ return nil , false
1592+ }
1593+ pso , perr := device .NewComputePipelineStateWithFunctionError (fn )
1594+ if perr != nil {
1595+ lthnGeluQMVPSOCache [key ] = nil
1596+ return nil , false
1597+ }
1598+ lthnGeluQMVPSOCache [key ] = pso
1599+ return pso , true
1600+ }
1601+
15581602// ffnMegaKernelCompatible is the KERNEL truth: the widths the megakernel is specialised for
15591603// (4/8-bit byte-aligned codes via ffnMegaPipelineBits, parity-proven at both) with all three
15601604// projections agreeing so one PSO serves the dispatch.
@@ -1706,6 +1750,20 @@ func encMoEBlockQuantDevice(enc metal.MTLComputeCommandEncoderObject, cb metal.M
17061750 if err != nil {
17071751 return enc , encConc , false , nil
17081752 }
1753+ // gelu fold (#341 phase 1): both down projections read gate/up directly and
1754+ // compute gelu(gate)·up at load — the two gelu dispatches (and the expert
1755+ // gelu's barrier) never encode. Decided ONCE for the whole block so the
1756+ // gated scratch stays coherent; either PSO missing (stale metallib, exotic
1757+ // width) or the lever falls back to the chain unchanged.
1758+ geluFold := false
1759+ var localDownGeluPSO , gatherDownGeluPSO metal.MTLComputePipelineState
1760+ if geluFoldEnabled {
1761+ if p1 , ok1 := lthnGeluQMVPipeline (localDownGroupSize , localDownBits ); ok1 {
1762+ if p2 , ok2 := lthnGatherQMVPipeline (lthnGatherQMVKey {groupSize : expDownGroupSize , bits : expDownBits , expertRows : dModel , batchedX : true , gelu : true }); ok2 {
1763+ localDownGeluPSO , gatherDownGeluPSO , geluFold = p1 , p2 , true
1764+ }
1765+ }
1766+ }
17091767 rmsPSO , err := pipelineFor (rmsKernelBF16 (dModel ))
17101768 if err != nil {
17111769 return enc , encConc , false , nil
@@ -1881,8 +1939,22 @@ func encMoEBlockQuantDevice(enc metal.MTLComputeCommandEncoderObject, cb metal.M
18811939 }
18821940 }
18831941 emitGatherDownAll := func () {
1942+ if geluFold {
1943+ // the fused down reads each route's gate/up rows and gelus at load —
1944+ // the expert gelu dispatch never encoded.
1945+ emitLthnGatherQMVGeluRoutes (sink , gatherDownGeluPSO , scratch .expertGateAll , 0 , scratch .expertUpAll , 0 , expDownPacked .buf , expDownPacked .off , expDownScales .buf , expDownScales .off , expDownBiases .buf , expDownBiases .off , scratch .routeIota , routeIdxBuf , 0 , scratch .expertDownAll , 0 , dModel , expertDFF , expDownGroupSize , expDownBits , 0 , topK )
1946+ return
1947+ }
18841948 emitGatherQMVAllRoutes (sink , gatherExpertDownPSO , downAllMeta , downKeyBatched , scratch .expertGatedAll , 0 , expDownPacked .buf , expDownPacked .off , expDownScales .buf , expDownScales .off , expDownBiases .buf , expDownBiases .off , scratch .routeIota , routeIdxBuf , 0 , scratch .expertDownAll , 0 , dModel , expertDFF , expDownGroupSize , expDownBits , 0 , topK )
18851949 }
1950+ emitLocalDown := func () {
1951+ if geluFold {
1952+ geluFoldDispatches .Add (1 )
1953+ emitGeluQMV (sink , localDownGeluPSO , localDownPacked .buf , localDownPacked .off , localDownScales .buf , localDownScales .off , localDownBiases .buf , localDownBiases .off , msc .gate , msc .up , scratch .localOut , 0 , dFF , dModel )
1954+ return
1955+ }
1956+ emitQ (localDownPSO , localDownPacked , localDownScales , localDownBiases , msc .gated , scratch .localOut , dFF , dModel )
1957+ }
18861958
18871959 // ---- concurrent pass: dispatches overlap; barriers mark the true dependency edges.
18881960 // The router, local-MLP, and expert branches are independent until the combine, so the
@@ -1921,19 +1993,27 @@ func encMoEBlockQuantDevice(enc metal.MTLComputeCommandEncoderObject, cb metal.M
19211993 emitQ (localGatePSO , localGatePacked , localGateScales , localGateBiases , scratch .localIn , msc .gate , dModel , dFF )
19221994 emitQ (localUpPSO , localUpPacked , localUpScales , localUpBiases , scratch .localIn , msc .up , dModel , dFF )
19231995 barrier ()
1924- // stage 3: top-k select ∥ local gelu
1996+ // stage 3: top-k select ∥ local gelu (folded into the local down when the
1997+ // fused kernels are available — the dispatch never encodes)
19251998 if ! routerFused {
19261999 routerPlan .emitTopK (sink )
19272000 }
1928- emitBinary (sink , geluPSO , msc .gate , 0 , msc .up , 0 , msc .gated , 0 , dFF )
2001+ if ! geluFold {
2002+ emitBinary (sink , geluPSO , msc .gate , 0 , msc .up , 0 , msc .gated , 0 , dFF )
2003+ }
19292004 barrier ()
19302005 // stage 4: expert gate/up gathers (need the top-k indices) ∥ local down
2006+ // (gelu-fused: reads msc.gate/msc.up from stage 2, two barriers upstream)
19312007 emitGatherInAll ()
1932- emitQ (localDownPSO , localDownPacked , localDownScales , localDownBiases , msc .gated , scratch .localOut , dFF , dModel )
1933- barrier ()
1934- // stage 5: expert gelu
1935- emitBinary (sink , geluPSO , scratch .expertGateAll , 0 , scratch .expertUpAll , 0 , scratch .expertGatedAll , 0 , topK * expertDFF )
2008+ emitLocalDown ()
19362009 barrier ()
2010+ // stage 5: expert gelu — folded into the down gather's load when fused
2011+ // (the stage and its barrier disappear; the stage-4 barrier already
2012+ // orders the gate/up slabs ahead of the down gather)
2013+ if ! geluFold {
2014+ emitBinary (sink , geluPSO , scratch .expertGateAll , 0 , scratch .expertUpAll , 0 , scratch .expertGatedAll , 0 , topK * expertDFF )
2015+ barrier ()
2016+ }
19372017 // stage 6: expert down gather
19382018 emitGatherDownAll ()
19392019 barrier ()
@@ -1989,14 +2069,18 @@ func encMoEBlockQuantDevice(enc metal.MTLComputeCommandEncoderObject, cb metal.M
19892069 } else {
19902070 emitQ (localGatePSO , localGatePacked , localGateScales , localGateBiases , scratch .localIn , msc .gate , dModel , dFF )
19912071 emitQ (localUpPSO , localUpPacked , localUpScales , localUpBiases , scratch .localIn , msc .up , dModel , dFF )
1992- emitBinary (sink , geluPSO , msc .gate , 0 , msc .up , 0 , msc .gated , 0 , dFF )
1993- emitQ (localDownPSO , localDownPacked , localDownScales , localDownBiases , msc .gated , scratch .localOut , dFF , dModel )
2072+ if ! geluFold {
2073+ emitBinary (sink , geluPSO , msc .gate , 0 , msc .up , 0 , msc .gated , 0 , dFF )
2074+ }
2075+ emitLocalDown ()
19942076 }
19952077 seam ("moe.expert" )
19962078 emitRMS (hBuf , pre2Buf .buf , scratch .expertIn , pre2Buf .off )
19972079 if allRoutes {
19982080 emitGatherInAll ()
1999- emitBinary (sink , geluPSO , scratch .expertGateAll , 0 , scratch .expertUpAll , 0 , scratch .expertGatedAll , 0 , topK * expertDFF )
2081+ if ! geluFold {
2082+ emitBinary (sink , geluPSO , scratch .expertGateAll , 0 , scratch .expertUpAll , 0 , scratch .expertGatedAll , 0 , topK * expertDFF )
2083+ }
20002084 emitGatherDownAll ()
20012085 seam ("moe.tail" )
20022086 // combine the routes: acc = Σ_r w_r · down_r — one fused dispatch (byte-identical
0 commit comments