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

2
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
// Remove redundant break at the end of case
// Remove redundant case blocks altogether
foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive<ILSwitch>()) {
foreach(ILBlock ilCase in ilSwitch.CaseBlocks) {
int count = ilCase.Body.Count;
@ -67,6 +68,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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

28
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -101,6 +101,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -101,6 +101,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression expr = block.Body[i] as ILExpression;
if (expr != null && expr.Prefixes == null) {
switch(expr.Code) {
case ILCode.Switch:
case ILCode.Brtrue:
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear();
@ -579,14 +580,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -579,14 +580,10 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condBranch = block.Body[0] as ILExpression;
// 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;
// The labels will not be used - kill them
condBranch.Operand = null;
ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch };
ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch.Arguments.Single() };
result.Add(new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilSwitch },
@ -611,13 +608,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -611,13 +608,17 @@ namespace ICSharpCode.Decompiler.ILAst
frontiers.UnionWith(condTarget.DominanceFrontier);
}
foreach(ILLabel condLabel in caseLabels) {
for (int i = 0; i < caseLabels.Length; i++) {
ILLabel condLabel = caseLabels[i];
// Find or create new case block
ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.Where(b => b.EntryGoto.Operand == condLabel).FirstOrDefault();
if (caseBlock == null) {
caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, condLabel) };
ilSwitch.CaseBlocks.Add(caseBlock);
ControlFlowNode condTarget = null;
labelToCfNode.TryGetValue(condLabel, out condTarget);
ILBlock caseBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, condLabel)
};
if (condTarget != null && !frontiers.Contains(condTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
scope.ExceptWith(content);
@ -625,7 +626,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -625,7 +626,8 @@ namespace ICSharpCode.Decompiler.ILAst
// 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 @@ @@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
@ -441,8 +442,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -441,8 +442,24 @@ namespace ICSharpCode.Decompiler.ILAst
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 List<ILBlock> CaseBlocks = new List<ILBlock>();
public List<CaseBlock> CaseBlocks = new List<CaseBlock>();
public override IEnumerable<ILNode> GetChildren()
{
@ -459,11 +476,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -459,11 +476,8 @@ namespace ICSharpCode.Decompiler.ILAst
Condition.WriteTo(output);
output.WriteLine(") {");
output.Indent();
for (int i = 0; i < CaseBlocks.Count; i++) {
output.WriteLine("case {0}:", i);
output.Indent();
CaseBlocks[i].WriteTo(output);
output.Unindent();
foreach (CaseBlock caseBlock in this.CaseBlocks) {
caseBlock.WriteTo(output);
}
output.Unindent();
output.WriteLine("}");

Loading…
Cancel
Save