summaryrefslogtreecommitdiff
path: root/compiler/nnc/backends/soft_backend/CPPGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/nnc/backends/soft_backend/CPPGenerator.cpp')
-rw-r--r--compiler/nnc/backends/soft_backend/CPPGenerator.cpp98
1 files changed, 95 insertions, 3 deletions
diff --git a/compiler/nnc/backends/soft_backend/CPPGenerator.cpp b/compiler/nnc/backends/soft_backend/CPPGenerator.cpp
index ce7057e15..f2188c3d3 100644
--- a/compiler/nnc/backends/soft_backend/CPPGenerator.cpp
+++ b/compiler/nnc/backends/soft_backend/CPPGenerator.cpp
@@ -21,8 +21,6 @@
#include "SBSerializer.h"
#include "option/Options.h"
-using namespace std;
-
#include "CommonData.def"
#include "cpp_header_types.generated.h"
@@ -52,12 +50,104 @@ using namespace std;
#include "cpp_transpose.generated.h"
#include "cpp_gather.generated.h"
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+#include <stdexcept>
+#include <sys/stat.h>
+
namespace nnc
{
using namespace sir;
+using namespace std;
+
+/**
+ * @brief Creates pointer to some output stream to encapsulate resource management into deleter
+ * for example may be used to return std::cout
+ * @param path Path to opened file
+ * @return Pointer output stream
+ * @throws runtime_error if did not succeed
+ */
+static unique_ptr<ofstream> getStream(const string &path)
+{
+ unique_ptr<ofstream> ofs(new ofstream(path));
+ if (ofs->fail())
+ throw runtime_error("Can not open code output file: " + path);
+ return ofs;
+}
+
+/**
+ * @brief Creates directory
+ * @param path Path to desired directory
+ * @throws runtime_error in did not succeed
+ */
+static void createDir(const string &path)
+{
+ int res =
+ mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); // NOLINT(hicpp-signed-bitwise)
+ if (res != 0 && errno != EEXIST)
+ throw runtime_error("Failed to create output directory");
+}
+
+void CPPCodeGenerator::materializeModelParams(ostream &out, const Serializer &s)
+{
+ using namespace params;
+
+ // First form a dump header
+ char header[HEADER_LEN];
+ uint32_t version = s.getFormatVersion();
+ uint32_t hash = s.getModelHash();
+ static_assert(VERSION_LEN == sizeof(version), "version length mismatch");
+ static_assert(HASH_LEN == sizeof(hash), "hash length mismatch");
+ memcpy(header, MAGIC, MAGIC_LEN);
+ memcpy(header + MAGIC_LEN, &version, VERSION_LEN);
+ memcpy(header + MAGIC_LEN + VERSION_LEN, &hash, HASH_LEN);
+
+ out.write(header, HEADER_LEN);
+ if (out.fail())
+ throw runtime_error("Failed to write model parameters header");
+ auto &params = s.getBuffer();
+ out.write(params.data(), params.size());
+ if (out.fail())
+ throw runtime_error("Failed to write model Parameters");
+}
-using TensorType = TensorDescriptor::Type;
+void CPPCodeGenerator::run(mir::Graph *graph)
+{
+ assert(graph);
+
+ // visit and analyze graph
+ ModelAnalyzer ma;
+ ma.analyze(graph);
+ // serialize parameters
+ Serializer serializer;
+ serializer.serialize(ma.getInferenceSequence());
+ // rename tensors for specific backend language
+ formatTensorNames(ma);
+
+ createDir(cli::artifactDir);
+
+ const string base_path = cli::artifactDir + "/" + cli::artifactName;
+ const string header_path = base_path + ".h";
+ const string code_path = base_path + ".cpp";
+ const string params_path = base_path + ".params";
+
+ // Print header
+ auto header_stream = getStream(header_path);
+ materializeHeader(*header_stream, ma);
+ header_stream.reset();
+
+ // Print code
+ auto code_stream = getStream(code_path);
+ materializeCode(*code_stream, ma, serializer);
+ code_stream.reset();
+
+ // Print model parameters
+ auto model_stream = getStream(params_path);
+ materializeModelParams(*model_stream, serializer);
+ model_stream.reset();
+}
/**
* @brief Renames tensors with respect to C++ naming conventions
@@ -65,6 +155,8 @@ using TensorType = TensorDescriptor::Type;
*/
void CPPCodeGenerator::formatTensorNames(const ModelAnalyzer &ma)
{
+ using TensorType = TensorDescriptor::Type;
+
int tmp_tensors = 0;
for (const TensorDescriptor &td : ma.getTensors())
{