From 459742f3cae18ff31ee236d51c54d6eef4e114e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Wed, 6 Feb 2008 14:50:36 +0000 Subject: [PATCH] Simplify short-circuit branches ("a && b" or "a || b"). Two new node types were created for this: SimpleBranch and ShortCircuitBranch. The short-circuit branches are found by pattern finding - single short-circuit branch forms a specific triangular pattern in the control flow graph. Nested short-circuit branches are found by doing this node reduction repeatedly. --- bin/Debug/output.cs | 427 +++++------------------------ src/AstMetodBodyBuilder.cs | 193 ++++++++----- src/ControlFlow/Node-Optimize.cs | 91 +++++- src/ControlFlow/Node-Transforms.cs | 6 +- src/ControlFlow/Nodes.cs | 71 ++++- src/Transforms/Ast/RemoveGotos.cs | 3 +- 6 files changed, 354 insertions(+), 437 deletions(-) diff --git a/bin/Debug/output.cs b/bin/Debug/output.cs index 1a219b90e..a99b70c8b 100644 --- a/bin/Debug/output.cs +++ b/bin/Debug/output.cs @@ -52,14 +52,7 @@ namespace Reversi (@this.squares).Set(row, col, color); for (int i = -1; (i <= 1); i = (i + 1)) { for (int j = -1; (j <= 1); j = (j + 1)) { - if (!(i)) { - if (!(!j)) { - } - else { - continue; - } - } - if (!(!@this.IsOutflanking(color, row, col, i, j))) { + if (!(((!i && !j) || !@this.IsOutflanking(color, row, col, i, j)))) { int k = (row + i); for (int l = (col + j); ((@this.squares).Get(k, l) == -color); l = (l + j)) { (@this.squares).Set(k, l, color); @@ -88,14 +81,7 @@ namespace Reversi } for (int i = -1; (i <= 1); i = (i + 1)) { for (int j = -1; (j <= 1); j = (j + 1)) { - if (!(i)) { - if (!(!j)) { - } - else { - continue; - } - } - if (!(!@this.IsOutflanking(color, row, col, i, j))) { + if (!(((!i && !j) || !@this.IsOutflanking(color, row, col, i, j)))) { return 1; } } @@ -117,56 +103,12 @@ namespace Reversi private bool IsOutflanking(int color, int row, int col, int dr, int dc) { int i = (row + dr); - for (int j = (col + dc);;) { - if (!(i < 0)) { - if (!(i >= 8)) { - if (!(j < 0)) { - if (!(j >= 8)) { - if (!((@this.squares).Get(i, j) == -color)) { - break; - } - i = (i + dr); - j = (j + dc); - } - else { - break; - } - } - else { - break; - } - } - else { - break; - } - } - else { - break; - } + for (int j = (col + dc); ((!(((i < 0 || i >= 8) || j < 0) || j >= 8) && (@this.squares).Get(i, j) == -color)); j = (j + dc)) { + i = (i + dr); } - if (!(i < 0)) { - if (!(i > 7)) { - if (!(j < 0)) { - if (!(j > 7)) { - if (!((i - dr) != row)) { - if (!((j - dc) == col)) { - } - else { - goto BasicBlock_202; - } - } - if (!((@this.squares).Get(i, j) == color)) { - } - else { - goto BasicBlock_203; - } - } - } - } + if (!((!((((i < 0 || i > 7) || j < 0) || j > 7) || (!(i - dr) != row && (j - dc) == col)) && (@this.squares).Get(i, j) == color))) { + return 0; } - BasicBlock_202: - return 0; - BasicBlock_203: return 1; } private void UpdateCounts() @@ -182,13 +124,9 @@ namespace Reversi V_2 = 0; for (int i = 0; (i < 8); i = (i + 1)) { for (int j = 0; (j < 8); j = (j + 1)) { - if (!((@this.squares).Get(i, j) == (IL__ldsfld(Empty)))) { - if (!((@this.safeDiscs).Get(i, j))) { - if (!(@this.IsOutflankable(i, j))) { - (@this.safeDiscs).Set(i, j, 1); - V_2 = 1; - } - } + if (!((((@this.squares).Get(i, j) == (IL__ldsfld(Empty)) || (@this.safeDiscs).Get(i, j)) || @this.IsOutflankable(i, j)))) { + (@this.safeDiscs).Set(i, j, 1); + V_2 = 1; } } } @@ -201,23 +139,8 @@ namespace Reversi if (!((@this.squares).Get(i, j) == (IL__ldsfld(Empty)))) { for (int k = -1; (k <= 1); k = (k + 1)) { for (int l = -1; (l <= 1); l = (l + 1)) { - if (!(k)) { - if (!(!l)) { - } - else { - continue; - } - } - if (!((i + k) < 0)) { - if (!((i + k) >= 8)) { - if (!((j + l) < 0)) { - if (!((j + l) >= 8)) { - if (!((@this.squares).Get((i + k), (j + l)) != (IL__ldsfld(Empty)))) { - V_5 = 1; - } - } - } - } + if (!(((((((!k && !l) || (i + k) < 0) || (i + k) >= 8) || (j + l) < 0) || (j + l) >= 8) || (@this.squares).Get((i + k), (j + l)) != (IL__ldsfld(Empty))))) { + V_5 = 1; } } } @@ -278,151 +201,57 @@ namespace Reversi bool V_5 = 0; bool V_4 = 0; bool V_6 = 0; - for (int k = 0;;) { - if (!(k >= col)) { - if (!(!V_3)) { - break; - } - if (!((@this.squares).Get(row, k) != (IL__ldsfld(Empty)))) { - V_3 = 1; - } - else { - if (!((@this.squares).Get(row, k) != i)) { - if (!((@this.safeDiscs).Get(row, k))) { - } - else { - goto BasicBlock_451; - } - } - V_5 = 1; - } - BasicBlock_451: - k = (k + 1); + for (int k = 0; ((!k >= col && !V_3)); k = (k + 1)) { + if (!((@this.squares).Get(row, k) != (IL__ldsfld(Empty)))) { + V_3 = 1; } else { - break; - } - } - k = (col + 1); - for (;;) { - if (!(k >= 8)) { - if (!(!V_4)) { - break; - } - if (!((@this.squares).Get(row, k) != (IL__ldsfld(Empty)))) { - V_4 = 1; - } - else { - if (!((@this.squares).Get(row, k) != i)) { - if (!((@this.safeDiscs).Get(row, k))) { - } - else { - goto BasicBlock_462; - } - } - V_6 = 1; + if (!((!(@this.squares).Get(row, k) != i && (@this.safeDiscs).Get(row, k)))) { + V_5 = 1; } - BasicBlock_462: - k = (k + 1); - } - else { - break; - } - } - if (!(!V_3)) { - if (!(V_4)) { - } - else { - goto BasicBlock_471; } } - if (!(!V_3)) { - if (!(V_6)) { + k = (col + 1); + for (; ((!k >= 8 && !V_4)); k = (k + 1)) { + if (!((@this.squares).Get(row, k) != (IL__ldsfld(Empty)))) { + V_4 = 1; } else { - goto BasicBlock_471; + if (!((!(@this.squares).Get(row, k) != i && (@this.safeDiscs).Get(row, k)))) { + V_6 = 1; + } } } - if (!(!V_5)) { - if (!(!V_4)) { - BasicBlock_471: - return 1; - } + if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) { + return 1; } V_3 = 0; V_4 = 0; V_5 = 0; V_6 = 0; - for (int j = 0;;) { - if (!(j >= row)) { - if (!(!V_3)) { - break; - } - if (!((@this.squares).Get(j, col) != (IL__ldsfld(Empty)))) { - V_3 = 1; - } - else { - if (!((@this.squares).Get(j, col) != i)) { - if (!((@this.safeDiscs).Get(j, col))) { - } - else { - goto BasicBlock_480; - } - } - V_5 = 1; - } - BasicBlock_480: - j = (j + 1); + for (int j = 0; ((!j >= row && !V_3)); j = (j + 1)) { + if (!((@this.squares).Get(j, col) != (IL__ldsfld(Empty)))) { + V_3 = 1; } else { - break; - } - } - j = (row + 1); - for (;;) { - if (!(j >= 8)) { - if (!(!V_4)) { - break; - } - if (!((@this.squares).Get(j, col) != (IL__ldsfld(Empty)))) { - V_4 = 1; - } - else { - if (!((@this.squares).Get(j, col) != i)) { - if (!((@this.safeDiscs).Get(j, col))) { - } - else { - goto BasicBlock_491; - } - } - V_6 = 1; + if (!((!(@this.squares).Get(j, col) != i && (@this.safeDiscs).Get(j, col)))) { + V_5 = 1; } - BasicBlock_491: - j = (j + 1); - } - else { - break; - } - } - if (!(!V_3)) { - if (!(V_4)) { - } - else { - goto BasicBlock_500; } } - if (!(!V_3)) { - if (!(V_6)) { + j = (row + 1); + for (; ((!j >= 8 && !V_4)); j = (j + 1)) { + if (!((@this.squares).Get(j, col) != (IL__ldsfld(Empty)))) { + V_4 = 1; } else { - goto BasicBlock_500; + if (!((!(@this.squares).Get(j, col) != i && (@this.safeDiscs).Get(j, col)))) { + V_6 = 1; + } } } - if (!(!V_5)) { - if (!(!V_4)) { - BasicBlock_500: - return 1; - } + if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) { + return 1; } V_3 = 0; V_4 = 0; @@ -430,89 +259,32 @@ namespace Reversi V_6 = 0; j = (row - 1); k = (col - 1); - for (;;) { - if (!(j < 0)) { - if (!(k < 0)) { - if (!(!V_3)) { - break; - } - if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { - V_3 = 1; - } - else { - if (!((@this.squares).Get(j, k) != i)) { - if (!((@this.safeDiscs).Get(j, k))) { - } - else { - goto BasicBlock_509; - } - } - V_5 = 1; - } - BasicBlock_509: - j = (j - 1); - k = (k - 1); - } - else { - break; - } + for (; ((!(j < 0 || k < 0) && !V_3)); k = (k - 1)) { + if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { + V_3 = 1; } else { - break; + if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) { + V_5 = 1; + } } + j = (j - 1); } j = (row + 1); k = (col + 1); - for (;;) { - if (!(j >= 8)) { - if (!(k >= 8)) { - if (!(!V_4)) { - break; - } - if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { - V_4 = 1; - } - else { - if (!((@this.squares).Get(j, k) != i)) { - if (!((@this.safeDiscs).Get(j, k))) { - } - else { - goto BasicBlock_521; - } - } - V_6 = 1; - } - BasicBlock_521: - j = (j + 1); - k = (k + 1); - } - else { - break; - } - } - else { - break; - } - } - if (!(!V_3)) { - if (!(V_4)) { - } - else { - goto BasicBlock_531; - } - } - if (!(!V_3)) { - if (!(V_6)) { + for (; ((!(j >= 8 || k >= 8) && !V_4)); k = (k + 1)) { + if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { + V_4 = 1; } else { - goto BasicBlock_531; + if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) { + V_6 = 1; + } } + j = (j + 1); } - if (!(!V_5)) { - if (!(!V_4)) { - BasicBlock_531: - return 1; - } + if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) { + return 1; } V_3 = 0; V_4 = 0; @@ -520,89 +292,32 @@ namespace Reversi V_6 = 0; j = (row - 1); k = (col + 1); - for (;;) { - if (!(j < 0)) { - if (!(k >= 8)) { - if (!(!V_3)) { - break; - } - if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { - V_3 = 1; - } - else { - if (!((@this.squares).Get(j, k) != i)) { - if (!((@this.safeDiscs).Get(j, k))) { - } - else { - goto BasicBlock_540; - } - } - V_5 = 1; - } - BasicBlock_540: - j = (j - 1); - k = (k + 1); - } - else { - break; - } + for (; ((!(j < 0 || k >= 8) && !V_3)); k = (k + 1)) { + if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { + V_3 = 1; } else { - break; + if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) { + V_5 = 1; + } } + j = (j - 1); } j = (row + 1); k = (col - 1); - for (;;) { - if (!(j >= 8)) { - if (!(k < 0)) { - if (!(!V_4)) { - break; - } - if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { - V_4 = 1; - } - else { - if (!((@this.squares).Get(j, k) != i)) { - if (!((@this.safeDiscs).Get(j, k))) { - } - else { - goto BasicBlock_552; - } - } - V_6 = 1; - } - BasicBlock_552: - j = (j + 1); - k = (k - 1); - } - else { - break; - } + for (; ((!(j >= 8 || k < 0) && !V_4)); k = (k - 1)) { + if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) { + V_4 = 1; } else { - break; - } - } - if (!(!V_3)) { - if (!(V_4)) { - } - else { - goto BasicBlock_562; - } - } - if (!(!V_3)) { - if (!(V_6)) { - } - else { - goto BasicBlock_562; + if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) { + V_6 = 1; + } } + j = (j + 1); } - if (!(!V_5)) { - if (!(!V_4)) { - BasicBlock_562: - return 1; - } + if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) { + return 1; } return 0; } diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index 81c5d8fcd..412ce4a76 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -87,12 +87,12 @@ namespace Decompiler if (node is BasicBlock) { foreach(StackExpression expr in ((BasicBlock)node).Body) { - yield return TransformExpression(expr); + yield return TransformExpressionToStatement(expr); } Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; // If there is default branch and it is not the following node if (fallThroughNode != null) { - yield return MakeBranchCommand(node, fallThroughNode); + yield return new Ast.GotoStatement(fallThroughNode.Label); } } else if (node is AcyclicGraph) { Ast.BlockStatement blockStatement = new Ast.BlockStatement(); @@ -111,38 +111,55 @@ namespace Decompiler foreach(Ast.INode inode in TransformNodes(node.Childs)) { yield return inode; } + } else if (node is Branch) { + yield return new Ast.LabelStatement(((Branch)node).FirstBasicBlock.Label); + + Ast.BlockStatement trueBlock = new Ast.BlockStatement(); + trueBlock.Children.Add(new Ast.GotoStatement(((Branch)node).TrueSuccessor.Label)); + + Ast.BlockStatement falseBlock = new Ast.BlockStatement(); + falseBlock.Children.Add(new Ast.GotoStatement(((Branch)node).FalseSuccessor.Label)); + + Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( + MakeBranchCondition((Branch)node), + trueBlock, + falseBlock + ); + trueBlock.Parent = ifElseStmt; + falseBlock.Parent = ifElseStmt; + + yield return ifElseStmt; } else if (node is ConditionalNode) { ConditionalNode conditionalNode = (ConditionalNode)node; - yield return new Ast.LabelStatement(conditionalNode.Condition.Label); - Ast.Statement lastStatement = null; - foreach(StackExpression expr in conditionalNode.Condition.Body) { - lastStatement = TransformExpression(expr); - yield return lastStatement; - } - Ast.IfElseStatement ifElseStmt = lastStatement as Ast.IfElseStatement; - if (ifElseStmt == null) { - ifElseStmt = new IfElseStatement(Ast.Expression.Null, Ast.Statement.Null, Ast.Statement.Null); - } - Ast.Statement oldTrueBody = ifElseStmt.TrueStatement[0]; - ifElseStmt.TrueStatement.Clear(); - // Swap the method bodies - ifElseStmt.Condition = new Ast.UnaryOperatorExpression(new Ast.ParenthesizedExpression(ifElseStmt.Condition), UnaryOperatorType.Not); + yield return new Ast.LabelStatement(conditionalNode.Condition.FirstBasicBlock.Label); Ast.BlockStatement trueBlock = new Ast.BlockStatement(); // The block entry code - trueBlock.Children.Add(MakeBranchCommand(node, conditionalNode.Condition.FallThroughBasicBlock)); + trueBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label)); // Sugested content trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); - ifElseStmt.TrueStatement.Add(trueBlock); - trueBlock.Parent = ifElseStmt; Ast.BlockStatement falseBlock = new Ast.BlockStatement(); // The block entry code - falseBlock.Children.Add(oldTrueBody); + falseBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label)); // Sugested content falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); - ifElseStmt.FalseStatement.Add(falseBlock); + + Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( + // Method bodies are swapped + new Ast.UnaryOperatorExpression( + new Ast.ParenthesizedExpression( + MakeBranchCondition(conditionalNode.Condition) + ), + UnaryOperatorType.Not + ), + falseBlock, + trueBlock + ); + trueBlock.Parent = ifElseStmt; falseBlock.Parent = ifElseStmt; + + yield return ifElseStmt; } else { throw new Exception("Bad node type"); } @@ -152,29 +169,57 @@ namespace Decompiler } } - Ast.Statement TransformExpression(StackExpression expr) + List TransformExpressionArguments(StackExpression expr) { - Ast.Statement astStatement = null; List args = new List(); foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) { string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset); args.Add(new Ast.IdentifierExpression(name)); } - object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray()); + // Args generated by nested expressions (which must be closed) + foreach(StackExpression nestedExpr in expr.LastArguments) { + Ast.Expression astExpr = (Ast.Expression)TransformExpression(nestedExpr); + if (nestedExpr.MustBeParenthesized) { + args.Add(new Ast.ParenthesizedExpression(astExpr)); + } else { + args.Add(astExpr); + } + } + return args; + } + + object TransformExpression(StackExpression expr) + { + List args = TransformExpressionArguments(expr); + try { + return TransformByteCode(methodDef, expr.LastByteCode, args.ToArray()); + } catch (NotImplementedException) { + // Output the operand of the unknown IL code as well + if (expr.LastByteCode.Operand != null) { + args.Insert(0, new IdentifierExpression(expr.LastByteCode.FormatedOperand)); + } + return new Ast.InvocationExpression(new IdentifierExpression("IL__" + expr.LastByteCode.OpCode.Name), args); + } + } + + Ast.Statement TransformExpressionToStatement(StackExpression expr) + { + object codeExpr = TransformExpression(expr); if (codeExpr is Ast.Expression) { if (expr.PushCount == 1) { string type = expr.LastByteCode.Type.FullName; string name = string.Format("expr{0:X2}", expr.LastByteCode.Offset); Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); - astStatement = astLocal; + return astLocal; } else { - astStatement = new ExpressionStatement((Ast.Expression)codeExpr); + return new Ast.ExpressionStatement((Ast.Expression)codeExpr); } } else if (codeExpr is Ast.Statement) { - astStatement = (Ast.Statement)codeExpr; + return (Ast.Statement)codeExpr; + } else { + throw new Exception(); } - return astStatement; } static Ast.ExpressionStatement MakeComment(string text) @@ -183,48 +228,72 @@ namespace Decompiler return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); } - public static Ast.Statement MakeBranchCommand(Node contextNode, Node targetNode) + Ast.Expression MakeBranchCondition(Branch branch) { -// // Propagate target up to the top most scope -// while (targetNode.Parent != null && targetNode.Parent.HeadChild == targetNode) { -// targetNode = targetNode.Parent; -// } -// // If branches to the start of encapsulating loop -// if (contextNode.Parent is Loop && targetNode == contextNode.Parent) { -// return new Ast.ContinueStatement(); -// } -// // If branches outside the encapsulating loop -// if (contextNode.Parent is Loop && targetNode == contextNode.Parent.NextNode) { -// return new Ast.BreakStatement(); -// } - return new Ast.GotoStatement(targetNode.Label); + if (branch is SimpleBranch) { // TODO: Delete + return MakeBranchCondition_Internal(branch); + } else { + return new ParenthesizedExpression(MakeBranchCondition_Internal(branch)); + } } - static object MakeCodeDomExpression(MethodDefinition methodDef, StackExpression expr, params Ast.Expression[] args) + Ast.Expression MakeBranchCondition_Internal(Branch branch) { - List allArgs = new List(); - // Add args from stack - allArgs.AddRange(args); - // Args generated by nested expressions (which must be closed) - foreach(StackExpression nestedExpr in expr.LastArguments) { - Ast.Expression astExpr = (Ast.Expression)MakeCodeDomExpression(methodDef, nestedExpr); - if (nestedExpr.MustBeParenthesized) { - allArgs.Add(new Ast.ParenthesizedExpression(astExpr)); - } else { - allArgs.Add(astExpr); + if (branch is SimpleBranch) { + List args = TransformExpressionArguments(((SimpleBranch)branch).BasicBlock.Body[0]); + Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; + Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; + switch(((SimpleBranch)branch).BasicBlock.Body[0].LastByteCode.OpCode.Code) { + case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not); + case Code.Brtrue: return arg1; + case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); + case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); + case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); + case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); + case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); + case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); + case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); + case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); + default: throw new Exception("Bad opcode"); } - } - try { - return MakeCodeDomExpression(methodDef, expr.LastByteCode, allArgs.ToArray()); - } catch (NotImplementedException) { - if (expr.LastByteCode.Operand != null) { - allArgs.Insert(0, new IdentifierExpression(expr.LastByteCode.FormatedOperand)); + } else if (branch is ShortCircuitBranch) { + ShortCircuitBranch scBranch = (ShortCircuitBranch)branch; + switch(scBranch.Operator) { + case ShortCircuitOperator.LeftAndRight: + return new BinaryOperatorExpression( + MakeBranchCondition(scBranch.Left), + BinaryOperatorType.LogicalAnd, + MakeBranchCondition(scBranch.Right) + ); + case ShortCircuitOperator.LeftOrRight: + return new BinaryOperatorExpression( + MakeBranchCondition(scBranch.Left), + BinaryOperatorType.LogicalOr, + MakeBranchCondition(scBranch.Right) + ); + case ShortCircuitOperator.NotLeftAndRight: + return new BinaryOperatorExpression( + new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), + BinaryOperatorType.LogicalAnd, + MakeBranchCondition(scBranch.Right) + ); + case ShortCircuitOperator.NotLeftOrRight: + return new BinaryOperatorExpression( + new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), + BinaryOperatorType.LogicalOr, + MakeBranchCondition(scBranch.Right) + ); + default: + throw new Exception("Bad operator"); } - return new Ast.InvocationExpression(new IdentifierExpression("IL__" + expr.LastByteCode.OpCode.Name), allArgs); + } else { + throw new Exception("Bad type"); } } - static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) + static object TransformByteCode(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) { OpCode opCode = byteCode.OpCode; object operand = byteCode.Operand; @@ -236,7 +305,7 @@ namespace Decompiler Ast.Statement branchCommand = null; if (operand is ByteCode) { - branchCommand = MakeBranchCommand(byteCode.Expression.BasicBlock, ((ByteCode)operand).Expression.BasicBlock); + branchCommand = new Ast.GotoStatement(((ByteCode)operand).Expression.BasicBlock.Label); } switch(opCode.Code) { diff --git a/src/ControlFlow/Node-Optimize.cs b/src/ControlFlow/Node-Optimize.cs index 2ab5f2824..9f7ed28e9 100644 --- a/src/ControlFlow/Node-Optimize.cs +++ b/src/ControlFlow/Node-Optimize.cs @@ -13,6 +13,7 @@ namespace Decompiler.ControlFlow OptimizeLoops(); } if (Options.ReduceConditonals) { + OptimizeShortCircuits(); OptimizeConditions(); } } @@ -57,6 +58,76 @@ namespace Decompiler.ControlFlow return reachableNodes; } + public void OptimizeShortCircuits() + { + foreach(Node child in this.Childs) { + if (child is Loop) { + child.OptimizeShortCircuits(); + } + } + + Reset: + foreach(Node child in this.Childs) { + if (TryOptimizeShortCircuit(child)) { + goto Reset; + } + } + } + + public static bool TryOptimizeShortCircuit(Node head) + { + if ((head is BasicBlock) && + (head as BasicBlock).BranchBasicBlock != null && + (head as BasicBlock).FallThroughBasicBlock != null) { + head.Parent.MergeChilds(head); + return true; + } + + Branch top = head as Branch; + if (top == null) return false; + + Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch; + Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch; + + // A & B + if (left != null && + left.Predecessors.Count == 1 && + left.FalseSuccessor == top.FalseSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, left); + scBranch.Operator = ShortCircuitOperator.LeftAndRight; + return true; + } + + // ~A | B + if (left != null && + left.Predecessors.Count == 1 && + left.TrueSuccessor == top.FalseSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, left); + scBranch.Operator = ShortCircuitOperator.NotLeftOrRight; + return true; + } + + // A | B + if (right != null && + right.Predecessors.Count == 1 && + right.TrueSuccessor == top.TrueSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, right); + scBranch.Operator = ShortCircuitOperator.LeftOrRight; + return true; + } + + // ~A & B + if (right != null && + right.Predecessors.Count == 1 && + right.FalseSuccessor == top.TrueSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, right); + scBranch.Operator = ShortCircuitOperator.NotLeftAndRight; + return true; + } + + return false; + } + public void OptimizeConditions() { foreach(Node child in this.Childs) { @@ -68,9 +139,9 @@ namespace Decompiler.ControlFlow Node conditionNode = this.HeadChild; while(conditionNode != null) { // Keep looking for some conditional block - if (conditionNode is BasicBlock && ((BasicBlock)conditionNode).IsConditionalBranch) { + if (conditionNode is Branch) { // Found start of conditional - OptimizeIf((BasicBlock)conditionNode); + OptimizeIf((Branch)conditionNode); // Restart conditionNode = this.HeadChild; continue; @@ -87,10 +158,10 @@ namespace Decompiler.ControlFlow } } - public static void OptimizeIf(BasicBlock condition) + public static void OptimizeIf(Branch condition) { - Node trueStart = condition.FloatUpToNeighbours(condition.FallThroughBasicBlock); - Node falseStart = condition.FloatUpToNeighbours(condition.BranchBasicBlock); + Node trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor); + Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor); NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; @@ -108,15 +179,15 @@ namespace Decompiler.ControlFlow ConditionalNode conditionalNode = new ConditionalNode(condition); conditionalNode.MoveTo(conditionParent, conditionIndex); - Options.NotifyReducingGraph(); - trueNodes.MoveTo(conditionalNode.TrueBody); - - // We can exit the 'true' part of Loop or MethodBody conviently using 'break' or 'return' + // If there are no common nodes, let the 'true' block be the default if (commonReachable.Count > 0) { Options.NotifyReducingGraph(); - falseNodes.MoveTo(conditionalNode.FalseBody); + trueNodes.MoveTo(conditionalNode.TrueBody); } + Options.NotifyReducingGraph(); + falseNodes.MoveTo(conditionalNode.FalseBody); + // Optimize the created subtrees conditionalNode.TrueBody.OptimizeConditions(); conditionalNode.FalseBody.OptimizeConditions(); diff --git a/src/ControlFlow/Node-Transforms.cs b/src/ControlFlow/Node-Transforms.cs index 31ae6efe6..ad96382e4 100644 --- a/src/ControlFlow/Node-Transforms.cs +++ b/src/ControlFlow/Node-Transforms.cs @@ -24,7 +24,7 @@ namespace Decompiler.ControlFlow newNode.Childs.Insert(index, this); } - Node MergeChilds(params Node[] nodes) where T: Node, new() + T MergeChilds(params Node[] nodes) where T: Node, new() { foreach(Node node in nodes) { if (node == null) throw new ArgumentNullException("nodes"); @@ -32,7 +32,7 @@ namespace Decompiler.ControlFlow } if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified"); - Node mergedNode = new T(); + T mergedNode = new T(); // Add the merged node Options.NotifyReducingGraph(); @@ -40,7 +40,7 @@ namespace Decompiler.ControlFlow this.Childs.Insert(headIndex, mergedNode); foreach(Node node in nodes) { - Options.NotifyReducingGraph(); + //Options.NotifyReducingGraph(); node.MoveTo(mergedNode); } diff --git a/src/ControlFlow/Nodes.cs b/src/ControlFlow/Nodes.cs index 261eeb0e0..1351ce84b 100644 --- a/src/ControlFlow/Nodes.cs +++ b/src/ControlFlow/Nodes.cs @@ -40,12 +40,73 @@ namespace Decompiler.ControlFlow } } } + } + + public enum ShortCircuitOperator { + LeftAndRight, + LeftOrRight, + NotLeftAndRight, + NotLeftOrRight, + } + + public abstract class Branch: Node + { + public abstract BasicBlock FirstBasicBlock { get; } + public abstract BasicBlock TrueSuccessor { get; } + public abstract BasicBlock FalseSuccessor { get; } + } + + public class SimpleBranch: Branch + { + public override BasicBlock FirstBasicBlock { + get { + return this.BasicBlock; + } + } + + public BasicBlock BasicBlock { + get { return (BasicBlock)this.Childs[0]; } + } + + public override BasicBlock TrueSuccessor { + get { return this.BasicBlock.BranchBasicBlock; } + } - public bool IsConditionalBranch { + public override BasicBlock FalseSuccessor { + get { return this.BasicBlock.FallThroughBasicBlock; } + } + } + + public class ShortCircuitBranch: Branch + { + ShortCircuitOperator @operator; + + public override BasicBlock FirstBasicBlock { get { - return fallThroughBasicBlock != null && branchBasicBlock != null; + return this.Left.FirstBasicBlock; } } + + public Branch Left { + get { return (Branch)this.Childs[0];; } + } + + public Branch Right { + get { return (Branch)this.Childs[1]; } + } + + public ShortCircuitOperator Operator { + get { return @operator; } + set { @operator = value; } + } + + public override BasicBlock TrueSuccessor { + get { return this.Right.TrueSuccessor; } + } + + public override BasicBlock FalseSuccessor { + get { return this.Right.FalseSuccessor; } + } } public class MethodBodyGraph: Node @@ -123,11 +184,11 @@ namespace Decompiler.ControlFlow public class ConditionalNode: Node { - BasicBlock condition; + Branch condition; Block trueBody = new Block(); Block falseBody = new Block(); - public BasicBlock Condition { + public Branch Condition { get { return condition; } } @@ -139,7 +200,7 @@ namespace Decompiler.ControlFlow get { return falseBody; } } - public ConditionalNode(BasicBlock condition) + public ConditionalNode(Branch condition) { this.condition = condition; diff --git a/src/Transforms/Ast/RemoveGotos.cs b/src/Transforms/Ast/RemoveGotos.cs index 5ce66bfb4..6cdd268b7 100644 --- a/src/Transforms/Ast/RemoveGotos.cs +++ b/src/Transforms/Ast/RemoveGotos.cs @@ -79,7 +79,8 @@ namespace Decompiler.Transforms.Ast if (next != null) { return EnterBlockStatement(next); } else { - if (statement.Parent is BlockStatement) { + if (statement.Parent is BlockStatement && + statement.Parent.Parent is Statement) { return ExitBlockStatement((Statement)statement.Parent.Parent); } else { return null;