|
|
|
|
@ -12,7 +12,7 @@ namespace Decompiler.ControlFlow
@@ -12,7 +12,7 @@ namespace Decompiler.ControlFlow
|
|
|
|
|
public enum ILAstOptimizationStep |
|
|
|
|
{ |
|
|
|
|
SplitToMovableBlocks, |
|
|
|
|
ShortCircuits, |
|
|
|
|
PeepholeOptimizations, |
|
|
|
|
FindLoops, |
|
|
|
|
FindConditions, |
|
|
|
|
FlattenNestedMovableBlocks, |
|
|
|
|
@ -34,8 +34,11 @@ namespace Decompiler.ControlFlow
@@ -34,8 +34,11 @@ namespace Decompiler.ControlFlow
|
|
|
|
|
SplitToBasicBlocks(block); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (abortBeforeStep == ILAstOptimizationStep.ShortCircuits) return; |
|
|
|
|
OptimizeShortCircuits(method); |
|
|
|
|
if (abortBeforeStep == ILAstOptimizationStep.PeepholeOptimizations) return; |
|
|
|
|
AnalyseLabels(method); |
|
|
|
|
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { |
|
|
|
|
PeepholeOptimizations(block); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return; |
|
|
|
|
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { |
|
|
|
|
@ -132,29 +135,21 @@ namespace Decompiler.ControlFlow
@@ -132,29 +135,21 @@ namespace Decompiler.ControlFlow
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
foreach (ILBasicBlock bb in basicBlocks) { |
|
|
|
|
if (bb.Body.Count > 0 && |
|
|
|
|
bb.Body.Last() is ILExpression && |
|
|
|
|
((ILExpression)bb.Body.Last()).Code == ILCode.Br) |
|
|
|
|
{ |
|
|
|
|
Debug.Assert(bb.FallthoughGoto == null); |
|
|
|
|
bb.FallthoughGoto = (ILExpression)bb.Body.Last(); |
|
|
|
|
bb.Body.RemoveAt(bb.Body.Count - 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
block.Body = basicBlocks; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OptimizeShortCircuits(ILBlock method) |
|
|
|
|
{ |
|
|
|
|
AnalyseLabels(method); |
|
|
|
|
|
|
|
|
|
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { |
|
|
|
|
bool modified; |
|
|
|
|
do { |
|
|
|
|
modified = false; |
|
|
|
|
for (int i = 0; i < block.Body.Count;) { |
|
|
|
|
if (TrySimplifyShortCircuit(block.Body, (ILBasicBlock)block.Body[i])) { |
|
|
|
|
modified = true; |
|
|
|
|
} else { |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} while(modified); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Dictionary<ILLabel, int> labelGlobalRefCount; |
|
|
|
|
Dictionary<ILLabel, ILBasicBlock> labelToBasicBlock; |
|
|
|
|
|
|
|
|
|
@ -175,11 +170,34 @@ namespace Decompiler.ControlFlow
@@ -175,11 +170,34 @@ namespace Decompiler.ControlFlow
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PeepholeOptimizations(ILBlock block) |
|
|
|
|
{ |
|
|
|
|
bool modified; |
|
|
|
|
do { |
|
|
|
|
modified = false; |
|
|
|
|
for (int i = 0; i < block.Body.Count;) { |
|
|
|
|
if (TrySimplifyShortCircuit(block.Body, (ILBasicBlock)block.Body[i])) { |
|
|
|
|
modified = true; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (TrySimplifyTernaryOperator(block.Body, (ILBasicBlock)block.Body[i])) { |
|
|
|
|
modified = true; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
} while(modified); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool IsConditionalBranch(ILBasicBlock bb, ref ILExpression branchExpr, ref ILLabel trueLabel, ref ILLabel falseLabel) |
|
|
|
|
{ |
|
|
|
|
if (bb.Body.Count == 1) { |
|
|
|
|
branchExpr = bb.Body[0] as ILExpression; |
|
|
|
|
if (branchExpr != null && branchExpr.Operand is ILLabel && branchExpr.Arguments.Count > 0) { |
|
|
|
|
if (branchExpr != null && |
|
|
|
|
branchExpr.Operand is ILLabel && |
|
|
|
|
branchExpr.Arguments.Count > 0 && |
|
|
|
|
branchExpr.Prefixes == null) |
|
|
|
|
{ |
|
|
|
|
trueLabel = (ILLabel)branchExpr.Operand; |
|
|
|
|
falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand; |
|
|
|
|
return true; |
|
|
|
|
@ -188,6 +206,71 @@ namespace Decompiler.ControlFlow
@@ -188,6 +206,71 @@ namespace Decompiler.ControlFlow
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel) |
|
|
|
|
{ |
|
|
|
|
if (bb.Body.Count == 1) { |
|
|
|
|
ILExpression expr = bb.Body[0] as ILExpression; |
|
|
|
|
if (expr != null && |
|
|
|
|
expr.Code == ILCode.Stloc && |
|
|
|
|
expr.Prefixes == null) |
|
|
|
|
{ |
|
|
|
|
locVar = (ILVariable)expr.Operand; |
|
|
|
|
val = expr.Arguments[0]; |
|
|
|
|
fallLabel = (ILLabel)bb.FallthoughGoto.Operand; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// scope is modified if successful
|
|
|
|
|
bool TrySimplifyTernaryOperator(List<ILNode> scope, ILBasicBlock head) |
|
|
|
|
{ |
|
|
|
|
Debug.Assert(scope.Contains(head)); |
|
|
|
|
|
|
|
|
|
ILExpression branchExpr = null; |
|
|
|
|
ILLabel trueLabel = null; |
|
|
|
|
ILLabel falseLabel = null; |
|
|
|
|
ILVariable trueLocVar = null; |
|
|
|
|
ILExpression trueExpr = null; |
|
|
|
|
ILLabel trueFall = null; |
|
|
|
|
ILVariable falseLocVar = null; |
|
|
|
|
ILExpression falseExpr = null; |
|
|
|
|
ILLabel falseFall = null; |
|
|
|
|
|
|
|
|
|
if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel) && |
|
|
|
|
labelGlobalRefCount[trueLabel] == 1 && |
|
|
|
|
labelGlobalRefCount[falseLabel] == 1 && |
|
|
|
|
IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) && |
|
|
|
|
IsStloc(labelToBasicBlock[falseLabel], ref falseLocVar, ref falseExpr, ref falseFall) && |
|
|
|
|
trueLocVar == falseLocVar && |
|
|
|
|
trueFall == falseFall) |
|
|
|
|
{ |
|
|
|
|
// Create the ternary expression
|
|
|
|
|
head.Body = new List<ILNode>() { |
|
|
|
|
new ILExpression(ILCode.Stloc, trueLocVar, |
|
|
|
|
new ILExpression(ILCode.TernaryOp, null, |
|
|
|
|
new ILExpression(branchExpr.Code, null, branchExpr.Arguments.ToArray()), |
|
|
|
|
trueExpr, |
|
|
|
|
falseExpr |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
}; |
|
|
|
|
head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall); |
|
|
|
|
|
|
|
|
|
// Remove the old basic blocks
|
|
|
|
|
scope.Remove(labelToBasicBlock[trueLabel]); |
|
|
|
|
scope.Remove(labelToBasicBlock[falseLabel]); |
|
|
|
|
labelToBasicBlock.Remove(trueLabel); |
|
|
|
|
labelToBasicBlock.Remove(falseLabel); |
|
|
|
|
labelGlobalRefCount.Remove(trueLabel); |
|
|
|
|
labelGlobalRefCount.Remove(falseLabel); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// scope is modified if successful
|
|
|
|
|
bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head) |
|
|
|
|
{ |
|
|
|
|
@ -228,7 +311,8 @@ namespace Decompiler.ControlFlow
@@ -228,7 +311,8 @@ namespace Decompiler.ControlFlow
|
|
|
|
|
head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel); |
|
|
|
|
|
|
|
|
|
// Remove the inlined branch from scope
|
|
|
|
|
labelGlobalRefCount[nextBasicBlock.EntryLabel] = 0; |
|
|
|
|
labelGlobalRefCount.Remove(nextBasicBlock.EntryLabel); |
|
|
|
|
labelToBasicBlock.Remove(nextBasicBlock.EntryLabel); |
|
|
|
|
if (!scope.Remove(nextBasicBlock)) |
|
|
|
|
throw new Exception("Element not found"); |
|
|
|
|
|
|
|
|
|
|