Skip to content

Commit 72fcd4e

Browse files
authored
[RUNTIME] Add System Lib (#227)
* [RUNTIME] Add System Lib * lint * lint * fix compile
1 parent b759d0f commit 72fcd4e

25 files changed

+397
-122
lines changed

include/tvm/codegen.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ runtime::Module Build(const Array<LoweredFunc>& funcs,
3838
* the dependency from the shared library.
3939
*
4040
* \param m The host module with the imports.
41+
* \param system_lib Whether expose as system library.
4142
* \return cstr The C string representation of the file.
4243
*/
43-
std::string PackImportsToC(const runtime::Module& m);
44+
std::string PackImportsToC(const runtime::Module& m, bool system_lib);
4445
} // namespace codegen
4546
} // namespace tvm
4647

include/tvm/runtime/c_runtime_api.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,17 @@ TVM_DLL int TVMFuncListGlobalNames(int *out_size,
350350
TVM_DLL int TVMBackendGetFuncFromEnv(void* mod_node,
351351
const char* func_name,
352352
TVMFunctionHandle *out);
353+
/*!
354+
* \brief Backend function to register system-wide library symbol.
355+
*
356+
* \note This API is supposed to be used by backend,
357+
* it is not supposed to be used by user.
358+
*
359+
* \param name The name of the symbol
360+
* \param ptr The symbol address.
361+
* \return 0 when no error is thrown, -1 when failure happens
362+
*/
363+
TVM_DLL int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr);
353364

354365
/*!
355366
* \brief Backend function for running parallel for loop.

include/tvm/runtime/registry.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class Registry {
9494
#define TVM_STR_CONCAT(__x, __y) TVM_STR_CONCAT_(__x, __y)
9595

9696
#define TVM_FUNC_REG_VAR_DEF \
97-
static TVM_ATTRIBUTE_UNUSED ::tvm::runtime::Registry& __make_ ## TVMOp
97+
static TVM_ATTRIBUTE_UNUSED ::tvm::runtime::Registry& __mk_ ## TVM
9898

9999
/*!
100100
* \brief Register a function globally.

python/tvm/build.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,23 +223,31 @@ def build(sch,
223223
The target and option of the compilation.
224224
When the target is llvm, you can set options like:
225225
226-
* **-mtriple=<target triple>** or **-target**
226+
- **-mtriple=<target triple>** or **-target**
227227
228228
Specify the target triple, which is useful for cross
229229
compilation.
230230
231-
* **-mcpu=<cpuname>**
231+
- **-mcpu=<cpuname>**
232232
233233
Specify a specific chip in the current architecture to
234234
generate code for. By default this is infered from the
235235
target triple and autodetected to the current architecture.
236236
237-
* **-mattr=a1,+a2,-a3,...**
237+
- **-mattr=a1,+a2,-a3,...**
238238
239239
Override or control specific attributes of the target,
240240
such as whether SIMD operations are enabled or not. The
241241
default set of attributes is set by the current CPU.
242242
243+
- **-system-lib**
244+
245+
Build TVM system library module. System lib is a global module that contains
246+
self registered functions in program startup. User can get the module using
247+
:any:`tvm.module.system_lib`.
248+
It is useful in environments where dynamic loading api like dlopen is banned.
249+
The system lib will be available as long as the result code is linked by the program.
250+
243251
target_host : str, optional
244252
Host compilation target, if target is device.
245253
When TVM compiles device specific program such as CUDA,

python/tvm/contrib/cc_compiler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def create_shared(output,
2525
The compile string.
2626
"""
2727
cmd = [cc]
28-
cmd += ["-shared"]
28+
cmd += ["-shared", "-fPIC"]
2929

3030
if sys.platform == "darwin":
3131
cmd += ["-undefined", "dynamic_lookup"]

python/tvm/module.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,26 @@ def export_library(self, file_name):
7171
file_name : str
7272
The name of the shared library.
7373
"""
74+
if self.type_key == "stacktvm":
75+
raise ValueError("Module[%s]: export_library requires llvm module,"
76+
" did you build with LLVM enabled?" % self.type_key)
77+
7478
if self.type_key != "llvm":
7579
raise ValueError("Module[%s]: Only llvm support export shared" % self.type_key)
7680
temp = _util.tempdir()
7781
path_obj = temp.relpath("lib.o")
7882
self.save(path_obj)
7983
files = [path_obj]
84+
try:
85+
self.get_function("__tvm_module_startup")
86+
is_system_lib = True
87+
except AttributeError:
88+
is_system_lib = False
89+
8090
if self.imported_modules:
8191
path_cc = temp.relpath("devc.cc")
8292
with open(path_cc, "w") as f:
83-
f.write(_PackImportsToC(self))
93+
f.write(_PackImportsToC(self, is_system_lib))
8494
files.append(path_cc)
8595
_cc.create_shared(file_name, files)
8696

@@ -116,6 +126,27 @@ def time_evaluator(self, func_name, ctx, number):
116126
raise NameError("time_evaluate is only supported when RPC is enabled")
117127

118128

129+
def system_lib():
130+
"""Get system-wide library module singleton.
131+
132+
System lib is a global module that contains self register functions in startup.
133+
Unlike normal dso modules which need to be loaded explicitly.
134+
It is useful in environments where dynamic loading api like dlopen is banned.
135+
136+
To build system lib function, simply specify target option ```llvm --system-lib```
137+
The system lib will be available as long as the result code is linked by the program.
138+
139+
The system lib is intended to be linked and loaded during the entire life-cyle of the program.
140+
If you want dynamic loading features, use dso modules instead.
141+
142+
Returns
143+
-------
144+
module : Module
145+
The system-wide library module.
146+
"""
147+
return _GetSystemLib()
148+
149+
119150
def load(path, fmt=""):
120151
"""Load module from file
121152

src/api/api_codegen.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ TVM_REGISTER_API("codegen._Build")
2323

2424
TVM_REGISTER_API("module._PackImportsToC")
2525
.set_body([](TVMArgs args, TVMRetValue *ret) {
26-
*ret = PackImportsToC(args[0]);
26+
*ret = PackImportsToC(args[0], args[1]);
2727
});
2828
} // namespace codegen
2929
} // namespace tvm

src/codegen/codegen.cc

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ runtime::Module Build(const Array<LoweredFunc>& funcs,
3535
return m;
3636
}
3737

38-
std::string PackImportsToC(const runtime::Module& mod) {
38+
std::string PackImportsToC(const runtime::Module& mod, bool system_lib) {
3939
std::string bin;
4040
dmlc::MemoryStringStream ms(&bin);
4141
dmlc::Stream* stream = &ms;
@@ -55,29 +55,39 @@ std::string PackImportsToC(const runtime::Module& mod) {
5555
<< "extern \"C\" {\n"
5656
<< "#endif\n";
5757
os << "extern const char " << runtime::symbol::tvm_dev_mblob << "[];\n";
58-
os << "extern const unsigned long " << runtime::symbol::tvm_dev_mblob_nbytes << ";\n";
58+
uint64_t nbytes = bin.length();
5959
os << "const char " << runtime::symbol::tvm_dev_mblob
60-
<< "[" << bin.length() << "] = {\n ";
60+
<< "[" << bin.length() + sizeof(nbytes) << "] = {\n ";
6161
os << std::hex;
6262
size_t nunit = 80 / 4;
63-
for (size_t i = 0; i < bin.length(); ++i) {
63+
for (size_t i = 0; i < sizeof(nbytes); ++i) {
6464
// sperators
6565
if (i != 0) {
66-
if (i % nunit == 0) {
67-
os << ",\n ";
68-
} else {
69-
os << ",";
70-
}
66+
os << ",";
67+
}
68+
os << "0x" << ((nbytes >> (i * 8)) & 0xffUL);
69+
}
70+
for (size_t i = 0; i < bin.length(); ++i) {
71+
// sperators
72+
if ((i + sizeof(nbytes)) % nunit == 0) {
73+
os << ",\n ";
74+
} else {
75+
os << ",";
7176
}
7277
int c = bin[i];
7378
os << "0x" << (c & 0xff);
7479
}
75-
os << "\n};\n"
76-
<< "const unsigned long " << runtime::symbol::tvm_dev_mblob_nbytes
77-
<< " = " << std::dec << bin.length() << "UL;\n"
78-
<< "#ifdef __cplusplus\n"
80+
os << "\n};\n";
81+
if (system_lib) {
82+
os << "extern int TVMBackendRegisterSystemLibSymbol(const char*, void*);\n";
83+
os << "static int " << runtime::symbol::tvm_dev_mblob << "_reg_ = "
84+
<< "TVMBackendRegisterSystemLibSymbol(\"" << runtime::symbol::tvm_dev_mblob << "\", (void*)"
85+
<< runtime::symbol::tvm_dev_mblob << ");\n";
86+
}
87+
os << "#ifdef __cplusplus\n"
7988
<< "}\n"
8089
<< "#endif\n";
90+
8191
return os.str();
8292
}
8393
} // namespace codegen

src/codegen/llvm/codegen_llvm.cc

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ std::unique_ptr<CodeGenLLVM> CodeGenLLVM::Create(llvm::TargetMachine *tm) {
2828

2929
void CodeGenLLVM::Init(const std::string& module_name,
3030
llvm::TargetMachine* tm,
31-
llvm::LLVMContext* ctx) {
31+
llvm::LLVMContext* ctx,
32+
bool system_lib) {
3233
InitializeLLVM();
3334
static_assert(sizeof(TVMValue) == sizeof(double), "invariant");
3435
// static_assert(alignof(TVMValue) == alignof(double), "invariant");
3536
// clear maps
3637
var_map_.clear();
3738
str_map_.clear();
3839
func_handle_map_.clear();
40+
export_system_symbols_.clear();
3941
// initialize types.
4042
if (ctx_ != ctx) {
4143
t_void_ = llvm::Type::getVoidTy(*ctx);
@@ -96,6 +98,13 @@ void CodeGenLLVM::Init(const std::string& module_name,
9698
t_int64_, t_int64_, t_f_tvm_par_for_lambda_->getPointerTo(), t_void_p_}
9799
, false),
98100
llvm::Function::ExternalLinkage, "TVMBackendParallelFor", module_.get());
101+
if (system_lib) {
102+
f_tvm_register_system_symbol_ = llvm::Function::Create(
103+
llvm::FunctionType::get(t_int_, {t_char_->getPointerTo(), t_void_p_}, false),
104+
llvm::Function::ExternalLinkage, "TVMBackendRegisterSystemLibSymbol", module_.get());
105+
} else {
106+
f_tvm_register_system_symbol_ = nullptr;
107+
}
99108
this->InitTarget(tm);
100109
// initialize builder
101110
builder_.reset(new IRBuilder(*ctx));
@@ -125,9 +134,15 @@ void CodeGenLLVM::InitTarget(llvm::TargetMachine* tm) {
125134
void CodeGenLLVM::InitGlobalContext() {
126135
gv_mod_ctx_ = new llvm::GlobalVariable(
127136
*module_, t_void_p_, false,
128-
llvm::GlobalValue::LinkOnceAnyLinkage, 0, "__tvm_module_ctx");
137+
llvm::GlobalValue::LinkOnceAnyLinkage, 0,
138+
tvm::runtime::symbol::tvm_module_ctx);
129139
gv_mod_ctx_->setAlignment(data_layout_->getTypeAllocSize(t_void_p_));
130140
gv_mod_ctx_->setInitializer(llvm::Constant::getNullValue(t_void_p_));
141+
142+
if (f_tvm_register_system_symbol_ != nullptr) {
143+
export_system_symbols_.emplace_back(
144+
std::make_pair(tvm::runtime::symbol::tvm_module_ctx, gv_mod_ctx_));
145+
}
131146
}
132147

133148
void CodeGenLLVM::InitFuncState() {
@@ -171,6 +186,11 @@ void CodeGenLLVM::AddFunction(const LoweredFunc& f) {
171186
builder_->SetInsertPoint(block);
172187
this->VisitStmt(f->body);
173188
builder_->CreateRet(ConstInt32(0));
189+
190+
if (f_tvm_register_system_symbol_ != nullptr) {
191+
export_system_symbols_.emplace_back(
192+
std::make_pair(f->name, builder_->CreatePointerCast(function_, t_void_p_)));
193+
}
174194
}
175195

176196
void CodeGenLLVM::AddMainFunction(const std::string& entry_func_name) {
@@ -225,13 +245,35 @@ void CodeGenLLVM::Optimize() {
225245
}
226246

227247
std::unique_ptr<llvm::Module> CodeGenLLVM::Finish() {
248+
this->AddStartupFunction();
228249
this->Optimize();
229250
var_map_.clear();
230251
str_map_.clear();
231252
func_handle_map_.clear();
253+
export_system_symbols_.clear();
232254
return std::move(module_);
233255
}
234256

257+
void CodeGenLLVM::AddStartupFunction() {
258+
if (export_system_symbols_.size() != 0) {
259+
llvm::FunctionType* ftype = llvm::FunctionType::get(t_void_, {}, false);
260+
function_ = llvm::Function::Create(
261+
ftype,
262+
llvm::Function::InternalLinkage,
263+
"__tvm_module_startup", module_.get());
264+
llvm::BasicBlock* startup_entry = llvm::BasicBlock::Create(*ctx_, "entry", function_);
265+
builder_->SetInsertPoint(startup_entry);
266+
for (const auto& kv : export_system_symbols_) {
267+
llvm::Value* name = GetConstString(kv.first);
268+
builder_->CreateCall(
269+
f_tvm_register_system_symbol_, {
270+
name, builder_->CreateBitCast(kv.second, t_void_p_)});
271+
}
272+
llvm::appendToGlobalCtors(*module_, function_, 65535);
273+
builder_->CreateRet(nullptr);
274+
}
275+
}
276+
235277
llvm::Type* CodeGenLLVM::LLVMType(const Type& t) const {
236278
llvm::Type* ret = nullptr;
237279
if (t.is_uint() || t.is_int()) {

src/codegen/llvm/codegen_llvm.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <tvm/codegen.h>
1313
#include <tvm/arithmetic.h>
1414
#include <memory>
15+
#include <utility>
1516
#include <vector>
1617
#include <string>
1718
#include "./llvm_common.h"
@@ -39,10 +40,12 @@ class CodeGenLLVM :
3940
* \param module_name The name of the module.
4041
* \param tm Target machine model
4142
* \param ctx The context.
43+
* \param system_lib Whether to insert system library registration.
4244
*/
4345
void Init(const std::string& module_name,
4446
llvm::TargetMachine* tm,
45-
llvm::LLVMContext* ctx);
47+
llvm::LLVMContext* ctx,
48+
bool system_lib);
4649
/*!
4750
* \brief Compile and add function f to the current module.
4851
* \param f The function to be added.
@@ -163,7 +166,7 @@ class CodeGenLLVM :
163166
llvm::LLVMContext* ctx_{nullptr};
164167
// helpful data types
165168
llvm::Type* t_void_{nullptr};
166-
llvm::Type* t_void_p_{nullptr};
169+
llvm::PointerType* t_void_p_{nullptr};
167170
llvm::Type* t_int_{nullptr};
168171
llvm::Type* t_char_{nullptr};
169172
llvm::Type* t_int8_{nullptr};
@@ -188,6 +191,7 @@ class CodeGenLLVM :
188191
llvm::Function* f_tvm_get_func_from_env_{nullptr};
189192
llvm::Function* f_tvm_api_set_last_error_{nullptr};
190193
llvm::Function* f_tvm_parallel_for_{nullptr};
194+
llvm::Function* f_tvm_register_system_symbol_{nullptr};
191195
// The acting body
192196
llvm::BasicBlock* block_{nullptr};
193197
/*! \brief native vector bits of current targetx*/
@@ -227,6 +231,8 @@ class CodeGenLLVM :
227231
llvm::BasicBlock* CheckCallSuccess(llvm::Value* retcode);
228232
// Add a function to set global module context
229233
void InitGlobalContext();
234+
// Add module startup function if needed.
235+
void AddStartupFunction();
230236
// add alias information.
231237
void AddAliasInfo(llvm::Instruction* load, const Variable* buffer, Expr index, Type type);
232238
// The definition of local variable.
@@ -243,6 +249,8 @@ class CodeGenLLVM :
243249
llvm::GlobalVariable* gv_mod_ctx_{nullptr};
244250
// global to packed function handle
245251
std::unordered_map<std::string, llvm::GlobalVariable*> func_handle_map_;
252+
// List of symbols to be exported to TVM system lib.
253+
std::vector<std::pair<std::string, llvm::Value*> > export_system_symbols_;
246254
};
247255
} // namespace codegen
248256
} // namespace tvm

0 commit comments

Comments
 (0)