Browse Source

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.
pull/1/head^2
David Srbecký 18 years ago
parent
commit
459742f3ca
  1. 427
      bin/Debug/output.cs
  2. 193
      src/AstMetodBodyBuilder.cs
  3. 91
      src/ControlFlow/Node-Optimize.cs
  4. 6
      src/ControlFlow/Node-Transforms.cs
  5. 71
      src/ControlFlow/Nodes.cs
  6. 3
      src/Transforms/Ast/RemoveGotos.cs

427
bin/Debug/output.cs

@ -52,14 +52,7 @@ namespace Reversi
(@this.squares).Set(row, col, color); (@this.squares).Set(row, col, color);
for (int i = -1; (i <= 1); i = (i + 1)) { for (int i = -1; (i <= 1); i = (i + 1)) {
for (int j = -1; (j <= 1); j = (j + 1)) { for (int j = -1; (j <= 1); j = (j + 1)) {
if (!(i)) { if (!(((!i && !j) || !@this.IsOutflanking(color, row, col, i, j)))) {
if (!(!j)) {
}
else {
continue;
}
}
if (!(!@this.IsOutflanking(color, row, col, i, j))) {
int k = (row + i); int k = (row + i);
for (int l = (col + j); ((@this.squares).Get(k, l) == -color); l = (l + j)) { for (int l = (col + j); ((@this.squares).Get(k, l) == -color); l = (l + j)) {
(@this.squares).Set(k, l, color); (@this.squares).Set(k, l, color);
@ -88,14 +81,7 @@ namespace Reversi
} }
for (int i = -1; (i <= 1); i = (i + 1)) { for (int i = -1; (i <= 1); i = (i + 1)) {
for (int j = -1; (j <= 1); j = (j + 1)) { for (int j = -1; (j <= 1); j = (j + 1)) {
if (!(i)) { if (!(((!i && !j) || !@this.IsOutflanking(color, row, col, i, j)))) {
if (!(!j)) {
}
else {
continue;
}
}
if (!(!@this.IsOutflanking(color, row, col, i, j))) {
return 1; return 1;
} }
} }
@ -117,56 +103,12 @@ namespace Reversi
private bool IsOutflanking(int color, int row, int col, int dr, int dc) private bool IsOutflanking(int color, int row, int col, int dr, int dc)
{ {
int i = (row + dr); int i = (row + dr);
for (int j = (col + dc);;) { for (int j = (col + dc); ((!(((i < 0 || i >= 8) || j < 0) || j >= 8) && (@this.squares).Get(i, j) == -color)); j = (j + dc)) {
if (!(i < 0)) { i = (i + dr);
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;
}
} }
if (!(i < 0)) { if (!((!((((i < 0 || i > 7) || j < 0) || j > 7) || (!(i - dr) != row && (j - dc) == col)) && (@this.squares).Get(i, j) == color))) {
if (!(i > 7)) { return 0;
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;
}
}
}
}
} }
BasicBlock_202:
return 0;
BasicBlock_203:
return 1; return 1;
} }
private void UpdateCounts() private void UpdateCounts()
@ -182,13 +124,9 @@ namespace Reversi
V_2 = 0; V_2 = 0;
for (int i = 0; (i < 8); i = (i + 1)) { for (int i = 0; (i < 8); i = (i + 1)) {
for (int j = 0; (j < 8); j = (j + 1)) { for (int j = 0; (j < 8); j = (j + 1)) {
if (!((@this.squares).Get(i, j) == (IL__ldsfld(Empty)))) { if (!((((@this.squares).Get(i, j) == (IL__ldsfld(Empty)) || (@this.safeDiscs).Get(i, j)) || @this.IsOutflankable(i, j)))) {
if (!((@this.safeDiscs).Get(i, j))) { (@this.safeDiscs).Set(i, j, 1);
if (!(@this.IsOutflankable(i, j))) { V_2 = 1;
(@this.safeDiscs).Set(i, j, 1);
V_2 = 1;
}
}
} }
} }
} }
@ -201,23 +139,8 @@ namespace Reversi
if (!((@this.squares).Get(i, j) == (IL__ldsfld(Empty)))) { if (!((@this.squares).Get(i, j) == (IL__ldsfld(Empty)))) {
for (int k = -1; (k <= 1); k = (k + 1)) { for (int k = -1; (k <= 1); k = (k + 1)) {
for (int l = -1; (l <= 1); l = (l + 1)) { for (int l = -1; (l <= 1); l = (l + 1)) {
if (!(k)) { 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))))) {
if (!(!l)) { V_5 = 1;
}
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;
}
}
}
}
} }
} }
} }
@ -278,151 +201,57 @@ namespace Reversi
bool V_5 = 0; bool V_5 = 0;
bool V_4 = 0; bool V_4 = 0;
bool V_6 = 0; bool V_6 = 0;
for (int k = 0;;) { for (int k = 0; ((!k >= col && !V_3)); k = (k + 1)) {
if (!(k >= col)) { if (!((@this.squares).Get(row, k) != (IL__ldsfld(Empty)))) {
if (!(!V_3)) { V_3 = 1;
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);
} }
else { else {
break; if (!((!(@this.squares).Get(row, k) != i && (@this.safeDiscs).Get(row, k)))) {
} V_5 = 1;
}
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;
} }
BasicBlock_462:
k = (k + 1);
}
else {
break;
}
}
if (!(!V_3)) {
if (!(V_4)) {
}
else {
goto BasicBlock_471;
} }
} }
if (!(!V_3)) { k = (col + 1);
if (!(V_6)) { for (; ((!k >= 8 && !V_4)); k = (k + 1)) {
if (!((@this.squares).Get(row, k) != (IL__ldsfld(Empty)))) {
V_4 = 1;
} }
else { else {
goto BasicBlock_471; if (!((!(@this.squares).Get(row, k) != i && (@this.safeDiscs).Get(row, k)))) {
V_6 = 1;
}
} }
} }
if (!(!V_5)) { if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) {
if (!(!V_4)) { return 1;
BasicBlock_471:
return 1;
}
} }
V_3 = 0; V_3 = 0;
V_4 = 0; V_4 = 0;
V_5 = 0; V_5 = 0;
V_6 = 0; V_6 = 0;
for (int j = 0;;) { for (int j = 0; ((!j >= row && !V_3)); j = (j + 1)) {
if (!(j >= row)) { if (!((@this.squares).Get(j, col) != (IL__ldsfld(Empty)))) {
if (!(!V_3)) { V_3 = 1;
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);
} }
else { else {
break; if (!((!(@this.squares).Get(j, col) != i && (@this.safeDiscs).Get(j, col)))) {
} V_5 = 1;
}
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;
} }
BasicBlock_491:
j = (j + 1);
}
else {
break;
}
}
if (!(!V_3)) {
if (!(V_4)) {
}
else {
goto BasicBlock_500;
} }
} }
if (!(!V_3)) { j = (row + 1);
if (!(V_6)) { for (; ((!j >= 8 && !V_4)); j = (j + 1)) {
if (!((@this.squares).Get(j, col) != (IL__ldsfld(Empty)))) {
V_4 = 1;
} }
else { else {
goto BasicBlock_500; if (!((!(@this.squares).Get(j, col) != i && (@this.safeDiscs).Get(j, col)))) {
V_6 = 1;
}
} }
} }
if (!(!V_5)) { if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) {
if (!(!V_4)) { return 1;
BasicBlock_500:
return 1;
}
} }
V_3 = 0; V_3 = 0;
V_4 = 0; V_4 = 0;
@ -430,89 +259,32 @@ namespace Reversi
V_6 = 0; V_6 = 0;
j = (row - 1); j = (row - 1);
k = (col - 1); k = (col - 1);
for (;;) { for (; ((!(j < 0 || k < 0) && !V_3)); k = (k - 1)) {
if (!(j < 0)) { if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) {
if (!(k < 0)) { V_3 = 1;
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;
}
} }
else { else {
break; if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) {
V_5 = 1;
}
} }
j = (j - 1);
} }
j = (row + 1); j = (row + 1);
k = (col + 1); k = (col + 1);
for (;;) { for (; ((!(j >= 8 || k >= 8) && !V_4)); k = (k + 1)) {
if (!(j >= 8)) { if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) {
if (!(k >= 8)) { V_4 = 1;
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)) {
} }
else { 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_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) {
if (!(!V_4)) { return 1;
BasicBlock_531:
return 1;
}
} }
V_3 = 0; V_3 = 0;
V_4 = 0; V_4 = 0;
@ -520,89 +292,32 @@ namespace Reversi
V_6 = 0; V_6 = 0;
j = (row - 1); j = (row - 1);
k = (col + 1); k = (col + 1);
for (;;) { for (; ((!(j < 0 || k >= 8) && !V_3)); k = (k + 1)) {
if (!(j < 0)) { if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) {
if (!(k >= 8)) { V_3 = 1;
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;
}
} }
else { else {
break; if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) {
V_5 = 1;
}
} }
j = (j - 1);
} }
j = (row + 1); j = (row + 1);
k = (col - 1); k = (col - 1);
for (;;) { for (; ((!(j >= 8 || k < 0) && !V_4)); k = (k - 1)) {
if (!(j >= 8)) { if (!((@this.squares).Get(j, k) != (IL__ldsfld(Empty)))) {
if (!(k < 0)) { V_4 = 1;
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;
}
} }
else { else {
break; if (!((!(@this.squares).Get(j, k) != i && (@this.safeDiscs).Get(j, k)))) {
} V_6 = 1;
} }
if (!(!V_3)) {
if (!(V_4)) {
}
else {
goto BasicBlock_562;
}
}
if (!(!V_3)) {
if (!(V_6)) {
}
else {
goto BasicBlock_562;
} }
j = (j + 1);
} }
if (!(!V_5)) { if (!((!((!!V_3 && V_4) || (!!V_3 && V_6)) && (!V_5 || !V_4)))) {
if (!(!V_4)) { return 1;
BasicBlock_562:
return 1;
}
} }
return 0; return 0;
} }

193
src/AstMetodBodyBuilder.cs

@ -87,12 +87,12 @@ namespace Decompiler
if (node is BasicBlock) { if (node is BasicBlock) {
foreach(StackExpression expr in ((BasicBlock)node).Body) { foreach(StackExpression expr in ((BasicBlock)node).Body) {
yield return TransformExpression(expr); yield return TransformExpressionToStatement(expr);
} }
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
// If there is default branch and it is not the following node // If there is default branch and it is not the following node
if (fallThroughNode != null) { if (fallThroughNode != null) {
yield return MakeBranchCommand(node, fallThroughNode); yield return new Ast.GotoStatement(fallThroughNode.Label);
} }
} else if (node is AcyclicGraph) { } else if (node is AcyclicGraph) {
Ast.BlockStatement blockStatement = new Ast.BlockStatement(); Ast.BlockStatement blockStatement = new Ast.BlockStatement();
@ -111,38 +111,55 @@ namespace Decompiler
foreach(Ast.INode inode in TransformNodes(node.Childs)) { foreach(Ast.INode inode in TransformNodes(node.Childs)) {
yield return inode; 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) { } else if (node is ConditionalNode) {
ConditionalNode conditionalNode = (ConditionalNode)node; ConditionalNode conditionalNode = (ConditionalNode)node;
yield return new Ast.LabelStatement(conditionalNode.Condition.Label); yield return new Ast.LabelStatement(conditionalNode.Condition.FirstBasicBlock.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);
Ast.BlockStatement trueBlock = new Ast.BlockStatement(); Ast.BlockStatement trueBlock = new Ast.BlockStatement();
// The block entry code // The block entry code
trueBlock.Children.Add(MakeBranchCommand(node, conditionalNode.Condition.FallThroughBasicBlock)); trueBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label));
// Sugested content // Sugested content
trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody));
ifElseStmt.TrueStatement.Add(trueBlock);
trueBlock.Parent = ifElseStmt;
Ast.BlockStatement falseBlock = new Ast.BlockStatement(); Ast.BlockStatement falseBlock = new Ast.BlockStatement();
// The block entry code // The block entry code
falseBlock.Children.Add(oldTrueBody); falseBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label));
// Sugested content // Sugested content
falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); 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; falseBlock.Parent = ifElseStmt;
yield return ifElseStmt;
} else { } else {
throw new Exception("Bad node type"); throw new Exception("Bad node type");
} }
@ -152,29 +169,57 @@ namespace Decompiler
} }
} }
Ast.Statement TransformExpression(StackExpression expr) List<Ast.Expression> TransformExpressionArguments(StackExpression expr)
{ {
Ast.Statement astStatement = null;
List<Ast.Expression> args = new List<Ast.Expression>(); List<Ast.Expression> args = new List<Ast.Expression>();
foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) { foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) {
string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset); string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset);
args.Add(new Ast.IdentifierExpression(name)); 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<Ast.Expression> 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 (codeExpr is Ast.Expression) {
if (expr.PushCount == 1) { if (expr.PushCount == 1) {
string type = expr.LastByteCode.Type.FullName; string type = expr.LastByteCode.Type.FullName;
string name = string.Format("expr{0:X2}", expr.LastByteCode.Offset); string name = string.Format("expr{0:X2}", expr.LastByteCode.Offset);
Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString()));
astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr));
astStatement = astLocal; return astLocal;
} else { } else {
astStatement = new ExpressionStatement((Ast.Expression)codeExpr); return new Ast.ExpressionStatement((Ast.Expression)codeExpr);
} }
} else if (codeExpr is Ast.Statement) { } 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) static Ast.ExpressionStatement MakeComment(string text)
@ -183,48 +228,72 @@ namespace Decompiler
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); 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 if (branch is SimpleBranch) { // TODO: Delete
// while (targetNode.Parent != null && targetNode.Parent.HeadChild == targetNode) { return MakeBranchCondition_Internal(branch);
// targetNode = targetNode.Parent; } else {
// } return new ParenthesizedExpression(MakeBranchCondition_Internal(branch));
// // 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);
} }
static object MakeCodeDomExpression(MethodDefinition methodDef, StackExpression expr, params Ast.Expression[] args) Ast.Expression MakeBranchCondition_Internal(Branch branch)
{ {
List<Ast.Expression> allArgs = new List<Ast.Expression>(); if (branch is SimpleBranch) {
// Add args from stack List<Ast.Expression> args = TransformExpressionArguments(((SimpleBranch)branch).BasicBlock.Body[0]);
allArgs.AddRange(args); Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
// Args generated by nested expressions (which must be closed) Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
foreach(StackExpression nestedExpr in expr.LastArguments) { switch(((SimpleBranch)branch).BasicBlock.Body[0].LastByteCode.OpCode.Code) {
Ast.Expression astExpr = (Ast.Expression)MakeCodeDomExpression(methodDef, nestedExpr); case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not);
if (nestedExpr.MustBeParenthesized) { case Code.Brtrue: return arg1;
allArgs.Add(new Ast.ParenthesizedExpression(astExpr)); case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
} else { case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
allArgs.Add(astExpr); 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");
} }
} } else if (branch is ShortCircuitBranch) {
try { ShortCircuitBranch scBranch = (ShortCircuitBranch)branch;
return MakeCodeDomExpression(methodDef, expr.LastByteCode, allArgs.ToArray()); switch(scBranch.Operator) {
} catch (NotImplementedException) { case ShortCircuitOperator.LeftAndRight:
if (expr.LastByteCode.Operand != null) { return new BinaryOperatorExpression(
allArgs.Insert(0, new IdentifierExpression(expr.LastByteCode.FormatedOperand)); 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; OpCode opCode = byteCode.OpCode;
object operand = byteCode.Operand; object operand = byteCode.Operand;
@ -236,7 +305,7 @@ namespace Decompiler
Ast.Statement branchCommand = null; Ast.Statement branchCommand = null;
if (operand is ByteCode) { 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) { switch(opCode.Code) {

91
src/ControlFlow/Node-Optimize.cs

@ -13,6 +13,7 @@ namespace Decompiler.ControlFlow
OptimizeLoops(); OptimizeLoops();
} }
if (Options.ReduceConditonals) { if (Options.ReduceConditonals) {
OptimizeShortCircuits();
OptimizeConditions(); OptimizeConditions();
} }
} }
@ -57,6 +58,76 @@ namespace Decompiler.ControlFlow
return reachableNodes; 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<SimpleBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(top, right);
scBranch.Operator = ShortCircuitOperator.NotLeftAndRight;
return true;
}
return false;
}
public void OptimizeConditions() public void OptimizeConditions()
{ {
foreach(Node child in this.Childs) { foreach(Node child in this.Childs) {
@ -68,9 +139,9 @@ namespace Decompiler.ControlFlow
Node conditionNode = this.HeadChild; Node conditionNode = this.HeadChild;
while(conditionNode != null) { while(conditionNode != null) {
// Keep looking for some conditional block // Keep looking for some conditional block
if (conditionNode is BasicBlock && ((BasicBlock)conditionNode).IsConditionalBranch) { if (conditionNode is Branch) {
// Found start of conditional // Found start of conditional
OptimizeIf((BasicBlock)conditionNode); OptimizeIf((Branch)conditionNode);
// Restart // Restart
conditionNode = this.HeadChild; conditionNode = this.HeadChild;
continue; 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 trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor);
Node falseStart = condition.FloatUpToNeighbours(condition.BranchBasicBlock); Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor);
NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty;
NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty;
@ -108,15 +179,15 @@ namespace Decompiler.ControlFlow
ConditionalNode conditionalNode = new ConditionalNode(condition); ConditionalNode conditionalNode = new ConditionalNode(condition);
conditionalNode.MoveTo(conditionParent, conditionIndex); conditionalNode.MoveTo(conditionParent, conditionIndex);
Options.NotifyReducingGraph(); // If there are no common nodes, let the 'true' block be the default
trueNodes.MoveTo(conditionalNode.TrueBody);
// We can exit the 'true' part of Loop or MethodBody conviently using 'break' or 'return'
if (commonReachable.Count > 0) { if (commonReachable.Count > 0) {
Options.NotifyReducingGraph(); Options.NotifyReducingGraph();
falseNodes.MoveTo(conditionalNode.FalseBody); trueNodes.MoveTo(conditionalNode.TrueBody);
} }
Options.NotifyReducingGraph();
falseNodes.MoveTo(conditionalNode.FalseBody);
// Optimize the created subtrees // Optimize the created subtrees
conditionalNode.TrueBody.OptimizeConditions(); conditionalNode.TrueBody.OptimizeConditions();
conditionalNode.FalseBody.OptimizeConditions(); conditionalNode.FalseBody.OptimizeConditions();

6
src/ControlFlow/Node-Transforms.cs

@ -24,7 +24,7 @@ namespace Decompiler.ControlFlow
newNode.Childs.Insert(index, this); newNode.Childs.Insert(index, this);
} }
Node MergeChilds<T>(params Node[] nodes) where T: Node, new() T MergeChilds<T>(params Node[] nodes) where T: Node, new()
{ {
foreach(Node node in nodes) { foreach(Node node in nodes) {
if (node == null) throw new ArgumentNullException("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"); 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 // Add the merged node
Options.NotifyReducingGraph(); Options.NotifyReducingGraph();
@ -40,7 +40,7 @@ namespace Decompiler.ControlFlow
this.Childs.Insert(headIndex, mergedNode); this.Childs.Insert(headIndex, mergedNode);
foreach(Node node in nodes) { foreach(Node node in nodes) {
Options.NotifyReducingGraph(); //Options.NotifyReducingGraph();
node.MoveTo(mergedNode); node.MoveTo(mergedNode);
} }

71
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 { 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 public class MethodBodyGraph: Node
@ -123,11 +184,11 @@ namespace Decompiler.ControlFlow
public class ConditionalNode: Node public class ConditionalNode: Node
{ {
BasicBlock condition; Branch condition;
Block trueBody = new Block(); Block trueBody = new Block();
Block falseBody = new Block(); Block falseBody = new Block();
public BasicBlock Condition { public Branch Condition {
get { return condition; } get { return condition; }
} }
@ -139,7 +200,7 @@ namespace Decompiler.ControlFlow
get { return falseBody; } get { return falseBody; }
} }
public ConditionalNode(BasicBlock condition) public ConditionalNode(Branch condition)
{ {
this.condition = condition; this.condition = condition;

3
src/Transforms/Ast/RemoveGotos.cs

@ -79,7 +79,8 @@ namespace Decompiler.Transforms.Ast
if (next != null) { if (next != null) {
return EnterBlockStatement(next); return EnterBlockStatement(next);
} else { } else {
if (statement.Parent is BlockStatement) { if (statement.Parent is BlockStatement &&
statement.Parent.Parent is Statement) {
return ExitBlockStatement((Statement)statement.Parent.Parent); return ExitBlockStatement((Statement)statement.Parent.Parent);
} else { } else {
return null; return null;

Loading…
Cancel
Save