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 e4e489b788 [TOPI] Use branchless boundary index for reflect/replicate
pad (#19928)
e4e489b788 is described below
commit e4e489b788d08bf96fada95d221aa7c8a5fb566e
Author: junghyunpark <[email protected]>
AuthorDate: Fri Sep 11 04:17:18 2026 +0900
[TOPI] Use branchless boundary index for reflect/replicate pad (#19928)
reflect_pad and replicate_pad computed the boundary source index with
nested if_then_else, which lowers to per-element branches on CUDA and
made both modes ~1.4-1.5x slower than constant/circular since v0.21.0.
Replace them with branchless integer expressions that are bit-identical
over the valid pad domain:
reflect-101: m = size - 1; idx = m - abs(m - abs(orig_idx))
replicate: idx = max(0, min(size - 1, orig_idx))
Measured on RTX 4060 Ti (sm_89, CUDA 11.8): reflect 7.37->4.73us
(1.50x), replicate 7.14->4.31us (1.43x), output bit-identical. Also
removes the now-unused if_then_else import.
Fixes #19848
---------
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
---
python/tvm/topi/nn/pad.py | 29 ++++++++++-------------------
tests/python/relax/test_frontend_common.py | 28 ++++++----------------------
2 files changed, 16 insertions(+), 41 deletions(-)
diff --git a/python/tvm/topi/nn/pad.py b/python/tvm/topi/nn/pad.py
index 8914c6ba48..2319166ffb 100644
--- a/python/tvm/topi/nn/pad.py
+++ b/python/tvm/topi/nn/pad.py
@@ -18,7 +18,6 @@
import tvm
from tvm import te
-from tvm.tirx import if_then_else
from .. import tag
from ..utils import equal_const_int
@@ -211,15 +210,12 @@ def reflect_pad(data, pad_before, pad_after=None,
name="ReflectPadInput"):
orig_idx = idx - before
- reflected_idx = if_then_else(
- orig_idx < 0,
- -orig_idx, # reflect from start (no repeat)
- if_then_else(
- orig_idx >= size,
- (2 * size - 2) - orig_idx, # reflect from end
- orig_idx,
- ),
- )
+ # Branchless reflect-101 boundary index. This is bit-identical to
the
+ # nested if_then_else form (-orig_idx below 0, (2*size-2)-orig_idx
at or
+ # above size, orig_idx otherwise) over the valid reflect-pad
domain, but
+ # lowers to plain integer arithmetic instead of per-element
branches.
+ m = size - 1
+ reflected_idx = m - tvm.tirx.abs(m - tvm.tirx.abs(orig_idx))
index_tuple.append(reflected_idx)
return data(*index_tuple)
@@ -260,15 +256,10 @@ def replicate_pad(data, pad_before, pad_after=None,
name="ReplicatePadInput"):
before = pad_before[i]
orig_idx = idx - before
- clamped_idx = if_then_else(
- orig_idx < 0,
- tvm.tirx.const(0, "int32"), # replicate first element
- if_then_else(
- orig_idx >= size,
- size - 1, # replicate last element
- orig_idx,
- ),
- )
+ # Branchless edge clamp. This is bit-identical to the nested
+ # if_then_else form (0 below 0, size-1 at or above size, orig_idx
+ # otherwise) but lowers to min/max instead of per-element branches.
+ clamped_idx = tvm.tirx.max(tvm.tirx.const(0, "int32"),
tvm.tirx.min(size - 1, orig_idx))
index_tuple.append(clamped_idx)
return data(*index_tuple)
diff --git a/tests/python/relax/test_frontend_common.py
b/tests/python/relax/test_frontend_common.py
index 024eb65d19..b376ec39b4 100644
--- a/tests/python/relax/test_frontend_common.py
+++ b/tests/python/relax/test_frontend_common.py
@@ -119,32 +119,16 @@ class TestAutopad:
x[
T.int64(0),
T.int64(0),
- T.int64(0) : T.int64(4),
- T.int64(0) : T.int64(4),
+ T.max(T.int64(0), T.min(T.int64(3), v_i2)),
+ T.max(T.int64(0), T.min(T.int64(3), v_i3)),
]
)
T.writes(ReplicatePadInput[v_i0, v_i1, v_i2, v_i3])
ReplicatePadInput[v_i0, v_i1, v_i2, v_i3] = x[
- T.if_then_else(
- v_i0 < T.int64(0),
- T.int64(0),
- T.if_then_else(T.int64(1) <= v_i0, T.int64(0),
v_i0),
- ),
- T.if_then_else(
- v_i1 < T.int64(0),
- T.int64(0),
- T.if_then_else(T.int64(1) <= v_i1, T.int64(0),
v_i1),
- ),
- T.if_then_else(
- v_i2 < T.int64(0),
- T.int64(0),
- T.if_then_else(T.int64(4) <= v_i2, T.int64(3),
v_i2),
- ),
- T.if_then_else(
- v_i3 < T.int64(0),
- T.int64(0),
- T.if_then_else(T.int64(4) <= v_i3, T.int64(3),
v_i3),
- ),
+ T.int64(0),
+ T.int64(0),
+ T.max(T.int64(0), T.min(T.int64(3), v_i2)),
+ T.max(T.int64(0), T.min(T.int64(3), v_i3)),
]
@R.function