Browse Source

Further adjustments to transforms now that copy propagation no longer runs.

pull/1612/head
Daniel Grunwald 6 years ago
parent
commit
752f0de978
  1. 18
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  2. 15
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  3. 22
      ICSharpCode.Decompiler/IL/Transforms/DynamicIsEventAssignmentTransform.cs
  4. 4
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  5. 2
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  6. 12
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  7. 38
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

18
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -45,6 +46,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -45,6 +46,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.CancellationToken.ThrowIfCancellationRequested();
RemoveNopInstructions(block);
RemoveDeadStackStores(block);
InlineVariableInReturnBlock(block, context);
// 1st pass SimplifySwitchInstruction before SimplifyBranchChains()
@ -68,6 +70,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -68,6 +70,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop);
}
private void RemoveDeadStackStores(Block block)
{
// Previously copy propagation did this;
// ideally the ILReader would already do this,
// for now do this here (even though it's not control-flow related).
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
if (block.Instructions[i] is StLoc stloc && stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 0 && stloc.Variable.Kind == VariableKind.StackSlot) {
if (SemanticHelper.IsPure(stloc.Value.Flags)) {
block.Instructions.RemoveAt(i++);
} else {
stloc.ReplaceWith(stloc.Value);
}
}
}
}
void InlineVariableInReturnBlock(Block block, ILTransformContext context)
{
// In debug mode, the C#-compiler generates 'return blocks' that

15
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -504,26 +504,23 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -504,26 +504,23 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// stloc nativeVar(conv o->i (ldloc pinnedVar))
// if (comp(ldloc nativeVar == conv i4->i <sign extend>(ldc.i4 0))) br targetBlock
// br adjustOffsetToStringData
if (!body.EntryPoint.Instructions[0].MatchStLoc(out ILVariable nativeVar, out ILInstruction initInst))
return;
ILVariable newVar;
if (body.EntryPoint.Instructions.Count != 3) {
if (!body.EntryPoint.Instructions[0].MatchStLoc(out ILVariable nativeVar, out ILInstruction initInst)) {
// potentially a special case with legacy csc and an unused pinned variable:
if (nativeVar.IsSingleDefinition && nativeVar.LoadCount == 0 && initInst.MatchLdLoc(pinnedRegion.Variable)
&& pinnedRegion.Variable.LoadCount == 1)
{
// initInst is dead store
body.EntryPoint.Instructions.RemoveAt(0);
if (pinnedRegion.Variable.AddressCount == 0 && pinnedRegion.Variable.LoadCount == 0) {
var charPtr = new PointerType(context.TypeSystem.FindType(KnownTypeCode.Char));
newVar = new ILVariable(VariableKind.PinnedLocal, charPtr, pinnedRegion.Variable.Index);
newVar.Name = pinnedRegion.Variable.Name;
newVar.HasGeneratedName = pinnedRegion.Variable.HasGeneratedName;
nativeVar.Function.Variables.Add(newVar);
pinnedRegion.Variable.Function.Variables.Add(newVar);
pinnedRegion.Variable = newVar;
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init);
}
return;
}
if (body.EntryPoint.Instructions.Count != 3) {
return;
}
if (nativeVar.Type.GetStackType() != StackType.I)
return;

22
ICSharpCode.Decompiler/IL/Transforms/DynamicIsEventAssignmentTransform.cs

@ -95,12 +95,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -95,12 +95,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
isEventConditionUse = condition;
} else
return false;
setMemberInst = UnwrapBlockAndUnusedStore(trueInst) as DynamicSetMemberInstruction;
setMemberInst = Block.Unwrap(trueInst) as DynamicSetMemberInstruction;
if (setMemberInst == null)
return false;
if (!isEvent.Argument.Match(setMemberInst.Target).Success)
return false;
if (!(UnwrapBlockAndUnusedStore(falseInst) is DynamicInvokeMemberInstruction invokeMemberInst && invokeMemberInst.Arguments.Count == 2))
if (!(Block.Unwrap(falseInst) is DynamicInvokeMemberInstruction invokeMemberInst && invokeMemberInst.Arguments.Count == 2))
return false;
if (!isEvent.Argument.Match(invokeMemberInst.Arguments[0]).Success)
return false;
@ -110,24 +110,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -110,24 +110,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
/// <summary>
/// If <paramref name="inst"/> is a Block unwraps the block, otherwise returns inst,
/// if the block contains a stloc to a stack slot that is unused, returns the value,
/// otherwise returns inst
/// </summary>
internal static ILInstruction UnwrapBlockAndUnusedStore(ILInstruction inst)
{
var unwrapped = Block.Unwrap(inst);
if (unwrapped is StLoc stloc
&& stloc.Variable.IsSingleDefinition
&& stloc.Variable.LoadCount == 0)
{
return stloc.Value;
}
return unwrapped;
}
/// <summary>
/// if (logic.not(ldloc V_1)) Block IL_004a {
/// stloc V_2(dynamic.getmember B(target))

4
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -497,8 +497,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -497,8 +497,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!(condition is DynamicIsEventInstruction isEvent))
return false;
trueInst = DynamicIsEventAssignmentTransform.UnwrapBlockAndUnusedStore(trueInst);
falseInst = DynamicIsEventAssignmentTransform.UnwrapBlockAndUnusedStore(falseInst);
trueInst = Block.Unwrap(trueInst);
falseInst = Block.Unwrap(falseInst);
if (!(falseInst is DynamicCompoundAssign dynamicCompoundAssign))
return false;
if (!(dynamicCompoundAssign.Target is DynamicGetMemberInstruction getMember))

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

@ -283,6 +283,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -283,6 +283,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return !method.IsStatic;
case OpCode.Await:
return true;
case OpCode.NullableUnwrap:
return ((NullableUnwrap)ldloca.Parent).RefInput;
default:
return false;
}

12
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -17,22 +17,15 @@ @@ -17,22 +17,15 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Transform that converts code patterns like "v != null ? v.M() : null" to "v?.M()"
/// </summary>
struct NullPropagationTransform
readonly struct NullPropagationTransform
{
internal static bool IsProtectedIfInst(IfInstruction ifInst)
{
@ -214,6 +207,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -214,6 +207,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst = ldLen.Array;
} else if (inst is NullableUnwrap unwrap) {
inst = unwrap.Argument;
if (unwrap.RefInput && inst is AddressOf addressOf) {
inst = addressOf.Value;
}
} else if (inst is DynamicGetMemberInstruction dynGetMember) {
inst = dynGetMember.Target;
} else if (inst is DynamicInvokeMemberInstruction dynInvokeMember) {

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

@ -569,7 +569,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -569,7 +569,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
targetKind = CompoundTargetKind.Address;
if (ldobj.Target.Match(stobj.Target).Success) {
return true;
} else if (IsDuplicatedAddressComputation()) {
} else if (IsDuplicatedAddressComputation(stobj.Target, ldobj.Target)) {
// 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;
@ -577,21 +577,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -577,21 +577,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} 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;
@ -608,6 +593,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -608,6 +593,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else {
return false;
}
bool IsDuplicatedAddressComputation(ILInstruction storeTarget, ILInstruction loadTarget)
{
// 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))
while (storeTarget is LdFlda storeLdFlda && loadTarget is LdFlda loadLdFlda) {
if (!storeLdFlda.Field.Equals(loadLdFlda.Field))
return false;
storeTarget = storeLdFlda.Target;
loadTarget = loadLdFlda.Target;
}
if (!storeTarget.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(loadTarget).Success;
}
}
/// <code>

Loading…
Cancel
Save