Browse Source

Support multiple values per case block

pull/70/head
David Srbecký 15 years ago
parent
commit
74b6624c5e
  1. 8
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 2
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  3. 50
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  4. 26
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

8
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -122,11 +122,11 @@ namespace ICSharpCode.Decompiler.Ast
}; };
} else if (node is ILSwitch) { } else if (node is ILSwitch) {
ILSwitch ilSwitch = (ILSwitch)node; ILSwitch ilSwitch = (ILSwitch)node;
SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition.Arguments[0]) }; SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition) };
for (int i = 0; i < ilSwitch.CaseBlocks.Count; i++) { foreach (var caseBlock in ilSwitch.CaseBlocks) {
SwitchSection section = new SwitchSection(); SwitchSection section = new SwitchSection();
section.CaseLabels.Add(new CaseLabel() { Expression = new PrimitiveExpression(i) }); section.CaseLabels.AddRange(caseBlock.Values.Select(i => new CaseLabel() { Expression = new PrimitiveExpression(i) }));
section.Statements.Add(TransformBlock(ilSwitch.CaseBlocks[i])); section.Statements.Add(TransformBlock(caseBlock));
switchStmt.SwitchSections.Add(section); switchStmt.SwitchSections.Add(section);
} }
yield return switchStmt; yield return switchStmt;

2
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
// Remove redundant break at the end of case // Remove redundant break at the end of case
// Remove redundant case blocks altogether
foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive<ILSwitch>()) { foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive<ILSwitch>()) {
foreach(ILBlock ilCase in ilSwitch.CaseBlocks) { foreach(ILBlock ilCase in ilSwitch.CaseBlocks) {
int count = ilCase.Body.Count; int count = ilCase.Body.Count;
@ -67,6 +68,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
} }
ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak));
} }
// Remove redundant return // Remove redundant return

50
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -101,6 +101,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression expr = block.Body[i] as ILExpression; ILExpression expr = block.Body[i] as ILExpression;
if (expr != null && expr.Prefixes == null) { if (expr != null && expr.Prefixes == null) {
switch(expr.Code) { switch(expr.Code) {
case ILCode.Switch:
case ILCode.Brtrue: case ILCode.Brtrue:
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges); expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear(); expr.ILRanges.Clear();
@ -579,19 +580,15 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condBranch = block.Body[0] as ILExpression; ILExpression condBranch = block.Body[0] as ILExpression;
// Switch // Switch
if (condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0) { ILLabel[] caseLabels;
if (condBranch.Match(ILCode.Switch, out caseLabels)) {
ILLabel[] caseLabels = (ILLabel[])condBranch.Operand; ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch.Arguments.Single() };
// The labels will not be used - kill them
condBranch.Operand = null;
ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch };
result.Add(new ILBasicBlock() { result.Add(new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilSwitch }, Body = { ilSwitch },
FallthoughGoto = block.FallthoughGoto FallthoughGoto = block.FallthoughGoto
}); });
// Remove the item so that it is not picked up as content // Remove the item so that it is not picked up as content
scope.RemoveOrThrow(node); scope.RemoveOrThrow(node);
@ -611,21 +608,26 @@ namespace ICSharpCode.Decompiler.ILAst
frontiers.UnionWith(condTarget.DominanceFrontier); frontiers.UnionWith(condTarget.DominanceFrontier);
} }
foreach(ILLabel condLabel in caseLabels) { for (int i = 0; i < caseLabels.Length; i++) {
ControlFlowNode condTarget = null; ILLabel condLabel = caseLabels[i];
labelToCfNode.TryGetValue(condLabel, out condTarget);
ILBlock caseBlock = new ILBlock() { // Find or create new case block
EntryGoto = new ILExpression(ILCode.Br, condLabel) ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.Where(b => b.EntryGoto.Operand == condLabel).FirstOrDefault();
}; if (caseBlock == null) {
if (condTarget != null && !frontiers.Contains(condTarget)) { caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, condLabel) };
HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget); ilSwitch.CaseBlocks.Add(caseBlock);
scope.ExceptWith(content);
caseBlock.Body.AddRange(FindConditions(content, condTarget)); ControlFlowNode condTarget = null;
// Add explicit break which should not be used by default, but the goto removal might decide to use it labelToCfNode.TryGetValue(condLabel, out condTarget);
caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); if (condTarget != null && !frontiers.Contains(condTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
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) } });
}
} }
ilSwitch.CaseBlocks.Add(caseBlock); caseBlock.Values.Add(i);
} }
} }

26
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -441,8 +442,24 @@ namespace ICSharpCode.Decompiler.ILAst
public class ILSwitch: ILNode public class ILSwitch: ILNode
{ {
public class CaseBlock: ILBlock
{
public List<int> Values = new List<int>();
public override void WriteTo(ITextOutput output)
{
Debug.Assert(Values.Count > 0);
foreach (int i in this.Values) {
output.WriteLine("case {0}:", i);
}
output.Indent();
base.WriteTo(output);
output.Unindent();
}
}
public ILExpression Condition; public ILExpression Condition;
public List<ILBlock> CaseBlocks = new List<ILBlock>(); public List<CaseBlock> CaseBlocks = new List<CaseBlock>();
public override IEnumerable<ILNode> GetChildren() public override IEnumerable<ILNode> GetChildren()
{ {
@ -459,11 +476,8 @@ namespace ICSharpCode.Decompiler.ILAst
Condition.WriteTo(output); Condition.WriteTo(output);
output.WriteLine(") {"); output.WriteLine(") {");
output.Indent(); output.Indent();
for (int i = 0; i < CaseBlocks.Count; i++) { foreach (CaseBlock caseBlock in this.CaseBlocks) {
output.WriteLine("case {0}:", i); caseBlock.WriteTo(output);
output.Indent();
CaseBlocks[i].WriteTo(output);
output.Unindent();
} }
output.Unindent(); output.Unindent();
output.WriteLine("}"); output.WriteLine("}");

Loading…
Cancel
Save