.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

188 lines
5.4 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Decompiler.ControlFlow
{
public abstract partial class Node
{
public void Optimize()
{
if (Options.ReduceLoops) {
OptimizeLoops();
}
if (Options.ReduceConditonals) {
OptimizeShortCircuits();
OptimizeConditions();
}
}
public void OptimizeLoops()
{
Reset:
foreach(Node child in this.Childs) {
if (child.Predecessors.Count == 1) {
Node predecessor = child.Predecessors[0];
Node mergedNode;
if (child.Successors.Contains(predecessor)) {
mergedNode = MergeChilds<Loop>(predecessor, child);
} else {
mergedNode = MergeChilds<AcyclicGraph>(predecessor, child);
}
mergedNode.FalttenAcyclicChilds();
goto Reset;
}
}
// If the result is single acyclic node, eliminate it
if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) {
Node headChild = this.HeadChild;
this.Childs.Remove(this.HeadChild);
headChild.Childs.MoveTo(this);
}
}
NodeCollection GetReachableNodes()
{
NodeCollection reachableNodes = new NodeCollection();
reachableNodes.Add(this);
for(int i = 0; i < reachableNodes.Count; i++) {
foreach(Node alsoReachable in reachableNodes[i].Successors) {
// Do not go though the head child
if (alsoReachable != this.Parent.HeadChild) {
reachableNodes.Add(alsoReachable);
}
}
}
return reachableNodes;
}
public void OptimizeShortCircuits()
{
foreach(Node child in this.Childs) {
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) {
child.OptimizeConditions();
}
Node conditionNode = this.HeadChild;
while(conditionNode != null) {
// Keep looking for some conditional block
if (conditionNode is Branch) {
// Found start of conditional
OptimizeIf((Branch)conditionNode);
// Restart
conditionNode = this.HeadChild;
continue;
} else if (conditionNode.Successors.Count > 0) {
// Keep looking down
conditionNode = conditionNode.Successors[0];
if (conditionNode == this.HeadChild) {
return;
}
continue; // Next
} else {
return; // End of block
}
}
}
public static void OptimizeIf(Branch condition)
{
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;
NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable);
NodeCollection trueNodes = trueReachable.Clone();
trueNodes.RemoveRange(commonReachable);
NodeCollection falseNodes = falseReachable.Clone();
falseNodes.RemoveRange(commonReachable);
// Replace the basic block with condition node
Node conditionParent = condition.Parent;
int conditionIndex = condition.Index;
ConditionalNode conditionalNode = new ConditionalNode(condition);
conditionalNode.MoveTo(conditionParent, conditionIndex);
// If there are no common nodes, let the 'true' block be the default
if (commonReachable.Count > 0) {
trueNodes.MoveTo(conditionalNode.TrueBody);
}
falseNodes.MoveTo(conditionalNode.FalseBody);
// Optimize the created subtrees
conditionalNode.TrueBody.OptimizeConditions();
conditionalNode.FalseBody.OptimizeConditions();
}
}
}