bool ion::EliminatePhis(MIRGenerator *mir, MIRGraph &graph) { Vector<MPhi *, 16, SystemAllocPolicy> worklist; // Add all observable phis to a worklist. We use the "in worklist" bit to // mean "this phi is live". for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) { if (mir->shouldCancel("Eliminate Phis (populate loop)")) return false; MPhiIterator iter = block->phisBegin(); while (iter != block->phisEnd()) { // Flag all as unused, only observable phis would be marked as used // when processed by the work list. iter->setUnused(); // If the phi is redundant, remove it here. if (MDefinition *redundant = IsPhiRedundant(*iter)) { iter->replaceAllUsesWith(redundant); iter = block->discardPhiAt(iter); continue; } // Enqueue observable Phis. if (IsPhiObservable(*iter)) { iter->setInWorklist(); if (!worklist.append(*iter)) return false; } iter++; } } // Iteratively mark all phis reachable from live phis. while (!worklist.empty()) { if (mir->shouldCancel("Eliminate Phis (worklist)")) return false; MPhi *phi = worklist.popCopy(); JS_ASSERT(phi->isUnused()); phi->setNotInWorklist(); // The removal of Phis can produce newly redundant phis. if (MDefinition *redundant = IsPhiRedundant(phi)) { // Add to the worklist the used phis which are impacted. for (MUseDefIterator it(phi); it; it++) { if (it.def()->isPhi()) { MPhi *use = it.def()->toPhi(); if (!use->isUnused()) { use->setUnusedUnchecked(); use->setInWorklist(); if (!worklist.append(use)) return false; } } } phi->replaceAllUsesWith(redundant); } else { // Otherwise flag them as used. phi->setNotUnused(); } // The current phi is/was used, so all its operands are used. for (size_t i = 0; i < phi->numOperands(); i++) { MDefinition *in = phi->getOperand(i); if (!in->isPhi() || !in->isUnused() || in->isInWorklist()) continue; in->setInWorklist(); if (!worklist.append(in->toPhi())) return false; } } // Sweep dead phis. for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) { MPhiIterator iter = block->phisBegin(); while (iter != block->phisEnd()) { if (iter->isUnused()) iter = block->discardPhiAt(iter); else iter++; } } return true; }
bool ion::EliminatePhis(MIRGenerator *mir, MIRGraph &graph, Observability observe) { // Eliminates redundant or unobservable phis from the graph. A // redundant phi is something like b = phi(a, a) or b = phi(a, b), // both of which can be replaced with a. An unobservable phi is // one that whose value is never used in the program. // // Note that we must be careful not to eliminate phis representing // values that the interpreter will require later. When the graph // is first constructed, we can be more aggressive, because there // is a greater correspondence between the CFG and the bytecode. // After optimizations such as GVN have been performed, however, // the bytecode and CFG may not correspond as closely to one // another. In that case, we must be more conservative. The flag // |conservativeObservability| is used to indicate that eliminate // phis is being run after some optimizations have been performed, // and thus we should use more conservative rules about // observability. The particular danger is that we can optimize // away uses of a phi because we think they are not executable, // but the foundation for that assumption is false TI information // that will eventually be invalidated. Therefore, if // |conservativeObservability| is set, we will consider any use // from a resume point to be observable. Otherwise, we demand a // use from an actual instruction. Vector<MPhi *, 16, SystemAllocPolicy> worklist; // Add all observable phis to a worklist. We use the "in worklist" bit to // mean "this phi is live". for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) { if (mir->shouldCancel("Eliminate Phis (populate loop)")) return false; MPhiIterator iter = block->phisBegin(); while (iter != block->phisEnd()) { // Flag all as unused, only observable phis would be marked as used // when processed by the work list. iter->setUnused(); // If the phi is redundant, remove it here. if (MDefinition *redundant = IsPhiRedundant(*iter)) { iter->replaceAllUsesWith(redundant); iter = block->discardPhiAt(iter); continue; } // Enqueue observable Phis. if (IsPhiObservable(*iter, observe)) { iter->setInWorklist(); if (!worklist.append(*iter)) return false; } iter++; } } // Iteratively mark all phis reachable from live phis. while (!worklist.empty()) { if (mir->shouldCancel("Eliminate Phis (worklist)")) return false; MPhi *phi = worklist.popCopy(); JS_ASSERT(phi->isUnused()); phi->setNotInWorklist(); // The removal of Phis can produce newly redundant phis. if (MDefinition *redundant = IsPhiRedundant(phi)) { // Add to the worklist the used phis which are impacted. for (MUseDefIterator it(phi); it; it++) { if (it.def()->isPhi()) { MPhi *use = it.def()->toPhi(); if (!use->isUnused()) { use->setUnusedUnchecked(); use->setInWorklist(); if (!worklist.append(use)) return false; } } } phi->replaceAllUsesWith(redundant); } else { // Otherwise flag them as used. phi->setNotUnused(); } // The current phi is/was used, so all its operands are used. for (size_t i = 0; i < phi->numOperands(); i++) { MDefinition *in = phi->getOperand(i); if (!in->isPhi() || !in->isUnused() || in->isInWorklist()) continue; in->setInWorklist(); if (!worklist.append(in->toPhi())) return false; } } // Sweep dead phis. for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) { MPhiIterator iter = block->phisBegin(); while (iter != block->phisEnd()) { if (iter->isUnused()) iter = block->discardPhiAt(iter); else iter++; } } return true; }