diff --git a/src/AstBuilder.cs b/src/AstBuilder.cs index 87ac38f39..2a526bc09 100644 --- a/src/AstBuilder.cs +++ b/src/AstBuilder.cs @@ -29,7 +29,6 @@ namespace Decompiler } if (Options.ReduceAstLoops) { astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); } if (Options.ReduceAstOther) { astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null); diff --git a/src/ControlFlow/Node-Optimize.cs b/src/ControlFlow/Node-Optimize.cs index 0c1ab7005..e3c527292 100644 --- a/src/ControlFlow/Node-Optimize.cs +++ b/src/ControlFlow/Node-Optimize.cs @@ -13,7 +13,7 @@ namespace Decompiler.ControlFlow OptimizeLoops(); } if (Options.ReduceConditonals) { - OptimizeIf(); + OptimizeConditions(); } } @@ -43,33 +43,38 @@ namespace Decompiler.ControlFlow } } - NodeCollection GetReachableNodes(Node exclude) + NodeCollection GetReachableNodes() { NodeCollection reachableNodes = new NodeCollection(); reachableNodes.Add(this); for(int i = 0; i < reachableNodes.Count; i++) { - reachableNodes.AddRange(reachableNodes[i].Successors); - reachableNodes.Remove(exclude); + foreach(Node alsoReachable in reachableNodes[i].Successors) { + // Do not go though the head child + if (alsoReachable != this.Parent.HeadChild) { + reachableNodes.Add(alsoReachable); + } + } } return reachableNodes; } - public void OptimizeIf() + public void OptimizeConditions() { foreach(Node child in this.Childs) { if (child is Loop) { - child.OptimizeIf(); + child.OptimizeConditions(); } } Node conditionNode = this.HeadChild; - // Find conditionNode (the start) while(conditionNode != null) { - if (conditionNode is BasicBlock && conditionNode.Successors.Count == 2) { - // Found if start + // Keep looking for some conditional block + if (conditionNode is BasicBlock && ((BasicBlock)conditionNode).IsConditionalBranch) { + // Found start of conditional OptimizeIf((BasicBlock)conditionNode); + // Restart conditionNode = this.HeadChild; - continue; // Restart + continue; } else if (conditionNode.Successors.Count > 0) { // Keep looking down conditionNode = conditionNode.Successors[0]; @@ -87,12 +92,9 @@ namespace Decompiler.ControlFlow { Node trueStart = condition.FloatUpToNeighbours(condition.FallThroughBasicBlock); Node falseStart = condition.FloatUpToNeighbours(condition.BranchBasicBlock); - Debug.Assert(trueStart != null); - Debug.Assert(falseStart != null); - Debug.Assert(trueStart != falseStart); - NodeCollection trueReachable = trueStart.GetReachableNodes(condition); - NodeCollection falseReachable = falseStart.GetReachableNodes(condition); + NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; + NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable); NodeCollection trueNodes = trueReachable.Clone(); @@ -111,11 +113,14 @@ namespace Decompiler.ControlFlow trueNodes.MoveTo(conditionalNode.TrueBody); if (Options.ReduceGraph-- <= 0) return; - falseNodes.MoveTo(conditionalNode.FalseBody); + // We can exit the 'true' part of Loop or MethodBody conviently using 'break' or 'return' + if (commonReachable.Count > 0 && (conditionalNode.Parent is Loop || conditionalNode.Parent is MethodBodyGraph)) { + falseNodes.MoveTo(conditionalNode.FalseBody); + } // Optimize the created subtrees - conditionalNode.TrueBody.OptimizeIf(); - conditionalNode.FalseBody.OptimizeIf(); + conditionalNode.TrueBody.OptimizeConditions(); + conditionalNode.FalseBody.OptimizeConditions(); } } } diff --git a/src/ControlFlow/NodeCollection.cs b/src/ControlFlow/NodeCollection.cs index b0f4b2084..eae0ad78b 100644 --- a/src/ControlFlow/NodeCollection.cs +++ b/src/ControlFlow/NodeCollection.cs @@ -19,6 +19,8 @@ namespace Decompiler.ControlFlow public class NodeCollection: System.Collections.ObjectModel.Collection { + public static NodeCollection Empty = new NodeCollection(); + public event EventHandler Added; public event EventHandler Removed; diff --git a/src/Transforms/Ast/RestoreLoop.cs b/src/Transforms/Ast/RestoreLoop.cs index 2f18e8363..b4aa400a8 100644 --- a/src/Transforms/Ast/RestoreLoop.cs +++ b/src/Transforms/Ast/RestoreLoop.cs @@ -40,6 +40,26 @@ namespace Decompiler.Transforms.Ast } } + // Restore loop condition (version 2) + if (forStatement.Condition.IsNull) { + IfElseStatement condition = forStatement.EmbeddedStatement.Children.First as IfElseStatement; + if (condition != null && + condition.TrueStatement[0] is BlockStatement && + condition.TrueStatement[0].Children.Count == 1 && + condition.TrueStatement[0].Children.First is BreakStatement && + condition.FalseStatement[0] is BlockStatement && + condition.FalseStatement[0].Children.Count == 0) + { + UnaryOperatorExpression negExpr = condition.Condition as UnaryOperatorExpression; + if (negExpr != null && + negExpr.Op == UnaryOperatorType.Not) { + + condition.Remove(); + forStatement.Condition = negExpr.Expression; + } + } + } + // Restore loop iterator if (forStatement.EmbeddedStatement.Children.Count > 0 && forStatement.Iterator.Count == 0)