private void Eliminate() { HashSet <Statement> marks = new HashSet <Statement>(); // Initially, just mark those statements that contain critical statements. // These are calls to other functions, functions (which have side effects) and use statements. // Critical instructions must never be considered dead. foreach (var stm in ssa.Procedure.Statements) { if (CriticalInstruction.IsCritical(stm.Instruction)) { trace.Inform("Critical: {0}", stm.Instruction); marks.Add(stm); stm.Instruction.Accept(this); // mark all used identifiers as live. } } // Each identifier is live, so its defining statement is also live. while (liveIds.GetWorkItem(out SsaIdentifier sid)) { Statement?def = sid.DefStatement; if (def != null) { if (!marks.Contains(def)) { trace.Inform("Marked: {0}", def.Instruction); marks.Add(def); sid.DefStatement?.Instruction.Accept(this); } } } // We have now marked all the useful instructions in the code. Any non-marked // instruction is now useless and should be deleted. Now remove all uses; // we just proved that no-one uses the non-marked instructions. foreach (var sid in ssa.Identifiers) { sid.Uses.RemoveAll(u => !marks.Contains(u)); if (sid.DefStatement != null && !marks.Contains(sid.DefStatement)) { sid.DefStatement = null; } } foreach (Block b in ssa.Procedure.ControlGraph.Blocks) { int iTo = 0; for (int iStm = 0; iStm < b.Statements.Count; ++iStm) { Statement stm = b.Statements[iStm]; if (stm.Instruction is CallInstruction call) { AdjustCallWithDeadDefinitions(call); } if (marks.Contains(stm)) { b.Statements[iTo] = stm; ++iTo; } else { trace.Inform("Deleting: {0}", stm.Instruction); } } b.Statements.RemoveRange(iTo, b.Statements.Count - iTo); } AdjustApplicationsWithDeadReturnValues(); }
private void Eliminate() { liveIds = new WorkList <SsaIdentifier>(); HashSet <Statement> marks = new HashSet <Statement>(); // Initially, just mark those statements that contain critical statements. // These are calls to other functions, functions (which have side effects) and use statements. // Critical instructions must never be considered dead. foreach (var stm in proc.Statements) { if (critical.IsCritical(stm.Instruction)) { if (trace.TraceInfo) { Debug.WriteLineIf(trace.TraceInfo, string.Format("Critical: {0}", stm.Instruction)); } marks.Add(stm); stm.Instruction.Accept(this); // mark all used identifiers as live. } } // Each identifier is live, so its defining statement is also live. SsaIdentifier sid; while (liveIds.GetWorkItem(out sid)) { Statement def = sid.DefStatement; if (def != null) { if (!marks.Contains(def)) { if (trace.TraceInfo) { Debug.WriteLine(string.Format("Marked: {0}", def.Instruction)); } marks.Add(def); sid.DefStatement.Instruction.Accept(this); } } } // We have now marked all the useful instructions in the code. Any non-marked // instruction is now useless and should be deleted. foreach (Block b in proc.ControlGraph.Blocks) { for (int iStm = 0; iStm < b.Statements.Count; ++iStm) { Statement stm = b.Statements[iStm]; if (!marks.Contains(stm)) { if (trace.TraceInfo) { Debug.WriteLineIf(trace.TraceInfo, string.Format("Deleting: {0}", stm.Instruction)); } ssa.DeleteStatement(stm); --iStm; } } } AdjustApplicationsWithDeadReturnValues(); }