@@ -36,6 +36,12 @@ namespace mt {
3636
3737using namespace ggml_cuda_mma ;
3838
39+ // Finite softmax-mask sentinel (mirrors mt_pagedattn_tile.cu). This TU is built
40+ // with -ffast-math (-ffinite-math-only), so IEEE negative-infinity is UB — the compiler
41+ // may delete -inf materialization / equality tests. -1e30f is finite and safely
42+ // below any real logit; expf(-1e30f - x) underflows to 0.
43+ static constexpr float SOFTMAX_MASK_VAL = -1 .0e30f;
44+
3945// MAD-180 follow-up (2026-05-18): WMMA decode kernel for HEAD_SIZE=128/256.
4046//
4147// The original mt_paged_attention_decode_kernel was designed BEFORE the GQA
@@ -495,7 +501,7 @@ static __device__ __forceinline__ float decode_block_reduce_max(
495501 v = decode_warp_reduce_max (v);
496502 if (lane == 0 ) red_smem[wid] = v;
497503 __syncthreads ();
498- float partial = (threadIdx .x < DECODE_NUM_WARPS ) ? red_smem[lane] : - INFINITY ;
504+ float partial = (threadIdx .x < DECODE_NUM_WARPS ) ? red_smem[lane] : SOFTMAX_MASK_VAL ;
499505 if (wid == 0 ) {
500506 partial = decode_warp_reduce_max (partial);
501507 if (lane == 0 ) red_smem[0 ] = partial;
@@ -637,7 +643,7 @@ __global__ void mt_paged_attention_decode_kernel(
637643 float running_sum[DECODE_MAX_Q ];
638644 #pragma unroll
639645 for (int qhqi = 0 ; qhqi < DECODE_MAX_Q ; ++qhqi) {
640- running_max[qhqi] = - INFINITY ;
646+ running_max[qhqi] = SOFTMAX_MASK_VAL ;
641647 running_sum[qhqi] = 0 .0f ;
642648 #pragma unroll
643649 for (int v = 0 ; v < VEC_PER_THREAD ; ++v) v_acc[v][qhqi] = 0 .0f ;
@@ -679,7 +685,7 @@ __global__ void mt_paged_attention_decode_kernel(
679685 const int qi = qhqi % q_len; // all q_heads in a group share q_pos
680686 const int q_pos_qi = q_pos_first + qi;
681687 const bool visible = (t < sub_len) && (token <= q_pos_qi);
682- smem_logits[qhqi * DECODE_K_TILE_N + t] = visible ? (qk * scale) : - INFINITY ;
688+ smem_logits[qhqi * DECODE_K_TILE_N + t] = visible ? (qk * scale) : SOFTMAX_MASK_VAL ;
683689 }
684690 }
685691 }
@@ -691,12 +697,12 @@ __global__ void mt_paged_attention_decode_kernel(
691697 for (int qhqi = 0 ; qhqi < total_q; ++qhqi) {
692698 float local_max = (tid < DECODE_K_TILE_N )
693699 ? smem_logits[qhqi * DECODE_K_TILE_N + tid]
694- : - INFINITY ;
700+ : SOFTMAX_MASK_VAL ;
695701 const float sub_max = decode_block_reduce_max (local_max, red_smem);
696702
697703 const float new_max = max (running_max[qhqi], sub_max);
698704 float rescale = 1 .0f ;
699- if (running_max[qhqi] > - INFINITY ) {
705+ if (running_max[qhqi] > SOFTMAX_MASK_VAL ) {
700706 rescale = __expf (running_max[qhqi] - new_max);
701707 running_sum[qhqi] *= rescale;
702708 #pragma unroll
@@ -706,7 +712,7 @@ __global__ void mt_paged_attention_decode_kernel(
706712 float local_sum = 0 .0f ;
707713 if (tid < DECODE_K_TILE_N ) {
708714 const float lg = smem_logits[qhqi * DECODE_K_TILE_N + tid];
709- const float e = (lg == - INFINITY ) ? 0 .0f : __expf (lg - new_max);
715+ const float e = (lg == SOFTMAX_MASK_VAL ) ? 0 .0f : __expf (lg - new_max);
710716 smem_logits[qhqi * DECODE_K_TILE_N + tid] = e;
711717 local_sum = e;
712718 }
@@ -864,7 +870,7 @@ __global__ void mt_paged_attention_decode_kernel_wmma(
864870 const size_t off = base + (size_t ) qi * (HEAD_SIZE + 2 );
865871 for (int d = tid; d < HEAD_SIZE ; d += 128 ) partials[off + d] = 0 .0f ;
866872 if (tid == 0 ) {
867- partials[off + HEAD_SIZE ] = - INFINITY ;
873+ partials[off + HEAD_SIZE ] = SOFTMAX_MASK_VAL ;
868874 partials[off + HEAD_SIZE + 1 ] = 0 .0f ;
869875 }
870876 }
@@ -924,7 +930,7 @@ __global__ void mt_paged_attention_decode_kernel_wmma(
924930 // Online softmax state. Each lane owns 8 cols of one Q row; the pair lane
925931 // (tid ^ 16) owns the other 8 cols of the same row. shfl_xor(_, 16) merges
926932 // the two halves for per-row reductions.
927- float running_max = - INFINITY ;
933+ float running_max = SOFTMAX_MASK_VAL ;
928934 float running_sum = 0 .0f ;
929935
930936 tile<16 , 16 , float , DATA_LAYOUT_I_MAJOR > acc[N_INNER ];
@@ -994,18 +1000,18 @@ __global__ void mt_paged_attention_decode_kernel_wmma(
9941000 const int col = 8 * (lane / 16 ) + l;
9951001 const int k_pos = sub_start + col;
9961002 const bool visible = row_valid && (col < sub_len) && (k_pos < valid_ctx_max) && (k_pos <= q_pos_qi);
997- scores.x [l] = visible ? (scores.x [l] * scale) : - INFINITY ;
1003+ scores.x [l] = visible ? (scores.x [l] * scale) : SOFTMAX_MASK_VAL ;
9981004 }
9991005
10001006 // Per-row max
1001- float local_max = - INFINITY ;
1007+ float local_max = SOFTMAX_MASK_VAL ;
10021008 #pragma unroll
10031009 for (int l = 0 ; l < scores.ne ; ++l) local_max = max (local_max, scores.x [l]);
10041010 const float row_max = max (local_max, __shfl_xor_sync (0xFFFFFFFF , local_max, 16 , WARP_SIZE ));
10051011
10061012 const float new_max = max (running_max, row_max);
10071013 float rescale = 1 .0f ;
1008- if (running_max > - INFINITY ) {
1014+ if (running_max > SOFTMAX_MASK_VAL ) {
10091015 rescale = __expf (running_max - new_max);
10101016 running_sum *= rescale;
10111017 #pragma unroll
@@ -1018,7 +1024,7 @@ __global__ void mt_paged_attention_decode_kernel_wmma(
10181024 float local_sum = 0 .0f ;
10191025 #pragma unroll
10201026 for (int l = 0 ; l < scores.ne ; ++l) {
1021- const float e = (scores.x [l] == - INFINITY ) ? 0 .0f : __expf (scores.x [l] - new_max);
1027+ const float e = (scores.x [l] == SOFTMAX_MASK_VAL ) ? 0 .0f : __expf (scores.x [l] - new_max);
10221028 scores.x [l] = e;
10231029 local_sum += e;
10241030 }
@@ -1156,7 +1162,7 @@ __global__ void mt_paged_attention_decode_reduce_kernel(
11561162 const size_t qi_stride = (size_t ) qi * (size_t ) (HEAD_SIZE + 2 );
11571163
11581164 // Pass 1: global max across chunks for this query position.
1159- float global_max = - INFINITY ;
1165+ float global_max = SOFTMAX_MASK_VAL ;
11601166 for (int c = 0 ; c < valid_chunks; ++c) {
11611167 const float m = partials[partial_seq_base + (size_t ) c * chunk_stride_q + qi_stride + HEAD_SIZE ];
11621168 global_max = max (global_max, m);
@@ -1168,7 +1174,7 @@ __global__ void mt_paged_attention_decode_reduce_kernel(
11681174 for (int c = 0 ; c < valid_chunks; ++c) {
11691175 const size_t cbase = partial_seq_base + (size_t ) c * chunk_stride_q + qi_stride;
11701176 const float c_max = partials[cbase + HEAD_SIZE ];
1171- if (c_max == - INFINITY ) continue ;
1177+ if (c_max == SOFTMAX_MASK_VAL ) continue ;
11721178 const float c_sum = partials[cbase + HEAD_SIZE + 1 ];
11731179 const float w = __expf (c_max - global_max);
11741180 global_sum += c_sum * w;
0 commit comments