Browse Source

Adapt StatementBuilder.ConvertLoop to new HighLevelLoopTransform changes.

pull/976/head
Siegfried Pammer 8 years ago
parent
commit
1de895524f
  1. 138
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

138
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -680,16 +680,49 @@ namespace ICSharpCode.Decompiler.CSharp @@ -680,16 +680,49 @@ namespace ICSharpCode.Decompiler.CSharp
Statement ConvertLoop(BlockContainer container)
{
DetectedLoop loop = DetectedLoop.DetectLoop(container);
ILInstruction condition;
Block loopBody;
BlockStatement blockStatement;
continueCount = 0;
breakTarget = container;
continueTarget = loop.ContinueJumpTarget;
Expression conditionExpr;
BlockStatement blockStatement;
switch (loop.Kind) {
case LoopKind.DoWhile:
blockStatement = ConvertBlockContainer(new BlockStatement(), loop.Container, loop.AdditionalBlocks, true);
if (container.EntryPoint.IncomingEdgeCount == continueCount) {
switch (container.Kind) {
case ContainerKind.Loop:
continueTarget = container.EntryPoint;
blockStatement = ConvertBlockContainer(container, true);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
Debug.Assert(blockStatement.Statements.First() is LabelStatement);
if (container.EntryPoint.IncomingEdgeCount == continueCount + 1) {
// Remove the entrypoint label if all jumps to the label were replaced with 'continue;' statements
blockStatement.Statements.First().Remove();
}
return new WhileStatement(new PrimitiveExpression(true), blockStatement);
case ContainerKind.While:
continueTarget = container.EntryPoint;
if (!container.MatchConditionBlock(continueTarget, out condition, out loopBody))
throw new NotSupportedException("Invalid condition block in while loop.");
blockStatement = ConvertAsBlock(loopBody);
if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
blockStatement.Add(new BreakStatement());
blockStatement = ConvertBlockContainer(blockStatement, container, container.Blocks.Skip(1).Except(new[] { loopBody }), true);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
if (continueCount + 1 < container.EntryPoint.IncomingEdgeCount) {
// There's an incoming edge to the entry point (=while condition) that wasn't represented as "continue;"
// -> emit a real label
// We'll also remove any "continue;" in front of the label, as it's redundant.
if (blockStatement.LastOrDefault() is ContinueStatement)
blockStatement.Last().Remove();
blockStatement.Add(new LabelStatement { Label = container.EntryPoint.Label });
}
if (blockStatement.LastOrDefault() is ContinueStatement stmt)
stmt.Remove();
return new WhileStatement(exprBuilder.TranslateCondition(condition), blockStatement);
case ContainerKind.DoWhile:
continueTarget = container.Blocks.Last();
if (!container.MatchConditionBlock(continueTarget, out condition, out _))
throw new NotSupportedException("Invalid condition block in do-while loop.");
blockStatement = ConvertBlockContainer(new BlockStatement(), container, container.Blocks.SkipLast(1), true);
if (continueTarget.IncomingEdgeCount == continueCount) {
// Remove the entrypoint label if all jumps to the label were replaced with 'continue;' statements
blockStatement.Statements.First().Remove();
}
@ -697,85 +730,32 @@ namespace ICSharpCode.Decompiler.CSharp @@ -697,85 +730,32 @@ namespace ICSharpCode.Decompiler.CSharp
continueStmt.Remove();
return new DoWhileStatement {
EmbeddedStatement = blockStatement,
Condition = exprBuilder.TranslateCondition(CombineConditions(loop.Conditions))
Condition = exprBuilder.TranslateCondition(condition)
};
case LoopKind.For:
conditionExpr = exprBuilder.TranslateCondition(loop.Conditions[0]);
blockStatement = ConvertAsBlock(loop.Body);
if (!loop.Body.HasFlag(InstructionFlags.EndPointUnreachable))
case ContainerKind.For:
continueTarget = container.Blocks.Last();
if (!container.MatchConditionBlock(container.EntryPoint, out condition, out loopBody))
throw new NotSupportedException("Invalid condition block in for loop.");
blockStatement = ConvertAsBlock(loopBody);
if (!loopBody.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);
if (!container.MatchIncrementBlock(continueTarget))
throw new NotSupportedException("Invalid increment block in for loop.");
blockStatement = ConvertBlockContainer(blockStatement, container, container.Blocks.SkipLast(1).Skip(1).Except(new[] { loopBody }), true);
var forStmt = new ForStatement() {
Condition = conditionExpr,
EmbeddedStatement = forBody
Condition = exprBuilder.TranslateCondition(condition),
EmbeddedStatement = blockStatement
};
if (forBody.LastOrDefault() is ContinueStatement continueStmt2)
if (blockStatement.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());
for (int i = 0; i < continueTarget.Instructions.Count - 1; i++) {
forStmt.Iterators.Add(Convert(continueTarget.Instructions[i]));
}
if (continueTarget.IncomingEdgeCount > continueCount)
blockStatement.Add(new LabelStatement { Label = continueTarget.Label });
return forStmt;
case LoopKind.While:
if (loop.Body == null) {
Debug.Assert(loop.Conditions == null);
conditionExpr = new PrimitiveExpression(true);
blockStatement = ConvertBlockContainer(container, true);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
Debug.Assert(blockStatement.Statements.First() is LabelStatement);
if (container.EntryPoint.IncomingEdgeCount == continueCount + 1) {
// Remove the entrypoint label if all jumps to the label were replaced with 'continue;' statements
blockStatement.Statements.First().Remove();
}
} else {
Debug.Assert(loop.Conditions.Length == 1);
conditionExpr = exprBuilder.TranslateCondition(loop.Conditions[0]);
blockStatement = ConvertAsBlock(loop.Body);
if (!loop.Body.HasFlag(InstructionFlags.EndPointUnreachable))
blockStatement.Add(new BreakStatement());
blockStatement = ConvertBlockContainer(blockStatement, container, loop.AdditionalBlocks, true);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
if (continueCount + 1 < container.EntryPoint.IncomingEdgeCount) {
// There's an incoming edge to the entry point (=while condition) that wasn't represented as "continue;"
// -> emit a real label
// We'll also remove any "continue;" in front of the label, as it's redundant.
if (blockStatement.LastOrDefault() is ContinueStatement)
blockStatement.Last().Remove();
blockStatement.Add(new LabelStatement { Label = container.EntryPoint.Label });
}
}
if (blockStatement.LastOrDefault() is ContinueStatement stmt)
stmt.Remove();
return new WhileStatement(conditionExpr, blockStatement);
default:
throw new ArgumentOutOfRangeException();
}
}
private ILInstruction CombineConditions(ILInstruction[] conditions)
{
ILInstruction condition = null;
foreach (var c in conditions) {
if (condition == null)
condition = Comp.LogicNot(c);
else
condition = IfInstruction.LogicAnd(Comp.LogicNot(c), condition);
}
return condition;
throw new NotSupportedException();
}
BlockStatement ConvertBlockContainer(BlockContainer container, bool isLoop)

Loading…
Cancel
Save