BB* BBTransform::clone(BB* src, Code* target, ClosureVersion* targetClosure) { std::vector<BB*> bbs; // Copy instructions and remember old -> new instruction map. std::unordered_map<Value*, Instruction*> relocation_table; Visitor::run(src, [&](BB* bb) { BB* theClone = BB::cloneInstrs(bb, target->nextBBId++, target); assert(bb->size() == theClone->size()); if (bb->id >= bbs.size()) bbs.resize(bb->id + 5); bbs[bb->id] = theClone; for (size_t i = 0; i < bb->size(); ++i) relocation_table[bb->at(i)] = theClone->at(i); }); // Fixup CFG: next pointers of copied BB's need to be filled in. Visitor::run(src, [&](BB* bb) { bbs[bb->id]->next0 = bbs[bb->id]->next1 = nullptr; if (bb->next0) bbs[bb->id]->next0 = bbs[bb->next0->id]; if (bb->next1) bbs[bb->id]->next1 = bbs[bb->next1->id]; }); std::unordered_map<Promise*, Promise*> promMap; // Relocate argument pointers using old -> new map BB* newEntry = bbs[src->id]; Visitor::run(newEntry, [&](Instruction* i) { auto phi = Phi::Cast(i); if (phi) { for (size_t j = 0; j < phi->nargs(); ++j) phi->updateInputAt(j, bbs[phi->inputAt(j)->id]); } i->eachArg([&](InstrArg& arg) { if (arg.val()->isInstruction()) { assert(relocation_table.count(arg.val())); arg.val() = relocation_table.at(arg.val()); } }); if (auto mk = MkArg::Cast(i)) { Promise* p = mk->prom(); if (p->owner != targetClosure) { if (promMap.count(p)) { mk->updatePromise(promMap.at(p)); } else { auto c = targetClosure->createProm(p->srcPoolIdx()); c->entry = clone(p->entry, c, targetClosure); mk->updatePromise(c); } } } }); return newEntry; }