// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Peephole::DoOneIteration(Function* function) { bool changed = false; int position = 0; while(position < worklist_.Count()) { // Get the instruction at the current position and try to simplify it. Instruction* instr = worklist_[position++]; // Branching instructions don't have any resulting operand, // and report a simplification by returning 'true'. if(instr->IsBranching()) { changed |= ProcessBranching(instr); continue; } // For all other kinds of instructions. // If the result is 'nullptr' nothing could be simplified. auto result = Simplify(instr); if(result == nullptr) continue; if(result->IsUndefinedConstant()) { if(HandleUndefinedResult(instr)) { // The instruction should not be considered below. continue; } } // Replace the previous result operand with the new one // in all instructions that use it as a source operand. instr->GetDestinationOp()->ReplaceWith(result); InstructionSimplified(instr, result); HandleSpecialCases(instr, result); changed = true; #if 1 IRPrinter(function).Dump(); #endif } // Some instructions may be dead now; delete them here, so that // the next iteration doesn't consider them anymore. Note that // this is necessary, else we would enter an infinite loop simplifying // the same instructions again and again... if(changed) DeleteDeadInstructions(function); return changed; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AggregateCopyPropagation::ReplaceWithOriginal(LoadInstr* instr, TOperandToIdDict& availableCopies, BitVector& killSet) { if(availableCopies.Count() == 0) { return; } // Try to replace each operand with the original one // (the one from which the copy was made). Instruction* lastInstr = nullptr; auto candidateOp = GetBaseOperand(instr->SourceOp(), &lastInstr); // Give up if we couldn't find a candidate, // or if the candidate is an instruction whose result // is used in more than one place. if((candidateOp == nullptr) || (lastInstr == nullptr) || (lastInstr->GetDestinationOp()->HasSingleUser() == false)) { return; } // We can replace the operand if it's a copy // (found in 'availableCopies') and the source or copy // was not killed until this point. CopySetInfo info; if(GetOldestAvailable(candidateOp, availableCopies, killSet, info)) { if(info.IsCopy) { // Replace the operand with the original. auto originalOp = info.Source; lastInstr->ReplaceSourceOp(0, originalOp); info.Replacements++; CopyPropagated(instr); } else if(instr->HasDestinationOp()) { // The load itself is replaced by the value // to which the record/array was set. auto requiredType = instr->GetDestinationOp()->GetType(); auto constantOp = CreateConstant(requiredType, info); instr->GetDestinationOp()->ReplaceWith(constantOp); info.Replacements++; CopyPropagated(instr); } } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AggregateCopyPropagation::ReplaceWithOriginal(CallInstr* instr, TOperandToIdDict& availableCopies, BitVector& killSet) { // Check if any of the arguments can be replaced // with the original operand. for(int i = 0; i < instr->ArgumentCount(); i++) { auto argument = instr->GetArgument(i); Instruction* lastInstr = nullptr; auto candidateOp = GetBaseOperand(argument, &lastInstr); // Give up if we couldn't find a candidate, // or if the candidate is used by an instruction // whose result is used in more than one place. if((candidateOp == nullptr) || (lastInstr && (lastInstr->GetDestinationOp()->HasSingleUser() == false))) { return; } // Check if this is a copy. CopySetInfo info; if(GetOldestAvailable(candidateOp, availableCopies, killSet, info)) { if(info.IsCopy) { // Replace the operand with the original. auto originalOp = info.Source; info.Replacements++; CopyPropagated(instr); // If the copy is used by an instruction, we modify // that instruction, else we replace the call argument. if(lastInstr) { lastInstr->ReplaceSourceOp(0, originalOp); } else instr->ReplaceArgument(i, originalOp); } } } }