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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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;
}

193
src/AstMetodBodyBuilder.cs

@ -87,12 +87,12 @@ namespace Decompiler @@ -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 @@ -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 @@ -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>();
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<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 (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 @@ -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<Ast.Expression> allArgs = new List<Ast.Expression>();
// 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<Ast.Expression> 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 @@ -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) {

91
src/ControlFlow/Node-Optimize.cs

@ -13,6 +13,7 @@ namespace Decompiler.ControlFlow @@ -13,6 +13,7 @@ namespace Decompiler.ControlFlow
OptimizeLoops();
}
if (Options.ReduceConditonals) {
OptimizeShortCircuits();
OptimizeConditions();
}
}
@ -57,6 +58,76 @@ namespace Decompiler.ControlFlow @@ -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<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()
{
foreach(Node child in this.Childs) {
@ -68,9 +139,9 @@ namespace Decompiler.ControlFlow @@ -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 @@ -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 @@ -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();

6
src/ControlFlow/Node-Transforms.cs

@ -24,7 +24,7 @@ namespace Decompiler.ControlFlow @@ -24,7 +24,7 @@ namespace Decompiler.ControlFlow
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) {
if (node == null) throw new ArgumentNullException("nodes");
@ -32,7 +32,7 @@ namespace Decompiler.ControlFlow @@ -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 @@ -40,7 +40,7 @@ namespace Decompiler.ControlFlow
this.Childs.Insert(headIndex, mergedNode);
foreach(Node node in nodes) {
Options.NotifyReducingGraph();
//Options.NotifyReducingGraph();
node.MoveTo(mergedNode);
}

71
src/ControlFlow/Nodes.cs

@ -40,12 +40,73 @@ namespace Decompiler.ControlFlow @@ -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 @@ -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 @@ -139,7 +200,7 @@ namespace Decompiler.ControlFlow
get { return falseBody; }
}
public ConditionalNode(BasicBlock condition)
public ConditionalNode(Branch condition)
{
this.condition = condition;

3
src/Transforms/Ast/RemoveGotos.cs

@ -79,7 +79,8 @@ namespace Decompiler.Transforms.Ast @@ -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;

Loading…
Cancel
Save