@@ -260,45 +260,75 @@ void cublasmp_gemm(InitMatricesFn init_matrices_fn, NVTECommGemmCtx* ctx, NVTECo
260260 const Tensor* d, const Tensor* bias, const Tensor* pre_act_out, bool transa,
261261 bool transb, bool grad, bool accumulate, int comm_sm_count,
262262 cudaStream_t main_stream) {
263- for (auto t : {a, b, d}) {
264- NVTE_CHECK (is_tensor_scaling (t->scaling_mode ),
265- " Unsupported scaling mode: " + std::to_string (t->scaling_mode ));
263+ const bool tensor_scaling =
264+ is_tensor_scaling (a->scaling_mode ) && is_tensor_scaling (b->scaling_mode );
265+ const bool mxfp8 = is_mxfp_scaling (a->scaling_mode ) && is_mxfp_scaling (b->scaling_mode );
266+
267+ NVTE_CHECK (tensor_scaling || mxfp8, " Unsupported scaling modes: A=" , to_string (a->scaling_mode ),
268+ " , B=" , to_string (b->scaling_mode ));
269+ NVTE_CHECK (is_tensor_scaling (d->scaling_mode ),
270+ " Unsupported scaling mode for D: " , to_string (d->scaling_mode ));
271+
272+ if (mxfp8) {
273+ #if CUBLASMP_VERSION < 801
274+ NVTE_ERROR (" MXFP8 GEMM requires cuBLASMp 0.8.1+." );
275+ #else
276+ NVTE_CHECK (a->with_gemm_swizzled_scales ,
277+ " MXFP8 scales for A are not in format expected by GEMM" );
278+ NVTE_CHECK (b->with_gemm_swizzled_scales ,
279+ " MXFP8 scales for B are not in format expected by GEMM" );
280+ #endif
266281 }
267282
268- // Mirror cublaslt_gemm.cu's CanonicalizeGemmInput for FP8 tensor scaling: depending on the
269- // architecture and the quantizer's usage modes, the appropriate data + scale_inv
270- // may live on the rowwise or columnwise side of the tensor.
271- // * Hopper (!nvte_is_non_tn_fp8_gemm_supported): only TN FP8 GEMMs are supported, so an
272- // FP8 input not already in TN orientation must be swapped to its columnwise (transposed)
273- // view and the transpose flag flipped.
274- // * Blackwell+ (nvte_is_non_tn_fp8_gemm_supported): any FP8 GEMM layout is supported, but
275- // the quantizer usage may have only been set to columnwise. In that case, fall back to
276- // the columnwise view and flip the transpose flag so the GEMM sees the matching data and
277- // scale_inv pair.
278- // The original tensor is never modified; a new Tensor view aliases the columnwise pointers.
283+ // Mirror cublaslt_gemm.cu's input canonicalization. Tensor FP8 columnwise data is a
284+ // transposed view, while MXFP8 columnwise data keeps the logical shape.
279285 const bool fp8_needs_tn = !nvte_is_non_tn_fp8_gemm_supported ();
280- auto canonicalize_fp8_input = [fp8_needs_tn](const Tensor* t, bool current_trans, bool want_trans,
281- const char * side) -> std::pair<Tensor, bool > {
286+ auto canonicalize_input = [fp8_needs_tn](const Tensor* t, bool current_trans, bool is_a,
287+ const char * side) -> std::pair<Tensor, bool > {
288+ auto use_columnwise = [t](bool new_trans) -> std::pair<Tensor, bool > {
289+ Tensor view = *t;
290+ view.data = t->columnwise_data ;
291+ view.scale_inv = t->columnwise_scale_inv ;
292+ view.amax = t->columnwise_amax ;
293+ return {view, new_trans};
294+ };
295+
296+ if (is_mxfp_scaling (t->scaling_mode )) {
297+ if (is_a) {
298+ if (current_trans) {
299+ NVTE_CHECK (t->has_data (), " MXFP8 transposed input A is missing row-wise data" );
300+ return {*t, current_trans};
301+ }
302+ NVTE_CHECK (t->has_columnwise_data (),
303+ " MXFP8 non-transposed input A is missing column-wise data" );
304+ return use_columnwise (current_trans);
305+ }
306+ if (current_trans) {
307+ NVTE_CHECK (t->has_columnwise_data (),
308+ " MXFP8 transposed input B is missing column-wise data" );
309+ return use_columnwise (current_trans);
310+ }
311+ NVTE_CHECK (t->has_data (), " MXFP8 non-transposed input B is missing row-wise data" );
312+ return {*t, current_trans};
313+ }
314+
282315 if (!is_fp8_dtype (t->dtype ())) {
283316 return {*t, current_trans};
284317 }
318+
319+ const bool want_trans = is_a;
285320 const bool hopper_tn_swap = fp8_needs_tn && current_trans != want_trans;
286321 const bool blackwell_missing_rowwise = !fp8_needs_tn && !t->has_data ();
287322 if (!hopper_tn_swap && !blackwell_missing_rowwise) {
288323 return {*t, current_trans};
289324 }
290325 NVTE_CHECK (t->has_columnwise_data () && is_fp8_dtype (t->columnwise_data .dtype ),
291326 " cuBLASMp FP8 GEMM input " , side, " is missing column-wise usage" );
292- Tensor view;
293- view.scaling_mode = t->scaling_mode ;
294- view.data = t->columnwise_data ;
295- view.scale_inv = t->columnwise_scale_inv ;
296- // Columnwise data is the transposed view of the original — flip the transpose flag.
297- return {view, !current_trans};
327+ return use_columnwise (!current_trans);
298328 };
299329
300- auto [a_used, transa_eff] = canonicalize_fp8_input (a, transa, /* want_trans =*/ true , " A" );
301- auto [b_used, transb_eff] = canonicalize_fp8_input (b, transb, /* want_trans =*/ false , " B" );
330+ auto [a_used, transa_eff] = canonicalize_input (a, transa, /* is_a =*/ true , " A" );
331+ auto [b_used, transb_eff] = canonicalize_input (b, transb, /* is_a =*/ false , " B" );
302332 transa = transa_eff;
303333 transb = transb_eff;
304334
@@ -321,20 +351,30 @@ void cublasmp_gemm(InitMatricesFn init_matrices_fn, NVTECommGemmCtx* ctx, NVTECo
321351 sizeof algo_attr));
322352
323353 const cublasMpMatmulMatrixScale_t scale_mode = CUBLASMP_MATMUL_MATRIX_SCALE_SCALAR_FP32 ;
324- if (is_fp8_dtype (a_used.dtype ())) {
325- NVTE_CHECK (a_used.scale_inv .dptr , " Scaling must be set for FP8 dtype" );
354+ auto get_input_scale_mode = [&](const Tensor& t) {
355+ #if CUBLASMP_VERSION >= 801
356+ if (is_mxfp_scaling (t.scaling_mode )) {
357+ return CUBLASMP_MATMUL_MATRIX_SCALE_VEC32_UE8M0 ;
358+ }
359+ #endif
360+ return scale_mode;
361+ };
362+ if (is_fp8_dtype (a_used.dtype ()) || is_mxfp_scaling (a_used.scaling_mode )) {
363+ const cublasMpMatmulMatrixScale_t input_scale_mode = get_input_scale_mode (a_used);
364+ NVTE_CHECK (a_used.scale_inv .dptr , " Scaling must be set for input A" );
326365 NVTE_CHECK_CUBLASMP (cublasMpMatmulDescriptorSetAttribute (
327- ctx->matmul_desc .get (), CUBLASMP_MATMUL_DESCRIPTOR_ATTRIBUTE_A_SCALE_MODE , &scale_mode,
328- sizeof scale_mode ));
366+ ctx->matmul_desc .get (), CUBLASMP_MATMUL_DESCRIPTOR_ATTRIBUTE_A_SCALE_MODE ,
367+ &input_scale_mode, sizeof input_scale_mode ));
329368 NVTE_CHECK_CUBLASMP (cublasMpMatmulDescriptorSetAttribute (
330369 ctx->matmul_desc .get (), CUBLASMP_MATMUL_DESCRIPTOR_ATTRIBUTE_A_SCALE_POINTER ,
331370 &a_used.scale_inv .dptr , sizeof (void *)));
332371 }
333- if (is_fp8_dtype (b_used.dtype ())) {
334- NVTE_CHECK (b_used.scale_inv .dptr , " Scaling must be set for FP8 dtype" );
372+ if (is_fp8_dtype (b_used.dtype ()) || is_mxfp_scaling (b_used.scaling_mode )) {
373+ const cublasMpMatmulMatrixScale_t input_scale_mode = get_input_scale_mode (b_used);
374+ NVTE_CHECK (b_used.scale_inv .dptr , " Scaling must be set for input B" );
335375 NVTE_CHECK_CUBLASMP (cublasMpMatmulDescriptorSetAttribute (
336- ctx->matmul_desc .get (), CUBLASMP_MATMUL_DESCRIPTOR_ATTRIBUTE_B_SCALE_MODE , &scale_mode,
337- sizeof scale_mode ));
376+ ctx->matmul_desc .get (), CUBLASMP_MATMUL_DESCRIPTOR_ATTRIBUTE_B_SCALE_MODE ,
377+ &input_scale_mode, sizeof input_scale_mode ));
338378 NVTE_CHECK_CUBLASMP (cublasMpMatmulDescriptorSetAttribute (
339379 ctx->matmul_desc .get (), CUBLASMP_MATMUL_DESCRIPTOR_ATTRIBUTE_B_SCALE_POINTER ,
340380 &b_used.scale_inv .dptr , sizeof (void *)));
0 commit comments