You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by tq...@apache.org on 2025/09/14 10:58:48 UTC
(tvm) branch main updated: [REFACTOR][FFI] Split tvm-ffi into a separate repo (#18314)
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.git
The following commit(s) were added to refs/heads/main by this push:
new 70e9164814 [REFACTOR][FFI] Split tvm-ffi into a separate repo (#18314)
70e9164814 is described below
commit 70e9164814e8b5f556c04c3f4a4dd8c75e81e13a
Author: Tianqi Chen <tq...@users.noreply.github.com>
AuthorDate: Sun Sep 14 06:58:43 2025 -0400
[REFACTOR][FFI] Split tvm-ffi into a separate repo (#18314)
This PR updates the code so we split tvm-ffi into a separate repo
---
.github/actions/setup/action.yml | 2 +-
.gitmodules | 3 +
3rdparty/tvm-ffi | 1 +
CMakeLists.txt | 2 +-
apps/android_rpc/app/src/main/jni/Android.mk | 4 +-
apps/android_rpc/app/src/main/jni/tvm_runtime.h | 24 +-
apps/ios_rpc/tvmrpc/TVMRuntime.mm | 2 +-
docs/install/from_source.rst | 2 +-
ffi/.clang-format | 8 -
ffi/CMakeLists.txt | 262 ---
ffi/README.md | 18 -
ffi/cmake/Utils/AddGoogleTest.cmake | 56 -
ffi/cmake/Utils/AddLibbacktrace.cmake | 68 -
ffi/cmake/Utils/CxxWarning.cmake | 30 -
ffi/cmake/Utils/Library.cmake | 88 -
ffi/cmake/Utils/Sanitizer.cmake | 35 -
ffi/cmake/tvm_ffi-config.cmake | 58 -
ffi/docs/.gitignore | 2 -
ffi/docs/Makefile | 41 -
ffi/docs/README.md | 46 -
ffi/docs/concepts/abi_overview.md | 430 -----
ffi/docs/conf.py | 228 ---
ffi/docs/get_started/install.md | 83 -
ffi/docs/get_started/quick_start.md | 213 ---
ffi/docs/guides/cpp_guide.md | 584 -------
ffi/docs/guides/packaging.md | 282 ----
ffi/docs/guides/python_guide.md | 242 ---
ffi/docs/index.rst | 53 -
ffi/docs/reference/cpp/index.rst | 107 --
ffi/docs/reference/python/index.rst | 69 -
ffi/docs/requirements.txt | 21 -
ffi/examples/inline_module/main.py | 87 -
ffi/examples/packaging/CMakeLists.txt | 73 -
ffi/examples/packaging/README.md | 61 -
ffi/examples/packaging/pyproject.toml | 58 -
.../packaging/python/my_ffi_extension/__init__.py | 48 -
.../packaging/python/my_ffi_extension/_ffi_api.py | 24 -
.../packaging/python/my_ffi_extension/base.py | 37 -
ffi/examples/packaging/run_example.py | 40 -
ffi/examples/packaging/src/extension.cc | 89 -
ffi/examples/quick_start/CMakeLists.txt | 65 -
ffi/examples/quick_start/README.md | 58 -
ffi/examples/quick_start/run_example.py | 82 -
ffi/examples/quick_start/run_example.sh | 27 -
ffi/examples/quick_start/src/add_one_cpu.cc | 41 -
ffi/examples/quick_start/src/add_one_cuda.cu | 58 -
ffi/examples/quick_start/src/run_example.cc | 53 -
ffi/include/tvm/ffi/any.h | 692 --------
ffi/include/tvm/ffi/base_details.h | 297 ----
ffi/include/tvm/ffi/c_api.h | 1097 ------------
ffi/include/tvm/ffi/cast.h | 79 -
ffi/include/tvm/ffi/container/array.h | 1147 -------------
ffi/include/tvm/ffi/container/container_details.h | 356 ----
ffi/include/tvm/ffi/container/map.h | 1762 --------------------
ffi/include/tvm/ffi/container/shape.h | 247 ---
ffi/include/tvm/ffi/container/tensor.h | 468 ------
ffi/include/tvm/ffi/container/tuple.h | 317 ----
ffi/include/tvm/ffi/container/variant.h | 302 ----
ffi/include/tvm/ffi/dtype.h | 192 ---
ffi/include/tvm/ffi/endian.h | 89 -
ffi/include/tvm/ffi/error.h | 335 ----
ffi/include/tvm/ffi/extra/base.h | 48 -
ffi/include/tvm/ffi/extra/base64.h | 142 --
ffi/include/tvm/ffi/extra/c_env_api.h | 142 --
ffi/include/tvm/ffi/extra/json.h | 84 -
ffi/include/tvm/ffi/extra/module.h | 262 ---
ffi/include/tvm/ffi/extra/serialization.h | 72 -
ffi/include/tvm/ffi/extra/structural_equal.h | 78 -
ffi/include/tvm/ffi/extra/structural_hash.h | 57 -
ffi/include/tvm/ffi/function.h | 880 ----------
ffi/include/tvm/ffi/function_details.h | 210 ---
ffi/include/tvm/ffi/memory.h | 229 ---
ffi/include/tvm/ffi/object.h | 1142 -------------
ffi/include/tvm/ffi/optional.h | 419 -----
ffi/include/tvm/ffi/reflection/access_path.h | 440 -----
ffi/include/tvm/ffi/reflection/accessor.h | 260 ---
ffi/include/tvm/ffi/reflection/creator.h | 120 --
ffi/include/tvm/ffi/reflection/registry.h | 564 -------
ffi/include/tvm/ffi/rvalue_ref.h | 155 --
ffi/include/tvm/ffi/string.h | 1014 -----------
ffi/include/tvm/ffi/type_traits.h | 781 ---------
ffi/licenses/LICENSE.dlpack.txt | 201 ---
ffi/licenses/LICENSE.libbacktrace.txt | 29 -
ffi/licenses/LICENSE.pytorch.txt | 84 -
ffi/licenses/NOTICE.pytorch.txt | 456 -----
ffi/pyproject.toml | 159 --
ffi/python/tvm_ffi/.gitignore | 2 -
ffi/python/tvm_ffi/__init__.py | 73 -
ffi/python/tvm_ffi/_convert.py | 65 -
ffi/python/tvm_ffi/_dtype.py | 141 --
ffi/python/tvm_ffi/_ffi_api.py | 20 -
ffi/python/tvm_ffi/_optional_torch_c_dlpack.py | 404 -----
ffi/python/tvm_ffi/_tensor.py | 88 -
ffi/python/tvm_ffi/access_path.py | 181 --
ffi/python/tvm_ffi/base.py | 53 -
ffi/python/tvm_ffi/config.py | 92 -
ffi/python/tvm_ffi/container.py | 252 ---
ffi/python/tvm_ffi/cpp/__init__.py | 18 -
ffi/python/tvm_ffi/cpp/load_inline.py | 437 -----
ffi/python/tvm_ffi/cython/base.pxi | 393 -----
ffi/python/tvm_ffi/cython/core.pyx | 26 -
ffi/python/tvm_ffi/cython/device.pxi | 191 ---
ffi/python/tvm_ffi/cython/dtype.pxi | 116 --
ffi/python/tvm_ffi/cython/error.pxi | 134 --
ffi/python/tvm_ffi/cython/function.pxi | 853 ----------
ffi/python/tvm_ffi/cython/object.pxi | 295 ----
ffi/python/tvm_ffi/cython/string.pxi | 80 -
ffi/python/tvm_ffi/cython/tensor.pxi | 362 ----
ffi/python/tvm_ffi/cython/tvm_ffi_python_helpers.h | 580 -------
ffi/python/tvm_ffi/error.py | 193 ---
ffi/python/tvm_ffi/libinfo.py | 167 --
ffi/python/tvm_ffi/module.py | 275 ---
ffi/python/tvm_ffi/registry.py | 226 ---
ffi/python/tvm_ffi/serialization.py | 67 -
ffi/python/tvm_ffi/testing.py | 63 -
ffi/python/tvm_ffi/utils/__init__.py | 18 -
ffi/python/tvm_ffi/utils/lockfile.py | 113 --
ffi/scripts/benchmark_dlpack.py | 448 -----
ffi/scripts/run_tests.sh | 27 -
ffi/src/ffi/container.cc | 88 -
ffi/src/ffi/dtype.cc | 328 ----
ffi/src/ffi/error.cc | 81 -
ffi/src/ffi/extra/buffer_stream.h | 127 --
ffi/src/ffi/extra/env_c_api.cc | 148 --
ffi/src/ffi/extra/env_context.cc | 120 --
ffi/src/ffi/extra/json_parser.cc | 731 --------
ffi/src/ffi/extra/json_writer.cc | 307 ----
ffi/src/ffi/extra/library_module.cc | 199 ---
ffi/src/ffi/extra/library_module_dynamic_lib.cc | 118 --
ffi/src/ffi/extra/library_module_system_lib.cc | 143 --
ffi/src/ffi/extra/module.cc | 157 --
ffi/src/ffi/extra/module_internal.h | 114 --
ffi/src/ffi/extra/reflection_extra.cc | 144 --
ffi/src/ffi/extra/serialization.cc | 430 -----
ffi/src/ffi/extra/structural_equal.cc | 439 -----
ffi/src/ffi/extra/structural_hash.cc | 317 ----
ffi/src/ffi/extra/testing.cc | 133 --
ffi/src/ffi/function.cc | 229 ---
ffi/src/ffi/object.cc | 513 ------
ffi/src/ffi/tensor.cc | 82 -
ffi/src/ffi/traceback.cc | 188 ---
ffi/src/ffi/traceback.h | 182 --
ffi/src/ffi/traceback_win.cc | 142 --
ffi/tests/cpp/CMakeLists.txt | 33 -
ffi/tests/cpp/extra/test_json_parser.cc | 394 -----
ffi/tests/cpp/extra/test_json_writer.cc | 241 ---
ffi/tests/cpp/extra/test_serialization.cc | 372 -----
ffi/tests/cpp/extra/test_structural_equal_hash.cc | 178 --
ffi/tests/cpp/test_any.cc | 415 -----
ffi/tests/cpp/test_array.cc | 286 ----
ffi/tests/cpp/test_c_ffi_abi.cc | 31 -
ffi/tests/cpp/test_dtype.cc | 130 --
ffi/tests/cpp/test_error.cc | 70 -
ffi/tests/cpp/test_example.cc | 288 ----
ffi/tests/cpp/test_function.cc | 239 ---
ffi/tests/cpp/test_map.cc | 366 ----
ffi/tests/cpp/test_object.cc | 258 ---
ffi/tests/cpp/test_optional.cc | 202 ---
ffi/tests/cpp/test_reflection.cc | 269 ---
ffi/tests/cpp/test_rvalue_ref.cc | 97 --
ffi/tests/cpp/test_shape.cc | 72 -
ffi/tests/cpp/test_string.cc | 430 -----
ffi/tests/cpp/test_tensor.cc | 164 --
ffi/tests/cpp/test_tuple.cc | 168 --
ffi/tests/cpp/test_variant.cc | 164 --
ffi/tests/cpp/testing_object.h | 296 ----
ffi/tests/python/test_access_path.py | 133 --
ffi/tests/python/test_container.py | 124 --
ffi/tests/python/test_device.py | 94 --
ffi/tests/python/test_dtype.py | 85 -
ffi/tests/python/test_error.py | 113 --
ffi/tests/python/test_examples.py | 47 -
ffi/tests/python/test_function.py | 221 ---
ffi/tests/python/test_load_inline.py | 324 ----
ffi/tests/python/test_object.py | 91 -
ffi/tests/python/test_string.py | 54 -
ffi/tests/python/test_tensor.py | 68 -
jvm/native/linux-x86_64/pom.xml | 2 +-
jvm/native/osx-x86_64/pom.xml | 2 +-
pyproject.toml | 2 +-
python/tvm/libinfo.py | 7 +-
python/tvm/relax/frontend/nn/extern.py | 18 +-
tests/lint/cpplint.sh | 1 -
tests/scripts/task_python_adreno.sh | 2 +-
tests/scripts/task_python_arm_compute_library.sh | 2 +-
tests/scripts/task_python_docs.sh | 4 +-
tests/scripts/task_python_hexagon.sh | 2 +-
tests/scripts/task_python_integration.sh | 2 +-
tests/scripts/task_python_nightly.sh | 2 +-
tests/scripts/task_python_unittest.sh | 2 +-
tests/scripts/task_web_wasm.sh | 2 +-
tests/scripts/unity/task_python_relax.sh | 2 +-
web/Makefile | 4 +-
web/emcc/wasm_runtime.cc | 22 +-
194 files changed, 63 insertions(+), 37818 deletions(-)
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
index 88b3888179..77271319b2 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/setup/action.yml
@@ -39,4 +39,4 @@ runs:
- name: Install tvm-ffi pip package
shell: bash -l {0}
run: |
- pip install -v ./ffi
+ pip install -v ./3rdparty/tvm-ffi
diff --git a/.gitmodules b/.gitmodules
index 32a70d37ae..6b14c3524f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,3 +28,6 @@
[submodule "ffi/3rdparty/dlpack"]
path = ffi/3rdparty/dlpack
url = https://github.com/dmlc/dlpack.git
+[submodule "3rdparty/tvm-ffi"]
+ path = 3rdparty/tvm-ffi
+ url = https://github.com/apache/tvm-ffi
diff --git a/3rdparty/tvm-ffi b/3rdparty/tvm-ffi
new file mode 160000
index 0000000000..3e07df45af
--- /dev/null
+++ b/3rdparty/tvm-ffi
@@ -0,0 +1 @@
+Subproject commit 3e07df45afbc8ea968ef03c34d84dc348ba6dfb0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b05e5e1657..5e5a61490d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -567,7 +567,7 @@ if(USE_IOS_RPC)
add_subdirectory("apps/ios_rpc")
endif()
-add_subdirectory(ffi)
+add_subdirectory(3rdparty/tvm-ffi)
if(TVM_DEBUG_WITH_ABI_CHANGE)
message(STATUS "Building with debug code that may cause ABI changes...")
diff --git a/apps/android_rpc/app/src/main/jni/Android.mk b/apps/android_rpc/app/src/main/jni/Android.mk
index 692a339013..d482f94295 100644
--- a/apps/android_rpc/app/src/main/jni/Android.mk
+++ b/apps/android_rpc/app/src/main/jni/Android.mk
@@ -37,8 +37,8 @@ LOCAL_SRC_FILES := org_apache_tvm_native_c_api.cc
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib/ -llog
LOCAL_C_INCLUDES := $(ROOT_PATH)/include \
- $(ROOT_PATH)/ffi/include \
- $(ROOT_PATH)/ffi/3rdparty/dlpack/include \
+ $(ROOT_PATH)/3rdparty/tvm-ffi/include \
+ $(ROOT_PATH)/3rdparty/tvm-ffi/3rdparty/dlpack/include \
$(ROOT_PATH)/3rdparty/dmlc-core/include \
$(ROOT_PATH)/3rdparty/OpenCL-Headers
diff --git a/apps/android_rpc/app/src/main/jni/tvm_runtime.h b/apps/android_rpc/app/src/main/jni/tvm_runtime.h
index b0cb033e88..6bda78cef0 100644
--- a/apps/android_rpc/app/src/main/jni/tvm_runtime.h
+++ b/apps/android_rpc/app/src/main/jni/tvm_runtime.h
@@ -34,18 +34,18 @@
#define TVM_LOG_CUSTOMIZE 1
#define TVM_FFI_USE_LIBBACKTRACE 0
-#include "../ffi/src/ffi/container.cc"
-#include "../ffi/src/ffi/dtype.cc"
-#include "../ffi/src/ffi/error.cc"
-#include "../ffi/src/ffi/extra/library_module.cc"
-#include "../ffi/src/ffi/extra/library_module_dynamic_lib.cc"
-#include "../ffi/src/ffi/extra/library_module_system_lib.cc"
-#include "../ffi/src/ffi/extra/module.cc"
-#include "../ffi/src/ffi/extra/testing.cc"
-#include "../ffi/src/ffi/function.cc"
-#include "../ffi/src/ffi/object.cc"
-#include "../ffi/src/ffi/tensor.cc"
-#include "../ffi/src/ffi/traceback.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/container.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/dtype.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/error.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/extra/library_module.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/extra/library_module_dynamic_lib.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/extra/library_module_system_lib.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/extra/module.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/extra/testing.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/function.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/object.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/tensor.cc"
+#include "../3rdparty/tvm-ffi/src/ffi/traceback.cc"
#include "../src/runtime/cpu_device_api.cc"
#include "../src/runtime/device_api.cc"
#include "../src/runtime/file_utils.cc"
diff --git a/apps/ios_rpc/tvmrpc/TVMRuntime.mm b/apps/ios_rpc/tvmrpc/TVMRuntime.mm
index 8831210242..5dfff0cd86 100644
--- a/apps/ios_rpc/tvmrpc/TVMRuntime.mm
+++ b/apps/ios_rpc/tvmrpc/TVMRuntime.mm
@@ -33,7 +33,7 @@
#if defined(USE_CUSTOM_DSO_LOADER) && USE_CUSTOM_DSO_LOADER == 1
// internal TVM header to achieve Library class
-#include <../../../ffi/src/ffi/extra/library_module.h>
+#include <../../../3rdparty/tvm-ffi/src/ffi/extra/library_module.h>
#include <custom_dlfcn.h>
#endif
diff --git a/docs/install/from_source.rst b/docs/install/from_source.rst
index 2fc3a9e88b..ee81f84778 100644
--- a/docs/install/from_source.rst
+++ b/docs/install/from_source.rst
@@ -135,7 +135,7 @@ Therefore, after we finish the build, we need to install the tvm-ffi package.
.. code-block:: bash
- cd ffi; pip install .; cd ..
+ cd 3rdparty/tvm-ffi; pip install .; cd ..
Leaving the build environment ``tvm-build-venv``, there are two ways to install the successful build into your environment:
diff --git a/ffi/.clang-format b/ffi/.clang-format
deleted file mode 100644
index 9d622b98ba..0000000000
--- a/ffi/.clang-format
+++ /dev/null
@@ -1,8 +0,0 @@
-# Run the following command to reformat a file:
-# clang-format -i -style=Google <file>
-# Or use clang-format-diff to only reformat the changed lines:
-# https://clang.llvm.org/docs/ClangFormat.html
-BasedOnStyle: Google
-DerivePointerAlignment: false
-ColumnLimit: 100
-PointerAlignment: Left
diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt
deleted file mode 100644
index 2767669bce..0000000000
--- a/ffi/CMakeLists.txt
+++ /dev/null
@@ -1,262 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-cmake_minimum_required(VERSION 3.18)
-
-project(
- tvm_ffi
- LANGUAGES CXX C
-)
-
-option(TVM_FFI_USE_LIBBACKTRACE "Enable libbacktrace" ON)
-option(TVM_FFI_USE_EXTRA_CXX_API "Enable extra CXX API in shared lib" ON)
-option(TVM_FFI_BACKTRACE_ON_SEGFAULT "Set signal handler to print traceback on segfault" ON)
-
-if (TVM_FFI_USE_LIBBACKTRACE)
- include(${CMAKE_CURRENT_LIST_DIR}/cmake/Utils/AddLibbacktrace.cmake)
-endif()
-
-include(${CMAKE_CURRENT_LIST_DIR}/cmake/Utils/Library.cmake)
-
-
-########## Target: `tvm_ffi_header` ##########
-
-# they can be used in cases where user do not want to link into the library
-# in cases like deferred linking
-add_library(tvm_ffi_header INTERFACE)
-target_compile_features(tvm_ffi_header INTERFACE cxx_std_17)
-target_include_directories(
- tvm_ffi_header INTERFACE
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
- $<INSTALL_INTERFACE:include>
-)
-target_include_directories(
- tvm_ffi_header INTERFACE
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/dlpack/include>
- $<INSTALL_INTERFACE:include>
-)
-
-########## Target: `tvm_ffi_objs` ##########
-
-set(tvm_ffi_objs_sources
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/traceback.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/traceback_win.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/object.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/error.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/function.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/tensor.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/dtype.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/container.cc"
-)
-
-set(tvm_ffi_extra_objs_sources
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/structural_equal.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/structural_hash.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/json_parser.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/json_writer.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/serialization.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/reflection_extra.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/module.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/library_module.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/library_module_system_lib.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/library_module_dynamic_lib.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/env_context.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/env_c_api.cc"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/testing.cc"
-)
-if (TVM_FFI_USE_EXTRA_CXX_API)
- list(APPEND tvm_ffi_objs_sources ${tvm_ffi_extra_objs_sources})
-endif()
-
-add_library(tvm_ffi_objs OBJECT ${tvm_ffi_objs_sources})
-target_compile_features(tvm_ffi_objs PRIVATE cxx_std_17)
-
-set_target_properties(
- tvm_ffi_objs PROPERTIES
- POSITION_INDEPENDENT_CODE ON
- CXX_EXTENSIONS OFF
- CXX_STANDARD_REQUIRED ON
- CXX_VISIBILITY_PRESET hidden
- VISIBILITY_INLINES_HIDDEN ON
- PREFIX "lib"
-)
-
-# add the include path as public so they are visible to downstreams
-target_link_libraries(tvm_ffi_objs PUBLIC tvm_ffi_header)
-
-if (TVM_FFI_USE_LIBBACKTRACE)
- message(STATUS "Setting C++ macro TVM_FFI_USE_LIBBACKTRACE - 1")
- target_compile_definitions(tvm_ffi_objs PRIVATE TVM_FFI_USE_LIBBACKTRACE=1)
-else()
- message(STATUS "Setting C++ macro TVM_FFI_USE_LIBBACKTRACE - 0")
- target_compile_definitions(tvm_ffi_objs PRIVATE TVM_FFI_USE_LIBBACKTRACE=0)
-endif()
-
-if (TVM_FFI_BACKTRACE_ON_SEGFAULT)
- message(STATUS "Setting C++ macro TVM_FFI_BACKTRACE_ON_SEGFAULT - 1")
- target_compile_definitions(tvm_ffi_objs PRIVATE TVM_FFI_BACKTRACE_ON_SEGFAULT=1)
-else()
- message(STATUS "Setting C++ macro TVM_FFI_BACKTRACE_ON_SEGFAULT - 0")
- target_compile_definitions(tvm_ffi_objs PRIVATE TVM_FFI_BACKTRACE_ON_SEGFAULT=0)
-endif()
-
-tvm_ffi_add_msvc_flags(tvm_ffi_objs)
-tvm_ffi_add_target_from_obj(tvm_ffi tvm_ffi_objs)
-
-if (TARGET libbacktrace)
- target_link_libraries(tvm_ffi_objs PRIVATE libbacktrace)
- target_link_libraries(tvm_ffi_shared PRIVATE libbacktrace)
- target_link_libraries(tvm_ffi_static PRIVATE libbacktrace)
-endif ()
-
-if (MSVC)
- target_link_libraries(tvm_ffi_objs PRIVATE DbgHelp.lib)
- target_link_libraries(tvm_ffi_shared PRIVATE DbgHelp.lib)
- target_link_libraries(tvm_ffi_static PRIVATE DbgHelp.lib)
- # produce pdb file
- target_link_options(tvm_ffi_shared PRIVATE /DEBUG)
-endif ()
-
-# expose the headers as public dependencies
-target_link_libraries(tvm_ffi_objs PUBLIC tvm_ffi_header)
-target_link_libraries(tvm_ffi_shared PUBLIC tvm_ffi_header)
-target_link_libraries(tvm_ffi_static PUBLIC tvm_ffi_header)
-
-#----------------------------------------------------------------------------
-# The following code section only is triggered when the project is the root
-# and will be skipped when the project is a subproject.
-#----------------------------------------------------------------------------
-if (NOT ${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
- return()
-endif()
-
-option(TVM_FFI_ATTACH_DEBUG_SYMBOLS "Attach debug symbols even in release mode" OFF)
-option(TVM_FFI_BUILD_TESTS "Adding test targets." OFF)
-
-if (TVM_FFI_ATTACH_DEBUG_SYMBOLS)
- if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
- target_compile_options(tvm_ffi_objs PRIVATE -g1)
- endif()
-endif()
-
-include(cmake/Utils/CxxWarning.cmake)
-include(cmake/Utils/Sanitizer.cmake)
-
-# remap the file name to the source directory so we can see the
-# exact file name in traceback relative to the project source root
-tvm_ffi_add_prefix_map(tvm_ffi_objs ${CMAKE_SOURCE_DIR})
-
-########## Adding cpp tests ##########
-
-# logics below are only executed when the project is the root project.
-# but not when the project is a subproject.
-if (TVM_FFI_BUILD_TESTS)
- enable_testing()
- message(STATUS "Enable Testing")
- include(cmake/Utils/AddGoogleTest.cmake)
- add_subdirectory(tests/cpp/)
- tvm_ffi_add_cxx_warning(tvm_ffi_objs)
-endif()
-
-########## Adding python module ##########
-option(TVM_FFI_BUILD_PYTHON_MODULE "Adding python module." OFF)
-
-if (TVM_FFI_BUILD_PYTHON_MODULE)
- # Helper function to build the cython module
- message(STATUS "Building cython module..")
- find_package(
- Python COMPONENTS Interpreter Development.Module Development.SABIModule
- REQUIRED)
- set(core_cpp ${CMAKE_CURRENT_BINARY_DIR}/core.cpp)
- set(core_pyx ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/core.pyx)
- set(cython_sources
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/core.pyx
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/base.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/device.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/dtype.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/error.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/function.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/tensor.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/object.pxi
- ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/string.pxi
- )
- # set working directory to source so we can see the exact file name in traceback
- # relatived to the project source root
- add_custom_command(
- OUTPUT ${core_cpp}
- COMMAND ${Python_EXECUTABLE} -m cython --cplus ${core_pyx} -o ${core_cpp}
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMENT "Transpiling ${core_pyx} to ${core_cpp}"
- DEPENDS ${cython_sources}
- VERBATIM
- )
- if(Python_VERSION VERSION_GREATER_EQUAL "3.12")
- # >= Python3.12, use Use_SABI version
- Python_add_library(tvm_ffi_cython MODULE "${core_cpp}" USE_SABI 3.12)
- set_target_properties(tvm_ffi_cython PROPERTIES OUTPUT_NAME "core")
- if(NOT WIN32)
- set_target_properties(tvm_ffi_cython PROPERTIES SUFFIX ".abi3.so")
- endif()
- else()
- # before Python3.12, use WITH_SOABI version
- Python_add_library(tvm_ffi_cython MODULE "${core_cpp}" WITH_SOABI)
- set_target_properties(tvm_ffi_cython PROPERTIES OUTPUT_NAME "core")
- endif()
- target_include_directories(tvm_ffi_cython PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython)
- target_compile_features(tvm_ffi_cython PRIVATE cxx_std_17)
- target_link_libraries(tvm_ffi_cython PRIVATE tvm_ffi_header)
- target_link_libraries(tvm_ffi_cython PRIVATE tvm_ffi_shared)
- # Set RPATH for tvm_ffi_cython to find tvm_ffi_shared.so relatively
- if(APPLE)
- # macOS uses @loader_path
- set_target_properties(tvm_ffi_cython PROPERTIES INSTALL_RPATH "@loader_path/lib")
- elseif(LINUX)
- # Linux uses $ORIGIN
- set_target_properties(tvm_ffi_cython PROPERTIES INSTALL_RPATH "\$ORIGIN/lib")
- endif()
- install(TARGETS tvm_ffi_cython DESTINATION .)
-
- ########## Installing the source ##########
- install(
- DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/dlpack/include DESTINATION 3rdparty/dlpack/include
- )
- install(
- DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libbacktrace DESTINATION 3rdparty/libbacktrace
- PATTERN ".git" EXCLUDE
- PATTERN ".git*" EXCLUDE
- PATTERN "*.tmp" EXCLUDE
- )
- install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/ DESTINATION src/ffi/)
- install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils/ DESTINATION cmake/Utils)
- install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt DESTINATION .)
- install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tvm_ffi-config.cmake DESTINATION cmake)
-endif()
-
-########## Install the related for normal cmake library ##########
-
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/tvm/ffi/ DESTINATION include/tvm/ffi/)
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/dlpack/include/ DESTINATION include/)
-install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/tvm_ffi_python_helpers.h DESTINATION include/)
-install(TARGETS tvm_ffi_shared DESTINATION lib)
-# ship additional dSYM files for debugging symbols on if available
-if (APPLE)
- install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib/ DESTINATION lib FILES_MATCHING PATTERN "*.dSYM")
-endif()
-
-if (NOT TVM_FFI_BUILD_PYTHON_MODULE)
- # when building wheel, we do not ship static as we already ships source and dll
- install(TARGETS tvm_ffi_static DESTINATION lib)
-endif()
diff --git a/ffi/README.md b/ffi/README.md
deleted file mode 100644
index 3b1b1199c2..0000000000
--- a/ffi/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-
-# tvm ffi
diff --git a/ffi/cmake/Utils/AddGoogleTest.cmake b/ffi/cmake/Utils/AddGoogleTest.cmake
deleted file mode 100644
index af841752c6..0000000000
--- a/ffi/cmake/Utils/AddGoogleTest.cmake
+++ /dev/null
@@ -1,56 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-include(FetchContent)
-set(gtest_force_shared_crt ON CACHE BOOL "Always use msvcrt.dll" FORCE)
-set(BUILD_GMOCK ON CACHE BOOL "" FORCE)
-set(BUILD_GTEST ON CACHE BOOL "" FORCE)
-FetchContent_Declare(
- googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG v1.14.0
-)
-FetchContent_GetProperties(googletest)
-if (NOT googletest_POPULATED)
- FetchContent_MakeAvailable(googletest)
- include(GoogleTest)
- set_target_properties(gtest PROPERTIES EXPORT_COMPILE_COMMANDS OFF EXCLUDE_FROM_ALL ON FOLDER 3rdparty)
- set_target_properties(gtest_main PROPERTIES EXPORT_COMPILE_COMMANDS OFF EXCLUDE_FROM_ALL ON FOLDER 3rdparty)
- set_target_properties(gmock PROPERTIES EXPORT_COMPILE_COMMANDS OFF EXCLUDE_FROM_ALL ON FOLDER 3rdparty)
- set_target_properties(gmock_main PROPERTIES EXPORT_COMPILE_COMMANDS OFF EXCLUDE_FROM_ALL ON FOLDER 3rdparty)
- mark_as_advanced(
- BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS
- gmock_build_tests gtest_build_samples gtest_build_tests
- gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols
- )
-endif()
-
-macro(tvm_ffi_add_googletest target_name)
- add_test(
- NAME ${target_name}
- COMMAND ${target_name}
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- )
- target_link_libraries(${target_name} PRIVATE gtest_main)
- gtest_discover_tests(${target_name}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- DISCOVERY_MODE PRE_TEST
- PROPERTIES
- VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
- )
- set_target_properties(${target_name} PROPERTIES FOLDER tests)
-endmacro()
diff --git a/ffi/cmake/Utils/AddLibbacktrace.cmake b/ffi/cmake/Utils/AddLibbacktrace.cmake
deleted file mode 100644
index e920a1f199..0000000000
--- a/ffi/cmake/Utils/AddLibbacktrace.cmake
+++ /dev/null
@@ -1,68 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-include(ExternalProject)
-
-function(_libbacktrace_compile)
- set(_libbacktrace_source ${CMAKE_CURRENT_LIST_DIR}/../../3rdparty/libbacktrace)
- set(_libbacktrace_prefix ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace)
- if(CMAKE_SYSTEM_NAME MATCHES "Darwin" AND (CMAKE_C_COMPILER MATCHES "^/Library" OR CMAKE_C_COMPILER MATCHES "^/Applications"))
- set(_cmake_c_compiler "/usr/bin/cc")
- else()
- set(_cmake_c_compiler "${CMAKE_C_COMPILER}")
- endif()
-
- message(STATUS CMAKC_C_COMPILER="${CMAKE_C_COMPILER}")
-
- file(MAKE_DIRECTORY ${_libbacktrace_prefix}/include)
- file(MAKE_DIRECTORY ${_libbacktrace_prefix}/lib)
-
- ExternalProject_Add(project_libbacktrace
- PREFIX libbacktrace
- SOURCE_DIR ${_libbacktrace_source}
- BINARY_DIR ${_libbacktrace_prefix}
- CONFIGURE_COMMAND
- "sh"
- "${_libbacktrace_source}/configure"
- "--prefix=${_libbacktrace_prefix}"
- --with-pic
- "CC=${_cmake_c_compiler}"
- "CPP=${_cmake_c_compiler} -E"
- "CFLAGS=${CMAKE_C_FLAGS}"
- "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS}"
- "NM=${CMAKE_NM}"
- "STRIP=${CMAKE_STRIP}"
- "--host=${MACHINE_NAME}"
- INSTALL_DIR ${_libbacktrace_prefix}
- BUILD_COMMAND make
- INSTALL_COMMAND make install
- BUILD_BYPRODUCTS "${_libbacktrace_prefix}/lib/libbacktrace.a"
- "${_libbacktrace_prefix}/include/backtrace.h"
- )
- ExternalProject_Add_Step(project_libbacktrace checkout DEPENDERS configure DEPENDEES download)
- set_target_properties(project_libbacktrace PROPERTIES EXCLUDE_FROM_ALL TRUE)
- add_library(libbacktrace STATIC IMPORTED)
- add_dependencies(libbacktrace project_libbacktrace)
- set_target_properties(libbacktrace PROPERTIES
- IMPORTED_LOCATION ${_libbacktrace_prefix}/lib/libbacktrace.a
- INTERFACE_INCLUDE_DIRECTORIES ${_libbacktrace_prefix}/include
- )
-endfunction()
-
-if(NOT MSVC)
- _libbacktrace_compile()
-endif()
diff --git a/ffi/cmake/Utils/CxxWarning.cmake b/ffi/cmake/Utils/CxxWarning.cmake
deleted file mode 100644
index a85e58825b..0000000000
--- a/ffi/cmake/Utils/CxxWarning.cmake
+++ /dev/null
@@ -1,30 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-function(tvm_ffi_add_cxx_warning target_name)
- # GNU, Clang, or AppleClang
- if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
- target_compile_options(${target_name} PRIVATE "-Werror" "-Wall" "-Wextra" "-Wpedantic" "-Wno-unused-parameter")
- return()
- endif()
- # MSVC
- if(MSVC)
- # target_compile_options(${target_name} PRIVATE "/W4" "/WX")
- return()
- endif()
- message(FATAL_ERROR "Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}")
-endfunction()
diff --git a/ffi/cmake/Utils/Library.cmake b/ffi/cmake/Utils/Library.cmake
deleted file mode 100644
index 611f972dce..0000000000
--- a/ffi/cmake/Utils/Library.cmake
+++ /dev/null
@@ -1,88 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-function(tvm_ffi_add_prefix_map target_name prefix_path)
- # Add prefix map so the path displayed becomes relative to prefix_path
- if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
- target_compile_options(${target_name} PRIVATE "-ffile-prefix-map=${prefix_path}/=")
- endif()
-endfunction()
-
-function(tvm_ffi_add_apple_dsymutil target_name)
- # running dsymutil on macos to generate debugging symbols for backtraces
- if(APPLE AND TVM_FFI_USE_LIBBACKTRACE)
- find_program(DSYMUTIL dsymutil)
- mark_as_advanced(DSYMUTIL)
- add_custom_command(TARGET ${target_name}
- POST_BUILD
- COMMAND ${DSYMUTIL} ARGS $<TARGET_FILE:${target_name}>
- COMMENT "[COMMAND] dsymutil $<TARGET_FILE:${target_name}>"
- VERBATIM
- )
- endif()
-endfunction()
-
-function(tvm_ffi_add_msvc_flags target_name)
- # running if we are under msvc
- if(MSVC)
- target_compile_definitions(${target_name} PUBLIC -DWIN32_LEAN_AND_MEAN)
- target_compile_definitions(${target_name} PUBLIC -D_CRT_SECURE_NO_WARNINGS)
- target_compile_definitions(${target_name} PUBLIC -D_SCL_SECURE_NO_WARNINGS)
- target_compile_definitions(${target_name} PUBLIC -D_ENABLE_EXTENDED_ALIGNED_STORAGE)
- target_compile_definitions(${target_name} PUBLIC -DNOMINMAX)
- target_compile_options(${target_name} PRIVATE "/Zi")
- endif()
-endfunction()
-
-function(tvm_ffi_add_target_from_obj target_name obj_target_name)
- add_library(${target_name}_static STATIC $<TARGET_OBJECTS:${obj_target_name}>)
- set_target_properties(
- ${target_name}_static PROPERTIES
- OUTPUT_NAME "${target_name}_static"
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- )
- add_library(${target_name}_shared SHARED $<TARGET_OBJECTS:${obj_target_name}>)
- set_target_properties(
- ${target_name}_shared PROPERTIES
- OUTPUT_NAME "${target_name}"
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
- )
- if (WIN32)
- target_compile_definitions(${obj_target_name} PRIVATE TVM_FFI_EXPORTS)
- # set the output directory for each config type so msbuild also get into lib
- # without appending the config type to the output directory
- # do both Release and RELEASE suffix, since while cmake docs suggest Release is ok.
- # real runs on MSbuild suggest that we might need RELEASE instead
- foreach(CONFIG_TYPE Release RELEASE)
- set_target_properties(${target_name}_shared PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPE} "${CMAKE_BINARY_DIR}/lib"
- LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE} "${CMAKE_BINARY_DIR}/lib"
- ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE} "${CMAKE_BINARY_DIR}/lib"
- )
- set_target_properties(${target_name}_static PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPE} "${CMAKE_BINARY_DIR}/lib"
- LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE} "${CMAKE_BINARY_DIR}/lib"
- ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE} "${CMAKE_BINARY_DIR}/lib"
- )
- endforeach()
- endif()
- tvm_ffi_add_apple_dsymutil(${target_name}_shared)
-endfunction()
diff --git a/ffi/cmake/Utils/Sanitizer.cmake b/ffi/cmake/Utils/Sanitizer.cmake
deleted file mode 100644
index a20eead0c8..0000000000
--- a/ffi/cmake/Utils/Sanitizer.cmake
+++ /dev/null
@@ -1,35 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-function(add_sanitizer_address target_name)
- if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
- include(CheckCXXCompilerFlag)
- set (_saved_CRF ${CMAKE_REQUIRED_FLAGS})
- set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
- check_cxx_source_compiles("int main() { return 0; }" COMPILER_SUPPORTS_ASAN)
- set (CMAKE_REQUIRED_FLAGS ${_saved_CRF})
- get_target_property(_saved_type ${target_name} TYPE)
- if (${_saved_type} STREQUAL "INTERFACE_LIBRARY")
- set(_saved_type INTERFACE)
- else()
- set(_saved_type PRIVATE)
- endif()
- target_link_options(${target_name} ${_saved_type} "-fsanitize=address")
- target_compile_options(${target_name} ${_saved_type} "-fsanitize=address" "-fno-omit-frame-pointer" "-g")
- return()
- endif()
-endfunction()
diff --git a/ffi/cmake/tvm_ffi-config.cmake b/ffi/cmake/tvm_ffi-config.cmake
deleted file mode 100644
index 01f60ca10b..0000000000
--- a/ffi/cmake/tvm_ffi-config.cmake
+++ /dev/null
@@ -1,58 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-find_package(Python COMPONENTS Interpreter REQUIRED)
-
-# call tvm_ffi.config to get the cmake directory and set it to tvm_ffi_ROOT
-execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --includedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_INCLUDE_DIR)
-
-execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --dlpack-includedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_DLPACK_INCLUDE_DIR)
-
-execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --libfiles
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_LIB_FILES)
-
-message(STATUS "Finding libfiles ${tvm_ffi_LIB_FILES}")
-
-add_library(tvm_ffi_header INTERFACE)
-target_compile_features(tvm_ffi_header INTERFACE cxx_std_17)
-target_include_directories(tvm_ffi_header INTERFACE "${tvm_ffi_INCLUDE_DIR}")
-target_include_directories(tvm_ffi_header INTERFACE "${tvm_ffi_DLPACK_INCLUDE_DIR}")
-
-add_library(tvm_ffi_shared SHARED IMPORTED)
-target_compile_features(tvm_ffi_shared INTERFACE cxx_std_17)
-
-if(WIN32)
- set_target_properties(
- tvm_ffi_shared PROPERTIES IMPORTED_IMPLIB "${tvm_ffi_LIB_FILES}"
- )
-else()
- set_target_properties(
- tvm_ffi_shared PROPERTIES IMPORTED_LOCATION "${tvm_ffi_LIB_FILES}"
- )
-endif()
-
-set_target_properties(
- tvm_ffi_shared PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
- "${tvm_ffi_INCLUDE_DIR};${tvm_ffi_DLPACK_INCLUDE_DIR}"
-)
-# extra cmake functions
-include(${CMAKE_CURRENT_LIST_DIR}/Utils/Library.cmake)
diff --git a/ffi/docs/.gitignore b/ffi/docs/.gitignore
deleted file mode 100644
index d7ab85b91f..0000000000
--- a/ffi/docs/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-_build
-**/generated/*
diff --git a/ffi/docs/Makefile b/ffi/docs/Makefile
deleted file mode 100644
index 51e4de21d3..0000000000
--- a/ffi/docs/Makefile
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-# You can set these variables from the command line, and also
-# from the environment for the first two.
-SPHINXOPTS ?=
-SPHINXBUILD ?= python3 -m sphinx
-SOURCEDIR = .
-BUILDDIR = _build
-
-# Put it first so that "make" without argument is like "make help".
-help:
- @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-.PHONY: help Makefile livehtml clean
-
-livehtml:
- @sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) --ignore reference/cpp/generated
-
-clean:
- rm -rf $(BUILDDIR)
- rm -rf reference/python/generated
- rm -rf reference/cpp/generated
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
- @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/ffi/docs/README.md b/ffi/docs/README.md
deleted file mode 100644
index 39fff194df..0000000000
--- a/ffi/docs/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-# TVM FFI Documentation
-
-To build locally
-
-First install the tvm-ffi package
-```bash
-pip install ..
-```
-
-Install all the requirements to build docs
-
-```bash
-pip install -r requirements.txt
-```
-
-Then build the doc
-```bash
-make livehtml
-```
-
-## Build with C++ Docs
-
-To build with C++ docs, we need to first install Doxygen. Then
-set the environment variable `BUILD_CPP_DOCS=1`, to turn on c++ docs.
-
-```bash
-BUILD_CPP_DOCS=1 make livehtml
-```
-
-Building c++ docs can take longer, so it is not on by default.
diff --git a/ffi/docs/concepts/abi_overview.md b/ffi/docs/concepts/abi_overview.md
deleted file mode 100644
index 1182578964..0000000000
--- a/ffi/docs/concepts/abi_overview.md
+++ /dev/null
@@ -1,430 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-# ABI Overview
-
-This section provides an overview of the ABI convention of TVM FFI. The ABI
-is designed around the following key principles:
-
-- **Stable C ABI:** Core ABI is defined on top of a stable C ABI.
-- **Minimal and efficient:** Keep things simple when possible and bring close-to-metal efficiency.
-- **Focus on machine learning systems:** while also ensuring reasonable extensibility.
-
-To explain the concepts in the following sections, we will write in **low-level C/C++ code** when possible,
-so the code itself illustrates the low-level semantics of how to work with the ABI convention.
-These can serve as references for how to build language bindings and compiler codegen for the ABI.
-
-```{note}
-The authoritative ABI specifications are defined in [tvm/ffi/c_api.h](https://github.com/apache/tvm/blob/main/ffi/include/tvm/ffi/c_api.h) for core ABI,
-and [tvm/ffi/extra/c_env_api.h](https://github.com/apache/tvm/blob/main/ffi/include/tvm/ffi/extra/c_env_api.h) for extra support features
-such as stream handling. This document provides explanations about design concepts and rationales.
-```
-
-## Simplified Example
-
-Before diving into details, it is helpful to review at a high level
-what happens when a function is called in TVM FFI ABI.
-One main design goal here is to represent all kinds of functions in a single
-unified C signature. Please review the following
-simplified code example that illustrates the key idea:
-
-```c++
-// simplified struct for TVMFFIAny
-typedef struct TVMFFIAny {
- int32_t type_index;
- uint32_t zero_padding;
- // union values
- union {
- int64_t v_int64; // integers
- double v_float64; // floating-point numbers
- const char* v_c_str; // raw C-string
- };
-};
-
-// This is the signature of TVM FFI function ABI
-typedef int (*TVMFFISafeCallType)(
- void* handle, const TVMFFIAny* args, int32_t num_args, TVMFFIAny* result
-);
-
-// An example function signature
-int MyFunc(const char* param0, int param1);
-
-// This is what MyFunc looks like when exposed through TVM FFI ABI
-int MyFuncTVMFFISafeCall(
- void* handle, const TVMFFIAny* args, int32_t num_args, TVMFFIAny* result
-) {
- assert(args[0].type_index == kTVMFFIRawStr);
- assert(args[1].type_index == kTVMFFInt);
- result->type_index = kTVMFFInt;
- result->v_int64 = MyFunc(args[0].v_c_str, args[1].v_int64);
- // return value indicates no error occurred
- return 0;
-}
-
-// This is how we call the MyFuncTVMFFISafeCall
-// this can happen on the caller side in another language (e.g. python)
-int CallTVMFFISafeCall(const char* param0, int param1) {
- // arguments on stack
- TVMFFIAny args[2], result;
- args[0].type_index = kTVMFFIRawStr;
- args[0].v_c_str = param0;
- args[1].type_index = kTVMFFInt;
- args[1].v_int64 = param1;
- result.type_index = kTVMFFINone;
- // In this case we do not need handle
- // handle is used to hold closure pointers
- void* handle = nullptr;
- int num_args = 2;
- MyFuncTVMFFISafeCall(handle, args, num_args, &result);
- return result.v_int64;
-}
-```
-
-At a high level, the `TVMFFISafeCallType` signature does the following things:
-- Arguments and return values are stored in structured `TVMFFIAny`
- - Each value comes with a `type_index` to indicate its type
- - Values are stored in union fields, depending on the specific type.
-- Caller can explicitly store the type index and value into
- a stack of `TVMFFIAny`.
-- Callee can load the parameters from args and check their type indices.
-
-In this way, the same `TVMFFISafeCallType` can be used to represent any function
-that contains an arbitrary number of arguments and types that can be identified by `type_index`.
-Of course, this is a simplified example and we did not touch on specific details
-like Any value format and error handling. The following sections will provide a more systematic
-treatment of each of these specific topics.
-You can keep this example in mind as the overall picture and refine it as you read through
-the following sections.
-
-
-## TVMFFIAny Storage Format
-
-To start with, we need a mechanism to store the values that are passed across machine learning frameworks.
-It achieves this using a core data structure called TVMFFIAny.
-
-```c++
-typedef struct TVMFFIAny {
- int32_t type_index;
- union { // 4 bytes
- uint32_t zero_padding;
- uint32_t small_str_len;
- };
- // union values
- union {
- int64_t v_int64; // integers
- double v_float64; // floating-point numbers
- void* v_ptr; // typeless pointers
- const char* v_c_str; // raw C-string
- TVMFFIObject* v_obj; // ref counted objects
- DLDataType v_dtype; // data type
- DLDevice v_device; // device
- char v_bytes[8]; // small string
- ...
- };
-} TVMFFIAny;
-```
-
-TVMFFIAny is a 16-byte C structure that follows the design principle of tagged-union:
-
-- `type_index` helps us identify the type being stored.
-- The value union part is designed to store the value:
- - Small POD values (like integers and floats) are stored directly as "on-stack" values.
- - `v_obj` can also point to a managed heap-allocated object, which we will discuss next.
-- The second field stores metadata for small strings.
-
-
-### Storing a POD Value
-
-There are many values that are plain-old-data types. In such cases, we store them directly
-on-stack in the value part of the TVMFFIAny. The following example shows how to store
-an int.
-
-```c++
-void SetIntValue(TVMFFIAny* any, int value) {
- // must zero the entire space first
- any->type_index = kTVMFFIInt;
- any->zero_padding = 0;
- any->v_int64 = value;
-}
-```
-
-:::{note}
-
-We **must zero the content that is not being used** by
-the current value type. The following example shows a common place
-where mistakes can be made when we forget to zero the value field
-on 32-bit platforms (where pointers only fill the 32-bit part of the value).
-
-```c++
-void SetOpaquePtrValue(TVMFFIAny* any, void* opaque_ptr) {
- any->type_index = kTVMFFIOpaquePtr;
- // must zero the padding
- any->zero_padding = 0;
- // the zeroing is needed for 32-bit platforms!
- any->v_uint64 = 0;
- any->v_ptr = opaque_ptr;
-}
-```
-
-**Rationale:** Such invariants allow us to directly compare
-and hash TVMFFIAny in bytes for quick equality checks without going through
-type index switching.
-:::
-
-
-## Object Storage Format
-
-When TVMFFIAny points to a heap-allocated object (such as n-dimensional arrays),
-we adopt a unified object storage format, defined as follows:
-
-```c++
-typedef struct TVMFFIObject {
- int32_t type_index;
- uint32_t weak_ref_count;
- uint64_t strong_ref_count;
- union {
- void (*deleter)(struct TVMFFIObject* self, int flags);
- int64_t __ensure_align;
- };
-} TVMFFIObject;
-```
-
-`TVMFFIObject` defines a common 24-byte intrusive header that all in-memory objects share:
-
-- `type_index` helps us identify the type being stored, which is consistent with `TVMFFIAny.type_index`.
-- `weak_ref_count` stores the weak atomic reference counter of the object.
-- `strong_ref_count` stores the strong atomic reference counter of the object.
-- `deleter` should be called when either the strong or weak ref counter goes to zero.
- - The flags are set to indicate the event of either weak or strong going to zero, or both.
- - When `strong_ref_count` gets to zero, the deleter needs to call the destructor of the object.
- - When `weak_ref_count` gets to zero, the deleter needs to free the memory allocated by self.
-
-**Rationales:** There are several considerations when designing the data structure:
-- `type_index` enables runtime dynamic type checking and casting.
-- We introduce weak/strong ref counters so we can be compatible with systems that need weak pointers.
-- The weak ref counter is kept as 32-bit so we can pack the object header as 24 bytes.
-- `deleter` ensures that objects allocated from one language/runtime can be safely deleted in another.
-
-The object format provides a unified way to manage object life-cycle and dynamic type casting
-for heap-allocated objects, including Shape, Tensor,
-Function, Array, Map and other custom objects.
-
-
-### DLPack Compatible Tensor
-
-We provide first-class support for DLPack raw unmanaged pointer support as well as a managed Tensor object that
-directly adopts the DLPack DLTensor layout. The overall layout of the Tensor object is as follows:
-
-```c++
-struct TensorObj: public ffi::Object, public DLTensor {
-};
-```
-
-That means we can read out the array buffer information from an `TVMFFIAny`
-in the following way:
-
-```c++
-DLTensor* ReadDLTensorPtr(const TVMFFIAny *value) {
- if (value->type_index == kTVMFFIDLTensorPtr) {
- return static_cast<DLTensor*>(value->v_ptr);
- }
- assert(value->type_index == kTVMFFITensor);
- return reinterpret_cast<DLTensor*>(
- reinterpret_cast<char*>(value->v_obj) + sizeof(TVMFFIObject));
-}
-```
-The above code can be used as a reference to implement compiler codegen for data.
-Note that the C++ API automatically handles such conversion.
-
-### Advanced: Dynamic Type Index
-
-The `TVMFFITypeIndex` defines a set of type indices. Each built-in type has a corresponding statically
-assigned type index that is defined in the enum. Static type indices should be sufficient for most
-library use cases.
-For advanced use cases we also support user-defined objects whose `type_index` are assigned at startup time
-by calling `TVMFFITypeGetOrAllocIndex` with a unique
-`type_key` string. This design allows us to enable decentralized extension of the objects as long as the `type_key`
-values are unique by appending namespace prefix to the key.
-
-## AnyView and Managed Any
-
-An `TVMFFIAny` can either be treated as a strongly managed value (corresponding to `ffi::Any` in C++),
-or an unmanaged value (corresponding to `ffi::AnyView` in C++).
-- For POD types, there is no difference between the two
-- For object types, copying of AnyView should not change reference counters, while copying and deletion
- of managed Any should result in increase and decrease of strong reference counters.
-- When we convert AnyView to Any, we will convert raw C string `const char*` and `const TVMFFIByteArray*`
- into their managed counterparts (String and Bytes).
-- C API function `TVMFFIAnyViewToOwnedAny` is provided to perform such conversion.
-
-Unless the user is writing a compiler backend that needs low-level C style access, we encourage use of the
-C++ API to automatically manage conversion and casting between normal types and Any. The following code
-shows some example usage of the C++ API.
-
-```c++
-#include <tvm/ffi/any.h>
-
-void AnyExample() {
- namespace ffi = tvm::ffi;
- // Here is a managed any
- ffi::Any value = "hello world";
- // explicit cast to a specific type
- ffi::String str_value = value.cast<ffi::String>();
- // copy int to value
- value = 1;
- // copy into a view
- ffi::AnyView view = value;
- // cast view back to int
- std::cout << "Value is " << view.cast<int>() << std::endl;
-}
-```
-
-`ffi::Any` can serve as a container type to hold managed values that can be recognized by the TVM FFI system.
-They can be composed with container structures such as `Map<String, Any>`, `Array<Any>` to represent various
-broad patterns in APIs that may appear in ML systems.
-
-## Function Calling Convention
-
-As discussed in the overview, we need to consider foreign function calls as first-class citizens. We adopt a single standard C function as follows:
-
-```c++
-typedef int (*TVMFFISafeCallType)(
- void* handle, const TVMFFIAny* args, int32_t num_args, TVMFFIAny* result
-);
-```
-
-The handle contains the pointer to the function object itself, allowing us to support closures. args and num_args describe the input arguments and results store the return value. When args and results contain heap-managed objects, we expect the caller to own args and result.
-
-```{note}
-Before calling the function, caller must set `result->type_index` to be kTVMFFINone, or any type index that do not corresponds
-to an on-heap object.
-
-**Rationale:** Simplifies callee implementation as initial state of result can be viewed as managed Any.
-```
-
-We call this approach a packed function, as it provides a single signature to represent all functions in a "type-erased" way. It saves the need to declare and jit shim for each FFI function call while maintaining reasonable efficiency. This mechanism enables the following scenarios:
-- Calling from Dynamic Languages (e.g., Python): we provide a tvm_ffi binding that prepares the args based on dynamically examining Python arguments passed in.
-- Calling from Static Languages (e.g., C++): For static languages, we can leverage C++ templates to directly instantiate the arguments on the stack, saving the need for dynamic examination.
-- Dynamic language Callbacks: the signature enables us to easily bring dynamic language (Python) callbacks as ffi::Function, as we can take each argument and convert to the dynamic values.
-- Efficiency: In practice, we find this approach is sufficient for machine learning focused workloads. For example, we can get to microsecond level overhead for Python/C++ calls, which is generally similar to overhead for eager mode. When both sides of calls are static languages, the overhead will go down to tens of nanoseconds. As a side note, although we did not find it necessary, the signature still leaves room for link time optimization (LTO), when both sides are static languages wit [...]
-
-We support first-class Function objects that allow us to also pass function/closures from different places around, enabling cool usages such as quick python callback for prototyping, and dynamic Functor creation for driver-based kernel launching.
-
-
-## Error Handling
-
-Most TVM FFI C API calls, including `TVMFFISafeCallType` uses the return value to
-indicate whether an error happens. When an error happens during a function call,
-a non-zero value will be returned. The callee needs also to set the error through `TVMFFIErrorSetRaisedFromCStr` or `TVMFFIErrorSetRaised` API, which stores
-the error on a thread-local storage.
-
-```c++
-// Example function that raises an error
-int ErrorFunc(void* handle, const TVMFFIAny* args, int num_args, TVMFFIAny *result) {
- const char* error_kind = "RuntimeError";
- const char* error_msg = "error message";
- // set the thread-local error state
- TVMFFIErrorSetRaisedFromCStr(error_kind, error_msg);
- return -1;
-}
-```
-
-The caller can retrieve the error from thread-local error storage
-using `TVMFFIErrorMoveFromRaised` function.
-The ABI stores Error also as a specific Object,
-the overall error object is stored as follows
-```c++
-typedef struct {
- /*! \brief The kind of the error. */
- TVMFFIByteArray kind;
- /*! \brief The message of the error. */
- TVMFFIByteArray message;
- /*! \brief The traceback of the error. */
- TVMFFIByteArray traceback;
- /*!
- * \brief Function handle to update the traceback of the error.
- * \param self The self object handle.
- * \param traceback The traceback to update.
- */
- void (*update_traceback)(TVMFFIObjectHandle self, const TVMFFIByteArray* traceback);
-} TVMFFIErrorCell;
-
-// error object
-class ErrorObj : public ffi::Object, public TVMFFIErrorCell {
-};
-```
-
-The error object stores kind, message and traceback as string. When possible,
-we store the traceback in the same format of python traceback (see an example as follows):
-```
-File "src/extension.cc", line 45, in void my_ffi_extension::RaiseError(tvm::ffi::String)
-```
-
-We provide C++ object `ffi::Error` that can be throwed as exception in c++ environment. When we encounter
-the C ABI boundary, we will catch the error and call `TVMFFIErrorSetRaised` to propagate the error
-to the caller safely.
-`TVMFFIErrorSetRaisedFromCStr` is a convenient method to set error directly from C string and can be useful in compiler backend construction to implement features such as assert.
-
-**Rationales:** The error object contains minimal but sufficient information to reconstruct structured
-error in python side. We opt-for thread-local error state as it simplifies overall support.
-
-## String and Bytes
-
-The ABI supports strings and bytes as first-class citizens. A string can take multiple forms that are identified by
-its `type_index`.
-
-- `kTVMFFIRawStr`: raw C string terminated by `\0`.
-- `kTVMFFISmallStr`: small string, the length is stored in `small_str_len` and data is stored in `v_bytes`.
-- `kTVMFFIStr`: on-heap string object for strings that are longer than 7 characters.
-
-The following code shows the layout of the on-heap string object.
-```c++
-// span-like data structure to store header and length
-typedef struct {
- const char* data;
- size_t size;
-} TVMFFIByteArray;
-
-// showcase the layout of the on-heap string.
-class StringObj : public ffi::Object, public TVMFFIByteArray {
-};
-```
-
-The following code shows how to read a string from `TVMFFIAny`
-```c++
-TVMFFIByteArray ReadString(const TVMFFIAny *value) {
- TVMFFIByteArray ret;
- if (value->type_index == kTVMFFIRawStr) {
- ret.data = value->v_c_str;
- ret.size = strlen(ret.data);
- } else if (value->type_index == kTVMFFISmallStr) {
- ret.data = value->v_bytes;
- ret.size = value->small_str_len;
- } else {
- assert(value->type_index == kTVMFFIStr);
- ret = *reinterpret_cast<TVMFFIByteArray*>(
- reinterpret_cast<char*>(value->v_obj) + sizeof(TVMFFIObject));
- }
- return ret;
-}
-```
-
-Similarly, we have type indices to represent bytes. The C++ API provides classes
-`ffi::String` and `ffi::Bytes` to enable the automatic conversion of these values with Any storage format.
-
-**Rationales:** Separate string and bytes enable clear mappings from the Python side. Small string allows us to
-store short names on-stack. To favor 8-byte alignment (v_bytes) and keep things simple, we did not further
-pack characters into the `small_len` field.
diff --git a/ffi/docs/conf.py b/ffi/docs/conf.py
deleted file mode 100644
index 139254fd97..0000000000
--- a/ffi/docs/conf.py
+++ /dev/null
@@ -1,228 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-# -*- coding: utf-8 -*-
-import os
-import sys
-
-import tomli
-
-
-os.environ["TVM_FFI_BUILD_DOCS"] = "1"
-
-build_exhale = os.environ.get("BUILD_CPP_DOCS", "0") == "1"
-
-
-# -- General configuration ------------------------------------------------
-
-# Load version from pyproject.toml
-with open("../pyproject.toml", "rb") as f:
- pyproject_data = tomli.load(f)
-__version__ = pyproject_data["project"]["version"]
-
-project = "tvm-ffi"
-
-version = __version__
-release = __version__
-
-# -- Extensions and extension configurations --------------------------------
-
-extensions = [
- "breathe",
- "myst_parser",
- "nbsphinx",
- "autodocsumm",
- "sphinx.ext.autodoc",
- "sphinx.ext.autosectionlabel",
- "sphinx.ext.autosummary",
- "sphinx.ext.intersphinx",
- "sphinx.ext.mathjax",
- "sphinx.ext.napoleon",
- "sphinx.ext.viewcode",
- "sphinx.ext.ifconfig",
- "sphinx_copybutton",
- "sphinx_reredirects",
- "sphinx_tabs.tabs",
- "sphinx_toolbox.collapse",
- "sphinxcontrib.httpdomain",
- "sphinxcontrib.mermaid",
-]
-
-if build_exhale:
- extensions.append("exhale")
-
-breathe_default_project = "tvm-ffi"
-
-breathe_projects = {"tvm-ffi": "./_build/doxygen/xml"}
-
-exhaleDoxygenStdin = """
-INPUT = ../include
-PREDEFINED += TVM_FFI_DLL= TVM_FFI_INLINE= TVM_FFI_EXTRA_CXX_API= __cplusplus=201703
-
-EXCLUDE_SYMBOLS += *details* *TypeTraits* std \
- *use_default_type_traits_v* *is_optional_type_v* *operator* \
-
-EXCLUDE_PATTERNS += *details.h
-ENABLE_PREPROCESSING = YES
-MACRO_EXPANSION = YES
-"""
-
-exhaleAfterTitleDescription = """
-This page contains the full API index for the C++ API.
-"""
-
-# Setup the exhale extension
-exhale_args = {
- "containmentFolder": "reference/cpp/generated",
- "rootFileName": "index.rst",
- "doxygenStripFromPath": "../include",
- "rootFileTitle": "Full API Index",
- "createTreeView": True,
- "exhaleExecutesDoxygen": True,
- "exhaleDoxygenStdin": exhaleDoxygenStdin,
- "afterTitleDescription": exhaleAfterTitleDescription,
-}
-nbsphinx_allow_errors = True
-nbsphinx_execute = "never"
-
-autosectionlabel_prefix_document = True
-nbsphinx_allow_directives = True
-
-myst_enable_extensions = [
- "dollarmath",
- "amsmath",
- "deflist",
- "colon_fence",
- "html_image",
- "linkify",
- "attrs_block",
- "substitution",
-]
-
-myst_heading_anchors = 3
-myst_ref_domains = ["std", "py"]
-myst_all_links_external = False
-
-intersphinx_mapping = {
- "python": ("https://docs.python.org/3.12", None),
- "typing_extensions": ("https://typing-extensions.readthedocs.io/en/latest", None),
- "pillow": ("https://pillow.readthedocs.io/en/stable", None),
- "numpy": ("https://numpy.org/doc/stable", None),
- "torch": ("https://pytorch.org/docs/stable", None),
-}
-
-autodoc_mock_imports = ["torch"]
-autodoc_default_options = {
- "members": True,
- "undoc-members": True,
- "show-inheritance": True,
- "inherited-members": False,
- "member-order": "bysource",
-}
-
-# -- Other Options --------------------------------------------------------
-
-templates_path = []
-
-redirects = {}
-
-source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
-
-language = "en"
-
-exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "README.md"]
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = "sphinx"
-
-# A list of ignored prefixes for module index sorting.
-# If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = False
-
-# -- Options for HTML output ----------------------------------------------
-
-html_theme = "sphinx_book_theme"
-html_title = project
-html_copy_source = True
-html_last_updated_fmt = ""
-
-html_favicon = "https://tvm.apache.org/images/logo/tvm-logo-square.png"
-
-
-footer_dropdown = {
- "name": "ASF",
- "items": [
- ("ASF Homepage", "https://apache.org/"),
- ("License", "https://www.apache.org/licenses/"),
- ("Sponsorship", "https://www.apache.org/foundation/sponsorship.html"),
- ("Security", "https://tvm.apache.org/docs/reference/security.html"),
- ("Thanks", "https://www.apache.org/foundation/thanks.html"),
- ("Events", "https://www.apache.org/events/current-event"),
- ],
-}
-
-
-footer_copyright = "Copyright © 2025, Apache Software Foundation"
-footer_note = (
- "Apache TVM, Apache, the Apache feather, and the Apache TVM project "
- + "logo are either trademarks or registered trademarks of the Apache Software Foundation."
-)
-
-
-def footer_html():
- # Create footer HTML with two-line layout
- # Generate dropdown menu items
- dropdown_items = ""
- for item_name, item_url in footer_dropdown["items"]:
- dropdown_items += f'<li><a class="dropdown-item" href="{item_url}" target="_blank" style="font-size: 0.9em;">{item_name}</a></li>\n'
-
- footer_dropdown_html = f"""
- <div class="footer-container" style="margin: 5px 0; font-size: 0.9em; color: #6c757d;">
- <div class="footer-line1" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 3px;">
- <div class="footer-copyright-short">
- {footer_copyright}
- </div>
- <div class="footer-dropdown">
- <div class="dropdown">
- <button class="btn btn-link dropdown-toggle" type="button" id="footerDropdown" data-bs-toggle="dropdown"
- aria-expanded="false" style="font-size: 0.9em; color: #6c757d; text-decoration: none; padding: 0; border: none; background: none;">
- {footer_dropdown['name']}
- </button>
- <ul class="dropdown-menu" aria-labelledby="footerDropdown" style="font-size: 0.9em;">
-{dropdown_items} </ul>
- </div>
- </div>
- </div>
- <div class="footer-line2" style="font-size: 0.9em; color: #6c757d;">
- {footer_note}
- </div>
- </div>
- """
- return footer_dropdown_html
-
-
-html_theme_options = {
- "repository_url": "https://github.com/apache/tvm",
- "use_repository_button": True,
- "extra_footer": footer_html(),
-}
-
-html_context = {
- "display_github": True,
- "github_user": "apache",
- "github_version": "main",
- "conf_py_path": "/ffi/docs/",
-}
diff --git a/ffi/docs/get_started/install.md b/ffi/docs/get_started/install.md
deleted file mode 100644
index 87223d0114..0000000000
--- a/ffi/docs/get_started/install.md
+++ /dev/null
@@ -1,83 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-# Installation
-
-TVM FFI is built and tested on Windows, macOS, and various
-Linux distributions. You can install tvm-ffi using one of the
-methods below
-
-## Quick Start
-
-The easiest way to try it out is to install from PyPI.
-
-```bash
-pip install apache-tvm-ffi
-```
-
-After installation, you can run the following command to confirm that
-the installation was successful
-
-```bash
-tvm-ffi-config -h
-```
-
-This configuration tool is also useful in various ways to help you build
-libraries with tvm-ffi.
-
-
-## Install From Source
-
-You can also build and install tvm-ffi from source.
-
-### Dependencies
-
-- CMake (>= 3.24.0)
-- Git
-- A recent C++ compiler supporting C++17, at minimum:
- - GCC 7.1
- - Clang 5.0
- - Apple Clang 9.3
- - Visual Studio 2019 (v16.7)
-- Python (>= 3.9)
-
-
-Developers can clone the source repository from GitHub.
-
-```bash
-git clone --recursive https://github.com/apache/tvm tvm
-```
-
-```{note}
-It's important to use the ``--recursive`` flag when cloning the repository, which will
-automatically clone the submodules. If you forget to use this flag, you can manually clone the submodules
-by running ``git submodule update --init --recursive`` in the root directory.
-```
-
-Then you can install directly in development mode
-
-```bash
-cd tvm/ffi
-pip install -ve .
-```
-
-The additional `-e` flag will install the Python files in `editable` mode,
-which allows direct editing of the Python files to be immediately reflected in the package
-and is useful for development.
-
-## What to Do Next
-
-Now that you have installed TVM FFI, we recommend reading the [Quick Start](./quick_start.md) tutorial.
diff --git a/ffi/docs/get_started/quick_start.md b/ffi/docs/get_started/quick_start.md
deleted file mode 100644
index 4861aa87b2..0000000000
--- a/ffi/docs/get_started/quick_start.md
+++ /dev/null
@@ -1,213 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-# Quick Start
-
-This is a quick start guide explaining the basic features and usage of tvm-ffi.
-The source code can be found at `examples/quick_start` in the project source.
-
-## Build and Run the Example
-
-Let us first get started by build and run the example. The example will show us:
-
-- How to expose c++ functions as tvm ffi ABI function
-- How to load and run tvm-ffi based library from python
-- How to load and run tvm-ffi based library from c++
-
-
-Before starting, ensure you have:
-
-- TVM FFI installed following [installation](./install.md)
-- C++ compiler with C++17 support
-- CMake 3.18 or later
-- (Optional) CUDA toolkit for GPU examples
-- (Optional) PyTorch for checking torch integrations
-
-Then obtain a copy of the tvm-ffi source code.
-
-```bash
-git clone https://github.com/apache/tvm --recursive
-cd tvm/ffi
-```
-
-The examples are now in the example folder, you can quickly build
-the example using the following command.
-```bash
-cd examples/quick_start
-cmake -B build -S .
-cmake --build build
-```
-
-After the build finishes, you can run the python examples by
-```
-python run_example.py
-```
-
-You can also run the c++ example
-
-```
-./build/example
-```
-
-## Walk through the Example
-
-Now we have quickly try things out. Let us now walk through the details of the example.
-Specifically, in this example, we create a simple "add one" operation that adds 1 to each element of an input
-tensor and expose that function as TVM FFI compatible function. The key file structures are as follows:
-
-```
-examples/quick_start/
-├── src/
-│ ├── add_one_cpu.cc # CPU implementation
-│ ├── add_one_cuda.cu # CUDA implementation
-│ └── run_example.cc # C++ usage example
-├── run_example.py # Python usage example
-├── run_example.sh # Build and run script
-└── CMakeLists.txt # Build configuration
-```
-
-### CPU Implementation
-
-```cpp
-#include <tvm/ffi/dtype.h>
-#include <tvm/ffi/error.h>
-#include <tvm/ffi/function.h>
-
-namespace tvm_ffi_example {
-
-void AddOne(DLTensor* x, DLTensor* y) {
- // Validate inputs
- TVM_FFI_ICHECK(x->ndim == 1) << "x must be a 1D tensor";
- DLDataType f32_dtype{kDLFloat, 32, 1};
- TVM_FFI_ICHECK(x->dtype == f32_dtype) << "x must be a float tensor";
- TVM_FFI_ICHECK(y->ndim == 1) << "y must be a 1D tensor";
- TVM_FFI_ICHECK(y->dtype == f32_dtype) << "y must be a float tensor";
- TVM_FFI_ICHECK(x->shape[0] == y->shape[0]) << "x and y must have the same shape";
-
- // Perform the computation
- for (int i = 0; i < x->shape[0]; ++i) {
- static_cast<float*>(y->data)[i] = static_cast<float*>(x->data)[i] + 1;
- }
-}
-
-// Expose the function through TVM FFI
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one_cpu, tvm_ffi_example::AddOne);
-}
-```
-
-**Key Points:**
-- Functions take `DLTensor*` parameters for cross-language compatibility
-- The `TVM_FFI_DLL_EXPORT_TYPED_FUNC` macro exposes the function with a given name
-
-### CUDA Implementation
-
-```cpp
-void AddOneCUDA(DLTensor* x, DLTensor* y) {
- // Validation (same as CPU version)
- // ...
-
- int64_t n = x->shape[0];
- int64_t nthread_per_block = 256;
- int64_t nblock = (n + nthread_per_block - 1) / nthread_per_block;
-
- // Get current CUDA stream from environment
- cudaStream_t stream = static_cast<cudaStream_t>(
- TVMFFIEnvGetStream(x->device.device_type, x->device.device_id));
-
- // Launch kernel
- AddOneKernel<<<nblock, nthread_per_block, 0, stream>>>(
- static_cast<float*>(x->data), static_cast<float*>(y->data), n);
-}
-
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one_cuda, tvm_ffi_example::AddOneCUDA);
-```
-
-**Key Points:**
-- We use `TVMFFIEnvGetStream` to obtain the current stream from the environement
-- When invoking ffi Function from python end with PyTorch tensor as argument,
- the stream will be populated with torch's current stream.
-
-
-### Working with PyTorch
-
-Atfer build, we will create library such as `build/add_one_cuda.so`, that can be loaded by
-with api {py:func}`tvm_ffi.load_module` that returns a {py:class}`tvm_ffi.Module`
-Then the function will become available as property of the loaded module.
-The tensor arguments in the ffi functions automatically consumes `torch.Tensor`. The following code shows how
-to use the function in torch.
-
-```python
-import torch
-import tvm_ffi
-
-if torch.cuda.is_available():
- mod = tvm_ffi.load_module("build/add_one_cuda.so")
-
- x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32, device="cuda")
- y = torch.empty_like(x)
-
- # TVM FFI automatically handles CUDA streams
- stream = torch.cuda.Stream()
- with torch.cuda.stream(stream):
- mod.add_one_cuda(x, y)
- stream.synchronize()
-```
-
-### Working with Python Data Arrays
-
-TVM FFI functions works automaticaly with python data arrays that are compatible with dlpack.
-The following examples how to use the function with numpy.
-
-```python
-import tvm_ffi
-import numpy as np
-
-# Load the compiled module
-mod = tvm_ffi.load_module("build/add_one_cpu.so")
-
-# Create input and output arrays
-x = np.array([1, 2, 3, 4, 5], dtype=np.float32)
-y = np.empty_like(x)
-
-# Call the function
-mod.add_one_cpu(x, y)
-print("Result:", y) # [2, 3, 4, 5, 6]
-```
-
-### Working with C++
-
-One important design goal of tvm-ffi is to be universally portable.
-As a result, the result libraries do not have explicit dependencies in python
-and can be loaded in other language environments, such as c++. The following code
-shows how to run the example exported function in C++.
-
-```cpp
-#include <tvm/ffi/container/tensor.h>
-#include <tvm/ffi/extra/module.h>
-
-void CallAddOne(DLTensor* x, DLTensor *y) {
- namespace ffi = tvm::ffi;
- ffi::Module mod = ffi::Module::LoadFromFile("build/add_one_cpu.so");
- ffi::Function add_one_cpu = mod->GetFunction("add_one_cpu").value();
- add_one_cpu(x, y);
-}
-```
-
-## Summary Key Concepts
-
-- **TVM_FFI_DLL_EXPORT_TYPED_FUNC** exposes a c++ function into tvm-ffi C ABI
-- **DLTensor** is a universal tensor structure that enables zero-copy exchange of array data
-- **Module loading** is provided by tvm ffi APIs in multiple languages.
diff --git a/ffi/docs/guides/cpp_guide.md b/ffi/docs/guides/cpp_guide.md
deleted file mode 100644
index a27fe2dac1..0000000000
--- a/ffi/docs/guides/cpp_guide.md
+++ /dev/null
@@ -1,584 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-{#cpp-guide}
-
-# C++ Guide
-
-This guide introduces the tvm-ffi C++ API.
-We provide C++ API on top of the stable C ABI to provide a type-safe and efficient way to work with the tvm-ffi.
-The C++ API is designed to abstract away the complexity of the C ABI while maintaining full compatibility.
-The C++ API builds around the following key concepts:
-
-- **Any and AnyView**: Type-erased containers that can hold values of any supported type in tvm-ffi.
-- **Function**: A type-erased "packed" function that can be invoked like normal functions.
-- **Objects and ObjectRefs**: Reference-counted objects to manage on-heap data types.
-
-Code examples in this guide use `EXPECT_EQ` for demonstration purposes, which is a testing framework macro. In actual applications, you would use standard C++ assertions or error handling.
-You can find runnable code of the examples under tests/cpp/test_example.cc.
-
-## Any and AnyView
-
-`Any` and `AnyView` are the foundation of tvm-ffi, providing
-ways to store values that are compatible with the ffi system.
-The following example shows how we can interact with Any and AnyView.
-
-```cpp
-
-#include <tvm/ffi/any.h>
-
-void ExampleAny() {
- namespace ffi = tvm::ffi;
- // Create an Any from various types
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- ffi::Any int_value = 42;
- ffi::Any float_value = 3.14;
- ffi::Any string_value = "hello world";
-
- // AnyView provides a lightweight view without ownership
- ffi::AnyView view = int_value;
- // we can cast Any/AnyView to a specific type
- int extracted = view.cast<int>();
- EXPECT_EQ(extracted, 42);
-
- // If we are not sure about the type
- // we can use as to get an optional value
- std::optional<int> maybe_int = view.as<int>();
- if (maybe_int.has_value()) {
- EXPECT_EQ(maybe_int.value(), 42);
- }
- // Try cast is another version that will try to run the type
- // conversion even if the type does not exactly match
- std::optional<int> maybe_int_try = view.try_cast<int>();
- if (maybe_int_try.has_value()) {
- EXPECT_EQ(maybe_int_try.value(), 42);
- }
-}
-```
-
-At a high level, we can perform the following operations:
-
-- We can store a value into Any, under the hood, Any will record the type of the value by its type_index.
-- We can fetch a value from Any or AnyView using the `cast` function.
-- If we are unsure about the type in Any, we can use `as` or `try_cast` function to get an optional value.
-
-Under the hood, Any and AnyView store the value via the ABI convention and also manage the reference
-counting correctly when the stored value is an on-heap object.
-
-## Object and ObjectRef
-
-The tvm-ffi object system provides the foundation for all managed, reference-counted objects
-in the system. It enables type safety, cross-language compatibility, and efficient memory management.
-
-The object system is built around three key classes: Object, ObjectPtr, and ObjectRef.
-The `Object` class is the base class of all heap-allocated objects. It contains a common header
-that includes the `type_index`, reference counter and deleter for the object.
-Users do not need to explicitly manage these fields as part of the C++ API. Instead,
-they are automatically managed through a smart pointer `ObjectPtr` which points
-to a heap-allocated object instance.
-The following code shows an example object and the creation of an `ObjectPtr`:
-
-```cpp
-#include <tvm/ffi/object.h>
-#include <tvm/ffi/memory.h>
-
-class MyIntPairObj : public tvm::ffi::Object {
- public:
- int64_t a;
- int64_t b;
-
- MyIntPairObj() = default;
- MyIntPairObj(int64_t a, int64_t b) : a(a), b(b) {}
-
- // Required: declare type information
- // to register a dynamic type index through the system
-TVM_FFI_DECLARE_OBJECT_INFO_FINAL("example.MyIntPair", MyIntPairObj, tvm::ffi::Object);
-};
-
-void ExampleObjectPtr() {
- namespace ffi = tvm::ffi;
- // make_object automatically sets up the deleter correctly
- // This function creates a new ObjectPtr with proper memory management
- // It handles allocation, initialization, and sets up the reference counting system
- ffi::ObjectPtr<MyIntPairObj> obj = ffi::make_object<MyIntPairObj>(100, 200);
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(obj->a, 100);
- EXPECT_EQ(obj->b, 200);
-}
-```
-
-We typically provide a reference class that wraps the ObjectPtr.
-The `ObjectRef` base class provides the interface and reference counting
-functionality for these wrapper classes.
-```cpp
-#include <tvm/ffi/object.h>
-#include <tvm/ffi/memory.h>
-
-class MyIntPair : public tvm::ffi::ObjectRef {
- public:
- // Constructor
- explicit MyIntPair(int64_t a, int64_t b) {
- data_ = tvm::ffi::make_object<MyIntPairObj>(a, b);
- }
-
- // Required: define object reference methods
- // This macro provides the necessary methods for ObjectRef functionality
- TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(MyIntPair, tvm::ffi::ObjectRef, MyIntPairObj);
-};
-
-void ExampleObjectRef() {
- namespace ffi = tvm::ffi;
- MyIntPair pair(100, 200);
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(pair->a, 100);
- EXPECT_EQ(pair->b, 200);
-}
-```
-
-**Note:** The ObjectRef provides a user-friendly interface while ObjectPtr handles the low-level memory management.
-The ObjectRef acts as a smart pointer wrapper that automatically manages the ObjectPtr lifecycle.
-
-The overall implementation pattern is as follows:
-- **Object Class**: Inherits from `ffi::Object`, stores data and implements the core functionality.
-- **ObjectPtr**: Smart pointer that manages the Object lifecycle and reference counting.
-- **Ref Class**: Inherits from `ffi::ObjectRef`, provides a user-friendly interface and automatic memory management.
-
-This design ensures efficient memory management while providing a clean API for users. Once we define an ObjectRef class,
-we can integrate it with the Any, AnyView and Functions.
-
-```cpp
-#include <tvm/ffi/object.h>
-#include <tvm/ffi/any.h>
-
-void ExampleObjectRefAny() {
- namespace ffi = tvm::ffi;
- MyIntPair pair(100, 200);
- ffi::Any any = pair;
- MyIntPair pair2 = any.cast<MyIntPair>();
- // Note: EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(pair2->a, 100);
- EXPECT_EQ(pair2->b, 200);
-}
-
-```
-
-Under the hood, ObjectPtr manages the lifecycle of the object through the same mechanism as shared pointers. We designed
-the object to be intrusive, which means the reference counter and type index metadata are embedded at the header of each object.
-This design allows us to allocate the control block and object memory together. As we will see in future sections,
-all of our heap-allocated classes such as Function, on-heap String, Array and Map are managed using subclasses of Object,
-and the user-facing classes such as Function are ObjectRefs.
-
-
-We provide a collection of built-in object and reference types, which are sufficient for common cases.
-Developers can also bring new object types as shown in the example of this section. We provide mechanisms
-to expose these objects to other language bindings such as Python.
-
-
-## Function
-
-The `Function` class provides a type-safe way to create and invoke callable objects
-through tvm-ffi ABI convention. We can create a `ffi::Function` from an existing typed lambda function.
-
-```cpp
-#include <tvm/ffi/function.h>
-
-void ExampleFunctionFromTyped() {
- namespace ffi = tvm::ffi;
- // Create a function from a typed lambda
- ffi::Function fadd1 = ffi::Function::FromTyped(
- [](const int a) -> int { return a + 1; }
- );
- int b = fadd1(1).cast<int>();
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(b, 2);
-}
-```
-
-Under the hood, tvm-ffi leverages Any and AnyView to create a unified ABI for
-all functions. The following example demonstrates the low-level way of defining
-a "packed" function for the same `fadd1`.
-
-```cpp
-void ExampleFunctionFromPacked() {
- namespace ffi = tvm::ffi;
- // Create a function from a typed lambda
- ffi::Function fadd1 = ffi::Function::FromPacked(
- [](const ffi::AnyView* args, int32_t num_args, ffi::Any* rv) {
- // Check that we have exactly one argument
- TVM_FFI_ICHECK_EQ(num_args, 1);
- int a = args[0].cast<int>();
- *rv = a + 1;
- }
- );
- int b = fadd1(1).cast<int>();
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(b, 2);
-}
-```
-
-At a high level, `ffi::Function` implements function calling by the following convention:
-- The arguments are passed through an on-stack array of `ffi::AnyView`
-- Return values are passed through `ffi::Any`
-
-Because the return value is `ffi::Any`, we need to explicitly call `cast` to convert the return
-value to the desirable type. Importantly, `ffi::Function` itself is a value type that is compatible
-with tvm-ffi, which means we can pass it as an argument and return values. The following code shows
-an example of passing a function as an argument and applying it inside.
-
-```cpp
-void ExampleFunctionPassFunction() {
- namespace ffi = tvm::ffi;
- // Create a function from a typed lambda
- ffi::Function fapply = ffi::Function::FromTyped(
- [](const ffi::Function f, ffi::Any param) { return f(param.cast<int>()); });
- ffi::Function fadd1 = ffi::Function::FromTyped( //
- [](const int a) -> int { return a + 1; });
- int b = fapply(fadd1, 2).cast<int>();
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(b, 3);
-}
-```
-
-This pattern is very powerful because we can construct `ffi::Function` not only from C++,
-but from any languages that expose to the tvm-ffi ABI. For example, this means we can easily call functions
-passed in or registered from Python for quick debugging or other purposes.
-
-
-### Global Function Registry
-
-Besides creating functions locally, tvm-ffi provides a global function registry that allows
-functions to be registered and called across different modules and languages.
-The following code shows an example
-
-```cpp
-#include <tvm/ffi/function.h>
-#include <tvm/ffi/reflection/registry.h>
-
-void ExampleGlobalFunctionRegistry() {
- namespace ffi = tvm::ffi;
- ffi::reflection::GlobalDef().def("xyz.add1", [](const int a) -> int { return a + 1; });
- ffi::Function fadd1 = ffi::Function::GetGlobalRequired("xyz.add1");
- int b = fadd1(1).cast<int>();
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(b, 2);
-}
-```
-
-You can also access and register global functions from the Python API.
-
-### Exporting as Library Symbol
-
-Besides the API that allows registration of functions into the global table,
-we also provide a macro to export static functions as `TVMFFISafeCallType` symbols in a dynamic library.
-
-```c++
-void AddOne(DLTensor* x, DLTensor* y) {
- // ... implementation omitted ...
-}
-
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one, my_ffi_extension::AddOne);
-```
-
-The new `add_one` takes the signature of `TVMFFISafeCallType` and can be wrapped as `ffi::Function`
-through the C++ `ffi::Module` API.
-
-```cpp
-ffi::Module mod = ffi::Module::LoadFromFile("path/to/export_lib.so");
-ffi::Function func = mod->GetFunction("add_one").value();
-```
-
-## Error Handling
-
-We provide a specific `ffi::Error` type that is also made compatible with the ffi ABI.
-We also provide a macro `TVM_FFI_THROW` to simplify the error throwing step.
-
-```cpp
-// file: cpp/test_example.cc
-#include <tvm/ffi/error.h>
-
-void FuncThrowError() {
- namespace ffi = tvm::ffi;
- TVM_FFI_THROW(TypeError) << "test0";
-}
-
-void ExampleErrorHandling() {
- namespace ffi = tvm::ffi;
- try {
- FuncThrowError();
- } catch (const ffi::Error& e) {
- EXPECT_EQ(e.kind(), "TypeError");
- EXPECT_EQ(e.message(), "test0");
- std::cout << e.traceback() << std::endl;
- }
-}
-```
-The structured error class records kind, message and traceback that can be mapped to
-Pythonic style error types and tracebacks. The traceback follows the Python style,
-tvm-ffi will try to preserve the traceback when possible. In the above example,
-you can see the traceback output as
-```
-... more lines omitted
-File "cpp/test_example.cc", line 106, in ExampleErrorHandling
-File "cpp/test_example.cc", line 100, in void FuncThrowError()
-```
-
-The ffi ABI provides minimal but sufficient mechanisms to propagate these errors across
-language boundaries.
-So when we call the function from Python, the Error will be translated into a corresponding
-Error type. Similarly, when we call a Python callback from C++, the error will be translated
-into the right error kind and message.
-
-
-## Tensor
-
-For many use cases, we do not need to manage the nd-array/Tensor memory.
-In such cases, `DLTensor*` can be used as the function arguments.
-There can be cases for a managed container for multi-dimensional arrays.
-`ffi::Tensor` is a minimal container to provide such support.
-Notably, specific logic of device allocations and array operations are non-goals
-of the FFI. Instead, we provide minimal generic API `ffi::Tensor::FromNDAlloc`
-to enable flexible customization of Tensor allocation.
-
-```cpp
-#include <tvm/ffi/container/tensor.h>
-#include <tvm/ffi/container/shape.h>
-
-struct CPUNDAlloc {
- void AllocData(DLTensor* tensor) {
- tensor->data = malloc(tvm::ffi::GetDataSize(*tensor));
- }
- void FreeData(DLTensor* tensor) { free(tensor->data); }
-};
-
-void ExampleTensor() {
- namespace ffi = tvm::ffi;
- ffi::Shape shape = {1, 2, 3};
- DLDataType dtype = {kDLFloat, 32, 1};
- DLDevice device = {kDLCPU, 0};
- ffi::Tensor tensor = ffi::Tensor::FromNDAlloc(CPUNDAlloc(), shape, dtype, device);
- // now tensor is a managed tensor
-}
-```
-
-The above example shows how we define `CPUNDAlloc` that customizes `AllocData`
-and `FreeData` behavior. The CPUNDAlloc struct will be kept alive with the Tensor object.
-This pattern allows us to implement various Tensor allocations using the same API:
-
-- For CUDA allocation, we can change malloc to cudaMalloc
-- For memory-pool based allocation, we can update `CPUNDAlloc` to keep a strong reference to the pool,
- so we can keep memory-pool alive when the array is alive.
-
-**Working with Shapes** As you may have noticed in the example, we have a `ffi::Shape` container that is used
-to represent the shapes in nd-array. This container allows us to have compact and efficient representation
-of managed shapes and we provide quick conversions from standard vector types.
-
-### DLPack Conversion
-
-We provide first-class DLPack support to the `ffi::Tensor` that enables efficient exchange
-through the DLPack Protocol.
-
-```cpp
-#include <tvm/ffi/container/tensor.h>
-
-void ExampleTensorDLPack() {
- namespace ffi = tvm::ffi;
- ffi::Shape shape = {1, 2, 3};
- DLDataType dtype = {kDLFloat, 32, 1};
- DLDevice device = {kDLCPU, 0};
- ffi::Tensor tensor = ffi::Tensor::FromNDAlloc(CPUNDAlloc(), shape, dtype, device);
- // convert to DLManagedTensorVersioned
- DLManagedTensorVersioned* dlpack = nd.ToDLPackVersioned();
- // load back from DLManagedTensorVersioned
- ffi::Tensor tensor2 = ffi::Tensor::FromDLPackVersioned(dlpack);
-}
-```
-
-These APIs are also available through the C APIs
-`TVMFFITensorFromDLPackVersioned` and `TVMFFITensorToDLPackVersioned`.
-
-## String and Bytes
-
-The tvm-ffi provides first-class support for `String` and `Bytes` types that are efficient,
-FFI-compatible, and interoperable with standard C++ string types.
-
-```cpp
-#include <tvm/ffi/string.h>
-
-void ExampleString() {
- namespace ffi = tvm::ffi;
- ffi::String str = "hello world";
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(str.size(), 11);
- std::string std_str = str;
- EXPECT_EQ(std_str, "hello world");
-}
-```
-
-Alternatively, users can always directly use `std::string` in function arguments, conversion
-will happen automatically.
-
-**Rationale:** We need to have separate Bytes and String so they map well to corresponding Python types.
-`ffi::String` is backed by a possibly managed object that makes it more compatible with the Object system.
-
-## Container Types
-
-To enable effective passing and storing of collections of values that are compatible with tvm-ffi,
-we provide several built-in container types.
-
-### Array
-
-`Array<T>` provides an array data type that can be used as function arguments.
-When we use `Array<T>` as an argument of a Function, it will
-perform runtime checks of the elements to ensure the values match the expected type.
-
-```cpp
-#include <tvm/ffi/container/array.h>
-
-
-void ExampleArray() {
- namespace ffi = tvm::ffi;
- ffi::Array<int> numbers = {1, 2, 3};
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(numbers.size(), 3);
- EXPECT_EQ(numbers[0], 1);
-
- ffi::Function head = ffi::Function::FromTyped([](const ffi::Array<int> a) {
- return a[0];
- });
- EXPECT_EQ(head(numbers).cast<int>(), 1);
-
- try {
- // throw an error because 2.2 is not int
- head(ffi::Array<ffi::Any>({1, 2.2}));
- } catch (const ffi::Error& e) {
- EXPECT_EQ(e.kind(), "TypeError");
- }
-}
-```
-
-Under the hood, Array is backed by a reference-counted Object `ArrayObj` that stores
-a collection of Any values. Note that conversion from Any to `Array<T>` will result in
-runtime checks of elements because the type index only indicates `ArrayObj` as the backing storage.
-If you want to defer such checks at the FFI function boundary, consider using `Array<Any>` instead.
-When passing lists and tuples from Python, the values will be converted to `Array<Any>` before
-being passed into the Function.
-
-**Performance note:** Repeatedly converting Any to `Array<T>` can incur repeated
-checking overhead at each element. Consider using `Array<Any>` to defer checking or only run conversion once.
-
-### Tuple
-
-`Tuple<Types...>` provides type-safe fixed-size collections.
-
-```cpp
-#include <tvm/ffi/container/tuple.h>
-
-void ExampleTuple() {
- namespace ffi = tvm::ffi;
- ffi::Tuple<int, ffi::String, bool> tup(42, "hello", true);
-
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(tup.get<0>(), 42);
- EXPECT_EQ(tup.get<1>(), "hello");
- EXPECT_EQ(tup.get<2>(), true);
-}
-```
-
-Under the hood, Tuple is backed by the same `ArrayObj` as the Array container.
-This enables zero-cost exchange with input arguments.
-
-**Rationale:** This design unifies the conversion rules from Python list/tuple to
-Array/Tuple. We always need a container representation for tuples
-to be stored in Any.
-
-### Map
-
-`Map<K, V>` provides a key-value based hashmap container that can accept dict-style parameters.
-
-```cpp
-#include <tvm/ffi/container/map.h>
-
-void ExampleMap() {
- namespace ffi = tvm::ffi;
-
- ffi::Map<ffi::String, int> map0 = {{"Alice", 100}, {"Bob", 95}};
-
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(map0.size(), 2);
- EXPECT_EQ(map0.at("Alice"), 100);
- EXPECT_EQ(map0.count("Alice"), 1);
-}
-```
-
-
-Under the hood, Map is backed by a reference-counted Object `MapObj` that stores
-a collection of Any values. The implementation provides a SmallMap variant that stores
-values as an array and another variant that is based on a hashmap. The Map preserves insertion
-order like Python dictionaries. Conversion from Any to `Map<K, V>` will result in
-runtime checks of its elements because the type index only indicates `MapObj` as the backing storage.
-If you want to defer such checks at the FFI function boundary, consider using `Map<Any, Any>` instead.
-When passing dictionaries from Python, the values will be converted to `Map<Any, Any>` before
-being passed into the Function.
-
-**Performance note:** Repeatedly converting Any to `Map<K, V>` can incur repeated
-checking overhead at each element. Consider using `Map<Any, Any>` to defer checking or only run conversion once.
-
-### Optional
-
-`Optional<T>` provides a safe way to handle values that may or may not exist.
-We specialize Optional for `ffi::String` and Object types to be more compact,
-using nullptr to indicate non-existence.
-
-```cpp
-#include <tvm/ffi/container/optional.h>
-
-void ExampleOptional() {
- namespace ffi = tvm::ffi;
- ffi::Optional<int> opt0 = 100;
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(opt0.has_value(), true);
- EXPECT_EQ(opt0.value(), 100);
-
- ffi::Optional<ffi::String> opt1;
- EXPECT_EQ(opt1.has_value(), false);
- EXPECT_EQ(opt1.value_or("default"), "default");
-}
-```
-
-
-### Variant
-
-`Variant<Types...>` provides a type-safe union of different types.
-
-```cpp
-#include <tvm/ffi/container/variant.h>
-
-void ExampleVariant() {
- namespace ffi = tvm::ffi;
- ffi::Variant<int, ffi::String> var0 = 100;
- // EXPECT_EQ is used here for demonstration purposes (testing framework)
- EXPECT_EQ(var0.get<int>(), 100);
-
- var0 = ffi::String("hello");
- std::optional<ffi::String> maybe_str = var0.as<ffi::String>();
- EXPECT_EQ(maybe_str.value(), "hello");
-
- std::optional<int> maybe_int2 = var0.as<int>();
- EXPECT_EQ(maybe_int2.has_value(), false);
-}
-```
-
-Under the hood, Variant is a wrapper around Any that restricts the type to the specific types in the list.
diff --git a/ffi/docs/guides/packaging.md b/ffi/docs/guides/packaging.md
deleted file mode 100644
index c12fe4e307..0000000000
--- a/ffi/docs/guides/packaging.md
+++ /dev/null
@@ -1,282 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-# Packaging
-
-This guide explains how to package a tvm-ffi-based library into a Python ABI-agnostic wheel.
-It demonstrates both source-level builds (for cross-compilation) and builds based on pre-shipped shared libraries.
-At a high level, packaging with tvm-ffi offers several benefits:
-
-- **ABI-agnostic wheels**: Works across different Python versions with minimal dependency.
-- **Universally deployable**: Build once with tvm-ffi and ship to different environments, including Python and non-Python environments.
-
-While this guide shows how to build a wheel package, the resulting `my_ffi_extension.so` is agnostic
-to Python, comes with minimal dependencies, and can be used in other deployment scenarios.
-
-## Build and Run the Example
-
-Let's start by building and running the example.
-First, obtain a copy of the tvm-ffi source code.
-
-```bash
-git clone https://github.com/apache/tvm --recursive
-cd tvm/ffi
-```
-
-The examples are now in the examples folder. You can quickly build
-and install the example using the following command.
-```bash
-cd examples/packaging
-pip install -v .
-```
-
-Then you can run examples that leverage the built wheel package.
-
-```bash
-python run_example.py add_one
-```
-
-## Setup pyproject.toml
-
-A typical tvm-ffi-based project has the following structure:
-
-```
-├── CMakeLists.txt # CMake build configuration
-├── pyproject.toml # Python packaging configuration
-├── src/
-│ └── extension.cc # C++ source code
-├── python/
-│ └── my_ffi_extension/
-│ ├── __init__.py # Python package initialization
-│ ├── base.py # Library loading logic
-│ └── _ffi_api.py # FFI API registration
-└── README.md # Project documentation
-```
-
-The `pyproject.toml` file configures the build system and project metadata.
-
-```toml
-[project]
-name = "my-ffi-extension"
-version = "0.1.0"
-# ... more project metadata omitted ...
-
-[build-system]
-requires = ["scikit-build-core>=0.10.0", "apache-tvm-ffi"]
-build-backend = "scikit_build_core.build"
-
-[tool.scikit-build]
-# ABI-agnostic wheel
-wheel.py-api = "py3"
-# ... more build configuration omitted ...
-```
-
-We use scikit-build-core for building the wheel. Make sure you add tvm-ffi as a build-system requirement.
-Importantly, we should set `wheel.py-api` to `py3` to indicate it is ABI-generic.
-
-## Setup CMakeLists.txt
-
-The CMakeLists.txt handles the build and linking of the project.
-There are two ways you can build with tvm-ffi:
-
-- Link the pre-built `libtvm_ffi` shipped from the pip package
-- Build tvm-ffi from source
-
-For common cases, using the pre-built library and linking tvm_ffi_shared is sufficient.
-To build with the pre-built library, you can do:
-
-```cmake
-cmake_minimum_required(VERSION 3.18)
-project(my_ffi_extension)
-
-find_package(Python COMPONENTS Interpreter REQUIRED)
-execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --cmakedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
-# find the prebuilt package
-find_package(tvm_ffi CONFIG REQUIRED)
-
-# ... more cmake configuration omitted ...
-
-# linking the library
-target_link_libraries(my_ffi_extension tvm_ffi_shared)
-```
-
-There are cases where one may want to cross-compile or bundle part of tvm_ffi objects directly
-into the project. In such cases, you should build from source.
-
-```cmake
-execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --sourcedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
-# add the shipped source code as a cmake subdirectory
-add_subdirectory(${tvm_ffi_ROOT} tvm_ffi)
-
-# ... more cmake configuration omitted ...
-
-# linking the library
-target_link_libraries(my_ffi_extension tvm_ffi_shared)
-```
-Note that it is always safe to build from source, and the extra cost of building tvm-ffi is small
-because tvm-ffi is a lightweight library. If you are in doubt,
-you can always choose to build tvm-ffi from source.
-In Python or other cases when we dynamically load libtvm_ffi shipped with the dedicated pip package,
-you do not need to ship libtvm_ffi.so in your package even if you build tvm-ffi from source.
-The built objects are only used to supply the linking information.
-
-## Exposing C++ Functions
-
-The C++ implementation is defined in `src/extension.cc`.
-There are two ways one can expose a function in C++ to the FFI library.
-First, `TVM_FFI_DLL_EXPORT_TYPED_FUNC` can be used to expose the function directly as a C symbol that follows the tvm-ffi ABI,
-which can later be accessed via `tvm_ffi.load_module`.
-
-Here's a basic example of the function implementation:
-
-```c++
-void AddOne(DLTensor* x, DLTensor* y) {
- // ... implementation omitted ...
-}
-
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one, my_ffi_extension::AddOne);
-```
-
-We can also register a function into the global function table with a given name:
-
-```c++
-void RaiseError(ffi::String msg) {
- TVM_FFI_THROW(RuntimeError) << msg;
-}
-
-TVM_FFI_STATIC_INIT_BLOCK() {
- namespace refl = tvm::ffi::reflection;
- refl::GlobalDef()
- .def("my_ffi_extension.raise_error", RaiseError);
-}
-```
-
-Make sure to have a unique name across all registered functions when registering a global function.
-Always prefix with a package namespace name to avoid name collisions.
-The function can then be found via `tvm_ffi.get_global_func(name)`
-and is expected to stay throughout the lifetime of the program.
-
-We recommend using `TVM_FFI_DLL_EXPORT_TYPED_FUNC` for functions that are supposed to be dynamically
-loaded (such as JIT scenarios) so they won't be exposed to the global function table.
-
-## Library Loading in Python
-
-The base module handles loading the compiled extension:
-
-```python
-import tvm_ffi
-import os
-import sys
-
-def _load_lib():
- file_dir = os.path.dirname(os.path.realpath(__file__))
-
- # Platform-specific library names
- if sys.platform.startswith("win32"):
- lib_name = "my_ffi_extension.dll"
- elif sys.platform.startswith("darwin"):
- lib_name = "my_ffi_extension.dylib"
- else:
- lib_name = "my_ffi_extension.so"
-
- lib_path = os.path.join(file_dir, lib_name)
- return tvm_ffi.load_module(lib_path)
-
-_LIB = _load_lib()
-```
-
-Effectively, it leverages the `tvm_ffi.load_module` call to load the library
-extension DLL shipped along with the package. The `_ffi_api.py` contains a function
-call to `tvm_ffi.init_ffi_api` that registers all global functions prefixed
-with `my_ffi_extension` into the module.
-
-```python
-# _ffi_api.py
-import tvm_ffi
-from .base import _LIB
-
-# Register all global functions prefixed with 'my_ffi_extension.'
-# This makes functions registered via TVM_FFI_STATIC_INIT_BLOCK available
-tvm_ffi.init_ffi_api("my_ffi_extension", __name__)
-```
-
-Then we can redirect the calls to the related functions.
-
-```python
-from .base import _LIB
-from . import _ffi_api
-
-def add_one(x, y):
- # ... docstring omitted ...
- return _LIB.add_one(x, y)
-
-def raise_error(msg):
- # ... docstring omitted ...
- return _ffi_api.raise_error(msg)
-```
-
-## Build and Use the Package
-
-First, build the wheel:
-```bash
-pip wheel -v -w dist .
-```
-
-Then install the built wheel:
-```bash
-pip install dist/*.whl
-```
-
-Then you can try it out:
-
-```python
-import torch
-import my_ffi_extension
-
-# Create input and output tensors
-x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32)
-y = torch.empty_like(x)
-
-# Call the function
-my_ffi_extension.add_one(x, y)
-print(y) # Output: tensor([2., 3., 4., 5., 6.])
-```
-
-You can also run the following command to see how errors are raised and propagated
-across language boundaries:
-
-```python
-python run_example.py raise_error
-```
-
-When possible, tvm-ffi will try to preserve tracebacks across language boundaries. You will see tracebacks like:
-```
-File "src/extension.cc", line 45, in void my_ffi_extension::RaiseError(tvm::ffi::String)
-```
-
-## Wheel Auditing
-
-When using `auditwheel`, exclude `libtvm_ffi` as it will be shipped with the `tvm_ffi` package.
-
-```bash
-auditwheel repair --exclude libtvm_ffi.so dist/*.whl
-```
-
-As long as you import `tvm_ffi` first before loading the library, the symbols will be available.
diff --git a/ffi/docs/guides/python_guide.md b/ffi/docs/guides/python_guide.md
deleted file mode 100644
index 0ab56eb9c4..0000000000
--- a/ffi/docs/guides/python_guide.md
+++ /dev/null
@@ -1,242 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-# Python Guide
-
-This guide introduces the `tvm_ffi` Python package.
-At a high level, the `tvm_ffi` Python package provides first-class Python support for
-
-- Pythonic classes to represent values in TVM FFI Any ABI.
-- Mechanisms to call into TVM FFI ABI compatible functions.
-- Conversion between Python values and `tvm_ffi` values.
-
-In this guide, we will run examples that make use of pre-registered testing functions in `tvm_ffi`.
-If so, we will also briefly copy snippets that show the corresponding C++ behavior.
-
-## Load and Run Module
-
-The most common use case of TVM FFI is to load a runnable module and run the corresponding function.
-You can follow the [quick start guide](../get_started/quick_start.md) for details on building the
-library `build/add_one_cpu.so`. Let's walk through the load and run example again for NumPy
-
-```python
-import tvm_ffi
-import numpy as np
-
-# Load the compiled module
-mod = tvm_ffi.load_module("build/add_one_cpu.so")
-
-# Create input and output arrays
-x = np.array([1, 2, 3, 4, 5], dtype=np.float32)
-y = np.empty_like(x)
-
-# Call the function
-mod.add_one_cpu(x, y)
-```
-
-In this case, {py:func}`tvm_ffi.load_module` will return a {py:class}`tvm_ffi.Module` class that contains
-the exported functions. You can access the functions by their names.
-
-## Tensor
-
-`tvm_ffi` provides a managed DLPack-compatible Tensor.
-
-```python
-import numpy as np
-import tvm_ffi
-
-# Demonstrate DLPack conversion between NumPy and TVM FFI
-np_data = np.array([1, 2, 3, 4], dtype=np.float32)
-tvm_array = tvm_ffi.from_dlpack(np_data)
-# Convert back to NumPy
-np_result = np.from_dlpack(tvm_array)
-```
-
-In most cases, however, you do not have to explicitly create Tensors.
-The Python interface can take in `torch.Tensor` and `numpy.ndarray` objects
-and automatically convert them to {py:class}`tvm_ffi.Tensor`.
-
-## Functions and Callbacks
-
-{py:class}`tvm_ffi.Function` provides the Python interface for `ffi::Function` in the C++.
-You can retrieve globally registered functions via {py:func}`tvm_ffi.get_global_func`.
-
-```python
-import tvm_ffi
-
-# testing.echo is defined and registered in C++
-# [](ffi::Any x) { return x; }
-fecho = tvm_ffi.get_global_func("testing.echo")
-assert fecho(1) == 1
-```
-
-You can pass a Python function as an argument to another FFI function as callbacks.
-Under the hood, {py:func}`tvm_ffi.convert` is called to convert the Python function into a
-{py:class}`tvm_ffi.Function`.
-
-```python
-import tvm_ffi
-
-# testing.apply is registered in C++
-# [](ffi::Function f, ffi::Any val) { return f(x); }
-fapply = tvm_ffi.get_global_func("testing.apply")
-# invoke fapply with lambda callback as f
-assert fapply(lambda x: x + 1, 1) == 2
-```
-
-This is a very powerful pattern that allows us to inject Python callbacks into the C++ code.
-You can also register a Python callback as a global function.
-
-```python
-import tvm_ffi
-
-@tvm_ffi.register_global_func("example.add_one")
-def add_one(a):
- return a + 1
-
-assert tvm_ffi.get_global_func("example.add_one")(1) == 2
-```
-
-## Container Types
-
-When an FFI function takes arguments from lists/tuples, they will be converted into {py:class}`tvm_ffi.Array`.
-
-```python
-import tvm_ffi
-
-# Lists become Arrays
-arr = tvm_ffi.convert([1, 2, 3, 4])
-assert isinstance(arr, tvm_ffi.Array)
-assert len(arr) == 4
-assert arr[0] == 1
-```
-
-Dictionaries will be converted to {py:class}`tvm_ffi.Map`
-
-```python
-import tvm_ffi
-
-map_obj = tvm_ffi.convert({"a": 1, "b": 2})
-assert isinstance(map_obj, tvm_ffi.Map)
-assert len(map_obj) == 2
-assert map_obj["a"] == 1
-assert map_obj["b"] == 2
-```
-
-When container values are returned from FFI functions, they are also stored in these
-types respectively.
-
-
-## Error Handling
-
-An FFI function may raise an error. In such cases, the Python package will automatically
-translate the error to the corresponding error kind in Python
-
-```python
-import tvm_ffi
-
-# defined in C++
-# [](String kind, String msg) { throw Error(kind, msg, traceback); }
-test_raise_error = tvm_ffi.get_global_func("testing.test_raise_error")
-
-test_raise_error("ValueError", "message")
-```
-The above code shows an example where an error is raised in C++, resulting in the following error trace
-```
-Traceback (most recent call last):
-File "example.py", line 7, in <module>
- test_raise_error("ValueError", "message")
- ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
-File "python/tvm_ffi/cython/function.pxi", line 325, in core.Function.__call__
- raise move_from_last_error().py_error()
- ^^^
-File "src/ffi/extra/testing.cc", line 60, in void tvm::ffi::TestRaiseError(tvm::ffi::String, tvm::ffi::String)
- throw ffi::Error(kind, msg, TVMFFITraceback(__FILE__, __LINE__, TVM_FFI_FUNC_SIG, 0));
-```
-
-We register common error kinds. You can also register extra error dispatch via the {py:func}`tvm_ffi.register_error` function.
-
-## Advanced: Register Your Own Object
-
-For advanced use cases, you may want to register your own objects. This can be achieved through the
-reflection registry in the TVM-FFI API. First, let's review the C++ side of the code. For this
-example, you do not need to change the C++ side as this code is pre-shipped with the testing module of the `tvm_ffi` package.
-
-```cpp
-#include <tvm/ffi/reflection/registry.h>
-
-// Step 1: Define the object class (stores the actual data)
-class TestIntPairObj : public tvm::ffi::Object {
-public:
- int64_t a;
- int64_t b;
-
- TestIntPairObj() = default;
- TestIntPairObj(int64_t a, int64_t b) : a(a), b(b) {}
-
- // Required: declare type information
-TVM_FFI_DECLARE_OBJECT_INFO_FINAL("testing.TestIntPair", TestIntPairObj, tvm::ffi::Object);
-};
-
-// Step 2: Define the reference wrapper (user-facing interface)
-class TestIntPair : public tvm::ffi::ObjectRef {
-public:
- // Constructor
- explicit TestIntPair(int64_t a, int64_t b) {
- data_ = tvm::ffi::make_object<TestIntPairObj>(a, b);
- }
-
- // Required: define object reference methods
- TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestIntPair, tvm::ffi::ObjectRef, TestIntPairObj);
-};
-
-TVM_FFI_STATIC_INIT_BLOCK() {
- namespace refl = tvm::ffi::reflection;
- // register the object into the system
- // register field accessors and a global static function `__create__` as ffi::Function
- refl::ObjectDef<TestIntPairObj>()
- .def_ro("a", &TestIntPairObj::a)
- .def_ro("b", &TestIntPairObj::b)
- .def_static("__create__", [](int64_t a, int64_t b) -> TestIntPair {
- return TestIntPair(a, b);
- });
-}
-```
-
-You can then create wrapper classes for objects that are in the library as follows:
-
-```python
-import tvm_ffi
-
-# Register the class
-@tvm_ffi.register_object("testing.TestIntPair")
-class TestIntPair(tvm_ffi.Object):
- def __init__(self, a, b):
- # This is a special method to call an FFI function whose return
- # value exactly initializes the object handle of the object
- self.__init_handle_by_constructor__(TestIntPair.__create__, a, b)
-
-test_int_pair = TestIntPair(1, 2)
-# We can access the fields by name
-# The properties are populated by the reflection mechanism
-assert test_int_pair.a == 1
-assert test_int_pair.b == 2
-```
-Under the hood, we leverage the information registered through the reflection registry to
-generate efficient field accessors and methods for each class.
-
-Importantly, when you have multiple inheritance, you need to call {py:func}`tvm_ffi.register_object`
-on both the base class and the child class.
diff --git a/ffi/docs/index.rst b/ffi/docs/index.rst
deleted file mode 100644
index 643ee41791..0000000000
--- a/ffi/docs/index.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-.. Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
-.. http://www.apache.org/licenses/LICENSE-2.0
-
-.. Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-
-Apache TVM FFI Documentation
-============================
-
-Welcome to the documentation for TVM FFI. You can get started by reading the get started section,
-or reading through the guides and concepts sections.
-
-
-.. toctree::
- :maxdepth: 1
- :caption: Get Started
-
- get_started/install.md
- get_started/quick_start.md
-
-.. toctree::
- :maxdepth: 1
- :caption: Guides
-
- guides/packaging.md
- guides/cpp_guide.md
- guides/python_guide.md
-
-
-.. toctree::
- :maxdepth: 1
- :caption: Concepts
-
- concepts/abi_overview.md
-
-
-.. toctree::
- :maxdepth: 1
- :caption: Reference
-
- reference/python/index.rst
- reference/cpp/index.rst
diff --git a/ffi/docs/reference/cpp/index.rst b/ffi/docs/reference/cpp/index.rst
deleted file mode 100644
index ac9b1d73f9..0000000000
--- a/ffi/docs/reference/cpp/index.rst
+++ /dev/null
@@ -1,107 +0,0 @@
-.. Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
-.. http://www.apache.org/licenses/LICENSE-2.0
-
-.. Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-
-C++ API
-=======
-
-This page contains the API reference for the C++ API. The full API index below
-can be a bit dense, so we recommend the following tips first:
-
-- Please read the :ref:`C++ Guide<cpp-guide>` for a high-level overview of the C++ API.
-
- - The C++ Guide and examples will likely be sufficient to get started with most use cases.
-
-- The :ref:`cpp-key-classes` lists the key classes that are most commonly used.
-- You can go to the Full API Index at the bottom of this page to access the full list of APIs.
-
- - We usually group the APIs by files. You can look at the file hierarchy in the
- full API index and navigate to the specific file to find the APIs in that file.
-
-Header Organization
--------------------
-
-The C++ APIs are organized into the following folders:
-
-.. list-table::
- :header-rows: 1
- :widths: 30 70
-
- * - Folder
- - Description
- * - ``tvm/ffi/``
- - Core functionalities that support Function, Any, Object, etc.
- * - ``tvm/ffi/container/``
- - Additional container types such as Array, Map, Shape, Tensor, Variant ...
- * - ``tvm/ffi/reflection/``
- - Reflection support for function and type information registration.
- * - ``tvm/ffi/extra/``
- - Extra APIs that are built on top.
-
-
-.. _cpp-key-classes:
-
-Key Classes
------------
-
-.. list-table::
- :header-rows: 1
- :widths: 30 70
-
- * - Class
- - Description
- * - :cpp:class:`tvm::ffi::Function`
- - Type-erased function that implements the ABI.
- * - :cpp:class:`tvm::ffi::Any`
- - Type-erased container for any supported value.
- * - :cpp:class:`tvm::ffi::AnyView`
- - Lightweight view of Any without ownership.
- * - :cpp:class:`tvm::ffi::Object`
- - Base class for all heap-allocated FFI objects.
- * - :cpp:class:`tvm::ffi::ObjectRef`
- - Reference class for objects.
- * - :cpp:class:`tvm::ffi::Tensor`
- - Multi-dimensional tensor with DLPack support.
- * - :cpp:class:`tvm::ffi::Shape`
- - Tensor shape container.
- * - :cpp:class:`tvm::ffi::Module`
- - Dynamic library module that can load exported functions.
- * - :cpp:class:`tvm::ffi::String`
- - String type for FFI.
- * - :cpp:class:`tvm::ffi::Bytes`
- - Byte array type.
- * - :cpp:class:`tvm::ffi::Array`
- - Dynamic array container.
- * - :cpp:class:`tvm::ffi::Tuple`
- - Heterogeneous tuple container.
- * - :cpp:class:`tvm::ffi::Map`
- - Key-value map container.
- * - :cpp:class:`tvm::ffi::Optional`
- - Optional value wrapper.
- * - :cpp:class:`tvm::ffi::Variant`
- - Type-safe union container.
-
-
-
-.. _cpp-full-api-index:
-
-Full API Index
---------------
-
-.. toctree::
- :maxdepth: 2
-
- generated/index.rst
diff --git a/ffi/docs/reference/python/index.rst b/ffi/docs/reference/python/index.rst
deleted file mode 100644
index 13008089f3..0000000000
--- a/ffi/docs/reference/python/index.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
-.. http://www.apache.org/licenses/LICENSE-2.0
-
-.. Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-
-Python API
-==========
-
-.. automodule:: tvm_ffi
- :no-members:
-
-.. currentmodule:: tvm_ffi
-
-Object
-------
-.. autosummary::
- :toctree: generated/
-
- Object
- register_object
-
-
-Function and Module
--------------------
-.. autosummary::
- :toctree: generated/
-
-
- Function
- Module
- register_global_func
- get_global_func
- system_lib
- load_module
- init_ffi_api
- register_error
- convert
-
-
-Tensor
-------
-.. autosummary::
- :toctree: generated/
-
- Shape
- Tensor
- Device
- from_dlpack
-
-
-Containers
-----------
-.. autosummary::
- :toctree: generated/
-
- Array
- Map
diff --git a/ffi/docs/requirements.txt b/ffi/docs/requirements.txt
deleted file mode 100644
index 74784b5153..0000000000
--- a/ffi/docs/requirements.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-autodocsumm
-exhale
-breathe
-linkify-it-py
-matplotlib
-myst-parser
-nbconvert
-nbsphinx
-nbstripout
-sphinx
-sphinx-autobuild
-sphinx-book-theme
-sphinx-copybutton
-sphinx-reredirects==0.1.2
-sphinx-tabs == 3.4.1
-sphinx-toolbox == 3.4.0
-sphinxcontrib-mermaid
-sphinxcontrib-napoleon==0.7
-sphinxcontrib_httpdomain==1.8.1
-tomli
-urllib3>=2.5.0
diff --git a/ffi/examples/inline_module/main.py b/ffi/examples/inline_module/main.py
deleted file mode 100644
index 5cfcd41bec..0000000000
--- a/ffi/examples/inline_module/main.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-import torch
-import tvm_ffi.cpp
-from tvm_ffi.module import Module
-
-
-def main():
- mod: Module = tvm_ffi.cpp.load_inline(
- name="hello",
- cpp_sources=r"""
- void add_one_cpu(DLTensor* x, DLTensor* y) {
- // implementation of a library function
- TVM_FFI_ICHECK(x->ndim == 1) << "x must be a 1D tensor";
- DLDataType f32_dtype{kDLFloat, 32, 1};
- TVM_FFI_ICHECK(x->dtype == f32_dtype) << "x must be a float tensor";
- TVM_FFI_ICHECK(y->ndim == 1) << "y must be a 1D tensor";
- TVM_FFI_ICHECK(y->dtype == f32_dtype) << "y must be a float tensor";
- TVM_FFI_ICHECK(x->shape[0] == y->shape[0]) << "x and y must have the same shape";
- for (int i = 0; i < x->shape[0]; ++i) {
- static_cast<float*>(y->data)[i] = static_cast<float*>(x->data)[i] + 1;
- }
- }
-
- void add_one_cuda(DLTensor* x, DLTensor* y);
- """,
- cuda_sources=r"""
- __global__ void AddOneKernel(float* x, float* y, int n) {
- int idx = blockIdx.x * blockDim.x + threadIdx.x;
- if (idx < n) {
- y[idx] = x[idx] + 1;
- }
- }
-
- void add_one_cuda(DLTensor* x, DLTensor* y) {
- // implementation of a library function
- TVM_FFI_ICHECK(x->ndim == 1) << "x must be a 1D tensor";
- DLDataType f32_dtype{kDLFloat, 32, 1};
- TVM_FFI_ICHECK(x->dtype == f32_dtype) << "x must be a float tensor";
- TVM_FFI_ICHECK(y->ndim == 1) << "y must be a 1D tensor";
- TVM_FFI_ICHECK(y->dtype == f32_dtype) << "y must be a float tensor";
- TVM_FFI_ICHECK(x->shape[0] == y->shape[0]) << "x and y must have the same shape";
-
- int64_t n = x->shape[0];
- int64_t nthread_per_block = 256;
- int64_t nblock = (n + nthread_per_block - 1) / nthread_per_block;
- // Obtain the current stream from the environment
- // it will be set to torch.cuda.current_stream() when calling the function
- // with torch.Tensors
- cudaStream_t stream = static_cast<cudaStream_t>(
- TVMFFIEnvGetStream(x->device.device_type, x->device.device_id));
- // launch the kernel
- AddOneKernel<<<nblock, nthread_per_block, 0, stream>>>(static_cast<float*>(x->data),
- static_cast<float*>(y->data), n);
- }
- """,
- functions=["add_one_cpu", "add_one_cuda"],
- )
-
- x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32)
- y = torch.empty_like(x)
- mod.add_one_cpu(x, y)
- torch.testing.assert_close(x + 1, y)
-
- x_cuda = x.cuda()
- y_cuda = torch.empty_like(x_cuda)
- mod.add_one_cuda(x_cuda, y_cuda)
- torch.testing.assert_close(x_cuda + 1, y_cuda)
-
-
-if __name__ == "__main__":
- main()
diff --git a/ffi/examples/packaging/CMakeLists.txt b/ffi/examples/packaging/CMakeLists.txt
deleted file mode 100644
index ed55f7ca33..0000000000
--- a/ffi/examples/packaging/CMakeLists.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-cmake_minimum_required(VERSION 3.18)
-project(my_ffi_extension)
-
-option(TVM_FFI_EXT_FROM_SOURCE "Build tvm_ffi from source, useful for cross compilation." ON)
-option(TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS "Ship debug symbols" ON)
-
-# There are two ways to include tvm_ffi
-#
-# 1. Build tvm_ffi from source, which is reasonably cheap since tvm ffi is small
-# 2. Use the pre-built tvm_ffi shipped from the pip
-#
-# This example shows both options, you only need to pick a specific one.
-#
-# - For common build cases, using pre-built and link tvm_ffi_shared is sufficient.
-# - For cases where you may want to cross-compile or bundle part of tvm_ffi_objects directly
-# into your project, opt for building tvm_ffi from source path.
-# Note that it is always safe to build from source and extra cost of building tvm_ffi is small.
-# So when in doubt, you can always choose to the building tvm_ffi from source route.
-#
-# In python or other cases when we dynamically load libtvm_ffi_shared. Even when you build
-# from source, you do not need to ship libtvm_ffi.so built here as they are only
-# used to supply the linking information.
-# first find python related components
-find_package(Python COMPONENTS Interpreter REQUIRED)
-if (TVM_FFI_BUILD_FROM_SOURCE)
- execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --sourcedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
- message(STATUS "Building tvm_ffi from source: ${tvm_ffi_ROOT}")
- add_subdirectory(${tvm_ffi_ROOT} tvm_ffi)
-else()
- # call tvm_ffi.config to get the cmake directory and set it to tvm_ffi_ROOT
- execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --cmakedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
- find_package(tvm_ffi CONFIG REQUIRED)
-endif()
-
-# use the projects as usual
-add_library(my_ffi_extension SHARED src/extension.cc)
-target_link_libraries(my_ffi_extension tvm_ffi_header)
-target_link_libraries(my_ffi_extension tvm_ffi_shared)
-
-# show as my_ffi_extension.so
-set_target_properties(
- my_ffi_extension PROPERTIES PREFIX ""
-)
-
-if (TVM_FFI_EXT_SHIP_DEBUG_SYMBOLS)
- # ship debugging symbols for backtrace on macos
- tvm_ffi_add_prefix_map(my_ffi_extension ${CMAKE_CURRENT_SOURCE_DIR})
- tvm_ffi_add_apple_dsymutil(my_ffi_extension)
- install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION . FILES_MATCHING PATTERN "*.dSYM")
-endif()
-
-install(TARGETS my_ffi_extension DESTINATION .)
diff --git a/ffi/examples/packaging/README.md b/ffi/examples/packaging/README.md
deleted file mode 100644
index 25bcc1ca3c..0000000000
--- a/ffi/examples/packaging/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-
-# TVM FFI Packaging Example
-
-This is an example project that packages a tvm-ffi based library
-into a Python ABI-agnostic wheel.
-
-This example can also serve as a guideline for general
-packaging as well.
-
-- Source-level build for cross-compilation support in CMake
-- Registration via global function table
-
-## Install the wheel
-
-```bash
-pip install .
-```
-
-### Note on build and auditwheel
-
-Note: When running the auditwheel process, make sure to skip
-`libtvm_ffi.so` as they are shipped via the tvm_ffi package.
-
-## Run the example
-
-After installing the `my_ffi_extension` example package, you can run the following example
-that invokes the `add_one` function exposed.
-
-```bash
-python run_example.py add_one
-```
-
-You can also run the following command to see how error is raised and propagated
-across the language boundaries.
-
-```python
-python run_example.py raise_error
-```
-
-When possible, tvm_ffi will try to preserve traceback across language boundary. You will see traceback like
-```
-File "src/extension.cc", line 45, in void my_ffi_extension::RaiseError(tvm::ffi::String)
-```
-If you are in an IDE like VSCode, you can click and jump to the C++ lines of error when
-the debug symbols are preserved.
diff --git a/ffi/examples/packaging/pyproject.toml b/ffi/examples/packaging/pyproject.toml
deleted file mode 100644
index 7825ca81ce..0000000000
--- a/ffi/examples/packaging/pyproject.toml
+++ /dev/null
@@ -1,58 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-[project]
-name = "my-ffi-extension"
-version = "0.1.0"
-
-readme = "README.md"
-license = { text = "Apache 2.0" }
-classifiers = [
- "License :: OSI Approved :: Apache Software License",
- "Development Status :: 4 - Beta",
- "Intended Audience :: Developers",
- "Intended Audience :: Education",
- "Intended Audience :: Science/Research",
-]
-keywords = ["machine learning", "inference"]
-requires-python = ">=3.9"
-
-dependencies = ["apache-tvm-ffi"]
-
-[build-system]
-requires = ["scikit-build-core>=0.10.0", "apache-tvm-ffi"]
-build-backend = "scikit_build_core.build"
-
-[tool.scikit-build]
-# the wheel is abi agnostic
-wheel.py-api = "py3"
-minimum-version = "build-system.requires"
-
-# Build configuration
-build-dir = "build"
-build.verbose = true
-
-# CMake configuration
-cmake.version = "CMakeLists.txt"
-cmake.build-type = "RelWithDebugInfo"
-
-# Logging
-logging.level = "INFO"
-
-# Wheel configuration
-wheel.packages = ["python/my_ffi_extension"]
-wheel.install-dir = "my_ffi_extension"
diff --git a/ffi/examples/packaging/python/my_ffi_extension/__init__.py b/ffi/examples/packaging/python/my_ffi_extension/__init__.py
deleted file mode 100644
index 4cd4207df1..0000000000
--- a/ffi/examples/packaging/python/my_ffi_extension/__init__.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations.
-from .base import _LIB
-from . import _ffi_api
-
-
-def add_one(x, y):
- """
- Adds one to the input tensor.
-
- Parameters
- ----------
- x : Tensor
- The input tensor.
- y : Tensor
- The output tensor.
- """
- return _LIB.add_one(x, y)
-
-
-def raise_error(msg):
- """
- Raises an error with the given message.
-
- Parameters
- ----------
- msg : str
- The message to raise the error with.
-
- Raises
- ------
- RuntimeError
- The error raised by the function.
- """
- return _ffi_api.raise_error(msg)
diff --git a/ffi/examples/packaging/python/my_ffi_extension/_ffi_api.py b/ffi/examples/packaging/python/my_ffi_extension/_ffi_api.py
deleted file mode 100644
index 616b1ee8e8..0000000000
--- a/ffi/examples/packaging/python/my_ffi_extension/_ffi_api.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations.
-
-import tvm_ffi
-
-# make sure lib is loaded first
-from .base import _LIB
-
-# this is a short cut to register all the global functions
-# prefixed by `my_ffi_extension.` to this module
-tvm_ffi.init_ffi_api("my_ffi_extension", __name__)
diff --git a/ffi/examples/packaging/python/my_ffi_extension/base.py b/ffi/examples/packaging/python/my_ffi_extension/base.py
deleted file mode 100644
index d65264eb71..0000000000
--- a/ffi/examples/packaging/python/my_ffi_extension/base.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations.
-# Base logic to load library for extension package
-import tvm_ffi
-import os
-import sys
-
-
-def _load_lib():
- # first look at the directory of the current file
- file_dir = os.path.dirname(os.path.realpath(__file__))
-
- if sys.platform.startswith("win32"):
- lib_dll_name = "my_ffi_extension.dll"
- elif sys.platform.startswith("darwin"):
- lib_dll_name = "my_ffi_extension.dylib"
- else:
- lib_dll_name = "my_ffi_extension.so"
-
- lib_path = os.path.join(file_dir, lib_dll_name)
- return tvm_ffi.load_module(lib_path)
-
-
-_LIB = _load_lib()
diff --git a/ffi/examples/packaging/run_example.py b/ffi/examples/packaging/run_example.py
deleted file mode 100644
index 11642257e8..0000000000
--- a/ffi/examples/packaging/run_example.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations.
-# Base logic to load library for extension package
-import torch
-import sys
-import my_ffi_extension
-
-
-def run_add_one():
- x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32)
- y = torch.empty_like(x)
- my_ffi_extension.add_one(x, y)
- print(y)
-
-
-def run_raise_error():
- my_ffi_extension.raise_error("This is an error")
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- if sys.argv[1] == "add_one":
- run_add_one()
- elif sys.argv[1] == "raise_error":
- run_raise_error()
- else:
- print("Usage: python run_example.py <add_one|raise_error>")
diff --git a/ffi/examples/packaging/src/extension.cc b/ffi/examples/packaging/src/extension.cc
deleted file mode 100644
index 6a7324f410..0000000000
--- a/ffi/examples/packaging/src/extension.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/*!
- * \file example.cc
- * \brief Example of a tvm-ffi based library that registers various functions.
- *
- * It is a simple example that demonstrates how to package a tvm-ffi library into a python wheel.
- * The library is written in C++ and can be compiled into a shared library.
- * The shared library can then be loaded into python and used to call the functions.
- */
-#include <tvm/ffi/container/tensor.h>
-#include <tvm/ffi/dtype.h>
-#include <tvm/ffi/error.h>
-#include <tvm/ffi/function.h>
-#include <tvm/ffi/reflection/registry.h>
-
-namespace my_ffi_extension {
-
-namespace ffi = tvm::ffi;
-
-/*!
- * \brief Raises a runtime error
- *
- * This is an example function to show how to raise and propagate
- * an error across the language boundary.
- *
- * \param msg The message to raise the error with
- */
-void RaiseError(ffi::String msg) { TVM_FFI_THROW(RuntimeError) << msg; }
-
-void AddOne(ffi::Tensor x, ffi::Tensor y) {
- // implementation of a library function
- TVM_FFI_ICHECK(x->ndim == 1) << "x must be a 1D tensor";
- DLDataType f32_dtype{kDLFloat, 32, 1};
- TVM_FFI_ICHECK(x->dtype == f32_dtype) << "x must be a float tensor";
- TVM_FFI_ICHECK(y->ndim == 1) << "y must be a 1D tensor";
- TVM_FFI_ICHECK(y->dtype == f32_dtype) << "y must be a float tensor";
- TVM_FFI_ICHECK(x->shape[0] == y->shape[0]) << "x and y must have the same shape";
- for (int i = 0; i < x->shape[0]; ++i) {
- static_cast<float*>(y->data)[i] = static_cast<float*>(x->data)[i] + 1;
- }
-}
-
-// expose global symbol add_one
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one, my_ffi_extension::AddOne);
-
-// The static initialization block is
-// called once when the library is loaded.
-TVM_FFI_STATIC_INIT_BLOCK() {
- namespace refl = tvm::ffi::reflection;
- // In this particular example, we use the reflection mechanisms to
- // register the functions directly into the global function table.
- //
- // This is an alternative approach to TVM_FFI_DLL_EXPORT_TYPED_FUNC
- // that exports the function directly as C symbol that follows tvm-ffi abi.
- //
- // - For functions that are expected to be static part of tvm_ffi_example project,
- // one can use reflection mechanisms to register the globa function.
- // - For functions that are compiled and dynamically loaded at runtime, consider
- // using the normal export mechanism so they won't be exposed to the global function table.
- //
- // Make sure to have a unique name across all registered functions,
- // always prefix with a package namespace name to avoid name collision.
- //
- // The function can then be found via tvm_ffi.get_global_func(name)
- // If the function is expected to stay throughout the lifetime of the program/
- //
- // When registering via reflection mechanisms, the library do not need to be loaded via
- // tvm::ffi::Module::LoadFromFile, instead, just load the dll or simply bundle into the
- // final project
- refl::GlobalDef().def("my_ffi_extension.raise_error", RaiseError);
-}
-} // namespace my_ffi_extension
diff --git a/ffi/examples/quick_start/CMakeLists.txt b/ffi/examples/quick_start/CMakeLists.txt
deleted file mode 100644
index 0553098800..0000000000
--- a/ffi/examples/quick_start/CMakeLists.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-cmake_minimum_required(VERSION 3.18)
-project(tvm_ffi_example)
-
-
-# first find python related components
-find_package(Python COMPONENTS Interpreter REQUIRED)
-
-# call tvm_ffi.config to get the cmake directory and set it to tvm_ffi_ROOT
-execute_process(
- COMMAND "${Python_EXECUTABLE}" -m tvm_ffi.config --cmakedir
- OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE tvm_ffi_ROOT)
-# find package will automatically include the related projects
-find_package(tvm_ffi CONFIG REQUIRED)
-
-# use the projects as usual
-add_library(add_one_cpu SHARED src/add_one_cpu.cc)
-target_link_libraries(add_one_cpu tvm_ffi_header)
-target_link_libraries(add_one_cpu tvm_ffi_shared)
-# show as add_one_cpu.so
-set_target_properties(
- add_one_cpu PROPERTIES
- PREFIX ""
- SUFFIX ".so"
-)
-
-# Check if CUDA is available
-if(NOT WIN32)
- find_package(CUDA QUIET)
- if(CUDA_FOUND)
- enable_language(CUDA)
- add_library(add_one_cuda SHARED src/add_one_cuda.cu)
- target_link_libraries(add_one_cuda tvm_ffi_shared)
-
- # show as add_one_cuda.so
- set_target_properties(
- add_one_cuda PROPERTIES
- PREFIX ""
- SUFFIX ".so"
- )
- endif()
-endif()
-
-add_executable(run_example src/run_example.cc)
-set_target_properties(
- run_example PROPERTIES
- CXX_STANDARD 17
-)
-target_link_libraries(run_example tvm_ffi_shared)
diff --git a/ffi/examples/quick_start/README.md b/ffi/examples/quick_start/README.md
deleted file mode 100644
index 002d4375a6..0000000000
--- a/ffi/examples/quick_start/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-<!--- Licensed to the Apache Software Foundation (ASF) under one -->
-<!--- or more contributor license agreements. See the NOTICE file -->
-<!--- distributed with this work for additional information -->
-<!--- regarding copyright ownership. The ASF licenses this file -->
-<!--- to you under the Apache License, Version 2.0 (the -->
-<!--- "License"); you may not use this file except in compliance -->
-<!--- with the License. You may obtain a copy of the License at -->
-
-<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
-
-<!--- Unless required by applicable law or agreed to in writing, -->
-<!--- software distributed under the License is distributed on an -->
-<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
-<!--- KIND, either express or implied. See the License for the -->
-<!--- specific language governing permissions and limitations -->
-<!--- under the License. -->
-
-# Getting Started with TVM FFI
-
-This example demonstrates how to use tvm-ffi to expose a universal function
-that can be loaded in different environments.
-
-The example implements a simple "add one" operation that adds 1 to each element
-of an input tensor, showing how to create C++ functions callable from Python.
-
-You can run this quick start example by:
-
-```bash
-# ensure you installed tvm-ffi first
-pip install -e ../..
-
-# Build and run the complete example
-./run_example.sh
-```
-
-At a high level, the `TVM_FFI_DLL_EXPORT_TYPED_FUNC` macro helps to expose
-a C++ function into the TVM FFI C ABI convention for functions.
-Then the function can be accessed by different environments and languages
-that interface with the TVM FFI. The current example shows how to do so
-in Python and C++.
-
-## Key Files
-
-- `src/add_one_cpu.cc` - CPU implementation of the add_one function
-- `src/add_one_cuda.cu` - CUDA implementation for GPU operations
-- `run_example.py` - Python example showing how to call the functions
-- `run_example.cc` - C++ example demonstrating the same functionality
-
-## Compile without CMake
-
-You can also compile the modules directly using
-flags provided by the `tvm-ffi-config` tool.
-
-```bash
-g++ -shared -fPIC `tvm-ffi-config --cxxflags` \
- src/add_one_cpu.cc -o build/add_one_cpu.so \
- `tvm-ffi-config --ldflags` `tvm-ffi-config --libs`
-```
diff --git a/ffi/examples/quick_start/run_example.py b/ffi/examples/quick_start/run_example.py
deleted file mode 100644
index a8f4fc00a6..0000000000
--- a/ffi/examples/quick_start/run_example.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-import tvm_ffi
-
-try:
- import torch
-except ImportError:
- torch = None
-
-import numpy
-import ctypes
-
-
-def run_add_one_cpu():
- """Load the add_one_cpu module and call the add_one_cpu function."""
- mod = tvm_ffi.load_module("build/add_one_cpu.so")
-
- x = numpy.array([1, 2, 3, 4, 5], dtype=numpy.float32)
- y = numpy.empty_like(x)
- # tvm-ffi automatically handles DLPack compatible tensors
- # torch tensors can be viewed as ffi::Tensor or DLTensor*
- # in the background
- mod.add_one_cpu(x, y)
- print("numpy.result after add_one(x, y)")
- print(x)
-
- if torch is None:
- return
-
- x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32)
- y = torch.empty_like(x)
- # tvm-ffi automatically handles DLPack compatible tensors
- # torch tensors can be viewed as ffi::Tensor or DLTensor*
- # in the background
- mod.add_one_cpu(x, y)
- print("torch.result after add_one(x, y)")
- print(y)
-
-
-def run_add_one_cuda():
- """Load the add_one_cuda module and call the add_one_cuda function."""
- if torch is None or not torch.cuda.is_available():
- return
-
- mod = tvm_ffi.load_module("build/add_one_cuda.so")
- x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32, device="cuda")
- y = torch.empty_like(x)
-
- stream = torch.cuda.Stream()
- with torch.cuda.stream(stream):
- # tvm-ffi automatically handles DLPack compatible tensors
- # it also handles interactions with torch runtime
- # torch.cuda.current_stream() will be set and available via TVMFFIEnvGetStream
- # when calling the function
- mod.add_one_cuda(x, y)
- stream.synchronize()
- print("torch.result after mod.add_one_cuda(x, y)")
- print(y)
-
-
-def main():
- """Main function to run the example."""
- run_add_one_cpu()
- run_add_one_cuda()
-
-
-if __name__ == "__main__":
- main()
diff --git a/ffi/examples/quick_start/run_example.sh b/ffi/examples/quick_start/run_example.sh
deleted file mode 100755
index 0602b85f37..0000000000
--- a/ffi/examples/quick_start/run_example.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#!/bin/bash
-set -ex
-
-cmake -B build -S .
-cmake --build build
-
-# running python example
-python run_example.py
-
-# running c++ example
-./build/run_example
diff --git a/ffi/examples/quick_start/src/add_one_cpu.cc b/ffi/examples/quick_start/src/add_one_cpu.cc
deleted file mode 100644
index 76b9b3752c..0000000000
--- a/ffi/examples/quick_start/src/add_one_cpu.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#include <tvm/ffi/container/tensor.h>
-#include <tvm/ffi/dtype.h>
-#include <tvm/ffi/error.h>
-#include <tvm/ffi/function.h>
-
-namespace tvm_ffi_example {
-
-void AddOne(tvm::ffi::Tensor x, tvm::ffi::Tensor y) {
- // implementation of a library function
- TVM_FFI_ICHECK(x->ndim == 1) << "x must be a 1D tensor";
- DLDataType f32_dtype{kDLFloat, 32, 1};
- TVM_FFI_ICHECK(x->dtype == f32_dtype) << "x must be a float tensor";
- TVM_FFI_ICHECK(y->ndim == 1) << "y must be a 1D tensor";
- TVM_FFI_ICHECK(y->dtype == f32_dtype) << "y must be a float tensor";
- TVM_FFI_ICHECK(x->shape[0] == y->shape[0]) << "x and y must have the same shape";
- for (int i = 0; i < x->shape[0]; ++i) {
- static_cast<float*>(y->data)[i] = static_cast<float*>(x->data)[i] + 1;
- }
-}
-
-// Expose global symbol `add_one_cpu` that follows tvm-ffi abi
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one_cpu, tvm_ffi_example::AddOne);
-} // namespace tvm_ffi_example
diff --git a/ffi/examples/quick_start/src/add_one_cuda.cu b/ffi/examples/quick_start/src/add_one_cuda.cu
deleted file mode 100644
index 52f1e74825..0000000000
--- a/ffi/examples/quick_start/src/add_one_cuda.cu
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#include <tvm/ffi/container/tensor.h>
-#include <tvm/ffi/dtype.h>
-#include <tvm/ffi/error.h>
-#include <tvm/ffi/extra/c_env_api.h>
-#include <tvm/ffi/function.h>
-
-namespace tvm_ffi_example {
-
-__global__ void AddOneKernel(float* x, float* y, int n) {
- int idx = blockIdx.x * blockDim.x + threadIdx.x;
- if (idx < n) {
- y[idx] = x[idx] + 1;
- }
-}
-
-void AddOneCUDA(tvm::ffi::Tensor x, tvm::ffi::Tensor y) {
- // implementation of a library function
- TVM_FFI_ICHECK(x->ndim == 1) << "x must be a 1D tensor";
- DLDataType f32_dtype{kDLFloat, 32, 1};
- TVM_FFI_ICHECK(x->dtype == f32_dtype) << "x must be a float tensor";
- TVM_FFI_ICHECK(y->ndim == 1) << "y must be a 1D tensor";
- TVM_FFI_ICHECK(y->dtype == f32_dtype) << "y must be a float tensor";
- TVM_FFI_ICHECK(x->shape[0] == y->shape[0]) << "x and y must have the same shape";
-
- int64_t n = x->shape[0];
- int64_t nthread_per_block = 256;
- int64_t nblock = (n + nthread_per_block - 1) / nthread_per_block;
- // Obtain the current stream from the environment
- // it will be set to torch.cuda.current_stream() when calling the function
- // with torch.Tensors
- cudaStream_t stream =
- static_cast<cudaStream_t>(TVMFFIEnvGetStream(x->device.device_type, x->device.device_id));
- // launch the kernel
- AddOneKernel<<<nblock, nthread_per_block, 0, stream>>>(static_cast<float*>(x->data),
- static_cast<float*>(y->data), n);
-}
-
-// Expose global symbol `add_one_cpu` that follows tvm-ffi abi
-TVM_FFI_DLL_EXPORT_TYPED_FUNC(add_one_cuda, tvm_ffi_example::AddOneCUDA);
-} // namespace tvm_ffi_example
diff --git a/ffi/examples/quick_start/src/run_example.cc b/ffi/examples/quick_start/src/run_example.cc
deleted file mode 100644
index 90e61d170b..0000000000
--- a/ffi/examples/quick_start/src/run_example.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#include <tvm/ffi/container/tensor.h>
-#include <tvm/ffi/extra/module.h>
-
-// This file shows how to load the same compiled module and interact with it in C++
-namespace ffi = tvm::ffi;
-
-struct CPUNDAlloc {
- void AllocData(DLTensor* tensor) { tensor->data = malloc(ffi::GetDataSize(*tensor)); }
- void FreeData(DLTensor* tensor) { free(tensor->data); }
-};
-
-inline ffi::Tensor Empty(ffi::Shape shape, DLDataType dtype, DLDevice device) {
- return ffi::Tensor::FromNDAlloc(CPUNDAlloc(), shape, dtype, device);
-}
-
-int main() {
- // load the module
- ffi::Module mod = ffi::Module::LoadFromFile("build/add_one_cpu.so");
-
- // create an Tensor, alternatively, one can directly pass in a DLTensor*
- ffi::Tensor x = Empty({5}, DLDataType({kDLFloat, 32, 1}), DLDevice({kDLCPU, 0}));
- for (int i = 0; i < 5; ++i) {
- reinterpret_cast<float*>(x->data)[i] = static_cast<float>(i);
- }
-
- ffi::Function add_one_cpu = mod->GetFunction("add_one_cpu").value();
- add_one_cpu(x, x);
-
- std::cout << "x after add_one_cpu(x, x)" << std::endl;
- for (int i = 0; i < 5; ++i) {
- std::cout << reinterpret_cast<float*>(x->data)[i] << " ";
- }
- std::cout << std::endl;
- return 0;
-}
diff --git a/ffi/include/tvm/ffi/any.h b/ffi/include/tvm/ffi/any.h
deleted file mode 100644
index 738adc4f86..0000000000
--- a/ffi/include/tvm/ffi/any.h
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/*!
- * \file tvm/ffi/any.h
- * \brief Any value support.
- */
-#ifndef TVM_FFI_ANY_H_
-#define TVM_FFI_ANY_H_
-
-#include <tvm/ffi/c_api.h>
-#include <tvm/ffi/string.h>
-#include <tvm/ffi/type_traits.h>
-
-#include <string>
-#include <utility>
-
-namespace tvm {
-namespace ffi {
-
-class Any;
-
-namespace details {
-// Helper to perform
-// unsafe operations related to object
-struct AnyUnsafe;
-} // namespace details
-
-/*!
- * \brief AnyView allows us to take un-managed reference view of any value.
- */
-class AnyView {
- protected:
- /*! \brief The underlying backing data of the any object */
- TVMFFIAny data_;
- // Any can see AnyView
- friend class Any;
-
- public:
- // NOTE: the following functions use style
- // since they are common functions appearing in FFI.
- /*!
- * \brief Reset any view to None
- */
- void reset() {
- data_.type_index = TypeIndex::kTVMFFINone;
- // invariance: always set the union padding part to 0
- data_.zero_padding = 0;
- data_.v_int64 = 0;
- }
- /*!
- * \brief Swap this AnyView with another AnyView
- * \param other The other AnyView
- */
- TVM_FFI_INLINE void swap(AnyView& other) noexcept { std::swap(data_, other.data_); }
- /*! \return the internal type index */
- TVM_FFI_INLINE int32_t type_index() const noexcept { return data_.type_index; }
- /*! \brief Default constructor */
- AnyView() {
- data_.type_index = TypeIndex::kTVMFFINone;
- data_.zero_padding = 0;
- data_.v_int64 = 0;
- }
- ~AnyView() = default;
- // constructors from any view
- /*! \brief Copy constructor */
- AnyView(const AnyView&) = default;
- /*! \brief Copy assignment operator */
- AnyView& operator=(const AnyView&) = default;
- /*! \brief Move constructor */
- AnyView(AnyView&& other) : data_(other.data_) {
- other.data_.type_index = TypeIndex::kTVMFFINone;
- other.data_.zero_padding = 0;
- other.data_.v_int64 = 0;
- }
- TVM_FFI_INLINE AnyView& operator=(AnyView&& other) {
- // copy-and-swap idiom
- AnyView(std::move(other)).swap(*this); // NOLINT(*)
- return *this;
- }
- /*!
- * \brief Constructor from a general type.
- * \tparam T The type to convert from.
- * \param other The value to convert from.
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- AnyView(const T& other) { // NOLINT(*)
- TypeTraits<T>::CopyToAnyView(other, &data_);
- }
- /*!
- * \brief Assign from a general type.
- * \tparam T The type to convert from.
- * \param other The value to convert from.
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- TVM_FFI_INLINE AnyView& operator=(const T& other) { // NOLINT(*)
- // copy-and-swap idiom
- AnyView(other).swap(*this); // NOLINT(*)
- return *this;
- }
-
- /*!
- * \brief Try to see if we can reinterpret the AnyView to as T object.
- *
- * \tparam T The type to cast to.
- * \return The casted value, or std::nullopt if the cast is not possible.
- * \note This function won't try run type conversion (use try_cast for that purpose).
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- TVM_FFI_INLINE std::optional<T> as() const {
- if (TypeTraits<T>::CheckAnyStrict(&data_)) {
- return TypeTraits<T>::CopyFromAnyViewAfterCheck(&data_);
- } else {
- return std::optional<T>(std::nullopt);
- }
- }
- /*!
- * \brief Shortcut of as Object to cast to a const pointer when T is an Object.
- *
- * \tparam T The object type.
- * \return The requested pointer, returns nullptr if type mismatches.
- */
- template <typename T, typename = std::enable_if_t<std::is_base_of_v<Object, T>>>
- TVM_FFI_INLINE const T* as() const {
- return this->as<const T*>().value_or(nullptr);
- }
-
- /*!
- * \brief Cast to a type T.
- *
- * \tparam T The type to cast to.
- * \return The casted value, or throws an exception if the cast is not possible.
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- TVM_FFI_INLINE T cast() const {
- std::optional<T> opt = TypeTraits<T>::TryCastFromAnyView(&data_);
- if (!opt.has_value()) {
- TVM_FFI_THROW(TypeError) << "Cannot convert from type `"
- << TypeTraits<T>::GetMismatchTypeInfo(&data_) << "` to `"
- << TypeTraits<T>::TypeStr() << "`";
- }
- return *std::move(opt);
- }
-
- /*!
- * \brief Try to cast to a type T, return std::nullopt if the cast is not possible.
- *
- * \tparam T The type to cast to.
- * \return The casted value, or std::nullopt if the cast is not possible.
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- TVM_FFI_INLINE std::optional<T> try_cast() const {
- return TypeTraits<T>::TryCastFromAnyView(&data_);
- }
-
- // comparison with nullptr
- TVM_FFI_INLINE bool operator==(std::nullptr_t) const noexcept {
- return data_.type_index == TypeIndex::kTVMFFINone;
- }
- TVM_FFI_INLINE bool operator!=(std::nullptr_t) const noexcept {
- return data_.type_index != TypeIndex::kTVMFFINone;
- }
- /*!
- * \brief Get the type key of the Any
- * \return The type key of the Any
- */
- TVM_FFI_INLINE std::string GetTypeKey() const { return TypeIndexToTypeKey(data_.type_index); }
- // The following functions are only used for testing purposes
- /*!
- * \return The underlying supporting data of any view
- * \note This function is used only for testing purposes.
- */
- TVM_FFI_INLINE TVMFFIAny CopyToTVMFFIAny() const { return data_; }
- /*!
- * \return Create an AnyView from TVMFFIAny
- * \param data the underlying ffi data.
- */
- TVM_FFI_INLINE static AnyView CopyFromTVMFFIAny(TVMFFIAny data) {
- AnyView view;
- view.data_ = data;
- return view;
- }
-};
-
-namespace details {
-/*!
- * \brief Helper function to inplace convert any view to any.
- * \param data The pointer that represents the format as any view.
- * \param extra_any_bytes Indicate that the data may contain extra bytes following
- * the TVMFFIAny data structure. This is reserved for future possible optimizations
- * of small-string and extended any object.
- */
-TVM_FFI_INLINE void InplaceConvertAnyViewToAny(TVMFFIAny* data,
- [[maybe_unused]] size_t extra_any_bytes = 0) {
- if (data->type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin) {
- details::ObjectUnsafe::IncRefObjectHandle(data->v_obj);
- } else if (data->type_index >= TypeIndex::kTVMFFIRawStr) {
- if (data->type_index == TypeIndex::kTVMFFIRawStr) {
- // convert raw string to owned string object
- String temp(data->v_c_str);
- TypeTraits<String>::MoveToAny(std::move(temp), data);
- } else if (data->type_index == TypeIndex::kTVMFFIByteArrayPtr) {
- // convert byte array to owned bytes object
- Bytes temp(*static_cast<TVMFFIByteArray*>(data->v_ptr));
- TypeTraits<Bytes>::MoveToAny(std::move(temp), data);
- } else if (data->type_index == TypeIndex::kTVMFFIObjectRValueRef) {
- // convert rvalue ref to owned object
- Object** obj_addr = static_cast<Object**>(data->v_ptr);
- TVM_FFI_ICHECK(obj_addr[0] != nullptr) << "RValueRef already moved";
- ObjectRef temp(details::ObjectUnsafe::ObjectPtrFromOwned<Object>(obj_addr[0]));
- // set the rvalue ref to nullptr to avoid double move
- obj_addr[0] = nullptr;
- TypeTraits<ObjectRef>::MoveToAny(std::move(temp), data);
- }
- }
-}
-} // namespace details
-
-/*!
- * \brief Managed Any that takes strong reference to a value.
- *
- * \note Develooper invariance: the TVMFFIAny data_
- * in the Any can be safely used in AnyView.
- */
-class Any {
- protected:
- /*! \brief The underlying backing data of the any object */
- TVMFFIAny data_;
-
- public:
- /*!
- * \brief Reset any to None
- */
- TVM_FFI_INLINE void reset() {
- if (data_.type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin) {
- details::ObjectUnsafe::DecRefObjectHandle(data_.v_obj);
- }
- data_.type_index = TVMFFITypeIndex::kTVMFFINone;
- data_.zero_padding = 0;
- data_.v_int64 = 0;
- }
- /*!
- * \brief Swap this Any with another Any
- * \param other The other Any
- */
- TVM_FFI_INLINE void swap(Any& other) noexcept { std::swap(data_, other.data_); }
- /*! \return the internal type index */
- TVM_FFI_INLINE int32_t type_index() const noexcept { return data_.type_index; }
- /*!
- * \brief Default constructor
- */
- Any() {
- data_.type_index = TypeIndex::kTVMFFINone;
- data_.zero_padding = 0;
- data_.v_int64 = 0;
- }
- /*!
- * \brief Destructor
- */
- ~Any() { this->reset(); }
- /*!
- * \brief Constructor from another Any
- * \param other The other Any
- */
- Any(const Any& other) : data_(other.data_) {
- if (data_.type_index >= TypeIndex::kTVMFFIStaticObjectBegin) {
- details::ObjectUnsafe::IncRefObjectHandle(data_.v_obj);
- }
- }
- /*!
- * \brief Move constructor from another Any
- * \param other The other Any
- */
- Any(Any&& other) : data_(other.data_) {
- other.data_.type_index = TypeIndex::kTVMFFINone;
- other.data_.zero_padding = 0;
- other.data_.v_int64 = 0;
- }
- /*!
- * \brief Assign from another Any
- * \param other The other Any
- */
- TVM_FFI_INLINE Any& operator=(const Any& other) {
- // copy-and-swap idiom
- Any(other).swap(*this); // NOLINT(*)
- return *this;
- }
- /*!
- * \brief Move assign from another Any
- * \param other The other Any
- */
- TVM_FFI_INLINE Any& operator=(Any&& other) {
- // copy-and-swap idiom
- Any(std::move(other)).swap(*this); // NOLINT(*)
- return *this;
- }
- /*!
- * \brief Constructor from another AnyView
- * \param other The other AnyView
- */
- Any(const AnyView& other) : data_(other.data_) { // NOLINT(*)
- details::InplaceConvertAnyViewToAny(&data_);
- }
- /*!
- * \brief Assign from another AnyView
- * \param other The other AnyView
- */
- TVM_FFI_INLINE Any& operator=(const AnyView& other) {
- // copy-and-swap idiom
- Any(other).swap(*this); // NOLINT(*)
- return *this;
- }
- /*! \brief Any can be converted to AnyView in zero cost. */
- operator AnyView() const { return AnyView::CopyFromTVMFFIAny(data_); }
- /*!
- * \brief Constructor from a general type
- * \tparam T The value type of the other
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- Any(T other) { // NOLINT(*)
- TypeTraits<T>::MoveToAny(std::move(other), &data_);
- }
- /*!
- * \brief Assignment from a general type
- * \tparam T The value type of the other
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- TVM_FFI_INLINE Any& operator=(T other) { // NOLINT(*)
- // copy-and-swap idiom
- Any(std::move(other)).swap(*this); // NOLINT(*)
- return *this;
- }
-
- /**
- * \brief Try to reinterpret the Any as a type T, return std::nullopt if it is not possible.
- *
- * \tparam T The type to cast to.
- * \return The casted value, or std::nullopt if the cast is not possible.
- * \note This function won't try to run type conversion (use try_cast for that purpose).
- */
- template <typename T,
- typename = std::enable_if_t<TypeTraits<T>::storage_enabled || std::is_same_v<T, Any>>>
- TVM_FFI_INLINE std::optional<T> as() && {
- if constexpr (std::is_same_v<T, Any>) {
- return std::move(*this);
- } else {
- if (TypeTraits<T>::CheckAnyStrict(&data_)) {
- return TypeTraits<T>::MoveFromAnyAfterCheck(&data_);
- } else {
- return std::optional<T>(std::nullopt);
- }
- }
- }
-
- /**
- * \brief Try to reinterpret the Any as a type T, return std::nullopt if it is not possible.
- *
- * \tparam T The type to cast to.
- * \return The casted value, or std::nullopt if the cast is not possible.
- * \note This function won't try to run type conversion (use try_cast for that purpose).
- */
- template <typename T,
- typename = std::enable_if_t<TypeTraits<T>::convert_enabled || std::is_same_v<T, Any>>>
- TVM_FFI_INLINE std::optional<T> as() const& {
- if constexpr (std::is_same_v<T, Any>) {
- return *this;
- } else {
- if (TypeTraits<T>::CheckAnyStrict(&data_)) {
- return TypeTraits<T>::CopyFromAnyViewAfterCheck(&data_);
- } else {
- return std::optional<T>(std::nullopt);
- }
- }
- }
-
- /*!
- * \brief Shortcut of as Object to cast to a const pointer when T is an Object.
- *
- * \tparam T The object type.
- * \return The requested pointer, returns nullptr if type mismatches.
- */
- template <typename T, typename = std::enable_if_t<std::is_base_of_v<Object, T>>>
- TVM_FFI_INLINE const T* as() const& {
- return this->as<const T*>().value_or(nullptr);
- }
-
- /**
- * \brief Cast to a type T, throw an exception if the cast is not possible.
- *
- * \tparam T The type to cast to.
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::convert_enabled>>
- TVM_FFI_INLINE T cast() const& {
- std::optional<T> opt = TypeTraits<T>::TryCastFromAnyView(&data_);
- if (!opt.has_value()) {
- TVM_FFI_THROW(TypeError) << "Cannot convert from type `"
- << TypeTraits<T>::GetMismatchTypeInfo(&data_) << "` to `"
- << TypeTraits<T>::TypeStr() << "`";
- }
- return *std::move(opt);
- }
-
- /**
- * \brief Cast to a type T, throw an exception if the cast is not possible.
- *
- * \tparam T The type to cast to.
- */
- template <typename T, typename = std::enable_if_t<TypeTraits<T>::storage_enabled>>
- TVM_FFI_INLINE T cast() && {
- if (TypeTraits<T>::CheckAnyStrict(&data_)) {
- return TypeTraits<T>::MoveFromAnyAfterCheck(&data_);
- }
- // slow path, try to do fallback convert
- std::optional<T> opt = TypeTraits<T>::TryCastFromAnyView(&data_);
- if (!opt.has_value()) {
- TVM_FFI_THROW(TypeError) << "Cannot convert from type `"
- << TypeTraits<T>::GetMismatchTypeInfo(&data_) << "` to `"
- << TypeTraits<T>::TypeStr() << "`";
- }
- return *std::move(opt);
- }
-
- /**
- * \brief Try to cast to a type T.
- *
- * \tparam T The type to cast to.
- * \return The casted value, or std::nullopt if the cast is not possible.
- * \note use STL name since it to be more consistent with cast API.
- */
- template <typename T,
- typename = std::enable_if_t<TypeTraits<T>::convert_enabled || std::is_same_v<T, Any>>>
- TVM_FFI_INLINE std::optional<T> try_cast() const {
- if constexpr (std::is_same_v<T, Any>) {
- return *this;
- } else {
- return TypeTraits<T>::TryCastFromAnyView(&data_);
- }
- }
- /*!
- * \brief Check if the two Any are same type and value in shallow comparison.
- * \param other The other Any
- * \return True if the two Any are same type and value, false otherwise.
- */
- TVM_FFI_INLINE bool same_as(const Any& other) const noexcept {
- return data_.type_index == other.data_.type_index &&
- data_.zero_padding == other.data_.zero_padding && data_.v_int64 == other.data_.v_int64;
- }
-
- /*!
- * \brief Check if any and ObjectRef are same type and value in shallow comparison.
- * \param other The other ObjectRef
- * \return True if the two Any are same type and value, false otherwise.
- */
- TVM_FFI_INLINE bool same_as(const ObjectRef& other) const noexcept {
- if (other.get() != nullptr) {
- return (data_.type_index == other->type_index() &&
- reinterpret_cast<Object*>(data_.v_obj) == other.get());
- } else {
- return data_.type_index == TypeIndex::kTVMFFINone;
- }
- }
-
- TVM_FFI_INLINE bool operator==(std::nullptr_t) const noexcept {
- return data_.type_index == TypeIndex::kTVMFFINone;
- }
- TVM_FFI_INLINE bool operator!=(std::nullptr_t) const noexcept {
- return data_.type_index != TypeIndex::kTVMFFINone;
- }
-
- /*!
- * \brief Get the type key of the Any
- * \return The type key of the Any
- */
- TVM_FFI_INLINE std::string GetTypeKey() const { return TypeIndexToTypeKey(data_.type_index); }
-
- friend struct details::AnyUnsafe;
- friend struct AnyHash;
- friend struct AnyEqual;
-};
-
-// layout assert to ensure we can freely cast between the two types
-static_assert(sizeof(AnyView) == sizeof(TVMFFIAny));
-static_assert(sizeof(Any) == sizeof(TVMFFIAny));
-
-namespace details {
-
-template <typename Type>
-struct Type2Str {
- static std::string v() { return TypeTraitsNoCR<Type>::TypeStr(); }
-};
-
-template <>
-struct Type2Str<Any> {
- static std::string v() { return "Any"; }
-};
-
-template <>
-struct Type2Str<const Any&> {
- static std::string v() { return "Any"; }
-};
-
-template <>
-struct Type2Str<AnyView> {
- static std::string v() { return "AnyView"; }
-};
-
-template <>
-struct Type2Str<const AnyView&> {
- static std::string v() { return "AnyView"; }
-};
-
-template <>
-struct Type2Str<void> {
- static std::string v() { return "void"; }
-};
-
-// Extra unsafe method to help any manipulation
-struct AnyUnsafe : public ObjectUnsafe {
- // FFI related operations
- TVM_FFI_INLINE static TVMFFIAny MoveAnyToTVMFFIAny(Any&& any) {
- TVMFFIAny result = any.data_;
- any.data_.type_index = TypeIndex::kTVMFFINone;
- any.data_.zero_padding = 0;
- any.data_.v_int64 = 0;
- return result;
- }
-
- TVM_FFI_INLINE static Any MoveTVMFFIAnyToAny(TVMFFIAny&& data) {
- Any any;
- any.data_ = data;
- data.type_index = TypeIndex::kTVMFFINone;
- data.zero_padding = 0;
- data.v_int64 = 0;
- return any;
- }
-
- template <typename T>
- TVM_FFI_INLINE static bool CheckAnyStrict(const Any& ref) {
- return TypeTraits<T>::CheckAnyStrict(&(ref.data_));
- }
-
- template <typename T>
- TVM_FFI_INLINE static T CopyFromAnyViewAfterCheck(const Any& ref) {
- if constexpr (!std::is_same_v<T, Any>) {
- return TypeTraits<T>::CopyFromAnyViewAfterCheck(&(ref.data_));
- } else {
- return ref;
- }
- }
-
- template <typename T>
- TVM_FFI_INLINE static T MoveFromAnyAfterCheck(Any&& ref) {
- if constexpr (!std::is_same_v<T, Any>) {
- return TypeTraits<T>::MoveFromAnyAfterCheck(&(ref.data_));
- } else {
- return std::move(ref);
- }
- }
-
- TVM_FFI_INLINE static Object* ObjectPtrFromAnyAfterCheck(const Any& ref) {
- return reinterpret_cast<Object*>(ref.data_.v_obj);
- }
-
- TVM_FFI_INLINE static const TVMFFIAny* TVMFFIAnyPtrFromAny(const Any& ref) {
- return &(ref.data_);
- }
-
- template <typename T>
- TVM_FFI_INLINE static std::string GetMismatchTypeInfo(const Any& ref) {
- return TypeTraits<T>::GetMismatchTypeInfo(&(ref.data_));
- }
-};
-} // namespace details
-
-/*! \brief String-aware Any equal functor */
-struct AnyHash {
- /*!
- * \brief Calculate the hash code of an Any
- * \param a The given Any
- * \return Hash code of a, string hash for strings and pointer address otherwise.
- */
- uint64_t operator()(const Any& src) const {
- if (src.data_.type_index == TypeIndex::kTVMFFISmallStr) {
- // for small string, we use the same type key hash as normal string
- // so heap allocated string and on stack string will have the same hash
- return details::StableHashCombine(TypeIndex::kTVMFFIStr,
- details::StableHashSmallStrBytes(&src.data_));
- } else if (src.data_.type_index == TypeIndex::kTVMFFISmallBytes) {
- // use byte the same type key as bytes
- return details::StableHashCombine(TypeIndex::kTVMFFIBytes,
- details::StableHashSmallStrBytes(&src.data_));
- } else if (src.data_.type_index == TypeIndex::kTVMFFIStr ||
- src.data_.type_index == TypeIndex::kTVMFFIBytes) {
- const details::BytesObjBase* src_str =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(src);
- return details::StableHashCombine(src.data_.type_index,
- details::StableHashBytes(src_str->data, src_str->size));
- } else {
- return details::StableHashCombine(src.data_.type_index, src.data_.v_uint64);
- }
- }
-};
-
-/*! \brief String-aware Any hash functor */
-struct AnyEqual {
- /*!
- * \brief Check if the two Any are equal
- * \param lhs left operand.
- * \param rhs right operand
- * \return String equality if both are strings, pointer address equality otherwise.
- */
- bool operator()(const Any& lhs, const Any& rhs) const {
- // header with type index
- const int64_t* lhs_as_int64 = reinterpret_cast<const int64_t*>(&lhs.data_);
- const int64_t* rhs_as_int64 = reinterpret_cast<const int64_t*>(&rhs.data_);
- static_assert(sizeof(TVMFFIAny) == 16);
- // fast path, check byte equality
- if (lhs_as_int64[0] == rhs_as_int64[0] && lhs_as_int64[1] == rhs_as_int64[1]) {
- return true;
- }
- // common false case type index match, in this case we only need to pay attention to string
- // equality
- if (lhs.data_.type_index == rhs.data_.type_index) {
- // specialy handle string hash
- if (lhs.data_.type_index == TypeIndex::kTVMFFIStr ||
- lhs.data_.type_index == TypeIndex::kTVMFFIBytes) {
- const details::BytesObjBase* lhs_str =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(lhs);
- const details::BytesObjBase* rhs_str =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(rhs);
- return Bytes::memequal(lhs_str->data, rhs_str->data, lhs_str->size, rhs_str->size);
- }
- return false;
- } else {
- // type_index mismatch, if index is not string, return false
- if (lhs.data_.type_index != kTVMFFIStr && lhs.data_.type_index != kTVMFFISmallStr &&
- lhs.data_.type_index != kTVMFFISmallBytes && lhs.data_.type_index != kTVMFFIBytes) {
- return false;
- }
- // small string and normal string comparison
- if (lhs.data_.type_index == kTVMFFIStr && rhs.data_.type_index == kTVMFFISmallStr) {
- const details::BytesObjBase* lhs_str =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(lhs);
- return Bytes::memequal(lhs_str->data, rhs.data_.v_bytes, lhs_str->size,
- rhs.data_.small_str_len);
- }
- if (lhs.data_.type_index == kTVMFFISmallStr && rhs.data_.type_index == kTVMFFIStr) {
- const details::BytesObjBase* rhs_str =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(rhs);
- return Bytes::memequal(lhs.data_.v_bytes, rhs_str->data, lhs.data_.small_str_len,
- rhs_str->size);
- }
- if (lhs.data_.type_index == kTVMFFIBytes && rhs.data_.type_index == kTVMFFISmallBytes) {
- const details::BytesObjBase* lhs_bytes =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(lhs);
- return Bytes::memequal(lhs_bytes->data, rhs.data_.v_bytes, lhs_bytes->size,
- rhs.data_.small_str_len);
- }
- if (lhs.data_.type_index == kTVMFFISmallBytes && rhs.data_.type_index == kTVMFFIBytes) {
- const details::BytesObjBase* rhs_bytes =
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<const details::BytesObjBase*>(rhs);
- return Bytes::memequal(lhs.data_.v_bytes, rhs_bytes->data, lhs.data_.small_str_len,
- rhs_bytes->size);
- }
- return false;
- }
- }
-};
-} // namespace ffi
-
-// Expose to the tvm namespace for usability
-// Rationale: no ambiguity even in root
-using tvm::ffi::Any;
-using tvm::ffi::AnyView;
-
-} // namespace tvm
-#endif // TVM_FFI_ANY_H_
diff --git a/ffi/include/tvm/ffi/base_details.h b/ffi/include/tvm/ffi/base_details.h
deleted file mode 100644
index c20f0e5c05..0000000000
--- a/ffi/include/tvm/ffi/base_details.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/*!
- * \file tvm/ffi/base_details.h
- * \brief Internal detail utils that can be used by files in tvm/ffi.
- * \note details headers are for internal use only
- * and not to be directly used by user.
- */
-#ifndef TVM_FFI_BASE_DETAILS_H_
-#define TVM_FFI_BASE_DETAILS_H_
-
-#include <tvm/ffi/c_api.h>
-#include <tvm/ffi/endian.h>
-
-#include <cstddef>
-#include <utility>
-
-#if defined(_MSC_VER)
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#include <windows.h>
-
-#ifdef ERROR
-#undef ERROR
-#endif
-
-#endif
-/// \cond Doxygen_Suppress
-
-#if defined(_MSC_VER)
-#define TVM_FFI_INLINE [[msvc::forceinline]] inline
-#else
-#define TVM_FFI_INLINE [[gnu::always_inline]] inline
-#endif
-
-/*!
- * \brief Macro helper to force a function not to be inlined.
- * It is only used in places that we know not inlining is good,
- * e.g. some logging functions.
- */
-#if defined(_MSC_VER)
-#define TVM_FFI_NO_INLINE [[msvc::noinline]]
-#else
-#define TVM_FFI_NO_INLINE [[gnu::noinline]]
-#endif
-
-#if defined(_MSC_VER)
-#define TVM_FFI_UNREACHABLE() __assume(false)
-#else
-#define TVM_FFI_UNREACHABLE() __builtin_unreachable()
-#endif
-
-#define TVM_FFI_STR_CONCAT_(__x, __y) __x##__y
-#define TVM_FFI_STR_CONCAT(__x, __y) TVM_FFI_STR_CONCAT_(__x, __y)
-
-#if defined(__GNUC__) || defined(__clang__)
-#define TVM_FFI_FUNC_SIG __PRETTY_FUNCTION__
-#elif defined(_MSC_VER)
-#define TVM_FFI_FUNC_SIG __FUNCSIG__
-#else
-#define TVM_FFI_FUNC_SIG __func__
-#endif
-
-#if defined(__GNUC__)
-// gcc and clang and attribute constructor
-/// \cond Doxygen_Suppress
-#define TVM_FFI_STATIC_INIT_BLOCK_DEF_(FnName) __attribute__((constructor)) static void FnName()
-/// \endcond
-/*
- * \brief Macro that defines a block that will be called during static initialization.
- *
- * \code
- * TVM_FFI_STATIC_INIT_BLOCK() {
- * RegisterFunctions();
- * }
- * \endcode
- */
-#define TVM_FFI_STATIC_INIT_BLOCK() \
- TVM_FFI_STATIC_INIT_BLOCK_DEF_(TVM_FFI_STR_CONCAT(__TVMFFIStaticInitFunc, __COUNTER__))
-
-#else
-/// \cond Doxygen_Suppress
-// for other compilers, use the variable trick
-#define TVM_FFI_STATIC_INIT_BLOCK_DEF_(FnName, RegVar) \
- static void FnName(); \
- [[maybe_unused]] static inline int RegVar = []() { \
- FnName(); \
- return 0; \
- }(); \
- static void FnName()
-
-#define TVM_FFI_STATIC_INIT_BLOCK() \
- TVM_FFI_STATIC_INIT_BLOCK_DEF_(TVM_FFI_STR_CONCAT(__TVMFFIStaticInitFunc, __COUNTER__), \
- TVM_FFI_STR_CONCAT(__TVMFFIStaticInitReg, __COUNTER__))
-/// \endcond
-#endif
-
-/*
- * \brief Define the default copy/move constructor and assign operator
- * \param TypeName The class typename.
- */
-#define TVM_FFI_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName) \
- TypeName(const TypeName& other) = default; \
- TypeName(TypeName&& other) = default; \
- TypeName& operator=(const TypeName& other) = default; \
- TypeName& operator=(TypeName&& other) = default;
-
-/**
- * \brief marks the begining of a C call that logs exception
- */
-#define TVM_FFI_LOG_EXCEPTION_CALL_BEGIN() \
- try { \
- (void)0
-
-/*!
- * \brief Marks the end of a C call that logs exception
- */
-#define TVM_FFI_LOG_EXCEPTION_CALL_END(Name) \
- } \
- catch (const std::exception& err) { \
- std::cerr << "Exception caught during " << #Name << ":\n" << err.what() << std::endl; \
- exit(-1); \
- }
-
-/*!
- * \brief Clear the padding parts so we can safely use v_int64 for hash
- * and equality check even when the value stored is a pointer.
- *
- * This macro is used to clear the padding parts for hash and equality check
- * in 32bit platform.
- */
-#define TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result) \
- if constexpr (sizeof((result)->v_obj) != sizeof((result)->v_int64)) { \
- (result)->v_int64 = 0; \
- }
-
-namespace tvm {
-namespace ffi {
-namespace details {
-
-// for each iterator
-struct for_each_dispatcher {
- template <typename F, typename... Args, size_t... I>
- static void run(std::index_sequence<I...>, const F& f, Args&&... args) { // NOLINT(*)
- (f(I, std::forward<Args>(args)), ...);
- }
-};
-
-template <typename F, typename... Args>
-void for_each(const F& f, Args&&... args) { // NOLINT(*)
- for_each_dispatcher::run(std::index_sequence_for<Args...>{}, f, std::forward<Args>(args)...);
-}
-
-/*!
- * \brief hash an object and combines uint64_t key with previous keys
- *
- * This hash function is stable across platforms.
- *
- * \param key The left operand.
- * \param value The right operand.
- * \return the combined result.
- */
-template <typename T, std::enable_if_t<std::is_convertible<T, uint64_t>::value, bool> = true>
-TVM_FFI_INLINE uint64_t StableHashCombine(uint64_t key, const T& value) {
- // XXX: do not use std::hash in this function. This hash must be stable
- // across different platforms and std::hash is implementation dependent.
- return key ^ (uint64_t(value) + 0x9e3779b9 + (key << 6) + (key >> 2));
-}
-
-/*!
- * \brief Hash the binary bytes
- * \param data The data pointer
- * \param size The size of the bytes.
- * \return the hash value.
- */
-TVM_FFI_INLINE uint64_t StableHashBytes(const void* data_ptr, size_t size) {
- const char* data = reinterpret_cast<const char*>(data_ptr);
- const constexpr uint64_t kMultiplier = 1099511628211ULL;
- const constexpr uint64_t kMod = 2147483647ULL;
- union Union {
- uint8_t a[8];
- uint64_t b;
- } u;
- static_assert(sizeof(Union) == sizeof(uint64_t), "sizeof(Union) != sizeof(uint64_t)");
- const char* it = data;
- const char* end = it + size;
- uint64_t result = 0;
- if constexpr (TVM_FFI_IO_NO_ENDIAN_SWAP) {
- // if alignment requirement is met, directly use load
- if (reinterpret_cast<uintptr_t>(it) % 8 == 0) {
- for (; it + 8 <= end; it += 8) {
- u.b = *reinterpret_cast<const uint64_t*>(it);
- result = (result * kMultiplier + u.b) % kMod;
- }
- } else {
- // unaligned version
- for (; it + 8 <= end; it += 8) {
- u.a[0] = it[0];
- u.a[1] = it[1];
- u.a[2] = it[2];
- u.a[3] = it[3];
- u.a[4] = it[4];
- u.a[5] = it[5];
- u.a[6] = it[6];
- u.a[7] = it[7];
- result = (result * kMultiplier + u.b) % kMod;
- }
- }
- } else {
- // need endian swap
- for (; it + 8 <= end; it += 8) {
- u.a[0] = it[7];
- u.a[1] = it[6];
- u.a[2] = it[5];
- u.a[3] = it[4];
- u.a[4] = it[3];
- u.a[5] = it[2];
- u.a[6] = it[1];
- u.a[7] = it[0];
- result = (result * kMultiplier + u.b) % kMod;
- }
- }
-
- if (it < end) {
- u.b = 0;
- uint8_t* a = u.a;
- if (it + 4 <= end) {
- a[0] = it[0];
- a[1] = it[1];
- a[2] = it[2];
- a[3] = it[3];
- it += 4;
- a += 4;
- }
- if (it + 2 <= end) {
- a[0] = it[0];
- a[1] = it[1];
- it += 2;
- a += 2;
- }
- if (it + 1 <= end) {
- a[0] = it[0];
- it += 1;
- a += 1;
- }
- if constexpr (!TVM_FFI_IO_NO_ENDIAN_SWAP) {
- std::swap(u.a[0], u.a[7]);
- std::swap(u.a[1], u.a[6]);
- std::swap(u.a[2], u.a[5]);
- std::swap(u.a[3], u.a[4]);
- }
- result = (result * kMultiplier + u.b) % kMod;
- }
- return result;
-}
-
-/*!
- * \brief Same as StableHashBytes, but for small string data.
- * \param data The data pointer
- * \return the hash value.
- */
-TVM_FFI_INLINE uint64_t StableHashSmallStrBytes(const TVMFFIAny* data) {
- if constexpr (TVM_FFI_IO_NO_ENDIAN_SWAP) {
- // fast path, no endian swap, simply hash as uint64_t
- const constexpr uint64_t kMod = 2147483647ULL;
- return data->v_uint64 % kMod;
- }
- return StableHashBytes(reinterpret_cast<const void*>(data), sizeof(data->v_uint64));
-}
-
-} // namespace details
-} // namespace ffi
-} // namespace tvm
-/// \endcond
-#endif // TVM_FFI_BASE_DETAILS_H_
diff --git a/ffi/include/tvm/ffi/c_api.h b/ffi/include/tvm/ffi/c_api.h
deleted file mode 100644
index f13f820b7f..0000000000
--- a/ffi/include/tvm/ffi/c_api.h
+++ /dev/null
@@ -1,1097 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * \file tvm/ffi/c_api.h
- * \brief This file defines the C convention of the FFI convention
- */
-#ifndef TVM_FFI_C_API_H_
-#define TVM_FFI_C_API_H_
-
-#include <dlpack/dlpack.h>
-#include <stdint.h>
-
-/*
- * \brief C-style Allocator that allocates memory for a DLPack tensor.
- * \param prototype The prototype DLTensor to offer details about device and shape.
- * \param out The output DLManagedTensorVersioned.
- * \param error_ctx The context to set the error.
- * \param SetError The function to set the error.
- * \return 0 on success, -1 on failure.
- * call SetError(error_ctx, kind, message) to set the error kind and message.
- * \note Error propagation via SetError.
- */
-typedef int (*DLPackTensorAllocator)( //
- DLTensor* prototype, DLManagedTensorVersioned** out, void* error_ctx, //
- void (*SetError)(void* error_ctx, const char* kind, const char* message) //
-);
-
-// Macros to do weak linking
-#ifdef _MSC_VER
-#define TVM_FFI_WEAK __declspec(selectany)
-#else
-#define TVM_FFI_WEAK __attribute__((weak))
-#endif
-
-// Defines two macros
-// TVM_FFI_DLL: marks the function as a DLL export/import
-// depending on whether TVM_FFI_EXPORTS is defined
-// TVM_FFI_DLL_EXPORT: always marks the function as a DLL export
-#if !defined(TVM_FFI_DLL) && defined(__EMSCRIPTEN__)
-#include <emscripten/emscripten.h>
-#define TVM_FFI_DLL EMSCRIPTEN_KEEPALIVE
-#define TVM_FFI_DLL_EXPORT EMSCRIPTEN_KEEPALIVE
-#endif
-#if !defined(TVM_FFI_DLL) && defined(_MSC_VER)
-#ifdef TVM_FFI_EXPORTS
-#define TVM_FFI_DLL __declspec(dllexport)
-#else
-#define TVM_FFI_DLL __declspec(dllimport)
-#endif
-#define TVM_FFI_DLL_EXPORT __declspec(dllexport)
-#endif
-#ifndef TVM_FFI_DLL
-#define TVM_FFI_DLL __attribute__((visibility("default")))
-#define TVM_FFI_DLL_EXPORT __attribute__((visibility("default")))
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-enum TVMFFITypeIndex : int32_t {
-#else
-typedef enum {
-#endif
-
- /*
- * \brief The root type of all FFI objects.
- *
- * We include it so TypeIndex captures all possible runtime values.
- * `kTVMFFIAny` code will never appear in Any::type_index.
- * However, it may appear in field annotations during reflection.
- */
- kTVMFFIAny = -1,
- // [Section] On-stack POD and special types: [0, kTVMFFIStaticObjectBegin)
- // N.B. `kTVMFFIRawStr` is a string backed by a `\0`-terminated char array,
- // which is not owned by TVMFFIAny. It is required that the following
- // invariant holds:
- // - `Any::type_index` is never `kTVMFFIRawStr`
- // - `AnyView::type_index` can be `kTVMFFIRawStr`
- //
- /*! \brief None/nullptr value */
- kTVMFFINone = 0,
- /*! \brief POD int value */
- kTVMFFIInt = 1,
- /*! \brief POD bool value */
- kTVMFFIBool = 2,
- /*! \brief POD float value */
- kTVMFFIFloat = 3,
- /*! \brief Opaque pointer object */
- kTVMFFIOpaquePtr = 4,
- /*! \brief DLDataType */
- kTVMFFIDataType = 5,
- /*! \brief DLDevice */
- kTVMFFIDevice = 6,
- /*! \brief DLTensor* */
- kTVMFFIDLTensorPtr = 7,
- /*! \brief const char* */
- kTVMFFIRawStr = 8,
- /*! \brief TVMFFIByteArray* */
- kTVMFFIByteArrayPtr = 9,
- /*! \brief R-value reference to ObjectRef */
- kTVMFFIObjectRValueRef = 10,
- /*! \brief Small string on stack */
- kTVMFFISmallStr = 11,
- /*! \brief Small bytes on stack */
- kTVMFFISmallBytes = 12,
- /*! \brief Start of statically defined objects. */
- kTVMFFIStaticObjectBegin = 64,
- /*!
- * \brief Object, all objects starts with TVMFFIObject as its header.
- * \note We will also add other fields
- */
- kTVMFFIObject = 64,
- /*!
- * \brief String object, layout = { TVMFFIObject, TVMFFIByteArray, ... }
- */
- kTVMFFIStr = 65,
- /*!
- * \brief Bytes object, layout = { TVMFFIObject, TVMFFIByteArray, ... }
- */
- kTVMFFIBytes = 66,
- /*! \brief Error object. */
- kTVMFFIError = 67,
- /*! \brief Function object. */
- kTVMFFIFunction = 68,
- /*!
- * \brief Shape object, layout = { TVMFFIObject, { const int64_t*, size_t }, ... }
- */
- kTVMFFIShape = 69,
- /*!
- * \brief Tensor object, layout = { TVMFFIObject, DLTensor, ... }
- */
- kTVMFFITensor = 70,
- /*! \brief Array object. */
- kTVMFFIArray = 71,
- //----------------------------------------------------------------
- // more complex objects
- //----------------------------------------------------------------
- /*! \brief Map object. */
- kTVMFFIMap = 72,
- /*! \brief Runtime dynamic loaded module object. */
- kTVMFFIModule = 73,
- /*!
- * \brief Opaque python object.
- *
- * This is a special type index to indicate we are storing an opaque PyObject.
- * Such object may interact with callback functions that are registered to support
- * python-related operations.
- *
- * We only translate the objects that we do not recognize into this type index.
- *
- * \sa TVMFFIObjectCreateOpaque
- */
- kTVMFFIOpaquePyObject = 74,
- kTVMFFIStaticObjectEnd,
- // [Section] Dynamic Boxed: [kTVMFFIDynObjectBegin, +oo)
- /*! \brief Start of type indices that are allocated at runtime. */
- kTVMFFIDynObjectBegin = 128
-#ifdef __cplusplus
-};
-#else
-} TVMFFITypeIndex;
-#endif
-
-/*! \brief Handle to Object from C API's pov */
-typedef void* TVMFFIObjectHandle;
-
-/*!
- * \brief bitmask of the object deleter flag.
- */
-#ifdef __cplusplus
-enum TVMFFIObjectDeleterFlagBitMask : int32_t {
-#else
-typedef enum {
-#endif
- /*!
- * \brief deleter action when strong reference count becomes zero.
- * Need to call destructor of the object but not free the memory block.
- */
- kTVMFFIObjectDeleterFlagBitMaskStrong = 1 << 0,
- /*!
- * \brief deleter action when weak reference count becomes zero.
- * Need to free the memory block.
- */
- kTVMFFIObjectDeleterFlagBitMaskWeak = 1 << 1,
- /*!
- * \brief deleter action when both strong and weak reference counts become zero.
- * \note This is the most common case.
- */
- kTVMFFIObjectDeleterFlagBitMaskBoth =
- (kTVMFFIObjectDeleterFlagBitMaskStrong | kTVMFFIObjectDeleterFlagBitMaskWeak),
-#ifdef __cplusplus
-};
-#else
-} TVMFFIObjectDeleterFlagBitMask;
-#endif
-
-/*!
- * \brief C-based type of all FFI object header that allocates on heap.
- * \note TVMFFIObject and TVMFFIAny share the common type_index header
- */
-typedef struct {
- /*!
- * \brief type index of the object.
- * \note The type index of Object and Any are shared in FFI.
- */
- int32_t type_index;
- /*!
- * \brief Weak reference counter of the object, for compatiblity with weak_ptr design.
- * \note Use u32 to ensure that overall object stays within 24-byte boundary, usually
- * manipulation of weak counter is less common than strong counter.
- */
- uint32_t weak_ref_count;
- /*! \brief Strong reference counter of the object. */
- uint64_t strong_ref_count;
- union {
- /*!
- * \brief Deleter to be invoked when strong reference counter goes to zero.
- * \param self The self object handle.
- * \param flags The flags to indicate deletion behavior.
- * \sa TVMFFIObjectDeleterFlagBitMask
- */
- void (*deleter)(void* self, int flags);
- /*!
- * \brief auxilary field to TVMFFIObject is always 8 bytes aligned.
- * \note This helps us to ensure cross platform compatibility.
- */
- int64_t __ensure_align;
- };
-} TVMFFIObject;
-
-/*!
- * \brief C-based type of all on stack Any value.
- *
- * Any value can hold on stack values like int,
- * as well as reference counted pointers to object.
- */
-typedef struct {
- /*!
- * \brief type index of the object.
- * \note The type index of Object and Any are shared in FFI.
- */
- int32_t type_index;
- union { // 4 bytes
- /*! \brief padding, must set to zero for values other than small string. */
- uint32_t zero_padding;
- /*!
- * \brief Length of small string, with a max value of 7.
- *
- * We keep small str to start at next 4 bytes to ensure alignment
- * when accessing the small str content.
- */
- uint32_t small_str_len;
- };
- union { // 8 bytes
- int64_t v_int64; // integers
- double v_float64; // floating-point numbers
- void* v_ptr; // typeless pointers
- const char* v_c_str; // raw C-string
- TVMFFIObject* v_obj; // ref counted objects
- DLDataType v_dtype; // data type
- DLDevice v_device; // device
- char v_bytes[8]; // small string
- char32_t v_char32[2]; // small UCS4 string and Unicode
- uint64_t v_uint64; // uint64 repr mainly used for hashing
- };
-} TVMFFIAny;
-
-/*!
- * \brief Byte array data structure used by String and Bytes.
- *
- * String and Bytes object layout = { TVMFFIObject, TVMFFIByteArray, ... }
- *
- * \note This byte array data structure layout differs in 32/64 bit platforms.
- * as size_t equals to the size of the pointer, use this convetion to
- * be consistent with std::string and also avoid need to calculate padding
- * for the size field on 32-bit platforms.
- * The FFI binding should be careful when treating this ABI.
- */
-typedef struct {
- /*! \brief The data pointer. */
- const char* data;
- /*! \brief The size of the data. */
- size_t size;
-} TVMFFIByteArray;
-
-/*!
- * \brief Shape cell used in shape object following header.
- */
-typedef struct {
- /*! \brief The data pointer. */
- const int64_t* data;
- /*! \brief The size of the data. */
- size_t size;
-} TVMFFIShapeCell;
-
-/*!
- * \brief Error cell used in error object following header.
- */
-typedef struct {
- /*! \brief The kind of the error. */
- TVMFFIByteArray kind;
- /*! \brief The message of the error. */
- TVMFFIByteArray message;
- /*!
- * \brief The traceback of the error.
- */
- TVMFFIByteArray traceback;
- /*!
- * \brief Function handle to update the traceback of the error.
- * \param self The self object handle.
- * \param traceback The traceback to update.
- */
- void (*update_traceback)(TVMFFIObjectHandle self, const TVMFFIByteArray* traceback);
-} TVMFFIErrorCell;
-
-/*!
- * \brief Type that defines C-style safe call convention
- *
- * Safe call explicitly catches exception on function boundary.
- *
- * \param handle The function handle
- * \param num_args Number of input arguments
- * \param args The input arguments to the call.
- * \param result Store output result.
- *
- * IMPORTANT: caller must initialize result->type_index to be kTVMFFINone,
- * or any other value smaller than kTVMFFIStaticObjectBegin.
- *
- * \return The call returns 0 if call is successful.
- * It returns non-zero value if there is an error.
- *
- * Possible return error of the API functions:
- * * 0: success
- * * -1: error happens, can be retrieved by TVMFFIErrorMoveFromRaised
- * * -2: a frontend error occurred and recorded in the frontend.
- *
- * \note We decided to leverage TVMFFIErrorMoveFromRaised and TVMFFIErrorSetRaised
- * for C function error propagation. This design choice, while
- * introducing a dependency for TLS runtime, simplifies error
- * propgation in chains of calls in compiler codegen.
- * As we do not need to propagate error through argument but simply
- * set them in the runtime environment.
- *
- * \sa TVMFFIErrorMoveFromRaised
- * \sa TVMFFIErrorSetRaised
- * \sa TVMFFIErrorSetRaisedFromCStr
- */
-typedef int (*TVMFFISafeCallType)(void* handle, const TVMFFIAny* args, int32_t num_args,
- TVMFFIAny* result);
-
-/*!
- * \brief Object cell for function object following header.
- */
-typedef struct {
- /*! \brief A C API compatible call with exception catching. */
- TVMFFISafeCallType safe_call;
-} TVMFFIFunctionCell;
-
-/*!
- * \brief Object cell for opaque object following header.
- */
-typedef struct {
- /*! \brief The handle of the opaque object, for python it is PyObject* */
- void* handle;
-} TVMFFIOpaqueObjectCell;
-
-//------------------------------------------------------------
-// Section: Basic object API
-//------------------------------------------------------------
-/*!
- * \brief Increase the strong reference count of an object handle
- * \param obj The object handle.
- * \note Internally we increase the reference counter of the object.
- * \return 0 when success, nonzero when failure happens
- */
-TVM_FFI_DLL int TVMFFIObjectIncRef(TVMFFIObjectHandle obj);
-
-/*!
- * \brief Free an object handle by decreasing strong reference
- * \param obj The object handle.
- * \return 0 when success, nonzero when failure happens
- */
-TVM_FFI_DLL int TVMFFIObjectDecRef(TVMFFIObjectHandle obj);
-
-/*!
- * \brief Create an Opaque object by passing in handle, type_index and deleter.
- *
- * The opaque object's lifetime is managed as an Object, so it can be retained
- * and released like other objects.
- * When the opaque object is kTVMFFIOpaquePyObject, it can be converted back to
- * the python type when returned or passed as arguments to a python function.
- *
- * We can support ffi::Function that interacts with these objects,
- * most likely callback registered from python.
- *
- * For language bindings, we only convert types that we do not recognize into this type.
- * On the C++ side, the most common way to represent such OpaqueObject is to simply
- * use ffi::ObjectRef or ffi::Any.
- *
- * \param handle The resource handle of the opaque object.
- * \param type_index The type index of the object.
- * \param deleter deleter to recycle
- * \param out The output of the opaque object.
- * \return 0 when success, nonzero when failure happens
- *
- * \note The caller must ensure the type_index is a valid opaque object type index.
- * \sa kTVMFFIOpaquePyObject
- */
-TVM_FFI_DLL int TVMFFIObjectCreateOpaque(void* handle, int32_t type_index,
- void (*deleter)(void* handle), TVMFFIObjectHandle* out);
-
-/*!
- * \brief Convert type key to type index.
- * \param type_key The key of the type.
- * \param out_tindex the corresponding type index.
- * \return 0 when success, nonzero when failure happens
- */
-TVM_FFI_DLL int TVMFFITypeKeyToIndex(const TVMFFIByteArray* type_key, int32_t* out_tindex);
-
-//-----------------------------------------------------------------------
-// Section: Basic function calling API for function implementation
-//-----------------------------------------------------------------------
-/*!
- * \brief Create a FFIFunc by passing in callbacks from a C callback.
- * The registered function can then be retrieved by the backend using its name.
- * \param self The resource handle of the C callback.
- * \param safe_call The C callback implementation.
- * \param deleter The deleter to recycle.
- * \param out The output of the function.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIFunctionCreate(void* self, TVMFFISafeCallType safe_call,
- void (*deleter)(void* self), TVMFFIObjectHandle* out);
-
-/*!
- * \brief Get a global function registered in the system.
- * \param name The name of the function.
- * \param out The result function pointer, NULL if it does not exist.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIFunctionGetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle* out);
-
-/*!
- * \brief Convert an AnyView to an owned Any.
- * \param any_view The AnyView to convert.
- * \param out The output Any, must be an empty object.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIAnyViewToOwnedAny(const TVMFFIAny* any_view, TVMFFIAny* out);
-
-/*!
- * \brief Call a FFIFunc by passing in arguments.
- * \param func The resource handle of the C callback.
- * \param args The input arguments to the call.
- * \param num_args The number of input arguments.
- * \param result The output result, caller must ensure result->type_index is set to kTVMFFINone.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIFunctionCall(TVMFFIObjectHandle func, TVMFFIAny* args, int32_t num_args,
- TVMFFIAny* result);
-
-/*!
- * \brief Move the last error from the environment to the result.
- * \param result The result error.
- * \note This function clears the error stored in the TLS.
- */
-TVM_FFI_DLL void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result);
-
-/*!
- * \brief Set a raised error in TLS, which can be fetched by TVMFFIErrorMoveFromRaised.
- * \param error The error object handle
- */
-TVM_FFI_DLL void TVMFFIErrorSetRaised(TVMFFIObjectHandle error);
-
-/*!
- * \brief Set a raised error in TLS, which can be fetched by TVMFFIMoveFromRaised.
- * \param kind The kind of the error.
- * \param message The error message.
- * \note This is a convenient method for the C API side to set an error directly from a string.
- */
-TVM_FFI_DLL void TVMFFIErrorSetRaisedFromCStr(const char* kind, const char* message);
-
-/*!
- * \brief Create an initial error object.
- * \param kind The kind of the error.
- * \param message The error message.
- * \param traceback The traceback of the error.
- * \return The created error object handle.
- * \note This function is different from other functions as it is used in the error handling loop.
- * So we do not follow normal error handling patterns via returning an error code.
- */
-TVM_FFI_DLL TVMFFIObjectHandle TVMFFIErrorCreate(const TVMFFIByteArray* kind,
- const TVMFFIByteArray* message,
- const TVMFFIByteArray* traceback);
-
-//------------------------------------------------------------
-// Section: DLPack support APIs
-//------------------------------------------------------------
-/*!
- * \brief Produce a managed Tensor from a DLPack tensor.
- * \param from The source DLPack tensor.
- * \param require_alignment The minimum alignment required of the data + byte_offset.
- * \param require_contiguous Boolean flag indicating if we need to check for contiguity.
- * \param out The output Tensor handle.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITensorFromDLPack(DLManagedTensor* from, int32_t require_alignment,
- int32_t require_contiguous, TVMFFIObjectHandle* out);
-
-/*!
- * \brief Produce a DLManagedTensor from the array that shares data memory with the array.
- * \param from The source array.
- * \param out The DLManagedTensor handle.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITensorToDLPack(TVMFFIObjectHandle from, DLManagedTensor** out);
-
-/*!
- * \brief Produce a managed Tensor from a DLPack tensor.
- * \param from The source DLPack tensor.
- * \param require_alignment The minimum alignment required of the data + byte_offset.
- * \param require_contiguous Boolean flag indicating if we need to check for contiguity.
- * \param out The output Tensor handle.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITensorFromDLPackVersioned(DLManagedTensorVersioned* from,
- int32_t require_alignment,
- int32_t require_contiguous,
- TVMFFIObjectHandle* out);
-
-/*!
- * \brief Produce a DLManagedTensor from the array that shares data memory with the array.
- * \param from The source array.
- * \param out The DLManagedTensor handle.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITensorToDLPackVersioned(TVMFFIObjectHandle from,
- DLManagedTensorVersioned** out);
-//---------------------------------------------------------------
-// Section: string/bytes support APIs.
-// These APIs are used to simplify the string/bytes construction
-//---------------------------------------------------------------
-/*!
- * \brief Reinterpret the content of TVMFFIByteArray to String.
- * \param input The TVMFFIByteArray to convert.
- * \param out The output String owned by the caller, maybe a SmallStr or a Str object.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIStringFromByteArray(const TVMFFIByteArray* input, TVMFFIAny* out);
-
-/*!
- * \brief Reinterpret the content of TVMFFIByteArray to Bytes.
- * \param input The TVMFFIByteArray to convert.
- * \param out The output Bytes owned by the caller, maybe a SmallBytes or a Bytes object.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIBytesFromByteArray(const TVMFFIByteArray* input, TVMFFIAny* out);
-
-//---------------------------------------------------------------
-// Section: dtype string support APIs.
-// These APIs are used to simplify the dtype printings during FFI
-//---------------------------------------------------------------
-
-/*!
- * \brief Convert a string to a DLDataType.
- * \param str The string to convert.
- * \param out The output DLDataType.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIDataTypeFromString(const TVMFFIByteArray* str, DLDataType* out);
-
-/*!
-* \brief Convert a DLDataType to a string.
-* \param dtype The DLDataType to convert.
-* \param out The output string.
-* \return 0 on success, nonzero on failure.
-* \note out is a String object that needs to be freed by the caller via TVMFFIObjectDecRef.
-The content of string can be accessed via TVMFFIObjectGetByteArrayPtr.
-
-* \note The input dtype is a pointer to the DLDataType to avoid ABI compatibility issues.
-*/
-TVM_FFI_DLL int TVMFFIDataTypeToString(const DLDataType* dtype, TVMFFIAny* out);
-
-//------------------------------------------------------------
-// Section: Type reflection support APIs
-//
-// The reflec
-//------------------------------------------------------------
-/*!
- * \brief Getter that can take the address of a field and set the result.
- * \param field The raw address of the field.
- * \param result Stores the result.
- * \return 0 on success, nonzero on failure.
- */
-typedef int (*TVMFFIFieldGetter)(void* field, TVMFFIAny* result);
-
-/*!
- * \brief Getter that can take the address of a field and set it to a value.
- * \param field The raw address of the field.
- * \param value The value to set.
- * \return 0 on success, nonzero on failure.
- */
-typedef int (*TVMFFIFieldSetter)(void* field, const TVMFFIAny* value);
-
-/*!
- * \brief Function that creates a new instance of the type.
- * \param result The new object handle
- * \return 0 on success, nonzero on failure.
- */
-typedef int (*TVMFFIObjectCreator)(TVMFFIObjectHandle* result);
-
-/*!
- * \brief bitmask of the field.
- */
-#ifdef __cplusplus
-enum TVMFFIFieldFlagBitMask : int32_t {
-#else
-typedef enum {
-#endif
- /*! \brief The field is writable. */
- kTVMFFIFieldFlagBitMaskWritable = 1 << 0,
- /*! \brief The field has default value. */
- kTVMFFIFieldFlagBitMaskHasDefault = 1 << 1,
- /*! \brief The field is a static method. */
- kTVMFFIFieldFlagBitMaskIsStaticMethod = 1 << 2,
- /*!
- * \brief The field should be ignored when performing structural eq/hash
- *
- * This is an optional meta-data for structural eq/hash.
- */
- kTVMFFIFieldFlagBitMaskSEqHashIgnore = 1 << 3,
- /*!
- * \brief The field enters a def region where var can be defined/matched.
- *
- * This is an optional meta-data for structural eq/hash.
- */
- kTVMFFIFieldFlagBitMaskSEqHashDef = 1 << 4,
-#ifdef __cplusplus
-};
-#else
-} TVMFFIFieldFlagBitMask;
-#endif
-
-/*!
- * \brief Optional meta-data for structural eq/hash.
- *
- * This meta-data is only useful when we want to leverage the information
- * to perform richer semantics aware structural comparison and hash.
- * It can be safely ignored if such information is not needed.
- *
- * The meta-data record comparison method in tree node and DAG node.
- *
- * \code
- * x = VarNode()
- * v0 = AddNode(x, 1)
- * v1 = AddNode(x, 1)
- * v2 = AddNode(v0, v0)
- * v3 = AddNode(v1, v0)
- * \endcode
- *
- * Consider the construct sequence of AddNode below,
- * if AddNode is treated as a tree node, then v2 and v3
- * structural equals to each other, but if AddNode is
- * treated as a DAG node, then v2 and v3 does not
- * structural equals to each other.
- */
-#ifdef __cplusplus
-enum TVMFFISEqHashKind : int32_t {
-#else
-typedef enum {
-#endif
- /*! \brief Do not support structural eq/hash. */
- kTVMFFISEqHashKindUnsupported = 0,
- /*!
- * \brief The object be compared as a tree node.
- */
- kTVMFFISEqHashKindTreeNode = 1,
- /*!
- * \brief The object is treated as a free variable that can be mapped
- * to another free variable in the definition region.
- */
- kTVMFFISEqHashKindFreeVar = 2,
- /*!
- * \brief The field should be compared as a DAG node.
- */
- kTVMFFISEqHashKindDAGNode = 3,
- /*!
- * \brief The object is treated as a constant tree node.
- *
- * Same as tree node, but the object does not contain free var
- * as any of its nested children.
- *
- * That means we can use pointer equality for equality.
- */
- kTVMFFISEqHashKindConstTreeNode = 4,
- /*!
- * \brief One can simply use pointer equality for equality.
- *
- * This is useful for "singleton"-style object that can
- * is only an unique copy of each value.
- */
- kTVMFFISEqHashKindUniqueInstance = 5,
-#ifdef __cplusplus
-};
-#else
-} TVMFFISEqHashKind;
-#endif
-
-/*!
- * \brief Information support for optional object reflection.
- */
-typedef struct {
- /*! \brief The name of the field. */
- TVMFFIByteArray name;
- /*! \brief The docstring about the field. */
- TVMFFIByteArray doc;
- /*! \brief The type schema of the field in JSON string. */
- TVMFFIByteArray type_schema;
- /*!
- * \brief bitmask flags of the field.
- */
- int64_t flags;
- /*! \brief The size of the field. */
- int64_t size;
- /*! \brief The alignment of the field. */
- int64_t alignment;
- /*! \brief The offset of the field. */
- int64_t offset;
- /*! \brief The getter to access the field. */
- TVMFFIFieldGetter getter;
- /*!
- * \brief The setter to access the field.
- * \note The setter is set even if the field is readonly for serialization.
- */
- TVMFFIFieldSetter setter;
- /*!
- * \brief The default value of the field, this field hold AnyView,
- * valid when flags set kTVMFFIFieldFlagBitMaskHasDefault
- */
- TVMFFIAny default_value;
- /*!
- * \brief Records the static type kind of the field.
- *
- * Possible values:
- *
- * - TVMFFITypeIndex::kTVMFFIObject for general objects.
- * The value is nullable when kTVMFFIObject is chosen.
- * - Static object type kinds such as Map, Dict, String
- * - POD type index, note it does not give information about storage size of the field.
- * - TVMFFITypeIndex::kTVMFFIAny if we don't have specialized info
- * about the field.
- *
- * When the value is a type index of Object type, the field is storaged as an ObjectRef.
- *
- * \note This information maybe helpful in designing serializer.
- * As it helps to narrow down the field type so we don't have to
- * print type_key for cases like POD types.
- * It also helps to provide opportunities to enable short-cut getter to ObjectRef fields.
- */
- int32_t field_static_type_index;
-} TVMFFIFieldInfo;
-
-/*!
- * \brief Method information that can appear in reflection table.
- */
-typedef struct {
- /*! \brief The name of the field. */
- TVMFFIByteArray name;
- /*! \brief The docstring about the method. */
- TVMFFIByteArray doc;
- /*! \brief Optional type schema of the method in JSON string. */
- TVMFFIByteArray type_schema;
- /*! \brief bitmask flags of the method. */
- int64_t flags;
- /*!
- * \brief The method wrapped as ffi::Function, stored as AnyView.
- * \note The first argument to the method is always the self for instance methods.
- */
- TVMFFIAny method;
-} TVMFFIMethodInfo;
-
-/*!
- * \brief Extra information of object type that can be used for reflection.
- *
- * \note This information is optional and can be used to enable reflection based
- * creation of the object.
- */
-typedef struct {
- /*! \brief The docstring about the object. */
- TVMFFIByteArray doc;
- /*!
- * \brief An optional function that can create a new empty instance of the type.
- *
- * When known_fixed_size is non-zero, creator can be called
- * with nullptr passed to optional_bytes.
- *
- * \note Caller must call setter for each field to initialize the object for
- * the final object to be in valid state.
- *
- * \note This field is optional to enable reflection based creation.
- */
- TVMFFIObjectCreator creator;
- /*!
- * \brief Total size of the object struct, if it is fixed and known.
- *
- * This field is set optional and set to 0 if not registered.
- */
- int32_t total_size;
- /*!
- * \brief Optional meta-data for structural eq/hash.
- */
- TVMFFISEqHashKind structural_eq_hash_kind;
-} TVMFFITypeMetadata;
-
-/*!
- * \brief Column array that stores extra attributes about types
- *
- * The attributes stored in a column array that can be looked up by type index.
- * Note that the TypeAttr behaves like type_traits so column[T] so not contain
- * attributes from base classes.
- *
- * \note
- * \sa TVMFFIRegisterTypeAttr
- */
-typedef struct {
- /*! \brief The data of the column. */
- const TVMFFIAny* data;
- /*! \brief The size of the column. */
- size_t size;
-} TVMFFITypeAttrColumn;
-
-/*!
- * \brief Runtime type information for object type checking.
- */
-#ifdef __cplusplus
-struct TVMFFITypeInfo {
-#else
-typedef struct TVMFFITypeInfo {
-#endif
- /*!
- *\brief The runtime type index,
- * It can be allocated during runtime if the type is dynamic.
- */
- int32_t type_index;
- /*! \brief number of parent types in the type hierachy. */
- int32_t type_depth;
- /*! \brief the unique type key to identify the type. */
- TVMFFIByteArray type_key;
- /*!
- * \brief type_acenstors[depth] stores the type_index of the acenstors at depth level
- * \note To keep things simple, we do not allow multiple inheritance so the
- * hieracy stays as a tree
- */
- const struct TVMFFITypeInfo** type_acenstors;
- // The following fields are used for reflection
- /*! \brief Cached hash value of the type key, used for consistent structural hashing. */
- uint64_t type_key_hash;
- /*! \brief number of reflection accessible fields. */
- int32_t num_fields;
- /*! \brief number of reflection acccesible methods. */
- int32_t num_methods;
- /*! \brief The reflection field information. */
- const TVMFFIFieldInfo* fields;
- /*! \brief The reflection method. */
- const TVMFFIMethodInfo* methods;
- /*! \brief The extra information of the type. */
- const TVMFFITypeMetadata* metadata;
-#ifdef __cplusplus
-};
-#else
-} TVMFFITypeInfo;
-#endif
-
-/*!
- * \brief Register the function to runtime's global table.
- * The registered function can then be retrieved by the backend using its name.
- * \param name The name of the function.
- * \param f The function to be registered.
- * \param allow_override Whether to allow overriding an already registered function.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle f,
- int allow_override);
-
-/*!
- * \brief Register the function to runtime's global table with method info.
- * This is the same as TVMFFIFunctionSetGlobal but with method info that can provide extra
- * metadata used in the runtime.
- * \param method_info The method info to be registered.
- * \param allow_override Whether to allow overriding an already registered function.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFIFunctionSetGlobalFromMethodInfo(const TVMFFIMethodInfo* method_info,
- int allow_override);
-
-/*!
- * \brief Register type field information for runtime reflection.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITypeRegisterField(int32_t type_index, const TVMFFIFieldInfo* info);
-
-/*!
- * \brief Register type method information for runtime reflection.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITypeRegisterMethod(int32_t type_index, const TVMFFIMethodInfo* info);
-
-/*!
- * \brief Register type creator information for runtime reflection.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITypeRegisterMetadata(int32_t type_index, const TVMFFITypeMetadata* metadata);
-
-/*!
- * \brief Register extra type attributes that can be looked up during runtime.
- * \return 0 on success, nonzero on failure.
- */
-TVM_FFI_DLL int TVMFFITypeRegisterAttr(int32_t type_index, const TVMFFIByteArray* attr_name,
- const TVMFFIAny* attr_value);
-
-/*!
- * \brief Get the type attribute column by name.
- * \return The pointer to the type attribute column.
- * \return NULL if the attribute was not registered in the system.
- */
-TVM_FFI_DLL const TVMFFITypeAttrColumn* TVMFFIGetTypeAttrColumn(const TVMFFIByteArray* attr_name);
-
-//------------------------------------------------------------
-// Section: Backend noexcept functions for internal use
-//
-// These functions are used internally and do not throw error
-// instead the error will be logged and abort the process
-// These are function are being called in startup or exit time
-// so exception handling do not apply
-//------------------------------------------------------------
-/*!
- * \brief Get stack traceback in a string.
- * \param filename The current file name.
- * \param lineno The current line number
- * \param func The current function
- * \param cross_ffi_boundary Whether the traceback is crossing the ffi boundary
- * or we should stop at the ffi boundary when detected
- * \return The traceback string
- *
- * \note filename/func can be nullptr, then this info is skipped, they are useful
- * for cases when debug symbols are not available.
- */
-TVM_FFI_DLL const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno,
- const char* func, int cross_ffi_boundary);
-
-/*!
- * \brief Initialize the type info during runtime.
- *
- * When the function is first called for a type,
- * it will register the type to the type table in the runtime.
- * If the static_tindex is non-negative, the function will
- * allocate a runtime type index.
- * Otherwise, we will populate the type table and return the static index.
- *
- * \param type_key The type key.
- * \param type_depth The type depth.
- * \param static_type_index Static type index if any, can be -1, which means this is a dynamic index
- * \param num_child_slots Number of slots reserved for its children.
- * \param child_slots_can_overflow Whether to allow child to overflow the slots.
- * \param parent_type_index Parent type index, pass in -1 if it is root.
- *
- * \return The allocated type index.
- */
-TVM_FFI_DLL int32_t TVMFFITypeGetOrAllocIndex(const TVMFFIByteArray* type_key,
- int32_t static_type_index, int32_t type_depth,
- int32_t num_child_slots,
- int32_t child_slots_can_overflow,
- int32_t parent_type_index);
-
-/*!
- * \brief Get dynamic type info by type index.
- * \return The type info.
- */
-TVM_FFI_DLL const TVMFFITypeInfo* TVMFFIGetTypeInfo(int32_t type_index);
-
-#ifdef __cplusplus
-} // TVM_FFI_EXTERN_C
-#endif
-
-//---------------------------------------------------------------
-// The following API defines static object attribute accessors
-// for language bindings.
-//
-// They are defined in C++ inline functions for cleaner code.
-// Note that they only have to do with address offset computation.
-// So they can always be reimplemented in bindings when c++ is
-// not available or when binding only wants to refer to the dll.
-//----------------------------------------------------------------
-#ifdef __cplusplus
-/*!
- * \brief Get the type index of an object.
- * \param obj The object handle.
- * \return The type index.
- */
-inline int32_t TVMFFIObjectGetTypeIndex(TVMFFIObjectHandle obj) {
- return static_cast<TVMFFIObject*>(obj)->type_index;
-}
-
-/*!
- * \brief Get the content of a small string in bytearray format.
- * \param value The value to get the content of the small string in bytearray format.
- * \return The content of the small string in bytearray format.
- */
-inline TVMFFIByteArray TVMFFISmallBytesGetContentByteArray(const TVMFFIAny* value) {
- return TVMFFIByteArray{value->v_bytes, static_cast<size_t>(value->small_str_len)};
-}
-
-/*!
- * \brief Get the data pointer of a bytearray from a string or bytes object.
- * \param obj The object handle.
- * \return The data pointer.
- */
-inline TVMFFIByteArray* TVMFFIBytesGetByteArrayPtr(TVMFFIObjectHandle obj) {
- return reinterpret_cast<TVMFFIByteArray*>(reinterpret_cast<char*>(obj) + sizeof(TVMFFIObject));
-}
-
-/*!
- * \brief Get the data pointer of a ErrorInfo from an Error object.
- * \param obj The object handle.
- * \return The cell pointer.
- */
-inline TVMFFIErrorCell* TVMFFIErrorGetCellPtr(TVMFFIObjectHandle obj) {
- return reinterpret_cast<TVMFFIErrorCell*>(reinterpret_cast<char*>(obj) + sizeof(TVMFFIObject));
-}
-
-/*!
- * \brief Get the data pointer of a function cell from a function object.
- * \param obj The object handle.
- * \return The cell pointer.
- */
-inline TVMFFIFunctionCell* TVMFFIFunctionGetCellPtr(TVMFFIObjectHandle obj) {
- return reinterpret_cast<TVMFFIFunctionCell*>(reinterpret_cast<char*>(obj) + sizeof(TVMFFIObject));
-}
-
-/*!
- * \brief Get the data pointer of a opaque object cell from a opaque object.
- * \param obj The object handle.
- * \return The cell pointer.
- */
-inline TVMFFIOpaqueObjectCell* TVMFFIOpaqueObjectGetCellPtr(TVMFFIObjectHandle obj) {
- return reinterpret_cast<TVMFFIOpaqueObjectCell*>(reinterpret_cast<char*>(obj) +
- sizeof(TVMFFIObject));
-}
-
-/*!
- * \brief Get the data pointer of a shape array from a shape object.
- * \param obj The object handle.
- * \return The cell pointer.
- */
-inline TVMFFIShapeCell* TVMFFIShapeGetCellPtr(TVMFFIObjectHandle obj) {
- return reinterpret_cast<TVMFFIShapeCell*>(reinterpret_cast<char*>(obj) + sizeof(TVMFFIObject));
-}
-
-/*!
- * \brief Get the DLTensor pointer from an Tensor object.
- * \param obj The object handle.
- * \return The DLTensor pointer.
- */
-inline DLTensor* TVMFFITensorGetDLTensorPtr(TVMFFIObjectHandle obj) {
- return reinterpret_cast<DLTensor*>(reinterpret_cast<char*>(obj) + sizeof(TVMFFIObject));
-}
-
-/*!
- * \brief Create a DLDevice from a device type and device id.
- * \param device_type The device type.
- * \param device_id The device id.
- * \return The DLDevice.
- */
-inline DLDevice TVMFFIDLDeviceFromIntPair(int32_t device_type, int32_t device_id) {
- return DLDevice{static_cast<DLDeviceType>(device_type), device_id};
-}
-#endif // __cplusplus
-#endif // TVM_FFI_C_API_H_
diff --git a/ffi/include/tvm/ffi/cast.h b/ffi/include/tvm/ffi/cast.h
deleted file mode 100644
index 398953ad65..0000000000
--- a/ffi/include/tvm/ffi/cast.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/*!
- * \file tvm/ffi/cast.h
- * \brief Extra value casting helpers
- */
-#ifndef TVM_FFI_CAST_H_
-#define TVM_FFI_CAST_H_
-
-#include <tvm/ffi/any.h>
-#include <tvm/ffi/object.h>
-#include <tvm/ffi/optional.h>
-
-namespace tvm {
-namespace ffi {
-
-/*!
- * \brief Get a reference type from a raw object ptr type
- *
- * It is always important to get a reference type
- * if we want to return a value as reference or keep
- * the object alive beyond the scope of the function.
- *
- * \param ptr The object pointer
- * \tparam RefType The reference type
- * \tparam ObjectType The object type
- * \return The corresponding RefType
- */
-template <typename RefType, typename ObjectType>
-inline RefType GetRef(const ObjectType* ptr) {
- using ContainerType = typename RefType::ContainerType;
- static_assert(std::is_base_of_v<ContainerType, ObjectType>,
- "Can only cast to the ref of same container type");
-
- if constexpr (is_optional_type_v<RefType> || RefType::_type_is_nullable) {
- if (ptr == nullptr) {
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<RefType>(nullptr);
- }
- } else {
- TVM_FFI_ICHECK_NOTNULL(ptr);
- }
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<RefType>(
- details::ObjectUnsafe::ObjectPtrFromUnowned<Object>(
- const_cast<Object*>(static_cast<const Object*>(ptr))));
-}
-
-/*!
- * \brief Get an object ptr type from a raw object ptr.
- *
- * \param ptr The object pointer
- * \tparam BaseType The reference type
- * \tparam ObjectType The object type
- * \return The corresponding RefType
- */
-template <typename BaseType, typename ObjectType>
-inline ObjectPtr<BaseType> GetObjectPtr(ObjectType* ptr) {
- static_assert(std::is_base_of<BaseType, ObjectType>::value,
- "Can only cast to the ref of same container type");
- return details::ObjectUnsafe::ObjectPtrFromUnowned<BaseType>(ptr);
-}
-} // namespace ffi
-} // namespace tvm
-#endif // TVM_FFI_CAST_H_
diff --git a/ffi/include/tvm/ffi/container/array.h b/ffi/include/tvm/ffi/container/array.h
deleted file mode 100644
index db025c02d8..0000000000
--- a/ffi/include/tvm/ffi/container/array.h
+++ /dev/null
@@ -1,1147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file tvm/ffi/container/array.h
- * \brief Array type.
- *
- * tvm::ffi::Array<Any> is an erased type that contains a list of content
- */
-#ifndef TVM_FFI_CONTAINER_ARRAY_H_
-#define TVM_FFI_CONTAINER_ARRAY_H_
-
-#include <tvm/ffi/any.h>
-#include <tvm/ffi/container/container_details.h>
-#include <tvm/ffi/memory.h>
-#include <tvm/ffi/object.h>
-#include <tvm/ffi/optional.h>
-
-#include <algorithm>
-#include <string>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-namespace tvm {
-namespace ffi {
-
-/*! \brief Array node content in array */
-class ArrayObj : public Object, public details::InplaceArrayBase<ArrayObj, TVMFFIAny> {
- public:
- ~ArrayObj() {
- Any* begin = MutableBegin();
- for (int64_t i = 0; i < size_; ++i) {
- (begin + i)->Any::~Any();
- }
- if (data_deleter_ != nullptr) {
- data_deleter_(data_);
- }
- }
-
- /*! \return The size of the array */
- size_t size() const { return this->size_; }
-
- /*!
- * \brief Read i-th element from array.
- * \param i The index
- * \return the i-th element.
- */
- const Any& at(int64_t i) const { return this->operator[](i); }
-
- /*!
- * \brief Read i-th element from array.
- * \param i The index
- * \return the i-th element.
- */
- const Any& operator[](int64_t i) const {
- if (i >= size_) {
- TVM_FFI_THROW(IndexError) << "Index " << i << " out of bounds " << size_;
- }
- return static_cast<Any*>(data_)[i];
- }
-
- /*! \return begin constant iterator */
- const Any* begin() const { return static_cast<Any*>(data_); }
-
- /*! \return end constant iterator */
- const Any* end() const { return begin() + size_; }
-
- /*! \brief Release reference to all the elements */
- void clear() { ShrinkBy(size_); }
-
- /*!
- * \brief Set i-th element of the array in-place
- * \param i The index
- * \param item The value to be set
- */
- void SetItem(int64_t i, Any item) {
- if (i >= size_) {
- TVM_FFI_THROW(IndexError) << "Index " << i << " out of bounds " << size_;
- }
- static_cast<Any*>(data_)[i] = std::move(item);
- }
-
- /*!
- * \brief Constructs a container and copy from another
- * \param cap The capacity of the container
- * \param from Source of the copy
- * \return Ref-counted ArrayObj requested
- */
- static ObjectPtr<ArrayObj> CopyFrom(int64_t cap, ArrayObj* from) {
- int64_t size = from->size_;
- if (size > cap) {
- TVM_FFI_THROW(ValueError) << "Not enough capacity";
- }
- ObjectPtr<ArrayObj> p = ArrayObj::Empty(cap);
- Any* write = p->MutableBegin();
- Any* read = from->MutableBegin();
- // To ensure exception safety, size is only incremented after the initialization succeeds
- for (int64_t& i = p->size_ = 0; i < size; ++i) {
- new (write++) Any(*read++);
- }
- return p;
- }
-
- /*!
- * \brief Constructs a container and move from another
- * \param cap The capacity of the container
- * \param from Source of the move
- * \return Ref-counted ArrayObj requested
- */
- static ObjectPtr<ArrayObj> MoveFrom(int64_t cap, ArrayObj* from) {
- int64_t size = from->size_;
- if (size > cap) {
- TVM_FFI_THROW(RuntimeError) << "Not enough capacity";
- }
- ObjectPtr<ArrayObj> p = ArrayObj::Empty(cap);
- Any* write = p->MutableBegin();
- Any* read = from->MutableBegin();
- // To ensure exception safety, size is only incremented after the initialization succeeds
- for (int64_t& i = p->size_ = 0; i < size; ++i) {
- new (write++) Any(std::move(*read++));
- }
- from->size_ = 0;
- return p;
- }
-
- /*!
- * \brief Constructs a container with n elements. Each element is a copy of val
- * \param n The size of the container
- * \param val The init value
- * \return Ref-counted ArrayObj requested
- */
- static ObjectPtr<ArrayObj> CreateRepeated(int64_t n, const Any& val) {
- ObjectPtr<ArrayObj> p = ArrayObj::Empty(n);
- Any* itr = p->MutableBegin();
- for (int64_t& i = p->size_ = 0; i < n; ++i) {
- new (itr++) Any(val);
- }
- return p;
- }
-
- /// \cond Doxygen_Suppress
- static constexpr const int32_t _type_index = TypeIndex::kTVMFFIArray;
- static const constexpr bool _type_final = true;
- TVM_FFI_DECLARE_OBJECT_INFO_STATIC(StaticTypeKey::kTVMFFIArray, ArrayObj, Object);
- /// \endcond
-
- private:
- /*! \return Size of initialized memory, used by InplaceArrayBase. */
- size_t GetSize() const { return this->size_; }
-
- /*! \return begin mutable iterator */
- Any* MutableBegin() const { return static_cast<Any*>(this->data_); }
-
- /*! \return end mutable iterator */
- Any* MutableEnd() const { return MutableBegin() + size_; }
-
- /*!
- * \brief Emplace a new element at the back of the array
- * \param idx The index of the element.
- * \param args The arguments to construct the new element
- */
- template <typename... Args>
- void EmplaceInit(size_t idx, Args&&... args) {
- Any* itr = MutableBegin() + idx;
- new (itr) Any(std::forward<Args>(args)...);
- }
-
- /*!
- * \brief Create an ArrayObj with the given capacity.
- * \param n Required capacity
- * \return Ref-counted ArrayObj requested
- */
- static ObjectPtr<ArrayObj> Empty(int64_t n = kInitSize) {
- ObjectPtr<ArrayObj> p = make_inplace_array_object<ArrayObj, Any>(n);
- p->capacity_ = n;
- p->size_ = 0;
- p->data_ = p->AddressOf(0);
- return p;
- }
-
- /*!
- * \brief Inplace-initialize the elements starting idx from [first, last)
- * \param idx The starting point
- * \param first Begin of iterator
- * \param last End of iterator
- * \tparam IterType The type of iterator
- * \return Self
- */
- template <typename IterType>
- ArrayObj* InitRange(int64_t idx, IterType first, IterType last) {
- Any* itr = MutableBegin() + idx;
- for (; first != last; ++first) {
- Any ref = *first;
- new (itr++) Any(std::move(ref));
- }
- return this;
- }
-
- /*!
- * \brief Move elements from right to left, requires src_begin > dst
- * \param dst Destination
- * \param src_begin The start point of copy (inclusive)
- * \param src_end The end point of copy (exclusive)
- * \return Self
- */
- ArrayObj* MoveElementsLeft(int64_t dst, int64_t src_begin, int64_t src_end) {
- Any* from = MutableBegin() + src_begin;
- Any* to = MutableBegin() + dst;
- while (src_begin++ != src_end) {
- *to++ = std::move(*from++);
- }
- return this;
- }
-
- /*!
- * \brief Move elements from left to right, requires src_begin < dst
- * \param dst Destination
- * \param src_begin The start point of move (inclusive)
- * \param src_end The end point of move (exclusive)
- * \return Self
- */
- ArrayObj* MoveElementsRight(int64_t dst, int64_t src_begin, int64_t src_end) {
- Any* from = MutableBegin() + src_end;
- Any* to = MutableBegin() + (src_end - src_begin + dst);
- while (src_begin++ != src_end) {
- *--to = std::move(*--from);
- }
- return this;
- }
-
- /*!
- * \brief Enlarges the size of the array
- * \param delta Size enlarged, should be positive
- * \param val Default value
- * \return Self
- */
- ArrayObj* EnlargeBy(int64_t delta, const Any& val = Any()) {
- Any* itr = MutableEnd();
- while (delta-- > 0) {
- new (itr++) Any(val);
- ++size_;
- }
- return this;
- }
-
- /*!
- * \brief Shrinks the size of the array
- * \param delta Size shrinked, should be positive
- * \return Self
- */
- ArrayObj* ShrinkBy(int64_t delta) {
- Any* itr = MutableEnd();
- while (delta-- > 0) {
- (--itr)->Any::~Any();
- --size_;
- }
- return this;
- }
-
- /*! \brief Data pointer to the first element of the array */
- void* data_;
- /*! \brief Number of elements used */
- int64_t size_;
- /*! \brief Number of elements allocated */
- int64_t capacity_;
- /*!
- * \brief Optional data deleter when data is allocated separately
- * and its deletion is not managed by ArrayObj::deleter_.
- */
- void (*data_deleter_)(void*) = nullptr;
-
- /*! \brief Initial size of ArrayObj */
- static constexpr int64_t kInitSize = 4;
-
- /*! \brief Expansion factor of the Array */
- static constexpr int64_t kIncFactor = 2;
-
- // CRTP parent class
- friend InplaceArrayBase<ArrayObj, Any>;
-
- // Reference class
- template <typename, typename>
- friend class Array;
-
- template <typename... Types>
- friend class Tuple;
-
- template <typename, typename>
- friend struct TypeTraits;
-
- // To specialize make_object<ArrayObj>
- friend ObjectPtr<ArrayObj> make_object<>();
-};
-
-/*! \brief Helper struct for type-checking
- *
- * is_valid_iterator<T,IterType>::value will be true if IterType can
- * be dereferenced into a type that can be stored in an Array<T>, and
- * false otherwise.
- */
-template <typename T, typename IterType>
-struct is_valid_iterator
- : std::bool_constant<
- std::is_same_v<
- T, std::remove_cv_t<std::remove_reference_t<decltype(*std::declval<IterType>())>>> ||
- std::is_base_of_v<
- T, std::remove_cv_t<std::remove_reference_t<decltype(*std::declval<IterType>())>>>> {
-};
-
-template <typename T, typename IterType>
-struct is_valid_iterator<Optional<T>, IterType> : is_valid_iterator<T, IterType> {};
-
-template <typename IterType>
-struct is_valid_iterator<Any, IterType> : std::true_type {};
-
-/*!
- * \brief Check whether IterType is valid iterator for T.
- * \tparam T The type.
- * \tparam IterType The type of iterator.
- */
-template <typename T, typename IterType>
-inline constexpr bool is_valid_iterator_v = is_valid_iterator<T, IterType>::value;
-
-/*!
- * \brief Array, container representing a contiguous sequence of ObjectRefs.
- *
- * Array implements in-place copy-on-write semantics.
- *
- * As in typical copy-on-write, a method which would typically mutate the array
- * instead opaquely copies the underlying container, and then acts on its copy.
- *
- * If the array has reference count equal to one, we directly update the
- * container in place without copying. This is optimization is sound because
- * when the reference count is equal to one this reference is guranteed to be
- * the sole pointer to the container.
- *
- *
- * operator[] only provides const access, use Set to mutate the content.
- * \tparam T The content Value type, must be compatible with tvm::ffi::Any
- */
-template <typename T, typename = typename std::enable_if_t<details::storage_enabled_v<T>>>
-class Array : public ObjectRef {
- public:
- /*! \brief The value type of the array */
- using value_type = T;
- // constructors
- /*!
- * \brief Construct an Array with UnsafeInit
- */
- explicit Array(UnsafeInit tag) : ObjectRef(tag) {}
- /*!
- * \brief default constructor
- */
- Array() { data_ = ArrayObj::Empty(); }
- /*!
- * \brief Move constructor
- * \param other The other array
- */
- Array(Array<T>&& other) : ObjectRef(std::move(other.data_)) {}
- /*!
- * \brief Copy constructor
- * \param other The other array
- */
- Array(const Array<T>& other) : ObjectRef(other.data_) {}
- /*!
- * \brief Constructor from another array
- * \param other The other array
- * \tparam U The value type of the other array
- */
- template <typename U, typename = std::enable_if_t<details::type_contains_v<T, U>>>
- Array(Array<U>&& other) : ObjectRef(std::move(other.data_)) {}
- /*!
- * \brief Constructor from another array
- * \param other The other array
- * \tparam U The value type of the other array
- */
- template <typename U, typename = std::enable_if_t<details::type_contains_v<T, U>>>
- Array(const Array<U>& other) : ObjectRef(other.data_) {}
-
- /*!
- * \brief Move assignment from another array
- * \param other The other array
- */
- TVM_FFI_INLINE Array<T>& operator=(Array<T>&& other) {
- data_ = std::move(other.data_);
- return *this;
- }
- /*!
- * \brief Assignment from another array
- * \param other The other array
- */
- TVM_FFI_INLINE Array<T>& operator=(const Array<T>& other) {
- data_ = other.data_;
- return *this;
- }
- /*!
- * \brief Move assignment from another array
- * \param other The other array
- * \tparam U The value type of the other array
- */
- template <typename U, typename = std::enable_if_t<details::type_contains_v<T, U>>>
- TVM_FFI_INLINE Array<T>& operator=(Array<U>&& other) {
- data_ = std::move(other.data_);
- return *this;
- }
- /*!
- * \brief Assignment from another array
- * \param other The other array
- * \tparam U The value type of the other array
- */
- template <typename U, typename = std::enable_if_t<details::type_contains_v<T, U>>>
- TVM_FFI_INLINE Array<T>& operator=(const Array<U>& other) {
- data_ = other.data_;
- return *this;
- }
-
- /*!
- * \brief Constructor from pointer
- * \param n the container pointer
- */
- explicit Array(ObjectPtr<Object> n) : ObjectRef(n) {}
-
- /*!
- * \brief Constructor from iterator
- * \param first begin of iterator
- * \param last end of iterator
- * \tparam IterType The type of iterator
- */
- template <typename IterType>
- Array(IterType first, IterType last) {
- static_assert(is_valid_iterator_v<T, IterType>,
- "IterType cannot be inserted into a tvm::Array<T>");
- Assign(first, last);
- }
-
- /*!
- * \brief constructor from initializer list
- * \param init The initializer list
- */
- Array(std::initializer_list<T> init) { // NOLINT(*)
- Assign(init.begin(), init.end());
- }
-
- /*!
- * \brief constructor from vector
- * \param init The vector
- */
- Array(const std::vector<T>& init) { // NOLINT(*)
- Assign(init.begin(), init.end());
- }
-
- /*!
- * \brief Constructs a container with n elements. Each element is a copy of val
- * \param n The size of the container
- * \param val The init value
- */
- explicit Array(const size_t n, const T& val) { data_ = ArrayObj::CreateRepeated(n, val); }
-
- public:
- // iterators
- /// \cond Doxygen_Suppress
- struct ValueConverter {
- using ResultType = T;
- /*!
- * \brief Convert any to T
- * \param n The any value to convert
- * \return The converted value
- */
- static T convert(const Any& n) { return details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(n); }
- };
- /// \endcond
-
- /*! \brief The iterator type of the array */
- using iterator = details::IterAdapter<ValueConverter, const Any*>;
- /*! \brief The reverse iterator type of the array */
- using reverse_iterator = details::ReverseIterAdapter<ValueConverter, const Any*>;
-
- /*! \return begin iterator */
- iterator begin() const { return iterator(GetArrayObj()->begin()); }
-
- /*! \return end iterator */
- iterator end() const { return iterator(GetArrayObj()->end()); }
-
- /*! \return rbegin iterator */
- reverse_iterator rbegin() const {
- // ArrayObj::end() is never nullptr
- return reverse_iterator(GetArrayObj()->end() - 1);
- }
-
- /*! \return rend iterator */
- reverse_iterator rend() const {
- // ArrayObj::begin() is never nullptr
- return reverse_iterator(GetArrayObj()->begin() - 1);
- }
-
- public:
- // const methods in std::vector
- /*!
- * \brief Immutably read i-th element from array.
- * \param i The index
- * \return the i-th element.
- */
- const T operator[](int64_t i) const {
- ArrayObj* p = GetArrayObj();
- if (p == nullptr) {
- TVM_FFI_THROW(IndexError) << "cannot index a null array";
- }
- if (i < 0 || i >= p->size_) {
- TVM_FFI_THROW(IndexError) << "indexing " << i << " on an array of size " << p->size_;
- }
- return details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(*(p->begin() + i));
- }
-
- /*! \return The size of the array */
- size_t size() const {
- ArrayObj* p = GetArrayObj();
- return p == nullptr ? 0 : GetArrayObj()->size_;
- }
-
- /*! \return The capacity of the array */
- size_t capacity() const {
- ArrayObj* p = GetArrayObj();
- return p == nullptr ? 0 : GetArrayObj()->capacity_;
- }
-
- /*! \return Whether array is empty */
- bool empty() const { return size() == 0; }
-
- /*! \return The first element of the array */
- const T front() const {
- ArrayObj* p = GetArrayObj();
- if (p == nullptr || p->size_ == 0) {
- TVM_FFI_THROW(IndexError) << "cannot index a empty array";
- }
- return details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(*(p->begin()));
- }
-
- /*! \return The last element of the array */
- const T back() const {
- ArrayObj* p = GetArrayObj();
- if (p == nullptr || p->size_ == 0) {
- TVM_FFI_THROW(IndexError) << "cannot index a empty array";
- }
- return details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(*(p->end() - 1));
- }
-
- public:
- // mutation in std::vector, implements copy-on-write
- /*!
- * \brief push a new item to the back of the list
- * \param item The item to be pushed.
- */
- void push_back(const T& item) {
- ArrayObj* p = CopyOnWrite(1);
- p->EmplaceInit(p->size_++, item);
- }
-
- /*!
- * \brief Emplace a new element at the back of the array
- * \param args The arguments to construct the new element
- */
- template <typename... Args>
- void emplace_back(Args&&... args) {
- ArrayObj* p = CopyOnWrite(1);
- p->EmplaceInit(p->size_++, std::forward<Args>(args)...);
- }
-
- /*!
- * \brief Insert an element into the given position
- * \param position An iterator pointing to the insertion point
- * \param val The element to insert
- */
- void insert(iterator position, const T& val) {
- if (data_ == nullptr) {
- TVM_FFI_THROW(RuntimeError) << "cannot insert a null array";
- }
- int64_t idx = std::distance(begin(), position);
- int64_t size = GetArrayObj()->size_;
- auto addr = CopyOnWrite(1) //
- ->EnlargeBy(1) //
- ->MoveElementsRight(idx + 1, idx, size) //
- ->MutableBegin();
- new (addr + idx) Any(val);
- }
-
- /*!
- * \brief Insert a range of elements into the given position
- * \param position An iterator pointing to the insertion point
- * \param first The begin iterator of the range
- * \param last The end iterator of the range
- */
- template <typename IterType>
- void insert(iterator position, IterType first, IterType last) {
- static_assert(is_valid_iterator_v<T, IterType>,
- "IterType cannot be inserted into a tvm::Array<T>");
-
- if (first == last) {
- return;
- }
- if (data_ == nullptr) {
- TVM_FFI_THROW(RuntimeError) << "cannot insert a null array";
- }
- int64_t idx = std::distance(begin(), position);
- int64_t size = GetArrayObj()->size_;
- int64_t numel = std::distance(first, last);
- CopyOnWrite(numel)
- ->EnlargeBy(numel)
- ->MoveElementsRight(idx + numel, idx, size)
- ->InitRange(idx, first, last);
- }
-
- /*! \brief Remove the last item of the list */
- void pop_back() {
- if (data_ == nullptr) {
- TVM_FFI_THROW(RuntimeError) << "cannot pop_back a null array";
- }
- int64_t size = GetArrayObj()->size_;
- if (size == 0) {
- TVM_FFI_THROW(RuntimeError) << "cannot pop_back an empty array";
- }
- CopyOnWrite()->ShrinkBy(1);
- }
-
- /*!
- * \brief Erase an element on the given position
- * \param position An iterator pointing to the element to be erased
- */
- void erase(iterator position) {
- if (data_ == nullptr) {
- TVM_FFI_THROW(RuntimeError) << "cannot erase a null array";
- }
- int64_t st = std::distance(begin(), position);
- int64_t size = GetArrayObj()->size_;
- if (st < 0 || st >= size) {
- TVM_FFI_THROW(RuntimeError) << "cannot erase at index " << st << ", because Array size is "
- << size;
- }
- CopyOnWrite() //
- ->MoveElementsLeft(st, st + 1, size) //
- ->ShrinkBy(1);
- }
-
- /*!
- * \brief Erase a given range of elements
- * \param first The begin iterator of the range
- * \param last The end iterator of the range
- */
- void erase(iterator first, iterator last) {
- if (first == last) {
- return;
- }
- if (data_ == nullptr) {
- TVM_FFI_THROW(RuntimeError) << "cannot erase a null array";
- }
- int64_t size = GetArrayObj()->size_;
- int64_t st = std::distance(begin(), first);
- int64_t ed = std::distance(begin(), last);
- if (st >= ed) {
- TVM_FFI_THROW(IndexError) << "cannot erase array in range [" << st << ", " << ed << ")";
- }
- if (st < 0 || st > size || ed < 0 || ed > size) {
- TVM_FFI_THROW(IndexError) << "cannot erase array in range [" << st << ", " << ed << ")"
- << ", because array size is " << size;
- }
- CopyOnWrite() //
- ->MoveElementsLeft(st, ed, size) //
- ->ShrinkBy(ed - st);
- }
-
- /*!
- * \brief Resize the array.
- * \param n The new size.
- */
- void resize(int64_t n) {
- if (n < 0) {
- TVM_FFI_THROW(ValueError) << "cannot resize an Array to negative size";
- }
- if (data_ == nullptr) {
- SwitchContainer(n);
- return;
- }
- int64_t size = GetArrayObj()->size_;
- if (size < n) {
- CopyOnWrite(n - size)->EnlargeBy(n - size);
- } else if (size > n) {
- CopyOnWrite()->ShrinkBy(size - n);
- }
- }
-
- /*!
- * \brief Make sure the list has the capacity of at least n
- * \param n lower bound of the capacity
- */
- void reserve(int64_t n) {
- if (data_ == nullptr || n > GetArrayObj()->capacity_) {
- SwitchContainer(n);
- }
- }
-
- /*! \brief Release reference to all the elements */
- void clear() {
- if (data_ != nullptr) {
- ArrayObj* p = CopyOnWrite();
- p->clear();
- }
- }
- /// \cond Doxygen_Suppress
- template <typename... Args>
- static size_t CalcCapacityImpl() {
- return 0;
- }
-
- template <typename... Args>
- static size_t CalcCapacityImpl(Array<T> value, Args... args) {
- return value.size() + CalcCapacityImpl(args...);
- }
-
- template <typename... Args>
- static size_t CalcCapacityImpl(T value, Args... args) {
- return 1 + CalcCapacityImpl(args...);
- }
-
- template <typename... Args>
- static void AgregateImpl(Array<T>& dest) {} // NOLINT(*)
-
- template <typename... Args>
- static void AgregateImpl(Array<T>& dest, Array<T> value, Args... args) { // NOLINT(*)
- dest.insert(dest.end(), value.begin(), value.end());
- AgregateImpl(dest, args...);
- }
-
- template <typename... Args>
- static void AgregateImpl(Array<T>& dest, T value, Args... args) { // NOLINT(*)
- dest.push_back(value);
- AgregateImpl(dest, args...);
- }
- /// \endcond
-
- public:
- // Array's own methods
-
- /*!
- * \brief set i-th element of the array.
- * \param i The index
- * \param value The value to be setted.
- */
- void Set(int64_t i, T value) {
- ArrayObj* p = this->CopyOnWrite();
- if (i < 0 || i >= p->size_) {
- TVM_FFI_THROW(IndexError) << "indexing " << i << " on an array of size " << p->size_;
- }
- *(p->MutableBegin() + i) = std::move(value);
- }
-
- /*! \return The underlying ArrayObj */
- ArrayObj* GetArrayObj() const { return static_cast<ArrayObj*>(data_.get()); }
-
- /*!
- * \brief Helper function to apply a map function onto the array.
- *
- * \param fmap The transformation function T -> U.
- *
- * \tparam F The type of the mutation function.
- *
- * \tparam U The type of the returned array, inferred from the
- * return type of F. If overridden by the user, must be something
- * that is convertible from the return type of F.
- *
- * \note This function performs copy on write optimization. If
- * `fmap` returns an object of type `T`, and all elements of the
- * array are mapped to themselves, then the returned array will be
- * the same as the original, and reference counts of the elements in
- * the array will not be incremented.
- *
- * \return The transformed array.
- */
- template <typename F, typename U = std::invoke_result_t<F, T>>
- Array<U> Map(F fmap) const {
- return Array<U>(MapHelper(data_, fmap));
- }
-
- /*!
- * \brief Helper function to apply fmutate to mutate an array.
- * \param fmutate The transformation function T -> T.
- * \tparam F the type of the mutation function.
- * \note This function performs copy on write optimization.
- */
- template <typename F, typename = std::enable_if_t<std::is_same_v<T, std::invoke_result_t<F, T>>>>
- void MutateByApply(F fmutate) {
- data_ = MapHelper(std::move(data_), fmutate);
- }
-
- /*!
- * \brief reset the array to content from iterator.
- * \param first begin of iterator
- * \param last end of iterator
- * \tparam IterType The type of iterator
- */
- template <typename IterType>
- void Assign(IterType first, IterType last) {
- int64_t cap = std::distance(first, last);
- if (cap < 0) {
- TVM_FFI_THROW(ValueError) << "cannot construct an Array of negative size";
- }
- ArrayObj* p = GetArrayObj();
- if (p != nullptr && data_.unique() && p->capacity_ >= cap) {
- // do not have to make new space
- p->clear();
- } else {
- // create new space
- data_ = ArrayObj::Empty(cap);
- p = GetArrayObj();
- }
- // To ensure exception safety, size is only incremented after the initialization succeeds
- Any* itr = p->MutableBegin();
- for (int64_t& i = p->size_ = 0; i < cap; ++i, ++first, ++itr) {
- new (itr) Any(*first);
- }
- }
-
- /*!
- * \brief Copy on write semantics
- * Do nothing if current handle is the unique copy of the array.
- * Otherwise make a new copy of the array to ensure the current handle
- * hold a unique copy.
- *
- * \return Handle to the internal node container(which ganrantees to be unique)
- */
- ArrayObj* CopyOnWrite() {
- if (data_ == nullptr) {
- return SwitchContainer(ArrayObj::kInitSize);
- }
- if (!data_.unique()) {
- return SwitchContainer(capacity());
- }
- return static_cast<ArrayObj*>(data_.get());
- }
-
- /*! \brief specify container node */
- using ContainerType = ArrayObj;
-
- /*!
- * \brief Agregate arguments into a single Array<T>
- * \param args sequence of T or Array<T> elements
- * \return Agregated Array<T>
- */
- template <typename... Args>
- static Array<T> Agregate(Args... args) {
- Array<T> result;
- result.reserve(CalcCapacityImpl(args...));
- AgregateImpl(result, args...);
- return result;
- }
-
- private:
- /*!
- * \brief Implement copy-on-write semantics, and ensures capacity is enough for extra elements.
- * \param reserve_extra Number of extra slots needed
- * \return ArrayObj pointer to the unique copy
- */
- ArrayObj* CopyOnWrite(int64_t reserve_extra) {
- ArrayObj* p = GetArrayObj();
- if (p == nullptr) {
- // necessary to get around the constexpr address issue before c++17
- const int64_t kInitSize = ArrayObj::kInitSize;
- return SwitchContainer(std::max(kInitSize, reserve_extra));
- }
- if (p->capacity_ >= p->size_ + reserve_extra) {
- return CopyOnWrite();
- }
- int64_t cap = p->capacity_ * ArrayObj::kIncFactor;
- cap = std::max(cap, p->size_ + reserve_extra);
- return SwitchContainer(cap);
- }
-
- /*!
- * \brief Move or copy the ArrayObj to new address with the given capacity
- * \param capacity The capacity requirement of the new address
- */
- ArrayObj* SwitchContainer(int64_t capacity) {
- if (data_ == nullptr) {
- data_ = ArrayObj::Empty(capacity);
- } else if (data_.unique()) {
- data_ = ArrayObj::MoveFrom(capacity, GetArrayObj());
- } else {
- data_ = ArrayObj::CopyFrom(capacity, GetArrayObj());
- }
- return static_cast<ArrayObj*>(data_.get());
- }
-
- /*! \brief Helper method for mutate/map
- *
- * A helper function used internally by both `Array::Map` and
- * `Array::MutateInPlace`. Given an array of data, apply the
- * mapping function to each element, returning the collected array.
- * Applies both mutate-in-place and copy-on-write optimizations, if
- * possible.
- *
- * \param data A pointer to the ArrayObj containing input data.
- * Passed by value to allow for mutate-in-place optimizations.
- *
- * \param fmap The mapping function
- *
- * \tparam F The type of the mutation function.
- *
- * \tparam U The output type of the mutation function. Inferred
- * from the callable type given. Must inherit from ObjectRef.
- *
- * \return The mapped array. Depending on whether mutate-in-place
- * or copy-on-write optimizations were applicable, may be the same
- * underlying array as the `data` parameter.
- */
- template <typename F, typename U = std::invoke_result_t<F, T>>
- static ObjectPtr<Object> MapHelper(ObjectPtr<Object> data, F fmap) {
- if (data == nullptr) {
- return nullptr;
- }
-
- TVM_FFI_ICHECK(data->IsInstance<ArrayObj>());
-
- constexpr bool is_same_output_type = std::is_same_v<T, U>;
-
- if constexpr (is_same_output_type) {
- if (data.unique()) {
- // Mutate-in-place path. Only allowed if the output type U is
- // the same as type T, we have a mutable this*, and there are
- // no other shared copies of the array.
- auto arr = static_cast<ArrayObj*>(data.get());
- for (auto it = arr->MutableBegin(); it != arr->MutableEnd(); it++) {
- T value = details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(*it);
- // reset the original value to nullptr, to ensure unique ownership
- it->reset();
- T mapped = fmap(std::move(value));
- *it = std::move(mapped);
- }
- return data;
- }
- }
-
- constexpr bool compatible_types = is_valid_iterator_v<T, U*> || is_valid_iterator_v<U, T*>;
-
- ObjectPtr<ArrayObj> output = nullptr;
- auto arr = static_cast<ArrayObj*>(data.get());
-
- auto it = arr->begin();
- if constexpr (compatible_types) {
- // Copy-on-write path, if the output Array<U> might be
- // represented by the same underlying array as the existing
- // Array<T>. Typically, this is for functions that map `T` to
- // `T`, but can also apply to functions that map `T` to
- // `Optional<T>`, or that map `T` to a subclass or superclass of
- // `T`.
- bool all_identical = true;
- for (; it != arr->end(); it++) {
- U mapped = fmap(details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(*it));
- if (!(*it).same_as(mapped)) {
- // At least one mapped element is different than the
- // original. Therefore, prepare the output array,
- // consisting of any previous elements that had mapped to
- // themselves (if any), and the element that didn't map to
- // itself.
- //
- // We cannot use `U()` as the default object, as `U` may be
- // a non-nullable type. Since the default `Any()`
- // will be overwritten before returning, all objects will be
- // of type `U` for the calling scope.
- all_identical = false;
- output = ArrayObj::CreateRepeated(arr->size(), Any());
- output->InitRange(0, arr->begin(), it);
- output->SetItem(it - arr->begin(), std::move(mapped));
- it++;
- break;
- }
- }
- if (all_identical) {
- return data;
- }
- } else {
- // Path for incompatible types. The constexpr check for
- // compatible types isn't strictly necessary, as the first
- // (*it).same_as(mapped) would return false, but we might as well
- // avoid it altogether.
- //
- // We cannot use `U()` as the default object, as `U` may be a
- // non-nullable type. Since the default `Any()` will be
- // overwritten before returning, all objects will be of type `U`
- // for the calling scope.
- output = ArrayObj::CreateRepeated(arr->size(), Any());
- }
-
- // Normal path for incompatible types, or post-copy path for
- // copy-on-write instances.
- //
- // If the types are incompatible, then at this point `output` is
- // empty, and `it` points to the first element of the input.
- //
- // If the types were compatible, then at this point `output`
- // contains zero or more elements that mapped to themselves
- // followed by the first element that does not map to itself, and
- // `it` points to the element just after the first element that
- // does not map to itself. Because at least one element has been
- // changed, we no longer have the opportunity to avoid a copy, so
- // we don't need to check the result.
- //
- // In both cases, `it` points to the next element to be processed,
- // so we can either start or resume the iteration from that point,
- // with no further checks on the result.
- for (; it != arr->end(); it++) {
- U mapped = fmap(details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(*it));
- output->SetItem(it - arr->begin(), std::move(mapped));
- }
-
- return output;
- }
- template <typename, typename>
- friend class Array;
-};
-
-/*!
- * \brief Concat two Arrays.
- * \param lhs first Array to be concatenated.
- * \param rhs second Array to be concatenated.
- * \return The concatenated Array. Original Arrays are kept unchanged.
- */
-template <typename T, typename = typename std::enable_if_t<std::is_same_v<T, Any> ||
- TypeTraits<T>::convert_enabled>>
-inline Array<T> Concat(Array<T> lhs, const Array<T>& rhs) {
- for (const auto& x : rhs) {
- lhs.push_back(x);
- }
- return std::move(lhs);
-}
-
-/*!
- * \brief Specialize make_object<ArrayObj>
- * \return The empty array object.
- */
-template <>
-inline ObjectPtr<ArrayObj> make_object() {
- return ArrayObj::Empty();
-}
-
-// Traits for Array
-template <typename T>
-inline constexpr bool use_default_type_traits_v<Array<T>> = false;
-
-template <typename T>
-struct TypeTraits<Array<T>> : public ObjectRefTypeTraitsBase<Array<T>> {
- static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIArray;
- using ObjectRefTypeTraitsBase<Array<T>>::CopyFromAnyViewAfterCheck;
-
- TVM_FFI_INLINE static std::string GetMismatchTypeInfo(const TVMFFIAny* src) {
- if (src->type_index != TypeIndex::kTVMFFIArray) {
- return TypeTraitsBase::GetMismatchTypeInfo(src);
- }
- if constexpr (!std::is_same_v<T, Any>) {
- const ArrayObj* n = reinterpret_cast<const ArrayObj*>(src->v_obj);
- for (size_t i = 0; i < n->size(); i++) {
- const Any& any_v = (*n)[i];
- // CheckAnyStrict is cheaper than try_cast<T>
- if (details::AnyUnsafe::CheckAnyStrict<T>(any_v)) continue;
- // try see if p is convertible to T
- if (any_v.try_cast<T>()) continue;
- // now report the accurate mismatch information
- return "Array[index " + std::to_string(i) + ": " +
- details::AnyUnsafe::GetMismatchTypeInfo<T>(any_v) + "]";
- }
- }
- TVM_FFI_THROW(InternalError) << "Cannot reach here";
- TVM_FFI_UNREACHABLE();
- }
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- if (src->type_index != TypeIndex::kTVMFFIArray) return false;
- if constexpr (std::is_same_v<T, Any>) {
- return true;
- } else {
- const ArrayObj* n = reinterpret_cast<const ArrayObj*>(src->v_obj);
- for (size_t i = 0; i < n->size(); i++) {
- const Any& any_v = (*n)[i];
- if (!details::AnyUnsafe::CheckAnyStrict<T>(any_v)) return false;
- }
- return true;
- }
- }
-
- TVM_FFI_INLINE static std::optional<Array<T>> TryCastFromAnyView(const TVMFFIAny* src) {
- // try to run conversion.
- if (src->type_index != TypeIndex::kTVMFFIArray) return std::nullopt;
- if constexpr (!std::is_same_v<T, Any>) {
- const ArrayObj* n = reinterpret_cast<const ArrayObj*>(src->v_obj);
- bool storage_check = [&]() {
- for (size_t i = 0; i < n->size(); i++) {
- const Any& any_v = (*n)[i];
- if (!details::AnyUnsafe::CheckAnyStrict<T>(any_v)) return false;
- }
- return true;
- }();
- // fast path, if storage check passes, we can return the array directly.
- if (storage_check) {
- return CopyFromAnyViewAfterCheck(src);
- }
- // slow path, try to run a conversion to Array<T>
- Array<T> result;
- result.reserve(n->size());
- for (size_t i = 0; i < n->size(); i++) {
- const Any& any_v = (*n)[i];
- if (auto opt_v = any_v.try_cast<T>()) {
- result.push_back(*std::move(opt_v));
- } else {
- return std::nullopt;
- }
- }
- return result;
- } else {
- return CopyFromAnyViewAfterCheck(src);
- }
- }
-
- TVM_FFI_INLINE static std::string TypeStr() { return "Array<" + details::Type2Str<T>::v() + ">"; }
-};
-
-namespace details {
-template <typename T, typename U>
-inline constexpr bool type_contains_v<Array<T>, Array<U>> = type_contains_v<T, U>;
-} // namespace details
-
-} // namespace ffi
-} // namespace tvm
-#endif // TVM_FFI_CONTAINER_ARRAY_H_
diff --git a/ffi/include/tvm/ffi/container/container_details.h b/ffi/include/tvm/ffi/container/container_details.h
deleted file mode 100644
index bb29a14f7c..0000000000
--- a/ffi/include/tvm/ffi/container/container_details.h
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file tvm/ffi/container/container_details.h
- * \brief Common utilities for typed container types.
- */
-#ifndef TVM_FFI_CONTAINER_CONTAINER_DETAILS_H_
-#define TVM_FFI_CONTAINER_CONTAINER_DETAILS_H_
-
-#include <tvm/ffi/memory.h>
-#include <tvm/ffi/object.h>
-
-#include <sstream>
-#include <string>
-#include <type_traits>
-#include <utility>
-
-namespace tvm {
-namespace ffi {
-namespace details {
-/*!
- * \brief Base template for classes with array like memory layout.
- *
- * It provides general methods to access the memory. The memory
- * layout is ArrayType + [ElemType]. The alignment of ArrayType
- * and ElemType is handled by the memory allocator.
- *
- * \tparam ArrayType The array header type, contains object specific metadata.
- * \tparam ElemType The type of objects stored in the array right after
- * ArrayType.
- *
- * \code
- * // Example usage of the template to define a simple array wrapper
- * class ArrayObj : public tvm::ffi::details::InplaceArrayBase<ArrayObj, Elem> {
- * public:
- * // Wrap EmplaceInit to initialize the elements
- * template <typename Iterator>
- * void Init(Iterator begin, Iterator end) {
- * size_t num_elems = std::distance(begin, end);
- * auto it = begin;
- * this->size = 0;
- * for (size_t i = 0; i < num_elems; ++i) {
- * InplaceArrayBase::EmplaceInit(i, *it++);
- * this->size++;
- * }
- * }
- * }
- *
- * void test_function() {
- * vector<Elem> fields;
- * auto ptr = make_inplace_array_object<ArrayObj, Elem>(fields.size());
- * ptr->Init(fields.begin(), fields.end());
- *
- * // Access the 0th element in the array.
- * assert(ptr->operator[](0) == fields[0]);
- * }
- *
- * \endcode
- */
-template <typename ArrayType, typename ElemType>
-class InplaceArrayBase {
- public:
- /*!
- * \brief Access element at index
- * \param idx The index of the element.
- * \return Const reference to ElemType at the index.
- */
- const ElemType& operator[](size_t idx) const {
- size_t size = Self()->GetSize();
- if (idx > size) {
- TVM_FFI_THROW(IndexError) << "Index " << idx << " out of bounds " << size;
- }
- return *(reinterpret_cast<ElemType*>(AddressOf(idx)));
- }
-
- /*!
- * \brief Access element at index
- * \param idx The index of the element.
- * \return Reference to ElemType at the index.
- */
- ElemType& operator[](size_t idx) {
- size_t size = Self()->GetSize();
- if (idx > size) {
- TVM_FFI_THROW(IndexError) << "Index " << idx << " out of bounds " << size;
- }
- return *(reinterpret_cast<ElemType*>(AddressOf(idx)));
- }
-
- /*!
- * \brief Destroy the Inplace Array Base object
- */
- ~InplaceArrayBase() {
- if constexpr (!(std::is_standard_layout<ElemType>::value && std::is_trivial<ElemType>::value)) {
- size_t size = Self()->GetSize();
- for (size_t i = 0; i < size; ++i) {
- ElemType* fp = reinterpret_cast<ElemType*>(AddressOf(i));
- fp->ElemType::~ElemType();
- }
- }
- }
-
- protected:
- /*!
- * \brief Construct a value in place with the arguments.
- *
- * \tparam Args Type parameters of the arguments.
- * \param idx Index of the element.
- * \param args Arguments to construct the new value.
- *
- * \note Please make sure ArrayType::GetSize returns 0 before first call of
- * EmplaceInit, and increment GetSize by 1 each time EmplaceInit succeeds.
- */
- template <typename... Args>
- void EmplaceInit(size_t idx, Args&&... args) {
- void* field_ptr = AddressOf(idx);
- new (field_ptr) ElemType(std::forward<Args>(args)...);
- }
-
- /*!
- * \brief Return the self object for the array.
- *
- * \return Pointer to ArrayType.
- */
- inline ArrayType* Self() const {
- return static_cast<ArrayType*>(const_cast<InplaceArrayBase*>(this));
- }
-
- /*!
- * \brief Return the raw pointer to the element at idx.
- *
- * \param idx The index of the element.
- * \return Raw pointer to the element.
- */
- void* AddressOf(size_t idx) const {
- static_assert(
- alignof(ArrayType) % alignof(ElemType) == 0 && sizeof(ArrayType) % alignof(ElemType) == 0,
- "The size and alignment of ArrayType should respect "
- "ElemType's alignment.");
-
- size_t kDataStart = sizeof(ArrayType);
- ArrayType* self = Self();
- char* data_start = reinterpret_cast<char*>(self) + kDataStart;
- return data_start + idx * sizeof(ElemType);
- }
-};
-
-/*!
- * \brief iterator adapter that adapts TIter to return another type.
- * \tparam Converter a struct that contains converting function
- * \tparam TIter the content iterator type.
- */
-template <typename Converter, typename TIter>
-class IterAdapter {
- public:
- using difference_type = typename std::iterator_traits<TIter>::difference_type;
- using value_type = typename Converter::ResultType;
- using pointer = typename Converter::ResultType*;
- using reference = typename Converter::ResultType&;
- using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
-
- explicit IterAdapter(TIter iter) : iter_(iter) {}
- IterAdapter& operator++() {
- ++iter_;
- return *this;
- }
- IterAdapter& operator--() {
- --iter_;
- return *this;
- }
- IterAdapter operator++(int) {
- IterAdapter copy = *this;
- ++iter_;
- return copy;
- }
- IterAdapter operator--(int) {
- IterAdapter copy = *this;
- --iter_;
- return copy;
- }
-
- IterAdapter operator+(difference_type offset) const { return IterAdapter(iter_ + offset); }
-
- IterAdapter operator-(difference_type offset) const { return IterAdapter(iter_ - offset); }
-
- IterAdapter& operator+=(difference_type offset) {
- iter_ += offset;
- return *this;
- }
-
- IterAdapter& operator-=(difference_type offset) {
- iter_ -= offset;
- return *this;
- }
-
- template <typename T = IterAdapter>
- typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
- typename T::difference_type>::type inline
- operator-(const IterAdapter& rhs) const {
- return iter_ - rhs.iter_;
- }
-
- bool operator==(IterAdapter other) const { return iter_ == other.iter_; }
- bool operator!=(IterAdapter other) const { return !(*this == other); }
- const value_type operator*() const { return Converter::convert(*iter_); }
-
- private:
- TIter iter_;
-};
-
-/*!
- * \brief iterator adapter that adapts TIter to return another type.
- * \tparam Converter a struct that contains converting function
- * \tparam TIter the content iterator type.
- */
-template <typename Converter, typename TIter>
-class ReverseIterAdapter {
- public:
- using difference_type = typename std::iterator_traits<TIter>::difference_type;
- using value_type = typename Converter::ResultType;
- using pointer = typename Converter::ResultType*;
- using reference = typename Converter::ResultType&; // NOLINT(*)
- using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
-
- explicit ReverseIterAdapter(TIter iter) : iter_(iter) {}
- ReverseIterAdapter& operator++() {
- --iter_;
- return *this;
- }
- ReverseIterAdapter& operator--() {
- ++iter_;
- return *this;
- }
- ReverseIterAdapter operator++(int) {
- ReverseIterAdapter copy = *this;
- --iter_;
- return copy;
- }
- ReverseIterAdapter operator--(int) {
- ReverseIterAdapter copy = *this;
- ++iter_;
- return copy;
- }
- ReverseIterAdapter operator+(difference_type offset) const {
- return ReverseIterAdapter(iter_ - offset);
- }
-
- template <typename T = ReverseIterAdapter>
- typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
- typename T::difference_type>::type inline
- operator-(const ReverseIterAdapter& rhs) const {
- return rhs.iter_ - iter_;
- }
-
- bool operator==(ReverseIterAdapter other) const { return iter_ == other.iter_; }
- bool operator!=(ReverseIterAdapter other) const { return !(*this == other); }
- const value_type operator*() const { return Converter::convert(*iter_); }
-
- private:
- TIter iter_;
-};
-
-/*!
- * \brief Check if T is compatible with Any.
- *
- * \tparam T The type to check.
- * \return True if T is compatible with Any, false otherwise.
- */
-template <typename T>
-inline constexpr bool storage_enabled_v = std::is_same_v<T, Any> || TypeTraits<T>::storage_enabled;
-
-/*!
- * \brief Check if all T are compatible with Any.
- *
- * \tparam T The type to check.
- * \return True if T is compatible with Any, false otherwise.
- */
-template <typename... T>
-inline constexpr bool all_storage_enabled_v = (storage_enabled_v<T> && ...);
-
-/*!
- * \brief Check if all T are compatible with Any.
- *
- * \tparam T The type to check.
- * \return True if T is compatible with Any, false otherwise.
- */
-template <typename... T>
-inline constexpr bool all_object_ref_v = (std::is_base_of_v<ObjectRef, T> && ...);
-/**
- * \brief Check if Any storage of Derived can always be directly used as Base.
- *
- * \tparam Base The base type.
- * \tparam Derived The derived type.
- * \return True if Derived's storage can be used as Base's storage, false otherwise.
- */
-template <typename Base, typename Derived>
-inline constexpr bool type_contains_v =
- std::is_base_of_v<Base, Derived> || std::is_same_v<Base, Derived>;
-// special case for Any
-template <typename Derived>
-inline constexpr bool type_contains_v<Any, Derived> = true;
-
-/*!
- * \brief Create a string of the container type.
- * \tparam V The types of the elements in the container.
- * \param name The name of the container type.
- * \return A string of the container type.
- */
-template <typename... V>
-std::string ContainerTypeStr(const char* name) {
- std::stringstream ss;
- // helper to construct concated string of TypeStr
- class TypeStrHelper {
- public:
- TypeStrHelper(std::stringstream& stream) : stream_(stream) {} // NOLINT(*)
-
- TypeStrHelper& operator<<(const std::string& str) {
- if (counter_ > 0) {
- stream_ << ", ";
- }
- stream_ << str;
- counter_++;
- return *this;
- }
-
- private:
- std::stringstream& stream_; // NOLINT(*)
- int counter_ = 0;
- };
- TypeStrHelper helper(ss);
- ss << name << '<';
- (helper << ... << Type2Str<V>::v());
- ss << '>';
- return ss.str();
-}
-
-} // namespace details
-} // namespace ffi
-} // namespace tvm
-#endif // TVM_FFI_CONTAINER_CONTAINER_DETAILS_H_
diff --git a/ffi/include/tvm/ffi/container/map.h b/ffi/include/tvm/ffi/container/map.h
deleted file mode 100644
index 471904502c..0000000000
--- a/ffi/include/tvm/ffi/container/map.h
+++ /dev/null
@@ -1,1762 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file tvm/ffi/container/map.h
- * \brief Runtime Map container types.
- */
-#ifndef TVM_FFI_CONTAINER_MAP_H_
-#define TVM_FFI_CONTAINER_MAP_H_
-
-#include <tvm/ffi/any.h>
-#include <tvm/ffi/container/container_details.h>
-#include <tvm/ffi/memory.h>
-#include <tvm/ffi/object.h>
-#include <tvm/ffi/optional.h>
-
-#include <algorithm>
-#include <limits>
-#include <string>
-#include <type_traits>
-#include <unordered_map>
-#include <utility>
-
-namespace tvm {
-namespace ffi {
-
-/// \cond Doxygen_Suppress
-#if TVM_FFI_DEBUG_WITH_ABI_CHANGE
-#define TVM_FFI_MAP_FAIL_IF_CHANGED() \
- TVM_FFI_ICHECK(state_marker == self->state_marker) << "Concurrent modification of the Map";
-#else
-#define TVM_FFI_MAP_FAIL_IF_CHANGED()
-#endif // TVM_FFI_DEBUG_WITH_ABI_CHANGE
-/// \endcond
-
-/*! \brief Shared content of all specializations of hash map */
-class MapObj : public Object {
- public:
- /*! \brief Type of the keys in the hash map */
- using key_type = Any;
- /*! \brief Type of the values in the hash map */
- using mapped_type = Any;
- /*! \brief Type of value stored in the hash map */
- using KVType = std::pair<Any, Any>;
- /// \cond Doxygen_Suppress
- /*! \brief Type of raw storage of the key-value pair in the hash map */
- struct KVRawStorageType {
- TVMFFIAny first;
- TVMFFIAny second;
- };
- /// \endcond
- /*! \brief Iterator class */
- class iterator;
-
- static_assert(std::is_standard_layout<KVType>::value, "KVType is not standard layout");
- static_assert(sizeof(KVType) == 32, "sizeof(KVType) incorrect");
-
- /// \cond Doxygen_Suppress
- static constexpr const int32_t _type_index = TypeIndex::kTVMFFIMap;
- static const constexpr bool _type_final = true;
- TVM_FFI_DECLARE_OBJECT_INFO_STATIC(StaticTypeKey::kTVMFFIMap, MapObj, Object);
- /// \endcond
-
- /*!
- * \brief Number of elements in the MapObj
- * \return The result
- */
- size_t size() const { return size_; }
- /*!
- * \brief Count the number of times a key exists in the hash map
- * \param key The indexing key
- * \return The result, 0 or 1
- */
- size_t count(const key_type& key) const;
- /*!
- * \brief Index value associated with a key, throw exception if the key does not exist
- * \param key The indexing key
- * \return The const reference to the value
- */
- const mapped_type& at(const key_type& key) const;
- /*!
- * \brief Index value associated with a key, throw exception if the key does not exist
- * \param key The indexing key
- * \return The mutable reference to the value
- */
- mapped_type& at(const key_type& key);
- /*! \return begin iterator */
- iterator begin() const;
- /*! \return end iterator */
- iterator end() const;
- /*!
- * \brief Index value associated with a key
- * \param key The indexing key
- * \return The iterator of the entry associated with the key, end iterator if not exists
- */
- iterator find(const key_type& key) const;
- /*!
- * \brief Erase the entry associated with the iterator
- * \param position The iterator
- */
- void erase(const iterator& position);
- /*!
- * \brief Erase the entry associated with the key, do nothing if not exists
- * \param key The indexing key
- */
- void erase(const key_type& key) { erase(find(key)); }
-
- /// \cond Doxygen_Suppress
- class iterator {
- public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = int64_t;
- using value_type = KVType;
- using pointer = KVType*;
- using reference = KVType&;
-/*! \brief Default constructor */
-#if TVM_FFI_DEBUG_WITH_ABI_CHANGE
- iterator() : state_marker(0), index(0), self(nullptr) {}
-#else
- iterator() : index(0), self(nullptr) {}
-#endif // TVM_FFI_DEBUG_WITH_ABI_CHANGE
- /*! \brief Compare iterators */
- bool operator==(const iterator& other) const {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- return index == other.index && self == other.self;
- }
- /*! \brief Compare iterators */
- bool operator!=(const iterator& other) const { return !(*this == other); }
- /*! \brief De-reference iterators */
- pointer operator->() const;
- /*! \brief De-reference iterators */
- reference operator*() const {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- return *((*this).operator->());
- }
- /*! \brief Prefix self increment, e.g. ++iter */
- iterator& operator++();
- /*! \brief Prefix self decrement, e.g. --iter */
- iterator& operator--();
- /*! \brief Suffix self increment */
- iterator operator++(int) {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- iterator copy = *this;
- ++(*this);
- return copy;
- }
- /*! \brief Suffix self decrement */
- iterator operator--(int) {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- iterator copy = *this;
- --(*this);
- return copy;
- }
-
- protected:
-#if TVM_FFI_DEBUG_WITH_ABI_CHANGE
- uint64_t state_marker;
- /*! \brief Construct by value */
- iterator(uint64_t index, const MapObj* self)
- : state_marker(self->state_marker), index(index), self(self) {}
-
-#else
- iterator(uint64_t index, const MapObj* self) : index(index), self(self) {}
-#endif // TVM_FFI_DEBUG_WITH_ABI_CHANGE
- /*! \brief The position on the array */
- uint64_t index;
- /*! \brief The container it points to */
- const MapObj* self;
-
- friend class DenseMapObj;
- friend class SmallMapObj;
- };
- /// \endcond
- /*!
- * \brief Create an empty container
- * \return The object created
- */
- static inline ObjectPtr<MapObj> Empty();
-
- protected:
-#if TVM_FFI_DEBUG_WITH_ABI_CHANGE
- uint64_t state_marker;
-#endif // TVM_FFI_DEBUG_WITH_ABI_CHANGE
- /*!
- * \brief Create the map using contents from the given iterators.
- * \param first Begin of iterator
- * \param last End of iterator
- * \tparam IterType The type of iterator
- * \return ObjectPtr to the map created
- */
- template <typename IterType>
- static inline ObjectPtr<Object> CreateFromRange(IterType first, IterType last);
- /*!
- * \brief InsertMaybeReHash an entry into the given hash map
- * \param kv The entry to be inserted
- * \param map The pointer to the map, can be changed if re-hashing happens
- */
- static inline void InsertMaybeReHash(KVType&& kv, ObjectPtr<Object>* map);
- /*!
- * \brief Create an empty container with elements copying from another SmallMapObj
- * \param from The source container
- * \return The object created
- */
- static inline ObjectPtr<MapObj> CopyFrom(MapObj* from);
- /*!
- * \brief data pointer to the data region of the map.
- * \note For immutable inplace small map we do not need data_,
- * but we keep it here for future compact with mutable container.
- */
- void* data_;
- /*! \brief number of entries in the container */
- uint64_t size_;
- /*! \brief number of slots */
- uint64_t slots_;
- /*!
- * \brief Small layout tag mask
- * \note The most significant bit is used to indicate the small map layout.
- */
- static constexpr uint64_t kSmallTagMask = static_cast<uint64_t>(1) << 63;
- /*!
- * \brief Check if the map is a small map
- * \return True if the map is a small map
- */
- bool IsSmallMap() const { return (slots_ & kSmallTagMask) != 0ull; }
- /*!
- * \brief Optional data deleter when data is allocated separately
- * and its deletion is not managed by MapObj::deleter_.
- */
- void (*data_deleter_)(void*) = nullptr;
- // Reference class
- template <typename, typename, typename>
- friend class Map;
-};
-
-/*! \brief A specialization of small-sized hash map */
-class SmallMapObj : public MapObj,
- public details::InplaceArrayBase<SmallMapObj, MapObj::KVRawStorageType> {
- private:
- static constexpr uint64_t kInitSize = 2;
- static constexpr uint64_t kMaxSize = 4;
-
- public:
- using MapObj::iterator;
- using MapObj::KVType;
-
- // Return the number of usable slots for Small layout (mask off tag).
- /*!
- * \brief Return the number of usable slots for Small layout (mask off tag).
- * \return The number of usable slots
- */
- uint64_t NumSlots() const { return slots_ & ~kSmallTagMask; }
-
- ~SmallMapObj() {
- KVType* begin = static_cast<KVType*>(data_);
- for (uint64_t index = 0; index < size_; ++index) {
- // call destructor to destroy the item in `begin + index`
- // Explicit call Any::~Any() to destroy the Any object
- // Favor this over ~KVType as MSVC may not support ~KVType (need the original name)
- (begin + index)->first.Any::~Any();
- (begin + index)->second.Any::~Any();
- }
- if (data_deleter_ != nullptr) {
- data_deleter_(data_);
- }
- }
- /*!
- * \brief Count the number of times a key exists in the SmallMapObj
- * \param key The indexing key
- * \return The result, 0 or 1
- */
- size_t count(const key_type& key) const { return find(key).index < size_; }
- /*!
- * \brief Index value associated with a key, throw exception if the key does not exist
- * \param key The indexing key
- * \return The const reference to the value
- */
- const mapped_type& at(const key_type& key) const {
- iterator itr = find(key);
- if (itr.index >= size_) {
- TVM_FFI_THROW(KeyError) << "key is not in Map";
- }
- return itr->second;
- }
- /*!
- * \brief Index value associated with a key, throw exception if the key does not exist
- * \param key The indexing key
- * \return The mutable reference to the value
- */
- mapped_type& at(const key_type& key) {
- iterator itr = find(key);
- if (itr.index >= size_) {
- TVM_FFI_THROW(KeyError) << "key is not in Map";
- }
- return itr->second;
- }
- /*! \return begin iterator */
- iterator begin() const { return iterator(0, this); }
- /*! \return end iterator */
- iterator end() const { return iterator(size_, this); }
- /*!
- * \brief Index value associated with a key
- * \param key The indexing key
- * \return The iterator of the entry associated with the key, end iterator if not exists
- */
- iterator find(const key_type& key) const {
- KVType* ptr = static_cast<KVType*>(data_);
- for (uint64_t i = 0; i < size_; ++i, ++ptr) {
- if (AnyEqual()(ptr->first, key)) {
- return iterator(i, this);
- }
- }
- return iterator(size_, this);
- }
- /*!
- * \brief Erase the entry associated with the iterator
- * \param position The iterator
- */
- void erase(const iterator& position) { Erase(position.index); }
-
- private:
- /*!
- * \brief Set the number of slots and attach tags bit.
- * \param n The number of slots
- */
- void SetSlotsAndSmallLayoutTag(uint64_t n) { slots_ = (n & ~kSmallTagMask) | kSmallTagMask; }
- /*!
- * \brief Remove a position in SmallMapObj
- * \param index The position to be removed
- */
- void Erase(const uint64_t index) {
- if (index >= size_) {
- return;
- }
- KVType* begin = static_cast<KVType*>(data_);
- // call destructor to destroy the item in `begin + index`
- // Explicit call Any::~Any() to destroy the Any object
- // Favor this over ~KVType as MSVC may not support ~KVType (need the original name)
- (begin + index)->first.Any::~Any();
- (begin + index)->second.Any::~Any();
- // IMPORTANT: We do direct raw memmove to bring later items to the current position
- // to preserve the order of insertion.
- // This works because direct memory copy preserves the Any's move semantics.
- if (index + 1 < size_) {
- std::memmove(reinterpret_cast<char*>(begin + index),
- reinterpret_cast<char*>(begin + index + 1),
- (size_ - index - 1) * sizeof(KVType));
- }
- size_ -= 1;
- }
- /*!
- * \brief Create an empty container
- * \param n Number of empty slots
- * \return The object created
- */
- static ObjectPtr<SmallMapObj> Empty(uint64_t n = kInitSize) {
- using ::tvm::ffi::make_inplace_array_object;
- ObjectPtr<SmallMapObj> p = make_inplace_array_object<SmallMapObj, KVType>(n);
- p->data_ = p->AddressOf(0);
- p->size_ = 0;
- p->SetSlotsAndSmallLayoutTag(n);
- return p;
- }
- /*!
- * \brief Create an empty container initialized with a given range
- * \param n Number of empty slots
- * \param first begin of iterator
- * \param last end of iterator
- * \tparam IterType The type of iterator
- * \return The object created
- */
- template <typename IterType>
- static ObjectPtr<SmallMapObj> CreateFromRange(uint64_t n, IterType first, IterType last) {
- ObjectPtr<SmallMapObj> p = Empty(n);
- KVType* ptr = static_cast<KVType*>(p->data_);
- for (; first != last; ++first, ++p->size_) {
- new (ptr++) KVType(*first);
- }
- return p;
- }
- /*!
- * \brief Create an empty container with elements copying from another SmallMapObj
- * \param from The source container
- * \return The object created
- */
- static ObjectPtr<SmallMapObj> CopyFrom(SmallMapObj* from) {
- KVType* first = static_cast<KVType*>(from->data_);
- KVType* last = first + from->size_;
- return CreateFromRange(from->size_, first, last);
- }
- /*!
- * \brief InsertMaybeReHash an entry into the given hash map
- * \param kv The entry to be inserted
- * \param map The pointer to the map, can be changed if re-hashing happens
- */
- static void InsertMaybeReHash(KVType&& kv, ObjectPtr<Object>* map) {
- SmallMapObj* map_node = static_cast<SmallMapObj*>(map->get());
- iterator itr = map_node->find(kv.first);
- if (itr.index < map_node->size_) {
- itr->second = kv.second;
- return;
- }
- if (map_node->size_ < map_node->NumSlots()) {
- KVType* ptr = static_cast<KVType*>(map_node->data_) + map_node->size_;
- new (ptr) KVType(std::move(kv));
- ++map_node->size_;
- return;
- }
- uint64_t next_size = std::max(map_node->NumSlots() * 2, uint64_t(kInitSize));
- next_size = std::min(next_size, uint64_t(kMaxSize));
- TVM_FFI_ICHECK_GT(next_size, map_node->NumSlots());
- ObjectPtr<Object> new_map = CreateFromRange(next_size, map_node->begin(), map_node->end());
- InsertMaybeReHash(std::move(kv), &new_map);
- *map = std::move(new_map);
- }
- /*!
- * \brief Increment the pointer
- * \param index The pointer to be incremented
- * \return The increased pointer
- */
- uint64_t IncItr(uint64_t index) const { return index + 1 < size_ ? index + 1 : size_; }
- /*!
- * \brief Decrement the pointer
- * \param index The pointer to be decremented
- * \return The decreased pointer
- */
- uint64_t DecItr(uint64_t index) const { return index > 0 ? index - 1 : size_; }
- /*!
- * \brief De-reference the pointer
- * \param index The pointer to be dereferenced
- * \return The result
- */
- KVType* DeRefItr(uint64_t index) const { return static_cast<KVType*>(data_) + index; }
- /*! \brief A size function used by InplaceArrayBase */
- uint64_t GetSize() const { return size_; }
-
- protected:
- friend class MapObj;
- friend class DenseMapObj;
- friend class details::InplaceArrayBase<SmallMapObj, MapObj::KVType>;
-};
-
-/*! \brief A specialization of hash map that implements the idea of array-based hash map.
- * Another reference implementation can be found [1].
- *
- * A. Overview
- *
- * DenseMapObj did several improvements over traditional separate chaining hash,
- * in terms of cache locality, memory footprints and data organization.
- *
- * A1. Implicit linked list. For better cache locality, instead of using linked list
- * explicitly for each bucket, we store list data into a single array that spans contiguously
- * in memory, and then carefully design access patterns to make sure most of them fall into
- * a single cache line.
- *
- * A2. 1-byte metadata. There is only 1 byte overhead for each slot in the array to indexing and
- * traversal. This can be divided in 3 parts.
- * 1) Reserved code: (0b11111111)_2 indicates a slot is empty; (0b11111110)_2 indicates protected,
- * which means the slot is empty but not allowed to be written.
- * 2) If not empty or protected, the highest bit is used to indicate whether data in the slot is
- * head of a linked list.
- * 3) The rest 7 bits are used as the "next pointer" (i.e. pointer to the next element). On 64-bit
- * architecture, an ordinary pointer can take up to 8 bytes, which is not acceptable overhead when
- * dealing with 16-byte ObjectRef pairs. Based on a commonly noticed fact that the lists are
- * relatively short (length <= 3) in hash maps, we follow [1]'s idea that only allows the pointer to
- * be one of the 126 possible values, i.e. if the next element of i-th slot is (i + x)-th element,
- * then x must be one of the 126 pre-defined values.
- *
- * A3. Data blocking. We organize the array in the way that every 16 elements forms a data block.
- * The 16-byte metadata of those 16 elements are stored together, followed by the real data, i.e.
- * 16 key-value pairs.
- *
- * B. Implementation details
- *
- * B1. Power-of-2 table size and Fibonacci Hashing. We use power-of-two as table size to avoid
- * modulo for more efficient arithmetics. To make the hash-to-slot mapping distribute more evenly,
- * we use the Fibonacci Hashing [2] trick.
- *
- * B2. Traverse a linked list in the array.
- * 1) List head. Assume Fibonacci Hashing maps a given key to slot i, if metadata at slot i
- * indicates that it is list head, then we found the head; otherwise the list is empty. No probing
- * is done in this procedure. 2) Next element. To find the next element of a non-empty slot i, we
- * look at the last 7 bits of the metadata at slot i. If they are all zeros, then it is the end of
- * list; otherwise, we know that the next element is (i + candidates[the-last-7-bits]).
- *
- * B3. InsertMaybeReHash an element. Following B2, we first traverse the linked list to see if this
- * element is in the linked list, and if not, we put it at the end by probing the next empty
- * position in one of the 126 candidate positions. If the linked list does not even exist, but the
- * slot for list head has been occupied by another linked list, we should find this intruder another
- * place.
- *
- * B4. Quadratic probing with triangle numbers. In open address hashing, it is provable that probing
- * with triangle numbers can traverse power-of-2-sized table [3]. In our algorithm, we follow the
- * suggestion in [1] that also use triangle numbers for "next pointer" as well as sparing for list
- * head.
- *
- * [1] https://github.com/skarupke/flat_hash_map
- * [2] https://programmingpraxis.com/2018/06/19/fibonacci-hash/
- * [3] https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/
- */
-class DenseMapObj : public MapObj {
- private:
- /*! \brief The number of elements in a memory block */
- static constexpr int kBlockCap = 16;
- /*! \brief Maximum load factor of the hash map */
- static constexpr double kMaxLoadFactor = 0.99;
- /*! \brief Binary representation of the metadata of an empty slot */
- static constexpr uint8_t kEmptySlot = uint8_t(0b11111111);
- /*! \brief Binary representation of the metadata of a protected slot */
- static constexpr uint8_t kProtectedSlot = uint8_t(0b11111110);
- /*! \brief Number of probing choices available */
- static constexpr int kNumJumpDists = 126;
- /*! \brief Index indicator to indicate an invalid index */
- static constexpr uint64_t kInvalidIndex = std::numeric_limits<uint64_t>::max();
- /*! \brief Head of the implicit linked list */
- struct ListNode;
- /*! \brief item type of the dense map, including a kv data and prev/next pointer */
- struct ItemType {
- KVType data;
- uint64_t prev = kInvalidIndex;
- uint64_t next = kInvalidIndex;
-
- explicit ItemType(KVType&& data) : data(std::move(data)) {}
- explicit ItemType(key_type key, mapped_type value) : data(key, value) {}
- };
- /*! \brief POD type of a block of memory */
- struct Block {
- uint8_t bytes[kBlockCap + kBlockCap * sizeof(ItemType)];
- };
- static_assert(sizeof(Block) == kBlockCap * (sizeof(ItemType) + 1), "sizeof(Block) incorrect");
- static_assert(std::is_standard_layout<Block>::value, "Block is not standard layout");
-
- /*!
- * \brief Deleter for the Block
- * \param data The pointer to the Block
- */
- static void BlockDeleter(void* data) { delete[] static_cast<Block*>(data); }
-
- public:
- using MapObj::iterator;
-
- /*!
- * \brief Return the number of usable slots for Dense layout (MSB clear => identity).
- * \return The number of usable slots
- */
- uint64_t NumSlots() const { return slots_; }
-
- /*!
- * \brief Destroy the DenseMapObj
- */
- ~DenseMapObj() { this->Reset(); }
- /*! \return The number of elements of the key */
- size_t count(const key_type& key) const { return !Search(key).IsNone(); }
- /*!
- * \brief Index value associated with a key, throw exception if the key does not exist
- * \param key The indexing key
- * \return The const reference to the value
- */
- const mapped_type& at(const key_type& key) const { return At(key); }
- /*!
- * \brief Index value associated with a key, throw exception if the key does not exist
- * \param key The indexing key
- * \return The mutable reference to the value
- */
- mapped_type& at(const key_type& key) { return At(key); }
- /*!
- * \brief Index value associated with a key
- * \param key The indexing key
- * \return The iterator of the entry associated with the key, end iterator if not exists
- */
- iterator find(const key_type& key) const {
- ListNode node = Search(key);
- return node.IsNone() ? end() : iterator(node.index, this);
- }
- /*!
- * \brief Erase the entry associated with the iterator
- * \param position The iterator
- */
- void erase(const iterator& position) {
- uint64_t index = position.index;
- if (position.self != nullptr && index <= this->NumSlots()) {
- Erase(ListNode(index, this));
- }
- }
- /*! \return begin iterator */
- iterator begin() const { return iterator(iter_list_head_, this); }
- /*! \return end iterator */
- iterator end() const { return iterator(kInvalidIndex, this); }
-
- private:
- Block* GetBlock(size_t index) const { return static_cast<Block*>(data_) + index; }
- /*!
- * \brief Unlink the entry from iterator list
- * \param node The node to be unlinked
- * \note This function is usually used before deletion,
- * and it does not change data content of the node.
- */
- void IterListUnlink(ListNode node) {
- // update head and tail of iterator list if needed
- if (node.Item().prev == kInvalidIndex) {
- iter_list_head_ = node.Item().next;
- } else {
- ListNode prev_node(node.Item().prev, this);
- prev_node.Item().next = node.Item().next;
- }
- if (node.Item().next == kInvalidIndex) {
- iter_list_tail_ = node.Item().prev;
- } else {
- ListNode next_node(node.Item().next, this);
- next_node.Item().prev = node.Item().prev;
- }
- }
- /*!
- * \brief Insert the entry into tail of iterator list
- * \param node The node to be inserted
- * \note this function does not change data content of the node.
- */
- void IterListPushBack(ListNode node) {
- node.Item().prev = iter_list_tail_;
- node.Item().next = kInvalidIndex;
- if (iter_list_tail_ != kInvalidIndex) {
- ListNode prev_node(iter_list_tail_, this);
- prev_node.Item().next = node.index;
- }
- if (iter_list_head_ == kInvalidIndex) {
- iter_list_head_ = node.index;
- }
- iter_list_tail_ = node.index;
- }
- /*!
- * \brief Replace node src by dst in the iter list
- * \param src The source node
- * \param dst The destination node, must be empty
- * \note This function does not change data content of the nodes,
- * which needs to be updated by the caller.
- */
- void IterListReplaceNodeBy(ListNode src, ListNode dst) {
- // set link correctly on the dst
- dst.Item().prev = src.Item().prev;
- dst.Item().next = src.Item().next;
- // update prev and next of dst
- if (dst.Item().prev == kInvalidIndex) {
- iter_list_head_ = dst.index;
- } else {
- ListNode prev_node(dst.Item().prev, this);
- prev_node.Item().next = dst.index;
- }
- if (dst.Item().next == kInvalidIndex) {
- iter_list_tail_ = dst.index;
- } else {
- ListNode next_node(dst.Item().next, this);
- next_node.Item().prev = dst.index;
- }
- }
- /*!
- * \brief Search for the given key
- * \param key The key
- * \return ListNode that associated with the key
- */
- ListNode Search(const key_type& key) const {
- if (this->size_ == 0) {
- return ListNode();
- }
- for (ListNode iter = GetListHead(AnyHash()(key)); !iter.IsNone(); iter.MoveToNext(this)) {
- if (AnyEqual()(key, iter.Key())) {
- return iter;
- }
- }
- return ListNode();
- }
- /*!
- * \brief Search for the given key, throw exception if not exists
- * \param key The key
- * \return ListNode that associated with the key
- */
- mapped_type& At(const key_type& key) const {
- ListNode iter = Search(key);
- if (iter.IsNone()) {
- TVM_FFI_THROW(IndexError) << "key is not in Map";
- }
- return iter.Val();
- }
- /*!
- * \brief Try to insert a key, or do nothing if already exists
- * \param key The indexing key
- * \param result The linked-list entry found or just constructed
- * \return A boolean, indicating if actual insertion happens
- */
- bool TryInsert(const key_type& key, ListNode* result) {
- if (slots_ == 0) {
- return false;
- }
- // required that `iter` to be the head of a linked list through which we can iterator
- ListNode iter = IndexFromHash(AnyHash()(key));
- // `iter` can be: 1) empty; 2) body of an irrelevant list; 3) head of the relevant list
- // Case 1: empty
- if (iter.IsEmpty()) {
- iter.NewHead(ItemType(key, Any(nullptr)));
- this->size_ += 1;
- *result = iter;
- return true;
- }
- // Case 2: body of an irrelevant list
- if (!iter.IsHead()) {
- // we move the elements around and construct the single-element linked list
- return IsFull() ? false : TrySpareListHead(iter, key, result);
- }
- // Case 3: head of the relevant list
- // we iterate through the linked list until the end
- // make sure `iter` is the previous element of `next`
- ListNode next = iter;
- do {
- // find equal item, do not insert
- if (AnyEqual()(key, next.Key())) {
- // we plan to take next, so we need to unlink it from iterator list
- IterListUnlink(next);
- *result = next;
- return true;
- }
- // make sure `iter` is the previous element of `next`
- iter = next;
- } while (next.MoveToNext(this));
- // `iter` is the tail of the linked list
- // always check capacity before insertion
- if (IsFull()) {
- return false;
- }
- // find the next empty slot
- uint8_t jump;
- if (!iter.GetNextEmpty(this, &jump, result)) {
- return false;
- }
- result->NewTail(ItemType(key, Any(nullptr)));
- // link `iter` to `empty`, and move forward
- iter.SetJump(jump);
- this->size_ += 1;
- return true;
- }
- /*!
- * \brief Spare an entry to be the head of a linked list.
- * As described in B3, during insertion, it is possible that the entire linked list does not
- * exist, but the slot of its head has been occupied by other linked lists. In this case, we need
- * to spare the slot by moving away the elements to another valid empty one to make insertion
- * possible.
- * \param target The given entry to be spared
- * \param key The indexing key
- * \param result The linked-list entry constructed as the head
- * \return A boolean, if actual insertion happens
- */
- bool TrySpareListHead(ListNode target, const key_type& key, ListNode* result) {
- // `target` is not the head of the linked list
- // move the original item of `target` (if any)
- // and construct new item on the position `target`
- // To make `target` empty, we
- // 1) find `w` the previous element of `target` in the linked list
- // 2) copy the linked list starting from `r = target`
- // 3) paste them after `w`
- // read from the linked list after `r`
- ListNode r = target;
- // write to the tail of `w`
- ListNode w = target.FindPrev(this);
- // after `target` is moved, we disallow writing to the slot
- bool is_first = true;
- uint8_t r_meta, jump;
- ListNode empty;
- do {
- // `jump` describes how `w` is jumped to `empty`
- // rehash if there is no empty space after `w`
- if (!w.GetNextEmpty(this, &jump, &empty)) {
- return false;
- }
- // move `r` to `empty`
- // first move the data over
- empty.NewTail(ItemType(std::move(r.Data())));
- // then move link list chain of r to empty
- // this needs to happen after NewTail so empty's prev/next get updated
- IterListReplaceNodeBy(r, empty);
- // explicit call destructor to destroy the item in `r`
- r.DestructData();
- // clear the metadata of `r`
- r_meta = r.Meta();
- if (is_first) {
- is_first = false;
- r.SetProtected();
- } else {
- r.SetEmpty();
- }
- // link `w` to `empty`, and move forward
- w.SetJump(jump);
- w = empty;
- // move `r` forward as well
- } while (r.MoveToNext(this, r_meta));
- // finally we have done moving the linked list
- // fill data_ into `target`
- target.NewHead(ItemType(key, Any(nullptr)));
- this->size_ += 1;
- *result = target;
- return true;
- }
- /*!
- * \brief Remove a ListNode
- * \param iter The node to be removed
- */
- void Erase(const ListNode& iter) {
- this->size_ -= 1;
- if (!iter.HasNext()) {
- // `iter` is the last
- if (!iter.IsHead()) {
- // cut the link if there is any
- iter.FindPrev(this).SetJump(0);
- }
- // unlink the node from iterator list
- IterListUnlink(iter);
- // IMPORTANT: must explicit call destructor `iter` to avoid memory leak
- // This is because we need to recycle iter's data
- iter.DestructData();
- // set the meta data to be empty
- iter.SetEmpty();
- } else {
- ListNode last = iter, prev = iter;
- for (last.MoveToNext(this); last.HasNext(); prev = last, last.MoveToNext(this)) {
- }
- // needs to first unlink iter from the list
- IterListUnlink(iter);
- // move data from last to iter
- iter.Data() = std::move(last.Data());
- // Move link chain of iter to last as we stores last node to the new iter loc.
- IterListReplaceNodeBy(last, iter);
- // IMPORTANT: must explicit call destructor `last` to avoid memory leak
- // likely we don't need this in this particular case because Any move behavior
- // keep it here to be safe so code do not depend on specific move behavior of KVType
- last.DestructData();
- // set the meta data to be empty
- last.SetEmpty();
- prev.SetJump(0);
- }
- }
- /*! \brief Clear the container to empty, release all entries and memory acquired */
- void Reset() {
- uint64_t n_blocks = CalcNumBlocks(this->NumSlots());
- for (uint64_t bi = 0; bi < n_blocks; ++bi) {
- uint8_t* meta_ptr = GetBlock(bi)->bytes;
- ItemType* data_ptr = reinterpret_cast<ItemType*>(GetBlock(bi)->bytes + kBlockCap);
- for (int j = 0; j < kBlockCap; ++j, ++meta_ptr, ++data_ptr) {
- uint8_t& meta = *meta_ptr;
- if (meta != uint8_t(kProtectedSlot) && meta != uint8_t(kEmptySlot)) {
- meta = uint8_t(kEmptySlot);
- data_ptr->ItemType::~ItemType();
- }
- }
- }
- ReleaseMemory();
- }
- /*! \brief Release the memory acquired by the container without deleting its entries stored inside
- */
- void ReleaseMemory() {
- if (data_ != nullptr) {
- TVM_FFI_ICHECK(data_deleter_ != nullptr);
- data_deleter_(data_);
- }
- data_ = nullptr;
- data_deleter_ = nullptr;
- slots_ = 0;
- size_ = 0;
- fib_shift_ = 63;
- }
- /*!
- * \brief Create an empty container
- * \param fib_shift The fib shift provided
- * \param n_slots Number of slots required, should be power-of-two
- * \return The object created
- */
- static ObjectPtr<DenseMapObj> Empty(uint32_t fib_shift, uint64_t n_slots) {
- TVM_FFI_ICHECK_GT(n_slots, uint64_t(SmallMapObj::kMaxSize));
- // Ensure even slot count (power-of-two expected by callers; this guard
- // makes the method robust if a non-even value slips through).
- ObjectPtr<DenseMapObj> p = make_object<DenseMapObj>();
- uint64_t n_blocks = CalcNumBlocks(n_slots);
- Block* block = new Block[n_blocks];
- p->data_ = block;
- // assign block deleter so even if we take re-alloc data
- // in another shared-lib that may have different malloc/free behavior
- // it will still be safe.
- p->data_deleter_ = BlockDeleter;
- p->SetSlotsAndDenseLayoutTag(n_slots);
- p->size_ = 0;
- p->fib_shift_ = fib_shift;
- p->iter_list_head_ = kInvalidIndex;
- p->iter_list_tail_ = kInvalidIndex;
- for (uint64_t i = 0; i < n_blocks; ++i, ++block) {
- std::fill(block->bytes, block->bytes + kBlockCap, uint8_t(kEmptySlot));
- }
- return p;
- }
- /*!
- * \brief Create an empty container with elements copying from another DenseMapObj
- * \param from The source container
- * \return The object created
- */
- static ObjectPtr<DenseMapObj> CopyFrom(DenseMapObj* from) {
- ObjectPtr<DenseMapObj> p = make_object<DenseMapObj>();
- uint64_t n_blocks = CalcNumBlocks(from->NumSlots());
- p->data_ = new Block[n_blocks];
- // assign block deleter so even if we take re-alloc data
- // in another shared-lib that may have different malloc/free behavior
- // it will still be safe.
- p->data_deleter_ = BlockDeleter;
- p->SetSlotsAndDenseLayoutTag(from->NumSlots());
- p->size_ = from->size_;
- p->fib_shift_ = from->fib_shift_;
- p->iter_list_head_ = from->iter_list_head_;
- p->iter_list_tail_ = from->iter_list_tail_;
- for (uint64_t bi = 0; bi < n_blocks; ++bi) {
- uint8_t* meta_ptr_from = from->GetBlock(bi)->bytes;
- ItemType* data_ptr_from = reinterpret_cast<ItemType*>(from->GetBlock(bi)->bytes + kBlockCap);
- uint8_t* meta_ptr_to = p->GetBlock(bi)->bytes;
- ItemType* data_ptr_to = reinterpret_cast<ItemType*>(p->GetBlock(bi)->bytes + kBlockCap);
- for (int j = 0; j < kBlockCap;
- ++j, ++meta_ptr_from, ++data_ptr_from, ++meta_ptr_to, ++data_ptr_to) {
- uint8_t& meta = *meta_ptr_to = *meta_ptr_from;
- TVM_FFI_ICHECK(meta != kProtectedSlot);
- if (meta != uint8_t(kEmptySlot)) {
- new (data_ptr_to) ItemType(*data_ptr_from);
- }
- }
- }
- return p;
- }
- /*!
- * \brief InsertMaybeReHash an entry into the given hash map
- * \param kv The entry to be inserted
- * \param map The pointer to the map, can be changed if re-hashing happens
- */
- static void InsertMaybeReHash(KVType&& kv, ObjectPtr<Object>* map) {
- DenseMapObj* map_node = static_cast<DenseMapObj*>(map->get());
- ListNode iter;
- // Try to insert. If succeed, we simply return
- if (map_node->TryInsert(kv.first, &iter)) {
- iter.Val() = std::move(kv.second);
- // update the iter list relation
- map_node->IterListPushBack(iter);
- return;
- }
- TVM_FFI_ICHECK(!map_node->IsSmallMap());
- // Otherwise, start rehash
- ObjectPtr<Object> p = Empty(map_node->fib_shift_ - 1, map_node->NumSlots() * 2);
-
- // need to insert in the same order as the original map
- for (uint64_t index = map_node->iter_list_head_; index != kInvalidIndex;) {
- ListNode node(index, map_node);
- // now try move src_data into the new map, note that src may still not
- // be fully consumed into the call, but destructor will be called.
- InsertMaybeReHash(std::move(node.Data()), &p);
- // Important, needs to explicit call destructor in case move did remove
- // node's internal item
- index = node.Item().next;
- // IMPORTANT: must explicit call destructor `node` to avoid memory leak
- // We must call node.DestructData() here.
- // This is because std::move() arguments in IterMaybeReHash may or may not
- // explicitly move out the node.Data()
- // Remove this call will cause memory leak very likely.
- node.DestructData();
- }
- InsertMaybeReHash(std::move(kv), &p);
- map_node->ReleaseMemory();
- *map = p;
- }
- /*!
- * \brief Check whether the hash table is full
- * \return A boolean indicating whether hash table is full
- */
- bool IsFull() const { return size_ + 1 > NumSlots() * kMaxLoadFactor; }
- /*!
- * \brief Increment the pointer
- * \param index The pointer to be incremented
- * \return The increased pointer
- */
- uint64_t IncItr(uint64_t index) const {
- // keep at the end of iterator
- if (index == kInvalidIndex) {
- return index;
- }
- ListNode node(index, this);
- return node.Item().next;
- }
- /*!
- * \brief Decrement the pointer
- * \param index The pointer to be decremented
- * \return The decreased pointer
- */
- uint64_t DecItr(uint64_t index) const {
- // this is the end iterator, we need to return tail.
- if (index == kInvalidIndex) {
- return iter_list_tail_;
- }
- // circle around the iterator list, which is OK
- ListNode node(index, this);
- return node.Item().prev;
- }
- /*!
- * \brief De-reference the pointer
- * \param index The pointer to be dereferenced
- * \return The result
- */
- KVType* DeRefItr(uint64_t index) const { return &ListNode(index, this).Data(); }
- /*! \brief Construct from hash code */
- ListNode IndexFromHash(uint64_t hash_value) const {
- return ListNode(FibHash(hash_value, fib_shift_), this);
- }
- /*! \brief Construct from hash code if the position is head of list */
- ListNode GetListHead(uint64_t hash_value) const {
- ListNode node = IndexFromHash(hash_value);
- return node.IsHead() ? node : ListNode();
- }
- /*! \brief Construct the number of blocks in the hash table */
- static uint64_t CalcNumBlocks(uint64_t n_slots) { return (n_slots + kBlockCap - 1) / kBlockCap; }
- /*!
- * \brief Calculate the power-of-2 table size given the lower-bound of required capacity.
- * \param cap The lower-bound of the required capacity
- * \param fib_shift The result shift for Fibonacci Hashing
- * \param n_slots The result number of slots
- */
- static void CalcTableSize(uint64_t cap, uint32_t* fib_shift, uint64_t* n_slots) {
- uint32_t shift = 64;
- uint64_t slots = 1;
- for (uint64_t c = cap; c; c >>= 1) {
- shift -= 1;
- slots <<= 1;
- }
- TVM_FFI_ICHECK_GT(slots, cap);
- if (slots < cap * 2) {
- *fib_shift = shift - 1;
- *n_slots = slots << 1;
- } else {
- *fib_shift = shift;
- *n_slots = slots;
- }
- }
- /*!
- * \brief Fibonacci Hashing, maps a hash code to an index in a power-of-2-sized table.
- * See also: https://programmingpraxis.com/2018/06/19/fibonacci-hash/.
- * \param hash_value The raw hash value
- * \param fib_shift The shift in Fibonacci Hashing
- * \return An index calculated using Fibonacci Hashing
- */
- static uint64_t FibHash(uint64_t hash_value, uint32_t fib_shift) {
- constexpr uint64_t coeff = 11400714819323198485ull;
- return (coeff * hash_value) >> fib_shift;
- }
- /*! \brief The implicit in-place linked list used to index a chain */
- struct ListNode {
- /*! \brief Construct None */
- ListNode() : index(0), block(nullptr) {}
- /*! \brief Construct from position */
- ListNode(uint64_t index, const DenseMapObj* self)
- : index(index), block(self->GetBlock(index / kBlockCap)) {}
- /*! \brief Metadata on the entry */
- uint8_t& Meta() const { return *(block->bytes + index % kBlockCap); }
- /*! \brief Data on the entry */
- ItemType& Item() const {
- return *(reinterpret_cast<ItemType*>(block->bytes + kBlockCap +
- (index % kBlockCap) * sizeof(ItemType)));
- }
- /*! \brief Data on the entry */
- KVType& Data() const { return Item().data; }
- /*! \brief Key on the entry */
- key_type& Key() const { return Data().first; }
- /*! \brief Value on the entry */
- mapped_type& Val() const { return Data().second; }
- /*! \brief If the entry is head of linked list */
- bool IsHead() const { return (Meta() & 0b10000000) == 0b00000000; }
- /*! \brief If the entry is none */
- bool IsNone() const { return block == nullptr; }
- /*! \brief If the entry is empty slot */
- bool IsEmpty() const { return Meta() == uint8_t(kEmptySlot); }
- /*! \brief If the entry is protected slot */
- bool IsProtected() const { return Meta() == uint8_t(kProtectedSlot); }
- /*! \brief Set the entry to be empty */
- void SetEmpty() const { Meta() = uint8_t(kEmptySlot); }
- /*! \brief Destruct the item in the entry */
- void DestructData() const {
- // explicit call destructor to destroy the item
- // Favor this over ~KVType as MSVC may not support ~KVType (need the original name)
- (&Data())->first.Any::~Any();
- (&Data())->second.Any::~Any();
- }
- /*! \brief Set the entry to be protected */
- void SetProtected() const { Meta() = uint8_t(kProtectedSlot); }
- /*! \brief Set the entry's jump to its next entry */
- void SetJump(uint8_t jump) const { (Meta() &= 0b10000000) |= jump; }
- /*! \brief Construct a head of linked list in-place */
- void NewHead(ItemType v) const {
- Meta() = 0b00000000;
- new (&Item()) ItemType(std::move(v));
- }
- /*! \brief Construct a tail of linked list in-place */
- void NewTail(ItemType v) const {
- Meta() = 0b10000000;
- new (&Item()) ItemType(std::move(v));
- }
-
- /*! \brief If the entry has next entry on the linked list */
- bool HasNext() const { return NextProbeLocation(Meta() & 0b01111111) != 0; }
- /*! \brief Move the entry to the next entry on the linked list */
- bool MoveToNext(const DenseMapObj* self, uint8_t meta) {
- uint64_t offset = NextProbeLocation(meta & 0b01111111);
- if (offset == 0) {
- index = 0;
- block = nullptr;
- return false;
- }
- // the probing will go to next position and round back to stay within the
- // correct range of the slots
- index = (index + offset) % self->NumSlots();
- block = self->GetBlock(index / kBlockCap);
- return true;
- }
- /*! \brief Move the entry to the next entry on the linked list */
- bool MoveToNext(const DenseMapObj* self) { return MoveToNext(self, Meta()); }
- /*! \brief Get the previous entry on the linked list */
- ListNode FindPrev(const DenseMapObj* self) const {
- // start from the head of the linked list, which must exist
- ListNode next = self->IndexFromHash(AnyHash()(Key()));
- // `prev` is always the previous item of `next`
- ListNode prev = next;
- for (next.MoveToNext(self); index != next.index; prev = next, next.MoveToNext(self)) {
- }
- return prev;
- }
- /*! \brief Get the next empty jump */
- bool GetNextEmpty(const DenseMapObj* self, uint8_t* jump, ListNode* result) const {
- for (uint8_t idx = 1; idx < kNumJumpDists; ++idx) {
- // the probing will go to next position and round back to stay within the
- // correct range of the slots
- ListNode candidate((index + NextProbeLocation(idx)) % self->NumSlots(), self);
- if (candidate.IsEmpty()) {
- *jump = idx;
- *result = candidate;
- return true;
- }
- }
- return false;
- }
- /*! \brief Index on the real array */
- uint64_t index;
- /*! \brief Pointer to the actual block */
- Block* block;
- };
-
- protected:
- /*! \brief fib shift in Fibonacci Hashing */
- uint32_t fib_shift_;
- /*! \brief the head of iterator list */
- uint64_t iter_list_head_ = kInvalidIndex;
- /*! \brief the tail of iterator list */
- uint64_t iter_list_tail_ = kInvalidIndex;
-
- static uint64_t NextProbeLocation(size_t index) {
- /* clang-format off */
- /*! \brief Candidates of probing distance */
- static const uint64_t kNextProbeLocation[kNumJumpDists] {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- // Quadratic probing with triangle numbers. See also:
- // 1) https://en.wikipedia.org/wiki/Quadratic_probing
- // 2) https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/
- // 3) https://github.com/skarupke/flat_hash_map
- 21, 28, 36, 45, 55, 66, 78, 91, 105, 120,
- 136, 153, 171, 190, 210, 231, 253, 276, 300, 325,
- 351, 378, 406, 435, 465, 496, 528, 561, 595, 630,
- 666, 703, 741, 780, 820, 861, 903, 946, 990, 1035,
- 1081, 1128, 1176, 1225, 1275, 1326, 1378, 1431, 1485, 1540,
- 1596, 1653, 1711, 1770, 1830, 1891, 1953, 2016, 2080, 2145,
- 2211, 2278, 2346, 2415, 2485, 2556, 2628,
- // larger triangle numbers
- 8515, 19110, 42778, 96141, 216153,
- 486591, 1092981, 2458653, 5532801, 12442566,
- 27993903, 62983476, 141717030, 318844378, 717352503,
- 1614057336, 3631522476, 8170957530, 18384510628, 41364789378,
- 93070452520, 209408356380, 471168559170, 1060128894105, 2385289465695,
- 5366898840628, 12075518705635, 27169915244790, 61132312065111, 137547689707000,
- 309482283181501, 696335127828753, 1566753995631385, 3525196511162271, 7931691992677701,
- 17846306936293605, 40154190677507445, 90346928918121501, 203280589587557251,
- 457381325854679626, 1029107982097042876, 2315492959180353330, 5209859154120846435,
- };
- /* clang-format on */
- return kNextProbeLocation[index];
- }
- friend class MapObj;
-
- private:
- /*!
- * \brief Set the number of slots and attach tags bit.
- * \param n The number of slots
- */
- void SetSlotsAndDenseLayoutTag(uint64_t n) {
- TVM_FFI_ICHECK(((n & kSmallTagMask) == 0ull)) << "DenseMap expects MSB clear";
- slots_ = n;
- }
-};
-
-/// \cond
-#define TVM_FFI_DISPATCH_MAP(base, var, body) \
- { \
- using TSmall = SmallMapObj*; \
- using TDense = DenseMapObj*; \
- if (base->IsSmallMap()) { \
- TSmall var = static_cast<TSmall>(base); \
- body; \
- } else { \
- TDense var = static_cast<TDense>(base); \
- body; \
- } \
- }
-
-#define TVM_FFI_DISPATCH_MAP_CONST(base, var, body) \
- { \
- using TSmall = const SmallMapObj*; \
- using TDense = const DenseMapObj*; \
- if (base->IsSmallMap()) { \
- TSmall var = static_cast<TSmall>(base); \
- body; \
- } else { \
- TDense var = static_cast<TDense>(base); \
- body; \
- } \
- }
-
-inline MapObj::iterator::pointer MapObj::iterator::operator->() const {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- TVM_FFI_DISPATCH_MAP_CONST(self, p, { return p->DeRefItr(index); });
-}
-
-inline MapObj::iterator& MapObj::iterator::operator++() {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- TVM_FFI_DISPATCH_MAP_CONST(self, p, {
- index = p->IncItr(index);
- return *this;
- });
-}
-
-inline MapObj::iterator& MapObj::iterator::operator--() {
- TVM_FFI_MAP_FAIL_IF_CHANGED()
- TVM_FFI_DISPATCH_MAP_CONST(self, p, {
- index = p->DecItr(index);
- return *this;
- });
-}
-
-inline size_t MapObj::count(const key_type& key) const {
- TVM_FFI_DISPATCH_MAP_CONST(this, p, { return p->count(key); });
-}
-
-inline const MapObj::mapped_type& MapObj::at(const MapObj::key_type& key) const {
- TVM_FFI_DISPATCH_MAP_CONST(this, p, { return p->at(key); });
-}
-
-inline MapObj::mapped_type& MapObj::at(const MapObj::key_type& key) {
- TVM_FFI_DISPATCH_MAP(this, p, { return p->at(key); });
-}
-
-inline MapObj::iterator MapObj::begin() const {
- TVM_FFI_DISPATCH_MAP_CONST(this, p, { return p->begin(); });
-}
-
-inline MapObj::iterator MapObj::end() const {
- TVM_FFI_DISPATCH_MAP_CONST(this, p, { return p->end(); });
-}
-
-inline MapObj::iterator MapObj::find(const MapObj::key_type& key) const {
- TVM_FFI_DISPATCH_MAP_CONST(this, p, { return p->find(key); });
-}
-
-inline void MapObj::erase(const MapObj::iterator& position) {
- TVM_FFI_DISPATCH_MAP(this, p, { return p->erase(position); });
-}
-/// \endcond
-
-#undef TVM_FFI_DISPATCH_MAP
-#undef TVM_FFI_DISPATCH_MAP_CONST
-
-inline ObjectPtr<MapObj> MapObj::Empty() { return SmallMapObj::Empty(); }
-
-inline ObjectPtr<MapObj> MapObj::CopyFrom(MapObj* from) {
- if (from->IsSmallMap()) {
- return SmallMapObj::CopyFrom(static_cast<SmallMapObj*>(from));
- } else {
- return DenseMapObj::CopyFrom(static_cast<DenseMapObj*>(from));
- }
-}
-
-template <typename IterType>
-inline ObjectPtr<Object> MapObj::CreateFromRange(IterType first, IterType last) {
- int64_t _cap = std::distance(first, last);
- if (_cap < 0) {
- return SmallMapObj::Empty();
- }
- uint64_t cap = static_cast<uint64_t>(_cap);
- if (cap < SmallMapObj::kMaxSize) {
- if (cap < 2) {
- return SmallMapObj::CreateFromRange(cap, first, last);
- }
- // need to insert to avoid duplicate keys
- ObjectPtr<Object> obj = SmallMapObj::Empty(cap);
- for (; first != last; ++first) {
- KVType kv(*first);
- SmallMapObj::InsertMaybeReHash(std::move(kv), &obj);
- }
- return obj;
- } else {
- uint32_t fib_shift;
- uint64_t n_slots;
- DenseMapObj::CalcTableSize(cap, &fib_shift, &n_slots);
- ObjectPtr<Object> obj = DenseMapObj::Empty(fib_shift, n_slots);
- for (; first != last; ++first) {
- KVType kv(*first);
- DenseMapObj::InsertMaybeReHash(std::move(kv), &obj);
- }
- return obj;
- }
-}
-
-inline void MapObj::InsertMaybeReHash(KVType&& kv, ObjectPtr<Object>* map) {
- MapObj* base = static_cast<MapObj*>(map->get());
-#if TVM_FFI_DEBUG_WITH_ABI_CHANGE
- base->state_marker++;
-#endif // TVM_FFI_DEBUG_WITH_ABI_CHANGE
- if (base->IsSmallMap()) {
- SmallMapObj* sm = static_cast<SmallMapObj*>(base);
- if (sm->NumSlots() < SmallMapObj::kMaxSize) {
- SmallMapObj::InsertMaybeReHash(std::move(kv), map);
- } else if (sm->NumSlots() == SmallMapObj::kMaxSize) {
- if (base->size_ < sm->NumSlots()) {
- SmallMapObj::InsertMaybeReHash(std::move(kv), map);
- } else {
- ObjectPtr<Object> new_map = MapObj::CreateFromRange(base->begin(), base->end());
- DenseMapObj::InsertMaybeReHash(std::move(kv), &new_map);
- *map = std::move(new_map);
- }
- }
- } else {
- DenseMapObj::InsertMaybeReHash(std::move(kv), map);
- }
-}
-
-template <>
-inline ObjectPtr<MapObj> make_object<>() = delete;
-
-/*!
- * \brief Map container of NodeRef->NodeRef in DSL graph.
- * Map implements copy on write semantics, which means map is mutable
- * but copy will happen when array is referenced in more than two places.
- *
- * operator[] only provide const acces, use Set to mutate the content.
- * \tparam K The key NodeRef type.
- * \tparam V The value NodeRef type.
- */
-template <typename K, typename V,
- typename = typename std::enable_if_t<details::storage_enabled_v<K> &&
- details::storage_enabled_v<V>>>
-class Map : public ObjectRef {
- public:
- /*! \brief The key type of the map */
- using key_type = K;
- /*! \brief The mapped type of the map */
- using mapped_type = V;
- /*! \brief The iterator type of the map */
- class iterator;
- /*!
- * \brief Construct an Map with UnsafeInit
- */
- explicit Map(UnsafeInit tag) : ObjectRef(tag) {}
- /*!
- * \brief default constructor
- */
- Map() { data_ = MapObj::Empty(); }
- /*!
- * \brief move constructor
- * \param other source
- */
- Map(Map<K, V>&& other) : ObjectRef(std::move(other.data_)) {}
- /*!
- * \brief copy constructor
- * \param other source
- */
- Map(const Map<K, V>& other) : ObjectRef(other.data_) {}
-
- /*!
- * \brief Move constructor
- * \param other The other map
- * \tparam KU The key type of the other map
- * \tparam VU The mapped type of the other map
- */
- template <typename KU, typename VU,
- typename = std::enable_if_t<details::type_contains_v<K, KU> &&
- details::type_contains_v<V, VU>>>
- Map(Map<KU, VU>&& other) : ObjectRef(std::move(other.data_)) {}
-
- /*!
- * \brief Copy constructor
- * \param other The other map
- * \tparam KU The key type of the other map
- * \tparam VU The mapped type of the other map
- */
- template <typename KU, typename VU,
- typename = std::enable_if_t<details::type_contains_v<K, KU> &&
- details::type_contains_v<V, VU>>>
- Map(const Map<KU, VU>& other) : ObjectRef(other.data_) {}
-
- /*!
- * \brief Move assignment
- * \param other The other map
- */
- Map<K, V>& operator=(Map<K, V>&& other) {
- data_ = std::move(other.data_);
- return *this;
- }
-
- /*!
- * \brief Copy assignment
- * \param other The other map
- */
- Map<K, V>& operator=(const Map<K, V>& other) {
- data_ = other.data_;
- return *this;
- }
-
- /*!
- * \brief Move assignment
- * \param other The other map
- * \tparam KU The key type of the other map
- * \tparam VU The mapped type of the other map
- */
- template <typename KU, typename VU,
- typename = std::enable_if_t<details::type_contains_v<K, KU> &&
- details::type_contains_v<V, VU>>>
- Map<K, V>& operator=(Map<KU, VU>&& other) {
- data_ = std::move(other.data_);
- return *this;
- }
-
- /*!
- * \brief Copy assignment
- * \param other The other map
- * \tparam KU The key type of the other map
- * \tparam VU The mapped type of the other map
- */
- template <typename KU, typename VU,
- typename = std::enable_if_t<details::type_contains_v<K, KU> &&
- details::type_contains_v<V, VU>>>
- Map<K, V>& operator=(const Map<KU, VU>& other) {
- data_ = other.data_;
- return *this;
- }
- /*!
- * \brief constructor from pointer
- * \param n the container pointer
- */
- explicit Map(ObjectPtr<Object> n) : ObjectRef(n) {}
- /*!
- * \brief constructor from iterator
- * \param begin begin of iterator
- * \param end end of iterator
- * \tparam IterType The type of iterator
- */
- template <typename IterType>
- Map(IterType begin, IterType end) {
- data_ = MapObj::CreateFromRange(begin, end);
- }
- /*!
- * \brief constructor from initializer list
- * \param init The initalizer list
- */
- Map(std::initializer_list<std::pair<K, V>> init) {
- data_ = MapObj::CreateFromRange(init.begin(), init.end());
- }
- /*!
- * \brief constructor from unordered_map
- * \param init The unordered_map
- */
- template <typename Hash, typename Equal>
- Map(const std::unordered_map<K, V, Hash, Equal>& init) { // NOLINT(*)
- data_ = MapObj::CreateFromRange(init.begin(), init.end());
- }
- /*!
- * \brief Read element from map.
- * \param key The key
- * \return the corresonding element.
- */
- const V at(const K& key) const {
- return details::AnyUnsafe::CopyFromAnyViewAfterCheck<V>(GetMapObj()->at(key));
- }
- /*!
- * \brief Read element from map.
- * \param key The key
- * \return the corresonding element.
- */
- const V operator[](const K& key) const { return this->at(key); }
- /*! \return The size of the array */
- size_t size() const {
- MapObj* n = GetMapObj();
- return n == nullptr ? 0 : n->size();
- }
- /*! \return The number of elements of the key */
- size_t count(const K& key) const {
- MapObj* n = GetMapObj();
- return n == nullptr ? 0 : GetMapObj()->count(key);
- }
- /*! \return whether array is empty */
- bool empty() const { return size() == 0; }
- /*! \brief Release reference to all the elements */
- void clear() {
- MapObj* n = GetMapObj();
- if (n != nullptr) {
- data_ = MapObj::Empty();
- }
- }
- /*!
- * \brief set the Map.
- * \param key The index key.
- * \param value The value to be setted.
- */
- void Set(const K& key, const V& value) {
- CopyOnWrite();
- MapObj::InsertMaybeReHash(MapObj::KVType(key, value), &data_);
- }
- /*! \return begin iterator */
- iterator begin() const { return iterator(GetMapObj()->begin()); }
- /*! \return end iterator */
- iterator end() const { return iterator(GetMapObj()->end()); }
- /*! \return find the key and returns the associated iterator */
- iterator find(const K& key) const { return iterator(GetMapObj()->find(key)); }
- /*! \return The value associated with the key, std::nullopt if not found */
- std::optional<V> Get(const K& key) const {
- MapObj::iterator iter = GetMapObj()->find(key);
- if (iter == GetMapObj()->end()) {
- return std::nullopt;
- }
- return details::AnyUnsafe::CopyFromAnyViewAfterCheck<V>(iter->second);
- }
-
- /*!
- * \brief Erase the entry associated with the key
- * \param key The key
- */
- void erase(const K& key) { CopyOnWrite()->erase(key); }
-
- /*!
- * \brief copy on write semantics
- * Do nothing if current handle is the unique copy of the array.
- * Otherwise make a new copy of the array to ensure the current handle
- * hold a unique copy.
- *
- * \return Handle to the internal node container(which guarantees to be unique)
- */
- MapObj* CopyOnWrite() {
- if (data_.get() == nullptr) {
- data_ = MapObj::Empty();
- } else if (!data_.unique()) {
- data_ = MapObj::CopyFrom(GetMapObj());
- }
- return GetMapObj();
- }
- /*! \brief specify container node */
- using ContainerType = MapObj;
-
- /// \cond Doxygen_Suppress
- /*! \brief Iterator of the hash map */
- class iterator {
- public:
- using iterator_category = std::bidirectional_iterator_tag;
- using difference_type = int64_t;
- using value_type = const std::pair<K, V>;
- using pointer = value_type*;
- using reference = value_type;
-
- iterator() : itr() {}
-
- /*! \brief Compare iterators */
- bool operator==(const iterator& other) const { return itr == other.itr; }
- /*! \brief Compare iterators */
- bool operator!=(const iterator& other) const { return itr != other.itr; }
- /*! \brief De-reference iterators is not allowed */
- pointer operator->() const = delete;
- /*! \brief De-reference iterators */
- reference operator*() const {
- auto& kv = *itr;
- return std::make_pair(details::AnyUnsafe::CopyFromAnyViewAfterCheck<K>(kv.first),
- details::AnyUnsafe::CopyFromAnyViewAfterCheck<V>(kv.second));
- }
- /*! \brief Prefix self increment, e.g. ++iter */
- iterator& operator++() {
- ++itr;
- return *this;
- }
- /*! \brief Suffix self increment */
- iterator operator++(int) {
- iterator copy = *this;
- ++(*this);
- return copy;
- }
-
- /*! \brief Prefix self decrement, e.g. --iter */
- iterator& operator--() {
- --itr;
- return *this;
- }
- /*! \brief Suffix self decrement */
- iterator operator--(int) {
- iterator copy = *this;
- --(*this);
- return copy;
- }
-
- private:
- iterator(const MapObj::iterator& itr) // NOLINT(*)
- : itr(itr) {}
-
- template <typename, typename, typename>
- friend class Map;
-
- MapObj::iterator itr;
- };
- /// \endcond
-
- private:
- /*! \brief Return data_ as type of pointer of MapObj */
- MapObj* GetMapObj() const { return static_cast<MapObj*>(data_.get()); }
-
- template <typename, typename, typename>
- friend class Map;
-};
-
-/*!
- * \brief Merge two Maps.
- * \param lhs the first Map to merge.
- * \param rhs the second Map to merge.
- * @return The merged Array. Original Maps are kept unchanged.
- */
-template <typename K, typename V,
- typename = typename std::enable_if_t<details::storage_enabled_v<K> &&
- details::storage_enabled_v<V>>>
-inline Map<K, V> Merge(Map<K, V> lhs, const Map<K, V>& rhs) {
- for (const auto& p : rhs) {
- lhs.Set(p.first, p.second);
- }
- return std::move(lhs);
-}
-
-// Traits for Map
-template <typename K, typename V>
-inline constexpr bool use_default_type_traits_v<Map<K, V>> = false;
-
-template <typename K, typename V>
-struct TypeTraits<Map<K, V>> : public ObjectRefTypeTraitsBase<Map<K, V>> {
- static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIMap;
- using ObjectRefTypeTraitsBase<Map<K, V>>::CopyFromAnyViewAfterCheck;
-
- TVM_FFI_INLINE static std::string GetMismatchTypeInfo(const TVMFFIAny* src) {
- if (src->type_index != TypeIndex::kTVMFFIMap) {
- return TypeTraitsBase::GetMismatchTypeInfo(src);
- }
- if constexpr (!std::is_same_v<K, Any> || !std::is_same_v<V, Any>) {
- const MapObj* n = reinterpret_cast<const MapObj*>(src->v_obj);
- for (const auto& kv : *n) {
- if constexpr (!std::is_same_v<K, Any>) {
- if (!details::AnyUnsafe::CheckAnyStrict<K>(kv.first) &&
- !kv.first.try_cast<K>().has_value()) {
- return "Map[some key is " + details::AnyUnsafe::GetMismatchTypeInfo<K>(kv.first) +
- ", V]";
- }
- }
- if constexpr (!std::is_same_v<V, Any>) {
- if (!details::AnyUnsafe::CheckAnyStrict<V>(kv.second) &&
- !kv.second.try_cast<V>().has_value()) {
- return "Map[K, some value is " + details::AnyUnsafe::GetMismatchTypeInfo<V>(kv.second) +
- "]";
- }
- }
- }
- }
- TVM_FFI_THROW(InternalError) << "Cannot reach here";
- TVM_FFI_UNREACHABLE();
- }
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- if (src->type_index != TypeIndex::kTVMFFIMap) return false;
- if constexpr (std::is_same_v<K, Any> && std::is_same_v<V, Any>) {
- return true;
- } else {
- const MapObj* n = reinterpret_cast<const MapObj*>(src->v_obj);
- for (const auto& kv : *n) {
- if constexpr (!std::is_same_v<K, Any>) {
- if (!details::AnyUnsafe::CheckAnyStrict<K>(kv.first)) return false;
- }
- if constexpr (!std::is_same_v<V, Any>) {
- if (!details::AnyUnsafe::CheckAnyStrict<V>(kv.second)) return false;
- }
- }
- return true;
- }
- }
-
- TVM_FFI_INLINE static std::optional<Map<K, V>> TryCastFromAnyView(const TVMFFIAny* src) {
- if (src->type_index != TypeIndex::kTVMFFIMap) return std::nullopt;
- if constexpr (!std::is_same_v<K, Any> || !std::is_same_v<V, Any>) {
- const MapObj* n = reinterpret_cast<const MapObj*>(src->v_obj);
- bool storage_check = [&]() {
- for (const auto& kv : *n) {
- if constexpr (!std::is_same_v<K, Any>) {
- if (!details::AnyUnsafe::CheckAnyStrict<K>(kv.first)) return false;
- }
- if constexpr (!std::is_same_v<V, Any>) {
- if (!details::AnyUnsafe::CheckAnyStrict<V>(kv.second)) return false;
- }
- }
- return true;
- }();
- // fast path, if storage check passes, we can return the array directly.
- if (storage_check) return CopyFromAnyViewAfterCheck(src);
- // slow path, we need to create a new map and convert to the target type.
- Map<K, V> ret;
- for (const auto& kv : *n) {
- auto k = kv.first.try_cast<K>();
- auto v = kv.second.try_cast<V>();
- if (!k.has_value() || !v.has_value()) return std::nullopt;
- ret.Set(*std::move(k), *std::move(v));
- }
- return ret;
- } else {
- return CopyFromAnyViewAfterCheck(src);
- }
- }
-
- TVM_FFI_INLINE static std::string TypeStr() {
- return "Map<" + details::Type2Str<K>::v() + ", " + details::Type2Str<V>::v() + ">";
- }
-};
-
-namespace details {
-template <typename K, typename V, typename KU, typename VU>
-inline constexpr bool type_contains_v<Map<K, V>, Map<KU, VU>> =
- type_contains_v<K, KU> && type_contains_v<V, VU>;
-} // namespace details
-
-} // namespace ffi
-} // namespace tvm
-#endif // TVM_FFI_CONTAINER_MAP_H_
diff --git a/ffi/include/tvm/ffi/container/shape.h b/ffi/include/tvm/ffi/container/shape.h
deleted file mode 100644
index de24a44ded..0000000000
--- a/ffi/include/tvm/ffi/container/shape.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file tvm/ffi/container/shape.h
- * \brief Container to store shape of an Tensor.
- */
-#ifndef TVM_FFI_CONTAINER_SHAPE_H_
-#define TVM_FFI_CONTAINER_SHAPE_H_
-
-#include <tvm/ffi/container/array.h>
-#include <tvm/ffi/error.h>
-#include <tvm/ffi/type_traits.h>
-
-#include <algorithm>
-#include <ostream>
-#include <utility>
-#include <vector>
-
-namespace tvm {
-namespace ffi {
-
... 29376 lines suppressed ...