Skip to content

CUDA Tile 1.3: store_masked crashes on element-wise-computed tiles #439

Description

@newjordan

CUDA Tile 1.3: store_masked crashes on element-wise-computed tiles

Environment: nvcc 13.3.33, CUDA Tile 1.3, sm_121 (GB10 / DGX Spark), driver 580.159.03

Summary

partition_view::store_masked produces illegal memory accesses when the stored tile
was produced by element-wise arithmetic (including ct::exp). The same store_masked
call works correctly when the tile was produced by ct::mma. The compiler appears to
generate store instructions targeting the wrong register file.

Minimal reproducer

// Build: nvcc -std=c++20 --enable-tile -arch=native -I<path>/include repro.cu -o repro
// Run:   ./repro
// Result: illegal memory access on the element-wise store path

#include <cstdio>
#include <cstdlib>
#include <cuda_runtime.h>
#include "cuda_tile.h"

using bf16 = __nv_bfloat16;

constexpr int M = 32, K = 64, N = 64;

__tile_global__ void repro(
    bf16* __restrict__ X,      // [M, K]  input
    bf16* __restrict__ W,      // [K, N]  weights
    float* __restrict__ Y_mma, // [M, N]  MMA-result output (WORKS)
    float* __restrict__ Y_ew   // [M, N]  element-wise output (CRASHES)
) {
  namespace ct = cuda::tiles; using namespace ct::literals;

  auto xV  = ct::partition_view{ct::tensor_span{X, ct::extents{M, K}}, ct::shape<M, K>{}};
  auto wV  = ct::partition_view{ct::tensor_span{W, ct::extents{K, N}}, ct::shape<K, N>{}};
  auto yM  = ct::partition_view{ct::tensor_span{Y_mma, ct::extents{M, N}}, ct::shape<M, N>{}};
  auto yE  = ct::partition_view{ct::tensor_span{Y_ew,  ct::extents{M, N}}, ct::shape<M, N>{}};

  using Acc = ct::tile<float, ct::shape<M, N>>;

  // Compute C = X @ W via MMA
  auto C = ct::full<Acc>(0.0f);
  C = ct::mma(xV.load_masked(0, 0), wV.load_masked(0, 0), C);

  // Path 1: store MMA result -- SUCCEEDS
  yM.store_masked(C, 0, 0);

  // Path 2: apply element-wise sigmoid, then store -- CRASHES
  auto one  = ct::full<Acc>(1.0f);
  auto C_sigmoid = C / (one + ct::exp(-C));
  yE.store_masked(C_sigmoid, 0, 0);  // ILLEGAL MEMORY ACCESS
}

int main() {
  size_t size_bf16 = (size_t)M * K * sizeof(bf16);
  size_t size_f32  = (size_t)M * N * sizeof(float);

  bf16 *dX, *dW;  float *dYm, *dYe;
  cudaMalloc(&dX, size_bf16);  cudaMemset(dX, 0, size_bf16);
  cudaMalloc(&dW, size_bf16);  cudaMemset(dW, 0, size_bf16);
  cudaMalloc(&dYm, size_f32);  cudaMemset(dYm, 0, size_f32);
  cudaMalloc(&dYe, size_f32);  cudaMemset(dYe, 0, size_f32);

  repro<<<1, 128>>>(dX, dW, dYm, dYe);
  cudaError_t err = cudaDeviceSynchronize();
  printf("result: %s\n", cudaGetErrorString(err));

  cudaFree(dX); cudaFree(dW); cudaFree(dYm); cudaFree(dYe);
  return err != cudaSuccess;
}

What works

Storing a tile that was accumulated via ct::mma works correctly:

auto C = ct::full<Acc>(0.0f);
C = ct::mma(A, B, C);       // MMA accumulation
yV.store_masked(C, 0, 0);   // SUCCEEDS

What crashes

Any element-wise operation on the tile breaks the store:

auto C = ct::full<Acc>(0.0f);
C = ct::mma(A, B, C);              // MMA accumulation
auto result = C / (one + ct::exp(-C));  // element-wise sigmoid
yV.store_masked(result, 0, 0);     // ILLEGAL MEMORY ACCESS

Failed workarounds

  1. Zero-input MMA before store: compiler eliminates the no-op. Crash persists.
  2. Shared-memory bridge: __shared__ forbidden in __tile_global__.
  3. Flat-thread epilogue: threadIdx/blockDim forbidden in __tile_global__.

Production workaround

Keep element-wise-computed tiles in registers and use them directly as MMA
inputs, avoiding any store to HBM.

Expected behavior

When store_masked is called on a non-accumulator-resident tile, the compiler
should spill through shared memory or emit a flat-thread store.

Environment

nvcc: 13.3.33 (sbsa-linux)
CUDA Tile: 1.3.0
GPU: NVIDIA GB10 (sm_121)
Driver: 580.159.03
Host: aarch64 (Grace CPU)

Contact

Reproduced in the hydrak kernel research project.
Full source: src/tile_moe/tile_moe_kernel.cu

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions