Browse Source

SimplifyCascadingIfStatements: Remove extra variable declarations before switch, if possible.

pull/887/head
Siegfried Pammer 8 years ago
parent
commit
d39a21afd7
  1. 43
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

43
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -41,9 +41,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -41,9 +41,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool changed = false;
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
SwitchInstruction newSwitch;
if (SimplifyCascadingIfStatements(block.Instructions, i, out newSwitch)) {
block.Instructions[i + 1].ReplaceWith(newSwitch);
block.Instructions.RemoveAt(i);
if (SimplifyCascadingIfStatements(block.Instructions, i, out newSwitch, out var extraLoad, out var keepAssignmentBefore)) {
if (extraLoad) {
block.Instructions[i - 2].ReplaceWith(newSwitch);
block.Instructions.RemoveRange(i - 1, 3);
i -= 2;
} else {
if (keepAssignmentBefore) {
block.Instructions[i].ReplaceWith(newSwitch);
block.Instructions.RemoveAt(i + 1);
} else {
block.Instructions[i - 1].ReplaceWith(newSwitch);
block.Instructions.RemoveRange(i, 2);
i--;
}
}
changed = true;
continue;
}
@ -77,9 +89,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -77,9 +89,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
container.SortBlocks(deleteUnreachableBlocks: true);
}
bool SimplifyCascadingIfStatements(InstructionCollection<ILInstruction> instructions, int i, out SwitchInstruction inst)
bool SimplifyCascadingIfStatements(InstructionCollection<ILInstruction> instructions, int i, out SwitchInstruction inst, out bool extraLoad, out bool keepAssignmentBefore)
{
inst = null;
extraLoad = false;
keepAssignmentBefore = false;
if (i < 1) return false;
// match first block: checking switch-value for null or first value (Roslyn)
// if (call op_Equality(ldloc switchValueVar, ldstr value)) br firstBlock
// -or-
@ -99,6 +114,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -99,6 +114,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// switchValueVar must be assigned only once and must be of type string.
if (!switchValueVar.IsSingleDefinition || !switchValueVar.Type.IsKnownType(KnownTypeCode.String))
return false;
// if instruction must be preceeded by a stloc to the switchValueVar
if (instructions[i - 1].MatchStLoc(switchValueVar, out var switchValue)) { }
// in case of legacy code there are two stlocs:
// stloc switchValueVar(ldloc switchValue)
// stloc otherSwitchValueVar(ldloc switchValueVar)
// if (comp(ldloc switchValueVar == ldnull)) br nullCase
else if (i > 1 && instructions[i - 2].MatchStLoc(switchValueVar, out switchValue) &&
instructions[i - 1].MatchStLoc(out var otherSwitchValueVar, out var switchValueCopyInst) &&
switchValueCopyInst.MatchLdLoc(switchValueVar) && otherSwitchValueVar.IsSingleDefinition && switchValueVar.LoadCount == 2)
{
extraLoad = true;
}
else return false;
// if instruction must be followed by a branch to the next case
if (!(instructions.ElementAtOrDefault(i + 1) is Branch nextCaseJump))
return false;
@ -112,9 +140,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -112,9 +140,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// We didn't find enough cases, exit
if (values.Count < 3)
return false;
// if the switchValueVar is used in other places as well, do not eliminate the store.
if (switchValueVar.LoadCount > values.Count) {
keepAssignmentBefore = true;
switchValue = new LdLoc(switchValueVar);
}
var sections = new List<SwitchSection>(values.SelectWithIndex((index, b) => new SwitchSection { Labels = new LongSet(index), Body = new Branch(b.Item2) }));
sections.Add(new SwitchSection { Labels = new LongSet(new LongInterval(0, sections.Count)).Invert(), Body = new Branch(currentCaseBlock) });
var stringToInt = new StringToInt(new LdLoc(switchValueVar), values.SelectArray(item => item.Item1));
var stringToInt = new StringToInt(switchValue, values.SelectArray(item => item.Item1));
inst = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections);
return true;

Loading…
Cancel
Save