Browse Source

ILBasicBlock refactored to consist only of the body. Removed ILComment. Closes #86

pull/100/head
David Srbecký 15 years ago
parent
commit
ab9452a30e
  1. 2
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 5
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  3. 50
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  4. 22
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  5. 40
      ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs
  6. 37
      ICSharpCode.Decompiler/ILAst/PatternMatching.cs
  7. 55
      ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs

2
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -193,8 +193,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -193,8 +193,6 @@ namespace ICSharpCode.Decompiler.Ast
yield return fixedStatement;
} else if (node is ILBlock) {
yield return TransformBlock((ILBlock)node);
} else if (node is ILComment) {
yield return new CommentStatement(((ILComment)node).Text).WithAnnotation(((ILComment)node).ILRanges);
} else {
throw new Exception("Unknown node type");
}

5
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -688,10 +688,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -688,10 +688,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILRange ilRange = new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset };
if (byteCode.StackBefore == null) {
ast.Add(new ILComment() {
Text = "Unreachable code: " + byteCode.Code.GetName(),
ILRanges = new List<ILRange>(new[] { ilRange })
});
// Unreachable code
continue;
}

50
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -285,14 +285,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -285,14 +285,14 @@ namespace ICSharpCode.Decompiler.ILAst
{
List<ILNode> basicBlocks = new List<ILNode>();
ILBasicBlock basicBlock = new ILBasicBlock() {
EntryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) }
};
ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) };
ILBasicBlock basicBlock = new ILBasicBlock();
basicBlocks.Add(basicBlock);
block.EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel);
basicBlock.Body.Add(entryLabel);
block.EntryGoto = new ILExpression(ILCode.Br, entryLabel);
if (block.Body.Count > 0) {
if (block.Body[0] != basicBlock.EntryLabel)
if (block.Body[0] != entryLabel)
basicBlock.Body.Add(block.Body[0]);
for (int i = 1; i < block.Body.Count; i++) {
@ -301,8 +301,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -301,8 +301,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Start a new basic block if necessary
if (currNode is ILLabel ||
currNode is ILTryCatchBlock ||
lastNode is ILTryCatchBlock ||
currNode is ILTryCatchBlock || // Counts as label
lastNode.IsConditionalControlFlow() ||
lastNode.IsUnconditionalControlFlow())
{
@ -312,21 +311,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -312,21 +311,18 @@ namespace ICSharpCode.Decompiler.ILAst
// Terminate the last block
if (!lastNode.IsUnconditionalControlFlow()) {
// 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);
basicBlock.Body.Add(new ILExpression(ILCode.Br, label));
}
// Start the new block
// 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(label);
// Add the node to the basic block
if (currNode != label)
basicBlock.Body.Add(currNode);
} else {
basicBlock.Body.Add(currNode);
}
}
@ -396,8 +392,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -396,8 +392,13 @@ namespace ICSharpCode.Decompiler.ILAst
List<ILNode> flatBody = new List<ILNode>();
foreach (ILNode child in block.GetChildren()) {
FlattenBasicBlocks(child);
if (child is ILBasicBlock) {
flatBody.AddRange(child.GetChildren());
ILBasicBlock childAsBB = child as ILBasicBlock;
if (childAsBB != null) {
if (!(childAsBB.Body.FirstOrDefault() is ILLabel))
throw new Exception("Basic block has to start with a label. \n" + childAsBB.ToString());
if (childAsBB.Body.LastOrDefault() is ILExpression && !childAsBB.Body.LastOrDefault().IsUnconditionalControlFlow())
throw new Exception("Basci block has to end with unconditional control flow. \n" + childAsBB.ToString());
flatBody.AddRange(childAsBB.GetChildren());
} else {
flatBody.Add(child);
}
@ -570,6 +571,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -570,6 +571,15 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
public static void RemoveTail(this List<ILNode> body, params ILCode[] codes)
{
for (int i = 0; i < codes.Length; i++) {
if (((ILExpression)body[body.Count - codes.Length + i]).Code != codes[i])
throw new Exception("Tailing code does not match expected.");
}
body.RemoveRange(body.Count - codes.Length, codes.Length);
}
public static V GetOrDefault<K,V>(this Dictionary<K, V> dict, K key)
{
V ret;

22
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -85,19 +85,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -85,19 +85,12 @@ namespace ICSharpCode.Decompiler.ILAst
public class ILBasicBlock: ILNode
{
public ILLabel EntryLabel;
/// <remarks> Body has to start with a label and end with unconditional control flow </remarks>
public List<ILNode> Body = new List<ILNode>();
public ILExpression FallthoughGoto;
public override IEnumerable<ILNode> GetChildren()
{
if (this.EntryLabel != null)
yield return this.EntryLabel;
foreach (ILNode child in this.Body) {
yield return child;
}
if (this.FallthoughGoto != null)
yield return this.FallthoughGoto;
return this.Body;
}
public override void WriteTo(ITextOutput output)
@ -119,17 +112,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -119,17 +112,6 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
public class ILComment: ILNode
{
public string Text;
public List<ILRange> ILRanges { get; set; }
public override void WriteTo(ITextOutput output)
{
output.WriteLine("// " + this.Text);
}
}
public class ILTryCatchBlock: ILNode
{
public class CatchBlock: ILBlock

40
ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -88,7 +88,7 @@ namespace ICSharpCode.Decompiler.ILAst
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)) {
if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault())) {
ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
source.Outgoing.Add(edge);
destination.Incoming.Add(edge);
@ -123,7 +123,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -123,7 +123,8 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(basicBlock.MatchSingle(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
// It has to be just brtrue - any preceding code would introduce goto
if(basicBlock.MatchSingleAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
{
ControlFlowNode trueTarget;
labelToCfNode.TryGetValue(trueLabel, out trueTarget);
@ -157,7 +158,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -157,7 +158,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
// Use loop to implement the brtrue
basicBlock.Body.RemoveAt(basicBlock.Body.Count - 1);
basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
basicBlock.Body.Add(new ILWhileLoop() {
Condition = condExpr,
BodyBlock = new ILBlock() {
@ -165,7 +166,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -165,7 +166,7 @@ namespace ICSharpCode.Decompiler.ILAst
Body = FindLoops(loopContents, node, false)
}
});
basicBlock.FallthoughGoto = new ILExpression(ILCode.Br, falseLabel);
basicBlock.Body.Add(new ILExpression(ILCode.Br, falseLabel));
result.Add(basicBlock);
scope.ExceptWith(loopContents);
@ -175,16 +176,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -175,16 +176,15 @@ namespace ICSharpCode.Decompiler.ILAst
// Fallback method: while(true)
if (scope.Contains(node)) {
result.Add(new ILBasicBlock() {
EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
Body = new List<ILNode>() {
new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
new ILWhileLoop() {
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel),
EntryGoto = new ILExpression(ILCode.Br, (ILLabel)basicBlock.Body.First()),
Body = FindLoops(loopContents, node, true)
}
},
},
FallthoughGoto = null
});
scope.ExceptWith(loopContents);
@ -233,12 +233,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -233,12 +233,13 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel[] caseLabels;
ILExpression switchArg;
ILLabel fallLabel;
if (block.MatchLast(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) {
if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) {
// Replace the switch code with ILSwitch
ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg };
block.Body.RemoveAt(block.Body.Count - 1);
block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
block.Body.Add(ilSwitch);
block.Body.Add(new ILExpression(ILCode.Br, fallLabel));
result.Add(block);
// Remove the item so that it is not picked up as content
@ -285,7 +286,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -285,7 +286,12 @@ namespace ICSharpCode.Decompiler.ILAst
scope.ExceptWith(content);
caseBlock.Body.AddRange(FindConditions(content, condTarget));
// Add explicit break which should not be used by default, but the goto removal might decide to use it
caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILExpression(ILCode.LoopOrSwitchBreak, null) } });
caseBlock.Body.Add(new ILBasicBlock() {
Body = {
new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
new ILExpression(ILCode.LoopOrSwitchBreak, null)
}
});
}
}
caseBlock.Values.Add(i + addValue);
@ -297,12 +303,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -297,12 +303,17 @@ namespace ICSharpCode.Decompiler.ILAst
if (content.Any()) {
var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) };
ilSwitch.CaseBlocks.Add(caseBlock);
block.FallthoughGoto = null;
block.Body.RemoveTail(ILCode.Br);
scope.ExceptWith(content);
caseBlock.Body.AddRange(FindConditions(content, fallTarget));
// Add explicit break which should not be used by default, but the goto removal might decide to use it
caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILExpression(ILCode.LoopOrSwitchBreak, null) } });
caseBlock.Body.Add(new ILBasicBlock() {
Body = {
new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
new ILExpression(ILCode.LoopOrSwitchBreak, null)
}
});
}
}
}
@ -311,7 +322,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -311,7 +322,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(block.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
// Swap bodies since that seems to be the usual C# order
ILLabel temp = trueLabel;
@ -325,9 +336,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -325,9 +336,8 @@ namespace ICSharpCode.Decompiler.ILAst
TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
};
block.Body.RemoveAt(block.Body.Count - 1);
block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
block.Body.Add(ilCond);
block.FallthoughGoto = null;
result.Add(block);
// Remove the item immediately so that it is not picked up as content

37
ICSharpCode.Decompiler/ILAst/PatternMatching.cs

@ -98,29 +98,44 @@ namespace ICSharpCode.Decompiler.ILAst @@ -98,29 +98,44 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool MatchSingle<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)
{
if (bb.Body.Count == 1) {
if (bb.Body[0].Match(code, out operand, out arg)) {
fallLabel = bb.FallthoughGoto != null ? (ILLabel)bb.FallthoughGoto.Operand : null;
return true;
}
if (bb.Body.Count == 2 &&
bb.Body[0] is ILLabel &&
bb.Body[1].Match(code, out operand, out arg))
{
return true;
}
operand = default(T);
arg = null;
return false;
}
public static bool MatchSingleAndBr<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
{
if (bb.Body.Count == 3 &&
bb.Body[0] is ILLabel &&
bb.Body[1].Match(code, out operand, out arg) &&
bb.Body[2].Match(ILCode.Br, out brLabel))
{
return true;
}
operand = default(T);
arg = null;
fallLabel = null;
brLabel = null;
return false;
}
public static bool MatchLast<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel)
public static bool MatchLastAndBr<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
{
if (bb.Body.LastOrDefault().Match(code, out operand, out arg)) {
fallLabel = bb.FallthoughGoto != null ? (ILLabel)bb.FallthoughGoto.Operand : null;
if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out arg) &&
bb.Body.LastOrDefault().Match(ILCode.Br, out brLabel))
{
return true;
}
operand = default(T);
arg = null;
fallLabel = null;
brLabel = null;
return false;
}

55
ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs

@ -48,15 +48,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -48,15 +48,14 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel falseFall;
object unused;
if (head.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
labelGlobalRefCount[trueLabel] == 1 &&
labelGlobalRefCount[falseLabel] == 1 &&
((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 &&
((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) &&
trueLocVar == falseLocVar && trueFall == falseFall) ||
(labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) &&
labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) &&
body.Contains(labelToBasicBlock[trueLabel]) &&
body.Contains(labelToBasicBlock[falseLabel])
)
@ -112,8 +111,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -112,8 +111,10 @@ namespace ICSharpCode.Decompiler.ILAst
newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
}
head.Body[head.Body.Count - 1] = new ILExpression(opCode, trueLocVar, newExpr);
head.FallthoughGoto = isStloc ? new ILExpression(ILCode.Br, trueFall) : null;
head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr));
if (isStloc)
head.Body.Add(new ILExpression(ILCode.Br, trueFall));
// Remove the old basic blocks
body.RemoveOrThrow(labelToBasicBlock[trueLabel]);
@ -147,22 +148,22 @@ namespace ICSharpCode.Decompiler.ILAst @@ -147,22 +148,22 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel rightBBLabel;
ILBasicBlock rightBB;
ILExpression rightExpr;
if (head.Body.Count >= 2 &&
head.Body[head.Body.Count - 2].Match(ILCode.Stloc, out v, out leftExpr) &&
if (head.Body.Count >= 3 &&
head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
leftExpr.Match(ILCode.Ldloc, out leftVar) &&
head.MatchLast(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
leftExpr2.Match(ILCode.Ldloc, leftVar) &&
labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) &&
rightBB.MatchSingle(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
v == v2 &&
endBBLabel == endBBLabel2 &&
labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 &&
body.Contains(rightBB)
)
{
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);
head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
head.Body.Add(new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr)));
head.Body.Add(new ILExpression(ILCode.Br, endBBLabel));
body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]);
return true;
@ -177,7 +178,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -177,7 +178,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(head.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
if(head.MatchLastAndBr(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
@ -192,8 +193,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -192,8 +193,8 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel nextFalseLabel;
if (body.Contains(nextBasicBlock) &&
nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
nextBasicBlock.MatchSingle(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 &&
nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
(otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
{
// Create short cicuit branch
@ -203,8 +204,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -203,8 +204,9 @@ namespace ICSharpCode.Decompiler.ILAst
} else {
logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr);
}
head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr);
head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel);
head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr));
head.Body.Add(new ILExpression(ILCode.Br, nextFalseLabel));
// Remove the inlined branch from scope
body.RemoveOrThrow(nextBasicBlock);
@ -235,19 +237,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -235,19 +237,18 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILLabel nextLabel;
ILBasicBlock nextBB;
ILNode last = head.Body.LastOrDefault();
if (!last.IsConditionalControlFlow() &&
!last.IsUnconditionalControlFlow() &&
head.FallthoughGoto.Match(ILCode.Br, out nextLabel) &&
if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() &&
head.Body.Last().Match(ILCode.Br, out nextLabel) &&
labelGlobalRefCount[nextLabel] == 1 &&
labelToBasicBlock.TryGetValue(nextLabel, out nextBB) &&
body.Contains(nextBB) &&
nextBB.EntryLabel == nextLabel &&
nextBB.Body.First() == nextLabel &&
!nextBB.Body.OfType<ILTryCatchBlock>().Any()
)
{
head.Body.RemoveTail(ILCode.Br);
nextBB.Body.RemoveAt(0); // Remove label
head.Body.AddRange(nextBB.Body);
head.FallthoughGoto = nextBB.FallthoughGoto;
body.RemoveOrThrow(nextBB);
return true;

Loading…
Cancel
Save