Browse Source

Do not put brtrue into its own basic block - store it together with the previous instructions.

Handle single-statement loops.
pull/100/head
David Srbecký 15 years ago
parent
commit
6046fdcdfb
  1. 4
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  2. 121
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 154
      ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs
  4. 16
      ICSharpCode.Decompiler/ILAst/PatternMatching.cs

4
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -18,8 +18,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -18,8 +18,8 @@ namespace ICSharpCode.Decompiler.ILAst
foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) {
ILNode previousChild = null;
foreach (ILNode child in node.GetChildren()) {
// TODO: Add back
// Debug.Assert(!parent.ContainsKey(child));
if (parent.ContainsKey(child))
throw new Exception("The following expression is linked from several locations: " + child.ToString());
parent[child] = node;
if (previousChild != null)
nextSibling[previousChild] = child;

121
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -168,6 +168,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -168,6 +168,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
// TODO: Move before loops
CachedDelegateInitialization(block, ref i);
}
}
@ -175,6 +176,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -175,6 +176,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
// TODO: Move before loops
IntroduceFixedStatements(block.Body, i);
}
}
@ -285,59 +287,51 @@ namespace ICSharpCode.Decompiler.ILAst @@ -285,59 +287,51 @@ namespace ICSharpCode.Decompiler.ILAst
List<ILNode> basicBlocks = new List<ILNode>();
ILBasicBlock basicBlock = new ILBasicBlock() {
EntryLabel = new ILLabel() { Name = "Block_" + (nextLabelIndex++) }
EntryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) }
};
basicBlocks.Add(basicBlock);
block.EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel);
if (block.Body.Count > 0) {
basicBlock.Body.Add(block.Body[0]);
if (block.Body[0] != basicBlock.EntryLabel)
basicBlock.Body.Add(block.Body[0]);
for (int i = 1; i < block.Body.Count; i++) {
ILNode lastNode = block.Body[i - 1];
ILNode currNode = block.Body[i];
// Insert split
// Start a new basic block if necessary
if (currNode is ILLabel ||
lastNode is ILTryCatchBlock ||
currNode is ILTryCatchBlock ||
(lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() ||
(currNode is ILExpression) && (((ILExpression)currNode).IsBranch() && ((ILExpression)currNode).Code.CanFallThough() && basicBlock.Body.Count > 0))
(lastNode is ILExpression && ((ILExpression)lastNode).IsBranch()))
{
ILBasicBlock lastBlock = basicBlock;
basicBlock = new ILBasicBlock();
basicBlocks.Add(basicBlock);
// Try to reuse the label
ILLabel label = currNode is ILLabel ? ((ILLabel)currNode) : new ILLabel() { Name = "Block_" + (nextLabelIndex++) };
if (currNode is ILLabel) {
// Insert as entry label
basicBlock.EntryLabel = (ILLabel)currNode;
} else {
basicBlock.EntryLabel = new ILLabel() { Name = "Block_" + (nextLabelIndex++) };
basicBlock.Body.Add(currNode);
// Terminate the last block
if (lastNode.CanFallThough()) {
// Explicit branch from one block to other
basicBlock.FallthoughGoto = new ILExpression(ILCode.Br, label);
} else if (lastNode.Match(ILCode.Br)) {
// Reuse the existing goto as FallthoughGoto
basicBlock.FallthoughGoto = (ILExpression)lastNode;
basicBlock.Body.RemoveAt(basicBlock.Body.Count - 1);
}
// Explicit branch from one block to other
// (unless the last expression was unconditional branch)
if (!(lastNode is ILExpression) || ((ILExpression)lastNode).Code.CanFallThough()) {
lastBlock.FallthoughGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel);
}
} else {
// Start the new block
basicBlock = new ILBasicBlock();
basicBlocks.Add(basicBlock);
basicBlock.EntryLabel = label;
}
// Add the node to the basic block
if (currNode != basicBlock.EntryLabel) {
basicBlock.Body.Add(currNode);
}
}
}
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;
}
@ -362,7 +356,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -362,7 +356,6 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
// scope is modified if successful
bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int pos)
{
Debug.Assert(body.Contains(head));
@ -378,13 +371,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -378,13 +371,13 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel falseFall;
object unused;
if (head.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
if (head.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
labelGlobalRefCount[trueLabel] == 1 &&
labelGlobalRefCount[falseLabel] == 1 &&
((labelToBasicBlock[trueLabel].Match(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
labelToBasicBlock[falseLabel].Match(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall)) ||
(labelToBasicBlock[trueLabel].Match(ILCode.Ret, out unused, out trueExpr, out trueFall) &&
labelToBasicBlock[falseLabel].Match(ILCode.Ret, out unused, out falseExpr, out falseFall))) &&
((labelToBasicBlock[trueLabel].MatchSingle(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
labelToBasicBlock[falseLabel].MatchSingle(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall)) ||
(labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr, out trueFall) &&
labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr, out falseFall))) &&
trueLocVar == falseLocVar &&
trueFall == falseFall &&
body.Contains(labelToBasicBlock[trueLabel]) &&
@ -436,7 +429,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -436,7 +429,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Create ternary expression
newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
}
head.Body = new List<ILNode>() { new ILExpression(opCode, trueLocVar, newExpr) };
head.Body[head.Body.Count - 1] = new ILExpression(opCode, trueLocVar, newExpr);
head.FallthoughGoto = trueFall != null ? new ILExpression(ILCode.Br, trueFall) : null;
// Remove the old basic blocks
@ -455,57 +448,45 @@ namespace ICSharpCode.Decompiler.ILAst @@ -455,57 +448,45 @@ namespace ICSharpCode.Decompiler.ILAst
{
// ...
// v = ldloc(leftVar)
// br(condBBLabel)
//
// condBBLabel:
// brtrue(endBBLabel, ldloc(leftVar))
// br(rightBBLabel)
//
// rightBBLabel:
// v = rightExpr
// br(endBBLabel)
//
// endBBLabel:
// ...
// =>
// ...
// v = NullCoalescing(ldloc(leftVar), rightExpr)
// br(endBBLabel)
ILVariable v, v2;
ILExpression leftExpr, leftExpr2;
ILVariable leftVar, leftVar2;
ILLabel condBBLabel;
ILBasicBlock condBB;
ILVariable leftVar;
ILLabel endBBLabel, endBBLabel2;
ILLabel rightBBLabel;
ILBasicBlock rightBB;
ILExpression rightExpr;
ILBasicBlock endBB;
if (head.Body.LastOrDefault().Match(ILCode.Stloc, out v, out leftExpr) &&
if (head.Body.Count >= 2 &&
head.Body[head.Body.Count - 2].Match(ILCode.Stloc, out v, out leftExpr) &&
leftExpr.Match(ILCode.Ldloc, out leftVar) &&
head.FallthoughGoto.Match(ILCode.Br, out condBBLabel) &&
labelToBasicBlock.TryGetValue(condBBLabel, out condBB) &&
condBB.Match(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
leftExpr2.Match(ILCode.Ldloc, out leftVar2) &&
leftVar == leftVar2 &&
head.MatchLast(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
leftExpr2.Match(ILCode.Ldloc, leftVar) &&
labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) &&
rightBB.Match(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
rightBB.MatchSingle(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
v == v2 &&
endBBLabel == endBBLabel2 &&
labelToBasicBlock.TryGetValue(endBBLabel, out endBB) &&
labelGlobalRefCount.GetOrDefault(condBBLabel) == 1 &&
labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 &&
labelGlobalRefCount.GetOrDefault(endBBLabel) == 2 &&
body.Contains(condBB) &&
body.Contains(rightBB) &&
body.Contains(endBB)
body.Contains(rightBB)
)
{
head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr));
head.Body[head.Body.Count - 2] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr));
head.Body.RemoveAt(head.Body.Count - 1);
head.FallthoughGoto = new ILExpression(ILCode.Br, endBBLabel);
foreach(ILLabel deleteLabel in new [] { condBBLabel, rightBBLabel }) {
body.RemoveOrThrow(labelToBasicBlock[deleteLabel]);
labelGlobalRefCount.RemoveOrThrow(deleteLabel);
labelToBasicBlock.RemoveOrThrow(deleteLabel);
}
body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]);
labelGlobalRefCount.RemoveOrThrow(rightBBLabel);
labelToBasicBlock.RemoveOrThrow(rightBBLabel);
return true;
}
return false;
@ -518,7 +499,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -518,7 +499,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(head.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
if(head.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
for (int pass = 0; pass < 2; pass++) {
// On the second pass, swap labels and negate expression of the first branch
@ -534,14 +515,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -534,14 +515,14 @@ namespace ICSharpCode.Decompiler.ILAst
if (body.Contains(nextBasicBlock) &&
nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
nextBasicBlock.Match(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
nextBasicBlock.MatchSingle(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
(otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
{
// Create short cicuit branch
if (otherLablel == nextFalseLabel) {
head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr));
head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr));
} else {
head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr));
head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr));
}
head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel);

154
ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs

@ -27,20 +27,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -27,20 +27,24 @@ namespace ICSharpCode.Decompiler.ILAst
public void FindLoops(ILBlock block)
{
ControlFlowGraph graph;
graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
graph.ComputeDominance(context.CancellationToken);
graph.ComputeDominanceFrontier();
block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false);
if (block.Body.Count > 0) {
ControlFlowGraph graph;
graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
graph.ComputeDominance(context.CancellationToken);
graph.ComputeDominanceFrontier();
block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false);
}
}
public void FindConditions(ILBlock block)
{
ControlFlowGraph graph;
graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
graph.ComputeDominance(context.CancellationToken);
graph.ComputeDominanceFrontier();
block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
if (block.Body.Count > 0) {
ControlFlowGraph graph;
graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
graph.ComputeDominance(context.CancellationToken);
graph.ComputeDominanceFrontier();
block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
}
}
ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
@ -57,7 +61,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -57,7 +61,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Create graph nodes
labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
foreach(ILNode node in nodes) {
foreach(ILBasicBlock node in nodes) {
ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);
cfNodes.Add(cfNode);
astNodeToCfNode[node] = cfNode;
@ -76,22 +80,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -76,22 +80,18 @@ namespace ICSharpCode.Decompiler.ILAst
entryNode.Incoming.Add(entryEdge);
// Create edges
foreach(ILNode node in nodes) {
foreach(ILBasicBlock node in nodes) {
ControlFlowNode source = astNodeToCfNode[node];
// Find all branches
foreach(ILExpression child in node.GetSelfAndChildrenRecursive<ILExpression>()) {
IEnumerable<ILLabel> targets = child.GetBranchTargets();
if (targets != null) {
foreach(ILLabel target in targets) {
ControlFlowNode destination;
// Labels which are out of out scope will not be int the collection
if (labelToCfNode.TryGetValue(target, out destination) && destination != source) {
ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
source.Outgoing.Add(edge);
destination.Incoming.Add(edge);
}
}
foreach(ILLabel target in node.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) {
ControlFlowNode destination;
// Labels which are out of out scope will not be int the collection
// Insert self edge only if we are sure we are a loop
if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.EntryLabel)) {
ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
source.Outgoing.Add(edge);
destination.Incoming.Add(edge);
}
}
}
@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(basicBlock.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
if(basicBlock.MatchSingle(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
{
ControlFlowNode trueTarget;
labelToCfNode.TryGetValue(trueLabel, out trueTarget);
@ -138,7 +138,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -138,7 +138,7 @@ namespace ICSharpCode.Decompiler.ILAst
scope.RemoveOrThrow(node);
// If false means enter the loop
if (loopContents.Contains(falseTarget))
if (loopContents.Contains(falseTarget) || falseTarget == node)
{
// Negate the condition
condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
@ -156,42 +156,39 @@ namespace ICSharpCode.Decompiler.ILAst @@ -156,42 +156,39 @@ namespace ICSharpCode.Decompiler.ILAst
loopContents.UnionWith(pullIn);
}
// Use loop to implement the condition
result.Add(new ILBasicBlock() {
EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() {
new ILWhileLoop() {
Condition = condExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true)
}
},
new ILExpression(ILCode.Br, falseLabel)
},
FallthoughGoto = null
});
// Use loop to implement the brtrue
basicBlock.Body.RemoveAt(basicBlock.Body.Count - 1);
basicBlock.Body.Add(new ILWhileLoop() {
Condition = condExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, false)
}
});
basicBlock.FallthoughGoto = new ILExpression(ILCode.Br, falseLabel);
result.Add(basicBlock);
scope.ExceptWith(loopContents);
}
}
// Fallback method: while(true)
if (scope.Contains(node)) {
result.Add(new ILBasicBlock() {
EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
Body = new List<ILNode>() {
new ILWhileLoop() {
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel),
Body = FindLoops(loopContents, node, true)
}
},
},
FallthoughGoto = null
});
EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
Body = new List<ILNode>() {
new ILWhileLoop() {
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel),
Body = FindLoops(loopContents, node, true)
}
},
},
FallthoughGoto = null
});
scope.ExceptWith(loopContents);
}
// Move the content into loop block
scope.ExceptWith(loopContents);
}
// Using the dominator tree should ensure we find the the widest loop first
@ -229,24 +226,20 @@ namespace ICSharpCode.Decompiler.ILAst @@ -229,24 +226,20 @@ namespace ICSharpCode.Decompiler.ILAst
// Find a block that represents a simple condition
if (scope.Contains(node)) {
ILBasicBlock block = node.UserData as ILBasicBlock;
ILBasicBlock block = (ILBasicBlock)node.UserData;
if (block != null && block.Body.Count == 1) {
ILExpression condBranch = block.Body[0] as ILExpression;
{
// Switch
ILLabel[] caseLabels;
List<ILExpression> switchArgs;
if (condBranch.Match(ILCode.Switch, out caseLabels, out switchArgs)) {
ILExpression switchArg;
ILLabel fallLabel;
if (block.MatchLast(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) {
ILSwitch ilSwitch = new ILSwitch() { Condition = switchArgs.Single() };
ILBasicBlock newBB = new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilSwitch },
FallthoughGoto = block.FallthoughGoto
};
result.Add(newBB);
// Replace the switch code with ILSwitch
ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg };
block.Body.RemoveAt(block.Body.Count - 1);
block.Body.Add(ilSwitch);
result.Add(block);
// Remove the item so that it is not picked up as content
scope.RemoveOrThrow(node);
@ -259,19 +252,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -259,19 +252,18 @@ namespace ICSharpCode.Decompiler.ILAst
}
// Pull in code of cases
ILLabel fallLabel = (ILLabel)block.FallthoughGoto.Operand;
ControlFlowNode fallTarget = null;
labelToCfNode.TryGetValue(fallLabel, out fallTarget);
HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
if (fallTarget != null)
frontiers.UnionWith(fallTarget.DominanceFrontier);
frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget }));
foreach(ILLabel condLabel in caseLabels) {
ControlFlowNode condTarget = null;
labelToCfNode.TryGetValue(condLabel, out condTarget);
if (condTarget != null)
frontiers.UnionWith(condTarget.DominanceFrontier);
frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget }));
}
for (int i = 0; i < caseLabels.Length; i++) {
@ -305,7 +297,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -305,7 +297,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (content.Any()) {
var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) };
ilSwitch.CaseBlocks.Add(caseBlock);
newBB.FallthoughGoto = null;
block.FallthoughGoto = null;
scope.ExceptWith(content);
caseBlock.Body.AddRange(FindConditions(content, fallTarget));
@ -319,7 +311,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -319,7 +311,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(block.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
if(block.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
// Swap bodies since that seems to be the usual C# order
ILLabel temp = trueLabel;
@ -327,16 +319,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -327,16 +319,16 @@ namespace ICSharpCode.Decompiler.ILAst
falseLabel = temp;
condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
// Convert the basic block to ILCondition
// Convert the brtrue to ILCondition
ILCondition ilCond = new ILCondition() {
Condition = condExpr,
TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
};
result.Add(new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilCond }
});
block.Body.RemoveAt(block.Body.Count - 1);
block.Body.Add(ilCond);
block.FallthoughGoto = null;
result.Add(block);
// Remove the item immediately so that it is not picked up as content
scope.RemoveOrThrow(node);
@ -349,9 +341,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -349,9 +341,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Pull in the conditional code
HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
if (trueTarget != null)
frontiers.UnionWith(trueTarget.DominanceFrontier);
frontiers.UnionWith(trueTarget.DominanceFrontier.Except(new [] { trueTarget }));
if (falseTarget != null)
frontiers.UnionWith(falseTarget.DominanceFrontier);
frontiers.UnionWith(falseTarget.DominanceFrontier.Except(new [] { falseTarget }));
if (trueTarget != null && !frontiers.Contains(trueTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);

16
ICSharpCode.Decompiler/ILAst/PatternMatching.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.ILAst
@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool Match<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel)
public static bool MatchSingle<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel)
{
if (bb.Body.Count == 1) {
if (bb.Body[0].Match(code, out operand, out arg)) {
@ -112,6 +112,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -112,6 +112,18 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool MatchLast<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel)
{
if (bb.Body.LastOrDefault().Match(code, out operand, out arg)) {
fallLabel = bb.FallthoughGoto != null ? (ILLabel)bb.FallthoughGoto.Operand : null;
return true;
}
operand = default(T);
arg = null;
fallLabel = null;
return false;
}
public static bool MatchThis(this ILNode node)
{
ILVariable v;

Loading…
Cancel
Save