--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AsmCode.h"
+
+namespace enco
+{
+
+void AsmCode::dump(std::ostream &os) const
+{
+ os << ".section .rodata" << std::endl;
+ os << ".global " << _varname << std::endl;
+ os << ".type " << _varname << ", @object" << std::endl;
+ os << ".align " << 4 << std::endl;
+ os << _varname << ":" << std::endl;
+ os << ".incbin " << '"' << _filename << '"' << std::endl;
+}
+
+} // namespace enco
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ENCO_ASM_CODE_H__
+#define __ENCO_ASM_CODE_H__
+
+#include <ostream>
+#include <string>
+
+namespace enco
+{
+
+class AsmCode
+{
+public:
+ AsmCode(const std::string &filename, const std::string &varname)
+ : _filename{filename}, _varname{varname}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void dump(std::ostream &) const;
+
+private:
+ std::string _filename;
+ std::string _varname;
+};
+
+} // namespace enco
+
+static inline std::ostream &operator<<(std::ostream &os, const enco::AsmCode &code)
+{
+ code.dump(os);
+ return os;
+}
+
+#endif // __ENCO_ASM_CODE_H__
#include "Session.h"
#include "Code.h"
+#include "AsmCode.h"
#include "CppCode.h"
#include "Transforms/Duplicate.h"
SplitPass split;
split.runOnCode(code(sess));
- generate_global_data(code(sess));
+ const std::string data_var = "data";
+ const std::string data_filename = _prefix + ".bin";
+
+ // Generate 'bin' file
+ {
+ std::ofstream ofs{data_filename, std::ios::binary};
+ generate_global_data(ofs, code(sess));
+ }
+
+ // Generate 'embed.S' file
+ {
+ std::ofstream ofs{_prefix + ".embed.S"};
+ ofs << AsmCode{data_filename, data_var};
+ }
// TODO Run various transforms over enco::Code
std::ofstream ofs{_prefix + ".cpp"};
- ofs << CppCode{code(sess)} << std::endl;
+ ofs << CppCode{data_var, code(sess)} << std::endl;
}
} // namespace enco
InvokeFunction invoke;
pp::LinearDocument internal;
- const std::string data_varname = "data";
-
- auto data_exp = [&data_varname](const GlobalOffset &off) {
- return pp::fmt(data_varname, " + ", off);
- };
+ auto data_exp = [this](const GlobalOffset &off) { return pp::fmt(_varname, " + ", off); };
// Record the subnet information
std::map<const ANNBinder *, SubnetInfo> subnet_ctx;
source.append(includes);
source.append();
- source.append("uint8_t ", data_varname, "[] = { ", *enco::GlobalData::global(m), " };");
+ source.append("extern uint8_t ", _varname, "[];");
source.append();
source.append("namespace");
class CppCode
{
public:
- CppCode(const Code *code) : _code{code}
+ CppCode(const std::string &varname, const Code *code) : _varname{varname}, _code{code}
{
// DO NOTHING
}
void dump(std::ostream &) const;
private:
+ const std::string _varname;
const Code *_code;
};
#include <pp/Format.h>
+#include <cassert>
+
+// TODO Remove unused code
namespace
{
GlobalOffset Global::constant(const uint8_t *base, uint32_t size)
{
- uint32_t offset = _content.size();
+ auto pos = _os.tellp();
+ assert(pos != -1);
- for (uint32_t n = 0; n < size; ++n)
- {
- _content.emplace_back(base[n]);
- }
-
- return offset;
-}
+ _os.write(reinterpret_cast<const char *>(base), size);
-void emit_as_initializer_list(std::ostream &os, const Global &global)
-{
- if (global.size() > 0)
- {
- os << u08_to_hex(global.at(0));
-
- for (uint32_t n = 1; n < global.size(); ++n)
- {
- os << ", " << u08_to_hex(global.at(n));
- }
- }
+ return static_cast<GlobalOffset>(pos);
}
} // namespace enco
class Global
{
public:
+ Global(std::ostream &os) : _os(os)
+ {
+ // DO NOTHING
+ }
+
+public:
// @brief Create a global constant string (const char *) literal, and return variable name
GlobalOffset constant(const std::string &value);
// @brief Create a global constant array variable of byte (uint8_t) type
GlobalOffset constant(const uint8_t *base, uint32_t size);
-public:
- uint32_t size(void) const { return _content.size(); }
- uint8_t at(uint32_t n) const { return _content.at(n); }
-
private:
- std::vector<uint8_t> _content;
+ uint32_t _offset = 0;
+ std::ostream &_os;
};
-void emit_as_initializer_list(std::ostream &os, const Global &global);
-
} // namespace enco
-static inline std::ostream &operator<<(std::ostream &os, const enco::Global &global)
-{
- emit_as_initializer_list(os, global);
- return os;
-}
-
#endif // __ENCO_GLOBAL_H__
namespace
{
-std::map<const coco::Module *, std::unique_ptr<enco::Global>> global_ctx;
std::map<const ann::Operand *, enco::GlobalOffset> data_offset_ctx;
std::map<const coco::Arg *, enco::GlobalOffset> name_offset_ctx;
std::map<const coco::Arg *, enco::GlobalOffset> dims_offset_ctx;
namespace enco
{
-const Global *GlobalData::global(const coco::Module *m) { return global_ctx.at(m).get(); }
-
GlobalOffset GlobalData::data_offset(const ann::Operand *o) { return data_offset_ctx.at(o); }
GlobalOffset GlobalData::name_offset(const coco::Input *in) { return name_offset_ctx.at(in); }
GlobalOffset GlobalData::name_offset(const coco::Output *out) { return name_offset_ctx.at(out); }
GlobalOffset GlobalData::dims_offset(const coco::Output *out) { return dims_offset_ctx.at(out); }
-void generate_global_data(enco::Code *code)
+void generate_global_data(std::ostream &os, enco::Code *code)
{
auto m = code->module();
- auto global = make_unique<Global>();
+ auto global = make_unique<Global>(os);
for (uint32_t n = 0; n < code->ann()->count(); ++n)
{
name_offset_ctx[output] = global->constant(output->name());
dims_offset_ctx[output] = global->constant<uint32_t>(dims);
}
-
- global_ctx[m] = std::move(global);
}
} // namespace enco
struct GlobalData
{
- static const Global *global(const coco::Module *);
-
static GlobalOffset data_offset(const ann::Operand *);
static GlobalOffset name_offset(const coco::Input *);
static GlobalOffset dims_offset(const coco::Input *);
*
* NOTE Succeeding passes can access offsets via "GlobalData"
*/
-void generate_global_data(enco::Code *);
+void generate_global_data(std::ostream &, enco::Code *);
} // namespace enco
###
set(PREFIX enco-basic-test-000)
set(GENERATED_CPP ${PREFIX}.cpp)
+set(GENERATED_ASM ${PREFIX}.embed.S)
+set(GENERATED_BIN ${PREFIX}.bin)
set(SOURCE_TARGET ${PREFIX}-src)
set(LIB_TARGET ${PREFIX}-lib)
--backend-arg ${PREFIX}
DEPENDS enco-cli ${PREFIX}-frontend)
set_source_files_properties(${GENERATED_CPP} PROPERTIES GENERATED TRUE)
-add_library(${LIB_TARGET} SHARED ${GENERATED_CPP})
+set_source_files_properties(${GENERATED_ASM} PROPERTIES GENERATED TRUE LANGUAGE C)
+set_source_files_properties(${GENERATED_BIN} PROPERTIES GENERATED TRUE)
+add_library(${LIB_TARGET} SHARED ${GENERATED_CPP} ${GENERATED_ASM})
target_link_libraries(${LIB_TARGET} PRIVATE ann_api)
add_dependencies(${LIB_TARGET} ${SOURCE_TARGET})
set(CAFFEMODEL_FILE "${PREFIX}.caffemodel" PARENT_SCOPE)
set(CAFFEMODEL_TARGET enco_caffe_test_${PREFIX}_caffemodel PARENT_SCOPE)
set(SOURCE_FILE ${PREFIX}.cpp PARENT_SCOPE)
+ set(ASM_FILE ${PREFIX}.embed.S PARENT_SCOPE)
+ set(BIN_FILE ${PREFIX}.bin PARENT_SCOPE)
set(SOURCE_TARGET enco_caffe_test_${PREFIX}_generated PARENT_SCOPE)
endfunction(get_test_configuration)
DEPENDS enco-cli enco_caffe_frontend ${CAFFEMODEL_TARGET}
COMMENT "Generating ${SOURCE_FILE}")
set_source_files_properties(${SOURCE_FILE} PROPERTIES GENERATED TRUE)
+ set_source_files_properties(${ASM_FILE} PROPERTIES GENERATED TRUE LANGUAGE C)
+ set_source_files_properties(${BIN_FILE} PROPERTIES GENERATED TRUE)
list(APPEND CANDIDATES ${PREFIX})
endforeach(MODEL)
# Compile shared library (from generated C++ code)
set(LIBRARY_TARGET enco_caffe_test_${PREFIX}_lib)
- add_library(${LIBRARY_TARGET} SHARED ${SOURCE_FILE})
+ add_library(${LIBRARY_TARGET} SHARED ${SOURCE_FILE} ${ASM_FILE})
+ target_include_directories(${LIBRARY_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(${LIBRARY_TARGET} ann_api)
add_dependencies(${LIBRARY_TARGET} ${SOURCE_TARGET})
endforeach(PREFIX)
set(BINDER_TARGET enco_caffe_test_${PREFIX}_binder)
# Compile nnkit binder (from generated C++ code)
- add_library(${BINDER_TARGET} SHARED binder.cpp ${SOURCE_FILE})
+ add_library(${BINDER_TARGET} SHARED binder.cpp ${SOURCE_FILE} ${ASM_FILE})
+ target_include_directories(${BINDER_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(${BINDER_TARGET} nnkit_intf_backend)
target_link_libraries(${BINDER_TARGET} ann_api)
target_link_libraries(${BINDER_TARGET} ann_ref_static)