Browse Source

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

pull/887/head
Siegfried Pammer 9 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
bool changed = false; bool changed = false;
for (int i = block.Instructions.Count - 1; i >= 0; i--) { for (int i = block.Instructions.Count - 1; i >= 0; i--) {
SwitchInstruction newSwitch; SwitchInstruction newSwitch;
if (SimplifyCascadingIfStatements(block.Instructions, i, out newSwitch)) { if (SimplifyCascadingIfStatements(block.Instructions, i, out newSwitch, out var extraLoad, out var keepAssignmentBefore)) {
block.Instructions[i + 1].ReplaceWith(newSwitch); if (extraLoad) {
block.Instructions.RemoveAt(i); 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; changed = true;
continue; continue;
} }
@ -77,9 +89,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
container.SortBlocks(deleteUnreachableBlocks: true); 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; inst = null;
extraLoad = false;
keepAssignmentBefore = false;
if (i < 1) return false;
// match first block: checking switch-value for null or first value (Roslyn) // match first block: checking switch-value for null or first value (Roslyn)
// if (call op_Equality(ldloc switchValueVar, ldstr value)) br firstBlock // if (call op_Equality(ldloc switchValueVar, ldstr value)) br firstBlock
// -or- // -or-
@ -99,6 +114,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// switchValueVar must be assigned only once and must be of type string. // switchValueVar must be assigned only once and must be of type string.
if (!switchValueVar.IsSingleDefinition || !switchValueVar.Type.IsKnownType(KnownTypeCode.String)) if (!switchValueVar.IsSingleDefinition || !switchValueVar.Type.IsKnownType(KnownTypeCode.String))
return false; 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 instruction must be followed by a branch to the next case
if (!(instructions.ElementAtOrDefault(i + 1) is Branch nextCaseJump)) if (!(instructions.ElementAtOrDefault(i + 1) is Branch nextCaseJump))
return false; return false;
@ -112,9 +140,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// We didn't find enough cases, exit // We didn't find enough cases, exit
if (values.Count < 3) if (values.Count < 3)
return false; 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) })); 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) }); 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 = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
return true; return true;

Loading…
Cancel
Save