--- /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 <enco/Frontend.h>
+#include <enco/Backend.h>
+
+#include <cmdline/View.h>
+
+#include <string>
+#include <vector>
+
+#include <functional>
+
+#include "Dump.h"
+
+namespace cmdline
+{
+
+// TODO Extract this helper class
+class Vector : public cmdline::View
+{
+public:
+ uint32_t size(void) const { return _args.size(); }
+
+public:
+ const char *at(uint32_t nth) const { return _args.at(nth).c_str(); }
+
+public:
+ Vector &append(const std::string &arg)
+ {
+ _args.emplace_back(arg);
+ return (*this);
+ }
+
+private:
+ std::vector<std::string> _args;
+};
+
+} // namespace cmdline
+
+namespace
+{
+
+class Zone
+{
+public:
+ Zone() = default;
+
+public:
+ const cmdline::View *args(void) const { return &_args; }
+
+public:
+ void append(const std::string &arg) { _args.append(arg); }
+
+private:
+ cmdline::Vector _args;
+};
+
+} // namespace
+
+#include <dlfcn.h>
+
+namespace
+{
+
+class FrontendFactory
+{
+public:
+ FrontendFactory(const std::string &path)
+ {
+ _handle = dlopen(path.c_str(), RTLD_LAZY);
+ assert(_handle != nullptr);
+ }
+
+public:
+ // Copy is not allowed to avoid double close
+ FrontendFactory(const FrontendFactory &) = delete;
+ FrontendFactory(FrontendFactory &&) = delete;
+
+public:
+ ~FrontendFactory() { dlclose(_handle); }
+
+private:
+ using Entry = std::unique_ptr<enco::Frontend> (*)(const cmdline::View &);
+
+private:
+ Entry entry(void) const
+ {
+ auto entry = reinterpret_cast<Entry>(dlsym(_handle, "make_frontend"));
+ assert(entry != nullptr);
+ return entry;
+ }
+
+public:
+ std::unique_ptr<enco::Frontend> make(const cmdline::View *args) const
+ {
+ auto fn = entry();
+ return fn(*args);
+ }
+
+private:
+ void *_handle;
+};
+
+} // namespace
+
+namespace
+{
+
+class FrontendZone : public Zone
+{
+public:
+ FrontendZone(const std::string &path) : _factory{path}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const FrontendFactory *factory(void) const { return &_factory; }
+
+private:
+ FrontendFactory _factory;
+};
+
+} // namespace
+
+#include <nncc/foundation/Memory.h>
+
+#include <map>
+
+#include <iostream>
+#include <stdexcept>
+
+/**
+ * @brief Dump IR for given arguments
+ *
+ * Call example:
+ * $ ./build/contrib/encodump/encodump \
+ * --frontend build/contrib/enco/frontend/caffe/libenco_caffe_frontend.so \
+ * --frontend-arg build/contrib/enco/test/caffe/003.prototxt \
+ * --frontend-arg build/contrib/enco/test/caffe/003.caffemodel
+ */
+static int entry(int argc, char **argv)
+{
+ // Usage:
+ // [Command] --frontend [Frontend .so path] --frontend-arg ...
+ std::unique_ptr<FrontendZone> frontend_zone;
+
+ // Simple argument parser (based on map)
+ std::map<std::string, std::function<void(const std::string &arg)>> argparse;
+
+ argparse["--frontend"] = [&](const std::string &path) {
+ frontend_zone = nncc::foundation::make_unique<FrontendZone>(path);
+ };
+
+ argparse["--frontend-arg"] = [&](const std::string &arg) { frontend_zone->append(arg); };
+
+ if (argc < 2)
+ {
+ std::cerr << "Usage:" << std::endl;
+ std::cerr << "[Command] --frontend [.so path]" << std::endl;
+ std::cerr << " --frontend-arg [argument] ..." << std::endl;
+ return 255;
+ }
+
+ for (int n = 1; n < argc; n += 2)
+ {
+ const std::string tag{argv[n]};
+ const std::string arg{argv[n + 1]};
+
+ auto it = argparse.find(tag);
+
+ if (it == argparse.end())
+ {
+ std::cerr << "Option '" << tag << "' is not supported" << std::endl;
+ return 255;
+ }
+
+ it->second(arg);
+ }
+
+ assert(frontend_zone != nullptr);
+
+ auto frontend = frontend_zone->factory()->make(frontend_zone->args());
+
+ auto bundle = frontend->load();
+
+ // dump
+ dump(bundle.module());
+
+ // todo : dump data
+
+ return 0;
+}
+
+#ifdef NDEBUG
+int main(int argc, char **argv)
+{
+ try
+ {
+ return entry(argc, argv);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ }
+
+ return 255;
+}
+#else // NDEBUG
+int main(int argc, char **argv)
+{
+ // NOTE main does not catch internal exceptions for debug build to make it easy to
+ // check the stacktrace with a debugger
+ return entry(argc, argv);
+}
+#endif // !NDEBUG
--- /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 "Dump.h"
+
+#include <iostream>
+
+std::string tab(int n) { return std::string(n * 2, ' '); }
+
+struct OpPrinter final : public coco::Op::Visitor<void>
+{
+public:
+ OpPrinter(std::ostream &os) : _os(os) {}
+
+public:
+ void visit(const coco::Load *op) override { _os << "; Load(" << op->object() << ")"; }
+
+ void visit(const coco::PadF *op) override
+ {
+ op->arg()->accept(this);
+ _os << "; PadF";
+ }
+
+ void visit(const coco::Conv2D *op) override
+ {
+ op->arg()->accept(this);
+ const coco::Padding2D *pad = op->pad();
+ const coco::Stride2D *stride = op->stride();
+
+ _os << "; Conv2D(ker: " << op->ker() << ", padding [T/B/L/R=" << pad->top() << ","
+ << pad->bottom() << "," << pad->left() << "," << pad->right() << "]"
+ << ", stride [V/H = " << stride->vertical() << "," << stride->horizontal() << "]"
+ << ")";
+ }
+
+ void visit(const coco::MaxPool2D *op) override
+ {
+ op->arg()->accept(this);
+ _os << "; MaxPool2D";
+ }
+
+ void visit(const coco::AvgPool2D *op) override
+ {
+ op->arg()->accept(this);
+ _os << "; AvgPool2D";
+ }
+
+ void visit(const coco::Add *op) override
+ {
+ op->left()->accept(this);
+ op->right()->accept(this);
+ _os << "; Add";
+ }
+
+ void visit(const coco::Mul *op) override
+ {
+ op->left()->accept(this);
+ op->right()->accept(this);
+ _os << "; Mul";
+ }
+
+ void visit(const coco::ReLU *op) override
+ {
+ op->arg()->accept(this);
+ _os << "; ReLU";
+ }
+
+private:
+ std::ostream &_os;
+};
+
+struct InstrPrinter final : public coco::Instr::Visitor<void>
+{
+public:
+ InstrPrinter() = delete;
+
+ InstrPrinter(int indent) : _indent(indent) {}
+
+ void visit(const coco::Eval *ins) override
+ {
+ std::cout << tab(_indent) << "Eval" << std::endl;
+ std::cout << tab(_indent) << " out: " << ins->out() << std::endl;
+ std::cout << tab(_indent) << " op: ";
+ {
+ OpPrinter prn(std::cout);
+ ins->op()->accept(prn);
+ }
+ std::cout << std::endl;
+ }
+
+ void visit(const coco::Copy *ins) override
+ {
+ std::cout << tab(_indent) << "Copy" << std::endl;
+ std::cout << tab(_indent) << " from: " << ins->from() << std::endl;
+ std::cout << tab(_indent) << " into: " << ins->into() << std::endl;
+ }
+
+ void visit(const coco::Shuffle *ins) override
+ {
+ std::cout << tab(_indent) << "Shuffle" << std::endl;
+ std::cout << tab(_indent) << " from: " << ins->from() << std::endl;
+ std::cout << tab(_indent) << " into: " << ins->into() << std::endl;
+ }
+
+private:
+ int _indent;
+};
+
+void dump(const coco::Op *op)
+{
+ OpPrinter prn(std::cout);
+ op->accept(prn);
+}
+
+void dump(const coco::Instr *ins, int indent)
+{
+ std::cout << tab(indent) << "Inst:" << std::endl;
+
+ static InstrPrinter prn(indent + 1);
+
+ ins->accept(prn);
+}
+
+void dump(const coco::Block *B, int indent)
+{
+ std::cout << tab(indent) << "Block (index: " << B->index().value() << ")" << std::endl;
+ for (auto I = B->instr()->head(); I != nullptr; I = I->next())
+ {
+ dump(I, indent + 1);
+ }
+}
+
+void dump(const coco::BlockList *L, int indent)
+{
+ for (auto B = L->head(); B != nullptr; B = B->next())
+ {
+ dump(B, indent);
+ }
+}
+
+void dump(const coco::BagManager *l, int indent)
+{
+ for (auto n = 0; n < l->size(); ++n)
+ {
+ auto bag = l->at(n);
+ std::cout << tab(indent) << "%" << bag << " = Bag(size: " << bag->size() << ")" << std::endl;
+ }
+}
+void dump(const coco::ObjectManager *l, int indent)
+{
+ for (auto n = 0; n < l->size(); ++n)
+ {
+ auto obj = l->at(n);
+ std::cout << tab(indent) << "%" << obj << " = Object(bag: " << obj->bag() << ")" << std::endl;
+ }
+}
+
+template <typename T> void head(int indent);
+
+template <> void head<coco::Input>(int indent) { std::cout << tab(indent) << "Input: "; }
+
+template <> void head<coco::Output>(int indent) { std::cout << tab(indent) << "Output: "; }
+
+template <typename PtrItemT> void dump(const coco::PtrList<PtrItemT> *list, int indent)
+{
+ head<PtrItemT>(indent);
+ for (int n = 0; n < list->size(); n++)
+ {
+ const PtrItemT *item = list->at(n);
+ if (n != 0)
+ std::cout << ", ";
+ std::cout << "#" << n + 1 << ". name=" << item->name();
+ }
+ std::cout << std::endl;
+}
+
+void dump(const coco::Module *module)
+{
+ std::cout << "Module" << std::endl;
+
+ dump(module->block(), 1);
+ dump(module->input(), 1);
+ dump(module->output(), 1);
+}