|
|
@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool MatchWhileLoop(BlockContainer loop, out ILInstruction condition, out Block loopBody) |
|
|
|
bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// while-loop:
|
|
|
|
// while-loop:
|
|
|
|
// if (loop-condition) br loop-content-block
|
|
|
|
// if (loop-condition) br loop-content-block
|
|
|
@ -64,7 +64,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (!ifInstruction.FalseInst.MatchNop()) |
|
|
|
if (!ifInstruction.FalseInst.MatchNop()) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
condition = ifInstruction.Condition; |
|
|
|
condition = ifInstruction; |
|
|
|
var trueInst = ifInstruction.TrueInst; |
|
|
|
var trueInst = ifInstruction.TrueInst; |
|
|
|
if (!loop.EntryPoint.Instructions[1].MatchLeave(loop)) |
|
|
|
if (!loop.EntryPoint.Instructions[1].MatchLeave(loop)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -90,13 +90,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SplitConditions(ILInstruction expression, List<ILInstruction> conditions) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (expression.MatchLogicAnd(out var l, out var r)) { |
|
|
|
|
|
|
|
SplitConditions(l, conditions); |
|
|
|
|
|
|
|
SplitConditions(r, conditions); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
conditions.Add(expression); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Matches a do-while loop and performs the following transformations:
|
|
|
|
/// Matches a do-while loop and performs the following transformations:
|
|
|
|
/// - combine all compatible conditions into one IfInstruction.
|
|
|
|
/// - combine all compatible conditions into one IfInstruction.
|
|
|
|
/// - extract conditions into a condition block, or move the existing condition block to the end.
|
|
|
|
/// - extract conditions into a condition block, or move the existing condition block to the end.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="loop"></param>
|
|
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
|
|
bool MatchDoWhileLoop(BlockContainer loop) |
|
|
|
bool MatchDoWhileLoop(BlockContainer loop) |
|
|
|
{ |
|
|
|
{ |
|
|
|
(List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split) = AnalyzeDoWhileConditions(loop); |
|
|
|
(List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split) = AnalyzeDoWhileConditions(loop); |
|
|
@ -230,7 +238,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool MatchForLoop(BlockContainer loop, ILInstruction condition, Block whileLoopBody) |
|
|
|
bool MatchForLoop(BlockContainer loop, IfInstruction whileCondition, Block whileLoopBody) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// for loops have exactly two incoming edges at the entry point.
|
|
|
|
// for loops have exactly two incoming edges at the entry point.
|
|
|
|
if (loop.EntryPoint.IncomingEdgeCount != 2) |
|
|
|
if (loop.EntryPoint.IncomingEdgeCount != 2) |
|
|
@ -267,10 +275,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
// the increment variable must be local/stack variable
|
|
|
|
// the increment variable must be local/stack variable
|
|
|
|
if (incrementVariable.Kind == VariableKind.Parameter) |
|
|
|
if (incrementVariable.Kind == VariableKind.Parameter) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
// the increment variable must be checked in the condition
|
|
|
|
// split conditions:
|
|
|
|
|
|
|
|
var conditions = new List<ILInstruction>(); |
|
|
|
|
|
|
|
SplitConditions(whileCondition.Condition, conditions); |
|
|
|
|
|
|
|
IfInstruction forCondition = null; |
|
|
|
|
|
|
|
int numberOfConditions = 0; |
|
|
|
|
|
|
|
foreach (var condition in conditions) { |
|
|
|
|
|
|
|
// the increment variable must be used in the condition
|
|
|
|
if (!condition.Descendants.Any(inst => inst.MatchLdLoc(incrementVariable))) |
|
|
|
if (!condition.Descendants.Any(inst => inst.MatchLdLoc(incrementVariable))) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
// condition should not contain an assignment
|
|
|
|
|
|
|
|
if (condition.Descendants.Any(IsAssignment)) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
if (forCondition == null) { |
|
|
|
|
|
|
|
forCondition = new IfInstruction(condition, whileCondition.TrueInst, whileCondition.FalseInst); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
forCondition.Condition = IfInstruction.LogicAnd(forCondition.Condition, condition); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
numberOfConditions++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (numberOfConditions == 0) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
context.Step("Transform to for loop", loop); |
|
|
|
context.Step("Transform to for loop", loop); |
|
|
|
|
|
|
|
// split condition block:
|
|
|
|
|
|
|
|
whileCondition.ReplaceWith(forCondition); |
|
|
|
|
|
|
|
new ExpressionTransforms().Run(loop.EntryPoint, forCondition.ChildIndex, new StatementTransformContext(new BlockTransformContext(context))); |
|
|
|
|
|
|
|
for (int i = conditions.Count - 1; i >= numberOfConditions; i--) { |
|
|
|
|
|
|
|
whileLoopBody.Instructions.Insert(0, new IfInstruction(Comp.LogicNot(conditions[i]), new Leave(loop))); |
|
|
|
|
|
|
|
new ExpressionTransforms().Run(whileLoopBody, 0, new StatementTransformContext(new BlockTransformContext(context))); |
|
|
|
|
|
|
|
} |
|
|
|
// create a new increment block and add it at the end:
|
|
|
|
// create a new increment block and add it at the end:
|
|
|
|
int secondToLastIndex = secondToLast.ChildIndex; |
|
|
|
int secondToLastIndex = secondToLast.ChildIndex; |
|
|
|
var newIncremenBlock = new Block(); |
|
|
|
var newIncremenBlock = new Block(); |
|
|
@ -287,6 +320,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IsAssignment(ILInstruction inst) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (inst is StLoc) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
if (inst is CompoundAssignmentInstruction) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Returns true if the instruction is stloc v(add(ldloc v, arg))
|
|
|
|
/// Returns true if the instruction is stloc v(add(ldloc v, arg))
|
|
|
|
/// or stloc v(compound.assign(ldloc v, arg))
|
|
|
|
/// or stloc v(compound.assign(ldloc v, arg))
|
|
|
|