return true;
}
+std::map<coco::Instr *, uint32_t> make_sequence_map(const coco::Module *m)
+{
+ std::map<coco::Instr *, uint32_t> res;
+
+ uint32_t pos = 0;
+
+ for (auto B = m->block()->head(); B; B = B->next())
+ {
+ for (auto I = B->instr()->head(); I; I = I->next())
+ {
+ res[I] = pos++;
+ }
+ }
+
+ return res;
+}
+
+bool complete(const coco::Shuffle *s) { return s->range().size() == s->into()->size(); }
+
+bool compatible(const coco::Shuffle *s1, const coco::Shuffle *s2)
+{
+ if (s1->from() != s2->from())
+ {
+ return false;
+ }
+
+ if (s1->into()->size() != s2->into()->size())
+ {
+ return false;
+ }
+
+ auto range_1 = s1->range();
+ auto range_2 = s2->range();
+
+ if (range_1.size() != range_2.size())
+ {
+ return false;
+ }
+
+ bool res = true;
+
+ for (const auto &dst : range_2)
+ {
+ if (!s1->defined(dst))
+ {
+ res = false;
+ break;
+ }
+
+ auto src_1 = s1->at(dst);
+ auto src_2 = s2->at(dst);
+
+ if (src_1.value() != src_2.value())
+ {
+ res = false;
+ break;
+ }
+ }
+
+ return res;
+}
+
} // namespace
namespace enco
{
auto m = code->module();
+ //
+ // Case 1
+ //
for (uint32_t n = 0; n < m->entity()->instr()->size(); ++n)
{
if (auto shuffle = m->entity()->instr()->at(n)->asShuffle())
}
}
}
+
+ //
+ // Case 2
+ //
+ auto sequence_map = make_sequence_map(m);
+
+ for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
+ {
+ auto bag = m->entity()->bag()->at(n);
+
+ std::map<uint32_t, coco::Shuffle *> collected;
+
+ for (auto reader : coco::readers(bag))
+ {
+ if (auto ins = reader->loc())
+ {
+ if (auto shuffle = ins->asShuffle())
+ {
+ collected[sequence_map.at(shuffle)] = shuffle;
+ }
+ }
+ }
+
+ std::vector<coco::Shuffle *> sorted;
+
+ for (auto it = collected.begin(); it != collected.end(); ++it)
+ {
+ sorted.emplace_back(it->second);
+ }
+
+ for (uint32_t curr = 0; curr < sorted.size(); ++curr)
+ {
+ auto const curr_ins = sorted.at(curr);
+ auto const curr_bag = curr_ins->into();
+
+ if (!complete(curr_ins))
+ {
+ continue;
+ }
+
+ for (uint32_t next = curr + 1; next < sorted.size(); ++next)
+ {
+ auto const next_ins = sorted.at(next);
+ auto const next_bag = next_ins->into();
+
+ if (!complete(next_ins))
+ {
+ continue;
+ }
+
+ if (compatible(curr_ins, next_ins))
+ {
+ next_bag->replaceAllDepsWith(curr_bag);
+ }
+ }
+ }
+ }
}
} // namespace enco
/**
* @brief Update the base bag of each object if possible
*
+ * --- Case 1 ---
* Let us consider the following code:
*
* %bag_1 = Bag(size: 4)
* Shuffle(from: %bag_1, into: %bag_2, [0 -> 0])
* ...
*
+ * --- Case 2 ---
+ * Let us consider the following code:
+ *
+ * %bag_1 = Bag(size: 4)
+ * %bag_2 = Bag(size: 1)
+ * %bag_3 = Bag(size: 1)
+ *
+ * %obj_1 = ... at %bag_2
+ * %obj_2 = ... at %bag_3
+ *
+ * Shuffle(from: %bag_1, into: %bag_2, [0 -> 0]) <- shuffle_1
+ * Shuffle(from: %bag_1, into: %bag_3, [0 -> 0]) <- shuffle_2
+ *
+ * Note that the content of %bag_3 after shuffle_2 is identical to that of %bag_2 after shuffle_1,
+ * so the following code is identical to the above one:
+ *
+ * %bag_1 = Bag(size: 4)
+ * %bag_2 = Bag(size: 1)
+ * %bag_3 = Bag(size: 1)
+ *
+ * %obj_1 = ... at %bag_2
+ * %obj_2 = ... at %bag_2 <- HERE
+ *
+ * Shuffle(from: %bag_1, into: %bag_2, [0 -> 0]) <- shuffle_1
+ * Shuffle(from: %bag_1, into: %bag_3, [0 -> 0]) <- shuffle_2
+ *
* "hoist_object" optimization rewrites the former code as the latter one.
*
* NOTE "hoist_object" DOES NOT change any instruction. It just updates the base bag of objects of