Soft backend: split C and C++ plugins (#862)
authorEfimov Alexander/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Thu, 2 Aug 2018 07:46:43 +0000 (10:46 +0300)
committerSergey Vostokov/AI Tools Lab /SRR/Staff Engineer/삼성전자 <s.vostokov@samsung.com>
Thu, 2 Aug 2018 07:46:43 +0000 (16:46 +0900)
Split soft backend plugin in two

Signed-off-by: Efimov Alexander <a.efimov@samsung.com>
contrib/nnc/README.md
contrib/nnc/libs/backend/soft/CMakeLists.txt
contrib/nnc/libs/backend/soft/include/soft_backend.h [new file with mode: 0644]
contrib/nnc/libs/backend/soft/src/c_backend.cpp [new file with mode: 0644]
contrib/nnc/libs/backend/soft/src/cpp_backend.cpp [new file with mode: 0644]
contrib/nnc/libs/backend/soft/src/soft_backend.cpp

index e824c78..42e9825 100644 (file)
@@ -58,13 +58,13 @@ Assuming that current directory is a build root and we have tflite model(for exa
 ```
 ./nnc --plugins-path . \
 --input-filename inceptionv3.tflite \
---emit-source c++ \
+--emit-c++ \
 --out-code nn.cpp \
 --out-header nn.h \
 --out-model param.file</p>
 ```
 
-``--emit-source c++`` is a _soft backend_ option that selects target language to emit
+``--emit-c++`` is a _soft backend_ option that selects target language to emit(for now supported ``--emit-c++`` and ``--emit-c``)
 
 ``--out-code nn.cpp`` is a _soft backend_ option, it sets path to source code file
 
index d6c8f80..4dca6e7 100644 (file)
@@ -1,10 +1,10 @@
-file(GLOB_RECURSE SOFT_BACKEND_SOURCES src/*.cpp)
-file(GLOB_RECURSE HEADERS "include/*.h")
+set(SOFT_BACKEND_COMMON_SOURCES src/soft_backend.cpp src/generator.cpp src/model_analyzer.cpp)
+set(SOFT_BACKEND_CPP_SOURCES src/cpp_backend.cpp)
+set(SOFT_BACKEND_C_SOURCES src/c_backend.cpp)
 set(DEF_CONV src/def2src.cpp)
 
 file(GLOB_RECURSE TESTS "src/*.test.cpp")
 file(GLOB_RECURSE SOFT_DEF_SOURCES include/*.def)
-list(REMOVE_ITEM SOFT_BACKEND_SOURCES ${TESTS} ${DEF_CONV})
 
 set(SOFT_GENERATED_SOURCES "")
 foreach(file IN LISTS SOFT_DEF_SOURCES)
@@ -18,20 +18,33 @@ foreach(file IN LISTS SOFT_DEF_SOURCES)
     )
 endforeach()
 
-add_library(soft_backend SHARED ${SOFT_BACKEND_SOURCES} ${SOFT_GENERATED_SOURCES})
+add_executable(def2src ${DEF_CONV})
 
-add_nncc_test(nnc_soft_backend_test ${TESTS})
-nncc_target_link_libraries(nnc_soft_backend_test nncc_core nnc_core nnc_plugin_core nncc_foundation soft_backend)
+add_library(soft_backend_common STATIC ${SOFT_BACKEND_COMMON_SOURCES} ${SOFT_GENERATED_SOURCES})
+set_property(TARGET soft_backend_common PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_include_directories(soft_backend_common PUBLIC include)
+target_include_directories(soft_backend_common PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(soft_backend_common PRIVATE nncc_core)
+target_link_libraries(soft_backend_common PRIVATE nnc_plugin_core)
+target_link_libraries(soft_backend_common PRIVATE nnc_core)
+
+function(make_soft_backend NAME SOURCES)
+    message(${NAME} ${SOURCES})
+    add_library(${NAME} SHARED ${SOURCES} ${SOFT_GENERATED_SOURCES})
+    target_include_directories(${NAME} PUBLIC include)
+    target_include_directories(${NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+
+    target_link_libraries(${NAME} PRIVATE soft_backend_common)
+    target_link_libraries(${NAME} PRIVATE nncc_core)
+    target_link_libraries(${NAME} PRIVATE nnc_plugin_core)
+    target_link_libraries(${NAME} PRIVATE nncc_foundation)
+    target_link_libraries(${NAME} PRIVATE nnc_core)
+endfunction(make_soft_backend)
+
+make_soft_backend(soft_backend_cpp ${SOFT_BACKEND_CPP_SOURCES})
+make_soft_backend(soft_backend_c ${SOFT_BACKEND_C_SOURCES})
+
+add_nncc_test(nnc_soft_backend_test ${TESTS} ${SOFT_BACKEND_COMMON_SOURCES})
+nncc_target_link_libraries(nnc_soft_backend_test nncc_core nnc_core nnc_plugin_core nncc_foundation soft_backend_common)
 target_include_directories(nnc_soft_backend_test PUBLIC include)
 target_include_directories(nnc_soft_backend_test PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
-
-add_executable(def2src ${DEF_CONV})
-
-target_link_libraries(soft_backend PRIVATE nncc_core)
-
-target_include_directories(soft_backend PUBLIC include)
-target_include_directories(soft_backend PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
-
-target_link_libraries(soft_backend PRIVATE nnc_plugin_core)
-target_link_libraries(soft_backend PRIVATE nncc_foundation)
-target_link_libraries(soft_backend PRIVATE nnc_core)
diff --git a/contrib/nnc/libs/backend/soft/include/soft_backend.h b/contrib/nnc/libs/backend/soft/include/soft_backend.h
new file mode 100644 (file)
index 0000000..679f8d2
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _NNC_SOFT_BACKEND_PLUGIN_H_
+#define _NNC_SOFT_BACKEND_PLUGIN_H_
+
+#include "PluginInstance.h"
+#include "nnc/core/IR/model/graph/graph.h"
+
+#include <string>
+#include <map>
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+enum class OPT_ID;
+
+class BaseSoftBackend : public nncc::contrib::plugin::AbstractPluginInstance
+{
+public:
+  BaseSoftBackend &operator=(const BaseSoftBackend &) = delete;
+
+  BaseSoftBackend(const BaseSoftBackend &) = delete;
+
+  void fillSession() override;
+
+  void checkConfig() override;
+
+  void *execute(void *data) override;
+
+  void setParam(const std::string &name) override;
+
+  void setParam(const std::string &name, const std::string &value) override;
+
+protected:
+  std::string _outHeaderFile;
+  std::string _outCodeFile;
+  std::string _outModelFile;
+
+  const std::string _pluginName;
+
+  // general options with some expected value
+  std::map<std::string, OPT_ID> _opts;
+
+  // flag options
+  std::map<std::string, OPT_ID> _flags;
+
+  BaseSoftBackend(const std::string &name, const std::string &target_opt);
+
+  ~BaseSoftBackend() override = default;
+
+  virtual void generate(nncc::contrib::core::IR::model::Graph *g) = 0;
+};
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
+#endif //_NNC_SOFT_BACKEND_PLUGIN_H_
diff --git a/contrib/nnc/libs/backend/soft/src/c_backend.cpp b/contrib/nnc/libs/backend/soft/src/c_backend.cpp
new file mode 100644 (file)
index 0000000..73c3178
--- /dev/null
@@ -0,0 +1,62 @@
+#include "soft_backend.h"
+#include "generator.h"
+
+#include "ConfigException.h"
+
+using namespace nncc::contrib::config;
+using namespace nncc::contrib::plugin;
+using namespace nncc::contrib::backend::soft;
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+namespace
+{
+const char *target_opt = "emit-c";
+const char *backend_name = "C soft backend";
+} // unnamed namespace
+
+class CSoftBackend final: public BaseSoftBackend
+{
+public:
+  CSoftBackend &operator=(const CSoftBackend &) = delete;
+
+  CSoftBackend(const CSoftBackend &) = delete;
+
+  void fillSession() override
+  {
+    BaseSoftBackend::fillSession();
+    getSession()->registerParam(PluginParam(target_opt, "option enables C backend", false));
+  }
+
+  void generate(nncc::contrib::core::IR::model::Graph *g) override
+  {
+    CCodeGenerator::create(_outHeaderFile, _outCodeFile, _outModelFile).generate(g);
+  }
+
+  static CSoftBackend &getInstance()
+  {
+    static CSoftBackend instance;
+    return instance;
+  }
+
+private:
+  CSoftBackend(): BaseSoftBackend(backend_name, target_opt) {}
+};
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
+
+extern "C" AbstractPluginInstance *get_instance()
+{
+  return &CSoftBackend::getInstance();
+}
diff --git a/contrib/nnc/libs/backend/soft/src/cpp_backend.cpp b/contrib/nnc/libs/backend/soft/src/cpp_backend.cpp
new file mode 100644 (file)
index 0000000..2f5f9e6
--- /dev/null
@@ -0,0 +1,62 @@
+#include "soft_backend.h"
+#include "generator.h"
+
+#include "ConfigException.h"
+
+using namespace nncc::contrib::config;
+using namespace nncc::contrib::plugin;
+using namespace nncc::contrib::backend::soft;
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+namespace
+{
+const char *target_opt = "emit-c++";
+const char *backend_name = "C++ soft backend";
+} // unnamed namespace
+
+class CPPSoftBackend final: public BaseSoftBackend
+{
+public:
+  CPPSoftBackend &operator=(const CPPSoftBackend &) = delete;
+
+  CPPSoftBackend(const CPPSoftBackend &) = delete;
+
+  void fillSession() override
+  {
+    BaseSoftBackend::fillSession();
+    getSession()->registerParam(PluginParam(target_opt, "option enables C++ backend", false));
+  }
+
+  void generate(nncc::contrib::core::IR::model::Graph *g) override
+  {
+    CPPCodeGenerator::create(_outHeaderFile, _outCodeFile, _outModelFile).generate(g);
+  }
+
+  static CPPSoftBackend &getInstance()
+  {
+    static CPPSoftBackend instance;
+    return instance;
+  }
+
+private:
+  CPPSoftBackend(): BaseSoftBackend(backend_name, target_opt) {}
+};
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
+
+extern "C" AbstractPluginInstance *get_instance()
+{
+  return &CPPSoftBackend::getInstance();
+}
index d2fc150..18ed127 100644 (file)
@@ -3,7 +3,7 @@
 #include <iostream>
 #include <cassert>
 
-#include "PluginInstance.h"
+#include "soft_backend.h"
 #include "PluginException.h"
 #include "ConfigException.h"
 #include "PluginType.h"
@@ -17,92 +17,44 @@ using namespace nncc::contrib::plugin;
 using namespace nncc::contrib::core::IR::model;
 using namespace nncc::contrib::backend::soft;
 
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
 namespace
 {
-const string pluginName = "soft backend";
 const string pluginVersion = "0.01";
 const string pluginDesc = "Generates source code for selected programming language from IR";
 const PluginType pluginType = typeBackEnd;
 
+const char *outCodeOpt = "out-code";
+const char *outHeaderOpt = "out-header";
+const char *outModelOpt = "out-model";
+} // unnamed namespace
+
 // Helpers
 enum class OPT_ID
 {
   INVALID,
-  TARGET_LANG,
+  TARGET,
   OUT_HEADER,
   OUT_CODE,
   OUT_MODEL
 };
 
-const char *targetLangOpt = "emit-source";
-const char *outCodeOpt = "out-code";
-const char *outHeaderOpt = "out-header";
-const char *outModelOpt = "out-model";
-
-// general options with some expected value
-const map<string, OPT_ID> opts = {{targetLangOpt, OPT_ID::TARGET_LANG},
-                                  {outCodeOpt, OPT_ID::OUT_CODE},
-                                  {outHeaderOpt, OPT_ID::OUT_HEADER},
-                                  {outModelOpt, OPT_ID::OUT_MODEL}};
-
-// flag options
-const map<string, OPT_ID> flags;
-
-enum class LANG_ID
-{
-  INVALID,
-  C,
-  CPP
-};
-
-const map<string, LANG_ID> langs = {{"c", LANG_ID::C},
-                                    {"c++", LANG_ID::CPP}};
-
-// Plugin implementation
-class SoftBackendInstance : public AbstractPluginInstance
-{
-public:
-  SoftBackendInstance &operator=(const SoftBackendInstance &) = delete;
-  SoftBackendInstance(const SoftBackendInstance &) = delete;
-
-  static AbstractPluginInstance &getInstance();
-  void fillSession() override;
-  void checkConfig() override;
-  void *execute(void *data) override;
-
-  void setParam(const string &name) override;
-  void setParam(const string &name, const string &value) override;
-
-private:
-  LANG_ID _target;
-  string _outHeaderFile;
-  string _outCodeFile;
-  string _outModelFile;
-
-  SoftBackendInstance();
-  ~SoftBackendInstance() override = default;
-};
-
-SoftBackendInstance::SoftBackendInstance(): _target(LANG_ID::INVALID)
-{
-    // EMPTY
-}
-
-AbstractPluginInstance &SoftBackendInstance::getInstance()
-{
-  static SoftBackendInstance instance;
-  return instance;
-}
-
-void SoftBackendInstance::fillSession()
+void BaseSoftBackend::fillSession()
 {
   const static map<string, string> info = {{"module description", pluginDesc}};
-  const static vector<PluginParam> moduleParams = {{targetLangOpt, "language to emit: c,c++", false},
-                                                   {outCodeOpt, "output file for code", true},
+  const static vector<PluginParam> moduleParams = {{outCodeOpt, "output file for code", true},
                                                    {outHeaderOpt, "output file for header", true},
                                                    {outModelOpt, "output file for model parameters", true}};
 
-  AbstractPluginInstance::fillSessionBase(pluginType, pluginVersion, pluginName);
+  AbstractPluginInstance::fillSessionBase(pluginType, pluginVersion, _pluginName);
 
   for (auto &i : info)
     getSession()->addInfo(i.first, i.second);
@@ -111,58 +63,39 @@ void SoftBackendInstance::fillSession()
     getSession()->registerParam(p);
 }
 
-void SoftBackendInstance::checkConfig()
+void BaseSoftBackend::checkConfig()
 {
-  assert(_target != LANG_ID::INVALID && "No target language selected");
   // Nothing to check for now
 }
 
-void *SoftBackendInstance::execute(void *data)
+void *BaseSoftBackend::execute(void *data)
 {
-  assert(_target != LANG_ID::INVALID);
   assert(data);
   Graph *graph = static_cast<Graph*>(data);
-  switch (_target)
-  {
-    case LANG_ID::C:
-      CCodeGenerator::create(_outHeaderFile, _outCodeFile, _outModelFile).generate(graph);
-      break;
-    case LANG_ID::CPP:
-      CPPCodeGenerator::create(_outHeaderFile, _outCodeFile, _outModelFile).generate(graph);
-      break;
-    default:
-      assert(false && "Unsupported language");
-      break;
-  };
-  clog << "[" << pluginName << "] Plugin executed" << endl;
+  generate(graph);
+  clog << "[" << _pluginName << "] Plugin executed" << endl;
   return data;
 }
 
-void SoftBackendInstance::setParam(const string &name)
-{
-  auto optionIt = flags.find(name);
-  (void) optionIt;
-  // plugin do not have flag arguments for now - throw exception
-  throw ConfigException("[" + pluginName + "] Unsupported flag parameter <" + name + ">");
-}
-
-void SoftBackendInstance::setParam(const string &name, const string &value)
+void BaseSoftBackend::setParam(const string &name)
 {
-  auto optionIt = opts.find(name);
-  assert(optionIt != opts.end());
+  auto optionIt = _flags.find(name);
   switch (optionIt->second)
   {
-    case OPT_ID::TARGET_LANG:
+    case OPT_ID::TARGET:
     {
-      auto langId = langs.find(value);
-      if (langId == langs.end())
-      {
-        string info = "[" + pluginName + "] Unsupported target language <" + value + ">";
-        throw ConfigException(info);
-      }
-      _target = langId->second;
       break;
     }
+    default:
+      throw ConfigException("[" + _pluginName + "] Unsupported flag parameter <" + name + ">");
+  }
+}
+
+void BaseSoftBackend::setParam(const string &name, const string &value)
+{
+  auto optionIt = _opts.find(name);
+  switch (optionIt->second)
+  {
     case OPT_ID::OUT_HEADER:
     {
       _outHeaderFile = value;
@@ -179,13 +112,20 @@ void SoftBackendInstance::setParam(const string &name, const string &value)
       break;
     }
     default:
-      throw ConfigException("[" + pluginName + "] Unsupported parameter <" + name + ">");
+      throw ConfigException("[" + _pluginName + "] Unsupported parameter with value <" + name + ">");
   }
 }
 
-} // unnamed namespace
-
-extern "C" AbstractPluginInstance *get_instance()
+BaseSoftBackend::BaseSoftBackend(const std::string &name, const std::string &target_opt):
+        _pluginName(name)
 {
-    return &SoftBackendInstance::getInstance();
+  _flags[target_opt] = OPT_ID::TARGET;
+  _opts[outCodeOpt] = OPT_ID::OUT_CODE;
+  _opts[outHeaderOpt] = OPT_ID::OUT_HEADER;
+  _opts[outModelOpt] = OPT_ID::OUT_MODEL;
 }
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc