summaryrefslogtreecommitdiff
path: root/compiler/enco/core/src/Transforms/FeatureUnification.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/enco/core/src/Transforms/FeatureUnification.cpp')
-rw-r--r--compiler/enco/core/src/Transforms/FeatureUnification.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/compiler/enco/core/src/Transforms/FeatureUnification.cpp b/compiler/enco/core/src/Transforms/FeatureUnification.cpp
new file mode 100644
index 000000000..1a7a0a8a4
--- /dev/null
+++ b/compiler/enco/core/src/Transforms/FeatureUnification.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FeatureUnification.h"
+#include "IRUtils.h"
+
+#include <stdex/Memory.h>
+
+#include <set>
+#include <vector>
+
+#include <cassert>
+
+using stdex::make_unique;
+
+namespace
+{
+
+bool is_static_layout(const coco::FeatureLayout::ID *id)
+{
+ if (id == coco::FeatureLayouts::BHWC::uid())
+ {
+ return true;
+ }
+
+ if (id == coco::FeatureLayouts::BCHW::uid())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool is_static_layout(const coco::FeatureLayout *l) { return is_static_layout(l->id()); }
+bool is_static_layout(const coco::FeatureObject *f) { return is_static_layout(f->layout()); }
+
+/**
+ * @brief Return ture if a given 'feature' is the candidate of unification
+ */
+bool candidate(const coco::FeatureObject *f) { return is_static_layout(f); }
+
+/**
+ * @brief Return true if two features are compatible
+ *
+ * Two features are referred to as compatible if these feature are interchangeable.
+ *
+ * NOTE The current implementation of "compatible" is sound, but incomplete.
+ *
+ * Soundness:
+ * For all feature objects "lhs" and "rhs" that "compatible(lhs, rhs)" returns true,
+ * "lhs" and "rhs" are interchangeable.
+ *
+ * Completeness:
+ * For all interchangeable feature objects "lhs" and "rhs", "compatible(lhs, rhs)" returns true.
+ */
+bool compatible(const coco::FeatureObject *lhs, const coco::FeatureObject *rhs)
+{
+ assert(candidate(lhs) && candidate(rhs));
+
+ if (lhs->layout()->id() != rhs->layout()->id())
+ {
+ return false;
+ }
+
+ if (lhs->layout()->batch() != rhs->layout()->batch())
+ {
+ return false;
+ }
+
+ if (!(lhs->layout()->shape() == rhs->layout()->shape()))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @brief A FeatureGroup denotes a group of FeatureObject(s)
+ *
+ * Each FeatureGroup includes at most 1 DEF FeatureObject (a FeatureObject that has a producer),
+ * and may include multiple USE FeatureObject(s) (a FeatureObject that has no producer).
+ *
+ * NOTE FeatureUnification pass internally uses this FeatureGroup to store a group of compatible
+ * FeatureObject(s)
+ */
+class FeatureGroup
+{
+public:
+ explicit FeatureGroup(coco::FeatureObject *feature) { insert(feature); }
+
+public:
+ uint32_t size(void) const { return _uses.size() + (_def ? 1 : 0); }
+
+public:
+ void insert(coco::FeatureObject *feature)
+ {
+ if (feature->def() != nullptr)
+ {
+ assert(_def == nullptr);
+ _def = feature;
+ }
+ else
+ {
+ _uses.insert(feature);
+ }
+ }
+
+public:
+ coco::FeatureObject *parent(void) const
+ {
+ if (_def)
+ {
+ return _def;
+ }
+
+ assert(_uses.size() > 0);
+ return *(_uses.begin());
+ }
+
+public:
+ std::set<coco::FeatureObject *> children(void) const
+ {
+ auto res = _uses;
+ res.erase(parent());
+ return res;
+ }
+
+private:
+ coco::FeatureObject *_def = nullptr;
+ std::set<coco::FeatureObject *> _uses;
+};
+
+} // namespace
+
+namespace enco
+{
+
+void unify_feature(enco::Code *code)
+{
+ auto m = code->module();
+
+ for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
+ {
+ std::vector<std::unique_ptr<FeatureGroup>> groups;
+
+ auto assign_group = [&](coco::FeatureObject *feature) {
+ // Find a compatible FeatureGroup
+ FeatureGroup *group = nullptr;
+
+ for (const auto &g : groups)
+ {
+ FeatureGroup *candidate = g.get();
+
+ if (!compatible(candidate->parent(), feature))
+ {
+ continue;
+ }
+
+ group = candidate;
+ break;
+ }
+
+ if (group == nullptr)
+ {
+ // Insert FeatureObject into a new FeatureGroup
+ groups.emplace_back(make_unique<FeatureGroup>(feature));
+ }
+ else
+ {
+ // Insert FeatureObject into the compatible FeatureGroup
+ group->insert(feature);
+ }
+ };
+
+ auto bag = m->entity()->bag()->at(n);
+
+ for (auto o : coco::dependent_objects(bag))
+ {
+ if (auto feature = o->asFeature())
+ {
+ if (candidate(feature))
+ {
+ assign_group(feature);
+ }
+ }
+ }
+
+ for (const auto &g : groups)
+ {
+ auto group = g.get();
+ for (const auto child : group->children())
+ {
+ subst(child, group->parent());
+ assert(child->def() == nullptr);
+ assert(child->uses()->size() == 0);
+ m->entity()->object()->destroy(child);
+ }
+ }
+ }
+}
+
+} // namespace enco