lrcyyds1 opened a new issue, #20238:
URL: https://github.com/apache/tvm/issues/20238
### 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:
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]