Browse Source

NullableLiftingTransform: Undo new compiler optimization (omitting get_HasValue for comparisions with constants)

pull/3243/head
Siegfried Pammer 10 months ago
parent
commit
9d22e3ab41
  1. 14
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 11
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  3. 4
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  4. 27
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

14
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -373,6 +373,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -373,6 +373,20 @@ namespace ICSharpCode.Decompiler.CSharp
return HandleImplicitConversion(method, argumentList.Arguments[0]);
}
if (settings.LiftNullables && method.Name == "GetValueOrDefault"
&& method.DeclaringType.IsKnownType(KnownTypeCode.NullableOfT)
&& method.DeclaringType.TypeArguments[0].IsKnownType(KnownTypeCode.Boolean)
&& argumentList.Length == 0)
{
argumentList.CheckNoNamedOrOptionalArguments();
return new BinaryOperatorExpression(
target.Expression,
BinaryOperatorType.Equality,
new PrimitiveExpression(true))
.WithRR(new CSharpInvocationResolveResult(target.ResolveResult, method,
argumentList.GetArgumentResolveResults(), isExpandedForm: argumentList.IsExpandedForm));
}
var transform = GetRequiredTransformationsForCall(expectedTargetDetails, method, ref target,
ref argumentList, CallTransformation.All, out IParameterizedMember foundMethod);

11
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -1167,6 +1167,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1167,6 +1167,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
return base.VisitBinaryOperatorExpression(expr);
}
public override AstNode VisitUnaryOperatorExpression(UnaryOperatorExpression expr)
{
if (expr.Operator == UnaryOperatorType.Not && expr.Expression is BinaryOperatorExpression { Operator: BinaryOperatorType.Equality } binary)
{
binary.Operator = BinaryOperatorType.InEquality;
expr.ReplaceWith(binary.Detach());
return VisitBinaryOperatorExpression(binary);
}
return base.VisitUnaryOperatorExpression(expr);
}
#endregion
#region C# 7.3 pattern based fixed (for value types)

4
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -96,8 +96,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -96,8 +96,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
}
else if (inst.Kind == ComparisonKind.Inequality && inst.LiftingKind == ComparisonLiftingKind.None
&& inst.Right.MatchLdcI4(0) && (IfInstruction.IsInConditionSlot(inst) || inst.Left is Comp)
)
&& inst.Right.MatchLdcI4(0) && (IfInstruction.IsInConditionSlot(inst) || inst.Left is Comp))
{
// if (comp(x != 0)) ==> if (x)
// comp(comp(...) != 0) => comp(...)
@ -107,6 +106,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -107,6 +106,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst.Left.AcceptVisitor(this);
return;
}
new NullableLiftingTransform(context).Run(inst);
base.VisitComp(inst);
if (inst.IsLifted)

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

@ -85,6 +85,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -85,6 +85,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
/// <summary>
/// VS2022.10 / Roslyn 4.10.0 adds an optimization that turns
/// a == 42 into a.GetValueOrDefault() == 42 without any HasValue check.
/// </summary>
public void Run(Comp comp)
{
if (!comp.IsLifted && comp.Kind.IsEqualityOrInequality())
{
var left = comp.Left;
var right = comp.Right;
if (MatchGetValueOrDefault(left, out ILInstruction arg)
&& right.MatchLdcI(out var value) && value != 0)
{
context.Step("comp(a.GetValueOrDefault() == const) -> comp.lifted(a == const)", comp);
comp.LiftingKind = ComparisonLiftingKind.CSharp;
comp.Left = new LdObj(arg, ((Call)left).Method.DeclaringType);
}
else if (MatchGetValueOrDefault(right, out arg)
&& left.MatchLdcI(out value) && value != 0)
{
context.Step("comp(const == a.GetValueOrDefault()) -> comp.lifted(const == a)", comp);
comp.LiftingKind = ComparisonLiftingKind.CSharp;
comp.Right = new LdObj(arg, ((Call)right).Method.DeclaringType);
}
}
}
public bool RunStatements(Block block, int pos)
{
// e.g.:

Loading…
Cancel
Save