--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantFolding.h"
+#include "Session.h"
+
+#include <queue>
+
+#include <cassert>
+
+namespace
+{
+
+/**
+ * @brief is_constant_bag(b) returns true if the bag "b" has corresponding weight
+ */
+bool is_constant_bag(coco::Bag *b)
+{
+ auto m = b->module();
+ auto d = enco::data(m);
+ return d->allocated(b);
+}
+
+class ConstantBagEnumerator
+{
+public:
+ ConstantBagEnumerator(enco::Code *code) : _code{code}
+ {
+ // DO NOTHING
+ }
+
+public:
+ template <typename Callable> void enumerate(Callable cb) const
+ {
+ auto m = _code->module();
+
+ for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
+ {
+ auto b = m->entity()->bag()->at(n);
+
+ if (is_constant_bag(b))
+ {
+ cb(b);
+ }
+ }
+ }
+
+private:
+ enco::Code *_code;
+};
+
+template <typename Callable> void operator<<(const ConstantBagEnumerator &e, Callable &&cb)
+{
+ e.enumerate(std::forward<Callable>(cb));
+}
+
+ConstantBagEnumerator constant_bag_enumerator(enco::Code *code)
+{
+ return ConstantBagEnumerator{code};
+}
+
+} // namespace
+
+namespace
+{
+
+/**
+ * @brief Take the first element from the queue
+ * @note The queue SHOULD have at least one element.
+ */
+template <typename T> T take(std::queue<T> &q)
+{
+ assert(q.size() > 0);
+ auto res = q.front();
+ q.pop();
+ return res;
+}
+
+} // namespace
+
+namespace
+{
+
+void fold_constant(std::queue<coco::Bag *> &q, coco::Copy *copy)
+{
+ auto m = copy->module();
+ auto d = enco::data(m);
+
+ auto src_obj = copy->from();
+ auto src_bag = src_obj->bag();
+
+ auto dst_obj = copy->into();
+ auto dst_bag = dst_obj->bag();
+
+ assert(d->allocated(src_bag));
+ assert(!d->allocated(dst_bag));
+
+ // TODO Support other data type
+ auto src_span = d->f32()->weight(src_bag);
+
+ assert(src_span.data() != nullptr);
+
+ auto src_feature = src_obj->asFeature();
+ auto dst_feature = dst_obj->asFeature();
+
+ // TODO Support other object type
+ if (src_feature == nullptr || dst_feature == nullptr)
+ {
+ return;
+ }
+
+ assert(src_feature != nullptr);
+ assert(dst_feature != nullptr);
+
+ // Allocate weight for destination
+ d->f32()->allocate(dst_bag);
+
+ auto dst_span = d->f32()->weight(dst_bag);
+
+ assert(src_feature->layout()->batch() == dst_feature->layout()->batch());
+ assert(src_feature->layout()->depth() == dst_feature->layout()->depth());
+ assert(src_feature->layout()->height() == dst_feature->layout()->height());
+ assert(src_feature->layout()->width() == dst_feature->layout()->width());
+
+ uint32_t const B = src_feature->layout()->batch();
+ uint32_t const C = src_feature->layout()->depth();
+ uint32_t const H = src_feature->layout()->height();
+ uint32_t const W = src_feature->layout()->width();
+
+ for (uint32_t b = 0; b < B; ++b)
+ {
+ for (uint32_t ch = 0; ch < C; ++ch)
+ {
+ for (uint32_t row = 0; row < H; ++row)
+ {
+ for (uint32_t col = 0; col < W; ++col)
+ {
+ auto src_ind = src_feature->layout()->at(b, ch, row, col);
+ auto dst_ind = dst_feature->layout()->at(b, ch, row, col);
+
+ dst_span[dst_ind.value()] = src_span[src_ind.value()];
+ }
+ }
+ }
+ }
+
+ // Let's detach copy
+ copy->from(nullptr);
+ copy->into(nullptr);
+ copy->detach();
+
+ // Let's visit destination bag!
+ q.push(dst_bag);
+}
+
+void fold_constant(std::queue<coco::Bag *> &q, coco::Instr *ins)
+{
+ if (auto copy = coco::safe_cast<coco::Copy>(ins))
+ {
+ fold_constant(q, copy);
+ return;
+ }
+}
+
+} // namespace
+
+namespace enco
+{
+
+void fold_constants(enco::Code *code)
+{
+ std::queue<coco::Bag *> q;
+
+ // Collect the initial set of "constant" bag
+ constant_bag_enumerator(code) << [&q](coco::Bag *bag) { q.push(bag); };
+
+ while (!q.empty())
+ {
+ auto candidate_bag = take(q);
+
+ // Scan the readers of each candidate bag
+ for (auto reader : coco::readers(candidate_bag))
+ {
+ // TODO Decide how to handle the reader with unknown instruction
+ if (auto ins = reader->loc())
+ {
+ fold_constant(q, ins);
+ }
+ }
+ }
+}
+
+} // namespace enco
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONSTANT_FOLDING_H__
+#define __CONSTANT_FOLDING_H__
+
+#include "Code.h"
+
+namespace enco
+{
+
+/**
+ * @brief Evaluate "constant" expressions at compile time
+ */
+void fold_constants(enco::Code *);
+
+} // namespace enco
+
+#endif // __CONSTANT_FOLDING_H__