module 导出

module 导出#

参考:tvm/tests/python/runtime/test_runtime_module_export.py

from pathlib import Path

temp_dir = Path(".temp")
temp_dir.mkdir(exist_ok=True, parents=True)
import tvm
import tvm.testing

from tvm.contrib import utils

静态库加载#

from tvm import te

# Generate two LLVM modules.
A = te.placeholder((1024,), name="A")
B = te.compute(A.shape, lambda *i: A(*i) + 1.0, name="B")
irmod0 = tvm.IRModule.from_expr(
    te.create_prim_func([A, B]).with_attr("global_symbol", "myadd0")
)
irmod1 = tvm.IRModule.from_expr(
    te.create_prim_func([A, B]).with_attr("global_symbol", "myadd1")
)

mod0 = tvm.tir.build(irmod0, target="llvm")
mod1 = tvm.tir.build(irmod1, target="llvm")

assert mod0.implements_function("myadd0")
assert mod1.implements_function("myadd1")
assert mod1.is_dso_exportable

# mod1 is currently an 'llvm' module.
# Save and reload it as a vanilla 'static_library'.
temp = utils.tempdir()
mod1_o_path = temp.relpath("mod1.o")
mod1.save(mod1_o_path)
mod1_o = tvm.runtime.load_static_library(mod1_o_path, ["myadd1"])
assert mod1_o.implements_function("myadd1")
assert mod1_o.is_dso_exportable

# Import mod1 as a static library into mod0 and compile to its own DSO.
mod0.import_module(mod1_o)
mod0_dso_path = temp.relpath("mod0.so")
mod0.export_library(mod0_dso_path)

# The imported mod1 is statically linked into mod0.
loaded_lib = tvm.runtime.load_module(mod0_dso_path)
assert loaded_lib.type_key == "library"
assert len(loaded_lib.imported_modules) == 0
assert loaded_lib.implements_function("myadd0")
assert loaded_lib.get_function("myadd0")
assert loaded_lib.implements_function("myadd1")
assert loaded_lib.get_function("myadd1")
assert not loaded_lib.is_dso_exportable

CSourceModuleCreate#

/*!
 * \brief Create a C source module for viewing and compiling GCC code.
 * \param code The code to be viewed.
 * \param fmt The code format.
 * \param func_names The name of functions inside the runtime module.
 * \param const_vars. The constant variables that the c source module needs.
 * \return The created module.
 */
runtime::Module CSourceModuleCreate(const String& code, const String& fmt,
                                    const Array<String>& func_names,
                                    const Array<String>& const_vars = {});
CSourceModuleCreate 用于创建 C 源代码模块,以便查看和编译 GCC 代码。

参数说明:

  1. const String& code

    • 这是字符串类型的参数,表示需要被查看和编译的 GCC 代码。

    • const 表示这个参数在函数内部不会被修改。

    • String& 表示这是字符串的引用,避免了不必要的拷贝。

  2. const String& fmt

    • 这是字符串类型的参数,表示代码的格式。

    • 可能用于指定代码的格式化方式(如缩进、换行等),或者用于指定代码的语言类型(如 C、C++ 等)。

  3. const Array<String>& func_names

    • 这是字符串数组类型的参数,表示运行时模块中函数的名称。

    • Array<String> 可能是自定义的数组类型,用于存储多个字符串。

    • 这些函数名称可能是需要在生成的 C 源代码模块中导出的函数。

  4. const Array<String>& const_vars = {}

    • 这是可选的字符串数组类型的参数,表示C源代码模块中需要的常量变量。

    • = {} 表示这个参数有默认值,即空数组。如果调用函数时不提供这个参数,函数会使用空数组作为默认值。

返回值:

  • runtime::Module

    • 这是函数的返回值类型,表示创建的 C 源代码模块。

    • runtime::Module 可能是自定义的类或结构体,用于表示运行时模块。

函数功能:

  • 该函数的主要功能是创建 C 源代码模块,该模块可以用于查看和编译 GCC 代码。

  • 生成的模块可能包含指定的函数名称和常量变量,并且可以根据提供的代码格式进行格式化。

使用场景

  • 这个函数可能用于编译器或代码生成工具中,用于将高级语言代码(如 GCC 代码)转换为 C 源代码模块,以便进一步编译或执行。

  • 通过指定函数名称和常量变量,可以定制生成的C源代码模块的内容。

示例调用

import tvm
code = r"int main() { return 0; }";
fmt = "c"
func_names = ["main"]
const_vars = ["MAX_VALUE"]
csource_module = tvm.runtime._ffi_api.CSourceModuleCreate(code, fmt, func_names, const_vars)
csource_module
runtime.Module(0x55cb0c06b9f8)

下面介绍更加复杂的例子。

先定义一些头文件。

Hide code cell content

import textwrap
def gen_engine_header(header_file_dir_path):
    code = r"""
        #ifndef _ENGINE_H_
        #define _ENGINE_H_
        #include <cstdint>
        #include <string>
        #include <sstream>
        #include <vector>
        class Engine {
        };

        #endif
        """
    header_file_dir_path = Path(header_file_dir_path)
    header_file = header_file_dir_path/"gcc_engine.h"
    code = textwrap.dedent(code).lstrip()
    with open(header_file, "w") as f:
        f.write(code)

def generate_engine_module(header_file_dir_path):
    code = r"""
        #include <tvm/runtime/c_runtime_api.h>
        #include <dlpack/dlpack.h>
        #include "gcc_engine.h"

        extern "C" void gcc_1_(float* gcc_input4, float* gcc_input5,
                float* gcc_input6, float* gcc_input7, float* out) {
            Engine engine;
        }
        """
    import tvm.runtime._ffi_api

    gen_engine_header(header_file_dir_path)
    code = textwrap.dedent(code).lstrip()
    csource_module = tvm.runtime._ffi_api.CSourceModuleCreate(code, "cc", [], None)
    return csource_module