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

tqchen pushed a commit to branch refactor-s0
in repository https://gitbox.apache.org/repos/asf/tvm.git

commit ea2549e0a8716b7984723a425a8071be3de9980e
Author: tqchen <[email protected]>
AuthorDate: Tue Aug 6 13:16:38 2024 -0400

    [FFI] Initial step to create ffi from the original tvm source
---
 ffi/CMakeLists.txt                   |   2 +-
 ffi/include                          |   1 -
 ffi/include/tvm/ffi/c_ffi_abi.h      | 134 +++++++++++++++++++++
 ffi/include/tvm/ffi/internal_utils.h |  77 ++++++++++++
 ffi/include/tvm/ffi/memory.h         |   0
 ffi/include/tvm/ffi/object.h         | 223 +++++++++++++++++++++++++++++++++++
 ffi/src                              |   1 -
 ffi/src/ffi/registry.cc              |   1 +
 ffi/tests/example/CMakeLists.txt     |  21 ++++
 ffi/tests/example/test_c_ffi_abi.cc  |  12 ++
 ffi/tests/example/test_object.cc     |  12 ++
 11 files changed, 481 insertions(+), 3 deletions(-)

diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt
index 8710a0c377..532922bf14 100644
--- a/ffi/CMakeLists.txt
+++ b/ffi/CMakeLists.txt
@@ -73,6 +73,6 @@ if (${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
     enable_testing()
     message(STATUS "Enable Testing")
     include(cmake/Utils/AddGoogleTest.cmake)
-    add_subdirectory(tests/cpp/)
+    add_subdirectory(tests/example/)
   endif()
 endif ()
diff --git a/ffi/include b/ffi/include
deleted file mode 120000
index f5030fe889..0000000000
--- a/ffi/include
+++ /dev/null
@@ -1 +0,0 @@
-../include
\ No newline at end of file
diff --git a/ffi/include/tvm/ffi/c_ffi_abi.h b/ffi/include/tvm/ffi/c_ffi_abi.h
new file mode 100644
index 0000000000..ccba3f58df
--- /dev/null
+++ b/ffi/include/tvm/ffi/c_ffi_abi.h
@@ -0,0 +1,134 @@
+/*
+ * 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_ffi_abi.h
+ * \brief This file defines
+ */
+#ifndef TVM_FFI_C_FFI_ABI_H_
+#define TVM_FFI_C_FFI_ABI_H_
+
+#include <dlpack/dlpack.h>
+#include <stdint.h>
+
+#if !defined(TVM_FFI_DLL) && defined(__EMSCRIPTEN__)
+#include <emscripten/emscripten.h>
+#define TVM_FFI_API 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
+#endif
+#ifndef TVM_FFI_DLL
+#define TVM_FFI_DLL __attribute__((visibility("default")))
+#endif
+
+#ifndef TVM_FFI_ALLOW_DYN_TYPE
+#define TVM_FFI_ALLOW_DYN_TYPE 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+enum class TVMFFITypeIndex : int32_t {
+#else
+typedef enum {
+#endif
+  // [Section] On-stack POD 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`
+  kTVMFFINone = 0,
+  kTVMFFIInt = 1,
+  kTVMFFIFloat = 2,
+  kTVMFFIOpaquePtr = 3,
+  kTVMFFIDataType = 4,
+  kTVMFFIDevice = 5,
+  kTVMFFIRawStr = 6,
+  // [Section] Static Boxed: [kTVMFFIStaticObjectBegin, kTVMFFIDynObjectBegin)
+  kTVMFFIStaticObjectBegin = 64,
+  kTVMFFIObject = 64,
+  kTVMFFIList = 65,
+  kTVMFFIDict = 66,
+  kTVMFFIError = 67,
+  kTVMFFIFunc = 68,
+  kTVMFFIStr = 69,
+  // [Section] Dynamic Boxed: [kTVMFFIDynObjectBegin, +oo)
+  kTVMFFIDynObjectBegin = 128,
+#ifdef __cplusplus
+};
+#else
+} TVMFFITypeIndex;
+#endif
+
+/*!
+ * \brief C-based type of all FFI object types that allocates on heap.
+ * \note TVMFFIObject and TVMFFIAny share the common type_index_ header
+ */
+typedef struct TVMFFIObject {
+  /*!
+   * \brief type index of the object.
+   * \note The type index of Object and Any are shared in FFI.
+   */
+  int32_t type_index;
+  /*! \brief Reference counter of the object. */
+  int32_t ref_counter;
+  /*! \brief Deleter to be invoked when reference counter goes to zero. */
+  void (*deleter)(struct TVMFFIObject* self);
+} 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 TVMFFIAny {
+  /*!
+   * \brief type index of the object.
+   * \note The type index of Object and Any are shared in FFI.
+   */
+  int32_t type_index;
+  /*! \brief length for on-stack Any object, such as small-string */
+  int32_t small_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
+  };
+} TVMFFIAny;
+
+#ifdef __cplusplus
+}  // TVM_FFI_EXTERN_C
+#endif
+
+#endif  // TVM_FFI_C_FFI_ABI_H_
diff --git a/ffi/include/tvm/ffi/internal_utils.h 
b/ffi/include/tvm/ffi/internal_utils.h
new file mode 100644
index 0000000000..53d08c364c
--- /dev/null
+++ b/ffi/include/tvm/ffi/internal_utils.h
@@ -0,0 +1,77 @@
+/*
+ * 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/internal_utils.h
+ * \brief Utility functions and macros for internal use, not meant for
+ */
+#ifndef TVM_FFI_INTERNAL_UTILS_H_
+#define TVM_FFI_INTERNAL_UTILS_H_
+
+#include <tvm/ffi/c_ffi_abi.h>
+
+#include <cstddef>
+
+#if defined(_MSC_VER)
+#define TVM_FFI_INLINE __forceinline
+#else
+#define TVM_FFI_INLINE inline __attribute__((always_inline))
+#endif
+
+#if defined(_MSC_VER)
+#define TVM_FFI_UNREACHABLE() __assume(false)
+#else
+#define TVM_FFI_UNREACHABLE() __builtin_unreachable()
+#endif
+
+namespace tvm {
+namespace ffi {
+
+namespace details {
+
+/********** Atomic Operations *********/
+
+TVM_FFI_INLINE int32_t AtomicIncrementRelaxed(int32_t* ptr) {
+#ifdef _MSC_VER
+  return _InterlockedIncrement(reinterpret_cast<volatile long*>(ptr)) - 1;
+#else
+  return __atomic_fetch_add(ptr, 1, __ATOMIC_RELAXED);
+#endif
+}
+
+TVM_FFI_INLINE int32_t AtomicDecrementRelAcq(int32_t* ptr) {
+#ifdef _MSC_VER
+  return _InterlockedDecrement(reinterpret_cast<volatile long*>(ptr)) + 1;
+#else
+  return __atomic_fetch_sub(ptr, 1, __ATOMIC_ACQ_REL);
+#endif
+}
+
+TVM_FFI_INLINE int32_t AtomicLoadRelaxed(const int32_t* ptr) {
+  int32_t* raw_ptr = const_cast<int32_t*>(ptr);
+#ifdef _MSC_VER
+  // simply load the variable ptr out
+  return (reinterpret_cast<const volatile long*>(raw_ptr))[0];
+#else
+  return __atomic_load_n(raw_ptr, __ATOMIC_RELAXED);
+#endif
+}
+}  // namespace details
+}  // namespace ffi
+}  // namespace tvm
+#endif  // TVM_FFI_INTERNAL_UTILS_H_
diff --git a/ffi/include/tvm/ffi/memory.h b/ffi/include/tvm/ffi/memory.h
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ffi/include/tvm/ffi/object.h b/ffi/include/tvm/ffi/object.h
new file mode 100644
index 0000000000..90e78defae
--- /dev/null
+++ b/ffi/include/tvm/ffi/object.h
@@ -0,0 +1,223 @@
+/*
+ * 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/object.h
+ * \brief A managed object in the TVM FFI.
+ */
+#ifndef TVM_FFI_OBJECT_H_
+#define TVM_FFI_OBJECT_H_
+
+#include <tvm/ffi/c_ffi_abi.h>
+#include <tvm/ffi/internal_utils.h>
+
+namespace tvm {
+namespace ffi {
+
+namespace details {
+// forward declare object internal
+struct ObjectInternal;
+}  // namespace details
+
+class Object : protected TVMFFIObject {
+ public:
+  Object() {
+    TVMFFIObject::ref_counter = 0;
+    TVMFFIObject::deleter = nullptr;
+  }
+
+ private:
+  /*! \brief decreas*/
+  void IncRef() { details::AtomicIncrementRelaxed(&(this->ref_counter)); }
+
+  void DecRef() {
+    if (details::AtomicDecrementRelAcq(&(this->ref_counter)) == 1) {
+      if (this->deleter != nullptr) {
+        this->deleter(this);
+      }
+    }
+  }
+
+  /*!
+   * \return The usage count of the cell.
+   * \note We use stl style naming to be consistent with known API in 
shared_ptr.
+   */
+  int32_t use_count() const { return 
details::AtomicLoadRelaxed(&(this->ref_counter)); }
+
+  // friend classes
+  template <typename>
+  friend class ObjectPtr;
+  friend class tvm::ffi::details::ObjectInternal;
+};
+
+/*!
+ * \brief A custom smart pointer for Object.
+ * \tparam T the content data type.
+ * \sa make_object
+ */
+template <typename T>
+class ObjectPtr {
+ public:
+  /*! \brief default constructor */
+  ObjectPtr() {}
+  /*! \brief default constructor */
+  ObjectPtr(std::nullptr_t) {}  // NOLINT(*)
+  /*!
+   * \brief copy constructor
+   * \param other The value to be moved
+   */
+  ObjectPtr(const ObjectPtr<T>& other)  // NOLINT(*)
+      : ObjectPtr(other.data_) {}
+  /*!
+   * \brief copy constructor
+   * \param other The value to be moved
+   */
+  template <typename U>
+  ObjectPtr(const ObjectPtr<U>& other)  // NOLINT(*)
+      : ObjectPtr(other.data_) {
+    static_assert(std::is_base_of<T, U>::value,
+                  "can only assign of child class ObjectPtr to parent");
+  }
+  /*!
+   * \brief move constructor
+   * \param other The value to be moved
+   */
+  ObjectPtr(ObjectPtr<T>&& other)  // NOLINT(*)
+      : data_(other.data_) {
+    other.data_ = nullptr;
+  }
+  /*!
+   * \brief move constructor
+   * \param other The value to be moved
+   */
+  template <typename Y>
+  ObjectPtr(ObjectPtr<Y>&& other)  // NOLINT(*)
+      : data_(other.data_) {
+    static_assert(std::is_base_of<T, Y>::value,
+                  "can only assign of child class ObjectPtr to parent");
+    other.data_ = nullptr;
+  }
+  /*! \brief destructor */
+  ~ObjectPtr() { this->reset(); }
+  /*!
+   * \brief Swap this array with another Object
+   * \param other The other Object
+   */
+  void swap(ObjectPtr<T>& other) {  // NOLINT(*)
+    std::swap(data_, other.data_);
+  }
+  /*!
+   * \return Get the content of the pointer
+   */
+  T* get() const { return static_cast<T*>(data_); }
+  /*!
+   * \return The pointer
+   */
+  T* operator->() const { return get(); }
+  /*!
+   * \return The reference
+   */
+  T& operator*() const {  // NOLINT(*)
+    return *get();
+  }
+  /*!
+   * \brief copy assignment
+   * \param other The value to be assigned.
+   * \return reference to self.
+   */
+  ObjectPtr<T>& operator=(const ObjectPtr<T>& other) {  // NOLINT(*)
+    // takes in plane operator to enable copy elison.
+    // copy-and-swap idiom
+    ObjectPtr(other).swap(*this);  // NOLINT(*)
+    return *this;
+  }
+  /*!
+   * \brief move assignment
+   * \param other The value to be assigned.
+   * \return reference to self.
+   */
+  ObjectPtr<T>& operator=(ObjectPtr<T>&& other) {  // NOLINT(*)
+    // copy-and-swap idiom
+    ObjectPtr(std::move(other)).swap(*this);  // NOLINT(*)
+    return *this;
+  }
+  /*!
+   * \brief nullptr check
+   * \return result of comparison of internal pointer with nullptr.
+   */
+  explicit operator bool() const { return get() != nullptr; }
+  /*! \brief reset the content of ptr to be nullptr */
+  void reset() {
+    if (data_ != nullptr) {
+      data_->DecRef();
+      data_ = nullptr;
+    }
+  }
+  /*! \return The use count of the ptr, for debug purposes */
+  int use_count() const { return data_ != nullptr ? data_->use_count() : 0; }
+  /*! \return whether the reference is unique */
+  bool unique() const { return data_ != nullptr && data_->use_count() == 1; }
+  /*! \return Whether two ObjectPtr do not equal each other */
+  bool operator==(const ObjectPtr<T>& other) const { return data_ == 
other.data_; }
+  /*! \return Whether two ObjectPtr equals each other */
+  bool operator!=(const ObjectPtr<T>& other) const { return data_ != 
other.data_; }
+  /*! \return Whether the pointer is nullptr */
+  bool operator==(std::nullptr_t null) const { return data_ == nullptr; }
+  /*! \return Whether the pointer is not nullptr */
+  bool operator!=(std::nullptr_t null) const { return data_ != nullptr; }
+
+ private:
+  /*! \brief internal pointer field */
+  Object* data_{nullptr};
+  /*!
+   * \brief constructor from Object
+   * \param data The data pointer
+   */
+  explicit ObjectPtr(Object* data) : data_(data) {
+    if (data != nullptr) {
+      data_->IncRef();
+    }
+  }
+  /*!
+   * \brief Move an ObjectPtr from an RValueRef argument.
+   * \param ref The rvalue reference.
+   * \return the moved result.
+   */
+  static ObjectPtr<T> MoveFromRValueRefArg(Object** ref) {
+    ObjectPtr<T> ptr;
+    ptr.data_ = *ref;
+    *ref = nullptr;
+    return ptr;
+  }
+  // friend classes
+  friend class Object;
+  friend class ObjectRef;
+  friend class tvm::ffi::details::ObjectInternal;
+  template <typename RelayRefType, typename ObjType>
+  friend RelayRefType GetRef(const ObjType* ptr);
+  template <typename BaseType, typename ObjType>
+  friend ObjectPtr<BaseType> GetObjectPtr(ObjType* ptr);
+};
+
+namespace details {
+/*! \brief Namespace to internally manipulate object class. */
+struct ObjectInternal {};
+}  // namespace details
+}  // namespace ffi
+}  // namespace tvm
+#endif  // TVM_FFI_OBJECT_H_
diff --git a/ffi/src b/ffi/src
deleted file mode 120000
index 5cd551cf26..0000000000
--- a/ffi/src
+++ /dev/null
@@ -1 +0,0 @@
-../src
\ No newline at end of file
diff --git a/ffi/src/ffi/registry.cc b/ffi/src/ffi/registry.cc
new file mode 100644
index 0000000000..698f81c2b6
--- /dev/null
+++ b/ffi/src/ffi/registry.cc
@@ -0,0 +1 @@
+namespace tvm {}
\ No newline at end of file
diff --git a/ffi/tests/example/CMakeLists.txt b/ffi/tests/example/CMakeLists.txt
new file mode 100644
index 0000000000..a78e3ee01a
--- /dev/null
+++ b/ffi/tests/example/CMakeLists.txt
@@ -0,0 +1,21 @@
+file(GLOB _test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test*.cc")
+add_executable(
+  tvm_ffi_tests
+  EXCLUDE_FROM_ALL
+  ${_test_sources}
+)
+set_target_properties(
+  tvm_ffi_tests PROPERTIES
+  CXX_STANDARD 17
+  CXX_STANDARD_REQUIRED ON
+  CXX_EXTENSIONS OFF
+  MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
+  ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+  LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+)
+add_cxx_warning(tvm_ffi_tests)
+add_sanitizer_address(tvm_ffi_tests)
+target_link_libraries(tvm_ffi_tests PRIVATE tvm_ffi)
+
+add_googletest(tvm_ffi_tests)
diff --git a/ffi/tests/example/test_c_ffi_abi.cc 
b/ffi/tests/example/test_c_ffi_abi.cc
new file mode 100644
index 0000000000..66f2dcf739
--- /dev/null
+++ b/ffi/tests/example/test_c_ffi_abi.cc
@@ -0,0 +1,12 @@
+#include <gtest/gtest.h>
+#include <tvm/ffi/c_ffi_abi.h>
+
+namespace {
+
+TEST(ABIHeaderAlignment, Default) {
+  TVMFFIObject value;
+  value.type_index = 10;
+  EXPECT_EQ(reinterpret_cast<TVMFFIAny*>(&value)->type_index, 10);
+}
+
+}  // namespace
diff --git a/ffi/tests/example/test_object.cc b/ffi/tests/example/test_object.cc
new file mode 100644
index 0000000000..95b7d0717f
--- /dev/null
+++ b/ffi/tests/example/test_object.cc
@@ -0,0 +1,12 @@
+#include <gtest/gtest.h>
+#include <tvm/ffi/object.h>
+
+namespace {
+
+using namespace tvm::ffi;
+
+TEST(Object, Default) {
+  // Object* x = new Object();
+}
+
+}  // namespace

Reply via email to