Skip to content

Commit c88b280

Browse files
authored
add fp4_x2 example (#3043)
* add fp4_x2 example * update docstring * improve comments
1 parent 8f50b05 commit c88b280

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Copyright (c) 2025 - 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
# Redistribution and use in source and binary forms, with or without
5+
# modification, are permitted provided that the following conditions are met:
6+
7+
# 1. Redistributions of source code must retain the above copyright notice, this
8+
# list of conditions and the following disclaimer.
9+
10+
# 2. Redistributions in binary form must reproduce the above copyright notice,
11+
# this list of conditions and the following disclaimer in the documentation
12+
# and/or other materials provided with the distribution.
13+
14+
# 3. Neither the name of the copyright holder nor the names of its
15+
# contributors may be used to endorse or promote products derived from
16+
# this software without specific prior written permission.
17+
18+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
29+
"""Example demonstrating how to pass torch.float4_e2m1fn_x2 tensors to CuTe JIT functions.
30+
31+
This example shows how to:
32+
1. Use make_fake_compact_tensor with Float4E2M1FN dtype for compilation
33+
2. Compile the function with "--enable-tvm-ffi" option
34+
3. Pass torch tensors with dtype=float4_e2m1fn_x2 to the compiled function
35+
4. Use recast_tensor to reinterpret a Uint8 tensor as Float4E2M1FN
36+
37+
Note: Float4E2M1FN is a 4-bit floating point type (2-bit exponent, 1-bit mantissa).
38+
In PyTorch, this is represented as torch.float4_e2m1fn_x2, where two float4 values
39+
are packed into a single byte. The tensor is stored as uint8 and viewed as float4_e2m1fn_x2.
40+
41+
To run this example:
42+
43+
.. code-block:: bash
44+
45+
python examples/python/CuTeDSL/cute/tvm_ffi/fp4_x2_tensor.py
46+
"""
47+
48+
import torch
49+
50+
import cutlass
51+
import cutlass.cute as cute
52+
from cutlass.cute.runtime import make_fake_compact_tensor
53+
54+
55+
@cute.kernel
56+
def print_fp4_x2_tensor_info_kernel(t_f4: cute.Tensor, t_uint8: cute.Tensor):
57+
print("[Compile INFO] Float4E2M1FN:", t_f4)
58+
print("[Compile INFO] Uint8:", t_uint8)
59+
t_f4_casted = cute.recast_tensor(t_uint8, cutlass.Float4E2M1FN)
60+
print("[Compile INFO] Float4E2M1FN casted from Uint8:", t_f4_casted)
61+
62+
63+
@cute.jit
64+
def print_fp4_x2_tensor_info(t_f4: cute.Tensor, t_uint8: cute.Tensor):
65+
"""Process a fp4_x2 tensor - prints its layout information.
66+
67+
Note: Float4E2M1FN is a sub-byte type (4-bit), so individual element
68+
dereference operations are not supported. This function demonstrates
69+
passing float4 tensors through the TVM-FFI interface.
70+
"""
71+
print_fp4_x2_tensor_info_kernel(t_f4, t_uint8).launch(grid=(1, 1, 1), block=(1, 1, 1))
72+
73+
74+
def torch_float4_x2_tensor():
75+
"""Demonstrate passing torch.float4_e2m1fn_x2 tensors to compiled function."""
76+
print("=" * 60)
77+
print("Pass torch.float4_e2m1fn_x2 tensor to compiled function")
78+
print("=" * 60)
79+
80+
if not torch.cuda.is_available():
81+
print("CUDA not available, skipping runtime example")
82+
return
83+
84+
m = cute.sym_int()
85+
# float4_e2m1fn_x2 packs two 4-bit values per byte, so the float4
86+
# dimension must be even.
87+
k_f4 = cute.sym_int(divisibility=2)
88+
# The uint8 dimension is half the float4 dimension (1 byte = 2 float4 values).
89+
k_uint8 = cute.sym_int()
90+
fake_tensor_f4 = make_fake_compact_tensor(
91+
cutlass.Float4E2M1FN,
92+
(m, k_f4),
93+
stride_order=(1, 0),
94+
assumed_align=16,
95+
)
96+
fake_tensor_uint8 = make_fake_compact_tensor(
97+
cutlass.Uint8,
98+
(m, k_uint8),
99+
stride_order=(1, 0),
100+
assumed_align=16,
101+
)
102+
103+
print(f"[Compile INFO] Compiling function for Float4E2M1FN tensor")
104+
105+
compiled_fn = cute.compile(
106+
print_fp4_x2_tensor_info, fake_tensor_f4, fake_tensor_uint8, options="--enable-tvm-ffi"
107+
)
108+
109+
tensor_uint8 = torch.randint(0, 256, (16, 16), dtype=torch.uint8, device="cuda")
110+
tensor_f4 = tensor_uint8.view(torch.float4_e2m1fn_x2)
111+
112+
print(f"\n[Runtime INFO] Created torch tensor:")
113+
print(f" Underlying uint8 shape: {tensor_uint8.shape}")
114+
print(f" Float4 view shape: {tensor_f4.shape}")
115+
print(f" Device: {tensor_f4.device}")
116+
117+
print("\n[Runtime INFO] Calling compiled function with float4 tensor...")
118+
# TVM-FFI allows passing torch tensors directly (no DLPack conversion needed).
119+
compiled_fn(tensor_f4, tensor_uint8)
120+
torch.cuda.synchronize()
121+
122+
print("[Runtime INFO] Function call completed successfully!")
123+
124+
125+
if __name__ == "__main__":
126+
torch_float4_x2_tensor()

0 commit comments

Comments
 (0)