Browse Source

Simplify SwitchOnNullableTransform.

pull/887/head
Daniel Grunwald 8 years ago
parent
commit
6272c21ece
  1. 41
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  2. 53
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs
  3. 2
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

41
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -102,7 +102,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -102,7 +102,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
#region AnalyzeCondition
bool AnalyzeCondition(ILInstruction condition)
{
if (MatchHasValueCall(condition, out var v)) {
if (MatchHasValueCall(condition, out ILVariable v)) {
if (nullableVars == null)
nullableVars = new List<ILVariable>();
nullableVars.Add(v);
@ -387,9 +387,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -387,9 +387,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Comparing two nullables: HasValue comparison must be the same operator as the Value comparison
if ((hasValueTestNegated ? hasValueComp.Kind.Negate() : hasValueComp.Kind) != newComparisonKind)
return null;
if (!MatchHasValueCall(hasValueComp.Left, out var leftVar))
if (!MatchHasValueCall(hasValueComp.Left, out ILVariable leftVar))
return null;
if (!MatchHasValueCall(hasValueComp.Right, out var rightVar))
if (!MatchHasValueCall(hasValueComp.Right, out ILVariable rightVar))
return null;
nullableVars = new List<ILVariable> { leftVar };
var (left, leftBits) = DoLift(valueComp.Left);
@ -401,7 +401,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -401,7 +401,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("NullableLiftingTransform: C# (in)equality comparison", valueComp.Instruction);
return valueComp.MakeLifted(newComparisonKind, left, right);
}
} else if (newComparisonKind == ComparisonKind.Equality && !hasValueTestNegated && MatchHasValueCall(hasValueTest, out var v)) {
} else if (newComparisonKind == ComparisonKind.Equality && !hasValueTestNegated && MatchHasValueCall(hasValueTest, out ILVariable v)) {
// Comparing nullable with non-nullable -> we can fall back to the normal comparison code.
nullableVars = new List<ILVariable> { v };
return LiftCSharpComparison(valueComp, newComparisonKind);
@ -461,13 +461,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -461,13 +461,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// else
// ldc.i4 0
if (!MatchHasValueCall(hasValueComp.Left, out var nullable1))
if (!MatchHasValueCall(hasValueComp.Left, out ILVariable nullable1))
return null;
if (!MatchHasValueCall(hasValueComp.Right, out var nullable2))
if (!MatchHasValueCall(hasValueComp.Right, out ILVariable nullable2))
return null;
if (!nestedIfInst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst))
return null;
if (!MatchHasValueCall(condition, out var nullable))
if (!MatchHasValueCall(condition, out ILVariable nullable))
return null;
if (nullable != nullable1 && nullable != nullable2)
return null;
@ -516,7 +516,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -516,7 +516,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (trueInst.MatchIfInstructionPositiveCondition(out var nestedCondition, out var nestedTrue, out var nestedFalse)) {
// Sometimes Roslyn generates pointless conditions like:
// if (nullable.HasValue && (!nullable.HasValue || nullable.GetValueOrDefault() == b))
if (MatchHasValueCall(nestedCondition, out var v) && nullableVars.Contains(v)) {
if (MatchHasValueCall(nestedCondition, out ILVariable v) && nullableVars.Contains(v)) {
trueInst = nestedTrue;
}
}
@ -758,11 +758,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -758,11 +758,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
#region Match...Call
/// <summary>
/// Matches 'call get_HasValue(ldloca v)'
/// Matches 'call get_HasValue(arg)'
/// </summary>
internal static bool MatchHasValueCall(ILInstruction inst, out ILVariable v)
internal static bool MatchHasValueCall(ILInstruction inst, out ILInstruction arg)
{
v = null;
arg = null;
if (!(inst is Call call))
return false;
if (call.Arguments.Count != 1)
@ -771,7 +771,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -771,7 +771,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (call.Method.DeclaringTypeDefinition?.KnownTypeCode != KnownTypeCode.NullableOfT)
return false;
return call.Arguments[0].MatchLdLoca(out v);
arg = call.Arguments[0];
return true;
}
/// <summary>
/// Matches 'call get_HasValue(ldloca v)'
/// </summary>
internal static bool MatchHasValueCall(ILInstruction inst, out ILVariable v)
{
if (MatchHasValueCall(inst, out ILInstruction arg)) {
return arg.MatchLdLoca(out v);
}
v = null;
return false;
}
/// <summary>
@ -779,7 +792,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -779,7 +792,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
internal static bool MatchHasValueCall(ILInstruction inst, ILVariable v)
{
return MatchHasValueCall(inst, out var v2) && v == v2;
return MatchHasValueCall(inst, out ILVariable v2) && v == v2;
}
/// <summary>
@ -811,7 +824,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -811,7 +824,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary>
/// Matches 'call Nullable{T}.GetValueOrDefault(arg)'
/// </summary>
static bool MatchGetValueOrDefault(ILInstruction inst, out ILInstruction arg)
internal static bool MatchGetValueOrDefault(ILInstruction inst, out ILInstruction arg)
{
arg = null;
if (!(inst is Call call))

53
ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs

@ -92,15 +92,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -92,15 +92,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!condition.MatchLogicNot(out var getHasValue))
return false;
if (!(getValueOrDefault is Call getValueOrDefaultCall) || getValueOrDefaultCall.Method.FullName != "System.Nullable.GetValueOrDefault" ||
getValueOrDefaultCall.Method.DeclaringType.TypeParameterCount != 1)
if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out ILInstruction getValueOrDefaultArg))
return false;
if (!(getHasValue is Call getHasValueCall) || !getHasValueCall.Method.IsAccessor || getHasValueCall.Method.FullName != "System.Nullable.get_HasValue" ||
getHasValueCall.Method.DeclaringType.TypeParameterCount != 1)
if (!NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILInstruction getHasValueArg))
return false;
if (getHasValueCall.Arguments.Count != 1 || getValueOrDefaultCall.Arguments.Count != 1)
return false;
if (!getHasValueCall.Arguments[0].MatchLdLoc(tmp) || !getValueOrDefaultCall.Arguments[0].MatchLdLoc(tmp))
if (!(getHasValueArg.MatchLdLoc(tmp) && getValueOrDefaultArg.MatchLdLoc(tmp)))
return false;
// match second block: switchBlock
// switch (ldloc switchVariable) {
@ -112,22 +108,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -112,22 +108,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!(switchBlock.Instructions[0] is SwitchInstruction switchInst))
return false;
newSwitch = new SwitchInstruction(new LdLoc(switchValueVar));
newSwitch.IsLifted = true;
SwitchSection defaultSection = null;
foreach (var section in switchInst.Sections) {
if (defaultSection == null || section.Labels.Count() >= defaultSection.Labels.Count())
defaultSection = section;
newSwitch.Sections.Add(section);
}
if (defaultSection.Body.MatchBranch(out var defaultBlock) && defaultBlock == nullCaseBlock)
defaultSection.HasNullLabel = true;
else {
newSwitch.Sections.Add(new SwitchSection { Body = new Branch(nullCaseBlock), HasNullLabel = true });
}
newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, new LdLoc(switchValueVar));
return true;
}
static SwitchInstruction BuildLiftedSwitch(Block nullCaseBlock, SwitchInstruction switchInst, ILInstruction switchValue)
{
SwitchInstruction newSwitch = new SwitchInstruction(switchValue);
newSwitch.IsLifted = true;
newSwitch.Sections.AddRange(switchInst.Sections);
newSwitch.Sections.Add(new SwitchSection { Body = new Branch(nullCaseBlock), HasNullLabel = true });
return newSwitch;
}
/// <summary>
/// Matches Roslyn C# switch on nullable.
/// </summary>
@ -142,11 +135,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -142,11 +135,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!instructions[i - 1].MatchStLoc(out var tmp, out var switchValue) ||
!instructions[i].MatchIfInstruction(out var condition, out var trueInst))
return false;
if (tmp.StoreCount != 1 || tmp.AddressCount != 2)
if (tmp.StoreCount != 1 || tmp.AddressCount != 2 || tmp.LoadCount != 0)
return false;
if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock))
return false;
if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out var target1) || target1 != tmp)
if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILVariable target1) || target1 != tmp)
return false;
// match second block: switchBlock
// stloc switchVar(call GetValueOrDefault(ldloca tmp))
@ -161,23 +154,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -161,23 +154,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!switchVar.IsSingleDefinition || switchVar.LoadCount != 1)
return false;
if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out var target2) || target2 != tmp)
if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, tmp))
return false;
if (!(switchBlock.Instructions[1] is SwitchInstruction switchInst))
return false;
newSwitch = new SwitchInstruction(switchValue);
newSwitch.IsLifted = true;
SwitchSection defaultSection = null;
foreach (var section in switchInst.Sections) {
if (defaultSection == null || section.Labels.Count() >= defaultSection.Labels.Count())
defaultSection = section;
newSwitch.Sections.Add(section);
}
if (defaultSection.Body.MatchBranch(out var defaultBlock) && defaultBlock == nullCaseBlock)
defaultSection.HasNullLabel = true;
else {
newSwitch.Sections.Add(new SwitchSection { Body = new Branch(nullCaseBlock), HasNullLabel = true });
}
newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, switchValue);
return true;
}
}

2
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (objVar.Type.IsKnownType(KnownTypeCode.NullableOfT)) {
if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst))
return false;
if (!(NullableLiftingTransform.MatchHasValueCall(condition, out var v) && v == objVar))
if (!NullableLiftingTransform.MatchHasValueCall(condition, objVar))
return false;
if (!(disposeInst is Block disposeBlock) || disposeBlock.Instructions.Count != 1)
return false;

Loading…
Cancel
Save