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 c4ab46c7a6 [FFI] Use thread-safe packed function initialization
(#19939)
c4ab46c7a6 is described below
commit c4ab46c7a6f18c34503b86d5f19bd7ce4421ecef
Author: Tianqi Chen <[email protected]>
AuthorDate: Sun Jul 5 04:33:31 2026 +0800
[FFI] Use thread-safe packed function initialization (#19939)
Generated LLVM modules currently cache imported packed functions through
an unsynchronized null check and plain store. Concurrent first calls can
therefore race the lookup and cache update.
This change:
- routes generated C and LLVM lookups directly through
TVMFFIEnvModLookupFromImports and removes the superseded
TVMBackendGetFuncFromEnv wrapper;
- gives each LLVM cached function a readable internal hidden initializer
and publishes its module-owned result through TVMFFIHandleInitOnce;
- removes the unused TVMBackendRunOnce export and dead LLVM static-init
producer while preserving the live static-handle path.
Validated with the existing LLVM, C-host, common codegen, static-init,
and C++ test suites.
---
include/tvm/runtime/c_backend_api.h | 26 ------
src/runtime/device_api.cc | 12 ---
src/runtime/module.cc | 3 +-
src/target/llvm/codegen_cpu.cc | 165 ++++++++++++++++--------------------
src/target/llvm/codegen_cpu.h | 20 +++--
src/target/source/codegen_c_host.cc | 5 +-
6 files changed, 91 insertions(+), 140 deletions(-)
diff --git a/include/tvm/runtime/c_backend_api.h
b/include/tvm/runtime/c_backend_api.h
index 5a3bd4c216..07d1d305de 100644
--- a/include/tvm/runtime/c_backend_api.h
+++ b/include/tvm/runtime/c_backend_api.h
@@ -34,19 +34,6 @@
extern "C" {
#endif
-/*!
- * \brief Backend function for modules to get function
- * from its environment mod_node (its imports and global function).
- * The user do should not call TVMFuncFree on func.
- *
- * \param mod_node The module handle.
- * \param func_name The name of the function.
- * \param out The result function.
- * \return 0 when no error is thrown, -1 when failure happens
- */
-TVM_RUNTIME_DLL int TVMBackendGetFuncFromEnv(void* mod_node, const char*
func_name,
- TVMFFIObjectHandle* out);
-
/*!
* \brief Backend function to allocate temporal workspace.
*
@@ -116,19 +103,6 @@ TVM_RUNTIME_DLL int
TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* c
*/
TVM_RUNTIME_DLL int TVMBackendParallelBarrier(int task_id,
TVMParallelGroupEnv* penv);
-/*!
- * \brief Simple static initialization function.
- * Run f once and set handle to be not null.
- * This function is mainly used for test purpose.
- *
- * \param handle A global address to indicate f
- * \param f The function to be run
- * \param cdata The closure data to pass to the function.
- * \param nbytes Number of bytes in the closure data.
- * \return 0 when no error is thrown, -1 when failure happens
- */
-TVM_RUNTIME_DLL int TVMBackendRunOnce(void** handle, int (*f)(void*), void*
cdata, int nbytes);
-
#ifdef __cplusplus
} // TVM_EXTERN_C
#endif
diff --git a/src/runtime/device_api.cc b/src/runtime/device_api.cc
index 959cd619ab..e573b8fb4e 100644
--- a/src/runtime/device_api.cc
+++ b/src/runtime/device_api.cc
@@ -241,10 +241,6 @@ TVM_FFI_STATIC_INIT_BLOCK() {
using namespace tvm::runtime;
-int TVMBackendGetFuncFromEnv(void* mod_node, const char* func_name,
TVMFFIObjectHandle* func) {
- return TVMFFIEnvModLookupFromImports(mod_node, func_name, func);
-}
-
void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t size,
int dtype_code_hint,
int dtype_bits_hint) {
DLDevice dev;
@@ -266,11 +262,3 @@ int TVMBackendFreeWorkspace(int device_type, int
device_id, void* ptr) {
DeviceAPIManager::Get(dev)->FreeWorkspace(dev, ptr);
return 0;
}
-
-int TVMBackendRunOnce(void** handle, int (*f)(void*), void* cdata, int nbytes)
{
- if (*handle == nullptr) {
- *handle = reinterpret_cast<void*>(1);
- return (*f)(cdata);
- }
- return 0;
-}
diff --git a/src/runtime/module.cc b/src/runtime/module.cc
index b72607134d..7892f3eb4e 100644
--- a/src/runtime/module.cc
+++ b/src/runtime/module.cc
@@ -78,7 +78,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
// Initialize the functions
TVM_INIT_CONTEXT_FUNC(TVMFFIFunctionCall);
TVM_INIT_CONTEXT_FUNC(TVMFFIErrorSetRaisedFromCStr);
- TVM_INIT_CONTEXT_FUNC(TVMBackendGetFuncFromEnv);
+ TVM_INIT_CONTEXT_FUNC(TVMFFIEnvModLookupFromImports);
+ TVM_INIT_CONTEXT_FUNC(TVMFFIHandleInitOnce);
TVM_INIT_CONTEXT_FUNC(TVMBackendAllocWorkspace);
TVM_INIT_CONTEXT_FUNC(TVMBackendFreeWorkspace);
TVM_INIT_CONTEXT_FUNC(TVMBackendParallelLaunch);
diff --git a/src/target/llvm/codegen_cpu.cc b/src/target/llvm/codegen_cpu.cc
index a3e0f9030b..35689e4f9a 100644
--- a/src/target/llvm/codegen_cpu.cc
+++ b/src/target/llvm/codegen_cpu.cc
@@ -76,6 +76,7 @@ void CodeGenCPU::Init(const std::string& module_name,
LLVMTarget* llvm_target,
system_lib_prefix_ = system_lib_prefix;
dbg_info_ = CreateDebugInfo(module_.get());
func_handle_map_.clear();
+ func_handle_init_map_.clear();
export_system_symbols_.clear();
// Runtime types.
@@ -128,11 +129,20 @@ void CodeGenCPU::Init(const std::string& module_name,
LLVMTarget* llvm_target,
t_void_,
{llvmGetPointerTo(t_char_, 0),
llvmGetPointerTo(llvmGetPointerTo(t_char_, 0), 0), t_int_},
false);
- // Defined in include/tvm/runtime/c_backend_api.h:
- // int TVMBackendGetFuncFromEnv(void* mod_node, const char* func_name,
TVMFunctionHandle* out);
- ftype_tvm_get_func_from_env_ = llvm::FunctionType::get(
+ // Defined in include/tvm/ffi/extra/c_env_api.h:
+ // int TVMFFIEnvModLookupFromImports(TVMFFIObjectHandle library_ctx, const
char* func_name,
+ // TVMFFIObjectHandle* out);
+ ftype_tvm_ffi_env_mod_lookup_from_imports_ = llvm::FunctionType::get(
t_int_, {t_void_p_, llvmGetPointerTo(t_char_, 0),
llvmGetPointerTo(t_tvm_func_handle_, 0)},
false);
+ // Defined in include/tvm/ffi/c_api.h:
+ // int TVMFFIHandleInitOnce(void** handle_addr, int (*init_func)(void**
result));
+ ftype_tvm_ffi_handle_init_callback_ =
+ llvm::FunctionType::get(t_int_, {llvmGetPointerTo(t_void_p_, 0)}, false);
+ ftype_tvm_ffi_handle_init_once_ = llvm::FunctionType::get(
+ t_int_,
+ {llvmGetPointerTo(t_void_p_, 0),
llvmGetPointerTo(ftype_tvm_ffi_handle_init_callback_, 0)},
+ false);
// Defined in include/tvm/runtime/c_backend_api.h:
// int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int
num_task);
ftype_tvm_parallel_launch_ = llvm::FunctionType::get(
@@ -141,12 +151,6 @@ void CodeGenCPU::Init(const std::string& module_name,
LLVMTarget* llvm_target,
// int TVMBackendParallelBarrier(int task_id, TVMParallelGroupEnv* penv);
ftype_tvm_parallel_barrier_ = llvm::FunctionType::get(
t_int_, {t_int_, llvmGetPointerTo(t_tvm_parallel_group_env_, 0)}, false);
- ftype_tvm_static_init_callback_ = llvm::FunctionType::get(t_int_,
{t_void_p_}, false);
- ftype_tvm_static_init_ = llvm::FunctionType::get(
- t_int_,
- {llvmGetPointerTo(t_void_p_, 0),
llvmGetPointerTo(ftype_tvm_static_init_callback_, 0),
- t_void_p_, t_int_},
- false);
// initialize TVM runtime API
if (system_lib_prefix_.has_value() && !target_c_runtime) {
// We will need this in environment for backward registration.
@@ -168,9 +172,12 @@ void CodeGenCPU::Init(const std::string& module_name,
LLVMTarget* llvm_target,
f_tvm_ffi_set_raised_from_c_str_parts_ = llvm::Function::Create(
ftype_tvm_ffi_error_set_raised_from_c_str_parts_,
llvm::Function::ExternalLinkage,
"TVMFFIErrorSetRaisedFromCStrParts", module_.get());
- f_tvm_get_func_from_env_ =
- llvm::Function::Create(ftype_tvm_get_func_from_env_,
llvm::Function::ExternalLinkage,
- "TVMBackendGetFuncFromEnv", module_.get());
+ f_tvm_ffi_env_mod_lookup_from_imports_ = llvm::Function::Create(
+ ftype_tvm_ffi_env_mod_lookup_from_imports_,
llvm::Function::ExternalLinkage,
+ "TVMFFIEnvModLookupFromImports", module_.get());
+ f_tvm_ffi_handle_init_once_ =
+ llvm::Function::Create(ftype_tvm_ffi_handle_init_once_,
llvm::Function::ExternalLinkage,
+ "TVMFFIHandleInitOnce", module_.get());
f_tvm_parallel_launch_ =
llvm::Function::Create(ftype_tvm_parallel_launch_,
llvm::Function::ExternalLinkage,
"TVMBackendParallelLaunch", module_.get());
@@ -462,8 +469,11 @@ void CodeGenCPU::InitGlobalContext(bool dynamic_lookup) {
if (!dynamic_lookup) {
gv_tvm_ffi_func_call_ =
InitContextPtr(llvmGetPointerTo(ftype_tvm_ffi_func_call_, 0),
"__TVMFFIFunctionCall");
- gv_tvm_get_func_from_env_ =
InitContextPtr(llvmGetPointerTo(ftype_tvm_get_func_from_env_, 0),
- "__TVMBackendGetFuncFromEnv");
+ gv_tvm_ffi_env_mod_lookup_from_imports_ =
+
InitContextPtr(llvmGetPointerTo(ftype_tvm_ffi_env_mod_lookup_from_imports_, 0),
+ "__TVMFFIEnvModLookupFromImports");
+ gv_tvm_ffi_handle_init_once_ = InitContextPtr(
+ llvmGetPointerTo(ftype_tvm_ffi_handle_init_once_, 0),
"__TVMFFIHandleInitOnce");
gv_tvm_ffi_set_last_error_c_str_ =
InitContextPtr(llvmGetPointerTo(ftype_tvm_ffi_error_set_raised_by_c_str_, 0),
"__TVMFFIErrorSetRaisedFromCStr");
@@ -689,49 +699,40 @@ llvm::Value* CodeGenCPU::CreateStaticHandle() {
return gv;
}
-void CodeGenCPU::CreateStaticInit(const std::string& init_fname, const Stmt&
body) {
- // closure data
- llvm::Function* f =
- llvm::Function::Create(ftype_tvm_static_init_callback_,
llvm::Function::PrivateLinkage,
- "__tvm_static_init_lambda", module_.get());
- SetTargetAttributes(f);
- llvm::Value* gv = CreateStaticHandle();
- llvm::Function* finit = module_->getFunction(init_fname);
- if (finit == nullptr) {
- finit = llvm::Function::Create(ftype_tvm_static_init_,
llvm::Function::ExternalLinkage,
- init_fname, module_.get());
- }
- // allocate and setup the closure, call the closure.
- uint64_t nbytes;
- ffi::Array<Var> vfields = tirx::UndefinedVars(body, {});
- TypedPointer cdata = PackClosureData(vfields, &nbytes);
- llvm::BasicBlock* init_end = CheckCallSuccess(builder_->CreateCall(
- finit, {gv, f, builder_->CreatePointerCast(cdata.addr, t_void_p_),
ConstInt32(nbytes)}));
- // Setup the closure function.
- auto* lambda_entry = llvm::BasicBlock::Create(*llvm_target_->GetContext(),
"entry", f);
- builder_->SetInsertPoint(lambda_entry);
- auto it = f->arg_begin();
- cdata.addr = builder_->CreatePointerCast(&(*it++), cdata.addr->getType());
- // setup new variable map, swap it with current var context.
- std::unordered_map<const VarNode*, llvm::Value*> new_vmap;
- UnpackClosureData(cdata, vfields, &new_vmap);
- TVM_FFI_ICHECK(parallel_env_.penv == nullptr);
- auto new_analyzer = arith::Analyzer();
- std::swap(function_, f);
- std::swap(analyzer_, new_analyzer);
- std::swap(var_map_, new_vmap);
- this->VisitStmt(body);
- builder_->CreateRet(ConstInt32(0));
- // swap the var map back, now we are back on track.
- std::swap(var_map_, new_vmap);
- std::swap(analyzer_, new_analyzer);
- std::swap(function_, f);
- builder_->SetInsertPoint(init_end);
+llvm::Function* CodeGenCPU::CreatePackedFuncInit(const std::string& fname) {
+ // Generate the equivalent of:
+ //
+ // static int __tvm_func_handle_init.<fname>(void** result) {
+ // return TVMFFIEnvModLookupFromImports(__tvm_ffi__library_ctx,
"<fname>", result);
+ // }
+ //
+ // The lookup result is owned by the module and remains valid for the
generated module's lifetime.
+ llvm::IRBuilderBase::InsertPoint saved_ip = builder_->saveIP();
+ llvm::Function* saved_function = function_;
+ llvm::LLVMContext* ctx = llvm_target_->GetContext();
+ llvm::Function* init_func =
+ llvm::Function::Create(ftype_tvm_ffi_handle_init_callback_,
llvm::Function::InternalLinkage,
+ "__tvm_func_handle_init." + fname, module_.get());
+ init_func->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ SetTargetAttributes(init_func);
+ function_ = init_func;
+ builder_->SetInsertPoint(llvm::BasicBlock::Create(*ctx, "entry", init_func));
+
+ llvm::Value* result = &*init_func->arg_begin();
+ llvm::Value* module_ctx =
builder_->CreateAlignedLoad(gv_mod_ctx_->getValueType(), gv_mod_ctx_,
+
llvm::Align(gv_mod_ctx_->getAlignment()));
+ auto lookup_callee =
llvm::FunctionCallee(ftype_tvm_ffi_env_mod_lookup_from_imports_,
+
RuntimeTVMFFIEnvModLookupFromImports());
+ builder_->CreateRet(
+ builder_->CreateCall(lookup_callee, {module_ctx, GetConstString(fname),
result}));
+
+ function_ = saved_function;
+ builder_->restoreIP(saved_ip);
+ return init_func;
}
llvm::Value* CodeGenCPU::GetPackedFuncHandle(const std::string& fname) {
- // We will store the packed function handle in global space.
- // Initialize it during the first call.
+ // Cache the module-owned packed-function handle in global space with
thread-safe initialization.
#if TVM_LLVM_VERSION >= 200
llvm::DataLayout layout(module_.get()->getDataLayout());
#else
@@ -741,49 +742,25 @@ llvm::Value* CodeGenCPU::GetPackedFuncHandle(const
std::string& fname) {
auto it = func_handle_map_.find(fname);
llvm::GlobalVariable* hptr;
+ llvm::Function* init_func;
if (it == func_handle_map_.end()) {
- // create global location for the handle
- // create the function handle
hptr =
new llvm::GlobalVariable(*module_, t_tvm_func_handle_, false,
llvm::GlobalValue::InternalLinkage, nullptr,
".tvm_func." + fname);
hptr->setAlignment(llvm::Align(align));
hptr->setInitializer(llvm::Constant::getNullValue(t_tvm_func_handle_));
func_handle_map_[fname] = hptr;
+ init_func = CreatePackedFuncInit(fname);
+ func_handle_init_map_[fname] = init_func;
} else {
hptr = it->second;
+ init_func = func_handle_init_map_.at(fname);
}
- // create emit codes that checks and load the function.
- llvm::LLVMContext* ctx = llvm_target_->GetContext();
- llvm::BasicBlock* pre_block = builder_->GetInsertBlock();
- auto* init_block = llvm::BasicBlock::Create(*ctx, "handle_init", function_);
- auto* end_block = llvm::BasicBlock::Create(*ctx, "handle_init_end",
function_);
- llvm::Value* handle = builder_->CreateAlignedLoad(hptr->getValueType(),
hptr, llvm::Align(align));
- llvm::Value* handle_not_null =
- builder_->CreateICmpNE(handle,
llvm::Constant::getNullValue(t_tvm_func_handle_));
- builder_->CreateCondBr(handle_not_null, end_block, init_block,
md_very_likely_branch_);
- // Initialize the handle if needed.
- builder_->SetInsertPoint(init_block);
- llvm::Value* out =
- WithFunctionEntry([&]() { return
builder_->CreateAlloca(t_tvm_func_handle_); });
- llvm::LoadInst* ctx_load =
builder_->CreateAlignedLoad(gv_mod_ctx_->getValueType(), gv_mod_ctx_,
-
llvm::Align(gv_mod_ctx_->getAlignment()));
- ctx_load->setMetadata(
- "tbaa", md_builder_->createTBAAStructTagNode(md_tbaa_ctx_ptr_,
md_tbaa_ctx_ptr_, 0));
- auto env_callee = llvm::FunctionCallee(ftype_tvm_get_func_from_env_,
RuntimeTVMGetFuncFromEnv());
- llvm::Value* retcode = builder_->CreateCall(env_callee, {ctx_load,
GetConstString(fname), out});
- init_block = CheckCallSuccess(retcode);
- llvm::Value* loaded_handle =
- builder_->CreateAlignedLoad(t_tvm_func_handle_, out, llvm::Align(align));
- // Store the handle
- builder_->CreateStore(loaded_handle, hptr);
- builder_->CreateBr(end_block);
- // end block
- builder_->SetInsertPoint(end_block);
- llvm::PHINode* phi = builder_->CreatePHI(t_tvm_func_handle_, 2);
- phi->addIncoming(handle, pre_block);
- phi->addIncoming(loaded_handle, init_block);
- return phi;
+
+ auto init_once_callee =
+ llvm::FunctionCallee(ftype_tvm_ffi_handle_init_once_,
RuntimeTVMFFIHandleInitOnce());
+ CheckCallSuccess(builder_->CreateCall(init_once_callee, {hptr, init_func}));
+ return builder_->CreateAlignedLoad(hptr->getValueType(), hptr,
llvm::Align(align));
}
CodeGenCPU::PackedCall CodeGenCPU::MakeCallPackedLowered(const
ffi::Array<PrimExpr>& args,
@@ -899,10 +876,18 @@ llvm::Value* CodeGenCPU::RuntimeTVMFFIFunctionCall() {
return GetContextPtr(gv_tvm_ffi_func_call_);
}
-llvm::Value* CodeGenCPU::RuntimeTVMGetFuncFromEnv() {
- if (f_tvm_get_func_from_env_ != nullptr) return f_tvm_get_func_from_env_;
- return GetContextPtr(gv_tvm_get_func_from_env_);
+llvm::Value* CodeGenCPU::RuntimeTVMFFIEnvModLookupFromImports() {
+ if (f_tvm_ffi_env_mod_lookup_from_imports_ != nullptr) {
+ return f_tvm_ffi_env_mod_lookup_from_imports_;
+ }
+ return GetContextPtr(gv_tvm_ffi_env_mod_lookup_from_imports_);
+}
+
+llvm::Value* CodeGenCPU::RuntimeTVMFFIHandleInitOnce() {
+ if (f_tvm_ffi_handle_init_once_ != nullptr) return
f_tvm_ffi_handle_init_once_;
+ return GetContextPtr(gv_tvm_ffi_handle_init_once_);
}
+
llvm::Value* CodeGenCPU::RuntimeTVMFFIErrorSetRaisedFromCStr() {
if (f_tvm_ffi_set_raised_by_c_str_ != nullptr) return
f_tvm_ffi_set_raised_by_c_str_;
return GetContextPtr(gv_tvm_ffi_set_last_error_c_str_);
diff --git a/src/target/llvm/codegen_cpu.h b/src/target/llvm/codegen_cpu.h
index d090687b7e..d448d381e7 100644
--- a/src/target/llvm/codegen_cpu.h
+++ b/src/target/llvm/codegen_cpu.h
@@ -92,15 +92,14 @@ class CodeGenCPU : public CodeGenLLVM {
llvm::FunctionType* ftype_tvm_ffi_c_func_{nullptr};
llvm::FunctionType* ftype_tvm_parallel_lambda_{nullptr};
llvm::FunctionType* ftype_tvm_ffi_func_call_{nullptr};
- llvm::FunctionType* ftype_tvm_get_func_from_env_{nullptr};
+ llvm::FunctionType* ftype_tvm_ffi_env_mod_lookup_from_imports_{nullptr};
+ llvm::FunctionType* ftype_tvm_ffi_handle_init_callback_{nullptr};
+ llvm::FunctionType* ftype_tvm_ffi_handle_init_once_{nullptr};
llvm::FunctionType* ftype_tvm_ffi_error_set_raised_by_c_str_{nullptr};
llvm::FunctionType*
ftype_tvm_ffi_error_set_raised_from_c_str_parts_{nullptr};
llvm::FunctionType* ftype_tvm_parallel_launch_{nullptr};
llvm::FunctionType* ftype_tvm_parallel_barrier_{nullptr};
llvm::FunctionType* ftype_tvm_register_system_symbol_{nullptr};
- // Lazy entry for function call.
- llvm::FunctionType* ftype_tvm_static_init_callback_{nullptr};
- llvm::FunctionType* ftype_tvm_static_init_{nullptr};
private:
// the parallel group information
@@ -117,7 +116,8 @@ class CodeGenCPU : public CodeGenLLVM {
llvm::GlobalVariable* InitContextPtr(llvm::Type* type, std::string name);
llvm::Value* GetContextPtr(llvm::GlobalVariable* gv);
llvm::Value* RuntimeTVMFFIFunctionCall();
- llvm::Value* RuntimeTVMGetFuncFromEnv();
+ llvm::Value* RuntimeTVMFFIEnvModLookupFromImports();
+ llvm::Value* RuntimeTVMFFIHandleInitOnce();
llvm::Value* RuntimeTVMFFIErrorSetRaisedFromCStr();
llvm::Value* RuntimeTVMFFIErrorSetRaisedFromCStrParts();
// Create a temp function to simplify error raising.
@@ -125,6 +125,7 @@ class CodeGenCPU : public CodeGenLLVM {
llvm::Value* RuntimeTVMParallelLaunch();
llvm::Value* RuntimeTVMParallelBarrier();
llvm::Value* CreateStaticHandle();
+ llvm::Function* CreatePackedFuncInit(const std::string& fname);
llvm::Value* GetPackedFuncHandle(const std::string& str);
TypedPointer PackClosureData(const ffi::Array<Var>& fields, uint64_t*
num_bytes,
std::string struct_name = "");
@@ -143,8 +144,6 @@ class CodeGenCPU : public CodeGenLLVM {
llvm::Value* CreateCallPacked(const CallNode* op);
// Create trace call into tvm packed function.
llvm::Value* CreateCallTracePacked(const CallNode* op);
- // Create static initialization
- void CreateStaticInit(const std::string& init_fname, const Stmt& body);
// Create parallel launch
void CreateParallelLaunch(const Stmt& body, int num_task, std::string name =
"");
// Create a new compute scope.
@@ -161,14 +160,16 @@ class CodeGenCPU : public CodeGenLLVM {
// Context for injection lookup
llvm::GlobalVariable* gv_mod_ctx_{nullptr};
llvm::GlobalVariable* gv_tvm_ffi_func_call_{nullptr};
- llvm::GlobalVariable* gv_tvm_get_func_from_env_{nullptr};
+ llvm::GlobalVariable* gv_tvm_ffi_env_mod_lookup_from_imports_{nullptr};
+ llvm::GlobalVariable* gv_tvm_ffi_handle_init_once_{nullptr};
llvm::GlobalVariable* gv_tvm_ffi_set_last_error_c_str_{nullptr};
llvm::GlobalVariable* gv_tvm_parallel_launch_{nullptr};
llvm::GlobalVariable* gv_tvm_parallel_barrier_{nullptr};
std::unordered_map<ffi::String, llvm::GlobalVariable*> gv_func_map_;
// context for direct dynamic lookup
llvm::Function* f_tvm_ffi_func_call_{nullptr};
- llvm::Function* f_tvm_get_func_from_env_{nullptr};
+ llvm::Function* f_tvm_ffi_env_mod_lookup_from_imports_{nullptr};
+ llvm::Function* f_tvm_ffi_handle_init_once_{nullptr};
llvm::Function* f_tvm_ffi_set_raised_by_c_str_{nullptr};
llvm::Function* f_tvm_ffi_set_raised_from_c_str_parts_{nullptr};
llvm::Function* f_tvm_parallel_launch_{nullptr};
@@ -180,6 +181,7 @@ class CodeGenCPU : public CodeGenLLVM {
std::unordered_map<int, llvm::Function*> set_raised_helpers_;
// global to packed function handle
std::unordered_map<std::string, llvm::GlobalVariable*> func_handle_map_;
+ std::unordered_map<std::string, llvm::Function*> func_handle_init_map_;
// List of symbols to be exported to TVM system lib.
std::vector<std::pair<std::string, llvm::Constant*>> export_system_symbols_;
// List of functions to be registered in the FuncRegistry, if generated.
diff --git a/src/target/source/codegen_c_host.cc
b/src/target/source/codegen_c_host.cc
index c48e1b1e65..cd5e24ddf6 100644
--- a/src/target/source/codegen_c_host.cc
+++ b/src/target/source/codegen_c_host.cc
@@ -46,6 +46,7 @@ void CodeGenCHost::Init(bool output_ssa, bool emit_asserts,
bool emit_fwd_func_d
declared_globals_.clear();
decl_stream << "// tvm target: " << target_str << "\n";
decl_stream << "#define TVM_EXPORTS\n";
+ decl_stream << "#include \"tvm/ffi/extra/c_env_api.h\"\n";
decl_stream << "#include \"tvm/runtime/base.h\"\n";
decl_stream << "#include \"tvm/runtime/c_backend_api.h\"\n";
decl_stream << "#include \"tvm/ffi/c_api.h\"\n";
@@ -209,8 +210,8 @@ void CodeGenCHost::PrintGetFuncFromBackend(const
std::string& func_name,
this->stream << "if (" << packed_func_name << " == NULL) {\n";
int packed_func_if_scope = this->BeginScope();
this->PrintIndent();
- this->stream << "if (TVMBackendGetFuncFromEnv(" << module_name_ << ", \"" <<
func_name << "\""
- << ", &" << packed_func_name << ") != 0) {\n";
+ this->stream << "if (TVMFFIEnvModLookupFromImports(" << module_name_ << ",
\"" << func_name
+ << "\", &" << packed_func_name << ") != 0) {\n";
int get_func_env_scope = this->BeginScope();
this->PrintIndent();
this->stream << "return -1;\n";