#include <cute/tensor.hpp>
#include <cute/atom/copy_atom.hpp>
#include <cute/atom/copy_traits_sm75.hpp>
#include <cstdio>
using namespace cute;
template <class T>
void show(char const* label, T const& value)
{
std::printf("%s", label);
cute::print(value);
cute::print("\n");
}
int main()
half_t storage[1024]{};
auto sB = make_tensor(
make_smem_ptr(storage),
make_layout(make_shape(_32{},_32{}), make_stride(_32{},_1{})));
auto coordB = make_identity_tensor(make_shape(_32{},_32{}));
auto mma_k = make_tiled_mma(
SM80_16x8x16_F32F16F16F32_TN{},
Layout<Shape<_1,_1,_1>>{}, Tile<_16,_8,_32>{});
auto copy_k = make_tiled_copy_B(
Copy_Atom<SM75_U32x4_LDSM_N,half_t>{}, mma_k);
using TC = decltype(copy_k);
int checked = 0;
int different_groups = 0;
for (int lane = 0; lane < 32; ++lane) {
auto thr_mma = mma_k.get_slice(lane);
auto thr_copy = copy_k.get_slice(lane);
auto tCrB = thr_mma.partition_fragment_B(sB);
auto tXrB = thr_copy.retile_D(tCrB);
auto direct = zipped_divide(tCrB, make_layout(_8{}));
auto mma_coords = thr_mma.partition_B(coordB);
auto copy_coords = thr_copy.partition_D(coordB);
auto retiled_coords = thr_copy.retile_D(mma_coords);
for (int n = 0; n < 4; ++n) {
for (int a = 0; a < 8; ++a) {
auto expected = mma_coords(a%4,n,a/4);
auto actual = copy_coords(make_coord(a,0),n,0);
auto retiled = retiled_coords(make_coord(a,0),n,0);
auto slot = tXrB.layout()(make_coord(a,0),n,0);
if (!(expected == actual && actual == retiled) ||
int(slot) != a+8*n) {
std::printf("K gather mismatch: lane=%d n=%d a=%d\n",
lane,n,a);
return 1;
++checked;
bool different = false;
int expected_slot = int(tXrB.layout()(make_coord(a,0),0,0));
int direct_slot = int(direct.layout()(a,0));
different |= expected_slot != direct_slot;
different_groups += different;
if (lane == 0) {
constexpr int R = decltype(tCrB)::rank;
auto V = size<0>(tCrB);
auto mn = right_inverse(typename TC::TiledLayout_TV{})
.with_shape(shape(typename TC::Tiler_MN{}));
auto fmn = upcast<TC::TiledNumThr{} * V>(mn);
auto gather = right_inverse(fmn);
auto values = logical_product(make_layout(V),gather);
auto fv = zipped_divide(values,make_layout(typename TC::AtomNumVal{}));
auto tile = prepend(product_each(shape(fmn)),V);
auto tt = zipped_divide(tCrB.layout(),tile);
auto vt = tt.compose(fv,_);
auto selection = append<R>(Int<0>{},_);
show("B input: ",tCrB.layout());
show("B retile: ",tXrB.layout());
show("B direct: ",direct.layout());
show("B TiledNumVal: ",typename TC::TiledNumVal{});
show("B AtomNumVal: ",typename TC::AtomNumVal{});
show("B inverse with NK shape: ",mn);
show("B frg_layout_nk: ",fmn);
show("B gather shape: ",product_each(shape(fmn)));
show("B gather: ",gather);
show("B product: ",values);
show("B frg_layout_v: ",fv);
show("B tile: ",tile);
show("B t_tensor: ",tt);
show("B v_tensor: ",vt);
show("B selection: ",selection);
show("B result: ",vt(_,selection));
std::printf("r[%d] -> B",a);
cute::print(copy_coords(make_coord(a,0),0,0));
std::printf("K group slots:");
std::printf(" %d",int(tXrB.layout()(make_coord(a,0),0,0)));
std::printf("\nDirect group slots:");
std::printf(" %d",int(direct.layout()(a,0)));
std::printf("\n");
if (different_groups != 32) {
std::printf("Verified %d K-gather matches; %d direct groups differ.\n",
checked,different_groups);