Description
TensorNHWC::inverse(LongIndex) (include/cutlass/layout/tensor.h ~lines 158-188) computes different results on device and host whenever stride_h or stride_n is not a multiple of stride_w.
The device branch computes
c = int(index % static_cast<int>(stride_[0])); // provisional, before any division
...
fast_divmod(n, tmp, index, stride_[2], hw_mul, hw_shr);
fast_divmod(h, w, tmp, stride_[1], w_mul, w_shr);
fast_divmod(w, tmp, w, stride_[0], c_mul, c_shr); // final remainder -> tmp, discarded
The channel coordinate is taken from the pre-division remainder expression and never updated; the actual post-divide residual lands in tmp and is thrown away. The host branch derives c = residual % stride_[0] from the final residual, which is the correct inverse of the packed/strided forward mapping.
Simulating the verbatim device branch with cutlass's own find_divisor/fast_divmod for strides (6, 15, 45) and index = 15 gives (n=0, h=1, w=0, c=3) where the host path returns (n=0, h=1, w=0, c=0). The only in-tree caller (test/unit/layout/tensor_nhwc.cu) uses packed strides where both paths agree, so the divergence has gone unnoticed. Minor adjacent note: find_divisor also assumes positive strides.
Suggested fix
Set c from the final fast_divmod remainder (the value currently discarded into tmp), matching the host branch.
Description
TensorNHWC::inverse(LongIndex)(include/cutlass/layout/tensor.h ~lines 158-188) computes different results on device and host wheneverstride_horstride_nis not a multiple ofstride_w.The device branch computes
The channel coordinate is taken from the pre-division remainder expression and never updated; the actual post-divide residual lands in
tmpand is thrown away. The host branch derivesc = residual % stride_[0]from the final residual, which is the correct inverse of the packed/strided forward mapping.Simulating the verbatim device branch with cutlass's own
find_divisor/fast_divmodfor strides (6, 15, 45) and index = 15 gives (n=0, h=1, w=0, c=3) where the host path returns (n=0, h=1, w=0, c=0). The only in-tree caller (test/unit/layout/tensor_nhwc.cu) uses packed strides where both paths agree, so the divergence has gone unnoticed. Minor adjacent note:find_divisoralso assumes positive strides.Suggested fix
Set
cfrom the finalfast_divmodremainder (the value currently discarded intotmp), matching the host branch.