@@ -691,6 +691,25 @@ def _dequant_fp4_bf16_fold(b, cs0, cs1, cs2, cs3):
691691 return x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8
692692
693693
694+ @triton .jit
695+ def _concat_k (bs , BLOCK_N : tl .constexpr , BLOCK_K : tl .constexpr , SWAP_AB : tl .constexpr ):
696+ # Concat the 8 dequant outputs along K; permute puts the sub-tile index ahead
697+ # of the in-tile K coord so the reshape flattens to k = K_PACK * j + kp.
698+ j0 = tl .join (bs [0 ], bs [1 ])
699+ j1 = tl .join (bs [2 ], bs [3 ])
700+ j2 = tl .join (bs [4 ], bs [5 ])
701+ j3 = tl .join (bs [6 ], bs [7 ])
702+ p0 = tl .join (j0 , j1 )
703+ p1 = tl .join (j2 , j3 )
704+ q = tl .join (p0 , p1 )
705+ if SWAP_AB :
706+ # bs[j] is (BLOCK_N, K_PACK) -> (BLOCK_N, 2, 2, 2, K_PACK) -> (BLOCK_N, BLOCK_K)
707+ return tl .reshape (tl .permute (q , (0 , 4 , 3 , 2 , 1 )), (BLOCK_N , BLOCK_K ))
708+ else :
709+ # bs[j] is (K_PACK, BLOCK_N) -> (2, 2, 2, K_PACK, BLOCK_N) -> (BLOCK_K, BLOCK_N)
710+ return tl .reshape (tl .permute (q , (4 , 3 , 2 , 0 , 1 )), (BLOCK_K , BLOCK_N ))
711+
712+
694713@triton .jit
695714def _dequant_fp4_fp16 (b , s0 , s1 , s2 , s3 ):
696715 x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 = tl .inline_asm_elementwise (
@@ -904,7 +923,6 @@ def _w4a16_moe_gemm_kernel(
904923 return
905924
906925 offs_bn = (pid_n * BLOCK_SIZE_N + tl .arange (0 , BLOCK_SIZE_N ).to (tl .int64 )) % N
907- offs_ak_pack = tl .arange (0 , BLOCK_SIZE_K_PACK )
908926 offs_bk = tl .arange (0 , BLOCK_SIZE_K_PACK )
909927
910928 if SWAP_AB :
@@ -939,20 +957,18 @@ def _w4a16_moe_gemm_kernel(
939957 bs = _dequant_int4_bf16 (b_packed , scale_bc )
940958
941959 k_logical_base = k * BLOCK_SIZE_K
942- for j in tl .static_range (8 ):
943- k_off = k_logical_base + j * BLOCK_SIZE_K_PACK
944- if SWAP_AB :
945- a_j_ptrs = a_base + (k_off + offs_ak_pack [:, None ]) * stride_ak
946- a_j = tl .load (
947- a_j_ptrs , mask = token_mask [None , :], other = 0.0
948- ) # (K_PACK, M)
949- accumulator = tl .dot (bs [j ], a_j , acc = accumulator ) # (N, M)
950- else :
951- a_j_ptrs = a_base + (k_off + offs_ak_pack [None , :]) * stride_ak
952- a_j = tl .load (
953- a_j_ptrs , mask = token_mask [:, None ], other = 0.0
954- ) # (M, K_PACK)
955- accumulator = tl .dot (a_j , bs [j ], acc = accumulator ) # (M, N)
960+ # One mma over the whole K tile; the activation is loaded once as a
961+ # full tile instead of once per sub-tile.
962+ bs_full = _concat_k (bs , BLOCK_SIZE_N , BLOCK_SIZE_K , SWAP_AB )
963+ offs_ak_full = tl .arange (0 , BLOCK_SIZE_K )
964+ if SWAP_AB :
965+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [:, None ]) * stride_ak
966+ a_full = tl .load (a_full_ptrs , mask = token_mask [None , :], other = 0.0 ) # (K, M)
967+ accumulator = tl .dot (bs_full , a_full , acc = accumulator ) # (N, M)
968+ else :
969+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [None , :]) * stride_ak
970+ a_full = tl .load (a_full_ptrs , mask = token_mask [:, None ], other = 0.0 ) # (M, K)
971+ accumulator = tl .dot (a_full , bs_full , acc = accumulator ) # (M, N)
956972
957973 b_ptrs += BLOCK_SIZE_K_PACK * stride_bk
958974
@@ -1080,7 +1096,6 @@ def _w4a16_moe_gemm_silu_kernel(
10801096
10811097 offs_bn_gate = offs_cn % N
10821098 offs_bn_up = offs_bn_gate + N
1083- offs_ak_pack = tl .arange (0 , BLOCK_SIZE_K_PACK )
10841099 offs_bk = tl .arange (0 , BLOCK_SIZE_K_PACK )
10851100
10861101 if SWAP_AB :
@@ -1136,18 +1151,21 @@ def _w4a16_moe_gemm_silu_kernel(
11361151 bs_up = _dequant_int4_bf16 (b_packed_up , scale_up_bc )
11371152
11381153 k_logical_base = k * BLOCK_SIZE_K
1139- for j in tl .static_range (8 ):
1140- k_off = k_logical_base + j * BLOCK_SIZE_K_PACK
1141- if SWAP_AB :
1142- a_j_ptrs = a_base + (k_off + offs_ak_pack [:, None ]) * stride_ak
1143- a_j = tl .load (a_j_ptrs , mask = token_mask [None , :], other = 0.0 )
1144- acc_gate = tl .dot (bs_gate [j ], a_j , acc = acc_gate )
1145- acc_up = tl .dot (bs_up [j ], a_j , acc = acc_up )
1146- else :
1147- a_j_ptrs = a_base + (k_off + offs_ak_pack [None , :]) * stride_ak
1148- a_j = tl .load (a_j_ptrs , mask = token_mask [:, None ], other = 0.0 )
1149- acc_gate = tl .dot (a_j , bs_gate [j ], acc = acc_gate )
1150- acc_up = tl .dot (a_j , bs_up [j ], acc = acc_up )
1154+ # gate and up each get one mma; the activation is loaded once and
1155+ # shared by both.
1156+ bs_gate_full = _concat_k (bs_gate , BLOCK_SIZE_N , BLOCK_SIZE_K , SWAP_AB )
1157+ bs_up_full = _concat_k (bs_up , BLOCK_SIZE_N , BLOCK_SIZE_K , SWAP_AB )
1158+ offs_ak_full = tl .arange (0 , BLOCK_SIZE_K )
1159+ if SWAP_AB :
1160+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [:, None ]) * stride_ak
1161+ a_full = tl .load (a_full_ptrs , mask = token_mask [None , :], other = 0.0 )
1162+ acc_gate = tl .dot (bs_gate_full , a_full , acc = acc_gate )
1163+ acc_up = tl .dot (bs_up_full , a_full , acc = acc_up )
1164+ else :
1165+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [None , :]) * stride_ak
1166+ a_full = tl .load (a_full_ptrs , mask = token_mask [:, None ], other = 0.0 )
1167+ acc_gate = tl .dot (a_full , bs_gate_full , acc = acc_gate )
1168+ acc_up = tl .dot (a_full , bs_up_full , acc = acc_up )
11511169
11521170 b_ptrs_gate += BLOCK_SIZE_K_PACK * stride_bk
11531171 b_ptrs_up += BLOCK_SIZE_K_PACK * stride_bk
@@ -1560,7 +1578,6 @@ def _mxfp4_moe_gemm_kernel(
15601578 return
15611579
15621580 offs_bn = (pid_n * BLOCK_SIZE_N + tl .arange (0 , BLOCK_SIZE_N ).to (tl .int64 )) % N
1563- offs_ak_pack = tl .arange (0 , BLOCK_SIZE_K_PACK )
15641581 offs_bk = tl .arange (0 , BLOCK_SIZE_K_PACK )
15651582
15661583 if SWAP_AB :
@@ -1605,16 +1622,18 @@ def _mxfp4_moe_gemm_kernel(
16051622 bs = _dequant_fp4_bf16 (b_packed , s0 , s1 , s2 , s3 )
16061623
16071624 k_logical_base = k * BLOCK_SIZE_K
1608- for j in tl .static_range (8 ):
1609- k_off = k_logical_base + j * BLOCK_SIZE_K_PACK
1610- if SWAP_AB :
1611- a_j_ptrs = a_base + (k_off + offs_ak_pack [:, None ]) * stride_ak
1612- a_j = tl .load (a_j_ptrs , mask = token_mask [None , :], other = 0.0 )
1613- accumulator = tl .dot (bs [j ], a_j , acc = accumulator )
1614- else :
1615- a_j_ptrs = a_base + (k_off + offs_ak_pack [None , :]) * stride_ak
1616- a_j = tl .load (a_j_ptrs , mask = token_mask [:, None ], other = 0.0 )
1617- accumulator = tl .dot (a_j , bs [j ], acc = accumulator )
1625+ # One mma over the whole K tile; the activation is loaded once as a
1626+ # full tile instead of once per sub-tile.
1627+ bs_full = _concat_k (bs , BLOCK_SIZE_N , BLOCK_SIZE_K , SWAP_AB )
1628+ offs_ak_full = tl .arange (0 , BLOCK_SIZE_K )
1629+ if SWAP_AB :
1630+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [:, None ]) * stride_ak
1631+ a_full = tl .load (a_full_ptrs , mask = token_mask [None , :], other = 0.0 ) # (K, M)
1632+ accumulator = tl .dot (bs_full , a_full , acc = accumulator ) # (N, M)
1633+ else :
1634+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [None , :]) * stride_ak
1635+ a_full = tl .load (a_full_ptrs , mask = token_mask [:, None ], other = 0.0 ) # (M, K)
1636+ accumulator = tl .dot (a_full , bs_full , acc = accumulator ) # (M, N)
16181637
16191638 b_ptrs += BLOCK_SIZE_K_PACK * stride_bk
16201639
@@ -1719,7 +1738,6 @@ def _mxfp4_moe_gemm_silu_kernel(
17191738
17201739 offs_bn_gate = offs_cn % N
17211740 offs_bn_up = offs_bn_gate + N
1722- offs_ak_pack = tl .arange (0 , BLOCK_SIZE_K_PACK )
17231741 offs_bk = tl .arange (0 , BLOCK_SIZE_K_PACK )
17241742
17251743 if SWAP_AB :
@@ -1808,18 +1826,21 @@ def _mxfp4_moe_gemm_silu_kernel(
18081826 bs_up = _dequant_fp4_bf16 (b_packed_up , su0 , su1 , su2 , su3 )
18091827
18101828 k_logical_base = k * BLOCK_SIZE_K
1811- for j in tl .static_range (8 ):
1812- k_off = k_logical_base + j * BLOCK_SIZE_K_PACK
1813- if SWAP_AB :
1814- a_j_ptrs = a_base + (k_off + offs_ak_pack [:, None ]) * stride_ak
1815- a_j = tl .load (a_j_ptrs , mask = token_mask [None , :], other = 0.0 )
1816- acc_gate = tl .dot (bs_gate [j ], a_j , acc = acc_gate )
1817- acc_up = tl .dot (bs_up [j ], a_j , acc = acc_up )
1818- else :
1819- a_j_ptrs = a_base + (k_off + offs_ak_pack [None , :]) * stride_ak
1820- a_j = tl .load (a_j_ptrs , mask = token_mask [:, None ], other = 0.0 )
1821- acc_gate = tl .dot (a_j , bs_gate [j ], acc = acc_gate )
1822- acc_up = tl .dot (a_j , bs_up [j ], acc = acc_up )
1829+ # gate and up each get one mma; the activation is loaded once and
1830+ # shared by both.
1831+ bs_gate_full = _concat_k (bs_gate , BLOCK_SIZE_N , BLOCK_SIZE_K , SWAP_AB )
1832+ bs_up_full = _concat_k (bs_up , BLOCK_SIZE_N , BLOCK_SIZE_K , SWAP_AB )
1833+ offs_ak_full = tl .arange (0 , BLOCK_SIZE_K )
1834+ if SWAP_AB :
1835+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [:, None ]) * stride_ak
1836+ a_full = tl .load (a_full_ptrs , mask = token_mask [None , :], other = 0.0 )
1837+ acc_gate = tl .dot (bs_gate_full , a_full , acc = acc_gate )
1838+ acc_up = tl .dot (bs_up_full , a_full , acc = acc_up )
1839+ else :
1840+ a_full_ptrs = a_base + (k_logical_base + offs_ak_full [None , :]) * stride_ak
1841+ a_full = tl .load (a_full_ptrs , mask = token_mask [:, None ], other = 0.0 )
1842+ acc_gate = tl .dot (a_full , bs_gate_full , acc = acc_gate )
1843+ acc_up = tl .dot (a_full , bs_up_full , acc = acc_up )
18231844
18241845 b_ptrs_gate += BLOCK_SIZE_K_PACK * stride_bk
18251846 b_ptrs_up += BLOCK_SIZE_K_PACK * stride_bk
0 commit comments