--- /dev/null
+/*
+ * 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 __LOGO_SIMPLIFY_DOMAIN_CONVERSION_H__
+#define __LOGO_SIMPLIFY_DOMAIN_CONVERSION_H__
+
+#include <logo/Pass.h>
+
+namespace logo
+{
+
+/**
+ * @brief Simplify redundant domain conversion
+ *
+ * SimplifyDomainConversionPass recognizes the following patterns:
+ * - FeatureDecode followed by FeatureEncode
+ * - (TO BE ADDED)
+ */
+struct SimplifyDomainConversionPass final : public Pass
+{
+ const char *name(void) const final { return "SimplifyDomainConversionPass"; }
+
+ bool run(loco::Graph *g) final;
+};
+
+} // namespace logo
+
+#endif // __LOGO_SIMPLIFY_DOMAIN_CONVERSION_H__
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <logo/SimplifyDomainConversionPass.h>
+
+#include <loco/IR/Algorithm.h>
+#include <loco/IR/CanonicalDialect.h>
+#include <loco/IR/CanonicalNode.h>
+
+#include <set>
+#include <cassert>
+
+namespace logo
+{
+
+bool SimplifyDomainConversionPass::run(loco::Graph *g)
+{
+ // Let's find FeatureDecode followed by FeatureEncode
+ //
+ // TODO Introduce and Use "Pattern Match"
+ struct Collector final : public loco::CanonicalNodeMutableVisitor<void>
+ {
+ void visit(loco::FeatureEncode *encode_node) final
+ {
+ using namespace loco;
+
+ auto encoder = encode_node->encoder();
+ assert(encoder != nullptr);
+
+ auto decode_node = dynamic_cast<loco::FeatureDecode *>(encode_node->input());
+ if (decode_node == nullptr)
+ {
+ return;
+ }
+ assert(decode_node->input() != nullptr);
+
+ auto decoder = decode_node->decoder();
+ assert(decoder != nullptr);
+
+ // NOTE Work only for permuting codec
+ auto perm_decoder = dynamic_cast<const PermutingDecoder<Domain::Feature> *>(decoder);
+ auto perm_encoder = dynamic_cast<const PermutingEncoder<Domain::Feature> *>(encoder);
+
+ if (perm_encoder == nullptr || perm_decoder == nullptr)
+ {
+ return;
+ }
+
+ // TODO Move this helper into loco
+ auto equal = [](const Permutation<Domain::Feature> *lhs,
+ const Permutation<Domain::Feature> *rhs) {
+ for (const auto &axis :
+ {FeatureAxis::Count, FeatureAxis::Depth, FeatureAxis::Height, FeatureAxis::Width})
+ {
+ if (lhs->axis(axis) != rhs->axis(axis))
+ {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ if (equal(perm_encoder->perm(), perm_decoder->perm()))
+ {
+ candidates.insert({encode_node, decode_node->input()});
+ }
+ }
+
+ void visit(loco::Node *) final { return; }
+
+ std::set<std::pair<loco::FeatureEncode *, loco::Node *>> candidates;
+ };
+
+ Collector collector;
+
+ for (auto node : loco::all_nodes(g))
+ {
+ if (node->dialect() == loco::CanonicalDialect::get())
+ {
+ auto canonical_node = dynamic_cast<loco::CanonicalNode *>(node);
+ canonical_node->accept(&collector);
+ }
+ }
+
+ for (auto p : collector.candidates)
+ {
+ auto forward_node = g->nodes()->create<loco::Forward>();
+ forward_node->input(p.second);
+ replace(p.first).with(forward_node);
+ p.first->input(nullptr);
+ }
+
+ return collector.candidates.size() > 0;
+}
+
+} // namespace logo