This is an automated email from the ASF dual-hosted git repository.
tqchen 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 de477ccd [REFACTOR][RUST] Link libtvm_tirx_compiler instead of loading
it at run time (#17)
de477ccd is described below
commit de477ccd574e4e97244434e3d23ae7588d7e0177
Author: Linzhang Li <[email protected]>
AuthorDate: Wed Oct 21 17:04:11 2026 -0400
[REFACTOR][RUST] Link libtvm_tirx_compiler instead of loading it at run
time (#17)
# [REFACTOR][RUST] Link libtvm_tirx_compiler instead of loading it at
run time
## Summary
The Rust crate linked only libtvm_ffi and loaded `libtvm_tirx_compiler`
at run time through
`Module::load_from_file`. Every test started with
`common::load_tirx_compiler()`, and a user of
the crate had to load the library and keep the module alive before
touching any binding.
The crate now links `libtvm_tirx_compiler` from its build script, the
way `tvm-ffi-sys` links
libtvm_ffi. The library is loaded when the program starts, its type keys
and global functions are
registered before any Rust code runs, and the run-time loading step is
gone. Before:
```rust
let _compiler =
Module::load_from_file("../build/lib/libtvm_tirx_compiler.so")?;
let target = Target::new("llvm")?;
```
After:
```rust
let target = Target::new("llvm")?;
```
---
AGENTS.md | 11 +--
rust/build.rs | 81 ++++++++++++++++++----
rust/src/lib.rs | 53 +++++++++++---
rust/tests/codegen/llvm.rs | 3 -
rust/tests/codegen/main.rs | 3 +-
rust/tests/common/mod.rs | 23 +-----
rust/tests/ir/expr.rs | 4 +-
rust/tests/ir/function.rs | 3 +-
rust/tests/ir/location.rs | 3 +-
rust/tests/ir/module.rs | 3 +-
rust/tests/ir/op.rs | 3 +-
rust/tests/ir/prim.rs | 3 +-
rust/tests/ir/prim/expr.rs | 3 +-
rust/tests/ir/prim/op.rs | 6 +-
rust/tests/ir/prim/vector_expr.rs | 3 +-
rust/tests/ir/stmt.rs | 3 +-
rust/tests/ir/transform/core.rs | 4 +-
rust/tests/ir/transform/instrument.rs | 4 +-
rust/tests/ir/type.rs | 3 +-
rust/tests/ir/unique_name_supply.rs | 3 +-
rust/tests/runtime/main.rs | 7 --
rust/tests/script/main.rs | 3 +-
rust/tests/sym/analyzer.rs | 5 +-
rust/tests/sym/int_set.rs | 5 +-
rust/tests/sym/iter_affine_map.rs | 4 +-
rust/tests/sym/main.rs | 3 +-
rust/tests/target/main.rs | 8 +--
rust/tests/tirx/analysis/analysis.rs | 4 +-
rust/tests/tirx/function.rs | 3 +-
rust/tests/tirx/index_map.rs | 3 +-
rust/tests/tirx/layout.rs | 5 +-
rust/tests/tirx/op.rs | 3 +-
rust/tests/tirx/tensor.rs | 3 +-
rust/tests/tirx/thread_scope.rs | 3 +-
rust/tests/tirx/tile/dispatch.rs | 3 +-
rust/tests/tirx/tile/instruction.rs | 4 +-
rust/tests/tirx/transform/function_pass.rs | 3 +-
rust/tests/tirx/transform/transform.rs | 4 +-
.../tests/codegen/main.rs => src/ir/link_anchor.cc | 32 ++++-----
.../codegen/main.rs => src/runtime/link_anchor.cc | 32 ++++-----
40 files changed, 175 insertions(+), 184 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index f79d0c70..62db434d 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -123,12 +123,15 @@ describe missing coverage; they do not demonstrate that a
backend works.
`rust/` is a standalone crate (`tvm-tirx`) over `3rdparty/tvm-ffi/rust`. Its
IR bindings are generated by `tvm-ffi-stubgen` between `tvm-ffi-stubgen(begin)`
-and `(end)` markers. Build TIRx first; the tests load
-`build/lib/libtvm_tirx_compiler.so` and need `tvm-ffi-config` on `PATH`:
+and `(end)` markers. The crate links `libtvm_tirx_compiler` from the directory
+`tvm-tirx-config --libdir` prints, so build TIRx first. Its build script needs
+`tvm-ffi-config` and `tvm-tirx-config` on `PATH`, which `uv run` provides after
+the editable install:
```bash
-tvm-ffi-stubgen rust/src --target rust --dlls
build/lib/libtvm_tirx_compiler.so --check
-(cd rust && cargo fmt --check && cargo test)
+uv run --no-sync tvm-ffi-stubgen rust/src --target rust --dlls
build/lib/libtvm_tirx_compiler.so --check
+uv run --no-sync cargo fmt --check --manifest-path rust/Cargo.toml
+uv run --no-sync cargo test --manifest-path rust/Cargo.toml
```
## Linting
diff --git a/rust/build.rs b/rust/build.rs
index 2caa6072..c062967e 100644
--- a/rust/build.rs
+++ b/rust/build.rs
@@ -16,30 +16,81 @@
* specific language governing permissions and limitations
* under the License.
*/
-//! `tvm-ffi-sys`'s build script links libtvm_ffi, but the loader-path
-//! environment it emits only applies to its own package; re-emit it here so a
-//! plain `cargo test` finds libtvm_ffi at startup.
+//! Links `libtvm_tirx_compiler` from the directory `tvm-tirx-config --libdir`
prints, as
+//! `tvm-ffi-sys` links libtvm_ffi from the one `tvm-ffi-config --libdir`
prints. The loader-path
+//! environment `tvm-ffi-sys` emits only applies to its own package, so this
script emits it again
+//! for both directories, so that a plain `cargo test` finds the libraries at
startup.
use std::env;
+use std::path::Path;
use std::process::Command;
+/// The library directory a configuration helper prints for `--libdir`.
+fn lib_dir(config: &str) -> String {
+ let output =
Command::new(config).arg("--libdir").output().unwrap_or_else(|err| {
+ panic!("could not run `{config}`: {err}; put the directory of
`{config}` on PATH")
+ });
+ assert!(
+ output.status.success(),
+ "`{config} --libdir` failed ({}): {}",
+ output.status,
+ String::from_utf8_lossy(&output.stderr).trim()
+ );
+ let lib_dir = String::from_utf8(output.stdout).unwrap().trim().to_string();
+ assert!(!lib_dir.is_empty(), "`{config} --libdir` printed no library
directory");
+ lib_dir
+}
+
+/// Checks that `lib_dir` holds the file the linker looks for under
`-ltvm_tirx_compiler`.
+///
+/// `tvm-tirx-config --libdir` falls back to `<prefix>/lib` when no directory
it knows holds the
+/// libraries, as before the first build. Failing here rather than in the link
step makes cargo
+/// run the script again on the next build, instead of keeping a search path
that has no library.
+fn check_compiler_library(lib_dir: &str, target_os: &str) {
+ let names: &[&str] = match target_os {
+ "windows" => &["tvm_tirx_compiler.lib", "libtvm_tirx_compiler.dll.a"],
+ "macos" | "ios" => &["libtvm_tirx_compiler.dylib"],
+ _ => &["libtvm_tirx_compiler.so"],
+ };
+ let dir = Path::new(lib_dir);
+ assert!(
+ names.iter().any(|name| dir.join(name).is_file()),
+ "`tvm-tirx-config --libdir` printed {lib_dir}, which holds no {}:
build TIRx first \
+ (`uv pip install -e .`), or set TVM_TIRX_LIBRARY_PATH to the
directory of the library",
+ names.join(" or ")
+ );
+}
+
fn main() {
println!("cargo:rerun-if-env-changed=PATH");
+ // `tvm-tirx-config` puts this directory first when it is set.
+ println!("cargo:rerun-if-env-changed=TVM_TIRX_LIBRARY_PATH");
println!("cargo:rerun-if-changed=build.rs");
- let output = Command::new("tvm-ffi-config")
- .arg("--libdir")
- .output()
- .expect("failed to run tvm-ffi-config; put the tvm_ffi package's bin
directory on PATH");
- assert!(output.status.success(), "tvm-ffi-config --libdir failed");
- let lib_dir = String::from_utf8(output.stdout).unwrap().trim().to_string();
+ let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
+ let ffi_lib_dir = lib_dir("tvm-ffi-config");
+ let tirx_lib_dir = lib_dir("tvm-tirx-config");
+ check_compiler_library(&tirx_lib_dir, &target_os);
+
+ // The crate references the library only through its link anchor (see
`src/lib.rs`).
+ println!("cargo:rustc-link-search=native={tirx_lib_dir}");
+ println!("cargo:rustc-link-lib=dylib=tvm_tirx_compiler");
- let loader_var = match env::var("CARGO_CFG_TARGET_OS").as_deref() {
- Ok("windows") => "PATH",
- Ok("macos") => "DYLD_LIBRARY_PATH",
+ let loader_var = match target_os.as_str() {
+ "windows" => "PATH",
+ "macos" => "DYLD_LIBRARY_PATH",
_ => "LD_LIBRARY_PATH",
};
+ // The value emitted below starts with the variable's value in this
script's environment, so
+ // the script must run again when that changes; on Windows the variable is
PATH, declared above.
+ if loader_var != "PATH" {
+ println!("cargo:rerun-if-env-changed={loader_var}");
+ }
let sep = if loader_var == "PATH" { ";" } else { ":" };
- let prev = env::var(loader_var).unwrap_or_default();
- let val = if prev.is_empty() { lib_dir } else {
format!("{prev}{sep}{lib_dir}") };
- println!("cargo:rustc-env={loader_var}={val}");
+ let mut dirs = vec![ffi_lib_dir, tirx_lib_dir];
+ if let Ok(prev) = env::var(loader_var) {
+ if !prev.is_empty() {
+ dirs.insert(0, prev);
+ }
+ }
+ println!("cargo:rustc-env={loader_var}={}", dirs.join(sep));
}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index cf2e636b..96a6e245 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -36,17 +36,25 @@
//!
//! # Using the bindings
//!
-//! Load `libtvm_tirx_compiler` before using these types, so that their type
keys are registered,
-//! and keep the module alive while its objects are in use. The native global
functions have Rust
-//! wrappers, as methods of the handle types and as functions of the modules,
such as
-//! [`target::Target::new`] for `target.Target`. Native functions that have no
Rust wrapper are
-//! called through [`tvm_ffi::Function::get_global`]. From `rust/` on Linux:
+//! The crate links `libtvm_tirx_compiler`, so its type keys and global
functions are registered
+//! when a program starts. The build script finds the library through
`tvm-tirx-config --libdir`,
+//! as `tvm-ffi-sys` finds libtvm_ffi through `tvm-ffi-config --libdir`: both
helpers come with
+//! their Python packages (`apache-tvm-tirx` and `apache-tvm-ffi`) and must be
on `PATH` when the
+//! crate is built. The native global functions have Rust wrappers, as methods
of the handle types
+//! and as functions of the modules, such as [`target::Target::new`] for
`target.Target`. Native
+//! functions that have no Rust wrapper are called through
[`tvm_ffi::Function::get_global`].
+//!
+//! The crate uses the library only through the TVM FFI registry, so a linker
that drops
+//! unreferenced libraries (`--as-needed`, which rustc passes on Linux) keeps
it only because
+//! the crate holds a reference to a symbol of it, the link anchor, that is
linked along with the
+//! crate. A program that calls at least one wrapper therefore has the library
as a dependency,
+//! at no run-time cost. A program that reaches the registry only through
`tvm_ffi` itself,
+//! without calling a wrapper, must keep the library by other means, such as
the linker
+//! arguments `tvm-tirx-config --libs compiler` prints.
//!
//! ```no_run
//! use tvm_tirx::target::Target;
-//! use tvm_tirx::tvm_ffi::Module;
//!
-//! let _compiler =
Module::load_from_file("../build/lib/libtvm_tirx_compiler.so")?;
//! let target = Target::new("llvm")?;
//! assert_eq!(target.kind()?.name()?.as_str(), "llvm");
//! # Ok::<(), tvm_tirx::tvm_ffi::Error>(())
@@ -98,15 +106,16 @@
//!
//! # Tests
//!
-//! Build `libtvm_tirx_compiler` first. The build scripts need
`tvm-ffi-config` on `PATH`, which
-//! `uv run` provides from the `.venv`:
+//! Build `libtvm_tirx_compiler` first. The build scripts need
`tvm-ffi-config` and
+//! `tvm-tirx-config` on `PATH`, which `uv run` provides from the `.venv`
after the editable
+//! install, where `tvm-tirx-config --libdir` is `build/lib`:
//!
//! ```bash
//! uv run --no-sync cargo test --manifest-path rust/Cargo.toml
//! ```
//!
-//! The tests load `build/lib/libtvm_tirx_compiler.so`; set
`TVM_TIRX_COMPILER_LIBRARY` to load
-//! another library.
+//! Set `TVM_TIRX_LIBRARY_PATH` to the directory of another
`libtvm_tirx_compiler` to build and
+//! test against that one; `tvm-tirx-config` puts it first.
//!
//! The tests are laid out like the modules. Each top-level module is one test
binary,
//! `tests/<module>/main.rs`, and the tests of `src/<path>.rs` are in
`tests/<path>.rs`:
@@ -114,6 +123,28 @@
//! tests of one module with `--test <module>`, such as `--test tirx`.
`tests/common/` holds the
//! helpers the binaries share.
+// The crate reaches `libtvm_tirx_compiler` through the FFI registry, so a
linker that drops
+// unreferenced libraries (`--as-needed`) would drop the library the build
script links, and its
+// registrations would never run. Each TIRx shared library exports a
`<library>_link_anchor`
+// function that does nothing, defined in the `link_anchor.cc` of its sources
(for the compiler,
+// `src/ir/link_anchor.cc`) and declared by whoever references it. The static
below holds the
+// anchor's address: a relocation against the symbol in the object of this
module, which costs
+// nothing at run time and is what makes the linker keep the library.
+//
+// A program pulls in only the objects of the crate it references, so the
static keeps the
+// library only when the object of this module is pulled. It is, because the
objects of the crate
+// reference one another densely and `sym::analyzer` references
`ExitOnDrop::new` below. The test
+// binaries rely on the same mechanism and fail at their first registry lookup
if that changes. A
+// program that uses the registry only through `tvm_ffi` itself, without
calling a wrapper, must
+// keep the library by other means, such as the linker arguments
`tvm-tirx-config --libs compiler`
+// prints.
+extern "C" {
+ fn tvm_tirx_compiler_link_anchor() -> i32;
+}
+
+#[used]
+static TVM_TIRX_COMPILER_LINK_ANCHOR: unsafe extern "C" fn() -> i32 =
tvm_tirx_compiler_link_anchor;
+
/// Makes a scope guard neither `Send` nor `Sync`: the native scopes keep
their state per thread,
/// or in an object that is not synchronized, so a scope must end on the
thread that opened it.
pub(crate) type ThreadBound = std::marker::PhantomData<*const ()>;
diff --git a/rust/tests/codegen/llvm.rs b/rust/tests/codegen/llvm.rs
index dec2c74d..e74843e6 100644
--- a/rust/tests/codegen/llvm.rs
+++ b/rust/tests/codegen/llvm.rs
@@ -22,11 +22,8 @@
use tvm_tirx::codegen::{self, llvm};
use tvm_tirx::target::Target;
-use crate::common::load_tirx_compiler;
-
#[test]
fn llvm_queries() {
- load_tirx_compiler();
assert!(llvm::version_major().unwrap() >= 10);
let sqrt = llvm::lookup_intrinsic_id("llvm.sqrt").unwrap();
assert!(sqrt > 0);
diff --git a/rust/tests/codegen/main.rs b/rust/tests/codegen/main.rs
index aebe9c0d..86856c24 100644
--- a/rust/tests/codegen/main.rs
+++ b/rust/tests/codegen/main.rs
@@ -28,11 +28,10 @@ mod llvm;
use tvm_tirx::codegen;
use tvm_tirx::target::Target;
-use common::{empty_module, load_tirx_compiler};
+use common::empty_module;
#[test]
fn build_module() {
- load_tirx_compiler();
let module = empty_module();
codegen::build_module(&module, Target::new("llvm").unwrap()).unwrap();
codegen::build_module(&module, Target::new("c").unwrap()).unwrap();
diff --git a/rust/tests/common/mod.rs b/rust/tests/common/mod.rs
index cd7bab2b..aa2f2cf8 100644
--- a/rust/tests/common/mod.rs
+++ b/rust/tests/common/mod.rs
@@ -22,30 +22,11 @@
#![allow(dead_code)]
use std::mem::size_of;
-use std::path::PathBuf;
-use std::sync::{Mutex, MutexGuard, OnceLock};
+use std::sync::{Mutex, MutexGuard};
use tvm_tirx::ir::{BaseFunc, GlobalInfo, GlobalVar, IRModule};
use tvm_tirx::tvm_ffi::tvm_ffi_sys::{TVMFFIGetTypeInfo, TVMFFITypeInfo};
-use tvm_tirx::tvm_ffi::{
- AnyCompatible, AnyView, Array, Function, Map, Module, ObjectCore, String
as FfiString,
-};
-
-static TIRX_COMPILER: OnceLock<Module> = OnceLock::new();
-
-/// Load `libtvm_tirx_compiler` so its type keys are in the FFI type registry.
-pub fn load_tirx_compiler() {
- TIRX_COMPILER.get_or_init(|| {
- let default = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
- .join("..")
- .join("build")
- .join("lib")
- .join("libtvm_tirx_compiler.so");
- let library =
-
std::env::var_os("TVM_TIRX_COMPILER_LIBRARY").map(PathBuf::from).unwrap_or(default);
- Module::load_from_file(library.to_string_lossy()).unwrap()
- });
-}
+use tvm_tirx::tvm_ffi::{AnyCompatible, AnyView, Array, Function, Map,
ObjectCore, String as FfiString};
/// Run the tests of a binary one at a time: registering an operator, a memory
scope or the layout
/// axes of a backend grows a native registry, which other threads must not
read meanwhile, and
diff --git a/rust/tests/ir/expr.rs b/rust/tests/ir/expr.rs
index 463d7c24..6d63613d 100644
--- a/rust/tests/ir/expr.rs
+++ b/rust/tests/ir/expr.rs
@@ -23,11 +23,10 @@ use tvm_tirx::ir::*;
use tvm_tirx::tvm_ffi::Any;
use super::{dtype, int32, int32_var, loc, op, tensor_var};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn expressions() {
- load_tirx_compiler();
let _serial = serial();
let x = int32_var("x");
assert_eq!(x.name.as_str(), "x");
@@ -70,7 +69,6 @@ fn expressions() {
#[test]
fn ranges() {
- load_tirx_compiler();
let _serial = serial();
let range = Range::new(int32(8), None, loc()).unwrap();
assert!(structural_equal(&range.extent, &int32(8)));
diff --git a/rust/tests/ir/function.rs b/rust/tests/ir/function.rs
index 484031d1..9a9be894 100644
--- a/rust/tests/ir/function.rs
+++ b/rust/tests/ir/function.rs
@@ -22,11 +22,10 @@
use tvm_tirx::tvm_ffi::{Any, Map, String as FfiString};
use super::{function, int32};
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
#[test]
fn function_attrs() {
- load_tirx_compiler();
let _serial = serial();
let func = function(0);
let copy = func.copy().unwrap();
diff --git a/rust/tests/ir/location.rs b/rust/tests/ir/location.rs
index 5337839b..8dc49db9 100644
--- a/rust/tests/ir/location.rs
+++ b/rust/tests/ir/location.rs
@@ -21,11 +21,10 @@
use tvm_tirx::ir::SourceName;
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn source_names() {
- load_tirx_compiler();
let _serial = serial();
let name = SourceName::get("main.py").unwrap();
assert_eq!(name.name.as_str(), "main.py");
diff --git a/rust/tests/ir/module.rs b/rust/tests/ir/module.rs
index 23bf1002..8c00b325 100644
--- a/rust/tests/ir/module.rs
+++ b/rust/tests/ir/module.rs
@@ -23,11 +23,10 @@ use tvm_tirx::ir::{BaseFunc, Expr, GlobalInfo, GlobalVar,
IRModule};
use tvm_tirx::tvm_ffi::{Any, Map, String as FfiString};
use super::{function, int32, loc};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn modules() {
- load_tirx_compiler();
let _serial = serial();
let func = function(0);
let main = GlobalVar::new("main", loc()).unwrap();
diff --git a/rust/tests/ir/op.rs b/rust/tests/ir/op.rs
index c0cb139e..32d5de4c 100644
--- a/rust/tests/ir/op.rs
+++ b/rust/tests/ir/op.rs
@@ -21,11 +21,10 @@
use tvm_tirx::ir::Op;
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
#[test]
fn ops() {
- load_tirx_compiler();
let _serial = serial();
let op_names = Op::list_op_names().unwrap();
assert!(op_names.iter().any(|name| name.as_str() == "prim.exp"));
diff --git a/rust/tests/ir/prim.rs b/rust/tests/ir/prim.rs
index e57ec544..d9d5bed9 100644
--- a/rust/tests/ir/prim.rs
+++ b/rust/tests/ir/prim.rs
@@ -29,7 +29,7 @@ use tvm_tirx::ir::{Expr, FloatImm, IntImm, PrimType, Var};
use tvm_tirx::tvm_ffi::{BigInt, DLDataType, DLDataTypeExt, ObjectRefCast,
String as FfiString};
use super::loc;
-use crate::common::{global, load_tirx_compiler, serial};
+use crate::common::{global, serial};
fn ty(dtype: &str) -> PrimType {
PrimType::from_dtype(DLDataType::try_from_str(dtype).unwrap()).unwrap()
@@ -73,7 +73,6 @@ fn int_value(expr: Expr) -> i64 {
#[test]
fn expr_deep_equal() {
- load_tirx_compiler();
let _serial = serial();
let x = var("x", "int32");
let a = prim::op::add(&x, int("int32", 1), loc()).unwrap();
diff --git a/rust/tests/ir/prim/expr.rs b/rust/tests/ir/prim/expr.rs
index 0a300126..9b0f91ae 100644
--- a/rust/tests/ir/prim/expr.rs
+++ b/rust/tests/ir/prim/expr.rs
@@ -23,12 +23,11 @@ use tvm_tirx::ir::prim;
use tvm_tirx::ir::Expr;
use super::{dtype, float, int, ty, var};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
use crate::loc;
#[test]
fn node_constructors() {
- load_tirx_compiler();
let _serial = serial();
let (x, y) = (var("x", "int32"), var("y", "int32"));
let (p, q) = (var("p", "bool"), var("q", "bool"));
diff --git a/rust/tests/ir/prim/op.rs b/rust/tests/ir/prim/op.rs
index 3c3b0aa7..c43d14f3 100644
--- a/rust/tests/ir/prim/op.rs
+++ b/rust/tests/ir/prim/op.rs
@@ -24,12 +24,11 @@ use tvm_tirx::ir::{Expr, FloatImm};
use tvm_tirx::tvm_ffi::ObjectRefCast;
use super::{dtype, float, int, int_value, ty, var};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
use crate::loc;
#[test]
fn arithmetic_operators() {
- load_tirx_compiler();
let _serial = serial();
let x = var("x", "int32");
@@ -73,7 +72,6 @@ fn arithmetic_operators() {
#[test]
fn comparison_and_logic_operators() {
- load_tirx_compiler();
let _serial = serial();
let x = var("x", "int32");
let one = int("int32", 1);
@@ -96,7 +94,6 @@ fn comparison_and_logic_operators() {
#[test]
fn casts_and_conversions() {
- load_tirx_compiler();
let _serial = serial();
let x = var("x", "int32");
assert_eq!(dtype(&op::cast(&x, ty("float16"), loc()).unwrap()), "float16");
@@ -107,7 +104,6 @@ fn casts_and_conversions() {
#[test]
fn math_operators() {
- load_tirx_compiler();
let _serial = serial();
let f = var("f", "float32");
for unary in [op::ceil, op::floor, op::round, op::nearbyint, op::trunc] {
diff --git a/rust/tests/ir/prim/vector_expr.rs
b/rust/tests/ir/prim/vector_expr.rs
index 514098dc..663e0c67 100644
--- a/rust/tests/ir/prim/vector_expr.rs
+++ b/rust/tests/ir/prim/vector_expr.rs
@@ -23,12 +23,11 @@ use tvm_tirx::ir::prim;
use tvm_tirx::ir::Expr;
use super::{dtype, int, var};
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
use crate::loc;
#[test]
fn vector_constructors() {
- load_tirx_compiler();
let _serial = serial();
let x = var("x", "int32");
let ramp = prim::Ramp::new(&x, int("int32", 1), int("int32", 4),
loc()).unwrap();
diff --git a/rust/tests/ir/stmt.rs b/rust/tests/ir/stmt.rs
index 40419334..d4463fe3 100644
--- a/rust/tests/ir/stmt.rs
+++ b/rust/tests/ir/stmt.rs
@@ -23,11 +23,10 @@ use tvm_tirx::ir::*;
use tvm_tirx::tvm_ffi::{Any, Map, String as FfiString};
use super::{dtype, int32, int32_var, loc, op, seq, tensor_var};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn statements() {
- load_tirx_compiler();
let _serial = serial();
let x = int32_var("x");
let y = int32_var("y");
diff --git a/rust/tests/ir/transform/core.rs b/rust/tests/ir/transform/core.rs
index a7f726fb..d4aa982a 100644
--- a/rust/tests/ir/transform/core.rs
+++ b/rust/tests/ir/transform/core.rs
@@ -23,11 +23,10 @@ use tvm_tirx::ir::transform::*;
use tvm_tirx::tvm_ffi::{Any, Map, String as FfiString};
use super::{logging_pass, no_instruments, Log};
-use crate::common::{empty_module, load_tirx_compiler, serial};
+use crate::common::{empty_module, serial};
#[test]
fn pass_context_scope() {
- load_tirx_compiler();
let _serial = serial();
let default_level = PassContext::current().unwrap().opt_level;
let ctx = PassContext::create(3, ["a"], ["b"], no_instruments(),
None).unwrap();
@@ -53,7 +52,6 @@ fn pass_context_scope() {
#[test]
fn module_and_sequential_passes() {
- load_tirx_compiler();
let _serial = serial();
let log = Log::default();
let first = logging_pass("first", &log);
diff --git a/rust/tests/ir/transform/instrument.rs
b/rust/tests/ir/transform/instrument.rs
index e613e3ad..986810e9 100644
--- a/rust/tests/ir/transform/instrument.rs
+++ b/rust/tests/ir/transform/instrument.rs
@@ -23,11 +23,10 @@ use tvm_tirx::ir::transform::*;
use tvm_tirx::ir::IRModule;
use super::{logging_pass, Log};
-use crate::common::{empty_module, load_tirx_compiler, serial};
+use crate::common::{empty_module, serial};
#[test]
fn instruments() {
- load_tirx_compiler();
let _serial = serial();
let log = Log::default();
let hook = |log: &Log, entry: &'static str| {
@@ -76,7 +75,6 @@ fn instruments() {
#[test]
fn pass_timing() {
- load_tirx_compiler();
let _serial = serial();
let log = Log::default();
let timing = pass_timing_instrument().unwrap();
diff --git a/rust/tests/ir/type.rs b/rust/tests/ir/type.rs
index bb9a10c1..f67da64e 100644
--- a/rust/tests/ir/type.rs
+++ b/rust/tests/ir/type.rs
@@ -22,11 +22,10 @@
use tvm_tirx::ir::{FuncType, MissingType, NoneType, PrimType, PtrType,
TensorRegionType, TupleType};
use super::{dtype, loc, scope};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn types() {
- load_tirx_compiler();
let _serial = serial();
MissingType::new().unwrap();
NoneType::instance().unwrap();
diff --git a/rust/tests/ir/unique_name_supply.rs
b/rust/tests/ir/unique_name_supply.rs
index 39d53df2..8c23cf0f 100644
--- a/rust/tests/ir/unique_name_supply.rs
+++ b/rust/tests/ir/unique_name_supply.rs
@@ -21,11 +21,10 @@
use tvm_tirx::ir::UniqueNameSupply;
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
#[test]
fn unique_names() {
- load_tirx_compiler();
let _serial = serial();
let names = UniqueNameSupply::new("p").unwrap();
let fresh = names.fresh_name("x", true, true).unwrap();
diff --git a/rust/tests/runtime/main.rs b/rust/tests/runtime/main.rs
index 2c5751a6..b7496e4f 100644
--- a/rust/tests/runtime/main.rs
+++ b/rust/tests/runtime/main.rs
@@ -26,11 +26,8 @@ mod common;
use tvm_tirx::runtime::{self, MemoryScope};
use tvm_tirx::tvm_ffi::{DLDataType, DLDataTypeExt, DLDevice, DLDeviceType,
Module, TypeIndex};
-use common::load_tirx_compiler;
-
#[test]
fn tensors() {
- load_tirx_compiler();
let cpu = DLDevice::new(DLDeviceType::kDLCPU, 0);
let float32 = DLDataType::try_from_str("float32").unwrap();
let tensor = runtime::empty(&[2, 8], float32, cpu, None).unwrap();
@@ -44,7 +41,6 @@ fn tensors() {
#[test]
fn memory_scopes() {
- load_tirx_compiler();
let scope = MemoryScope::register("rust_test.scratch").unwrap();
let again = MemoryScope::register("rust_test.scratch");
assert!(again.is_err());
@@ -56,14 +52,12 @@ fn memory_scopes() {
#[test]
fn queries() {
- load_tirx_compiler();
assert!(runtime::enabled("cpu").unwrap());
assert!(runtime::num_threads().unwrap() >= 1);
}
#[test]
fn device_attrs() {
- load_tirx_compiler();
let cpu = DLDevice::new(DLDeviceType::kDLCPU, 0);
let exist = runtime::get_device_attr(cpu, "exist").unwrap();
assert!(bool::try_from(exist).unwrap());
@@ -73,7 +67,6 @@ fn device_attrs() {
#[test]
fn cuda_queries() {
- load_tirx_compiler();
// The CUDA queries are in the CUDA runtime library, which the build may
have.
let cuda_runtime = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../build/lib/libtvm_runtime_cuda.so");
diff --git a/rust/tests/script/main.rs b/rust/tests/script/main.rs
index 4ff85d89..44b63f88 100644
--- a/rust/tests/script/main.rs
+++ b/rust/tests/script/main.rs
@@ -25,11 +25,10 @@ mod common;
use tvm_tirx::script;
-use common::{empty_module, load_tirx_compiler};
+use common::empty_module;
#[test]
fn print_module() {
- load_tirx_compiler();
let text = script::script(&empty_module()).unwrap();
assert!(text.as_str().contains("class Module"), "{}", text.as_str());
}
diff --git a/rust/tests/sym/analyzer.rs b/rust/tests/sym/analyzer.rs
index 03abb2ea..b9974a82 100644
--- a/rust/tests/sym/analyzer.rs
+++ b/rust/tests/sym/analyzer.rs
@@ -24,11 +24,10 @@ use tvm_tirx::sym::*;
use tvm_tirx::tvm_ffi::Object;
use super::{fixture, int32, op, range, var, Fixture};
-use crate::common::{assert_type_contracts, global, load_tirx_compiler};
+use crate::common::{assert_type_contracts, global};
#[test]
fn generated_types_match_the_registry() {
- load_tirx_compiler();
assert_type_contracts!(true;
ConstIntBoundObj: Object, ModularSetObj: Object,
RewriteSimplifierStatsObj: Object,
);
@@ -86,7 +85,6 @@ fn rust_allocated_bounds_reach_the_native_analyzer() {
#[test]
fn bounds_and_simplification() {
- load_tirx_compiler();
let analyzer = Analyzer::new().unwrap();
let x = var("x");
analyzer.bind_range(&x, &range(0, 16), false).unwrap();
@@ -113,7 +111,6 @@ fn bounds_and_simplification() {
#[test]
fn scopes_end_on_drop() {
- load_tirx_compiler();
let analyzer = Analyzer::new().unwrap();
let x = var("x");
let x_mod_3 = op("prim._OpFloorMod", &x, int32(3));
diff --git a/rust/tests/sym/int_set.rs b/rust/tests/sym/int_set.rs
index 5c85449e..a8ee5efc 100644
--- a/rust/tests/sym/int_set.rs
+++ b/rust/tests/sym/int_set.rs
@@ -24,11 +24,10 @@ use tvm_tirx::sym::*;
use tvm_tirx::tvm_ffi::{Map, Object, ObjectRefCast};
use super::{fixture, imm, int32, loc, op, range, var, Fixture};
-use crate::common::{assert_type_contracts, global, load_tirx_compiler};
+use crate::common::{assert_type_contracts, global};
#[test]
fn generated_types_match_the_registry() {
- load_tirx_compiler();
// `sym.IntSet` registers no layout of its own, so its subclasses are
opaque too.
assert_type_contracts!(false; IntSetObj: Object, IntervalSetObj:
IntSetObj);
}
@@ -56,7 +55,6 @@ fn interval_sets_are_read_through_accessors() {
#[test]
fn int_sets() {
- load_tirx_compiler();
let analyzer = Analyzer::new().unwrap();
let interval = IntervalSet::new(int32(0), int32(10)).unwrap();
assert!(analyzer.can_prove_equal(interval.min_value().unwrap(),
int32(0)).unwrap());
@@ -94,7 +92,6 @@ fn int_sets() {
#[test]
fn region_bounds() {
- load_tirx_compiler();
let x = var("x");
let var_dom = Map::from_iter([(x.clone(), range(0, 16))]);
let region = [Range::from_complete_fields(x.clone().into(), int32(1),
loc())];
diff --git a/rust/tests/sym/iter_affine_map.rs
b/rust/tests/sym/iter_affine_map.rs
index b92c0bc0..9128bc66 100644
--- a/rust/tests/sym/iter_affine_map.rs
+++ b/rust/tests/sym/iter_affine_map.rs
@@ -24,11 +24,10 @@ use tvm_tirx::sym::*;
use tvm_tirx::tvm_ffi::{Array, Map, Object, ObjectIdentity, ObjectRefCast};
use super::{fixture, imm, int32, op, range, var, Fixture};
-use crate::common::{assert_type_contracts, global, load_tirx_compiler};
+use crate::common::{assert_type_contracts, global};
#[test]
fn generated_types_match_the_registry() {
- load_tirx_compiler();
assert_type_contracts!(true; IterMapResultObj: Object, IterMarkObj:
Object);
// The expression hierarchy registers no layout of its own, so the
iterator expressions are
// opaque.
@@ -89,7 +88,6 @@ fn iter_maps_decompose_into_marks_and_splits() {
#[test]
fn iter_maps() {
- load_tirx_compiler();
let analyzer = Analyzer::new().unwrap();
let (x, y) = (var("x"), var("y"));
let dom = Map::from_iter([(x.clone(), range(0, 4)), (y.clone(), range(0,
4))]);
diff --git a/rust/tests/sym/main.rs b/rust/tests/sym/main.rs
index 9cf793a2..a20141d0 100644
--- a/rust/tests/sym/main.rs
+++ b/rust/tests/sym/main.rs
@@ -31,7 +31,7 @@ use tvm_tirx::ir::{Expr, IntImm, Location, PrimType, Range,
Var};
use tvm_tirx::sym::Analyzer;
use tvm_tirx::tvm_ffi::{BigInt, DLDataType, DLDataTypeExt, String as
FfiString};
-use common::{global, load_tirx_compiler};
+use common::global;
fn loc() -> Location {
global("ir.UnknownLoc").call_packed(&[]).unwrap().try_into().unwrap()
@@ -79,7 +79,6 @@ struct Fixture {
/// An analyzer with `x` bound to `[0, 16)`, through the native functions only.
fn fixture() -> Fixture {
- load_tirx_compiler();
let x = var("x");
// A typed `Analyzer` handle goes through `call_tuple` like any other
object.
let analyzer: Analyzer =
global("sym.Analyzer").call_tuple(()).unwrap().try_into().unwrap();
diff --git a/rust/tests/target/main.rs b/rust/tests/target/main.rs
index 01f390e2..d1ca39ec 100644
--- a/rust/tests/target/main.rs
+++ b/rust/tests/target/main.rs
@@ -26,7 +26,7 @@ mod common;
use tvm_tirx::target::{self, Target, TargetKind, TargetKindObj, TargetObj};
use tvm_tirx::tvm_ffi::{Any, Map, Object, ObjectRefCast, String as FfiString,
TypeIndex};
-use common::{assert_type_contracts, empty_module, global, load_tirx_compiler};
+use common::{assert_type_contracts, empty_module, global};
fn config(kind: &str) -> Map<FfiString, Any> {
Map::from_iter([(FfiString::from("kind"),
Any::from(FfiString::from(kind)))])
@@ -39,14 +39,12 @@ fn native_target(name: &str) -> Target {
#[test]
fn generated_types_match_the_registry() {
- load_tirx_compiler();
// Both hold members reflection does not describe, so both bindings are
opaque.
assert_type_contracts!(false; TargetObj: Object, TargetKindObj: Object);
}
#[test]
fn native_targets_are_read_through_accessors() {
- load_tirx_compiler();
let llvm = native_target("llvm");
let kind: TargetKind = llvm.kind().unwrap();
assert_eq!(kind.name().unwrap().as_str(), "llvm");
@@ -79,7 +77,6 @@ fn native_targets_are_read_through_accessors() {
#[test]
fn construction_and_queries() {
- load_tirx_compiler();
let llvm = Target::new("llvm").unwrap();
assert_eq!(llvm.kind().unwrap().name().unwrap().as_str(), "llvm");
assert_eq!(llvm.get_target_device_type().unwrap(), 1);
@@ -104,7 +101,6 @@ fn construction_and_queries() {
#[test]
fn scope_ends_on_drop() {
- load_tirx_compiler();
assert!(Target::current(true).unwrap().is_none());
assert!(Target::current(false).is_err());
{
@@ -117,7 +113,6 @@ fn scope_ends_on_drop() {
#[test]
fn tags() {
- load_tirx_compiler();
let tagged = target::register_tag("rust-test/llvm", &config("llvm"),
true).unwrap();
assert_eq!(tagged.kind().unwrap().name().unwrap().as_str(), "llvm");
let tags = target::list_tags().unwrap();
@@ -127,7 +122,6 @@ fn tags() {
#[test]
fn build_by_kind() {
- load_tirx_compiler();
let c = Target::new("c").unwrap();
target::build("c", empty_module(), &c).unwrap();
target::build("llvm", empty_module(),
Target::new("llvm").unwrap()).unwrap();
diff --git a/rust/tests/tirx/analysis/analysis.rs
b/rust/tests/tirx/analysis/analysis.rs
index b3c06a27..30ab5dae 100644
--- a/rust/tests/tirx/analysis/analysis.rs
+++ b/rust/tests/tirx/analysis/analysis.rs
@@ -22,12 +22,11 @@
use tvm_tirx::tirx::analysis;
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
use crate::{as_i64, int32, module_of, op, prim_type, var, void_function};
#[test]
fn well_formedness() {
- load_tirx_compiler();
let _serial = serial();
let func = void_function(vec![var("x", prim_type("int32"))]);
assert!(analysis::verify_memory(&func).unwrap());
@@ -37,7 +36,6 @@ fn well_formedness() {
#[test]
fn expression_analyses() {
- load_tirx_compiler();
let _serial = serial();
let (x, y) = (var("x", prim_type("int32")), var("y", prim_type("int32")));
let undefined = analysis::undefined_vars(op("prim._OpAdd", &x, &y),
[x.clone()]).unwrap();
diff --git a/rust/tests/tirx/function.rs b/rust/tests/tirx/function.rs
index fd753e65..babe1672 100644
--- a/rust/tests/tirx/function.rs
+++ b/rust/tests/tirx/function.rs
@@ -22,11 +22,10 @@
use tvm_tirx::tirx::renew_def;
use super::{prim_type, var, void_function};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn functions() {
- load_tirx_compiler();
let _serial = serial();
let x = var("x", prim_type("int32"));
let func = void_function(vec![x.clone()]);
diff --git a/rust/tests/tirx/index_map.rs b/rust/tests/tirx/index_map.rs
index 2b2f8060..7b559da1 100644
--- a/rust/tests/tirx/index_map.rs
+++ b/rust/tests/tirx/index_map.rs
@@ -24,11 +24,10 @@ use tvm_tirx::tirx::IndexMap;
use tvm_tirx::tvm_ffi::{Array, DLDataType, DLDataTypeExt, DLDevice,
DLDeviceType};
use super::{as_i64, int32, op, prim_type, range, var};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn index_maps() {
- load_tirx_compiler();
let _serial = serial();
let (i, j) = (var("i", prim_type("int32")), var("j", prim_type("int32")));
let transpose = IndexMap::new(
diff --git a/rust/tests/tirx/layout.rs b/rust/tests/tirx/layout.rs
index bcde3d76..0eb50fcd 100644
--- a/rust/tests/tirx/layout.rs
+++ b/rust/tests/tirx/layout.rs
@@ -24,11 +24,10 @@ use tvm_tirx::tirx::{Axis, ComposeLayout, Iter, Layout,
TileLayout};
use tvm_tirx::tvm_ffi::{Map, String as FfiString};
use super::{as_i64, int32, tile_8x8};
-use crate::common::{global, load_tirx_compiler, serial};
+use crate::common::{global, serial};
#[test]
fn memory_axes() {
- load_tirx_compiler();
let _serial = serial();
let m = Axis::get("m").unwrap();
assert!(m.is_memory().unwrap() && !m.is_thread().unwrap());
@@ -38,7 +37,6 @@ fn memory_axes() {
#[test]
fn layouts() {
- load_tirx_compiler();
let _serial = serial();
let tile = tile_8x8();
let layout = Layout::from(&tile);
@@ -71,7 +69,6 @@ fn layouts() {
#[test]
fn thread_layout_scope() {
- load_tirx_compiler();
let _serial = serial();
global("tirx.cuda.RegisterLayoutAxes").call_tuple(()).unwrap();
let laneid = Axis::get("laneid").unwrap();
diff --git a/rust/tests/tirx/op.rs b/rust/tests/tirx/op.rs
index 53d6df5a..7320af47 100644
--- a/rust/tests/tirx/op.rs
+++ b/rust/tests/tirx/op.rs
@@ -22,11 +22,10 @@
use tvm_tirx::tirx::{gpu_thread_return, logaddexp, reinterpret};
use super::{loc, prim_type, var};
-use crate::common::{load_tirx_compiler, serial, structural_equal};
+use crate::common::{serial, structural_equal};
#[test]
fn ops() {
- load_tirx_compiler();
let _serial = serial();
let (a, b) = (var("a", prim_type("float32")), var("b",
prim_type("float32")));
let sum = logaddexp(&a, &b, loc()).unwrap();
diff --git a/rust/tests/tirx/tensor.rs b/rust/tests/tirx/tensor.rs
index 5830cfd5..80fe481b 100644
--- a/rust/tests/tirx/tensor.rs
+++ b/rust/tests/tirx/tensor.rs
@@ -22,11 +22,10 @@
use tvm_tirx::tirx::{tensor_is_scalar, Layout, TensorType};
use super::{int32, loc, memory_scope, prim_type, tile_8x8, var};
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
#[test]
fn tensor_types() {
- load_tirx_compiler();
let _serial = serial();
let scope = memory_scope();
let ty = TensorType::new([int32(1)], prim_type("float32"), &scope, 0,
None, loc()).unwrap();
diff --git a/rust/tests/tirx/thread_scope.rs b/rust/tests/tirx/thread_scope.rs
index 7121642d..d5746739 100644
--- a/rust/tests/tirx/thread_scope.rs
+++ b/rust/tests/tirx/thread_scope.rs
@@ -21,11 +21,10 @@
use tvm_tirx::tirx::ThreadScope;
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
#[test]
fn thread_scopes() {
- load_tirx_compiler();
let _serial = serial();
let warp = ThreadScope::get("cuda.warp").unwrap();
let cta = ThreadScope::get("cuda.cta").unwrap();
diff --git a/rust/tests/tirx/tile/dispatch.rs b/rust/tests/tirx/tile/dispatch.rs
index 10f9f3a1..63bada3a 100644
--- a/rust/tests/tirx/tile/dispatch.rs
+++ b/rust/tests/tirx/tile/dispatch.rs
@@ -25,12 +25,11 @@ use tvm_tirx::tirx::tile::DispatchContext;
use tvm_tirx::tirx::{TensorType, ThreadScope};
use tvm_tirx::tvm_ffi::{Any, Map, ObjectRefCast, String as FfiString};
-use crate::common::{global, load_tirx_compiler, serial, structural_equal};
+use crate::common::{global, serial, structural_equal};
use crate::{int32, loc, memory_scope, prim_type, var};
#[test]
fn dispatch_contexts() {
- load_tirx_compiler();
let _serial = serial();
let target = Target::new("cuda").unwrap();
let warp = ThreadScope::get("cuda.warp").unwrap();
diff --git a/rust/tests/tirx/tile/instruction.rs
b/rust/tests/tirx/tile/instruction.rs
index 1cab4cf8..12ece73c 100644
--- a/rust/tests/tirx/tile/instruction.rs
+++ b/rust/tests/tirx/tile/instruction.rs
@@ -24,12 +24,11 @@ use tvm_tirx::tirx::tile::{as_tensor_region,
configure_tensor_instruction};
use tvm_tirx::tirx::TensorType;
use tvm_tirx::tvm_ffi::Array;
-use crate::common::{global, load_tirx_compiler, serial, structural_equal};
+use crate::common::{global, serial, structural_equal};
use crate::{int32, loc, memory_scope, prim_type, var};
#[test]
fn tensor_regions() {
- load_tirx_compiler();
let _serial = serial();
let scope = memory_scope();
let ty = TensorType::new([int32(4)], prim_type("float32"), &scope, 0,
None, loc()).unwrap();
@@ -45,7 +44,6 @@ fn tensor_regions() {
#[test]
fn tensor_instructions() {
- load_tirx_compiler();
let _serial = serial();
Op::register("rust.tests.tirx.instruction", "").unwrap();
let instruction = Op::get("rust.tests.tirx.instruction").unwrap();
diff --git a/rust/tests/tirx/transform/function_pass.rs
b/rust/tests/tirx/transform/function_pass.rs
index a07b0c86..b3fde2c1 100644
--- a/rust/tests/tirx/transform/function_pass.rs
+++ b/rust/tests/tirx/transform/function_pass.rs
@@ -25,12 +25,11 @@ use std::sync::Arc;
use tvm_tirx::ir::transform::{Pass, PassInfo};
use tvm_tirx::tirx::transform::FunctionPass;
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
use crate::{module_of, void_function};
#[test]
fn function_passes() {
- load_tirx_compiler();
let _serial = serial();
let func = void_function(vec![]);
let runs = Arc::new(AtomicUsize::new(0));
diff --git a/rust/tests/tirx/transform/transform.rs
b/rust/tests/tirx/transform/transform.rs
index 923bd811..e266a07c 100644
--- a/rust/tests/tirx/transform/transform.rs
+++ b/rust/tests/tirx/transform/transform.rs
@@ -23,12 +23,11 @@ use tvm_tirx::ir::transform::Pass;
use tvm_tirx::target::Target;
use tvm_tirx::tirx::transform as tx;
-use crate::common::{load_tirx_compiler, serial};
+use crate::common::serial;
use crate::{module_of, void_function};
#[test]
fn passes() {
- load_tirx_compiler();
let _serial = serial();
let target = Target::new("llvm").unwrap();
let passes: Vec<Pass> = vec![
@@ -67,7 +66,6 @@ fn passes() {
#[test]
fn filter() {
- load_tirx_compiler();
let _serial = serial();
let func = void_function(vec![]);
let kept = tx::filter(|_func| Ok(true)).unwrap().run(module_of("main",
&func)).unwrap();
diff --git a/rust/tests/codegen/main.rs b/src/ir/link_anchor.cc
similarity index 52%
copy from rust/tests/codegen/main.rs
copy to src/ir/link_anchor.cc
index aebe9c0d..4ebc7eed 100644
--- a/rust/tests/codegen/main.rs
+++ b/src/ir/link_anchor.cc
@@ -17,23 +17,17 @@
* under the License.
*/
-//! Tests of `tvm_tirx::codegen`, laid out like `src/codegen/`: the tests of
`src/codegen.rs` are
-//! here, and those of `src/codegen/llvm.rs` in `tests/codegen/llvm.rs`.
-
-#[path = "../common/mod.rs"]
-mod common;
-
-mod llvm;
-
-use tvm_tirx::codegen;
-use tvm_tirx::target::Target;
-
-use common::{empty_module, load_tirx_compiler};
+/*!
+ * \file src/ir/link_anchor.cc
+ * \brief The link anchor of libtvm_tirx_compiler.
+ *
+ * Each TIRx shared library exports a `<library>_link_anchor` function that
does nothing, defined
+ * in the `link_anchor.cc` of its sources. A language binding that uses the
library only through
+ * the TVM FFI registry references no other symbol of it, so a linker that
drops unreferenced
+ * libraries (`--as-needed`) would drop the dependency and the library's
registrations would
+ * never run; the binding references the anchor (its address is enough) to
keep the library
+ * linked. There is no header: the binding declares the function itself.
+ */
+#include <tvm/runtime/base.h>
-#[test]
-fn build_module() {
- load_tirx_compiler();
- let module = empty_module();
- codegen::build_module(&module, Target::new("llvm").unwrap()).unwrap();
- codegen::build_module(&module, Target::new("c").unwrap()).unwrap();
-}
+extern "C" TVM_TIRX_DLL int tvm_tirx_compiler_link_anchor() { return 0; }
diff --git a/rust/tests/codegen/main.rs b/src/runtime/link_anchor.cc
similarity index 52%
copy from rust/tests/codegen/main.rs
copy to src/runtime/link_anchor.cc
index aebe9c0d..bd3270bb 100644
--- a/rust/tests/codegen/main.rs
+++ b/src/runtime/link_anchor.cc
@@ -17,23 +17,17 @@
* under the License.
*/
-//! Tests of `tvm_tirx::codegen`, laid out like `src/codegen/`: the tests of
`src/codegen.rs` are
-//! here, and those of `src/codegen/llvm.rs` in `tests/codegen/llvm.rs`.
-
-#[path = "../common/mod.rs"]
-mod common;
-
-mod llvm;
-
-use tvm_tirx::codegen;
-use tvm_tirx::target::Target;
-
-use common::{empty_module, load_tirx_compiler};
+/*!
+ * \file src/runtime/link_anchor.cc
+ * \brief The link anchor of libtvm_runtime.
+ *
+ * Each TIRx shared library exports a `<library>_link_anchor` function that
does nothing, defined
+ * in the `link_anchor.cc` of its sources. A language binding that uses the
library only through
+ * the TVM FFI registry references no other symbol of it, so a linker that
drops unreferenced
+ * libraries (`--as-needed`) would drop the dependency and the library's
registrations would
+ * never run; the binding references the anchor (its address is enough) to
keep the library
+ * linked. There is no header: the binding declares the function itself.
+ */
+#include <tvm/runtime/base.h>
-#[test]
-fn build_module() {
- load_tirx_compiler();
- let module = empty_module();
- codegen::build_module(&module, Target::new("llvm").unwrap()).unwrap();
- codegen::build_module(&module, Target::new("c").unwrap()).unwrap();
-}
+extern "C" TVM_RUNTIME_DLL int tvm_runtime_link_anchor() { return 0; }