Browse Source

[Loops] Detect simple for loops in ILAst as well.

pull/850/head
Siegfried Pammer 8 years ago
parent
commit
f5d7b4e712
  1. 22
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 32
      ICSharpCode.Decompiler/IL/DetectedLoop.cs
  3. 19
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

22
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -316,18 +316,30 @@ namespace ICSharpCode.Decompiler.CSharp
blockStatement = ConvertAsBlock(loop.Body);
if (!loop.Body.HasFlag(InstructionFlags.EndPointUnreachable))
blockStatement.Add(new BreakStatement());
Statement iterator = null;
if (loop.IncrementBlock == null) {
// increment check is done by DetectLoop
var statement = blockStatement.Last();
while (statement is ContinueStatement)
statement = (Statement)statement.PrevSibling;
iterator = statement.Detach();
}
var forBody = ConvertBlockContainer(blockStatement, container, loop.AdditionalBlocks, true);
var forStmt = new ForStatement() {
Condition = conditionExpr,
EmbeddedStatement = forBody
};
for (int i = 0; i < loop.IncrementBlock.Instructions.Count - 1; i++) {
forStmt.Iterators.Add(Convert(loop.IncrementBlock.Instructions[i]));
}
if (loop.IncrementBlock.IncomingEdgeCount > continueCount)
forBody.Add(new LabelStatement { Label = loop.IncrementBlock.Label });
if (forBody.LastOrDefault() is ContinueStatement continueStmt2)
continueStmt2.Remove();
if (loop.IncrementBlock != null) {
for (int i = 0; i < loop.IncrementBlock.Instructions.Count - 1; i++) {
forStmt.Iterators.Add(Convert(loop.IncrementBlock.Instructions[i]));
}
if (loop.IncrementBlock.IncomingEdgeCount > continueCount)
forBody.Add(new LabelStatement { Label = loop.IncrementBlock.Label });
} else if (iterator != null) {
forStmt.Iterators.Add(iterator.Detach());
}
return forStmt;
default:
case LoopKind.While:

32
ICSharpCode.Decompiler/IL/DetectedLoop.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.Decompiler.IL
public Block ContinueJumpTarget { get; private set; } // jumps to this block are "continue;" jumps
public ILInstruction Body { get; private set; } // null in case of DoWhile
public Block[] AdditionalBlocks { get; private set; } // blocks to be merged into the loop body
public ILVariable IncrementTarget { get; private set; } // null, except in case of For
private DetectedLoop(BlockContainer container)
{
@ -106,7 +107,20 @@ namespace ICSharpCode.Decompiler.IL
if (IncrementBlock != null) {
// for-loop
Kind = LoopKind.For;
if (IncrementBlock.Instructions[0] is StLoc increment)
IncrementTarget = increment.Variable;
AdditionalBlocks = Container.Blocks.Skip(1).Where(b => b != IncrementBlock).ToArray();
} else if (trueInst is Block block) {
var variable = GetVariableFromCondition(conditionInst);
var last = block.Instructions.LastOrDefault();
var secondToLast = block.Instructions.SecondToLastOrDefault();
if (variable != null && last != null && secondToLast != null && last.MatchBranch(Container.EntryPoint) && MatchIncrement(secondToLast, variable)) {
Kind = LoopKind.For;
IncrementTarget = variable;
AdditionalBlocks = Container.Blocks.Skip(1).ToArray();
} else {
AdditionalBlocks = Container.Blocks.Skip(1).ToArray();
}
} else {
AdditionalBlocks = Container.Blocks.Skip(1).ToArray();
}
@ -126,5 +140,23 @@ namespace ICSharpCode.Decompiler.IL
}
return this;
}
static ILVariable GetVariableFromCondition(ILInstruction conditionInst)
{
var ldLocs = conditionInst.Children.OfType<LdLoc>().ToArray();
if (ldLocs.Length == 1)
return ldLocs[0].Variable;
else
return null;
}
static bool MatchIncrement(ILInstruction inst, ILVariable variable)
{
if (!inst.MatchStLoc(variable, out var value))
return false;
if (!value.MatchBinaryNumericInstruction(BinaryNumericOperator.Add, out var left, out var right))
return false;
return left.MatchLdLoc(variable) && right.MatchLdcI(out var val) && val == 1;
}
}
}

19
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -147,22 +147,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (BlockContainer possibleLoop in methodBody.Descendants.OfType<BlockContainer>().Reverse()) {
if (possibleLoop.EntryPoint.IncomingEdgeCount == 1) continue;
var loop = DetectedLoop.DetectLoop(possibleLoop);
if (loop.Kind != LoopKind.For) continue;
var condition = loop.Conditions?[0];
while (condition is LogicNot not)
condition = not.Argument;
if (condition is Comp comp) {
switch (comp.Kind) {
case ComparisonKind.GreaterThan:
case ComparisonKind.GreaterThanOrEqual:
case ComparisonKind.LessThan:
case ComparisonKind.LessThanOrEqual:
if (comp.Left.MatchLdLoc(variable)) {
isLoopCounter = true;
}
break;
}
}
if (loop.Kind != LoopKind.For || loop.IncrementTarget == null) continue;
if (loop.IncrementTarget == variable)
isLoopCounter = true;
}
if (isLoopCounter) {
// For loop variables, use i,j,k,l,m,n

Loading…
Cancel
Save