[BUG] Reusing an alloc_var name as a loop target causes an out-of-scope error
Required prerequisites
- I have read the documentation https://tilelang.com.
- I have searched the Issue Tracker that this hasn't already been reported. (comment there if it has.)
What version of TileLang are you using?
0.1.14 and 0.1.14+cuda.gitd178b4c9
System information
Reproduced in:
- Linux, Python 3.13, TileLang 0.1.14, PyTorch 2.7.1+cu128, RTX 5090.
- Windows, Python 3.13, TileLang source build at d178b4c9, PyTorch 2.11.0+cu130, RTX 5060 Laptop.
The failure occurs during frontend IR construction, before CUDA compilation.
Problem description
Reusing a previous T.alloc_var name as the induction variable of a subsequent loop raises an out-of-scope error.
The second loop introduces a new induction variable, but the frontend treats its binding as an assignment to the previous mutable scalar. Renaming only the second loop target avoids the error.
Reproducible example code
import tilelang.language as T
@T.prim_func
def kernel(A: T.Tensor((2,), "int32")):
with T.Kernel(1, threads=1):
for j in T.serial(2):
d = T.alloc_var("int32")
d = j
A[j] = d
for d in T.Parallel(2):
A[d] = d
Control case: replace the second loop with:
for k in T.Parallel(2):
A[k] = kTraceback
Relevant excerpt:
File ".../repro_loop_rebind.py", line 17, in kernel
A[d] = d
File ".../tilelang/language/eager/builder.py", in rval
raise RuntimeError(...)
RuntimeError: Immutable variable `d` is used outside its defining region!
The error dump shows the second loop incorrectly storing its induction variable into the old buffer:
d[0] = vExpected behavior
The second loop should bind d to its own induction variable, without writing to the previous alloc_var. The kernel should produce [0, 1]. Actual reads of expired bindings should remain rejected.
Additional context
In Builder.bind(), an existing local.var binding takes the mutable-assignment path when the incoming value is a PrimExpr. Loop targets currently use this same path. Distinguishing loop-target binding from ordinary assignment avoids the unintended buffer store while preserving mutable-scalar updates and scope validation.
Source: tile-ai/tilelang