summaryrefslogtreecommitdiff
path: root/compiler/loco/include
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/loco/include')
-rw-r--r--compiler/loco/include/loco.h26
-rw-r--r--compiler/loco/include/loco/ADT/AnnotatedItem.h82
-rw-r--r--compiler/loco/include/loco/ADT/ObjectPool.h77
-rw-r--r--compiler/loco/include/loco/IR/Algorithm.h48
-rw-r--r--compiler/loco/include/loco/IR/BiasShape.h43
-rw-r--r--compiler/loco/include/loco/IR/CanonicalDialect.h45
-rw-r--r--compiler/loco/include/loco/IR/CanonicalNode.h23
-rw-r--r--compiler/loco/include/loco/IR/CanonicalNodeDecl.h50
-rw-r--r--compiler/loco/include/loco/IR/CanonicalNodeImpl.h64
-rw-r--r--compiler/loco/include/loco/IR/CanonicalNodeVisitor.forward.h29
-rw-r--r--compiler/loco/include/loco/IR/CanonicalNodeVisitor.h79
-rw-r--r--compiler/loco/include/loco/IR/CanonicalNodes.lst49
-rw-r--r--compiler/loco/include/loco/IR/CanonicalOpcode.h37
-rw-r--r--compiler/loco/include/loco/IR/DataType.h51
-rw-r--r--compiler/loco/include/loco/IR/DataTypeTraits.h86
-rw-r--r--compiler/loco/include/loco/IR/DepthwiseFilterAxis.h33
-rw-r--r--compiler/loco/include/loco/IR/DepthwiseFilterCodec.h69
-rw-r--r--compiler/loco/include/loco/IR/DepthwiseFilterIndex.h65
-rw-r--r--compiler/loco/include/loco/IR/DepthwiseFilterShape.h63
-rw-r--r--compiler/loco/include/loco/IR/Dialect.h66
-rw-r--r--compiler/loco/include/loco/IR/DialectService.h35
-rw-r--r--compiler/loco/include/loco/IR/Dimension.h85
-rw-r--r--compiler/loco/include/loco/IR/Domain.h53
-rw-r--r--compiler/loco/include/loco/IR/FeatureAxis.h33
-rw-r--r--compiler/loco/include/loco/IR/FeatureCodec.h77
-rw-r--r--compiler/loco/include/loco/IR/FeatureIndex.h65
-rw-r--r--compiler/loco/include/loco/IR/FeatureShape.h66
-rw-r--r--compiler/loco/include/loco/IR/FilterAxis.h33
-rw-r--r--compiler/loco/include/loco/IR/FilterCodec.h61
-rw-r--r--compiler/loco/include/loco/IR/FilterIndex.h65
-rw-r--r--compiler/loco/include/loco/IR/FilterShape.h69
-rw-r--r--compiler/loco/include/loco/IR/Graph.forward.h28
-rw-r--r--compiler/loco/include/loco/IR/Graph.h284
-rw-r--r--compiler/loco/include/loco/IR/GraphInputIndex.h29
-rw-r--r--compiler/loco/include/loco/IR/GraphOutputIndex.h29
-rw-r--r--compiler/loco/include/loco/IR/MatrixAxis.h31
-rw-r--r--compiler/loco/include/loco/IR/MatrixCodec.h73
-rw-r--r--compiler/loco/include/loco/IR/MatrixIndex.h55
-rw-r--r--compiler/loco/include/loco/IR/MatrixShape.h56
-rw-r--r--compiler/loco/include/loco/IR/Node.forward.h28
-rw-r--r--compiler/loco/include/loco/IR/Node.h147
-rw-r--r--compiler/loco/include/loco/IR/NodeMixins.h133
-rw-r--r--compiler/loco/include/loco/IR/NodePool.forward.h28
-rw-r--r--compiler/loco/include/loco/IR/NodePool.h62
-rw-r--r--compiler/loco/include/loco/IR/NodeShape.h70
-rw-r--r--compiler/loco/include/loco/IR/Nodes.h1123
-rw-r--r--compiler/loco/include/loco/IR/Padding2D.h65
-rw-r--r--compiler/loco/include/loco/IR/PaddingND.h56
-rw-r--r--compiler/loco/include/loco/IR/PermutingCodec.h421
-rw-r--r--compiler/loco/include/loco/IR/Stride.h50
-rw-r--r--compiler/loco/include/loco/IR/TensorAxis.h29
-rw-r--r--compiler/loco/include/loco/IR/TensorAxisSet.h42
-rw-r--r--compiler/loco/include/loco/IR/TensorIndex.h30
-rw-r--r--compiler/loco/include/loco/IR/TensorShape.h62
-rw-r--r--compiler/loco/include/loco/IR/Use.h71
-rw-r--r--compiler/loco/include/loco/IR/Verifier.h100
-rw-r--r--compiler/loco/include/loco/IR/Window.h52
-rw-r--r--compiler/loco/include/loco/Service/CanonicalShapeInferenceRule.h38
-rw-r--r--compiler/loco/include/loco/Service/MultiDialectShapeInferenceRule.h45
-rw-r--r--compiler/loco/include/loco/Service/ShapeInference.h66
-rw-r--r--compiler/loco/include/loco/Service/ShapeInferenceRule.h97
-rw-r--r--compiler/loco/include/loco/Service/TypeInference.h114
62 files changed, 5241 insertions, 0 deletions
diff --git a/compiler/loco/include/loco.h b/compiler/loco/include/loco.h
new file mode 100644
index 000000000..5cc4487ea
--- /dev/null
+++ b/compiler/loco/include/loco.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_H__
+#define __LOCO_H__
+
+#include "loco/IR/Graph.h"
+#include "loco/IR/Algorithm.h"
+#include "loco/IR/Verifier.h"
+
+#include "loco/IR/PermutingCodec.h"
+
+#endif // __LOCO_H__
diff --git a/compiler/loco/include/loco/ADT/AnnotatedItem.h b/compiler/loco/include/loco/ADT/AnnotatedItem.h
new file mode 100644
index 000000000..be0d9ac1d
--- /dev/null
+++ b/compiler/loco/include/loco/ADT/AnnotatedItem.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_ADT_ANNOTATED_ITEM_H__
+#define __LOCO_ADT_ANNOTATED_ITEM_H__
+
+#include <map>
+#include <memory>
+#include <typeindex>
+
+namespace loco
+{
+
+template <typename Annotation> class AnnotatedItem
+{
+public:
+ AnnotatedItem() = default;
+
+public:
+ virtual ~AnnotatedItem() = default;
+
+public:
+ /**
+ * @brief Retrieve a stored annotation of type T
+ *
+ * @note This method returns nullptr if annotation does not exist
+ */
+ template <typename T> const T *annot(void) const
+ {
+ // TODO Insert static_assert(T derives Annotation);
+
+ auto it = _attrs.find(typeid(T));
+
+ if (it == _attrs.end())
+ {
+ return nullptr;
+ }
+
+ // TODO Insert null check
+ return dynamic_cast<T *>(it->second.get());
+ }
+
+ /**
+ * @brief Attach or remove a new annotation of type T
+ *
+ * @note annot<T>(nullptr) removes an attached annotation if it exists
+ */
+ template <typename T> void annot(std::unique_ptr<T> &&p)
+ {
+ // TODO: Insert static_assert(T derives Annotation);
+
+ if (p == nullptr)
+ {
+ _attrs.erase(typeid(T));
+ }
+ else
+ {
+ // TODO: assert(_attribs.find(typeid(T)) == _attribs.end());
+ _attrs[typeid(T)] = std::move(p);
+ }
+ }
+
+private:
+ std::map<std::type_index, std::unique_ptr<Annotation>> _attrs;
+};
+
+} // namespace loco
+
+#endif // __LOCO_ADT_ANNOTATED_ITEM_H__
diff --git a/compiler/loco/include/loco/ADT/ObjectPool.h b/compiler/loco/include/loco/ADT/ObjectPool.h
new file mode 100644
index 000000000..3f3a25c16
--- /dev/null
+++ b/compiler/loco/include/loco/ADT/ObjectPool.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_ADT_OBJECT_POOL_H__
+#define __LOCO_ADT_OBJECT_POOL_H__
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+namespace loco
+{
+
+/**
+ * @brief Object Pool
+ * @note ObjectPool owns registered objects.
+ */
+template <typename T> class ObjectPool
+{
+public:
+ virtual ~ObjectPool() = default;
+
+public:
+ /// @brief Return the number of objects
+ uint32_t size(void) const { return _pool.size(); }
+
+ /// @brief Access N-th object
+ T *at(uint32_t n) const { return _pool.at(n).get(); }
+
+protected:
+ /// @brief Take the ownership of a given object and returns its raw pointer
+ template <typename U> U *take(std::unique_ptr<U> &&o)
+ {
+ auto res = o.get();
+ _pool.emplace_back(std::move(o));
+ return res;
+ }
+
+ /**
+ * @brief Erase an object from the pool
+ *
+ * erase(p) returns false if p does not belong to this object pool.
+ */
+ bool erase(T *ptr)
+ {
+ auto pred = [ptr](const std::unique_ptr<T> &o) { return o.get() == ptr; };
+ auto it = std::find_if(_pool.begin(), _pool.end(), pred);
+
+ if (it == _pool.end())
+ {
+ return false;
+ }
+
+ _pool.erase(it);
+ return true;
+ }
+
+private:
+ std::vector<std::unique_ptr<T>> _pool;
+};
+
+} // namespace loco
+
+#endif // __LOCO_ADT_OBJECT_POOL_H__
diff --git a/compiler/loco/include/loco/IR/Algorithm.h b/compiler/loco/include/loco/IR/Algorithm.h
new file mode 100644
index 000000000..f7812e85d
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Algorithm.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_ALGORITHM_H__
+#define __LOCO_IR_ALGORITHM_H__
+
+#include "loco/IR/Node.h"
+
+#include <set>
+#include <vector>
+
+namespace loco
+{
+
+/**
+ * @brief Generate postorder traversal sequence starting from "roots"
+ *
+ * HOW TO USE
+ *
+ * for (auto node : postorder_traversal(...))
+ * {
+ * ... node->do_something() ...
+ * }
+ *
+ */
+std::vector<loco::Node *> postorder_traversal(const std::vector<loco::Node *> &roots);
+
+/**
+ * @brief Enumerate all the nodes required to compute "roots"
+ */
+std::set<loco::Node *> active_nodes(const std::vector<loco::Node *> &roots);
+
+} // namespace loco
+
+#endif // __LOCO_IR_ALGORITHM_H__
diff --git a/compiler/loco/include/loco/IR/BiasShape.h b/compiler/loco/include/loco/IR/BiasShape.h
new file mode 100644
index 000000000..037b0873e
--- /dev/null
+++ b/compiler/loco/include/loco/IR/BiasShape.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_BIAS_SHAPE_H__
+#define __LOCO_IR_BIAS_SHAPE_H__
+
+#include "loco/IR/Dimension.h"
+
+namespace loco
+{
+
+/**
+ * \brief Bias Shape
+ */
+class BiasShape final
+{
+public:
+ BiasShape() = default;
+
+public:
+ const Dimension &length(void) const { return _length; }
+ Dimension &length(void) { return _length; }
+
+private:
+ Dimension _length;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_BIAS_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalDialect.h b/compiler/loco/include/loco/IR/CanonicalDialect.h
new file mode 100644
index 000000000..940d29a59
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalDialect.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_DIALECT_H__
+#define __LOCO_IR_CANONICAL_DIALECT_H__
+
+#include "loco/IR/Dialect.h"
+
+namespace loco
+{
+
+/**
+ * @brief A singleton for Canonical Dialect
+ *
+ * CanonicalDialect serves as an in-memory unique identifier.
+ */
+class CanonicalDialect final : public Dialect
+{
+private:
+ CanonicalDialect();
+
+public:
+ CanonicalDialect(const CanonicalDialect &) = delete;
+ CanonicalDialect(CanonicalDialect &&) = delete;
+
+public:
+ static Dialect *get(void);
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_CANONICAL_DIALECT_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalNode.h b/compiler/loco/include/loco/IR/CanonicalNode.h
new file mode 100644
index 000000000..2dcc02e5d
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalNode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_NODE_H__
+#define __LOCO_IR_CANONICAL_NODE_H__
+
+#include "loco/IR/CanonicalNodeDecl.h"
+#include "loco/IR/CanonicalNodeImpl.h"
+
+#endif // __LOCO_IR_CANONICAL_NODE_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalNodeDecl.h b/compiler/loco/include/loco/IR/CanonicalNodeDecl.h
new file mode 100644
index 000000000..872edbb3e
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalNodeDecl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_NODE_DECL_H__
+#define __LOCO_IR_CANONICAL_NODE_DECL_H__
+
+#include "loco/IR/Node.h"
+#include "loco/IR/Dialect.h"
+#include "loco/IR/CanonicalOpcode.h"
+#include "loco/IR/CanonicalNodeVisitor.forward.h"
+
+namespace loco
+{
+
+struct CanonicalNode : public Node
+{
+ virtual ~CanonicalNode() = default;
+
+ const Dialect *dialect(void) const final;
+ virtual CanonicalOpcode opcode(void) const = 0;
+
+ template <typename T> T accept(CanonicalNodeVisitorBase<T> *) const;
+ template <typename T> T accept(CanonicalNodeMutableVisitorBase<T> *);
+};
+
+template <CanonicalOpcode Code, template <typename T> class... Mixins>
+struct CanonicalNodeDef : public virtual CanonicalNode, public Mixins<CanonicalNode>...
+{
+ virtual ~CanonicalNodeDef() = default;
+
+ uint32_t opnum(void) const final { return static_cast<uint32_t>(Code); }
+ CanonicalOpcode opcode(void) const final { return Code; }
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_CANONICAL_NODE_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalNodeImpl.h b/compiler/loco/include/loco/IR/CanonicalNodeImpl.h
new file mode 100644
index 000000000..73aa4caa5
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalNodeImpl.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_NODE_IMPL_H__
+#define __LOCO_IR_CANONICAL_NODE_IMPL_H__
+
+#include "loco/IR/Nodes.h"
+#include "loco/IR/CanonicalNodeVisitor.h"
+
+#include <stdexcept>
+
+namespace loco
+{
+
+template <typename T> T CanonicalNode::accept(CanonicalNodeVisitorBase<T> *v) const
+{
+ switch (this->opcode())
+ {
+#define CANONICAL_NODE(OPCODE, CLASS) \
+ case CanonicalOpcode::OPCODE: \
+ return v->visit(dynamic_cast<const CLASS *>(this));
+
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+ default:
+ break;
+ }
+
+ throw std::runtime_error{"NYI"};
+}
+
+template <typename T> T CanonicalNode::accept(CanonicalNodeMutableVisitorBase<T> *v)
+{
+ switch (this->opcode())
+ {
+#define CANONICAL_NODE(OPCODE, CLASS) \
+ case CanonicalOpcode::OPCODE: \
+ return v->visit(dynamic_cast<CLASS *>(this));
+
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+ default:
+ break;
+ }
+
+ throw std::runtime_error{"NYI"};
+}
+
+} // namespace loco
+
+#endif // __LOCO_IR_CANONICAL_NODE_IMPL_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalNodeVisitor.forward.h b/compiler/loco/include/loco/IR/CanonicalNodeVisitor.forward.h
new file mode 100644
index 000000000..425d77997
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalNodeVisitor.forward.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_NODE_VISITOR_FORWARD_H__
+#define __LOCO_IR_CANONICAL_NODE_VISITOR_FORWARD_H__
+
+namespace loco
+{
+
+// NOTE These forward declarations SHOULD BE aligned with "CanonicalNodeVisitor.h"
+template <typename T> struct CanonicalNodeVisitorBase;
+template <typename T> struct CanonicalNodeMutableVisitorBase;
+
+} // namespace loco
+
+#endif // __LOCO_IR_CANONICAL_NODE_VISITOR_FORWARD_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalNodeVisitor.h b/compiler/loco/include/loco/IR/CanonicalNodeVisitor.h
new file mode 100644
index 000000000..b9ffd5472
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalNodeVisitor.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_NODE_VISITOR_H__
+#define __LOCO_IR_CANONICAL_NODE_VISITOR_H__
+
+#include "loco/IR/Nodes.h"
+
+#include <stdexcept>
+
+namespace loco
+{
+
+/**
+ * DO NOT use this class. Use CanonicalNodeVisitor instead.
+ */
+template <typename T> struct CanonicalNodeVisitorBase
+{
+ virtual ~CanonicalNodeVisitorBase() = default;
+
+#define CANONICAL_NODE(OPCODE, CLASS) virtual T visit(const CLASS *) = 0;
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+};
+
+template <typename T> struct CanonicalNodeVisitor : public CanonicalNodeVisitorBase<T>
+{
+ virtual ~CanonicalNodeVisitor() = default;
+
+#define CANONICAL_NODE(OPCODE, CLASS) \
+ virtual T visit(const CLASS *node) { return visit(static_cast<const Node *>(node)); }
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+
+ /// @brief Default fallback
+ virtual T visit(const Node *) { throw std::runtime_error{"Not implemented, yet"}; }
+};
+
+/**
+ * DO NOT use this class. Use CanonicalNodeMutableVisitor instead.
+ */
+template <typename T> struct CanonicalNodeMutableVisitorBase
+{
+ virtual ~CanonicalNodeMutableVisitorBase() = default;
+
+#define CANONICAL_NODE(OPCODE, CLASS) virtual T visit(CLASS *) = 0;
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+};
+
+template <typename T> struct CanonicalNodeMutableVisitor : public CanonicalNodeMutableVisitorBase<T>
+{
+ virtual ~CanonicalNodeMutableVisitor() = default;
+
+#define CANONICAL_NODE(OPCODE, CLASS) \
+ virtual T visit(CLASS *node) { return visit(static_cast<Node *>(node)); }
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+
+ /// @brief Default fallback
+ virtual T visit(Node *) { throw std::runtime_error{"Not implemented, yet"}; }
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_CANONICAL_NODE_VISITOR_H__
diff --git a/compiler/loco/include/loco/IR/CanonicalNodes.lst b/compiler/loco/include/loco/IR/CanonicalNodes.lst
new file mode 100644
index 000000000..527856fbe
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalNodes.lst
@@ -0,0 +1,49 @@
+#ifndef CANONICAL_NODE
+#error "Define CANONICAL_NODE"
+#endif // CANONICAL_NODE
+
+//
+// PLEASE SORT NODE DECLS IN ALPHABETICAL ORDER
+//
+
+// CANONICAL_NODE(OPCODE, CLASS)
+CANONICAL_NODE(AvgPool2D, AvgPool2D)
+CANONICAL_NODE(BiasDecode, BiasDecode)
+CANONICAL_NODE(BiasEncode, BiasEncode)
+CANONICAL_NODE(ConstGen, ConstGen)
+CANONICAL_NODE(Conv2D, Conv2D)
+CANONICAL_NODE(DepthwiseConv2D, DepthwiseConv2D)
+CANONICAL_NODE(DepthwiseFilterDecode, DepthwiseFilterDecode)
+CANONICAL_NODE(DepthwiseFilterEncode, DepthwiseFilterEncode)
+CANONICAL_NODE(EltwiseAdd, EltwiseAdd)
+CANONICAL_NODE(EltwiseDiv, EltwiseDiv)
+CANONICAL_NODE(EltwiseMax, EltwiseMax)
+CANONICAL_NODE(EltwiseMul, EltwiseMul)
+CANONICAL_NODE(EltwiseSqrt, EltwiseSqrt)
+CANONICAL_NODE(EltwiseSub, EltwiseSub)
+CANONICAL_NODE(FeatureBiasAdd, BiasAdd<Domain::Feature>)
+CANONICAL_NODE(FeatureDecode, FeatureDecode)
+CANONICAL_NODE(FeatureEncode, FeatureEncode)
+CANONICAL_NODE(FilterDecode, FilterDecode)
+CANONICAL_NODE(FilterEncode, FilterEncode)
+CANONICAL_NODE(FixedReshape, Reshape<ReshapeType::Fixed>)
+CANONICAL_NODE(Forward, Forward)
+CANONICAL_NODE(MaxPool2D, MaxPool2D)
+// WARN Push may be excluded from canoncial dialect in the future
+CANONICAL_NODE(Push, Push)
+// WARN Pull may be excluded from canoncial dialect in the future
+CANONICAL_NODE(Pull, Pull)
+CANONICAL_NODE(ReLU, ReLU)
+CANONICAL_NODE(ReLU6, ReLU6)
+CANONICAL_NODE(Tanh, Tanh)
+CANONICAL_NODE(TensorConcat, TensorConcat)
+CANONICAL_NODE(TensorConstantPad, TensorConstantPad)
+CANONICAL_NODE(TensorBiasAdd, BiasAdd<Domain::Tensor>)
+CANONICAL_NODE(TensorBroadcast, TensorBroadcast)
+CANONICAL_NODE(TensorReduce, TensorReduce)
+CANONICAL_NODE(TensorTranspose, TensorTranspose)
+CANONICAL_NODE(TensorSoftmax, Softmax<Domain::Tensor>)
+CANONICAL_NODE(TransposedConv2D, TransposedConv2D)
+CANONICAL_NODE(MatrixEncode, MatrixEncode)
+CANONICAL_NODE(MatrixDecode, MatrixDecode)
+CANONICAL_NODE(MatMul, MatMul)
diff --git a/compiler/loco/include/loco/IR/CanonicalOpcode.h b/compiler/loco/include/loco/IR/CanonicalOpcode.h
new file mode 100644
index 000000000..58aa7de6d
--- /dev/null
+++ b/compiler/loco/include/loco/IR/CanonicalOpcode.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_CANONICAL_OPCODE_H__
+#define __LOCO_IR_CANONICAL_OPCODE_H__
+
+namespace loco
+{
+
+/**
+ * @brief Canonical Node Opcode
+ *
+ * WARNING The order is subject to change. DO NOT serialize this value.
+ */
+enum class CanonicalOpcode
+{
+#define CANONICAL_NODE(OPCODE, CLASS) OPCODE,
+#include "CanonicalNodes.lst"
+#undef CANONICAL_NODE
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_CANONICAL_OPCODE_H__
diff --git a/compiler/loco/include/loco/IR/DataType.h b/compiler/loco/include/loco/IR/DataType.h
new file mode 100644
index 000000000..b07022bf5
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DataType.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DATA_TYPE_H__
+#define __LOCO_IR_DATA_TYPE_H__
+
+namespace loco
+{
+
+/**
+ * @brief "scalar" value type
+ */
+enum class DataType
+{
+ Unknown, // Unknown type (serves as a default value)
+
+ U8, // 8-bit unsigned integer
+ U16, // 16-bit unsigned integer
+ U32, // 32-bit unsigned integer
+ U64, // 64-bit unsigned integer
+
+ S8, // 8-bit signed integer
+ S16, // 16-bit signed integer
+ S32, // 32-bit signed integer
+ S64, // 64-bit signed integer
+
+ FLOAT16, // IEEE 16-bit floating-point
+ FLOAT32, // IEEE 32-bit floating-point
+ FLOAT64, // IEEE 64-bit floating-point
+
+ // WARNING the size of Bool may vary for NN frameworks
+ // TODO we need to find a way to resolve this issue
+ BOOL, // Boolean
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DATA_TYPE_H__
diff --git a/compiler/loco/include/loco/IR/DataTypeTraits.h b/compiler/loco/include/loco/IR/DataTypeTraits.h
new file mode 100644
index 000000000..c4479e545
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DataTypeTraits.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DATA_TYPE_TRAITS_H__
+#define __LOCO_IR_DATA_TYPE_TRAITS_H__
+
+#include "loco/IR/DataType.h"
+
+#include <cassert>
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * @brief C++ scalar type corresponding to each DataType
+ */
+template <DataType DT> struct DataTypeImpl
+{
+ // using Type = ...
+};
+
+// TODO Support other enum values
+template <> struct DataTypeImpl<DataType::S8>
+{
+ // Use C++ int8_t type for 8bit integer
+ using Type = int8_t;
+};
+
+template <> struct DataTypeImpl<DataType::U8>
+{
+ // Use C++ uint8_t type for unsigned 8bit integer
+ using Type = uint8_t;
+};
+
+template <> struct DataTypeImpl<DataType::S32>
+{
+ // Use C++ int32_t type for 32bit integer
+ using Type = int32_t;
+};
+
+template <> struct DataTypeImpl<DataType::FLOAT32>
+{
+ // Use C++ float type for IEEE 32-bit floating-point numbers
+ using Type = float;
+};
+
+/**
+ * @brief Returns the size of the data type.
+ * @note If you need the size at compile time, use `sizeof(typename DataTypeImpl<DT>::Type)`.
+ */
+inline uint32_t size(DataType data_type)
+{
+ switch (data_type)
+ {
+ case DataType::S8:
+ return sizeof(DataTypeImpl<DataType::S8>::Type);
+ case DataType::U8:
+ return sizeof(DataTypeImpl<DataType::U8>::Type);
+ case DataType::S32:
+ return sizeof(DataTypeImpl<DataType::S32>::Type);
+ case DataType::FLOAT32:
+ return sizeof(DataTypeImpl<DataType::FLOAT32>::Type);
+ default:
+ // TODO Support remaining data types.
+ assert(false);
+ return UINT32_MAX; // Avoid compiler warning.
+ }
+}
+
+} // namespace loco
+
+#endif // __LOCO_IR_DATA_TYPE_TRAITS_H__
diff --git a/compiler/loco/include/loco/IR/DepthwiseFilterAxis.h b/compiler/loco/include/loco/IR/DepthwiseFilterAxis.h
new file mode 100644
index 000000000..eb4650ec9
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DepthwiseFilterAxis.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DEPTHWISE_FILTER_AXIS_H__
+#define __LOCO_IR_DEPTHWISE_FILTER_AXIS_H__
+
+namespace loco
+{
+
+enum class DepthwiseFilterAxis
+{
+ Depth,
+ Multiplier,
+ Height,
+ Width
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DEPTHWISE_FILTER_AXIS_H__
diff --git a/compiler/loco/include/loco/IR/DepthwiseFilterCodec.h b/compiler/loco/include/loco/IR/DepthwiseFilterCodec.h
new file mode 100644
index 000000000..0d9286b46
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DepthwiseFilterCodec.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DEPTHWISE_FILTER_CODEC_H__
+#define __LOCO_IR_DEPTHWISE_FILTER_CODEC_H__
+
+#include "loco/IR/DepthwiseFilterShape.h"
+#include "loco/IR/DepthwiseFilterIndex.h"
+
+#include "loco/IR/TensorShape.h"
+#include "loco/IR/TensorIndex.h"
+
+namespace loco
+{
+
+/**
+ * @brief Describe how to build a depthwise convolution filter from a tensor
+ *
+ * Let us assume that "enc" is a depthwise filter encoder.
+ *
+ * Given a tensor "inp" and its shape "inp.shape", "enc" builds a depthwise filter
+ * "out" as follows:
+ *
+ * for each valid filter_index for enc.shape(inp.shape)
+ * out.at(filter_index) = inp.at(enc.value(filter_index))
+ */
+struct DepthwiseFilterEncoder
+{
+ virtual ~DepthwiseFilterEncoder() = default;
+
+ virtual DepthwiseFilterShape shape(const TensorShape &shape) const = 0;
+ virtual TensorIndex value(const DepthwiseFilterIndex &index) const = 0;
+};
+
+/**
+ * @brief Describe how to build a tensor from a depthwise convolution filter
+ *
+ * Let us assume that "dec" is a depthwise filter decoder.
+ *
+ * Given a depthwise filter "inp" and its shape "inp.shape", "dec" builds a tensor
+ * "out" as follows:
+ *
+ * for each valid tensor_index for dec.shape(inp.shape)
+ * out.at(tensor_index) = inp.at(dec.value(tensor_index))
+ */
+struct DepthwiseFilterDecoder
+{
+ virtual ~DepthwiseFilterDecoder() = default;
+
+ virtual TensorShape shape(const DepthwiseFilterShape &shape) const = 0;
+ virtual DepthwiseFilterIndex value(const TensorIndex &index) const = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DEPTHWISE_FILTER_CODEC_H__
diff --git a/compiler/loco/include/loco/IR/DepthwiseFilterIndex.h b/compiler/loco/include/loco/IR/DepthwiseFilterIndex.h
new file mode 100644
index 000000000..884e50a56
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DepthwiseFilterIndex.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DEPTHWISE_FILTER_INDEX_H__
+#define __LOCO_IR_DEPTHWISE_FILTER_INDEX_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * @brief DepthwiseFilter Index
+ *
+ * DepthwiseFilter Index indicates an "element" in a given Depthwise convolution filter.
+ *
+ * Assume there is a filter K where KS denotes its shape (of DepthwiseFilterShape type).
+ *
+ * Then, any valid filter index I satisfies the following invariants:
+ * - 0 <= I.channel() < KS.depth()
+ * - 0 <= I.nth() < KS.multiplier()
+ * - 0 <= I.row() < KS.height()
+ * - 0 <= I.column() < KS.width()
+ */
+class DepthwiseFilterIndex final
+{
+public:
+ DepthwiseFilterIndex() = default;
+
+public:
+ const uint32_t &channel(void) const { return _channel; }
+ uint32_t &channel(void) { return _channel; }
+
+ const uint32_t &nth(void) const { return _nth; }
+ uint32_t &nth(void) { return _nth; }
+
+ const uint32_t &row(void) const { return _row; }
+ uint32_t &row(void) { return _row; }
+
+ const uint32_t &column(void) const { return _column; }
+ uint32_t &column(void) { return _column; }
+
+private:
+ uint32_t _channel = 0;
+ uint32_t _nth = 0;
+ uint32_t _row = 0;
+ uint32_t _column = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DEPTHWISE_FILTER_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/DepthwiseFilterShape.h b/compiler/loco/include/loco/IR/DepthwiseFilterShape.h
new file mode 100644
index 000000000..eb1a1e335
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DepthwiseFilterShape.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DEPTHWISE_FILTER_SHAPE_H__
+#define __LOCO_IR_DEPTHWISE_FILTER_SHAPE_H__
+
+#include "loco/IR/Dimension.h"
+
+namespace loco
+{
+
+/**
+ * @brief DepthwiseFilter Shape
+ *
+ * This class describes the shape of depthwise filter, which is an input of depthwise 2D
+ * convolutional operation.
+ *
+ * depth() refers to expected channel depth of matching input
+ * multiplier() refers to number of traverse for one input
+ * height() refers to the height of 2D weights
+ * width() refers to the width of 2D weights
+ */
+class DepthwiseFilterShape final
+{
+public:
+ DepthwiseFilterShape() = default;
+
+public:
+ const Dimension &depth(void) const { return _depth; }
+ Dimension &depth(void) { return _depth; }
+
+ const Dimension &multiplier(void) const { return _multiplier; }
+ Dimension &multiplier(void) { return _multiplier; }
+
+ const Dimension &height(void) const { return _height; }
+ Dimension &height(void) { return _height; }
+
+ const Dimension &width(void) const { return _width; }
+ Dimension &width(void) { return _width; }
+
+private:
+ Dimension _depth;
+ Dimension _multiplier;
+ Dimension _height;
+ Dimension _width;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DEPTHWISE_FILTER_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/Dialect.h b/compiler/loco/include/loco/IR/Dialect.h
new file mode 100644
index 000000000..b8942bfb4
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Dialect.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DIALECT_H__
+#define __LOCO_IR_DIALECT_H__
+
+#include "loco/IR/DialectService.h"
+
+#include <map>
+#include <memory>
+#include <typeindex>
+#include <typeinfo>
+
+namespace loco
+{
+
+/**
+ * @brief Dialect interface
+ *
+ * Each dialect implementation is expected to have static "get" method
+ * which returns "const Dialect *" value.
+ */
+class Dialect
+{
+public:
+ virtual ~Dialect() = default;
+
+protected:
+ template <typename ConcreteService> void service(std::unique_ptr<ConcreteService> &&s)
+ {
+ _services[typeid(ConcreteService)] = std::move(s);
+ }
+
+public:
+ template <typename ConcreteService> ConcreteService *service(void) const
+ {
+ auto it = _services.find(typeid(ConcreteService));
+
+ if (it == _services.end())
+ {
+ return nullptr;
+ }
+
+ return dynamic_cast<ConcreteService *>(it->second.get());
+ }
+
+private:
+ std::map<std::type_index, std::unique_ptr<DialectService>> _services;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DIALECT_H__
diff --git a/compiler/loco/include/loco/IR/DialectService.h b/compiler/loco/include/loco/IR/DialectService.h
new file mode 100644
index 000000000..54a3fac74
--- /dev/null
+++ b/compiler/loco/include/loco/IR/DialectService.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DIALECT_SERVICE_H__
+#define __LOCO_IR_DIALECT_SERVICE_H__
+
+namespace loco
+{
+
+/**
+ * @brief Dialect Service interface
+ *
+ * Every service that each dialect exposes should inherit this interface.
+ */
+struct DialectService
+{
+ virtual ~DialectService() = default;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DIALECT_SERVICE_H__
diff --git a/compiler/loco/include/loco/IR/Dimension.h b/compiler/loco/include/loco/IR/Dimension.h
new file mode 100644
index 000000000..7b5d5943f
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Dimension.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DIMENSION_H__
+#define __LOCO_IR_DIMENSION_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * @brief The value of one dimension in a tensor shape
+ * @note The value may be unknown
+ */
+class Dimension final
+{
+private:
+ enum class Kind
+ {
+ Known,
+ Unknown
+ };
+
+public:
+ // @brief Construct an "unknown" dimension
+ Dimension() = default;
+
+ // @brief Construct a "known" dimension
+ Dimension(uint32_t value) { set(value); }
+
+public:
+ // @brief Return whether the value is known (or not)
+ bool known(void) const { return _kind == Kind::Known; }
+
+ // @brief Return the value
+ // @note This value is meaningful only for known dimension
+ uint32_t value(void) const { return _value; }
+
+ void set(uint32_t value)
+ {
+ _kind = Kind::Known;
+ _value = value;
+ }
+
+ void unset(void)
+ {
+ _kind = Kind::Unknown;
+ _value = 0;
+ }
+
+private:
+ Kind _kind{Kind::Unknown};
+ uint32_t _value{0};
+};
+
+/**
+ * @brief Equality operator between two Dimensions
+ *
+ * @note Refer to the definition of equality of dimemsion at
+ * https://www.tensorflow.org/api_docs/python/tf/Dimension#__eq__
+ */
+bool operator==(const Dimension &, const Dimension &);
+bool operator==(const Dimension &, uint32_t);
+bool operator==(uint32_t, const Dimension &);
+
+// @brief Make an "unknown" dimension
+Dimension make_dimension(void);
+
+} // namespace loco
+
+#endif // __LOCO_IR_DIMENSION_H__
diff --git a/compiler/loco/include/loco/IR/Domain.h b/compiler/loco/include/loco/IR/Domain.h
new file mode 100644
index 000000000..823bc1833
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Domain.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_DOMAIN_H__
+#define __LOCO_IR_DOMAIN_H__
+
+namespace loco
+{
+
+/**
+ * @brief Describe the kind of (N-dimensional) loco values
+ *
+ * loco is an intermediate representation for neural network compiler, which mainly focuses on
+ * N-dimensional values (usually referred to as Tensor).
+ *
+ * There are several special cases for N-dimensional values according to its usage. For example,
+ * vision community often refers to 4D array as "FeatureMap".
+ *
+ * It is definitely possible to represent all of these special cases using Tensor, but that scheme
+ * may introduces some confusion (e.g. NCHW vs NHWC issue).
+ *
+ * loco distinguishes these special cases from Tensor in order to reduce such confusion.
+ *
+ * This "Domain" enum class enumerates all of these special cases that loco supports.
+ */
+enum class Domain
+{
+ Unknown,
+ Tensor,
+ Feature,
+ Filter, /* 2D Convolution Filter */
+ DepthwiseFilter, /* Depthwise 2D Convolution Filter */
+ Bias,
+ Matrix,
+ /* ... */
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_DOMAIN_H__
diff --git a/compiler/loco/include/loco/IR/FeatureAxis.h b/compiler/loco/include/loco/IR/FeatureAxis.h
new file mode 100644
index 000000000..cf020edd2
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FeatureAxis.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FEATURE_AXIS_H__
+#define __LOCO_IR_FEATURE_AXIS_H__
+
+namespace loco
+{
+
+enum class FeatureAxis
+{
+ Count,
+ Depth,
+ Height,
+ Width
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FEATURE_AXIS_H__
diff --git a/compiler/loco/include/loco/IR/FeatureCodec.h b/compiler/loco/include/loco/IR/FeatureCodec.h
new file mode 100644
index 000000000..93094e13a
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FeatureCodec.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FEATURE_CODEC_H__
+#define __LOCO_IR_FEATURE_CODEC_H__
+
+#include "loco/IR/FeatureShape.h"
+#include "loco/IR/FeatureIndex.h"
+
+#include "loco/IR/TensorShape.h"
+#include "loco/IR/TensorIndex.h"
+
+#include <memory>
+
+namespace loco
+{
+
+/**
+ * @brief Decribe how to build a (convolution) feature map from a tensor
+ *
+ * Let us assume that "enc" is a feature encoder.
+ *
+ * Given a tensor "inp" and its shape "inp.shape", "enc" builds a feature map
+ * "out" as follows:
+ *
+ * for each valid feature index (referred to as feature_idx below) for enc.shape(inp.shape)
+ * out.at(feature_index) = inp.at(enc.value(feature_index))
+ */
+struct FeatureEncoder
+{
+ virtual ~FeatureEncoder() = default;
+
+ virtual FeatureShape shape(const TensorShape &shape) const = 0;
+ virtual TensorIndex value(const FeatureIndex &index) const = 0;
+
+ virtual std::unique_ptr<FeatureEncoder> clone(void) const = 0;
+};
+
+/**
+ * @brief Describe how to build a tensor from a (convolution) feature map
+ *
+ * Let us assume that "dec" is a feature decoder.
+ *
+ * Given a feature map "inp" and its shape "inp.shape", "dec" builds a tensor
+ * "out" as follows:
+ *
+ * for each valid tensor index (referred to as tensor_index below) for dec.shape(inp.shape)
+ * out.at(tensor_index) = inp.at(dec.value(tensor_index))
+ *
+ * NOTE "inp" is a feature value and "out" is a tensor value in this example.
+ */
+struct FeatureDecoder
+{
+ virtual ~FeatureDecoder() = default;
+
+ virtual TensorShape shape(const FeatureShape &) const = 0;
+ virtual FeatureIndex value(const TensorIndex &) const = 0;
+
+ virtual std::unique_ptr<FeatureDecoder> clone(void) const = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FEATURE_CODEC_H__
diff --git a/compiler/loco/include/loco/IR/FeatureIndex.h b/compiler/loco/include/loco/IR/FeatureIndex.h
new file mode 100644
index 000000000..007f94491
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FeatureIndex.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FEATURE_INDEX_H__
+#define __LOCO_IR_FEATURE_INDEX_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * \brief Feature Index
+ *
+ * Feature Index indicates an "element" in a given feature map.
+ *
+ * Let us assume that there is a feature map F and S denotes its shape (of FeatureShape type).
+ *
+ * Then, any valid feature index I satisfies the following invariants:
+ * - 0 <= I.batch() < S.count()
+ * - 0 <= I.channel() < S.depth()
+ * - 0 <= I.row() < S.height()
+ * - 0 <= I.column() < S.width()
+ */
+class FeatureIndex final
+{
+public:
+ FeatureIndex() = default;
+
+public:
+ const uint32_t &batch(void) const { return _batch; }
+ uint32_t &batch(void) { return _batch; }
+
+ const uint32_t &channel(void) const { return _channel; }
+ uint32_t &channel(void) { return _channel; }
+
+ const uint32_t &row(void) const { return _row; }
+ uint32_t &row(void) { return _row; }
+
+ const uint32_t &column(void) const { return _column; }
+ uint32_t &column(void) { return _column; }
+
+private:
+ uint32_t _batch = 0;
+ uint32_t _channel = 0;
+ uint32_t _row = 0;
+ uint32_t _column = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FEATURE_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/FeatureShape.h b/compiler/loco/include/loco/IR/FeatureShape.h
new file mode 100644
index 000000000..d09a2b2b8
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FeatureShape.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FEATURE_SHAPE_H__
+#define __LOCO_IR_FEATURE_SHAPE_H__
+
+#include "loco/IR/Dimension.h"
+
+namespace loco
+{
+
+/**
+ * \brief Feature Map Shape
+ *
+ * This class describes the shape of feature maps, which serves as the input/output of 2D
+ * convolutional operations (e.g. Convolution).
+ *
+ * Each feature map is a collection of 3D features conceptually.
+ * Each feature has depth, height, width.
+ *
+ * count() refers to the number of features in a feature map
+ * depth() refers to the depth of features in a given feature map
+ * height() refers to the height of features in a given feature map
+ * width() refers to the width of features in a given feature map
+ */
+class FeatureShape final
+{
+public:
+ FeatureShape() = default;
+
+public:
+ const Dimension &count(void) const { return _count; }
+ Dimension &count(void) { return _count; }
+
+ const Dimension &depth(void) const { return _depth; }
+ Dimension &depth(void) { return _depth; }
+
+ const Dimension &height(void) const { return _height; }
+ Dimension &height(void) { return _height; }
+
+ const Dimension &width(void) const { return _width; }
+ Dimension &width(void) { return _width; }
+
+private:
+ Dimension _count;
+ Dimension _depth;
+ Dimension _height;
+ Dimension _width;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FEATURE_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/FilterAxis.h b/compiler/loco/include/loco/IR/FilterAxis.h
new file mode 100644
index 000000000..269e2aecc
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FilterAxis.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FILTER_AXIS_H__
+#define __LOCO_IR_FILTER_AXIS_H__
+
+namespace loco
+{
+
+enum class FilterAxis
+{
+ Count,
+ Depth,
+ Height,
+ Width
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FILTER_AXIS_H__
diff --git a/compiler/loco/include/loco/IR/FilterCodec.h b/compiler/loco/include/loco/IR/FilterCodec.h
new file mode 100644
index 000000000..3ff548d6d
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FilterCodec.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FILTER_CODEC_H__
+#define __LOCO_IR_FILTER_CODEC_H__
+
+#include "loco/IR/FilterShape.h"
+#include "loco/IR/FilterIndex.h"
+
+#include "loco/IR/TensorShape.h"
+#include "loco/IR/TensorIndex.h"
+
+namespace loco
+{
+
+/**
+ * @brief Decribe how to build a (convolution) filter from a tensor
+ *
+ * Let us assume that "enc" is a filter encoder.
+ *
+ * Given a tensor "inp" and its shape "inp.shape", "enc" builds a filter
+ * "out" as follows:
+ *
+ * for each valid filter index (referred to as filter_index below) for enc.shape(inp.shape)
+ * out.at(filter_index) = inp.at(enc.value(filter_index))
+ */
+struct FilterEncoder
+{
+ virtual ~FilterEncoder() = default;
+
+ virtual FilterShape shape(const TensorShape &shape) const = 0;
+ virtual TensorIndex value(const FilterIndex &index) const = 0;
+};
+
+/**
+ * @brief Decribe how to build a a tensor from a filter
+ */
+struct FilterDecoder
+{
+ virtual ~FilterDecoder() = default;
+
+ virtual TensorShape shape(const FilterShape &shape) const = 0;
+ virtual FilterIndex value(const TensorIndex &index) const = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FILTER_CODEC_H__
diff --git a/compiler/loco/include/loco/IR/FilterIndex.h b/compiler/loco/include/loco/IR/FilterIndex.h
new file mode 100644
index 000000000..5765ea764
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FilterIndex.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FILTER_INDEX_H__
+#define __LOCO_IR_FILTER_INDEX_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * \brief Filter Index
+ *
+ * Filter Index indicates an "element" in a given (convolutional) filter.
+ *
+ * Let us assume that there is a filter K where KS denotes its shape (of FilterShape type).
+ *
+ * Then, any valid filter index I satisfies the following invariants:
+ * - 0 <= I.nth() < KS.count()
+ * - 0 <= I.channel() < KS.depth()
+ * - 0 <= I.row() < KS.height()
+ * - 0 <= I.column() < KS.width()
+ */
+class FilterIndex final
+{
+public:
+ FilterIndex() = default;
+
+public:
+ const uint32_t &nth(void) const { return _nth; }
+ uint32_t &nth(void) { return _nth; }
+
+ const uint32_t &channel(void) const { return _channel; }
+ uint32_t &channel(void) { return _channel; }
+
+ const uint32_t &row(void) const { return _row; }
+ uint32_t &row(void) { return _row; }
+
+ const uint32_t &column(void) const { return _column; }
+ uint32_t &column(void) { return _column; }
+
+private:
+ uint32_t _nth = 0;
+ uint32_t _channel = 0;
+ uint32_t _row = 0;
+ uint32_t _column = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FILTER_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/FilterShape.h b/compiler/loco/include/loco/IR/FilterShape.h
new file mode 100644
index 000000000..00e44892a
--- /dev/null
+++ b/compiler/loco/include/loco/IR/FilterShape.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_FILTER_SHAPE_H__
+#define __LOCO_IR_FILTER_SHAPE_H__
+
+#include "loco/IR/Dimension.h"
+
+namespace loco
+{
+
+/**
+ * \brief Filter Shape
+ *
+ * This class describes the shape of filter, which is an input of 2D
+ * convolutional operations (e.g. Convolution).
+ *
+ * count() refers to the number of 3D weight in a filter
+ * depth() refers to the depth of 3D weights
+ * height() refers to the height of 3D weights
+ * width() refers to the width of 3D weights
+ *
+ * NOTE
+ *
+ * The definition of FilterShape is almost same as that of FeatureShape, but loco
+ * distinguishes FeatureShape and FilterShape in class-level in order to prevent
+ * potential errors by type check.
+ */
+class FilterShape final
+{
+public:
+ FilterShape() = default;
+
+public:
+ const Dimension &count(void) const { return _count; }
+ Dimension &count(void) { return _count; }
+
+ const Dimension &depth(void) const { return _depth; }
+ Dimension &depth(void) { return _depth; }
+
+ const Dimension &height(void) const { return _height; }
+ Dimension &height(void) { return _height; }
+
+ const Dimension &width(void) const { return _width; }
+ Dimension &width(void) { return _width; }
+
+private:
+ Dimension _count;
+ Dimension _depth;
+ Dimension _height;
+ Dimension _width;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_FILTER_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/Graph.forward.h b/compiler/loco/include/loco/IR/Graph.forward.h
new file mode 100644
index 000000000..2a43be93a
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Graph.forward.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_GRAPH_FORWARD_H__
+#define __LOCO_IR_GRAPH_FORWARD_H__
+
+namespace loco
+{
+
+// This forward declaration SHOULD BE aligned with the actual declaration in "Graph.h".
+class Graph;
+
+} // namespace loco
+
+#endif // __LOCO_IR_GRAPH_FORWARD_H__
diff --git a/compiler/loco/include/loco/IR/Graph.h b/compiler/loco/include/loco/IR/Graph.h
new file mode 100644
index 000000000..a820aba91
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Graph.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_GRAPH_H__
+#define __LOCO_IR_GRAPH_H__
+
+#include "loco/IR/DataType.h"
+// TODO Include "Node.h" instead
+#include "loco/IR/Nodes.h"
+#include "loco/IR/NodePool.h"
+#include "loco/IR/GraphInputIndex.h"
+#include "loco/IR/GraphOutputIndex.h"
+
+#include "loco/ADT/ObjectPool.h"
+
+#include <initializer_list>
+#include <set>
+#include <string>
+#include <memory>
+#include <vector>
+
+namespace loco
+{
+
+// TODO Introduce Named trait
+enum class Trait
+{
+ // Any "DataTyped" class has the following methods
+ // - DataType dtype(void) const;
+ // - void dtype(const DataType &value);
+ DataTyped,
+ // Any "TensorShaped" class has the following methods
+ // - const TensorShape *shape(void) const;
+ // - void shape(std::unique_ptr<TensorShape> &&);
+ // - void shape(std::initializer_list<Dimension> &&);
+ //
+ // TODO Rename NodeMixin::TensorShape as NodeMixin::NDShape
+ TensorShaped,
+};
+
+template <Trait T> class Mixin;
+
+// TODO Re-implement NodeMixin<NodeTrait::DataType> using this mixin
+template <> class Mixin<Trait::DataTyped>
+{
+public:
+ Mixin() = default;
+
+public:
+ const DataType &dtype(void) const { return _dtype; }
+ void dtype(const DataType &value) { _dtype = value; }
+
+private:
+ DataType _dtype = DataType::Unknown;
+};
+
+template <> class Mixin<Trait::TensorShaped>
+{
+public:
+ Mixin() = default;
+
+public:
+ const TensorShape *shape(void) const { return _shape.get(); }
+ void shape(std::unique_ptr<TensorShape> &&shape) { _shape = std::move(shape); }
+ void shape(std::initializer_list<Dimension> dims);
+
+private:
+ std::unique_ptr<TensorShape> _shape = nullptr;
+};
+
+/**
+ * @brief Trait for elements with name
+ */
+class NamedEntity
+{
+public:
+ const std::string &name(void) const { return _name; }
+ void name(const std::string &name) { _name = name; }
+
+/// If new interface methods are added to this class they also will need to
+/// be added in `using` of this macro to get them visible from inherited classes
+#define LOCO_NAMED_ENTITY_EXPOSE using NamedEntity::name
+
+private:
+ std::string _name;
+};
+
+/**
+ * @brief Graph-level Input Metadata
+ */
+class GraphInput final : private NamedEntity,
+ public Mixin<Trait::DataTyped>,
+ public Mixin<Trait::TensorShaped>
+{
+public:
+ LOCO_NAMED_ENTITY_EXPOSE;
+
+ // TODO Use GraphInputIndex (instead of uint32_t)
+ GraphInput(uint32_t index) : _index{index}
+ {
+ // DO NOTHING
+ }
+
+ GraphInput(const GraphInput &) = delete;
+ GraphInput(GraphInput &&) = delete;
+
+ ~GraphInput() = default;
+
+public:
+ GraphInputIndex index(void) const { return _index; }
+
+private:
+ uint32_t _index;
+};
+
+/**
+ * @brief Graph-level Output Metadata
+ */
+class GraphOutput final : private NamedEntity,
+ public Mixin<Trait::DataTyped>,
+ public Mixin<Trait::TensorShaped>
+{
+public:
+ LOCO_NAMED_ENTITY_EXPOSE;
+
+ // TODO Use GraphOutputIndex (instead of uint32_t)
+ GraphOutput(uint32_t index) : _index{index}
+ {
+ // DO NOTHING
+ }
+
+ GraphOutput(const GraphOutput &) = delete;
+ GraphOutput(GraphOutput &&) = delete;
+
+ ~GraphOutput() = default;
+
+public:
+ GraphOutputIndex index(void) const { return _index; }
+
+private:
+ uint32_t _index;
+};
+
+/**
+ * @brief A neural network graph
+ */
+class Graph final : public NamedEntity
+{
+public:
+ /**
+ * @brief Node Pool
+ *
+ * This alias confines the impact of changes to loco internals.
+ *
+ * TODO Remove this alias
+ */
+ using NodeContext = NodePool;
+
+ /**
+ * @brief Object Pool with Simple Factory Method
+ *
+ * TODO Remove this unused class
+ */
+ template <typename T> struct SimpleFactoryObjectPool : public ObjectPool<T>
+ {
+ virtual ~SimpleFactoryObjectPool() = default;
+
+ T *create(void)
+ {
+ std::unique_ptr<T> ptr{new T};
+ return ObjectPool<T>::take(std::move(ptr));
+ }
+ };
+
+ /**
+ * @brief GraphInput Pool
+ */
+ struct InputContext final : public ObjectPool<GraphInput>
+ {
+ GraphInput *create(void);
+ };
+
+ /**
+ * @brief GraphOutput Pool
+ */
+ struct OutputContext final : public ObjectPool<GraphOutput>
+ {
+ GraphOutput *create(void);
+ };
+
+public:
+ Graph()
+ {
+ // Associate "NodeContext" and the current "Graph"
+ _node_ctx.graph(this);
+ }
+
+ // Copy/Move is not allowed for Graph
+ Graph(const Graph &) = delete;
+ Graph(Graph &&) = delete;
+
+ ~Graph() = default;
+
+public:
+ NodeContext *nodes(void) { return &_node_ctx; }
+ const NodeContext *nodes(void) const { return &_node_ctx; }
+ InputContext *inputs(void) { return &_input_ctx; }
+ const InputContext *inputs(void) const { return &_input_ctx; }
+ OutputContext *outputs(void) { return &_output_ctx; }
+ const OutputContext *outputs(void) const { return &_output_ctx; }
+
+private:
+ NodeContext _node_ctx;
+ InputContext _input_ctx;
+ OutputContext _output_ctx;
+};
+
+struct GraphInputIndexQueryService : public DialectService
+{
+ virtual ~GraphInputIndexQueryService() = default;
+
+ /**
+ * @brief Check whether a given node is associated with any Graph-level input
+ */
+ virtual bool associated(const Node *node) const = 0;
+
+ /**
+ * Exceptions
+ * - index SHOULD throw std::invalid_argument exception if a given node is not associated with
+ * any input (i.e. assocaited above returns false).
+ */
+ virtual GraphInputIndex index(const Node *node) const = 0;
+};
+
+std::vector<Node *> input_nodes(const Graph *);
+
+struct GraphOutputIndexQueryService : public DialectService
+{
+ virtual ~GraphOutputIndexQueryService() = default;
+
+ /**
+ * @brief Check whether a given node is associated with any Graph-level output
+ */
+ virtual bool associated(const Node *node) const = 0;
+
+ /**
+ * Exceptions
+ * - index SHOULD throw std::invalid_argument exception if a given node is not associated with
+ * any output (i.e. assocaited above returns false).
+ */
+ virtual GraphOutputIndex index(const Node *node) const = 0;
+};
+
+// TODO Use "const Graph *"
+std::vector<Node *> output_nodes(Graph *);
+
+/**
+ * @brief Enumerate all the nodes in a given graph
+ *
+ * NOTE This method returns std::set<Node *> unlike input_nodes and output_nodes.
+ *
+ * Please use traverse algorithms that "Algorithm.h" provides (such as postorder_traversal)
+ * if order is relevant for implementation.
+ */
+std::set<Node *> all_nodes(Graph *);
+
+std::unique_ptr<Graph> make_graph(void);
+
+} // namespace loco
+
+#endif // __LOCO_IR_GRAPH_H__
diff --git a/compiler/loco/include/loco/IR/GraphInputIndex.h b/compiler/loco/include/loco/IR/GraphInputIndex.h
new file mode 100644
index 000000000..3c7ae98ef
--- /dev/null
+++ b/compiler/loco/include/loco/IR/GraphInputIndex.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_GRAPH_INPUT_INDEX_H__
+#define __LOCO_IR_GRAPH_INPUT_INDEX_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+using GraphInputIndex = uint32_t;
+
+} // namespace loco
+
+#endif // __LOCO_IR_GRAPH_INPUT_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/GraphOutputIndex.h b/compiler/loco/include/loco/IR/GraphOutputIndex.h
new file mode 100644
index 000000000..3231cbd95
--- /dev/null
+++ b/compiler/loco/include/loco/IR/GraphOutputIndex.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_GRAPH_OUTPUT_INDEX_H__
+#define __LOCO_IR_GRAPH_OUTPUT_INDEX_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+using GraphOutputIndex = uint32_t;
+
+} // namespace loco
+
+#endif // __LOCO_IR_GRAPH_OUTPUT_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/MatrixAxis.h b/compiler/loco/include/loco/IR/MatrixAxis.h
new file mode 100644
index 000000000..8a1689bb3
--- /dev/null
+++ b/compiler/loco/include/loco/IR/MatrixAxis.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_MATRIX_AXIS_H__
+#define __LOCO_IR_MATRIX_AXIS_H__
+
+namespace loco
+{
+
+enum class MatrixAxis
+{
+ Height,
+ Width
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_MATRIX_AXIS_H__
diff --git a/compiler/loco/include/loco/IR/MatrixCodec.h b/compiler/loco/include/loco/IR/MatrixCodec.h
new file mode 100644
index 000000000..40312641a
--- /dev/null
+++ b/compiler/loco/include/loco/IR/MatrixCodec.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_MATRIX_CODEC_H__
+#define __LOCO_IR_MATRIX_CODEC_H__
+
+#include "loco/IR/MatrixShape.h"
+#include "loco/IR/MatrixIndex.h"
+
+#include "loco/IR/TensorShape.h"
+#include "loco/IR/TensorIndex.h"
+
+#include <memory>
+
+namespace loco
+{
+
+/**
+ * @brief Decribe how to build a matrix from a tensor
+ *
+ * Let us assume that "enc" is a matrix encoder.
+ *
+ * Given a tensor "inp" and its shape "inp.shape", "enc" builds a matrix
+ * "out" as follows:
+ *
+ * for each valid matrix index (referred to as matrix_idx below) for enc.shape(inp.shape)
+ * out.at(matrix_index) = inp.at(enc.value(matrix_index))
+ */
+struct MatrixEncoder
+{
+ virtual ~MatrixEncoder() = default;
+
+ virtual MatrixShape shape(const TensorShape &shape) const = 0;
+ virtual TensorIndex value(const MatrixIndex &index) const = 0;
+};
+
+/**
+ * @brief Describe how to build a tensor from a matrix
+ *
+ * Let us assume that "dec" is a matrix decoder.
+ *
+ * Given a matrix "inp" and its shape "inp.shape", "dec" builds a tensor
+ * "out" as follows:
+ *
+ * for each valid tensor index (referred to as tensor_index below) for dec.shape(inp.shape)
+ * out.at(tensor_index) = inp.at(dec.value(tensor_index))
+ *
+ * NOTE "inp" is a matrix value and "out" is a tensor value in this example.
+ */
+struct MatrixDecoder
+{
+ virtual ~MatrixDecoder() = default;
+
+ virtual TensorShape shape(const MatrixShape &) const = 0;
+ virtual MatrixIndex value(const TensorIndex &) const = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_MATRIX_CODEC_H__
diff --git a/compiler/loco/include/loco/IR/MatrixIndex.h b/compiler/loco/include/loco/IR/MatrixIndex.h
new file mode 100644
index 000000000..eb6d65580
--- /dev/null
+++ b/compiler/loco/include/loco/IR/MatrixIndex.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_MATRIX_INDEX_H__
+#define __LOCO_IR_MATRIX_INDEX_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * @brief Matrix Index
+ *
+ * Matrix Index indicates an "element" in a given Matrix
+ *
+ * Let us assume that there is a Matrix F and S denotes its shape (of MatrixShape type).
+ *
+ * Then, any valid Matrix index I satisfies the following invariants:
+ * - 0 <= I.row() < S.height()
+ * - 0 <= I.column() < S.width()
+ */
+class MatrixIndex final
+{
+public:
+ MatrixIndex() = default;
+
+public:
+ const uint32_t &row(void) const { return _row; }
+ uint32_t &row(void) { return _row; }
+
+ const uint32_t &column(void) const { return _column; }
+ uint32_t &column(void) { return _column; }
+
+private:
+ uint32_t _row = 0;
+ uint32_t _column = 0;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_MATRIX_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/MatrixShape.h b/compiler/loco/include/loco/IR/MatrixShape.h
new file mode 100644
index 000000000..512691beb
--- /dev/null
+++ b/compiler/loco/include/loco/IR/MatrixShape.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_MATRIX_SHAPE_H__
+#define __LOCO_IR_MATRIX_SHAPE_H__
+
+#include "loco/IR/Dimension.h"
+
+namespace loco
+{
+
+/**
+ * @brief Matrix Shape
+ *
+ * This class describes the shape of matrix, which serves as the input/output of
+ * matrix operations (e.g. Matrix Multiplication).
+ *
+ * Each matrix is a collection of 2D features conceptually.
+ * Each matrix has height, width.
+ *
+ * height() refers to the height of matrix in a given matrix
+ * width() refers to the width of matrix in a given matrix
+ */
+class MatrixShape final
+{
+public:
+ MatrixShape() = default;
+
+public:
+ const Dimension &height(void) const { return _height; }
+ Dimension &height(void) { return _height; }
+
+ const Dimension &width(void) const { return _width; }
+ Dimension &width(void) { return _width; }
+
+private:
+ Dimension _height;
+ Dimension _width;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_MATRIX_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/Node.forward.h b/compiler/loco/include/loco/IR/Node.forward.h
new file mode 100644
index 000000000..425b28aff
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Node.forward.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODE_FORWARD_H__
+#define __LOCO_IR_NODE_FORWARD_H__
+
+namespace loco
+{
+
+// NOTE This forward declaration SHOULD BE aligned with Node delcaration in "Node.h"
+class Node;
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODE_FORWARD_H__
diff --git a/compiler/loco/include/loco/IR/Node.h b/compiler/loco/include/loco/IR/Node.h
new file mode 100644
index 000000000..ef0bf238d
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Node.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODE_H__
+#define __LOCO_IR_NODE_H__
+
+#include "loco/ADT/AnnotatedItem.h"
+
+#include "loco/IR/Use.h"
+#include "loco/IR/Dialect.h"
+#include "loco/IR/NodePool.forward.h"
+#include "loco/IR/Graph.forward.h"
+
+#include <array>
+#include <memory>
+#include <set>
+
+namespace loco
+{
+
+/**
+ * @brief Extensible Node Metadata
+ */
+struct NodeAnnotation
+{
+ virtual ~NodeAnnotation() = default;
+};
+
+enum class SubstQualifier
+{
+ Default, // Replace all the occurrences as "Use" (by default)
+};
+
+template <SubstQualifier Q> class Subst;
+
+/**
+ * @brief Logical unit of computation
+ */
+class Node : public AnnotatedItem<NodeAnnotation>
+{
+public:
+ friend class Use;
+ friend class Subst<SubstQualifier::Default>;
+ friend class NodePool;
+ friend std::set<Node *> succs(const Node *node);
+
+public:
+ Node() = default;
+
+ Node(const Node &) = delete;
+ Node(Node &&) = delete;
+
+ virtual ~Node();
+
+public:
+ Graph *graph(void) { return _graph; }
+ const Graph *graph(void) const { return _graph; }
+
+private:
+ /**
+ * @brief Set associated "Graph"
+ *
+ * @note Only "NodePool" class is permitted to invoke this private method.
+ */
+ void graph(Graph *g) { _graph = g; }
+
+public:
+ /**
+ * @brief Return "Dialect" identifier that this node belongs to
+ *
+ * dialect() SHOULD return a valid pointer.
+ */
+ virtual const Dialect *dialect(void) const = 0;
+
+ virtual uint32_t opnum(void) const = 0;
+
+public:
+ /// @brief Return the number of arguments
+ virtual uint32_t arity(void) const = 0;
+
+ /// @brief Access N-th argument node
+ virtual Node *arg(uint32_t N) const = 0;
+
+ /**
+ * @brief Drop all the reference of arguments
+ *
+ * arg(n) SHOULD return nullptr for every valid n after drop() call.
+ */
+ virtual void drop(void) = 0;
+
+private:
+ /**
+ * @brief Associated Graph
+ *
+ * May be nullptr if no associated Graph exists.
+ */
+ Graph *_graph = nullptr;
+
+ /**
+ * @brief The edges to a node that uses this node as its argument
+ *
+ * @note "succs" function below accesses this private field.
+ */
+ std::set<Use *> _uses;
+};
+
+/// @brief Enumerate all the predecessors of a given node
+std::set<Node *> preds(const Node *node);
+/// @brief Enumerate all the successors of a given node
+std::set<Node *> succs(const Node *node);
+
+/**
+ * @brief A helper for below "replace" helper
+ */
+template <> class Subst<SubstQualifier::Default>
+{
+public:
+ friend Subst<SubstQualifier::Default> replace(Node *node);
+
+private:
+ explicit Subst(Node *from);
+
+public:
+ void with(Node *into) const;
+
+private:
+ Node *_from;
+};
+
+Subst<SubstQualifier::Default> replace(Node *node);
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODE_H__
diff --git a/compiler/loco/include/loco/IR/NodeMixins.h b/compiler/loco/include/loco/IR/NodeMixins.h
new file mode 100644
index 000000000..f0e34b0ba
--- /dev/null
+++ b/compiler/loco/include/loco/IR/NodeMixins.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODE_MIXINS_H__
+#define __LOCO_IR_NODE_MIXINS_H__
+
+#include "loco/IR/Node.h"
+#include "loco/IR/DataType.h"
+#include "loco/IR/Dimension.h"
+
+#include <vector>
+#include <initializer_list>
+
+namespace loco
+{
+
+enum class NodeTrait
+{
+ DataType,
+ // Nodes with TensorShape trait will provide the following methods:
+ // - rank()
+ // - rank(value)
+ // - dim()
+ // - dim(value)
+ // - shape({...})
+ TensorShape,
+};
+
+template <NodeTrait T> class NodeMixin;
+
+template <> class NodeMixin<NodeTrait::DataType>
+{
+public:
+ NodeMixin() = default;
+
+public:
+ const DataType &dtype(void) const { return _dtype; }
+ void dtype(const DataType &dtype) { _dtype = dtype; }
+
+private:
+ /// @brief Data type
+ DataType _dtype{DataType::Unknown};
+};
+
+template <> class NodeMixin<NodeTrait::TensorShape>
+{
+public:
+ NodeMixin() = default;
+
+public:
+ uint32_t rank(void) const { return _dims.size(); }
+ void rank(uint32_t value) { _dims.resize(value); }
+
+ const Dimension &dim(uint32_t axis) const { return _dims.at(axis); }
+ Dimension &dim(uint32_t axis) { return _dims.at(axis); }
+
+ void shape(std::initializer_list<uint32_t> dims)
+ {
+ rank(dims.size());
+
+ uint32_t axis = 0;
+ for (auto d : dims)
+ {
+ dim(axis++) = d;
+ }
+ }
+
+private:
+ /// @brief Data shape (as tensor)
+ std::vector<Dimension> _dims;
+};
+
+template <unsigned N> struct FixedArity
+{
+ template <typename Base> class Mixin : public virtual Base
+ {
+ public:
+ Mixin()
+ {
+ for (uint32_t n = 0; n < N; ++n)
+ {
+ _args[n] = std::unique_ptr<Use>{new Use{this}};
+ }
+ }
+
+ virtual ~Mixin() = default;
+
+ public:
+ unsigned arity(void) const final { return N; }
+
+ Node *arg(uint32_t n) const final { return _args.at(n)->node(); }
+
+ void drop(void) final
+ {
+ for (uint32_t n = 0; n < N; ++n)
+ {
+ _args.at(n)->node(nullptr);
+ }
+ }
+
+ protected:
+ // This API allows inherited classes to access "_args" field.
+ Use *at(unsigned n) const { return _args.at(n).get(); }
+
+ private:
+ std::array<std::unique_ptr<Use>, N> _args{};
+ };
+};
+
+template <NodeTrait Trait> struct With
+{
+ template <typename Base> struct Mixin : public virtual Base, public NodeMixin<Trait>
+ {
+ // DO NOTHING
+ };
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODE_MIXINS_H__
diff --git a/compiler/loco/include/loco/IR/NodePool.forward.h b/compiler/loco/include/loco/IR/NodePool.forward.h
new file mode 100644
index 000000000..87bf01311
--- /dev/null
+++ b/compiler/loco/include/loco/IR/NodePool.forward.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODE_POOL_FORWARD_H__
+#define __LOCO_IR_NODE_POOL_FORWARD_H__
+
+namespace loco
+{
+
+// This forward declaration SHOULD BE aligned with the actual declaration in "NodePool.h".
+class NodePool;
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODE_POOL_FORWARD_H__
diff --git a/compiler/loco/include/loco/IR/NodePool.h b/compiler/loco/include/loco/IR/NodePool.h
new file mode 100644
index 000000000..4db4caae3
--- /dev/null
+++ b/compiler/loco/include/loco/IR/NodePool.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODE_POOL_H__
+#define __LOCO_IR_NODE_POOL_H__
+
+#include "loco/IR/Node.h"
+#include "loco/IR/Graph.forward.h"
+
+#include "loco/ADT/ObjectPool.h"
+
+namespace loco
+{
+
+class NodePool final : public ObjectPool<Node>
+{
+public:
+ friend class Graph;
+
+public:
+ ~NodePool();
+
+public:
+ template <typename Derived, typename... Args> Derived *create(Args &&... args)
+ {
+ std::unique_ptr<Derived> ptr{new Derived(std::forward<Args>(args)...)};
+ ptr->graph(_graph);
+ return ObjectPool<Node>::take<Derived>(std::move(ptr));
+ }
+
+ void destroy(Node *node)
+ {
+ if (!ObjectPool<Node>::erase(node))
+ {
+ throw std::invalid_argument{"node"};
+ }
+ }
+
+private:
+ /// Only "Graph" is permitted to invoke this private method.
+ void graph(Graph *g) { _graph = g; }
+
+private:
+ Graph *_graph = nullptr;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODE_POOL_H__
diff --git a/compiler/loco/include/loco/IR/NodeShape.h b/compiler/loco/include/loco/IR/NodeShape.h
new file mode 100644
index 000000000..5eefd3c19
--- /dev/null
+++ b/compiler/loco/include/loco/IR/NodeShape.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODE_SHAPE_H__
+#define __LOCO_IR_NODE_SHAPE_H__
+
+#include "loco/IR/Domain.h"
+
+#include "loco/IR/BiasShape.h"
+#include "loco/IR/DepthwiseFilterShape.h"
+#include "loco/IR/FeatureShape.h"
+#include "loco/IR/FilterShape.h"
+#include "loco/IR/MatrixShape.h"
+#include "loco/IR/TensorShape.h"
+
+#include <vector>
+
+namespace loco
+{
+
+class NodeShape final
+{
+public:
+ NodeShape() = default;
+
+public:
+ NodeShape(const BiasShape &shape) { set(shape); }
+ NodeShape(const DepthwiseFilterShape &shape) { set(shape); }
+ NodeShape(const FeatureShape &shape) { set(shape); }
+ NodeShape(const FilterShape &shape) { set(shape); }
+ NodeShape(const MatrixShape &shape) { set(shape); }
+ NodeShape(const TensorShape &shape) { set(shape); }
+
+public:
+ const Domain &domain(void) const { return _domain; }
+
+public:
+ void set(const BiasShape &);
+ void set(const DepthwiseFilterShape &);
+ void set(const FeatureShape &);
+ void set(const FilterShape &);
+ void set(const MatrixShape &);
+ void set(const TensorShape &);
+
+public:
+ template <typename ShapeType> ShapeType as(void) const;
+
+private:
+ Domain _domain = Domain::Unknown;
+ std::vector<Dimension> _dims;
+};
+
+bool operator==(const NodeShape &lhs, const NodeShape &rhs);
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODE_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/Nodes.h b/compiler/loco/include/loco/IR/Nodes.h
new file mode 100644
index 000000000..9aac48b6e
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Nodes.h
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_NODES_H__
+#define __LOCO_IR_NODES_H__
+
+#include "loco/IR/Node.h"
+#include "loco/IR/Use.h"
+#include "loco/IR/Domain.h"
+#include "loco/IR/DataType.h"
+#include "loco/IR/DataTypeTraits.h"
+#include "loco/IR/Dimension.h"
+#include "loco/IR/Window.h"
+#include "loco/IR/Stride.h"
+#include "loco/IR/Padding2D.h"
+#include "loco/IR/PaddingND.h"
+#include "loco/IR/TensorAxis.h"
+#include "loco/IR/TensorAxisSet.h"
+#include "loco/IR/FeatureCodec.h"
+#include "loco/IR/FilterCodec.h"
+#include "loco/IR/DepthwiseFilterCodec.h"
+#include "loco/IR/MatrixCodec.h"
+#include "loco/IR/NodeMixins.h"
+#include "loco/IR/CanonicalNodeDecl.h"
+#include "loco/IR/GraphInputIndex.h"
+#include "loco/IR/GraphOutputIndex.h"
+
+namespace loco
+{
+
+class Graph;
+class GraphInput;
+class GraphOutput;
+
+/**
+ * @brief Make a value visible to user
+ */
+class Push /* to user */ final
+ : public CanonicalNodeDef<CanonicalOpcode::Push, FixedArity<1>::Mixin>
+{
+public:
+ Push() = default;
+
+public:
+ Node *from(void) const { return at(0)->node(); }
+ void from(Node *node) { at(0)->node(node); }
+
+public:
+ void index(const GraphOutputIndex &index);
+
+ /**
+ * @brief Get associated output index
+ *
+ * The behavior of this method is undefined when "index" is not set before.
+ *
+ * NOTE This method intentionally returns "GraphOutputIndex" instead of "const GraphOutputIndex &"
+ * not to expose the internal implementation details.
+ */
+ GraphOutputIndex index(void) const;
+
+ /**
+ * @brief Check whether index is initialized
+ *
+ * NOTE "indexed" method does not validate whether index is in a valid range
+ */
+ bool indexed(void) const { return _index != -1; }
+
+private:
+ int64_t _index = -1; // Uninitialized
+};
+
+void link(GraphOutput *, Push *push);
+
+/// @brief Find a Push node with a given output index
+Push *push_node(Graph *g, const GraphOutputIndex &index);
+
+/**
+ * @brief Create a value from user data
+ */
+class Pull /* from user */ final
+ : public CanonicalNodeDef<CanonicalOpcode::Pull, FixedArity<0>::Mixin,
+ With<NodeTrait::TensorShape>::Mixin>
+{
+public:
+ Pull() = default;
+
+public:
+ void index(const GraphInputIndex &index);
+
+ /**
+ * @brief Get associated input index
+ *
+ * The behavior of this method is undefined when "index" is not set before.
+ *
+ * NOTE This method intentionally returns "GraphInputIndex" instead of "const GraphInputIndex &"
+ * not to expose the internal implementation details.
+ */
+ GraphInputIndex index(void) const;
+
+ /**
+ * @brief Check whether index is initialized
+ *
+ * NOTE "indexed" method does not validate whether index is in a valid range
+ */
+ bool indexed(void) const { return _index != -1; }
+
+public:
+ void dtype(const DataType &d);
+ DataType dtype(void) const;
+
+private:
+ int64_t _index = -1; // Uninitialized
+
+ /**
+ * @brief Locally cached data type attribute
+ *
+ * TODO Remove this cache once all the clients are updated
+ */
+ DataType _dtype = DataType::Unknown;
+};
+
+void link(GraphInput *, Pull *pull);
+
+/// @brief Find a Pull node with a given input index
+Pull *pull_node(Graph *g, const GraphInputIndex &index);
+
+/**
+ * @brief Create a new value identical to its input
+ *
+ * This node may encode memory transfer (such as CPU -> GPU or GPU -> CPU)
+ */
+class Forward final : public CanonicalNodeDef<CanonicalOpcode::Forward, FixedArity<1>::Mixin>
+{
+public:
+ Forward() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Create a new value that rectifies its input
+ */
+class ReLU final : public CanonicalNodeDef<CanonicalOpcode::ReLU, FixedArity<1>::Mixin>
+{
+public:
+ ReLU() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Create a new value that rectifies its input capping the units at 6.
+ */
+class ReLU6 final : public CanonicalNodeDef<CanonicalOpcode::ReLU6, FixedArity<1>::Mixin>
+{
+public:
+ ReLU6() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Create a new value that rectifies its input by tanh
+ */
+class Tanh final : public CanonicalNodeDef<CanonicalOpcode::Tanh, FixedArity<1>::Mixin>
+{
+public:
+ Tanh() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Create a value from constant byte array
+ *
+ * @note ConstGen assumes "lexical memory layout".
+ *
+ * Let us assume that a 'ConstGen' generates a constant tensor of shape "S".
+ * for each valid index I, the corresponding value comes from offset(S, I)
+ * where the implementation of "offset" is given as follows:
+ *
+ * uint32_t stride(TensorShape shape, uint32_t axis) {
+ * uint32_t res = 1;
+ * for (uint32_t n = rank(shape) - 1; n > axis; --n) { res *= shape.dim(n); }
+ * return res;
+ * }
+ *
+ * uint32_t offset(TensorShape shape, TensorIndex index) {
+ * uint32_t res = 0;
+ * for (uint32_t n = 0; n < rank(shape); ++n) { res += index.at(n) * stride(shape, n); }
+ * return res;
+ * }
+ */
+class ConstGen final
+ : public CanonicalNodeDef<CanonicalOpcode::ConstGen, FixedArity<0>::Mixin,
+ With<NodeTrait::DataType>::Mixin, With<NodeTrait::TensorShape>::Mixin>
+{
+public:
+ ConstGen() = default;
+
+public:
+ /**
+ * @brief Return the number of reserved elements
+ * @note This method returns the number of ELEMENT (not BYTE).
+ */
+ template <DataType DT> uint32_t size(void) const;
+
+ /**
+ * @brief Adjust the number of reserved elements
+ */
+ template <DataType DT> void size(uint32_t size);
+
+ /**
+ * @brief Get the element at a given position
+ * @require at(n) is valid only when n < size()
+ */
+ template <DataType DT> const typename DataTypeImpl<DT>::Type &at(uint32_t n) const;
+
+ /**
+ * @brief Update the element at a given position
+ * @require at(n) is valid only when n < size()
+ */
+ template <DataType DT> typename DataTypeImpl<DT>::Type &at(uint32_t n);
+
+private:
+ /// @brief Data
+ std::vector<uint8_t> _data;
+};
+
+/**
+ * @brief 2D Max Pooling
+ *
+ * MaxPool2D takes as input a feature map, and produces another feature map
+ *
+ * ---
+ * Any valid MaxPool2D nodes SHOULD satisfy the following conditions.
+ *
+ * Let us define several helper functions that takes a MaxPool2D nodes first:
+ * - IFM_DOMAIN returns the domain of its input
+ * - IFM_H returns the height of its input.
+ * - IFM_W returns the width of its input.
+ * - PAD_T returns the top padding required over its input
+ * - PAD_B returns the bottom padding required over its input
+ * - PAD_L returns the left padding required over its input
+ * - PAD_R returns the right padding required over its input
+ * - WIN_H returns the height of its receptive field.
+ * - WIN_W returns the width of its receptive field.
+ * - STRIDE_H returns the vertical(= on height) stride.
+ * - STRIDE_W returns the horizontal(= on width) stride.
+ *
+ * Condition 1
+ * Statement
+ *
+ * A valid MaxPool2D node M SHOULD satisfy the following condition:
+ * - IFM_DOMAIN(M) == Feature
+ *
+ * Motivation
+ *
+ * There are many possible ways to encode a feature map as a tensor.
+ * - e.g. NCHW/NHWC/...
+ *
+ * In order to give some freedom on memory layout to backend, loco requires a feature map
+ * value to be explicitly encoded via FeatureEncode.
+ *
+ * Condition 2:
+ * Statement
+ *
+ * A valid MaxPool2D node M SHOULD satisfy the following conditions:
+ * - (IFM_H(M) + PAD_T(M) + PAD_B(M) - WIN_H(M)) % STRIDE_H(M) == 0
+ * - (IFM_W(M) + PAD_L(M) + PAD_R(M) - WIN_W(M)) % STRIDE_W(M) == 0
+ *
+ * Motivation
+ *
+ * The output shape may differ for each NN framework when these conditions do not hold.
+ *
+ * In order to mitigate such a difference among NN frameworks, loco requires these conditions
+ * for MaxPool2D nodes.
+ *
+ * This means that each frontend implementation SHOULD insert appropriate padding/trimming node
+ * before/after MaxPool2D node according to the semantics of the corresponding NN framework.
+ * ---
+ */
+class MaxPool2D final : public CanonicalNodeDef<CanonicalOpcode::MaxPool2D, FixedArity<1>::Mixin>
+{
+public:
+ Node *ifm(void) const { return at(0)->node(); }
+ void ifm(Node *node) { at(0)->node(node); }
+
+public:
+ const Padding2D *pad(void) const { return &_pad; }
+ Padding2D *pad(void) { return &_pad; }
+
+public:
+ const Window<2> *window(void) const { return &_window; }
+ Window<2> *window(void) { return &_window; }
+
+public:
+ const Stride<2> *stride(void) const { return &_stride; }
+ Stride<2> *stride(void) { return &_stride; }
+
+private:
+ // Pad
+ Padding2D _pad;
+ // Window
+ Window<2> _window;
+ // Stride
+ Stride<2> _stride;
+};
+
+/**
+ * @brief 2D Average Pooling
+ *
+ * @note Follows MaxPool2D (TODO: describe difference)
+ */
+class AvgPool2D final : public CanonicalNodeDef<CanonicalOpcode::AvgPool2D, FixedArity<1>::Mixin>
+{
+public:
+ enum class Convention
+ {
+ Unknown,
+ // Use the number of elements in each receptive field as a divisor
+ Full,
+ // Use the number of valid (non-padding) elements in each receptive field as a divisor
+ Valid
+ };
+
+public:
+ Node *ifm(void) const { return at(0)->node(); }
+ void ifm(Node *node) { at(0)->node(node); }
+
+public:
+ Convention convention(void) const { return _convention; }
+ void convention(const Convention &convention) { _convention = convention; }
+
+public:
+ const Padding2D *pad(void) const { return &_pad; }
+ Padding2D *pad(void) { return &_pad; }
+
+public:
+ const Window<2> *window(void) const { return &_window; }
+ Window<2> *window(void) { return &_window; }
+
+public:
+ const Stride<2> *stride(void) const { return &_stride; }
+ Stride<2> *stride(void) { return &_stride; }
+
+private:
+ Convention _convention = Convention::Unknown;
+ Padding2D _pad;
+ Window<2> _window;
+ Stride<2> _stride;
+};
+
+/**
+ * @brief Create a feature map from a tensor
+ */
+class FeatureEncode final
+ : public CanonicalNodeDef<CanonicalOpcode::FeatureEncode, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ FeatureEncoder *encoder(void) const { return _enc.get(); }
+ void encoder(std::unique_ptr<FeatureEncoder> &&enc) { _enc = std::move(enc); }
+
+private:
+ /// @note "encoder" is mandatory
+ std::unique_ptr<FeatureEncoder> _enc{nullptr};
+};
+
+/**
+ * @brief Create a tensor from a feature map
+ */
+class FeatureDecode final
+ : public CanonicalNodeDef<CanonicalOpcode::FeatureDecode, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ FeatureDecoder *decoder(void) const { return _dec.get(); }
+ void decoder(std::unique_ptr<FeatureDecoder> &&dec) { _dec = std::move(dec); }
+
+private:
+ /// @NOTE "decoder" is mandatory
+ std::unique_ptr<FeatureDecoder> _dec{nullptr};
+};
+
+/**
+ * @brief Create a filter from a tensor
+ */
+class FilterEncode final
+ : public CanonicalNodeDef<CanonicalOpcode::FilterEncode, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ FilterEncoder *encoder(void) const { return _enc.get(); }
+ void encoder(std::unique_ptr<FilterEncoder> &&enc) { _enc = std::move(enc); }
+
+private:
+ /// @note "encoder" is mandatory
+ std::unique_ptr<FilterEncoder> _enc{nullptr};
+};
+
+/**
+ * @brief Create a tensor from a filter
+ */
+class FilterDecode final
+ : public CanonicalNodeDef<CanonicalOpcode::FilterDecode, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ FilterDecoder *decoder(void) const { return _dec.get(); }
+ void decoder(std::unique_ptr<FilterDecoder> &&dec) { _dec = std::move(dec); }
+
+private:
+ /// @note "decoder" is mandatory
+ std::unique_ptr<FilterDecoder> _dec{nullptr};
+};
+
+/**
+ * @brief Create a depthwise filter from a tensor
+ */
+class DepthwiseFilterEncode final
+ : public CanonicalNodeDef<CanonicalOpcode::DepthwiseFilterEncode, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ DepthwiseFilterEncoder *encoder(void) const { return _enc.get(); }
+ void encoder(std::unique_ptr<DepthwiseFilterEncoder> &&enc) { _enc = std::move(enc); }
+
+private:
+ /// @note "encoder" is mandatory
+ std::unique_ptr<DepthwiseFilterEncoder> _enc{nullptr};
+};
+
+/**
+ * @brief Create a tensor from a depthwise filter
+ */
+class DepthwiseFilterDecode final
+ : public CanonicalNodeDef<CanonicalOpcode::DepthwiseFilterDecode, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ DepthwiseFilterDecoder *decoder(void) const { return _dec.get(); }
+ void decoder(std::unique_ptr<DepthwiseFilterDecoder> &&dec) { _dec = std::move(dec); }
+
+private:
+ /// @note "decoder" is mandatory
+ std::unique_ptr<DepthwiseFilterDecoder> _dec{nullptr};
+};
+
+enum class ReshapeType
+{
+ Fixed, // shape is known at compile time
+ // Add another type for a case when shape is not known at compile time
+};
+
+template <ReshapeType RT> class Reshape;
+
+/**
+ * @brief Reshape a tensor to another tensor whose shape is known at compile time
+ *
+ * @note This class reshapes the shape of an input tensor to _shape.
+ * Each dimension of _shape should be known at compile time.
+ * Any dimension of _shape should be greater than 0.
+ *
+ * Interpreter or runtime should lexicographically copy an input tensor into an output tensor.
+ * For example, values of an input tesor of shape [2, 2, 2, 2] will be copied into an output
+ * tensor of new shape [4, 4] like the following:
+ * input[0, 0, 0, 0] => output [0, 0]
+ * input[0, 0, 0, 1] => output [0, 1]
+ * input[0, 0, 1, 0] => output [0, 2]
+ * ...
+ * input[1, 1, 1, 1] => output [3, 3]
+ */
+template <>
+class Reshape<ReshapeType::Fixed> final
+ : public CanonicalNodeDef<CanonicalOpcode::FixedReshape, FixedArity<1>::Mixin,
+ With<NodeTrait::TensorShape>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+using FixedReshape = Reshape<ReshapeType::Fixed>;
+
+/**
+ * @brief Concatenate two tensors
+ *
+ * Given an axis, TensorConcat takes as input two tensors and produces a tensor
+ * concatenated along the given axis.
+ */
+class TensorConcat final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorConcat, FixedArity<2>::Mixin>
+{
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { at(1)->node(node); }
+
+public:
+ uint32_t axis(void) const { return _axis; }
+ void axis(uint32_t val) { _axis = val; }
+
+private:
+ // Axis
+ uint32_t _axis{0};
+};
+
+/**
+ * @brief 2D Spatial Convolution
+ */
+class Conv2D final : public CanonicalNodeDef<CanonicalOpcode::Conv2D, FixedArity<2>::Mixin>
+{
+public:
+ Node *ifm(void) const { return at(0)->node(); }
+ void ifm(Node *node) { at(0)->node(node); }
+
+ Node *ker(void) const { return at(1)->node(); }
+ void ker(Node *node) { at(1)->node(node); }
+
+public:
+ const Padding2D *pad(void) const { return &_pad; }
+ Padding2D *pad(void) { return &_pad; }
+
+public:
+ const Stride<2> *stride(void) const { return &_stride; }
+ Stride<2> *stride(void) { return &_stride; }
+
+private:
+ Padding2D _pad;
+ Stride<2> _stride;
+
+ // TODO Support "Dilation"
+};
+
+/**
+ * @brief Depthwise 2D Convolution
+ */
+class DepthwiseConv2D final
+ : public CanonicalNodeDef<CanonicalOpcode::DepthwiseConv2D, FixedArity<2>::Mixin>
+{
+public:
+ Node *ifm(void) const { return at(0)->node(); }
+ void ifm(Node *node) { at(0)->node(node); }
+
+ Node *ker(void) const { return at(1)->node(); }
+ void ker(Node *node) { at(1)->node(node); }
+
+public:
+ const Padding2D *pad(void) const { return &_pad; }
+ Padding2D *pad(void) { return &_pad; }
+
+public:
+ const Stride<2> *stride(void) const { return &_stride; }
+ Stride<2> *stride(void) { return &_stride; }
+
+private:
+ Padding2D _pad;
+ Stride<2> _stride;
+
+ // TODO Support "Dilation"
+};
+
+/**
+ * @brief Reduce type functions
+ */
+enum class ReduceFunc
+{
+ Mean, // ReduceMean
+ // TODO Support other reduce operations
+};
+
+/**
+ * @brief Computes ReduceFunc operations for Tensor domain
+ * @note All the reduce functions always keep dimensions
+ */
+class TensorReduce final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorReduce, FixedArity<1>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ const TensorAxisSet *axes(void) const { return &_axes; }
+ TensorAxisSet *axes(void) { return &_axes; }
+
+public:
+ ReduceFunc func(void) const { return _func; }
+ void func(ReduceFunc func) { _func = func; }
+
+private:
+ TensorAxisSet _axes;
+ ReduceFunc _func;
+};
+
+/**
+ * @brief 2D Transposed Convolution
+ *
+ * @note TransposedConv2D have a few important conventions that IR users should
+ * understand and follow, so please check below notice carefully.
+ *
+ *
+ * 1. What is 'input' and 'output'
+ *
+ * For loco canonical TransposedConv2D, 'input' and 'output' mean actual input
+ * and output node of TransposedConv2D node. Be careful that some other
+ * frameworks may use opposite sense, especially TensorFlow which is inspired by
+ * backpropagation of convolution.
+ * For example, loco::TransposedConv2D::ifm() means actual input feature map
+ * node that is sourced into TransposedConv2D.
+ *
+ * 2. How to read kernel representation
+ *
+ * TransposedConv2D::ker() should be a node of Filter domain. Following is what
+ * each FilterAxis means as a kernel of TransposedConv2D:
+ * - FilterAxis::Height : kernel's height
+ * - FilterAxis::Width : kernel's width
+ * - FilterAxis::Depth : IFM's channel depth
+ * - FilterAxis::Count : OFM's channel depth
+ * TODO We may refactor FilterAxis as follow to reduce ambiguity:
+ * - FilterAxis::Height -> FilterAxis::H
+ * - FilterAxis::Width -> FilterAxis::W
+ * - FilterAxis::Depth -> FilterAxis::I
+ * - FilterAxis::Count -> FilterAxis::O
+ *
+ *
+ * 3. Tight fit rule
+ *
+ * TransposedConv2D have no information about its output shape. Instead, it
+ * always satisfy following 'tight fit' rule for horizontal and vertical
+ * dimension:
+ *
+ * O = S * ( I - 1 ) + F - P
+ *
+ * where
+ * O: output size
+ * S: stride
+ * I: input size
+ * F: effective kernal(filter) size
+ * P: whole pad size (= front + rear pad)
+ *
+ * With this, output shape is uniquely determined by all inputs and attributes.
+ */
+class TransposedConv2D final
+ : public CanonicalNodeDef<CanonicalOpcode::TransposedConv2D, FixedArity<2>::Mixin>
+{
+public:
+ Node *ifm(void) const { return at(0)->node(); }
+ void ifm(Node *node) { at(0)->node(node); }
+
+ Node *ker(void) const { return at(1)->node(); }
+ void ker(Node *node) { at(1)->node(node); }
+
+public:
+ const Padding2D *pad(void) const { return &_pad; }
+ Padding2D *pad(void) { return &_pad; }
+
+public:
+ const Stride<2> *stride(void) const { return &_stride; }
+ Stride<2> *stride(void) { return &_stride; }
+
+private:
+ Padding2D _pad;
+ Stride<2> _stride;
+
+ // TODO Support "Dilation"
+};
+
+/**
+ * @brief Computes softmax activations
+ */
+template <Domain D> class Softmax;
+
+/**
+* @brief Computes softmax activations for Tensor domain
+*/
+template <>
+class Softmax<Domain::Tensor> final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorSoftmax, FixedArity<1>::Mixin>
+{
+public:
+ Softmax() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { return at(0)->node(node); }
+
+ uint32_t axis(void) const { return _axis; }
+ void axis(uint32_t axis) { _axis = axis; }
+
+private:
+ uint32_t _axis = 0;
+};
+
+using TensorSoftmax = Softmax<Domain::Tensor>;
+
+/**
+ * @brief Create a "Tensor" from a "Bias"
+ */
+class BiasDecode final : public CanonicalNodeDef<CanonicalOpcode::BiasDecode, FixedArity<1>::Mixin>
+{
+public:
+ BiasDecode() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Create a "Bias" from a "Tensor"
+ *
+ * BiasEncode currently requires a rank-1 tensor as its input.
+ */
+class BiasEncode final : public CanonicalNodeDef<CanonicalOpcode::BiasEncode, FixedArity<1>::Mixin>
+{
+public:
+ BiasEncode() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Produce a value of domain D from an input value (of domain D) and a bias
+ */
+template <Domain D> class BiasAdd;
+
+/**
+ * @brief Add Tensor and Bias
+ *
+ * for each valid tensor index I
+ * out(I) = value(I) + bias(I.at(axis))
+ */
+template <>
+class BiasAdd<Domain::Tensor> final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorBiasAdd, FixedArity<2>::Mixin>
+{
+public:
+ BiasAdd() = default;
+
+public:
+ Node *value(void) const { return at(0)->node(); }
+ void value(Node *node) { return at(0)->node(node); }
+
+ Node *bias(void) const { return at(1)->node(); }
+ void bias(Node *node) { return at(1)->node(node); }
+
+ uint32_t axis(void) const { return _axis; }
+ void axis(uint32_t axis) { _axis = axis; }
+
+private:
+ uint32_t _axis = 0;
+};
+
+//
+// Alias for external users
+//
+// loco::TensorBiasAdd
+// vs.
+// loco::BiasAdd<loco::Domain::Tensor>
+//
+using TensorBiasAdd = BiasAdd<Domain::Tensor>;
+
+/**
+ * @brief Add Feature and Bias along "depth" axis
+ *
+ * for each valid feature index (b, ch, row, col)
+ * out(b, ch, row, col) = value(b, ch, row, col) + bias(ch)
+ */
+template <>
+class BiasAdd<Domain::Feature> final
+ : public CanonicalNodeDef<CanonicalOpcode::FeatureBiasAdd, FixedArity<2>::Mixin>
+{
+public:
+ BiasAdd() = default;
+
+public:
+ Node *value(void) const { return at(0)->node(); }
+ void value(Node *node) { return at(0)->node(node); }
+
+ Node *bias(void) const { return at(1)->node(); }
+ void bias(Node *node) { return at(1)->node(node); }
+};
+
+using FeatureBiasAdd = BiasAdd<Domain::Feature>;
+
+/**
+ * @brief Pads a tensor with constant value
+ *
+ * Pads a input tensor according to the padding with constant value.
+ *
+ * The dimension of each axis n of the output is
+ * output.dim(n) = padding.front(n) + input.dim(n) + padding.back(n)
+ *
+ * For example, input tensor of shape [1, 2] with
+ *
+ * padding.front(0) = 1;
+ * padding.back(0) = 2;
+ *
+ * padding.front(1) = 3;
+ * padding.back(1) = 4;
+ *
+ * will be a output tensor of shape
+ * [padding.front(0) + 1 + padding.back(0), padding.front(1) + 2 + padding.back(1)] = [4,9].
+ */
+class TensorConstantPad final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorConstantPad, FixedArity<2>::Mixin>
+{
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+ Node *constant(void) const { return at(1)->node(); }
+ void constant(Node *node) { at(1)->node(node); }
+
+public:
+ const PaddingND *padding(void) const { return &_padding; }
+ PaddingND *padding(void) { return &_padding; }
+
+private:
+ PaddingND _padding;
+};
+
+/**
+ * @brief Elementwise Add lhs and rhs
+ */
+class EltwiseAdd final : public CanonicalNodeDef<CanonicalOpcode::EltwiseAdd, FixedArity<2>::Mixin>
+{
+public:
+ EltwiseAdd() = default;
+
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { return at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { return at(1)->node(node); }
+};
+
+/**
+ * @brief Elementwise Maximum of lhs and rhs
+ *
+ * o = (l > r) ? l : r (element-wise)
+ */
+class EltwiseMax final : public CanonicalNodeDef<CanonicalOpcode::EltwiseMax, FixedArity<2>::Mixin>
+{
+public:
+ EltwiseMax() = default;
+
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { return at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { return at(1)->node(node); }
+};
+
+/**
+ * @brief Elementwise Mul lhs and rhs
+ */
+class EltwiseMul final : public CanonicalNodeDef<CanonicalOpcode::EltwiseMul, FixedArity<2>::Mixin>
+{
+public:
+ EltwiseMul() = default;
+
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { return at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { return at(1)->node(node); }
+};
+
+/**
+ * @brief Elementwise Sub lhs and rhs
+ */
+class EltwiseSub final : public CanonicalNodeDef<CanonicalOpcode::EltwiseSub, FixedArity<2>::Mixin>
+{
+public:
+ EltwiseSub() = default;
+
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { return at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { return at(1)->node(node); }
+};
+
+/**
+ * @brief Elementwise Div lhs and rhs
+ */
+class EltwiseDiv final : public CanonicalNodeDef<CanonicalOpcode::EltwiseDiv, FixedArity<2>::Mixin>
+{
+public:
+ EltwiseDiv() = default;
+
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { return at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { return at(1)->node(node); }
+};
+
+/**
+ * @brief Elementwise Sqrt of input
+ */
+class EltwiseSqrt final
+ : public CanonicalNodeDef<CanonicalOpcode::EltwiseSqrt, FixedArity<1>::Mixin>
+{
+public:
+ EltwiseSqrt() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+/**
+ * @brief Duplicate elements along specified axes
+ *
+ * TensorBroadcast takes a tensor and produces another tensor with the same rank but HIGHER
+ * dimensionality.
+ *
+ * To create such a tensor. TensorBroadcast duplicates the element along the specified axes.
+ *
+ * It is possible to control the degree of duplication with a partial map from TensorAxis to
+ * Dimension.
+ *
+ * TODO Explain the constraints (The dimension of inputs for specified axes SHOULD BE 1).
+ * TODO Explain the operation semantics
+ */
+class TensorBroadcast final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorBroadcast, FixedArity<1>::Mixin>
+{
+public:
+ TensorBroadcast() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ class Mapping final
+ {
+ public:
+ Mapping() = default;
+
+ public:
+ bool defined(const TensorAxis &axis) const;
+
+ const Dimension &dim(const TensorAxis &axis) const;
+ Dimension &dim(const TensorAxis &axis);
+
+ private:
+ std::map<TensorAxis, Dimension> _content;
+ };
+
+ Mapping *mapping(void) { return &_mapping; }
+ const Mapping *mapping(void) const { return &_mapping; }
+
+private:
+ Mapping _mapping;
+};
+
+/**
+ * @brief Create Matrix from Tensor
+ *
+ * MatrixEncode currently requires a rank-2 Tensor as its input.
+ */
+class MatrixEncode final
+ : public CanonicalNodeDef<CanonicalOpcode::MatrixEncode, FixedArity<1>::Mixin>
+{
+public:
+ MatrixEncode() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ MatrixEncoder *encoder(void) const { return _enc.get(); }
+ void encoder(std::unique_ptr<MatrixEncoder> &&enc) { _enc = std::move(enc); }
+
+private:
+ /// @note "encoder" is mandatory
+ std::unique_ptr<MatrixEncoder> _enc{nullptr};
+};
+
+/**
+ * @brief Create Tensor from Matrix
+ *
+ * MatrixDecode currently requires a Matrix as its input.
+ */
+class MatrixDecode final
+ : public CanonicalNodeDef<CanonicalOpcode::MatrixDecode, FixedArity<1>::Mixin>
+{
+public:
+ MatrixDecode() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ MatrixDecoder *decoder(void) const { return _dec.get(); }
+ void decoder(std::unique_ptr<MatrixDecoder> &&dec) { _dec = std::move(dec); }
+
+private:
+ /// @note "decoder" is mandatory
+ std::unique_ptr<MatrixDecoder> _dec{nullptr};
+};
+
+/**
+ * @brief Matrix Multiplication lhs and rhs
+ *
+ * LHS and RHS must be on Matrix domain
+ */
+class MatMul final : public CanonicalNodeDef<CanonicalOpcode::MatMul, FixedArity<2>::Mixin>
+{
+public:
+ MatMul() = default;
+
+public:
+ Node *lhs(void) const { return at(0)->node(); }
+ void lhs(Node *node) { return at(0)->node(node); }
+
+ Node *rhs(void) const { return at(1)->node(); }
+ void rhs(Node *node) { return at(1)->node(node); }
+};
+
+/**
+ * @brief Permute an input
+ *
+ * In the following case,
+ *
+ * output = loco::TensorTranspose(input)
+ *
+ * perm()->axis(output's axis) = input's axis
+ *
+ * Input and output belong to tensor domain.
+ */
+class TensorTranspose final
+ : public CanonicalNodeDef<CanonicalOpcode::TensorTranspose, FixedArity<1>::Mixin>
+{
+public:
+ TensorTranspose() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { return at(0)->node(node); }
+
+ class Perm final
+ {
+ public:
+ Perm() = default;
+
+ public:
+ uint32_t size() const { return _vals.size(); }
+ void size(uint32_t size) { _vals.resize(size); }
+
+ const TensorAxis &axis(TensorAxis n) const { return _vals[n]; }
+ TensorAxis &axis(TensorAxis n) { return _vals[n]; }
+
+ private:
+ std::vector<TensorAxis> _vals;
+ };
+
+ Perm *perm(void) { return &_perm; }
+ const Perm *perm(void) const { return &_perm; }
+
+private:
+ Perm _perm;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_NODES_H__
diff --git a/compiler/loco/include/loco/IR/Padding2D.h b/compiler/loco/include/loco/IR/Padding2D.h
new file mode 100644
index 000000000..30557a891
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Padding2D.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_PADDING2D_H__
+#define __LOCO_IR_PADDING2D_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+class Padding2D final
+{
+public:
+ Padding2D() : _top{0}, _bottom{0}, _left{0}, _right{0}
+ {
+ // DO NOTHING
+ }
+
+public:
+ Padding2D(uint32_t top, uint32_t bottom, uint32_t left, uint32_t right)
+ : _top{top}, _bottom{bottom}, _left{left}, _right{right}
+ {
+ // DO NOTHING
+ }
+
+public:
+ uint32_t top(void) const { return _top; }
+ void top(uint32_t value) { _top = value; }
+
+public:
+ uint32_t bottom(void) const { return _bottom; }
+ void bottom(uint32_t value) { _bottom = value; }
+
+public:
+ uint32_t left(void) const { return _left; }
+ void left(uint32_t value) { _left = value; }
+
+public:
+ uint32_t right(void) const { return _right; }
+ void right(uint32_t value) { _right = value; }
+
+private:
+ uint32_t _top;
+ uint32_t _bottom;
+ uint32_t _left;
+ uint32_t _right;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_PADDING2D_H__
diff --git a/compiler/loco/include/loco/IR/PaddingND.h b/compiler/loco/include/loco/IR/PaddingND.h
new file mode 100644
index 000000000..59be73943
--- /dev/null
+++ b/compiler/loco/include/loco/IR/PaddingND.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_PADDINGND_H__
+#define __LOCO_IR_PADDINGND_H__
+
+#include <cstdint>
+#include <vector>
+
+namespace loco
+{
+
+/**
+ * This class indicates how many pads to add before(front) and after(back) the contents of
+ * tensor in that dimension.
+ */
+class PaddingND final
+{
+
+public:
+ const uint32_t &front(uint32_t dim) const { return _front.at(dim); }
+ uint32_t &front(uint32_t dim) { return _front.at(dim); }
+
+public:
+ const uint32_t &back(uint32_t dim) const { return _back.at(dim); }
+ uint32_t &back(uint32_t dim) { return _back.at(dim); }
+
+public:
+ uint32_t rank(void) const { return _front.size(); }
+ void rank(uint32_t s)
+ {
+ _front.resize(s);
+ _back.resize(s);
+ }
+
+private:
+ std::vector<uint32_t> _front;
+ std::vector<uint32_t> _back;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_PADDINGND_H__
diff --git a/compiler/loco/include/loco/IR/PermutingCodec.h b/compiler/loco/include/loco/IR/PermutingCodec.h
new file mode 100644
index 000000000..60b05dcbb
--- /dev/null
+++ b/compiler/loco/include/loco/IR/PermutingCodec.h
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_PERMUTING_CODEC_H__
+#define __LOCO_IR_PERMUTING_CODEC_H__
+
+#include "loco/IR/Domain.h"
+
+#include "loco/IR/FeatureAxis.h"
+#include "loco/IR/FeatureCodec.h"
+#include "loco/IR/FilterAxis.h"
+#include "loco/IR/FilterCodec.h"
+#include "loco/IR/DepthwiseFilterAxis.h"
+#include "loco/IR/DepthwiseFilterCodec.h"
+#include "loco/IR/MatrixAxis.h"
+#include "loco/IR/MatrixCodec.h"
+#include "loco/IR/TensorAxis.h"
+
+#include <map>
+
+namespace loco
+{
+
+template <Domain D> class Permutation;
+template <Domain D> class PermutingEncoder;
+template <Domain D> class PermutingDecoder;
+
+/**
+ * @brief Mapping between Feature/Tensor Axis
+ */
+template <> class Permutation<Domain::Feature>
+{
+public:
+ Permutation() = default;
+
+public:
+ /**
+ * @brief Return whether a tensor axis is specified for a given feature axis
+ *
+ * This method does not validate the corresponding value.
+ */
+ bool mapped(const FeatureAxis &axis_f) const;
+
+ /**
+ * @brief Get the tensor axis corresponding to a given feature axis
+ *
+ * This method works correclty only when feature axis is mapped before.
+ */
+ TensorAxis axis(const FeatureAxis &axis_f) const;
+
+ /**
+ * @brief Set the tensor axis corresponding to a given feature axis
+ */
+ TensorAxis &axis(const FeatureAxis &axis_f);
+
+ TensorAxis operator[](const FeatureAxis &axis_f) const { return axis(axis_f); }
+ TensorAxis &operator[](const FeatureAxis &axis_f) { return axis(axis_f); }
+
+private:
+ std::map<FeatureAxis, TensorAxis> _map;
+};
+
+template <> class PermutingEncoder<Domain::Feature> final : public FeatureEncoder
+{
+public:
+ PermutingEncoder() = default;
+
+public:
+ PermutingEncoder(const Permutation<Domain::Feature> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ FeatureShape shape(const TensorShape &tensor_shape) const override;
+ TensorIndex value(const FeatureIndex &index) const override;
+
+ std::unique_ptr<FeatureEncoder> clone(void) const override;
+
+public:
+ const Permutation<Domain::Feature> *perm(void) const { return &_perm; }
+ Permutation<Domain::Feature> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::Feature> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::Feature> _perm;
+};
+
+template <> class PermutingDecoder<Domain::Feature> final : public FeatureDecoder
+{
+public:
+ PermutingDecoder() = default;
+
+public:
+ PermutingDecoder(const Permutation<Domain::Feature> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ TensorShape shape(const FeatureShape &tensor_shape) const override;
+ FeatureIndex value(const TensorIndex &index) const override;
+
+ std::unique_ptr<FeatureDecoder> clone(void) const override;
+
+public:
+ const Permutation<Domain::Feature> *perm(void) const { return &_perm; }
+ Permutation<Domain::Feature> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::Feature> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::Feature> _perm;
+};
+
+/**
+ * @brief Mapping between Filter/Tensor Axis
+ */
+template <> class Permutation<Domain::Filter>
+{
+public:
+ Permutation() = default;
+
+public:
+ /**
+ * @brief Return whether a given filter axis has a corresponding tensor axis
+ *
+ * This method does not validate the corresponding value.
+ */
+ bool mapped(const FilterAxis &axis_f) const;
+
+ /**
+ * @brief Get the tensor axis corresponding to a given filter axis
+ *
+ * This method works correctly only for mapped filter axes.
+ */
+ const TensorAxis &axis(const FilterAxis &axis_f) const;
+
+ /**
+ * @brief Set the tensor axis corresponding to a given filter axis
+ */
+ TensorAxis &axis(const FilterAxis &axis_f);
+
+ TensorAxis operator[](const FilterAxis &axis_f) const { return axis(axis_f); }
+ TensorAxis &operator[](const FilterAxis &axis_f) { return axis(axis_f); }
+
+private:
+ std::map<FilterAxis, TensorAxis> _map;
+};
+
+/**
+ * @brief Permutation-based Tensor-to-Filter converter
+ */
+template <> class PermutingEncoder<Domain::Filter> final : public FilterEncoder
+{
+public:
+ PermutingEncoder() = default;
+
+public:
+ explicit PermutingEncoder(const Permutation<Domain::Filter> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ FilterShape shape(const TensorShape &tensor_shape) const override;
+ TensorIndex value(const FilterIndex &index) const override;
+
+public:
+ const Permutation<Domain::Filter> *perm(void) const { return &_perm; }
+ Permutation<Domain::Filter> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::Filter> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::Filter> _perm;
+};
+
+/**
+ * @brief Permutation-based Filter-to-Tensor converter
+ */
+template <> class PermutingDecoder<Domain::Filter> final : public FilterDecoder
+{
+public:
+ PermutingDecoder() = default;
+
+public:
+ explicit PermutingDecoder(const Permutation<Domain::Filter> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ TensorShape shape(const FilterShape &tensor_shape) const override;
+ FilterIndex value(const TensorIndex &index) const override;
+
+public:
+ const Permutation<Domain::Filter> *perm(void) const { return &_perm; }
+ Permutation<Domain::Filter> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::Filter> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::Filter> _perm;
+};
+
+/**
+ * @brief Mapping between DepthwiseFilter/Tensor Axis
+ */
+template <> class Permutation<Domain::DepthwiseFilter>
+{
+public:
+ Permutation() = default;
+
+public:
+ /**
+ * @brief Return whether a given depthwise filter axis has a corresponding tensor axis
+ *
+ * This method does not validate the corresponding value.
+ */
+ bool mapped(const DepthwiseFilterAxis &axis_f) const;
+
+ /**
+ * @brief Get the tensor axis corresponding to a given depthwise filter axis
+ *
+ * This method works correctly only for mapped depthwise filter axes.
+ */
+ const TensorAxis &axis(const DepthwiseFilterAxis &axis_f) const;
+
+ /**
+ * @brief Set the tensor axis corresponding to a given depthwise filter axis
+ */
+ TensorAxis &axis(const DepthwiseFilterAxis &axis_f);
+
+ TensorAxis operator[](const DepthwiseFilterAxis &axis_f) const { return axis(axis_f); }
+ TensorAxis &operator[](const DepthwiseFilterAxis &axis_f) { return axis(axis_f); }
+
+private:
+ std::map<DepthwiseFilterAxis, TensorAxis> _map;
+};
+
+/**
+ * @brief Permutation-based Tensor-to-DepthwiseFilter converter
+ */
+template <> class PermutingEncoder<Domain::DepthwiseFilter> final : public DepthwiseFilterEncoder
+{
+public:
+ PermutingEncoder() = default;
+
+public:
+ PermutingEncoder(const Permutation<Domain::DepthwiseFilter> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ DepthwiseFilterShape shape(const TensorShape &tensor_shape) const override;
+ TensorIndex value(const DepthwiseFilterIndex &index) const override;
+
+public:
+ const Permutation<Domain::DepthwiseFilter> *perm(void) const { return &_perm; }
+ Permutation<Domain::DepthwiseFilter> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::DepthwiseFilter> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::DepthwiseFilter> _perm;
+};
+
+/**
+ * @brief Permutation-based DepthwiseFilter-to-Tensor converter
+ */
+template <> class PermutingDecoder<Domain::DepthwiseFilter> final : public DepthwiseFilterDecoder
+{
+public:
+ PermutingDecoder() = default;
+
+public:
+ PermutingDecoder(const Permutation<Domain::DepthwiseFilter> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ TensorShape shape(const DepthwiseFilterShape &shape) const override;
+ DepthwiseFilterIndex value(const TensorIndex &index) const override;
+
+public:
+ const Permutation<Domain::DepthwiseFilter> *perm(void) const { return &_perm; }
+ Permutation<Domain::DepthwiseFilter> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::DepthwiseFilter> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::DepthwiseFilter> _perm;
+};
+
+/**
+ * @brief Mapping between Matrix/Tensor Axis
+ */
+template <> class Permutation<Domain::Matrix>
+{
+public:
+ Permutation() = default;
+
+public:
+ /**
+ * @brief Return whether a given matrix axis has a corresponding tensor axis
+ *
+ * This method does not validate the corresponding value.
+ */
+ bool mapped(const MatrixAxis &axis_f) const;
+
+ /**
+ * @brief Get the tensor axis corresponding to a given matrix axis
+ *
+ * This method works correctly only for mapped matrix axes.
+ */
+ TensorAxis axis(const MatrixAxis &axis_f) const;
+
+ /**
+ * @brief Set the tensor axis corresponding to a given matrix axis
+ */
+ TensorAxis &axis(const MatrixAxis &axis_f);
+
+ TensorAxis operator[](const MatrixAxis &axis_f) const { return axis(axis_f); }
+ TensorAxis &operator[](const MatrixAxis &axis_f) { return axis(axis_f); }
+
+private:
+ std::map<MatrixAxis, TensorAxis> _map;
+};
+
+/**
+ * @brief Permutation-based Tensor-to-Matrix converter
+ */
+template <> class PermutingEncoder<Domain::Matrix> final : public MatrixEncoder
+{
+public:
+ PermutingEncoder() = default;
+
+public:
+ PermutingEncoder(const Permutation<Domain::Matrix> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ MatrixShape shape(const TensorShape &tensor_shape) const override;
+ TensorIndex value(const MatrixIndex &index) const override;
+
+public:
+ const Permutation<Domain::Matrix> *perm(void) const { return &_perm; }
+ Permutation<Domain::Matrix> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::Matrix> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::Matrix> _perm;
+};
+
+/**
+ * @brief Permutation-based Matrix-to-Tensor converter
+ */
+template <> class PermutingDecoder<Domain::Matrix> final : public MatrixDecoder
+{
+public:
+ PermutingDecoder() = default;
+
+public:
+ PermutingDecoder(const Permutation<Domain::Matrix> &perm) : _perm{perm}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool valid(void) const;
+
+public:
+ TensorShape shape(const MatrixShape &tensor_shape) const override;
+ MatrixIndex value(const TensorIndex &index) const override;
+
+public:
+ const Permutation<Domain::Matrix> *perm(void) const { return &_perm; }
+ Permutation<Domain::Matrix> *perm(void) { return &_perm; }
+ void perm(const Permutation<Domain::Matrix> &p) { _perm = p; }
+
+private:
+ Permutation<Domain::Matrix> _perm;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_PERMUTING_CODEC_H__
diff --git a/compiler/loco/include/loco/IR/Stride.h b/compiler/loco/include/loco/IR/Stride.h
new file mode 100644
index 000000000..eb9d47115
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Stride.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_STRIDE_H__
+#define __LOCO_IR_STRIDE_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * @brief Stride configuration for N-dimensional spatial operations
+ */
+template <unsigned N> class Stride;
+
+/**
+ * @brief Stride configuration for 2D spatial operations
+ */
+template <> class Stride<2> final
+{
+public:
+ uint32_t vertical(void) const { return _vertical; }
+ void vertical(uint32_t value) { _vertical = value; }
+
+public:
+ uint32_t horizontal(void) const { return _horizontal; }
+ void horizontal(uint32_t value) { _horizontal = value; }
+
+private:
+ uint32_t _vertical = 1;
+ uint32_t _horizontal = 1;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_STRIDE_H__
diff --git a/compiler/loco/include/loco/IR/TensorAxis.h b/compiler/loco/include/loco/IR/TensorAxis.h
new file mode 100644
index 000000000..c41da512e
--- /dev/null
+++ b/compiler/loco/include/loco/IR/TensorAxis.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_TENSOR_AXIS_H__
+#define __LOCO_IR_TENSOR_AXIS_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+using TensorAxis = uint32_t;
+
+} // namespace loco
+
+#endif // __LOCO_IR_TENSOR_AXIS_H__
diff --git a/compiler/loco/include/loco/IR/TensorAxisSet.h b/compiler/loco/include/loco/IR/TensorAxisSet.h
new file mode 100644
index 000000000..240dcc556
--- /dev/null
+++ b/compiler/loco/include/loco/IR/TensorAxisSet.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_TENSOR_AXIS_SET_H__
+#define __LOCO_IR_TENSOR_AXIS_SET_H__
+
+#include "loco/IR/TensorAxis.h"
+
+#include <set>
+
+namespace loco
+{
+
+class TensorAxisSet final
+{
+public:
+ TensorAxisSet() = default;
+
+public:
+ bool defined(const TensorAxis &axis) const { return _axes.find(axis) != _axes.end(); }
+ void insert(const TensorAxis &axis) { _axes.insert(axis); }
+
+private:
+ std::set<TensorAxis> _axes;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_TENSOR_AXIS_SET_H__
diff --git a/compiler/loco/include/loco/IR/TensorIndex.h b/compiler/loco/include/loco/IR/TensorIndex.h
new file mode 100644
index 000000000..8f2385104
--- /dev/null
+++ b/compiler/loco/include/loco/IR/TensorIndex.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_TENSOR_INDEX_H__
+#define __LOCO_IR_TENSOR_INDEX_H__
+
+#include <nncc/core/ADT/tensor/Index.h>
+
+namespace loco
+{
+
+// TODO Remove dependencies on angkor
+using TensorIndex = nncc::core::ADT::tensor::Index;
+
+} // namespace loco
+
+#endif // __LOCO_IR_TENSOR_INDEX_H__
diff --git a/compiler/loco/include/loco/IR/TensorShape.h b/compiler/loco/include/loco/IR/TensorShape.h
new file mode 100644
index 000000000..af1066d52
--- /dev/null
+++ b/compiler/loco/include/loco/IR/TensorShape.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_TENSOR_SHAPE_H__
+#define __LOCO_IR_TENSOR_SHAPE_H__
+
+#include "loco/IR/Dimension.h"
+
+#include <initializer_list>
+#include <vector>
+
+namespace loco
+{
+
+class TensorShape
+{
+public:
+ TensorShape() = default;
+ TensorShape(std::initializer_list<Dimension> dims) : _dims(dims.begin(), dims.end()) {}
+
+public:
+ uint32_t rank(void) const { return _dims.size(); }
+ void rank(uint32_t r) { _dims.resize(r); }
+
+ const Dimension &dim(uint32_t axis) const { return _dims.at(axis); }
+ Dimension &dim(uint32_t axis) { return _dims.at(axis); }
+
+private:
+ std::vector<Dimension> _dims;
+};
+
+/**
+ * @brief Return the number of elements in a tensor of given shape
+ *
+ * NOTE 1.
+ *
+ * "volume" returns 1 if the rank is 0.
+ *
+ * NOTE 2.
+ *
+ * "caller" SHOULD pass a valid shape that has no unknown dimension.
+ * - The behavior of "volume" on invalid is undefined.
+ *
+ */
+uint32_t element_count(const loco::TensorShape *tensor_shape);
+
+} // namespace loco
+
+#endif // __LOCO_IR_TENSOR_SHAPE_H__
diff --git a/compiler/loco/include/loco/IR/Use.h b/compiler/loco/include/loco/IR/Use.h
new file mode 100644
index 000000000..a4db924e4
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Use.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_USE_H__
+#define __LOCO_IR_USE_H__
+
+#include "loco/IR/Node.forward.h"
+
+namespace loco
+{
+
+/**
+ * @brief The edge between a node definition and its user.
+ *
+ * Note that this "Use" denotes **one** edge between a node and its users,
+ * and thus there are unique node and user for each Use.
+ *
+ * There will be multiple "Use" edges for the same node if there are multiple
+ * users.
+ *
+ * This class design is heavily inspired from "Use" class in LLVM.
+ */
+class Use final
+{
+public:
+ /**
+ * @brief Construct Use with its user
+ * @note user SHOULD BE set on construction.
+ */
+ Use(Node *user) : _user{user}
+ {
+ // DO NOTHING
+ }
+
+ Use(const Use &) = delete;
+ Use(Use &&) = delete;
+
+ ~Use()
+ {
+ // Unlink itself from the node
+ node(nullptr);
+ }
+
+public:
+ Node *node(void) const { return _node; }
+ void node(Node *node);
+
+public:
+ Node *user(void) const { return _user; }
+
+private:
+ Node *_node{nullptr};
+ Node *_user{nullptr};
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_USE_H__
diff --git a/compiler/loco/include/loco/IR/Verifier.h b/compiler/loco/include/loco/IR/Verifier.h
new file mode 100644
index 000000000..8ff85e16f
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Verifier.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_VERIFIER_H__
+#define __LOCO_IR_VERIFIER_H__
+
+#include "loco/IR/Graph.h"
+
+#include <memory>
+
+namespace loco
+{
+
+/**
+ * @brief Possible error categories
+ *
+ * This enum class enumerates all the possible validation failure reasons.
+ *
+ * WARN DO NOT serialize this code. The tag value is subject to change.
+ */
+enum class ErrorCategory
+{
+ MissingArgument,
+ /* TO BE ADDED */
+};
+
+/**
+ * @brief The details of each error
+ */
+template <ErrorCategory Code> class ErrorDetail;
+
+/**
+ * @brief The details of MissingArgument error
+ */
+template <> class ErrorDetail<ErrorCategory::MissingArgument>
+{
+public:
+ ErrorDetail(loco::Node *node, uint32_t index) : _node{node}, _index{index}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /// @brief The node with missing arguments
+ loco::Node *node(void) const { return _node; }
+ /// @brief The missing argument index
+ uint32_t index(void) const { return _index; }
+
+private:
+ loco::Node *_node;
+ uint32_t _index;
+};
+
+/**
+ * @brief Error listener interface
+ *
+ * DOo NOT inherit this interface. Use DefaultErrorListener instead.
+ */
+struct IErrorListener
+{
+ virtual ~IErrorListener() = default;
+
+ virtual void notify(const ErrorDetail<ErrorCategory::MissingArgument> &) = 0;
+};
+
+/**
+ * @brief Error listener (with default implementation)
+ */
+struct ErrorListener : public IErrorListener
+{
+ virtual ~ErrorListener() = default;
+
+ void notify(const ErrorDetail<ErrorCategory::MissingArgument> &) override { return; }
+};
+
+/**
+ * @brief Validate a loco graph
+ *
+ * "valid" returns true if a given graph has no error.
+ *
+ * NOTE Given a valid(non-null) listener, "valid" notifies error details to the listener.
+ */
+bool valid(Graph *g, std::unique_ptr<ErrorListener> &&l = nullptr);
+
+} // namespace loco
+
+#endif // __LOCO_IR_VERIFIER_H__
diff --git a/compiler/loco/include/loco/IR/Window.h b/compiler/loco/include/loco/IR/Window.h
new file mode 100644
index 000000000..604fea868
--- /dev/null
+++ b/compiler/loco/include/loco/IR/Window.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_IR_WINDOW_H__
+#define __LOCO_IR_WINDOW_H__
+
+#include <cstdint>
+
+namespace loco
+{
+
+/**
+ * @brief ND Receptive Field Shape
+ *
+ * Window<N> describes the shape of N-dimensional receptive field.
+ */
+template <unsigned N> class Window;
+
+/**
+ * @brief 2D Receptive Field Shape
+ */
+template <> class Window<2> final
+{
+public:
+ uint32_t vertical(void) const { return _vertical; }
+ void vertical(uint32_t value) { _vertical = value; }
+
+public:
+ uint32_t horizontal(void) const { return _horizontal; }
+ void horizontal(uint32_t value) { _horizontal = value; }
+
+private:
+ uint32_t _vertical = 1;
+ uint32_t _horizontal = 1;
+};
+
+} // namespace loco
+
+#endif // __LOCO_IR_WINDOW_H__
diff --git a/compiler/loco/include/loco/Service/CanonicalShapeInferenceRule.h b/compiler/loco/include/loco/Service/CanonicalShapeInferenceRule.h
new file mode 100644
index 000000000..cd3bed405
--- /dev/null
+++ b/compiler/loco/include/loco/Service/CanonicalShapeInferenceRule.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_SERVICE_CANONICAL_SHAPE_INFERENCE_RULE_H__
+#define __LOCO_SERVICE_CANONICAL_SHAPE_INFERENCE_RULE_H__
+
+#include "loco/Service/ShapeInferenceRule.h"
+
+namespace loco
+{
+
+/**
+ * @brief Shape inference rule for canonical dialect
+ */
+struct CanonicalShapeInferenceRule final : public ShapeInferenceRule
+{
+ bool support(const API &ver) const final;
+ bool recognize(const Dialect *) const final;
+ bool infer(const Node *, NodeShape &) const final;
+ void infer(const Context *, const Node *, Sink *) const final;
+};
+
+} // namespace loco
+
+#endif // __LOCO_SERVICE_CANONICAL_SHAPE_INFERENCE_RULE_H__
diff --git a/compiler/loco/include/loco/Service/MultiDialectShapeInferenceRule.h b/compiler/loco/include/loco/Service/MultiDialectShapeInferenceRule.h
new file mode 100644
index 000000000..1a6c85b42
--- /dev/null
+++ b/compiler/loco/include/loco/Service/MultiDialectShapeInferenceRule.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_SERVICE_MULTI_DIALECT_SHAPE_INFERENCE_RULE_H__
+#define __LOCO_SERVICE_MULTI_DIALECT_SHAPE_INFERENCE_RULE_H__
+
+#include "loco/Service/ShapeInferenceRule.h"
+
+#include <map>
+
+namespace loco
+{
+
+/**
+ * @brief Shape inference rule for multiple dialects
+ */
+class MultiDialectShapeInferenceRule final : public ShapeInferenceRule
+{
+public:
+ bool recognize(const Dialect *) const final;
+ bool infer(const Node *, NodeShape &) const final;
+
+ /// @brief Bind a specific rule to a Dialect
+ MultiDialectShapeInferenceRule &bind(const Dialect *d, const ShapeInferenceRule *rule);
+
+private:
+ std::map<const Dialect *, const ShapeInferenceRule *> _rules;
+};
+
+} // namespace loco
+
+#endif // __LOCO_SERVICE_MULTI_DIALECT_SHAPE_INFERENCE_RULE_H__
diff --git a/compiler/loco/include/loco/Service/ShapeInference.h b/compiler/loco/include/loco/Service/ShapeInference.h
new file mode 100644
index 000000000..f7bc5d4d6
--- /dev/null
+++ b/compiler/loco/include/loco/Service/ShapeInference.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_SERVICE_SHAPE_INFERENCE_H__
+#define __LOCO_SERVICE_SHAPE_INFERENCE_H__
+
+#include "loco/Service/ShapeInferenceRule.h"
+#include "loco/IR/Graph.h"
+
+/**
+ * @file This file implements dialect-agnostic shape inference framework
+ *
+ * HOW TO USE:
+ *
+ * loco::Graph *g = ...;
+ * loco::ShapeInferenceRule *rule = ...;
+ * loco::apply(rule).to(g);
+ *
+ */
+namespace loco
+{
+
+class ShapeInferenceSession
+{
+public:
+ ShapeInferenceSession(const ShapeInferenceRule *rule) : _rule{rule}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool to(Graph *g) const;
+
+private:
+ const ShapeInferenceRule *_rule;
+};
+
+inline ShapeInferenceSession apply(ShapeInferenceRule *r) { return ShapeInferenceSession{r}; }
+
+struct ShapeInference
+{
+ static bool known(const Node *);
+ static NodeShape get(const Node *);
+ static void erase(Node *);
+};
+
+inline bool shape_known(const Node *node) { return ShapeInference::known(node); }
+inline NodeShape shape_get(const Node *node) { return ShapeInference::get(node); }
+inline void shape_erase(Node *node) { ShapeInference::erase(node); }
+
+} // namespace loco
+
+#endif // __LOCO_SERVICE_SHAPE_INFERENCE_H__
diff --git a/compiler/loco/include/loco/Service/ShapeInferenceRule.h b/compiler/loco/include/loco/Service/ShapeInferenceRule.h
new file mode 100644
index 000000000..889f0b6b2
--- /dev/null
+++ b/compiler/loco/include/loco/Service/ShapeInferenceRule.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_SERVICE_SHAPE_INFERENCE_RULE_H__
+#define __LOCO_SERVICE_SHAPE_INFERENCE_RULE_H__
+
+#include "loco/IR/Domain.h"
+#include "loco/IR/Dialect.h"
+#include "loco/IR/Node.h"
+#include "loco/IR/NodeShape.h"
+
+namespace loco
+{
+
+struct ShapeInferenceRule
+{
+ virtual ~ShapeInferenceRule() = default;
+
+ enum class API
+ {
+ /**
+ * API v1
+ *
+ * This API uses "shape_get" method to query the shape of other nodes.
+ */
+ V1,
+
+ /**
+ * API v2
+ *
+ * This API uses a given context (defined below) to query the shape of other nodes.
+ */
+ V2,
+ };
+
+ /// @brief Check whether a given API is available or not
+ virtual bool support(const API &api) const
+ {
+ // To be backward compatible
+ return api == API::V1;
+ }
+
+ /// @brief Return true if this rule recognizes a given dialect
+ virtual bool recognize(const Dialect *) const = 0;
+
+ /**
+ * @brief Infer node's shape
+ *
+ * WARNING!!
+ *
+ * Implementation SHOULD return true only when it succeeds in inference!
+ *
+ */
+ virtual bool infer(const Node *, NodeShape &) const = 0;
+
+ //
+ // API v2
+ //
+ struct Context
+ {
+ virtual ~Context() = default;
+
+ virtual bool known(const Node *node) const = 0;
+ virtual NodeShape get(const Node *node) const = 0;
+ };
+
+ struct Sink
+ {
+ virtual ~Sink() = default;
+
+ // TODO Add methods for error reporting
+
+ // Each ShapeInferenceRule SHOULD invoke one of okay and fail before it returns
+ virtual void okay(const NodeShape &) = 0;
+ virtual void fail(void) = 0;
+ };
+
+ // WARNING! Invoke this method only when API v2 is supported
+ virtual void infer(const Context *, const Node *, Sink *) const;
+};
+
+} // namespace loco
+
+#endif // __LOCO_SERVICE_SHAPE_INFERENCE_RULE_H__
diff --git a/compiler/loco/include/loco/Service/TypeInference.h b/compiler/loco/include/loco/Service/TypeInference.h
new file mode 100644
index 000000000..c2ce1a4c7
--- /dev/null
+++ b/compiler/loco/include/loco/Service/TypeInference.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019 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 __LOCO_SERVICE_TYPE_INFERENCE_H__
+#define __LOCO_SERVICE_TYPE_INFERENCE_H__
+
+#include "loco/IR/DataType.h"
+
+#include "loco/IR/Node.h"
+#include "loco/IR/Dialect.h"
+#include "loco/IR/Graph.h"
+
+#include <map>
+
+/**
+ * @file This file implements dialect-agnostic type inference framework.
+ *
+ * HOW TO USE:
+ *
+ * loco::Graph *g = ...;
+ * loco::TypeInferenceRule *rule = ...;
+ * loco::apply(rule).to(g);
+ *
+ */
+namespace loco
+{
+
+struct TypeInferenceRule
+{
+ virtual ~TypeInferenceRule() = default;
+
+ /// @brief Return true if this rule recognizes a given dialect
+ virtual bool recognize(const Dialect *) const = 0;
+
+ /**
+ * Framework guarantees the followings:
+ *
+ * 1. Framework tries to infer the data type of each node only after the data type of all of
+ * its valid (= non-nullptr) argument nodes is inferred.
+ * 2. The result of preceding "infer" is accessible through below dtype_get method.
+ * - This holds only when preceding "infer" returns true.
+ */
+ virtual bool infer(const Node *, DataType &) const = 0;
+};
+
+/**
+ * @brief Type Inference Rule for Canonical Dialect
+ */
+struct CanonicalTypeInferenceRule final : public TypeInferenceRule
+{
+ bool recognize(const Dialect *) const final;
+ bool infer(const Node *, DataType &) const final;
+};
+
+/**
+ * @brief Type Inference Rule for multiple dialects
+ */
+class MultiDialectTypeInferenceRule final : public TypeInferenceRule
+{
+public:
+ bool recognize(const Dialect *) const final;
+ bool infer(const Node *, DataType &) const final;
+
+ /// @brief Bind a specific rule to a Dialect
+ MultiDialectTypeInferenceRule &bind(const Dialect *d, const TypeInferenceRule *rule);
+
+private:
+ std::map<const Dialect *, const TypeInferenceRule *> _rules;
+};
+
+class TypeInferenceSession
+{
+public:
+ TypeInferenceSession(const TypeInferenceRule *rule) : _rule{rule}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool to(Graph *g) const;
+
+private:
+ const TypeInferenceRule *_rule;
+};
+
+inline TypeInferenceSession apply(TypeInferenceRule *r) { return TypeInferenceSession{r}; }
+
+struct TypeInference
+{
+ static bool known(const Node *);
+ static DataType get(const Node *);
+ static void erase(Node *);
+};
+
+inline bool dtype_known(const Node *node) { return TypeInference::known(node); }
+inline DataType dtype_get(const Node *node) { return TypeInference::get(node); }
+inline void dtype_erase(Node *node) { TypeInference::erase(node); }
+
+} // namespace loco
+
+#endif // __LOCO_SERVICE_TYPE_INFERENCE_H__