#include "Code.h"
#include "CppCode.h"
+#include "Transforms/Duplicate.h"
+
#include <stdexcept>
namespace
{
Code code{m, d};
+ // As explained below, the current implementation does not work if there is a pair of input/ouput
+ // that share the same bag as their underlying bag.
+ //
+ // This DuplicatePass creates a copy of such bags in order to eliminate such a pair.
+ DuplicatePass duplicate;
+ duplicate.runOnCode(&code);
+
// The current implementation will assign memory region for each bag as follows:
// Bind input bag to the region provided by Network_input_bind
// Bind output bag to the region provided by Network_output_bind
--- /dev/null
+#include "Duplicate.h"
+
+#include <map>
+#include <set>
+
+#include <cassert>
+
+namespace
+{
+
+coco::Block *find_or_create_first_block(coco::Module *m)
+{
+ if (m->block()->empty())
+ {
+ auto blk = m->entity()->block()->create();
+ m->block()->append(blk);
+ return blk;
+ }
+
+ return m->block()->head();
+}
+
+} // namespace
+
+namespace enco
+{
+
+void DuplicatePass::runOnModule(coco::Module *m) const
+{
+ // Let's find candidates
+ std::set<coco::Bag *> candidates;
+
+ for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
+ {
+ auto bag = m->entity()->bag()->at(n);
+
+ if (bag->isInput() && bag->isOutput())
+ {
+ candidates.insert(bag);
+ }
+ }
+
+ // Return if there is no candidate
+ if (candidates.empty())
+ {
+ return;
+ }
+
+ std::map<const coco::Bag *, coco::Input *> input_map;
+ std::map<const coco::Bag *, coco::Output *> output_map;
+
+ for (uint32_t n = 0; n < m->input()->size(); ++n)
+ {
+ auto input = m->input()->at(n);
+ assert(input->bag() != nullptr);
+ input_map[input->bag()] = input;
+ }
+
+ for (uint32_t n = 0; n < m->output()->size(); ++n)
+ {
+ auto output = m->output()->at(n);
+ assert(output->bag() != nullptr);
+ output_map[output->bag()] = output;
+ }
+
+ // For each in/out bag,
+ // 1. Create a new bag of the same size
+ // 2. Copy the content from the original bag
+ // 3. Mark the newly created bag as an output
+ for (const auto &candidate : candidates)
+ {
+ assert(candidate->updates().empty());
+ assert(input_map.find(candidate) != input_map.end());
+ assert(output_map.find(candidate) != output_map.end());
+
+ auto src = candidate;
+ auto dst = m->entity()->bag()->create(src->size());
+
+ // Create a copy instruction
+ auto shuffle = m->entity()->instr()->create<coco::Shuffle>();
+
+ shuffle->from(src);
+ shuffle->into(dst);
+
+ for (uint32_t n = 0; n < src->size(); ++n)
+ {
+ shuffle->at(n) = coco::ElemID{n};
+ }
+
+ find_or_create_first_block(m)->instr()->prepend(shuffle);
+
+ // Let's use the new bag as an output
+ output_map.at(src)->bag(dst);
+ }
+}
+
+void DuplicatePass::runOnCode(Code *code) const { runOnModule(code->module()); }
+
+} // namespace enco