Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BACKEND][CODEGEN] C codegen with tests #2161

Merged
merged 11 commits into from
Nov 28, 2018
60 changes: 60 additions & 0 deletions python/tvm/_ffi/libinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,66 @@ def find_lib_path(name=None, search_path=None, optional=False):
return lib_found


def find_include_path(name=None, search_path=None, optional=False):
"""Find header files for C compilation.

Parameters
----------
name : list of str
List of directory names to be searched.

Returns
-------
include_path : list(string)
List of all found paths to header files.
"""
ffi_dir = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
source_dir = os.path.join(ffi_dir, "..", "..", "..")
install_include_dir = os.path.join(ffi_dir, "..", "..", "..", "..")
third_party_dir = os.path.join(source_dir, "3rdparty")

header_path = []

if os.environ.get('TVM_INCLUDE_PATH', None):
header_path.append(os.environ['TVM_INCLUDE_PATH'])

header_path.append(install_include_dir)
header_path.append(source_dir)
header_path.append(third_party_dir)

header_path = [os.path.abspath(x) for x in header_path]
if search_path is not None:
if search_path is list:
header_path = header_path + search_path
else:
header_path.append(search_path)
if name is not None:
if isinstance(name, list):
tvm_include_path = []
for n in name:
tvm_include_path += [os.path.join(p, n) for p in header_path]
else:
tvm_include_path = [os.path.join(p, name) for p in header_path]
dlpack_include_path = []
else:
tvm_include_path = [os.path.join(p, 'include') for p in header_path]
dlpack_include_path = [os.path.join(p, 'dlpack/include') for p in header_path]

# try to find include path
include_found = [p for p in tvm_include_path if os.path.exists(p) and os.path.isdir(p)]
include_found += [p for p in dlpack_include_path if os.path.exists(p) and os.path.isdir(p)]

if not include_found:
message = ('Cannot find the files.\n' +
'List of candidates:\n' +
str('\n'.join(tvm_include_path + dlpack_include_path)))
if not optional:
raise RuntimeError(message)
return None

return include_found


# current version
# We use the version of the incoming release for code
# that is under development.
Expand Down
1 change: 1 addition & 0 deletions python/tvm/_ffi/runtime_ctypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class TVMContext(ctypes.Structure):
'llvm': 1,
'stackvm': 1,
'cpu': 1,
'c': 1,
'gpu': 2,
'cuda': 2,
'nvptx': 2,
Expand Down
2 changes: 2 additions & 0 deletions python/tvm/contrib/cc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from .._ffi.base import py_str
from .util import tempdir
from .._ffi.libinfo import find_include_path


def create_shared(output,
Expand Down Expand Up @@ -49,6 +50,7 @@ def _linux_shared(output, objects, options, cc="g++"):
cmd += objects
if options:
cmd += options
cmd += ["-I" + path for path in find_include_path()]
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
(out, _) = proc.communicate()
Expand Down
12 changes: 8 additions & 4 deletions python/tvm/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,21 @@ def export_library(self,
self.save(file_name)
return

if self.type_key != "llvm":
raise ValueError("Module[%s]: Only llvm support export shared" % self.type_key)
if not (self.type_key == "llvm" or self.type_key == "c"):
raise ValueError("Module[%s]: Only llvm and c support export shared" % self.type_key)
temp = _util.tempdir()
if fcompile is not None and hasattr(fcompile, "object_format"):
object_format = fcompile.object_format
else:
object_format = "o"
if self.type_key == "llvm":
object_format = "o"
else:
Mutinifni marked this conversation as resolved.
Show resolved Hide resolved
assert self.type_key == "c"
object_format = "cc"
path_obj = temp.relpath("lib." + object_format)
self.save(path_obj)
files = [path_obj]
is_system_lib = self.get_function("__tvm_is_system_module")()
is_system_lib = self.type_key == "llvm" and self.get_function("__tvm_is_system_module")()
if self.imported_modules:
path_cc = temp.relpath("devc.cc")
with open(path_cc, "w") as f:
Expand Down
44 changes: 39 additions & 5 deletions src/codegen/codegen_c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,43 @@ void CodeGenC::InitFuncState(LoweredFunc f) {
handle_data_type_.clear();
CodeGenSourceBase::ClearFuncState();
}
void CodeGenC::AddFunction(LoweredFunc f) {
// clear previous generated state.
this->InitFuncState(f);

void CodeGenC::ReserveKeywordsAsUnique() {
// skip the first underscore, so SSA variable starts from _1
GetUniqueName("_");
GetUniqueName("extern");
GetUniqueName("void");
GetUniqueName("int");
GetUniqueName("float");
GetUniqueName("double");
GetUniqueName("char");
GetUniqueName("unsigned");
GetUniqueName("short");
GetUniqueName("long");
GetUniqueName("if");
GetUniqueName("else");
GetUniqueName("switch");
GetUniqueName("case");
GetUniqueName("default");
GetUniqueName("for");
GetUniqueName("do");
GetUniqueName("while");
GetUniqueName("goto");
GetUniqueName("register");
GetUniqueName("continue");
GetUniqueName("break");
GetUniqueName("typedef");
GetUniqueName("struct");
GetUniqueName("enum");
GetUniqueName("union");
GetUniqueName("return");
}

void CodeGenC::AddFunction(LoweredFunc f) {
// clear previous generated state.
this->InitFuncState(f);
// reserve keywords
ReserveKeywordsAsUnique();
// add to alloc buffer type.
for (const auto & kv : f->handle_data_type) {
RegisterHandleType(kv.first.get(), kv.second.type());
Expand Down Expand Up @@ -187,6 +218,7 @@ std::string CodeGenC::GetStructRef(
case intrinsic::kArrNDim: os << "ndim"; break;
case intrinsic::kArrTypeCode: os << "dtype.code"; break;
case intrinsic::kArrTypeBits: os << "dtype.bits"; break;
case intrinsic::kArrByteOffset: os << "byte_offset"; break;
case intrinsic::kArrTypeLanes: os << "dtype.lanes"; break;
case intrinsic::kArrDeviceId: os << "ctx.device_id"; break;
case intrinsic::kArrDeviceType: os << "ctx.device_type"; break;
Expand Down Expand Up @@ -834,8 +866,10 @@ void CodeGenC::VisitStmt_(const Evaluate *op) {
}
}
std::string vid = this->PrintExpr(op->value);
this->PrintIndent();
this->stream << "(void)" << vid << ";\n";
if (vid != "") {
this->PrintIndent();
this->stream << "(void)" << vid << ";\n";
}
}

void CodeGenC::VisitStmt_(const ProducerConsumer *op) {
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/codegen_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ class CodeGenC :
std::unordered_map<const Variable*, std::string> alloc_storage_scope_;
/*! \brief the data type of allocated buffers */
std::unordered_map<const Variable*, Type> handle_data_type_;
/*! \brief reserves common C keywords */
void ReserveKeywordsAsUnique();
Mutinifni marked this conversation as resolved.
Show resolved Hide resolved

private:
/*! \brief whether to print in SSA form */
Expand Down
Loading