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 f6726b0245 [Relax][VM] Improve diagnostics for unlowered Relax 
operators (#19899)
f6726b0245 is described below

commit f6726b024545e916ece1b6063bfbafc1e5f49065
Author: Yin Li <[email protected]>
AuthorDate: Fri Sep 11 01:19:44 2026 +0400

    [Relax][VM] Improve diagnostics for unlowered Relax operators (#19899)
    
    ## What changed
    
    This improves the diagnostics emitted when VM codegen sees a normal
    Relax operator that was not lowered before codegen.
    
    - Include actionable guidance in both bytecode (`CodeGenVM`) and
    compiled (`CodeGenVMTIR`) paths.
    - Print the full offending Relax call, including attributes, instead of
    only the operator name.
    - Add VM build coverage using an unsupported `relax.nn.conv2d_transpose`
    layout so the diagnostic exposes the layout attributes.
    
    ## Why
    
    Issue #19694 reports that unsupported `conv{1,2,3}d_transpose`
    attributes can pass through legalization and later fail with an opaque
    VM codegen error that only names the operator. Recent upstream work
    added dilation support, while layout/out-layout passthrough remains
    useful for external codegen flows. This keeps legalization behavior
    unchanged but makes an eventual VM failure actionable by showing the
    exact unlowered call and how to address it.
    
    Helps #19694.
    
    ## Validation
    
    - Merged current `main` (87 upstream commits at validation time) without
    changing the three-file PR scope.
    - Configured and built TVM from source on Apple Silicon with CMake 4.3.3
    (`USE_LLVM=OFF`): `tvm_runtime` and `tvm_compiler` completed
    successfully.
    - Built and installed the pinned `tvm-ffi` submodule as a non-editable
    wheel, per repository guidance.
    - `pytest tests/python/relax/test_vm_build.py -k
    test_vm_compile_unlowered_operator_error -vv`: 2 passed (`bytecode` and
    `compiled`). The diagnostic is raised before low-level LLVM code
    generation, so the test is valid in this build configuration.
    - Full pre-commit suite on all three changed files: ASF header, file
    checks, Ruff, Ruff format, and clang-format passed.
    - Python byte compilation and `git diff upstream/main --check` passed.
    
    The previous branch CI was also green on Windows, macOS, and lint before
    the latest-main merge.
    
    ## AI assistance
    
    AI tooling assisted with validation and branch maintenance. I reviewed
    the final diagnostic and test behavior and ran the source build,
    targeted tests, and pre-commit checks listed above.
    
    ---------
    
    Co-authored-by: Kevin-Li-2025 <[email protected]>
---
 src/relax/backend/vm/codegen_vm.cc     |  7 +++++--
 src/relax/backend/vm/codegen_vm_tir.cc |  7 +++++--
 tests/python/relax/test_vm_build.py    | 24 ++++++++++++++++++++++++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/relax/backend/vm/codegen_vm.cc 
b/src/relax/backend/vm/codegen_vm.cc
index a7dd9a21a8..066469eac6 100644
--- a/src/relax/backend/vm/codegen_vm.cc
+++ b/src/relax/backend/vm/codegen_vm.cc
@@ -157,8 +157,11 @@ class CodeGenVM : public 
ExprFunctor<Instruction::Arg(const Expr&)> {
       } else {
         // every "normal" operator is lowered to a global var in the IRModule. 
The Attrs for those
         // ops are handled in a pass when lowering them to TIR.
-        TVM_FFI_THROW(InternalError) << "CodeGenVM cannot handle this 
intrinsic now:\n"
-                                     << call_node->op;
+        TVM_FFI_THROW(InternalError)
+            << "CodeGenVM cannot emit this Relax operator directly. "
+            << "Run the appropriate lowering pass, or route the operator to an 
external "
+            << "codegen before VM codegen.\nOffending call:\n"
+            << call;
       }
     } else {
       EmitNormalCall(call, dst_reg);
diff --git a/src/relax/backend/vm/codegen_vm_tir.cc 
b/src/relax/backend/vm/codegen_vm_tir.cc
index 77057d31ed..b060f935df 100644
--- a/src/relax/backend/vm/codegen_vm_tir.cc
+++ b/src/relax/backend/vm/codegen_vm_tir.cc
@@ -252,8 +252,11 @@ class CodeGenVMTIR : public 
ExprFunctor<ffi::Optional<Expr>(const Expr&)> {
       } else {
         // every "normal" operator is lowered to a global var in the IRModule. 
The Attrs for those
         // ops are handled in a pass when lowering them to TIR.
-        TVM_FFI_THROW(InternalError) << "CodeGenVMTIR cannot handle this 
intrinsic now:\n"
-                                     << call_node->op;
+        TVM_FFI_THROW(InternalError)
+            << "CodeGenVMTIR cannot emit this Relax operator directly. "
+            << "Run the appropriate lowering pass, or route the operator to an 
external "
+            << "codegen before VM codegen.\nOffending call:\n"
+            << call;
       }
     } else {
       EmitNormalCall(call, dst_reg);
diff --git a/tests/python/relax/test_vm_build.py 
b/tests/python/relax/test_vm_build.py
index ad8f94e8a5..d3537615ff 100644
--- a/tests/python/relax/test_vm_build.py
+++ b/tests/python/relax/test_vm_build.py
@@ -84,6 +84,30 @@ def test_vm_compile_without_target_arg(exec_mode):
     tvm.testing.assert_allclose(inp2.numpy(), inp1.numpy(), rtol=1e-7, 
atol=1e-7)
 
 
+def test_vm_compile_unlowered_operator_error(exec_mode):
+    @tvm.script.ir_module
+    class Conv2dTranspose:
+        @R.function
+        def main(
+            x: R.Tensor((1, 4, 4, 1), "float32"),
+            w: R.Tensor((1, 2, 3, 3), "float32"),
+        ):
+            gv = R.nn.conv2d_transpose(
+                x,
+                w,
+                data_layout="NHWC",
+                kernel_layout="IOHW",
+            )
+            return gv
+
+    mod = relax.transform.LegalizeOps()(Conv2dTranspose)
+    with pytest.raises(
+        tvm.error.InternalError,
+        match=r"(?s)Offending 
call:.*(?:R|relax)\.nn\.conv2d_transpose.*data_layout.*NHWC",
+    ):
+        relax.build(mod, target="llvm", exec_mode=exec_mode)
+
+
 def test_match_check(exec_mode):
     @tvm.script.ir_module
     class TestMatchCheck:

Reply via email to