use std::ffi::c_void; use xserv_tensor::{DType, Device, Tensor}; unsafe extern "C" { fn launch_softmax_f32( x: *const c_void, out: *mut c_void, rows: i32, cols: i32, stream: *mut c_void, ); fn launch_softmax_bf16( x: *const c_void, out: *mut c_void, rows: i32, cols: i32, stream: *mut c_void, ); } /// Softmax along the last dimension. pub fn softmax(x: &Tensor) -> Tensor { assert!(x.ndim() >= 1); assert!(x.is_contiguous()); assert!(matches!(x.device(), Device::Cuda(_))); let cols = *x.shape().last().unwrap(); let rows = x.numel() / cols; assert!( rows <= i32::MAX as usize, "too many rows for i32 kernel param" ); assert!( cols <= i32::MAX as usize, "cols too large for i32 kernel param" ); let out = Tensor::empty(x.shape(), x.dtype(), x.device()); unsafe { match x.dtype() { DType::F32 => launch_softmax_f32( x.data_ptr() as _, out.data_ptr() as *mut c_void, rows as i32, cols as i32, xserv_cuda::current_stream_raw(), ), DType::BF16 => launch_softmax_bf16( x.data_ptr() as _, out.data_ptr() as *mut c_void, rows as i32, cols as i32, xserv_cuda::current_stream_raw(), ), _ => panic!("unsupported dtype for softmax"), } } out }