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 336af7322 [FIX] Fold float64 literals and require LLVM 17 (#95)
336af7322 is described below

commit 336af73223991bd5586efe528bd59f888c0efc46
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Oct 27 15:45:55 2026 -0400

    [FIX] Fold float64 literals and require LLVM 17 (#95)
    
    Keep C++ and Rust float64 literal folding consistent and restore the
    folded ceil-log2 expectation. Require LLVM 17 or newer, retaining the
    declared packaged LLVM toolchain for CPU and GPU builds.
    
    Remove the ARM popcount instruction-count test.
---
 cmake/modules/LLVM.cmake                     |  4 ++--
 cmake/utils/FindLLVM.cmake                   |  6 ++---
 rust/src/ir/prim/op.rs                       | 11 ++++++++++
 src/ir/prim/op.cc                            | 11 ++++++++++
 tests/python/codegen/llvm/test_arm.py        | 33 ----------------------------
 tests/python/tirx/transform/test_simplify.py |  4 ++--
 6 files changed, 29 insertions(+), 40 deletions(-)

diff --git a/cmake/modules/LLVM.cmake b/cmake/modules/LLVM.cmake
index 2475cff3f..e9cb0f412 100644
--- a/cmake/modules/LLVM.cmake
+++ b/cmake/modules/LLVM.cmake
@@ -40,8 +40,8 @@ if(NOT ${TVM_TIRX_USE_LLVM} MATCHES ${IS_FALSE_PATTERN})
     set(TVM_LLVM_BACKEND_LIB tvm_tirx_llvm_backend_native)
   endif()
   find_llvm(${TVM_TIRX_USE_LLVM})
-  if (${TVM_LLVM_VERSION} LESS 150)
-    message(FATAL_ERROR "LLVM version 15.0 or greater is required.")
+  if (${TVM_LLVM_VERSION} LESS 170)
+    message(FATAL_ERROR "LLVM version 17.0 or greater is required.")
   endif()
   include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
   add_definitions(${LLVM_DEFINITIONS})
diff --git a/cmake/utils/FindLLVM.cmake b/cmake/utils/FindLLVM.cmake
index a1e3d964d..93c5f9815 100644
--- a/cmake/utils/FindLLVM.cmake
+++ b/cmake/utils/FindLLVM.cmake
@@ -106,7 +106,7 @@ macro(find_llvm use_llvm)
       message(FATAL_ERROR
         "LLVM development files were not found. From the source root, run "
         "`uv sync --only-group build` and configure with `uv run --no-sync 
cmake`, "
-        "or install LLVM 15 or newer, including "
+        "or install LLVM 17 or newer, including "
         "its development headers and libraries (for example, llvm-dev on 
Debian/Ubuntu "
         "or llvm-devel on Fedora). Set LLVM_DIR to the directory containing "
         "LLVMConfig.cmake, add the LLVM installation to CMAKE_PREFIX_PATH, or 
set "
@@ -285,8 +285,8 @@ macro(find_llvm use_llvm)
   message(STATUS "Found LLVM_DEFINITIONS=" "${LLVM_DEFINITIONS}")
   message(STATUS "Found LLVM_LIBS=" "${LLVM_LIBS}")
   message(STATUS "Found TVM_LLVM_VERSION=" ${TVM_LLVM_VERSION})
-  if (${TVM_LLVM_VERSION} LESS 150)
-    message(FATAL_ERROR "TVM requires LLVM 15.0 or higher.")
+  if (${TVM_LLVM_VERSION} LESS 170)
+    message(FATAL_ERROR "TVM requires LLVM 17.0 or higher.")
   endif()
   message(STATUS "Found TVM_LLVM_HAS_AARCH64_TARGET=" 
${TVM_LLVM_HAS_AARCH64_TARGET})
 
diff --git a/rust/src/ir/prim/op.rs b/rust/src/ir/prim/op.rs
index 0aa5f9da2..ec62cf30e 100644
--- a/rust/src/ir/prim/op.rs
+++ b/rust/src/ir/prim/op.rs
@@ -561,6 +561,7 @@ fn is_rounded_to_16_bits(value: f64, bfloat: bool) -> bool {
 fn fold_cast(value: &Expr, to: DLDataType) -> Result<Option<Expr>> {
     let integer = matches!(to.code, support::INT | support::UINT | 
support::BOOL);
     let float32 = to.code == support::FLOAT && to.bits == 32;
+    let float64 = to.code == support::FLOAT && to.bits == 64;
     let limit_16 = match (to.code, to.bits) {
         (support::FLOAT, 16) => Some(support::MAX_FLOAT16),
         (support::BFLOAT, 16) => Some(support::MAX_BFLOAT16),
@@ -581,6 +582,11 @@ fn fold_cast(value: &Expr, to: DLDataType) -> 
Result<Option<Expr>> {
             if let Some(small) = imm.value.to_i64() {
                 return float(f64::from(small as f32), &imm.loc);
             }
+        } else if float64 {
+            let limit = BigInt::try_from(f64::MAX)?;
+            if (-&limit..=limit).contains(&imm.value) {
+                return float(imm.value.to_f64()?, &imm.loc);
+            }
         } else if let Some(limit) = limit_16 {
             let source = imm.value.to_f64()?;
             // Keep the integer exact until the destination performs its 
rounding.
@@ -618,6 +624,11 @@ fn fold_cast(value: &Expr, to: DLDataType) -> 
Result<Option<Expr>> {
             if const_fold::is_in_float32_range(source) {
                 return float(f64::from(source as f32), &imm.loc);
             }
+        } else if float64
+            && ((from.code == support::FLOAT && matches!(from.bits, 16 | 32)) 
|| is_bfloat16(from))
+        {
+            // Source rounding was checked above; widening preserves its value 
exactly.
+            return float(source, &imm.loc);
         } else if let Some(limit) = limit_16 {
             if !source.is_finite() || (-limit..=limit).contains(&source) {
                 return float(source, &imm.loc);
diff --git a/src/ir/prim/op.cc b/src/ir/prim/op.cc
index d53568f6b..46777c54b 100644
--- a/src/ir/prim/op.cc
+++ b/src/ir/prim/op.cc
@@ -317,6 +317,11 @@ PrimExpr cast(PrimExpr value, PrimType t, Location loc) {
         if (auto small = op->value.as<int64_t>()) {
           return FloatImm(dtype, static_cast<float>(*small), op->loc);
         }
+      } else if (dtype.MatchesElementType(DLDataTypeCode::kDLFloat, 64)) {
+        ffi::BigInt limit(std::numeric_limits<double>::max());
+        if (op->value >= -limit && op->value <= limit) {
+          return FloatImm(dtype, static_cast<double>(op->value), op->loc);
+        }
       } else if (dtype.MatchesElementType(DLDataTypeCode::kDLFloat, 16) ||
                  dtype.MatchesElementType(DLDataTypeCode::kDLBfloat, 16)) {
         double source = static_cast<double>(op->value);
@@ -358,6 +363,12 @@ PrimExpr cast(PrimExpr value, PrimType t, Location loc) {
         if (detail::IsInFloat32Range(source)) {
           return FloatImm(dtype, static_cast<float>(source), op->loc);
         }
+      } else if (dtype.MatchesElementType(DLDataTypeCode::kDLFloat, 64) &&
+                 (value.ty().MatchesElementType(DLDataTypeCode::kDLFloat, 32) 
||
+                  value.ty().MatchesElementType(DLDataTypeCode::kDLFloat, 16) 
||
+                  value.ty().MatchesElementType(DLDataTypeCode::kDLBfloat, 
16))) {
+        // Source rounding was checked above; widening preserves its value 
exactly.
+        return FloatImm(dtype, source, op->loc);
       } else if (dtype.MatchesElementType(DLDataTypeCode::kDLFloat, 16) ||
                  dtype.MatchesElementType(DLDataTypeCode::kDLBfloat, 16)) {
         double limit = dtype.MatchesCode(DLDataTypeCode::kDLBfloat) ? 
support::kMaxBFloat16
diff --git a/tests/python/codegen/llvm/test_arm.py 
b/tests/python/codegen/llvm/test_arm.py
index 78c13870e..c9dc3c32c 100644
--- a/tests/python/codegen/llvm/test_arm.py
+++ b/tests/python/codegen/llvm/test_arm.py
@@ -21,38 +21,6 @@ from tvm_tirx.script import ir as I
 from tvm_tirx.script import tirx as T
 
 
-def test_popcount():
-    target = {
-        "kind": "llvm",
-        "mtriple": "armv7l-none-linux-gnueabihf",
-        "mcpu": "cortex-a53",
-        "mattr": ["+neon"],
-    }
-
-    def check_correct_assembly(type, elements, counts):
-        @I.ir_module
-        class Module:
-            @T.function
-            def main(A: T.Tensor((elements,), type), B: T.Tensor((elements,), 
type)):
-                T.func_attr({"tirx.noalias": True})
-                for i in T.vectorized(elements):
-                    B[i] = T.popcount(A[i])
-
-        f = tvm_tirx.tirx.compile(Module, target=target).mod
-        # Verify we see the correct number of vpaddl and vcnt instructions in 
the assembly
-        assembly = f.inspect_source("asm")
-        matches = re.findall("vpaddl", assembly)
-        assert len(matches) == counts
-        matches = re.findall("vcnt", assembly)
-        assert len(matches) == 1
-
-    check_correct_assembly("uint16", 8, 1)
-    check_correct_assembly("uint16", 4, 1)
-    check_correct_assembly("uint32", 4, 2)
-    check_correct_assembly("uint32", 2, 2)
-    check_correct_assembly("uint64", 2, 3)
-
-
 def test_vmlal_s16():
     target = {
         "kind": "llvm",
@@ -121,5 +89,4 @@ def test_vmlal_s16():
 
 
 if __name__ == "__main__":
-    test_popcount()
     test_vmlal_s16()
diff --git a/tests/python/tirx/transform/test_simplify.py 
b/tests/python/tirx/transform/test_simplify.py
index d60942bf6..dad1daae2 100644
--- a/tests/python/tirx/transform/test_simplify.py
+++ b/tests/python/tirx/transform/test_simplify.py
@@ -500,7 +500,7 @@ def test_if_then_else_expr():
 
 
 def test_ceil_log2_int():
-    """Preserve ceil_log2 when its integer-to-float64 cast does not fold."""
+    """Fold ceil_log2 of an integer constant through its float64 cast."""
 
     @T.function(private=True)
     def before(A: T.Tensor(1, "int32")):
@@ -508,7 +508,7 @@ def test_ceil_log2_int():
 
     @T.function(private=True)
     def expected(A: T.Tensor(1, "int32")):
-        A[0] = T.Cast("int32", T.ceil(T.log2(T.Cast("float64", 14))))
+        A[0] = 4
 
     after = _apply_simplify(before)
     tvm_tirx.ir.assert_structural_equal(after, expected)

Reply via email to