This is an automated email from the ASF dual-hosted git repository.

spectrometerHBH pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-tirx.git


The following commit(s) were added to refs/heads/main by this push:
     new 0d2205f25 [CI] Split minimal example runners and cover Windows and 
macOS (#115)
0d2205f25 is described below

commit 0d2205f2530843eef1e396b2680a37633ff97150
Author: Tianqi Chen <[email protected]>
AuthorDate: Wed Oct 28 15:13:28 2026 -0400

    [CI] Split minimal example runners and cover Windows and macOS (#115)
    
    Run the quick-start examples through separate argument-free CPU and CUDA
    task scripts, each retaining an explicit example list. Update the
    existing Jenkins unit-test calls and run the CPU examples in the
    existing Windows and macOS/Metal test steps.
    
    Use the native MSVC ABI and installed FFI import library for standard
    Windows module exports. Extend the Windows CPU runner to build and run
    the C++ loader with CMake, including multi-config output placement and
    runtime DLL discovery. Use the runtime tensor allocator for portable
    alignment, remove the redundant Linux linker workaround, and update the
    adjacent example documentation.
---
 .github/workflows/main.yml                         | 18 ++++++++-------
 ci/jenkins/cpu_jenkinsfile.groovy                  |  2 +-
 ci/jenkins/gpu_jenkinsfile.groovy                  |  2 +-
 docs/get_started/quick_start.rst                   |  4 ++--
 examples/quick_start/CMakeLists.txt                |  5 ----
 examples/quick_start/README.md                     |  2 +-
 examples/quick_start/load_cpp.cc                   | 16 ++++---------
 examples/quick_start/run_all_cpu.bat               |  7 ++++++
 python/tvm_tirx/codegen/executable.py              |  5 ++++
 python/tvm_tirx/support/cc.py                      |  3 ++-
 tests/python/codegen/llvm/test_minimal.py          | 27 ++++++++++++++++++++++
 .../scripts/task_minimal_examples_cpu.bat          | 13 ++++-------
 ...al_examples.sh => task_minimal_examples_cpu.sh} |  7 +-----
 ...l_examples.sh => task_minimal_examples_cuda.sh} |  7 +-----
 14 files changed, 66 insertions(+), 52 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0c6891393..9dbd66561 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -72,10 +72,11 @@ jobs:
           uv pip install --no-deps --force-reinstall dist/apache_tvm_tirx-*.whl
       - name: Test
         shell: bash
-        run: >-
-          uv run --no-sync python -m pytest -v 
tests/python/codegen/llvm/test_minimal.py
-          tests/python/runtime/test_validate_wheel_library.py 
tests/python/script
-          tests/python/ir/test_op_rust.py
+        run: |
+          uv run --no-sync python -m pytest -v 
tests/python/codegen/llvm/test_minimal.py \
+            tests/python/runtime/test_validate_wheel_library.py 
tests/python/script \
+            tests/python/ir/test_op_rust.py
+          ./tests/scripts/task_minimal_examples_cpu.sh
       - name: Rust tests
         timeout-minutes: 20
         shell: bash
@@ -127,10 +128,11 @@ jobs:
           )
       - name: Test
         shell: cmd /C call {0}
-        run: >-
-          uv run --no-sync python -m pytest -v 
tests/python/codegen/llvm/test_minimal.py
-          tests/python/runtime/test_validate_wheel_library.py 
tests/python/script
-          tests/python/ir/test_op_rust.py
+        run: |
+          uv run --no-sync python -m pytest -v 
tests/python/codegen/llvm/test_minimal.py ^
+            tests/python/runtime/test_validate_wheel_library.py 
tests/python/script ^
+            tests/python/ir/test_op_rust.py || exit /b 1
+          call tests\scripts\task_minimal_examples_cpu.bat || exit /b 1
       - name: Rust tests
         timeout-minutes: 20
         shell: cmd /C call {0}
diff --git a/ci/jenkins/cpu_jenkinsfile.groovy 
b/ci/jenkins/cpu_jenkinsfile.groovy
index 8f91c9f32..54f149fa9 100644
--- a/ci/jenkins/cpu_jenkinsfile.groovy
+++ b/ci/jenkins/cpu_jenkinsfile.groovy
@@ -57,7 +57,7 @@ stage('Test') {
         script: """${docker_run} ${images.ci_cpu} bash -euo pipefail -c '
             source ./tests/scripts/test_task_install_dist_wheels.sh
             ./tests/scripts/task_python_unittest.sh
-            ./tests/scripts/task_minimal_examples.sh cpu
+            ./tests/scripts/task_minimal_examples_cpu.sh
           '""",
         label: 'Run Python unit tests',
       )
diff --git a/ci/jenkins/gpu_jenkinsfile.groovy 
b/ci/jenkins/gpu_jenkinsfile.groovy
index 9f2374259..e6d1c5789 100644
--- a/ci/jenkins/gpu_jenkinsfile.groovy
+++ b/ci/jenkins/gpu_jenkinsfile.groovy
@@ -66,7 +66,7 @@ parallel(
           script: """${docker_run} ${images.ci_gpu} bash -euo pipefail -c '
             source ./tests/scripts/test_task_install_dist_wheels.sh --group 
cuda
             ./tests/scripts/task_python_unittest_gpuonly.sh
-            ./tests/scripts/task_minimal_examples.sh cuda
+            ./tests/scripts/task_minimal_examples_cuda.sh
           '""",
           label: 'Run Python GPU unit tests',
         )
diff --git a/docs/get_started/quick_start.rst b/docs/get_started/quick_start.rst
index 35f1d0b51..cd8cb41ff 100644
--- a/docs/get_started/quick_start.rst
+++ b/docs/get_started/quick_start.rst
@@ -250,8 +250,8 @@ Load from C++
 
 The following C++ program loads the CPU build, ``add_one_cpu.so``, and calls
 ``add_one`` through the TVM-FFI C++ API. TIRx kernels require 64-byte aligned
-tensor data for performance, so the program allocates its tensors with
-``std::aligned_alloc``:
+tensor data for performance, so the program uses the runtime tensor allocator
+to provide the required alignment on each platform:
 
 .. literalinclude:: ../../examples/quick_start/load_cpp.cc
    :language: cpp
diff --git a/examples/quick_start/CMakeLists.txt 
b/examples/quick_start/CMakeLists.txt
index d30abcec9..e7ded3280 100644
--- a/examples/quick_start/CMakeLists.txt
+++ b/examples/quick_start/CMakeLists.txt
@@ -40,10 +40,5 @@ find_package(tvm_tirx CONFIG REQUIRED)
 
 # Load add_one_cpu.so from C++ using only the runtime libraries.
 add_executable(load_cpp load_cpp.cc)
-# load_cpp never calls the TIRx runtime directly; keep it linked so that it is
-# loaded at startup and can run the exported module.
-if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
-  target_link_options(load_cpp PRIVATE "LINKER:--no-as-needed")
-endif ()
 target_link_libraries(load_cpp PRIVATE tvm_runtime::shared tvm_ffi::shared)
 set_target_properties(load_cpp PROPERTIES RUNTIME_OUTPUT_DIRECTORY 
"${CMAKE_BINARY_DIR}")
diff --git a/examples/quick_start/README.md b/examples/quick_start/README.md
index 0098147db..f40e9bdd2 100644
--- a/examples/quick_start/README.md
+++ b/examples/quick_start/README.md
@@ -31,7 +31,7 @@ This directory contains all the source code for the
 
 ```bash
 pip install apache-tvm-tirx torch
-bash run_all_cpu.sh        # on Windows: run_all_cpu.bat (Python steps only)
+bash run_all_cpu.sh        # on Windows: run_all_cpu.bat
 
 # needs an NVIDIA GPU with CUDA 13 or newer
 pip install "apache-tvm-tirx[cuda]"
diff --git a/examples/quick_start/load_cpp.cc b/examples/quick_start/load_cpp.cc
index 5ce19ff8f..c187cf664 100644
--- a/examples/quick_start/load_cpp.cc
+++ b/examples/quick_start/load_cpp.cc
@@ -20,26 +20,18 @@
 // [main.begin]
 #include <tvm/ffi/extra/module.h>
 #include <tvm/ffi/tvm_ffi.h>
+#include <tvm/runtime/tensor.h>
 
-#include <cstdlib>
 #include <iostream>
 
 namespace ffi = tvm::ffi;
 
-// TIRx kernels require 64-byte aligned tensor data for performance.
-struct CPUAllocator {
-  void AllocData(DLTensor* tensor) {
-    size_t bytes = (tensor->shape[0] * sizeof(float) + 63) / 64 * 64;
-    tensor->data = std::aligned_alloc(64, bytes);
-  }
-  void FreeData(DLTensor* tensor) { std::free(tensor->data); }
-};
-
 int main() {
   DLDataType f32{kDLFloat, 32, 1};
   DLDevice cpu{kDLCPU, 0};
-  ffi::Tensor a = ffi::Tensor::FromNDAlloc(CPUAllocator(), {10}, f32, cpu);
-  ffi::Tensor b = ffi::Tensor::FromNDAlloc(CPUAllocator(), {10}, f32, cpu);
+  // The runtime allocator provides the alignment required by TIRx kernels.
+  ffi::Tensor a = tvm::runtime::Empty({10}, f32, cpu);
+  ffi::Tensor b = tvm::runtime::Empty({10}, f32, cpu);
   float* a_data = static_cast<float*>(a.data_ptr());
   for (int i = 0; i < 10; ++i) a_data[i] = static_cast<float>(i);
 
diff --git a/examples/quick_start/run_all_cpu.bat 
b/examples/quick_start/run_all_cpu.bat
index 11798399e..9e2c63d61 100644
--- a/examples/quick_start/run_all_cpu.bat
+++ b/examples/quick_start/run_all_cpu.bat
@@ -28,4 +28,11 @@ python load_add_one_cpu.py || exit /b 1
 rem Inspect add_one and specialize it to 128 elements
 python inspect_and_transform.py || exit /b 1
 
+rem Load add_one_cpu.so from C++ using only the runtime libraries.
+cmake . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo 
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO="%CD%\build" || exit /b 1
+cmake --build build --config RelWithDebInfo || exit /b 1
+for /f "delims=" %%d in ('python -m tvm_tirx.config --libdir') do set 
"PATH=%%d;%PATH%"
+for /f "delims=" %%d in ('python -m tvm_ffi.config --libdir') do set 
"PATH=%%d;%PATH%"
+build\load_cpp.exe || exit /b 1
+
 endlocal
diff --git a/python/tvm_tirx/codegen/executable.py 
b/python/tvm_tirx/codegen/executable.py
index ae72fd7fa..918e82777 100644
--- a/python/tvm_tirx/codegen/executable.py
+++ b/python/tvm_tirx/codegen/executable.py
@@ -18,6 +18,7 @@
 
 import json
 import os
+import sys
 from collections.abc import Callable
 from typing import Any
 
@@ -280,6 +281,10 @@ class Executable:
             else:
                 fcompile = _cc.create_shared
 
+        if sys.platform == "win32" and fcompile is _cc.create_shared:
+            # Windows DLLs must resolve generated FFI calls through the import 
library.
+            files.append(tvm_ffi_libinfo.find_windows_implib())
+
         if llvm_target is None and hasattr(fcompile, "get_target_triple"):
             triple = fcompile.get_target_triple()
             assert triple, "Target triple should not be empty"
diff --git a/python/tvm_tirx/support/cc.py b/python/tvm_tirx/support/cc.py
index c3c54fe3d..35497aafc 100644
--- a/python/tvm_tirx/support/cc.py
+++ b/python/tvm_tirx/support/cc.py
@@ -375,7 +375,8 @@ def _linux_compile(
 
 def _windows_compile(output, objects, options, cwd=None, ccache_env=None):
     compiler = os.getenv("TVM_TIRX_WIN_CC", default="clang")
-    win_target = os.getenv("TVM_TIRX_WIN_TARGET", default="x86_64")
+    # Match the MSVC ABI used by native Windows LLVM objects and import 
libraries.
+    win_target = os.getenv("TVM_TIRX_WIN_TARGET", 
default="x86_64-pc-windows-msvc")
     cmd = [compiler]
     cmd += ["-O2"]
     cmd += ["--target=" + win_target]
diff --git a/tests/python/codegen/llvm/test_minimal.py 
b/tests/python/codegen/llvm/test_minimal.py
index 2e7680d60..be5e3a26e 100644
--- a/tests/python/codegen/llvm/test_minimal.py
+++ b/tests/python/codegen/llvm/test_minimal.py
@@ -22,6 +22,7 @@ import pytest
 import tvm_tirx
 import tvm_tirx.testing
 from tvm_tirx.script import tirx as T
+from tvm_tirx.support import cc
 from tvm_tirx.testing import env
 
 
@@ -57,5 +58,31 @@ def test_llvm_add_pipeline():
     tvm_tirx.testing.assert_allclose(c.numpy(), a.numpy() + b.numpy())
 
 
[email protected](not env.has_llvm(), reason="need llvm")
[email protected]("fcompile", [None, cc.create_shared])
+def test_llvm_export_and_reload(tmp_path, fcompile):
+    n = T.dynamic("n")
+
+    @T.function
+    def add_one(A: T.Tensor((n,), "float32"), B: T.Tensor((n,), "float32")):
+        for i in range(n):
+            B[i] = A[i] + 1
+
+    kernel = tvm_tirx.compile(add_one, target="llvm")
+    path = tmp_path / "add_one.so"
+    kernel.export_library(path, fcompile=fcompile)
+    loaded = tvm_tirx.runtime.load_module(str(path))["add_one"]
+    dev = tvm_tirx.cpu(0)
+    a = tvm_tirx.runtime.tensor(np.arange(10, dtype="float32"), dev)
+    b = tvm_tirx.runtime.tensor(np.zeros(10, dtype="float32"), dev)
+    loaded(a, b)
+    tvm_tirx.testing.assert_allclose(b.numpy(), a.numpy() + 1)
+
+    # Exercise the generated error path that calls the FFI library directly.
+    wrong_shape = tvm_tirx.runtime.tensor(np.zeros(11, dtype="float32"), dev)
+    with pytest.raises(ValueError, match="shape"):
+        loaded(a, wrong_shape)
+
+
 if __name__ == "__main__":
     tvm_tirx.testing.main()
diff --git a/examples/quick_start/run_all_cpu.bat 
b/tests/scripts/task_minimal_examples_cpu.bat
similarity index 73%
copy from examples/quick_start/run_all_cpu.bat
copy to tests/scripts/task_minimal_examples_cpu.bat
index 11798399e..1610a220b 100644
--- a/examples/quick_start/run_all_cpu.bat
+++ b/tests/scripts/task_minimal_examples_cpu.bat
@@ -17,15 +17,10 @@ rem specific language governing permissions and limitations
 rem under the License.
 
 setlocal
-cd /d "%~dp0"
 
-rem Write, compile, and run add_one; export it to add_one_cpu.so
-python add_one_cpu.py || exit /b 1
-
-rem Load add_one_cpu.so in a new Python process
-python load_add_one_cpu.py || exit /b 1
-
-rem Inspect add_one and specialize it to 128 elements
-python inspect_and_transform.py || exit /b 1
+rem Keep this explicit list limited to examples that run in a few seconds.
+for %%e in (examples\quick_start) do (
+    uv run --no-sync cmd /c call "%%e\run_all_cpu.bat" || exit /b 1
+)
 
 endlocal
diff --git a/tests/scripts/task_minimal_examples.sh 
b/tests/scripts/task_minimal_examples_cpu.sh
similarity index 85%
copy from tests/scripts/task_minimal_examples.sh
copy to tests/scripts/task_minimal_examples_cpu.sh
index 481d4c774..42c7fa376 100755
--- a/tests/scripts/task_minimal_examples.sh
+++ b/tests/scripts/task_minimal_examples_cpu.sh
@@ -18,13 +18,8 @@
 
 set -euxo pipefail
 
-if [[ $# -ne 1 || ( "$1" != cpu && "$1" != cuda ) ]]; then
-    echo "Usage: $0 cpu|cuda" >&2
-    exit 1
-fi
-
 # Keep this explicit list limited to examples that run in a few seconds.
 examples=(examples/quick_start)
 for example in "${examples[@]}"; do
-    uv run --no-sync bash "${example}/run_all_$1.sh"
+    uv run --no-sync bash "${example}/run_all_cpu.sh"
 done
diff --git a/tests/scripts/task_minimal_examples.sh 
b/tests/scripts/task_minimal_examples_cuda.sh
similarity index 85%
rename from tests/scripts/task_minimal_examples.sh
rename to tests/scripts/task_minimal_examples_cuda.sh
index 481d4c774..0db34cce1 100755
--- a/tests/scripts/task_minimal_examples.sh
+++ b/tests/scripts/task_minimal_examples_cuda.sh
@@ -18,13 +18,8 @@
 
 set -euxo pipefail
 
-if [[ $# -ne 1 || ( "$1" != cpu && "$1" != cuda ) ]]; then
-    echo "Usage: $0 cpu|cuda" >&2
-    exit 1
-fi
-
 # Keep this explicit list limited to examples that run in a few seconds.
 examples=(examples/quick_start)
 for example in "${examples[@]}"; do
-    uv run --no-sync bash "${example}/run_all_$1.sh"
+    uv run --no-sync bash "${example}/run_all_cuda.sh"
 done

Reply via email to