Skip to content

fix(kernel): encode tensor maps with the typed op for cuda_host builds - #3

Open
spectrometerHBH wants to merge 1 commit into
mainfrom
fix/cuda-host-tensor-map-encode
Open

spectrometerHBH wants to merge 1 commit into
mainfrom
fix/cuda-host-tensor-map-encode

Conversation

@spectrometerHBH

Copy link
Copy Markdown
Member

fp16_bf16_gemm and mla_dsv4_multishape encode their TMA descriptors in the host prelude with a hand-written txl.call_packed("runtime.cuTensorMapEncodeTiled", ...). TVM's cuda_host target (tvm.backend.cuda.export_cuda_host) encodes descriptors itself from the typed tensormap_encode_tiled op and rejects the packed runtime encoder, so these two kernels could not be built as a CUDA-host bundle.

This adds txl.cu_tensor_map_encode_tiled(descriptor, dtype, rank, data, *operands). It takes the same operands in the same order as the packed call (shape operands, then the interleave, swizzle, L2-promotion and OOB-fill modes and an optional forced CUDA dtype) and emits tensormap_encode_tiled. The five call sites switch to it by name only. Ordinary hosts lower the typed op back to the same packed runtime.cuTensorMapEncodeTiled call, so the default build path is unchanged.

The CUDA-host side needs apache/tvm#20489 (C++ host-pass types, typed launch arguments and cluster/PDL launch attributes).

Testing

On B200 with TVM v0.27.0 plus apache/tvm#20489:

  • tests/test_tirx_lite_api.py: 37 passed, including two new tests for the helper (emitted op, attributes and operand count; operand-count validation).
  • Default host path: fp16_bf16_gemm (fp16 and bf16) and mla_dsv4_multishape (bf16 decode, fp8 decode, h128 prefill) correctness pass.
  • CUDA-host path, with every CUDA compile built as host="cuda_host", bundled by export_cuda_host, compiled by tvm_ffi.cpp.build_inline and loaded by tvm_ffi.load_module: all correctness configs pass for fp16_bf16_gemm (10) and mla_dsv4_multishape (94), along with every config of nvfp4_gemm, rmsnorm, alphamoe_fp8_blockscale_qwen3next, kda_decode_multishape, msa_prefill_multishape, msa_decode_multishape and vsa_multishape (220 in total).

Add txl.cu_tensor_map_encode_tiled, which keeps the cuTensorMapEncodeTiled
operand order of the existing packed calls but emits TVM's typed
tensormap_encode_tiled op. CUDA-host code generation encodes that op
directly and rejects the packed runtime encoder; ordinary hosts lower it
back to the same packed call.

Switch the fp16_bf16_gemm and mla_dsv4_multishape host preludes to the
helper.
tqchen pushed a commit to apache/tvm that referenced this pull request Sep 29, 2026
…ls in CUDA-host bundles (#20490)

A CUDA-host bundle (`tvm.backend.cuda.export_cuda_host`, #20395)
compiles device and host code as one NVCC C++ translation unit. Building
the native kernels of mlc-ai/TIRx-kernels this way exposed several
patterns that the bundle could not compile or launch:

- **Low-precision types in the host pass.** The CUDA device header
included `cuda_fp16.h`, `cuda_bf16.h`, `cuda_fp8.h`, `cuda_fp6.h` and
`cuda_fp4.h` (and defined the `fp8_e4_t`-style aliases) only under
`defined(__CUDA_ARCH__)`. NVCC's host pass then fails on kernel
signatures that use `half` or `nv_bfloat16`. The guards now also admit
the host pass (`!defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= N`); NVRTC
and device-only NVCC compilation always define `__CUDA_ARCH__` and are
unchanged.
- **Tensor-map parameters.** The host wrapper bound a `T.TensorMap()`
parameter as `CUtensorMap* x = ((void*)...)`, which C accepts and C++
rejects. It now casts explicitly.
- **Argument types at the launch.** Host C code spells some device types
differently (bfloat16 is `uint16_t*` on the host, `nv_bfloat16*` in the
kernel), so the direct `<<<>>>` launch did not type-check. Launches now
go through a small helper that converts each argument to the kernel's
own parameter type and calls `cudaLaunchKernelEx`.
- **Launch attributes.** `clusterCtaIdx.*`, `preferredClusterCtaIdx.*`,
programmatic dependent launch and cooperative launch were rejected. They
now become the corresponding `cudaLaunchAttribute`s, following
`CUDAWrappedFunc` in the CUDA runtime module (including
`cudaFuncAttributeNonPortableClusterSizeAllowed` for cluster launches
and omitting a unit preferred cluster). Required block dimensions remain
unsupported and are still diagnosed.

### Testing

On B200 (sm_100a), CUDA 13.2, this branch:

- `tests/python/codegen/test_target_codegen_cuda.py -k cuda_host`: 8
passed (4 tests, each under NVCC and NVRTC device compilation). New
tests:
- bfloat16 buffers with a two-CTA cluster launch: runs and checks both
the values and each CTA's cluster rank (`[0, 1, 0, 1]`);
- a programmatic dependent launch flag: runs and checks the launch
attribute;
  - a tensor-map parameter: compiles the bundle with NVCC.
- `tests/python/codegen/test_target_codegen_cuda.py`,
`tests/python/tirx/codegen/test_codegen_cuda.py`,
`tests/python/tirx-transform/test_tir_transform_split_host_device.py`,
`tests/python/tirx-transform/test_tir_transform_lower_tvm_builtin.py`:
487 passed, 8 skipped. The remaining 120 failures are all
parametrizations of `test_ptx_cp_async`, which fails while parsing its
TVMScript body (`prim._OpEQ` receives a string), before any code
generation; this change does not touch that path.

The same change is proposed for the v0.27.0 release branch in #20489.
There it was also verified end to end with mlc-ai/TIRx-kernels (whose
kernels currently target the v0.27.0 script APIs): with
mlc-ai/TIRx-kernels#3, all 220 correctness configs of its nine
single-GPU native kernels pass when every CUDA compile is built with
`host="cuda_host"`, bundled with `export_cuda_host`, compiled by
`tvm_ffi.cpp.build_inline` and loaded with `tvm_ffi.load_module`.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant