Browse Source

Slightly generalize the post-increment transform so that it no longer depends on copy propagation.

pull/1612/head
Daniel Grunwald 6 years ago
parent
commit
97d490a3df
  1. 5
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  2. 37
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

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

@ -66,7 +66,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -66,7 +66,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (SemanticHelper.IsPure(copiedExpr.Flags)) {
// no-op -> delete
context.Step("remove dead store to stack: no-op -> delete", block.Instructions[i]);
block.Instructions.RemoveAt(i--);
block.Instructions.RemoveAt(i);
// This can open up new inlining opportunities:
int c = ILInlining.InlineInto(block, i, InliningOptions.None, context: context);
i -= c + 1;
} else {
// evaluate the value for its side-effects
context.Step("remove dead store to stack: evaluate the value for its side-effects", block.Instructions[i]);

37
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -547,10 +547,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -547,10 +547,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Some transforms effectively move a store around,
/// which is only valid if the variable stored to does not occur in the compound load/store.
/// </param>
/// <param name="previousInstruction">
/// Instruction preceding the load.
/// </param>
static bool IsMatchingCompoundLoad(ILInstruction load, ILInstruction store,
out ILInstruction target, out CompoundTargetKind targetKind,
out Action<ILTransformContext> finalizeMatch,
ILVariable forbiddenVariable = null)
ILVariable forbiddenVariable = null,
ILInstruction previousInstruction = null)
{
target = null;
targetKind = 0;
@ -563,7 +567,31 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -563,7 +567,31 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
target = ldobj.Target;
targetKind = CompoundTargetKind.Address;
return ldobj.Target.Match(stobj.Target).Success;
if (ldobj.Target.Match(stobj.Target).Success) {
return true;
} else if (IsDuplicatedAddressComputation()) {
// Use S_0 as target, so that S_0 can later be eliminated by inlining.
// (we can't eliminate previousInstruction right now, because it's before the transform's starting instruction)
target = stobj.Target;
return true;
} else {
return false;
}
bool IsDuplicatedAddressComputation()
{
// Sometimes roslyn duplicates the address calculation:
// stloc S_0(ldloc refParam)
// stloc V_0(ldobj System.Int32(ldloc refParam))
// stobj System.Int32(ldloc S_0, binary.add.i4(ldloc V_0, ldc.i4 1))
if (!stobj.Target.MatchLdLoc(out var s))
return false;
if (!(s.Kind == VariableKind.StackSlot && s.IsSingleDefinition && s != forbiddenVariable))
return false;
if (s.StoreInstructions.SingleOrDefault() != previousInstruction)
return false;
return previousInstruction is StLoc addressStore && addressStore.Value.Match(ldobj.Target).Success;
}
} else if (MatchingGetterAndSetterCalls(load as CallInstruction, store as CallInstruction, out finalizeMatch)) {
if (forbiddenVariable != null && forbiddenVariable.IsUsedWithin(load))
return false;
@ -677,8 +705,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -677,8 +705,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// 'stloc tmp' is implicitly truncating the value
return false;
}
if (!IsMatchingCompoundLoad(inst.Value, store, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: inst.Variable))
if (!IsMatchingCompoundLoad(inst.Value, store, out var target, out var targetKind, out var finalizeMatch,
forbiddenVariable: inst.Variable,
previousInstruction: block.Instructions.ElementAtOrDefault(i - 1))) {
return false;
}
if (UnwrapSmallIntegerConv(value, out var conv) is BinaryNumericInstruction binary) {
if (!binary.Left.MatchLdLoc(tmpVar) || !binary.Right.MatchLdcI(1))
return false;

Loading…
Cancel
Save