[enco] Introduce Split pass (#1200)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Tue, 28 Aug 2018 03:03:39 +0000 (12:03 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 28 Aug 2018 03:03:39 +0000 (12:03 +0900)
This commit introduces Split pass which split a sequence of instructions
into a sequence of phases.

This Split pass marks aome of phases as Andoird NN compatible if all the
op/instruction in it have a correponds Andoird NN operation.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
contrib/enco/core/src/Backend.cpp
contrib/enco/core/src/Transforms/Split.cpp [new file with mode: 0644]
contrib/enco/core/src/Transforms/Split.h [new file with mode: 0644]

index 02a7e8d..d0e3142 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "Transforms/Duplicate.h"
 #include "Transforms/Normalize.h"
+#include "Transforms/Split.h"
 
 #include <stdexcept>
 
@@ -56,6 +57,10 @@ void Backend::compile(coco::Module *m, coco::Data *d)
   NormalizePass normalize;
   normalize.runOnCode(&code);
 
+  // Split instructions into a set of phases (each block serves as a phase)
+  SplitPass split;
+  split.runOnCode(&code);
+
   // TODO Run various transforms over enco::Code
 
   _os << CppCode{&code} << std::endl;
diff --git a/contrib/enco/core/src/Transforms/Split.cpp b/contrib/enco/core/src/Transforms/Split.cpp
new file mode 100644 (file)
index 0000000..b99be04
--- /dev/null
@@ -0,0 +1,146 @@
+#include "Split.h"
+
+#include <coco/IR.h>
+
+namespace
+{
+
+enum Compatibility
+{
+  COMPATIBLE,
+  INCOMPATIBLE
+};
+
+class ANNGroupBuilder
+{
+public:
+  ANNGroupBuilder(enco::Code *code) : _code{code}
+  {
+    // DO NOTHING
+  }
+
+public:
+  Compatibility kind(const coco::Instr *ins) const;
+  Compatibility kind(const coco::Block *blk) const;
+
+public:
+  void build(void) const;
+
+private:
+  enco::Code *_code;
+};
+
+Compatibility ANNGroupBuilder::kind(const coco::Instr *ins) const
+{
+  struct CompatibilityCheck final : public coco::Instr::Visitor<bool>,
+                                    public coco::Op::Visitor<bool>
+  {
+    //
+    // Instruction
+    //
+    bool visit(const coco::UnitF *unit) override
+    {
+      // TODO Check data layout
+      return unit->op()->accept(this);
+    }
+
+    bool visit(const coco::Shuffle *) override
+    {
+      // TODO Distinguish Reshape
+      return false;
+    }
+
+    //
+    // Op
+    //
+    bool visit(const coco::Conv2D *) override
+    {
+      // TODO Check data layout
+      return true;
+    }
+  };
+
+  return ins->accept(CompatibilityCheck{}) ? COMPATIBLE : INCOMPATIBLE;
+}
+
+Compatibility ANNGroupBuilder::kind(const coco::Block *blk) const
+{
+  return (_code->ann()->find(blk) != nullptr) ? COMPATIBLE : INCOMPATIBLE;
+}
+
+void ANNGroupBuilder::build(void) const
+{
+  auto m = _code->module();
+
+  // ANNGroupBuilder will construct a sequence of blocks from the original block sequence, and
+  // a destination block (that dst_blk points to) is the tail of the generated sequence.
+  coco::Block *dst_blk = nullptr;
+
+  auto append = [&](const Compatibility &t) {
+    auto blk = m->entity()->block()->create();
+
+    if (dst_blk == nullptr)
+    {
+      m->block()->prepend(blk);
+    }
+    else
+    {
+      blk->insertAfter(dst_blk);
+    }
+
+    dst_blk = blk;
+
+    if (COMPATIBLE == t)
+    {
+      _code->ann()->create(blk);
+    }
+  };
+
+  for (auto blk = m->block()->head(); blk;)
+  {
+    // Let's move instructions from a block of interest (referred to as source block) into
+    // a destination block
+    auto src_blk = blk;
+    blk = src_blk->next();
+    src_blk->detach();
+
+    for (auto ins = src_blk->instr()->head(); ins;)
+    {
+      auto cur_ins = ins;
+      ins = cur_ins->next();
+      cur_ins->detach();
+
+      // Create a new compatible block and use it as a destination block if the current
+      // destination block is absent or incompatible with the instruction of intereset.
+      if ((dst_blk == nullptr) || (kind(cur_ins) != kind(dst_blk)))
+      {
+        append(kind(cur_ins));
+      }
+
+      assert(dst_blk != nullptr);
+      assert(kind(cur_ins) == kind(dst_blk));
+
+      // Append ins to the dst_blk block
+      dst_blk->instr()->append(cur_ins);
+    }
+
+    // Destroy the source block
+    assert(src_blk->instr()->empty());
+    m->entity()->block()->destroy(src_blk);
+  }
+}
+
+} // namespace
+
+namespace enco
+{
+
+void SplitPass::runOnCode(enco::Code *code) const
+{
+  ANNGroupBuilder group_builder{code};
+  group_builder.build();
+
+  // TODO Construct Android NN module for each compatible block
+}
+
+} // namespace enco
diff --git a/contrib/enco/core/src/Transforms/Split.h b/contrib/enco/core/src/Transforms/Split.h
new file mode 100644 (file)
index 0000000..4781919
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __SPLIT_H__
+#define __SPLIT_H__
+
+#include "Code.h"
+
+namespace enco
+{
+
+/**
+ * @brief Split instructions into a set of phases
+ */
+class SplitPass
+{
+public:
+  void runOnCode(enco::Code *code) const;
+};
+
+} // namespace enco;
+
+#endif // __SPLIT_H__