This is an automated email from the ASF dual-hosted git repository.

tlopex pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new 7924acaef4 [TOPI][CUDA] Fix topk/sort gridDim overflow by remapping 
grid axes in sort_ir (#19900)
7924acaef4 is described below

commit 7924acaef4277042b6ba981d5b9d44e0611f9610
Author: Neo Chien <[email protected]>
AuthorDate: Mon Sep 14 11:54:58 2026 +0800

    [TOPI][CUDA] Fix topk/sort gridDim overflow by remapping grid axes in 
sort_ir (#19900)
    
    Hi Committers,
    
    This PR addresses issue https://github.com/apache/tvm/issues/19549. Any
    suggestions would be appreciated if you are available.
    
    ---------
    
    Co-authored-by: cchung100m <[email protected]>
---
 python/tvm/topi/gpu/sort.py                        | 27 ++++++---
 .../relax/test_backend_dispatch_sort_scan.py       | 67 ++++++++++++++++++++++
 2 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/python/tvm/topi/gpu/sort.py b/python/tvm/topi/gpu/sort.py
index 2ca4056438..eabed85a9b 100644
--- a/python/tvm/topi/gpu/sort.py
+++ b/python/tvm/topi/gpu/sort.py
@@ -30,9 +30,15 @@ from ..utils import ceil_div, prod, swap
 
 
 def _get_threads(nthread_tx, nthread_bx, nthread_by):
+    target = tvm.target.Target.current(allow_none=True)
+    is_cuda = target is not None and target.kind.name == "cuda"
     tx = te.thread_axis("threadIdx.x")
-    bx = te.thread_axis("blockIdx.x")
-    by = te.thread_axis("blockIdx.y")
+    if is_cuda:
+        bx = te.thread_axis("blockIdx.y")
+        by = te.thread_axis("blockIdx.x")
+    else:
+        bx = te.thread_axis("blockIdx.x")
+        by = te.thread_axis("blockIdx.y")
     return tx, bx, by, nthread_tx, nthread_bx, nthread_by
 
 
@@ -501,17 +507,24 @@ def _sort_common(
             nbx = cast(ceil_div(width, max_threads * thread_work), "int32")
             nbz = cast(ceil_div(size, width), "int32")
 
-        tx, bx, by, _, _, _ = _get_threads(ntx, nbx, nthread_by * nbz)
+        is_cuda = target.kind.name == "cuda"
+        tx = te.thread_axis("threadIdx.x")
+        bx = te.thread_axis("blockIdx.z")  # nbx
+        if is_cuda:
+            by = te.thread_axis("blockIdx.x")  # batch
+            bz = te.thread_axis("blockIdx.y")  # nbz
+        else:
+            by = te.thread_axis("blockIdx.y")  # batch
+            bz = te.thread_axis("blockIdx.x")  # nbz
         with T.frame_scope(
             [
                 T.attr(tx, "thread_extent", ntx),
                 T.attr(bx, "thread_extent", nbx),
-                T.attr(by, "thread_extent", nthread_by * nbz),
+                T.attr(by, "thread_extent", nthread_by),
+                T.attr(bz, "thread_extent", nbz),
             ]
         ):
-            by_val = by % nthread_by
-            bz = by // nthread_by
-            base_idx = by_val * size
+            base_idx = by * size
 
             # calculate the start, mid, and end points of this section
             start_pos = width * bz
diff --git a/tests/python/relax/test_backend_dispatch_sort_scan.py 
b/tests/python/relax/test_backend_dispatch_sort_scan.py
index df4aca033a..c2dc7ef66a 100644
--- a/tests/python/relax/test_backend_dispatch_sort_scan.py
+++ b/tests/python/relax/test_backend_dispatch_sort_scan.py
@@ -411,6 +411,73 @@ def test_dispatch_topk_gpu():
     assert_structural_equal(mod, expected_mod)
 
 
[email protected]
[email protected]("size", [300, 600])
+def test_dispatch_sort_cuda_large_batch(size):
+    target = "cuda"
+    if not tvm.testing.device_enabled(target):
+        pytest.skip(f"{target} not enabled")
+
+    @I.ir_module
+    class Module:
+        @R.function
+        def main(x: R.Tensor(("m", "n"), "float32")):
+            with R.dataflow():
+                gv = R.sort(x, axis=-1, descending=False)
+                R.output(gv)
+            return gv
+
+    batch = 65600  # > CUDA's 65535 gridDim.y/z limit
+    np_data = np.random.uniform(size=(batch, size)).astype("float32")
+    np_sorted = np.sort(np_data, axis=-1)
+
+    with tvm.target.Target(target):
+        mod = DispatchSortScan()(Module)
+        ex = tvm.compile(mod, target)
+
+    def run_and_check():
+        dev = tvm.device_from_target(target)
+        vm = tvm.relax.VirtualMachine(ex, dev)
+        tvm_data = tvm.runtime.tensor(np_data, dev)
+        sorted_data = vm["main"](tvm_data)
+        tvm.testing.assert_allclose(sorted_data.numpy(), np_sorted)
+
+    tvm.testing.run_with_gpu_lock(run_and_check)
+
+
[email protected]
+def test_dispatch_topk_cuda_large_batch():
+    target = "cuda"
+    if not tvm.testing.device_enabled(target):
+        pytest.skip(f"{target} not enabled")
+
+    @I.ir_module
+    class Module:
+        @R.function
+        def main(x: R.Tensor(("m", "n"), "float32")):
+            with R.dataflow():
+                gv = R.topk(x, k=1, axis=-1, ret_type="values", largest=True)
+                R.output(gv)
+            return gv
+
+    batch, size = 65600, 300
+    np_data = np.random.uniform(size=(batch, size)).astype("float32")
+    np_values = np.sort(np_data, axis=-1)[:, -1:]
+
+    with tvm.target.Target(target):
+        mod = DispatchSortScan()(Module)
+        ex = tvm.compile(mod, target)
+
+    def run_and_check():
+        dev = tvm.device_from_target(target)
+        vm = tvm.relax.VirtualMachine(ex, dev)
+        tvm_data = tvm.runtime.tensor(np_data, dev)
+        values = vm["main"](tvm_data)
+        tvm.testing.assert_allclose(values.numpy(), np_values)
+
+    tvm.testing.run_with_gpu_lock(run_and_check)
+
+
 @pytest.mark.parametrize(
     "target",
     [

Reply via email to