apache / apache/tvm

[Bug][Relax] CPU default pipeline: fused PrimFunc keeps symbolic height/width unbound (MakePackedAPI ICHECK)

Open
#20,238 2 comments 0 reactions 0 assignees View on GitHub
needs-triage type: bug
Dominant language
Python
Stars
13.7k
Forks
4k
Avg merge
2d 1h
Merged PRs (30d)
112

Description

### Expected behavior

`relax.get_default_pipeline(Target("llvm"))` should compile a valid Relax function whose input has symbolic height/width, or reject it with a clean error. In particular, this minimal graph — conv (stride 2) →
conv → bias add — is well-typed and builds fine with the plain default build.

### Actual behavior

The CPU pipeline (the one returned by `relax.get_default_pipeline`, i.e. `cpu_generic`: `LegalizeOps → AnnotateTIROpPattern → FoldConstant → FuseOps → FuseTIR → …`) aborts **at compile time** with an internal
check while wrapping the fused function:

```text
InternalError: Check failed: undefined.size() == 0 (2 vs. 0) :
In PrimFunc fused_conv2d1_add variables (width, height) are used,
but are not passed in as API arguments
```

Classification: this is a compile-time abort of the compiler itself (an internal invariant violation), not a runtime crash of generated code and not a silent miscompilation — no executable is produced. The
input is a valid Relax module that another official build path accepts (see controls), so the failure is not a legitimate rejection of invalid input.

### Environment

```text
OS: Linux x86_64
Target: llvm
TVM commit: 5a8dae4d95c55c8fec9246a607a28c3ff54ffe05 (0.26.dev1)
```

### Steps to reproduce

```python
import tvm
from tvm import relax
from tvm.script import ir as I, relax as R

@I.ir_module
class M:
@R.function
def main(
x: R.Tensor(("batch", 3, "height", "width"), "float32"),
w1: R.Tensor((16, 3, 3, 3), "float32"),
w2: R.Tensor((16, 16, 1, 1), "float32"),
b2: R.Tensor((16,), "float32"),
):
with R.dataflow():
c1 = R.nn.conv2d(x, w1, strides=[2, 2], padding=[1, 1, 1, 1])
c2 = R.nn.conv2d(c1, w2)
bias = R.reshape(b2, R.shape([1, 16, 1, 1]))
out = R.add(c2, bias)
R.output(out)
return out

llvm = tvm.target.Target("llvm")
exe = tvm.relax.build(M, target=llvm, exec_mode="compiled",
relax_pipeline=relax.get_default_pipeline(llvm))
```

### Controls (each removes exactly one trigger condition)

- Trigger: symbolic H/W + conv stride 2 + fused conv+add — **ICHECK abort**
- First conv stride 1 (intermediate shapes stay raw `height`/`width`) — OK
- No bias add (conv→conv is not fused into one group) — OK
- Fully static shapes — OK
- Trigger under the plain default build (`relax.build` without `relax_pipeline`) — OK

### Diagnosis

After the stride-2 conv, intermediate shapes become *expressions* over the input SizeVars (`(height - 1) // 2 + 1`). When FuseOps groups the second conv with the elementwise add, the fused PrimFunc's buffers
carry those expression extents, but `height`/`width` themselves never enter the fused function's signature (not parameters, and not recoverable via `T.match_buffer` of the group input, whose dims are the
expressions — not the raw vars). `MakePackedAPI` (`src/tirx/transform/make_packed_api.cc:278`) then correctly rejects the function for free variables.

For contrast, when the first conv has stride 1, the fused function's input buffer has raw `height`/`width` dims, `match_buffer` binds them, and the build succeeds.

### Real-world impact

ONNX exports with dynamic H/W inputs (e.g. Hugging Face-hosted ResNet50 / ConvNeXt-Tiny ONNX, input `(batch_size, num_channels, height, width)`) fail out of the box with this pipeline:

Contributor guide

No contributing guide indexed for this repository

Research direction

Reproduce the failure with the minimal Relax module and relax.get_default_pipeline(Target("llvm")), then inspect src/tirx/transform/make_packed_api.cc around line 278 and the CPU pipeline stages. Compare the stride-1, no-bias, static-shape, and plain-build controls to isolate where the fused PrimFunc leaves height and width unbound. Done means the valid symbolic-shape graph either builds successfully or receives a clean compiler error instead of the MakePackedAPI ICHECK.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.