Browse Source

Improve RemoveDeadVariableInit and CopyPropagation

pull/900/head
Siegfried Pammer 8 years ago
parent
commit
9e2f98cb8d
  1. 2
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  2. 28
      ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs

2
ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (block.Instructions[i].MatchStLoc(out v, out copiedExpr)) { if (block.Instructions[i].MatchStLoc(out v, out copiedExpr)) {
if (v.IsSingleDefinition && v.LoadCount == 0 && v.Kind == VariableKind.StackSlot) { if (v.IsSingleDefinition && v.LoadCount == 0 && v.Kind == VariableKind.StackSlot) {
// dead store to stack // dead store to stack
if (copiedExpr.Flags == InstructionFlags.None) { if (SemanticHelper.IsPure(copiedExpr.Flags)) {
// no-op -> delete // no-op -> delete
context.Step("remove dead store to stack: no-op -> delete", block.Instructions[i]); context.Step("remove dead store to stack: no-op -> delete", block.Instructions[i]);
block.Instructions.RemoveAt(i--); block.Instructions.RemoveAt(i--);

28
ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
namespace ICSharpCode.Decompiler.IL.Transforms namespace ICSharpCode.Decompiler.IL.Transforms
@ -37,13 +39,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
v.HasInitialValue = false; v.HasInitialValue = false;
} }
} }
if (function.IsIterator || function.IsAsync) { // Remove dead stores to variables that are never read from.
// In yield return + async, the C# compiler tends to store null/default(T) to variables // If the stored value has some side-effect, the value is unwrapped.
// when the variable goes out of scope. Remove such useless stores. // This is necessary to remove useless stores generated by some compilers, e.g., the F# compiler.
foreach (var v in function.Variables) { // In yield return + async, the C# compiler tends to store null/default(T) to variables
if (v.Kind == VariableKind.Local && v.StoreCount == 1 && v.LoadCount == 0 && v.AddressCount == 0) { // when the variable goes out of scope.
if (v.StoreInstructions[0] is StLoc stloc && (stloc.Value.MatchLdNull() || stloc.Value is DefaultValue) && stloc.Parent is Block block) { var variableQueue = new Queue<ILVariable>(function.Variables.Where(v => v.Kind == VariableKind.Local || v.Kind == VariableKind.StackSlot));
while (variableQueue.Count > 0) {
var v = variableQueue.Dequeue();
if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot)
continue;
if (v.LoadCount != 0 || v.AddressCount != 0)
continue;
foreach (var stloc in v.StoreInstructions.OfType<StLoc>().ToArray()) {
if (stloc.Parent is Block block) {
if (SemanticHelper.IsPure(stloc.Value.Flags)) {
block.Instructions.Remove(stloc); block.Instructions.Remove(stloc);
} else {
stloc.ReplaceWith(stloc.Value);
}
if (stloc.Value is LdLoc ldloc && (ldloc.Variable.Kind == VariableKind.Local || ldloc.Variable.Kind == VariableKind.StackSlot)) {
variableQueue.Enqueue(ldloc.Variable);
} }
} }
} }

Loading…
Cancel
Save