--- /dev/null
+#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