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

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


The following commit(s) were added to refs/heads/main by this push:
     new 9186b44  [CPP] Introduce InvokeExternC (#117)
9186b44 is described below

commit 9186b44d63df3be9d3d67bb10b784f5e263f7e36
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Oct 14 12:15:35 2025 -0400

    [CPP] Introduce InvokeExternC (#117)
    
    This PR introduces a static method InvokeExternC to directly invoke an
    already exported symbol in SafeCall convention without having to
    construct an ffi::Function object
---
 include/tvm/ffi/function.h | 38 ++++++++++++++++++++++++++++++++++++++
 tests/cpp/test_function.cc |  6 ++++++
 2 files changed, 44 insertions(+)

diff --git a/include/tvm/ffi/function.h b/include/tvm/ffi/function.h
index d665070..24155e3 100644
--- a/include/tvm/ffi/function.h
+++ b/include/tvm/ffi/function.h
@@ -512,6 +512,44 @@ class Function : public ObjectRef {
     };
     return FromPackedInternal(std::move(call_packed));
   }
+
+  /*!
+   * \brief Directly invoke an extern "C" function that follows the TVM FFI 
SafeCall convention.
+   *
+   * This function can be useful to turn an existing exported symbol into a 
typed function.
+   *
+   * \code
+   *
+   * // An extern "C" function, matching TVMFFISafeCallType
+   * extern "C" int __tvm_ffi_add(
+   *   void* handle, const TVMFFIAny* args, int32_t num_args, TVMFFIAny*result
+   * );
+   *
+   * // redirect an existing symbol into a typed function
+   * inline int add(int a, int b) {
+   *   return tvm::ffi::Function::InvokeExternC(nullptr, __tvm_ffi_add, a, 
b).cast<int>();
+   * }
+   *
+   * \endcode
+   *
+   * \tparam Args The types of the arguments to the extern function.
+   * \param handle The handle argument, for exported symbols this is usually 
nullptr.
+   * \param safe_call The function pointer to the extern "C" function.
+   * \param args The arguments to pass to the function.
+   * \return The return value, wrapped in a tvm::ffi::Any.
+   */
+  template <typename... Args>
+  TVM_FFI_INLINE static Any InvokeExternC(void* handle, TVMFFISafeCallType 
safe_call,
+                                          Args&&... args) {
+    const int kNumArgs = sizeof...(Args);
+    const int kArraySize = kNumArgs > 0 ? kNumArgs : 1;
+    AnyView args_pack[kArraySize];
+    PackedArgs::Fill(args_pack, std::forward<Args>(args)...);
+    Any result;
+    TVM_FFI_CHECK_SAFE_CALL(safe_call(handle, reinterpret_cast<const 
TVMFFIAny*>(args_pack),
+                                      kNumArgs, 
reinterpret_cast<TVMFFIAny*>(&result)));
+    return result;
+  }
   /*!
    * \brief Call function by directly passing in unpacked arguments.
    *
diff --git a/tests/cpp/test_function.cc b/tests/cpp/test_function.cc
index f075f7f..b8ff769 100644
--- a/tests/cpp/test_function.cc
+++ b/tests/cpp/test_function.cc
@@ -263,4 +263,10 @@ TEST(Func, FromExternC) {
   EXPECT_EQ(fadd1(1).cast<int>(), 2);
 }
 
+int invoke_testing_add1(int x) {
+  return Function::InvokeExternC(nullptr, __tvm_ffi_testing_add1, 
x).cast<int>();
+}
+
+TEST(Func, InvokeExternC) { EXPECT_EQ(invoke_testing_add1(1), 2); }
+
 }  // namespace

Reply via email to