[enco] Hoist objects across multiple shuffle(s) (#1489)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Fri, 14 Sep 2018 07:47:50 +0000 (16:47 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Fri, 14 Sep 2018 07:47:50 +0000 (16:47 +0900)
* [enco] Hoist objects across multiple shuffle(s)

This commit extends object hoist optimization pass to support object
hoist across multiple shuffle(s).

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
* Add 'Case 1' section

* Fix a typo (followinc --> following)

contrib/enco/core/src/Transforms/Optimizations.cpp
contrib/enco/core/src/Transforms/Optimizations.h

index df09e11..bd93fee 100644 (file)
@@ -105,6 +105,68 @@ bool hoistable(const coco::Shuffle *shuffle)
   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
@@ -114,6 +176,9 @@ void hoist_object(enco::Code *code)
 {
   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())
@@ -132,6 +197,63 @@ void hoist_object(enco::Code *code)
       }
     }
   }
+
+  //
+  // 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
index d606115..544153e 100644 (file)
@@ -12,6 +12,7 @@ void generate_bypass_shuffle(enco::Code *code);
 /**
  * @brief Update the base bag of each object if possible
  *
+ * --- Case 1 ---
  * Let us consider the following code:
  *
  * %bag_1 = Bag(size: 4)
@@ -37,6 +38,32 @@ void generate_bypass_shuffle(enco::Code *code);
  * 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