From d6301d665416b6c24c9ac9181051fd883a1bf446 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Sat, 8 Feb 2020 20:43:18 +0000 Subject: [PATCH 01/10] Use dummy func when no lowered_funcs exists in Relay mod --- src/relay/backend/build_module.cc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index ff64d4a3acbb..4af23e2b2171 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "utils.h" @@ -37,6 +38,9 @@ namespace relay { namespace backend { using tir::LoweredFunc; +using tir::Stmt; +using tir::MakeAPI; +using tir::EvaluateNode; using TargetsMap = Map; using namespace tvm::relay::transform; @@ -438,13 +442,19 @@ class RelayBuildModule : public runtime::ModuleNode { auto lowered_funcs = graph_codegen_->GetLoweredFunc(); if (lowered_funcs.size() == 0) { - LOG(WARNING) << "no lowered funcs exist in the compiled module"; - } else { - ret_.mod = tvm::build( - lowered_funcs, - target_host_, - BuildConfig::Current()); + LOG(WARNING) << "No lowered funcs exist in the compiled module, " + << "a dummy function \"__dummy__\" will be created."; + Stmt body = EvaluateNode::make(0); + Array api_args; + auto dummy_func = MakeAPI(body, "__dummy__", api_args, 0, false); + lowered_funcs.Set("llvm", Array({dummy_func})); } + + ret_.mod = tvm::build( + lowered_funcs, + target_host_, + BuildConfig::Current()); + Array ext_mods = graph_codegen_->GetExternalModules(); if (!ext_mods.empty()) { CHECK(lowered_funcs.size() > 0 || ext_mods.size() == 1) From adbe5a27cc42a16556fb1317b05603414dec1221 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Tue, 11 Feb 2020 21:46:13 +0000 Subject: [PATCH 02/10] Dummy func -> CSourceModule with empty code str --- src/relay/backend/build_module.cc | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index 4af23e2b2171..79ef6fde8282 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -28,9 +28,9 @@ #include #include #include -#include #include +#include "../../target/source/codegen_source_base.h" #include "utils.h" namespace tvm { @@ -38,9 +38,6 @@ namespace relay { namespace backend { using tir::LoweredFunc; -using tir::Stmt; -using tir::MakeAPI; -using tir::EvaluateNode; using TargetsMap = Map; using namespace tvm::relay::transform; @@ -442,19 +439,14 @@ class RelayBuildModule : public runtime::ModuleNode { auto lowered_funcs = graph_codegen_->GetLoweredFunc(); if (lowered_funcs.size() == 0) { - LOG(WARNING) << "No lowered funcs exist in the compiled module, " - << "a dummy function \"__dummy__\" will be created."; - Stmt body = EvaluateNode::make(0); - Array api_args; - auto dummy_func = MakeAPI(body, "__dummy__", api_args, 0, false); - lowered_funcs.Set("llvm", Array({dummy_func})); + ret_.mod = tvm::codegen::CSourceModuleCreate("", ""); + } else { + ret_.mod = tvm::build( + lowered_funcs, + target_host_, + BuildConfig::Current()); } - ret_.mod = tvm::build( - lowered_funcs, - target_host_, - BuildConfig::Current()); - Array ext_mods = graph_codegen_->GetExternalModules(); if (!ext_mods.empty()) { CHECK(lowered_funcs.size() > 0 || ext_mods.size() == 1) From ca6e419e0bd35a72b89bce3c9d9075fc75f48df5 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Tue, 11 Feb 2020 22:05:27 +0000 Subject: [PATCH 03/10] Added comments describing the empty CSouceModule --- src/relay/backend/build_module.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index 79ef6fde8282..9c7d553f2aa9 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -439,6 +439,8 @@ class RelayBuildModule : public runtime::ModuleNode { auto lowered_funcs = graph_codegen_->GetLoweredFunc(); if (lowered_funcs.size() == 0) { + // When there is no lowered_funcs generated, due to reasons such as optimization, + // a module with empty code content will be generated. ret_.mod = tvm::codegen::CSourceModuleCreate("", ""); } else { ret_.mod = tvm::build( From cbaa76c6cfde8842c9c7b6da0da637a9407a3017 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Wed, 12 Feb 2020 22:36:59 +0000 Subject: [PATCH 04/10] Always import external modules w/o assertions --- src/relay/backend/build_module.cc | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index 9c7d553f2aa9..90a1b4c80938 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -450,19 +450,9 @@ class RelayBuildModule : public runtime::ModuleNode { } Array ext_mods = graph_codegen_->GetExternalModules(); - if (!ext_mods.empty()) { - CHECK(lowered_funcs.size() > 0 || ext_mods.size() == 1) - << "Expect to have a TVM DSOModule when multiple external runtime modules exist"; - if (lowered_funcs.size() == 0) { - // Execute the whole module using external runtime. - ret_.mod = ext_mods[0]; - } else { - // Import all external runtime modules. - for (const auto& it : ext_mods) { - ret_.mod.Import(it); - } - } - } + // Import all external runtime modules. + for (const auto& it : ext_mods) + ret_.mod.Import(it); } protected: From 3e83a11352dfca0daeb0ad54293e60cfc2627214 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Thu, 13 Feb 2020 22:32:14 +0000 Subject: [PATCH 05/10] Use CSourceModule as a fallback for LLVMModule --- src/relay/backend/build_module.cc | 38 ++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index 90a1b4c80938..b545402b77e0 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../target/source/codegen_source_base.h" @@ -38,6 +39,8 @@ namespace relay { namespace backend { using tir::LoweredFunc; +using tir::MakeAPI; +using tir::EvaluateNode; using TargetsMap = Map; using namespace tvm::relay::transform; @@ -438,10 +441,39 @@ class RelayBuildModule : public runtime::ModuleNode { ret_.params = graph_codegen_->GetParams(); auto lowered_funcs = graph_codegen_->GetLoweredFunc(); + + // When there is no lowered_funcs due to reasons such as optimization, + // we first try to generate a dummy one if the target host is "llvm". + if (lowered_funcs.size() == 0) { + // Decide first the target host + Target target_host_val = target_host_; + if (!target_host_.defined()) { + for (const auto &it: targets_) { + if (it.second->device_type == kDLCPU) { + target_host_val = it.second; + break; + } + } + } + + // If no target_host has been set, we choose a default one, which is + // llvm if "codegen.build_llvm" is accessible. + const runtime::PackedFunc* pf = runtime::Registry::Get("codegen.build_llvm"); + if (!target_host_val.defined()) + target_host_val = (pf != nullptr) ? target::llvm() : target::stackvm(); + + if (target_host_val.defined() && target_host_val->str() == "llvm") + lowered_funcs.Set( + target_host_val->str(), + Array({ + MakeAPI(EvaluateNode::make(0), "__dummy__", Array(), 0, false) })); + } + if (lowered_funcs.size() == 0) { - // When there is no lowered_funcs generated, due to reasons such as optimization, - // a module with empty code content will be generated. - ret_.mod = tvm::codegen::CSourceModuleCreate("", ""); + // If there is still no lowered_funcs, a fallback solution is to create a module + // with empty code content. + // The code content is initialized with ";" to prevent complaining from CSourceModuleNode::SaveToFile. + ret_.mod = tvm::codegen::CSourceModuleCreate(";", ""); } else { ret_.mod = tvm::build( lowered_funcs, From a4f0d969076ba2af2b4d3713d73798e81c059cf6 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Fri, 14 Feb 2020 17:06:13 +0000 Subject: [PATCH 06/10] Changed cond for target == llvm --- src/relay/backend/build_module.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index b545402b77e0..c35bea87486f 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include "../../target/source/codegen_source_base.h" @@ -445,10 +445,10 @@ class RelayBuildModule : public runtime::ModuleNode { // When there is no lowered_funcs due to reasons such as optimization, // we first try to generate a dummy one if the target host is "llvm". if (lowered_funcs.size() == 0) { - // Decide first the target host + // Decide first the target host Target target_host_val = target_host_; if (!target_host_.defined()) { - for (const auto &it: targets_) { + for (const auto &it : targets_) { if (it.second->device_type == kDLCPU) { target_host_val = it.second; break; @@ -462,17 +462,18 @@ class RelayBuildModule : public runtime::ModuleNode { if (!target_host_val.defined()) target_host_val = (pf != nullptr) ? target::llvm() : target::stackvm(); - if (target_host_val.defined() && target_host_val->str() == "llvm") + if (target_host_val.defined() && target_host_val->target_name == "llvm") lowered_funcs.Set( target_host_val->str(), Array({ MakeAPI(EvaluateNode::make(0), "__dummy__", Array(), 0, false) })); } - + if (lowered_funcs.size() == 0) { // If there is still no lowered_funcs, a fallback solution is to create a module // with empty code content. - // The code content is initialized with ";" to prevent complaining from CSourceModuleNode::SaveToFile. + // The code content is initialized with ";" to prevent complaining + // from CSourceModuleNode::SaveToFile. ret_.mod = tvm::codegen::CSourceModuleCreate(";", ""); } else { ret_.mod = tvm::build( From 9441c52597ac806e325e0802c4a35baac3d0a648 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Fri, 28 Feb 2020 21:37:54 +0000 Subject: [PATCH 07/10] Create an empty LLVM module w/o using dummy func --- src/relay/backend/build_module.cc | 62 +++++++++++++++---------------- src/target/llvm/llvm_module.cc | 34 +++++++++++++++++ 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index c35bea87486f..624ad17b7fd2 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -39,8 +39,6 @@ namespace relay { namespace backend { using tir::LoweredFunc; -using tir::MakeAPI; -using tir::EvaluateNode; using TargetsMap = Map; using namespace tvm::relay::transform; @@ -442,39 +440,25 @@ class RelayBuildModule : public runtime::ModuleNode { auto lowered_funcs = graph_codegen_->GetLoweredFunc(); - // When there is no lowered_funcs due to reasons such as optimization, - // we first try to generate a dummy one if the target host is "llvm". + // When there is no lowered_funcs due to reasons such as optimization. if (lowered_funcs.size() == 0) { - // Decide first the target host - Target target_host_val = target_host_; - if (!target_host_.defined()) { - for (const auto &it : targets_) { - if (it.second->device_type == kDLCPU) { - target_host_val = it.second; - break; - } - } - } + Target target_host = GetTargetHost(); // If no target_host has been set, we choose a default one, which is - // llvm if "codegen.build_llvm" is accessible. - const runtime::PackedFunc* pf = runtime::Registry::Get("codegen.build_llvm"); - if (!target_host_val.defined()) - target_host_val = (pf != nullptr) ? target::llvm() : target::stackvm(); - - if (target_host_val.defined() && target_host_val->target_name == "llvm") - lowered_funcs.Set( - target_host_val->str(), - Array({ - MakeAPI(EvaluateNode::make(0), "__dummy__", Array(), 0, false) })); - } - - if (lowered_funcs.size() == 0) { - // If there is still no lowered_funcs, a fallback solution is to create a module - // with empty code content. - // The code content is initialized with ";" to prevent complaining - // from CSourceModuleNode::SaveToFile. - ret_.mod = tvm::codegen::CSourceModuleCreate(";", ""); + // llvm if "codegen.LLVMModuleCreate" is accessible. + const runtime::PackedFunc* pf = runtime::Registry::Get("codegen.LLVMModuleCreate"); + if (!target_host.defined()) + target_host = (pf != nullptr) ? target::llvm() : target::stackvm(); + + if (target_host.defined() && target_host->target_name == "llvm") { + // If we can decide the target is LLVM, we then create an empty LLVM module. + ret_.mod = (*pf)(target_host->str()); + } else { + // If we cannot decide the target is LLVM, we create an empty CSourceModule. + // The code content is initialized with ";" to prevent complaining + // from CSourceModuleNode::SaveToFile. + ret_.mod = tvm::codegen::CSourceModuleCreate(";", ""); + } } else { ret_.mod = tvm::build( lowered_funcs, @@ -488,6 +472,20 @@ class RelayBuildModule : public runtime::ModuleNode { ret_.mod.Import(it); } + private: + Target GetTargetHost() { + Target target_host = target_host_; + if (!target_host_.defined()) { + for (const auto &it : targets_) { + if (it.second->device_type == kDLCPU) { + target_host = it.second; + break; + } + } + } + return target_host; + } + protected: std::unique_ptr graph_codegen_; /*! \brief target device */ diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc index 2e04920d866b..450120d69da3 100644 --- a/src/target/llvm/llvm_module.cc +++ b/src/target/llvm/llvm_module.cc @@ -356,6 +356,40 @@ TVM_REGISTER_GLOBAL("codegen.build_llvm") *rv = runtime::Module(n); }); +TVM_REGISTER_GLOBAL("codegen.LLVMModuleCreate") +.set_body([](TVMArgs args, TVMRetValue *rv) { + auto n = make_object(); + + // parse target triple from the first argument + auto target = args[0].operator std::string(); + std::string triple, mcpu, mattr; + llvm::TargetOptions opt; + ParseLLVMTargetOptions(target, &triple, &mcpu, &mattr, &opt); + + // create a default data layout + auto tm = GetLLVMTargetMachine(target); + llvm::DataLayout layout(tm->createDataLayout()); + + // initialize an IR code snippet from a simple template + std::string ir_str; + ir_str += "target triple = \"" + triple + "\"\n"; + ir_str += "target datalayout = \"" + layout.getStringRepresentation() + "\""; + + // use parseIR to create a LLVM Module. + auto ctx = std::make_shared(); + llvm::SMDiagnostic err; + auto mem_buf = llvm::MemoryBuffer::getMemBuffer(ir_str); + auto module = llvm::parseIR(mem_buf->getMemBufferRef(), err, *ctx); + if (module == nullptr) { + std::string msg = std::string(err.getMessage()); + LOG(FATAL) << "Failed to create a LLVM module from the generated IR code:" + << std::endl << ir_str << std::endl << "Error message: " << msg; + } + n->Init(std::move(module), ctx); + + *rv = runtime::Module(n); +}); + TVM_REGISTER_GLOBAL("target.llvm_lookup_intrinsic_id") .set_body([](TVMArgs args, TVMRetValue* rv) { *rv = static_cast(LookupLLVMIntrinsic(args[0])); From ccded94d8ff35b838e30de544e89611d02b62d42 Mon Sep 17 00:00:00 2001 From: Vincent Zhao Date: Mon, 2 Mar 2020 19:31:55 +0000 Subject: [PATCH 08/10] Avoid using IR str concat to create LLVM module --- src/relay/backend/build_module.cc | 2 +- src/target/llvm/llvm_module.cc | 28 +++++++--------------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index 624ad17b7fd2..80919bc30baf 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -452,7 +452,7 @@ class RelayBuildModule : public runtime::ModuleNode { if (target_host.defined() && target_host->target_name == "llvm") { // If we can decide the target is LLVM, we then create an empty LLVM module. - ret_.mod = (*pf)(target_host->str()); + ret_.mod = (*pf)(target_host->str(), "empty_module"); } else { // If we cannot decide the target is LLVM, we create an empty CSourceModule. // The code content is initialized with ";" to prevent complaining diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc index 450120d69da3..fde3e8494a42 100644 --- a/src/target/llvm/llvm_module.cc +++ b/src/target/llvm/llvm_module.cc @@ -359,32 +359,18 @@ TVM_REGISTER_GLOBAL("codegen.build_llvm") TVM_REGISTER_GLOBAL("codegen.LLVMModuleCreate") .set_body([](TVMArgs args, TVMRetValue *rv) { auto n = make_object(); - - // parse target triple from the first argument auto target = args[0].operator std::string(); - std::string triple, mcpu, mattr; - llvm::TargetOptions opt; - ParseLLVMTargetOptions(target, &triple, &mcpu, &mattr, &opt); + auto module_name = args[1].operator std::string(); // create a default data layout + InitializeLLVM(); auto tm = GetLLVMTargetMachine(target); - llvm::DataLayout layout(tm->createDataLayout()); - - // initialize an IR code snippet from a simple template - std::string ir_str; - ir_str += "target triple = \"" + triple + "\"\n"; - ir_str += "target datalayout = \"" + layout.getStringRepresentation() + "\""; - - // use parseIR to create a LLVM Module. + auto triple = tm->getTargetTriple(); auto ctx = std::make_shared(); - llvm::SMDiagnostic err; - auto mem_buf = llvm::MemoryBuffer::getMemBuffer(ir_str); - auto module = llvm::parseIR(mem_buf->getMemBufferRef(), err, *ctx); - if (module == nullptr) { - std::string msg = std::string(err.getMessage()); - LOG(FATAL) << "Failed to create a LLVM module from the generated IR code:" - << std::endl << ir_str << std::endl << "Error message: " << msg; - } + std::unique_ptr module(new llvm::Module(module_name, *ctx)); + module->setTargetTriple(triple.str()); + module->setDataLayout(tm->createDataLayout()); + n->Init(std::move(module), ctx); *rv = runtime::Module(n); From bb5593573212dc98739dbb158363e00ee67d0207 Mon Sep 17 00:00:00 2001 From: Ruizhe Zhao Date: Wed, 11 Mar 2020 10:45:55 +0000 Subject: [PATCH 09/10] Improved comments for codegen.LLVMModuleCreate --- src/target/llvm/llvm_module.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc index fde3e8494a42..650dd6a18336 100644 --- a/src/target/llvm/llvm_module.cc +++ b/src/target/llvm/llvm_module.cc @@ -362,17 +362,19 @@ TVM_REGISTER_GLOBAL("codegen.LLVMModuleCreate") auto target = args[0].operator std::string(); auto module_name = args[1].operator std::string(); - // create a default data layout + // Generate a LLVM module from an input target string InitializeLLVM(); auto tm = GetLLVMTargetMachine(target); - auto triple = tm->getTargetTriple(); auto ctx = std::make_shared(); std::unique_ptr module(new llvm::Module(module_name, *ctx)); + + // Use a default data layout and target triple + auto triple = tm->getTargetTriple(); module->setTargetTriple(triple.str()); module->setDataLayout(tm->createDataLayout()); n->Init(std::move(module), ctx); - + *rv = runtime::Module(n); }); From 41450a57ebc3b3d10dd6a6ee97126c0b9cce7ad8 Mon Sep 17 00:00:00 2001 From: Ruizhe Zhao Date: Wed, 11 Mar 2020 10:49:30 +0000 Subject: [PATCH 10/10] Satisfy the linter for LLVMModuleCreate --- src/target/llvm/llvm_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc index 650dd6a18336..a4234d0232da 100644 --- a/src/target/llvm/llvm_module.cc +++ b/src/target/llvm/llvm_module.cc @@ -367,14 +367,14 @@ TVM_REGISTER_GLOBAL("codegen.LLVMModuleCreate") auto tm = GetLLVMTargetMachine(target); auto ctx = std::make_shared(); std::unique_ptr module(new llvm::Module(module_name, *ctx)); - + // Use a default data layout and target triple auto triple = tm->getTargetTriple(); module->setTargetTriple(triple.str()); module->setDataLayout(tm->createDataLayout()); n->Init(std::move(module), ctx); - + *rv = runtime::Module(n); });