#include #include #include #include #include #include #include #include #include #include #include #include #include namespace { using deepseek_v4::fp8::cast_to_ue8m0; using deepseek_v4::fp8::inv_scale_ue8m0; using deepseek_v4::fp8::pack_fp8; struct FusedStoreCacheParam { const void* __restrict__ input; void* __restrict__ cache; const void* __restrict__ indices; uint32_t num_tokens; }; template __global__ void fused_store_flashmla_cache(const __grid_constant__ FusedStoreCacheParam param) { using namespace device; /// NOTE: 584 = 576 + 8 constexpr int64_t kPageBytes = host::div_ceil(584 << kPageBits, 576) * 576; // each warp handles 64 elements, 8 warps, each block handles 1 row const auto& [input, cache, indices, num_tokens] = param; const uint32_t bid = blockIdx.x; const uint32_t tid = threadIdx.x; const uint32_t wid = tid / 32; PDLWaitPrimary(); // prefetch the index const auto index = static_cast(indices)[bid]; // always load the value from input (don't store if invalid) using Float2 = packed_t; const auto elems = static_cast(input)[tid + bid * 256]; if (wid != 7) { const auto [x, y] = cast(elems); const auto abs_max = warp::reduce_max(fmaxf(fabs(x), fabs(y))); const auto scale_raw = fmaxf(1e-4f, abs_max) / kFP8E4M3Max; const auto scale_ue8m0 = cast_to_ue8m0(scale_raw); const auto inv_scale = inv_scale_ue8m0(scale_ue8m0); const auto result = pack_fp8(x * inv_scale, y * inv_scale); const int32_t page = index >> kPageBits; const int32_t offset = index & ((1 << kPageBits) - 1); const auto page_ptr = pointer::offset(cache, page * kPageBytes); const auto value_ptr = pointer::offset(page_ptr, offset * 576); const auto scale_ptr = pointer::offset(page_ptr, 576 << kPageBits, offset * 8); static_cast(value_ptr)[tid] = result; static_cast(scale_ptr)[wid] = scale_ue8m0; } else { const auto result = cast(elems); const int32_t page = index >> kPageBits; const int32_t offset = index & ((1 << kPageBits) - 1); const auto page_ptr = pointer::offset(cache, page * kPageBytes); const auto value_ptr = pointer::offset(page_ptr, offset * 576, 448); static_cast(value_ptr)[tid - 7 * 32] = result; } PDLTriggerSecondary(); } template __global__ void fused_store_indexer_cache(const __grid_constant__ FusedStoreCacheParam param) { using namespace device; /// NOTE: 132 = 128 + 4 constexpr int64_t kPageBytes = 132 << kPageBits; // each warp handles 128 elements, 1 warp, each block handles multiple rows const auto& [input, cache, indices, num_tokens] = param; const auto global_tid = blockIdx.x * blockDim.x + threadIdx.x; const auto global_wid = global_tid / 32; const auto lane_id = threadIdx.x % 32; if (global_wid >= num_tokens) return; PDLWaitPrimary(); // prefetch the index const auto index = static_cast(indices)[global_wid]; // always load the value from input (don't store if invalid) using Float2 = packed_t; using InStorage = AlignedVector; using OutStorage = AlignedVector; const auto elems = static_cast(input)[global_tid]; const auto [x0, x1] = cast(elems[0]); const auto [y0, y1] = cast(elems[1]); const auto local_max = fmaxf(fmaxf(fabs(x0), fabs(x1)), fmaxf(fabs(y0), fabs(y1))); const auto abs_max = warp::reduce_max(local_max); // use normal fp32 scale const auto scale = fmaxf(1e-4f, abs_max) / kFP8E4M3Max; const auto inv_scale = 1.0f / scale; const int32_t page = index >> kPageBits; const int32_t offset = index & ((1 << kPageBits) - 1); const auto page_ptr = pointer::offset(cache, page * kPageBytes); const auto value_ptr = pointer::offset(page_ptr, offset * 128); const auto scale_ptr = pointer::offset(page_ptr, 128 << kPageBits, offset * 4); OutStorage result; result[0] = pack_fp8(x0 * inv_scale, x1 * inv_scale); result[1] = pack_fp8(y0 * inv_scale, y1 * inv_scale); static_cast(value_ptr)[lane_id] = result; static_cast(scale_ptr)[0] = scale; PDLTriggerSecondary(); } template struct FusedStoreCacheFlashMLAKernel { static constexpr int32_t kLogSize = std::countr_zero(kPageSize); static constexpr int64_t kPageBytes = host::div_ceil(584 * kPageSize, 576) * 576; static constexpr auto kernel = fused_store_flashmla_cache; static_assert(std::has_single_bit(kPageSize), "kPageSize must be a power of 2"); static_assert(1 << kLogSize == kPageSize); static void run(tvm::ffi::TensorView input, tvm::ffi::TensorView cache, tvm::ffi::TensorView indices) { using namespace host; auto N = SymbolicSize{"num_tokens"}; auto device_ = SymbolicDevice{}; device_.set_options(); TensorMatcher({N, 512}) // input .with_dtype() .with_device(device_) .verify(input); TensorMatcher({-1, -1}) // cache .with_strides({kPageBytes, 1}) .with_dtype() .with_device(device_) .verify(cache); TensorMatcher({N}) // indices .with_dtype() .with_device(device_) .verify(indices); const auto num_tokens = static_cast(N.unwrap()); const auto params = FusedStoreCacheParam{ .input = input.data_ptr(), .cache = cache.data_ptr(), .indices = indices.data_ptr(), .num_tokens = num_tokens, }; const auto kBlockSize = 256; const auto num_blocks = num_tokens; LaunchKernel(num_blocks, kBlockSize, device_.unwrap()).enable_pdl(kUsePDL)(kernel, params); } }; template struct FusedStoreCacheIndexerKernel { static constexpr int32_t kLogSize = std::countr_zero(kPageSize); static constexpr int64_t kPageBytes = 132 * kPageSize; static constexpr auto kernel = fused_store_indexer_cache; static_assert(std::has_single_bit(kPageSize), "kPageSize must be a power of 2"); static_assert(1 << kLogSize == kPageSize); static void run(tvm::ffi::TensorView input, tvm::ffi::TensorView cache, tvm::ffi::TensorView indices) { using namespace host; auto N = SymbolicSize{"num_tokens"}; auto device_ = SymbolicDevice{}; device_.set_options(); TensorMatcher({N, 128}) // input .with_dtype() .with_device(device_) .verify(input); TensorMatcher({-1, -1}) // cache .with_strides({kPageBytes, 1}) .with_dtype() .with_device(device_) .verify(cache); TensorMatcher({N}) // indices .with_dtype() .with_device(device_) .verify(indices); const auto num_tokens = static_cast(N.unwrap()); const auto params = FusedStoreCacheParam{ .input = input.data_ptr(), .cache = cache.data_ptr(), .indices = indices.data_ptr(), .num_tokens = num_tokens, }; const auto kBlockSize = 128; const auto num_blocks = div_ceil(num_tokens * 32, kBlockSize); LaunchKernel(num_blocks, kBlockSize, device_.unwrap()).enable_pdl(kUsePDL)(kernel, params); } }; } // namespace