// Visit the control instruction at the end of |block|. bool ValueNumberer::visitControlInstruction(MBasicBlock* block, const MBasicBlock* dominatorRoot) { // Look for a simplified form of the control instruction. MControlInstruction* control = block->lastIns(); MDefinition* rep = simplified(control); if (rep == control) return true; if (rep == nullptr) return false; MControlInstruction* newControl = rep->toControlInstruction(); MOZ_ASSERT(!newControl->block(), "Control instruction replacement shouldn't already be in a block"); #ifdef DEBUG JitSpew(JitSpew_GVN, " Folded control instruction %s%u to %s%u", control->opName(), control->id(), newControl->opName(), graph_.getNumInstructionIds()); #endif // If the simplification removes any CFG edges, update the CFG and remove // any blocks that become dead. size_t oldNumSuccs = control->numSuccessors(); size_t newNumSuccs = newControl->numSuccessors(); if (newNumSuccs != oldNumSuccs) { MOZ_ASSERT(newNumSuccs < oldNumSuccs, "New control instruction has too many successors"); for (size_t i = 0; i != oldNumSuccs; ++i) { MBasicBlock* succ = control->getSuccessor(i); if (HasSuccessor(newControl, succ)) continue; if (succ->isMarked()) continue; if (!removePredecessorAndCleanUp(succ, block)) return false; if (succ->isMarked()) continue; if (!rerun_) { if (!remainingBlocks_.append(succ)) return false; } } } if (!releaseOperands(control)) return false; block->discardIgnoreOperands(control); block->end(newControl); if (block->entryResumePoint() && newNumSuccs != oldNumSuccs) block->flagOperandsOfPrunedBranches(newControl); return processDeadDefs(); }
bool ValueNumberer::computeValueNumbers() { // At the end of this function, we will have the value numbering stored in // each instruction. // // We also need an "optimistic" value number, for temporary use, which is // stored in a hashtable. // // For the instruction x := y op z, we map (op, VN[y], VN[z]) to a value // number, say v. If it is not in the map, we use the instruction id. // // If the instruction in question's value number is not already // v, we break the congruence and set it to v. We repeat until saturation. // This will take at worst O(d) time, where d is the loop connectedness // of the SSA def/use graph. // // The algorithm is the simple RPO-based algorithm from // "SCC-Based Value Numbering" by Cooper and Simpson. // // If we are performing a pessimistic pass, then we assume that every // definition is in its own congruence class, since we know nothing about // values that enter Phi nodes through back edges. We then make one pass // through the graph, ignoring back edges. This yields less congruences on // any graph with back-edges, but is much faster to perform. IonSpew(IonSpew_GVN, "Numbering instructions"); if (!values.init()) return false; // Stick a VN object onto every mdefinition for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { for (MDefinitionIterator iter(*block); iter; iter++) iter->setValueNumberData(new ValueNumberData); MControlInstruction *jump = block->lastIns(); jump->setValueNumberData(new ValueNumberData); } // Assign unique value numbers if pessimistic. // It might be productive to do this in the MDefinition constructor or // possibly in a previous pass, if it seems reasonable. if (pessimisticPass_) { for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { for (MDefinitionIterator iter(*block); iter; iter++) iter->setValueNumber(iter->id()); } } else { // For each root block, add all of its instructions to the worklist. markBlock(*(graph_.begin())); if (graph_.osrBlock()) markBlock(graph_.osrBlock()); } while (count_ > 0) { #ifdef DEBUG if (!pessimisticPass_) { size_t debugCount = 0; IonSpew(IonSpew_GVN, "The following instructions require processing:"); for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { for (MDefinitionIterator iter(*block); iter; iter++) { if (iter->isInWorklist()) { IonSpew(IonSpew_GVN, "\t%d", iter->id()); debugCount++; } } if (block->lastIns()->isInWorklist()) { IonSpew(IonSpew_GVN, "\t%d", block->lastIns()->id()); debugCount++; } } if (!debugCount) IonSpew(IonSpew_GVN, "\tNone"); JS_ASSERT(debugCount == count_); } #endif for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { for (MDefinitionIterator iter(*block); iter; ) { if (!isMarked(*iter)) { iter++; continue; } JS_ASSERT_IF(!pessimisticPass_, count_ > 0); unmarkDefinition(*iter); MDefinition *ins = simplify(*iter, false); if (ins != *iter) { iter = block->discardDefAt(iter); continue; } uint32 value = lookupValue(ins); if (!value) return false; // Hashtable insertion failed if (ins->valueNumber() != value) { IonSpew(IonSpew_GVN, "Broke congruence for instruction %d (%p) with VN %d (now using %d)", ins->id(), (void *) ins, ins->valueNumber(), value); ins->setValueNumber(value); markConsumers(ins); } iter++; } // Process control flow instruction: MControlInstruction *jump = block->lastIns(); // If we are pessimistic, then this will never get set. if (!jump->isInWorklist()) continue; unmarkDefinition(jump); if (jump->valueNumber() == 0) { jump->setValueNumber(jump->id()); for (size_t i = 0; i < jump->numSuccessors(); i++) markBlock(jump->getSuccessor(i)); } } // If we are doing a pessimistic pass, we only go once through the // instruction list. if (pessimisticPass_) break; } #ifdef DEBUG for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { for (MDefinitionIterator iter(*block); iter; iter++) { JS_ASSERT(!iter->isInWorklist()); JS_ASSERT(iter->valueNumber() != 0); } } #endif return true; }