// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RecursionElimination::ReplaceParameters() { // As it is now, the function still uses the parameters // in SSA form directly, but now it should use // the 'phi' instructions from the old entry block. // We use a dictionary to map from parameter to 'phi' result. Dictionary<Parameter*, Operand*> paramToPhi; DebugValidator::AreEqual(funct_->ParameterCount(), parameterPhis_.Count()); for(int i = 0; i < funct_->ParameterCount(); i++) { paramToPhi.Add(funct_->GetParameter(i), parameterPhis_[i]->ResultOp()); } // Scan all instructions and do the replacements. auto oldEntryBlock = oldEntryBlock_; funct_->ForEachInstruction([¶mToPhi, oldEntryBlock] (Instruction* instr) -> bool { if(instr->IsPhi() && (instr->ParentBlock() == oldEntryBlock)) { // The 'phi's int the old entry block // shouldn't have their operands changed. return true; } for(int i = 0; i < instr->SourceOpCount(); i++) { if(auto parameter = instr->GetSourceOp(i)->As<Parameter>()) { DebugValidator::IsTrue(paramToPhi.ContainsKey(parameter)); instr->ReplaceSourceOp(i, paramToPhi[parameter]); } } return true; }); }
void SimpleDeadCodeElimination::Execute(Function* function) { StaticList<Instruction*, 512> worklist; Dictionary<Instruction*, bool> inWorklist; // If an instruction is in the worklist. // Try to remove 'store' instructions that have no effect. // The algorithm is really simple, but should catch cases like // arrays initialized with constants that were propagated already. RemoveDeadStores(function); // Try to remove copy/set operations that are unused, // because the aggregates they target are never referenced. RemoveDeadCopyOperations(function); // We process the blocks from last to first, and the instructions in the block // from last to first too; this allows removing more instructions on each // iteration that the usual first-last order. for(auto block = function->LastBlock(); block; block = block->PreviousBlock()) { // If the block is unreachable we remove all instructions from it, // but don't remove the block; this will be handled by the CFG Simplifier, // which knows how to repair the Dominator Tree. if(block->IsUnreachable() && (block->IsEmpty() == false)) { CleanUnreachableBlock(block); continue; } for(auto instr = block->LastInstruction(); instr; instr = instr->PreviousInstruction()) { if(GetSafetyInfo()->IsDefinitelyDead(instr)) { worklist.Add(instr); inWorklist.Add(instr, true); } } } // Process while we have instructions in the worklist. while(worklist.IsNotEmpty()) { auto instr = worklist.RemoveLast(); inWorklist.Remove(instr); // Remove the instruction if it's dead. if(GetSafetyInfo()->IsDefinitelyDead(instr)) { // All the instructions that where used by this one // may be dead now, add them to the worklist. for(int i = 0; i < instr->SourceOpCount(); i++) { auto sourceOp = instr->GetSourceOp(i); // Make sure we don't add an instruction in the worklist twice. if(auto definingInstr = sourceOp->DefiningInstruction()) { if(inWorklist.ContainsKey(definingInstr) == false) { worklist.Add(definingInstr); inWorklist.Add(definingInstr, true); } } } InstructionRemoved(instr); instr->RemoveFromBlock(true /* free */); } } // If there were removed stored we may now have variables // that are not used by any instruction. RemoveDeadVariables(function); }
bool WasInstructionProcessed(Instruction* instr) { return processedInstrs_.ContainsKey(instr); }
// Sets the number of volatile operations for the specified function. void SetVolatileCount(Function* function, int value) { if(volatileCount_.ContainsKey(function)) { volatileCount_[function] = value; } else volatileCount_.Add(function, value); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Returns the number of volatile operations from the specified function. int GetVolatileCount(Function* function) { if(volatileCount_.ContainsKey(function)) { return volatileCount_[function]; } else return 0; }