diff options
Diffstat (limited to 'compiler/nnc/backends/soft_backend/CPPGenerator.cpp')
-rw-r--r-- | compiler/nnc/backends/soft_backend/CPPGenerator.cpp | 98 |
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 ¶ms = 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()) { |