Skip to content

Commit

Permalink
NullableLiftingTransform: Undo new compiler optimization (omitting ge…
Browse files Browse the repository at this point in the history
…t_HasValue for comparisions with constants)
siegfriedpammer committed Jul 20, 2024
1 parent cf5f100 commit 9d22e3a
Showing 4 changed files with 54 additions and 2 deletions.
14 changes: 14 additions & 0 deletions ICSharpCode.Decompiler/CSharp/CallBuilder.cs
Original file line number Diff line number Diff line change
@@ -373,6 +373,20 @@ public ExpressionWithResolveResult Build(OpCode callOpCode, IMethod method,
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);

Original file line number Diff line number Diff line change
@@ -1167,6 +1167,17 @@ public override AstNode VisitBinaryOperatorExpression(BinaryOperatorExpression e
}
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 changes: 2 additions & 2 deletions ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
Original file line number Diff line number Diff line change
@@ -96,8 +96,7 @@ protected internal override void VisitComp(Comp inst)
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 @@ protected internal override void VisitComp(Comp inst)
inst.Left.AcceptVisitor(this);
return;
}
new NullableLiftingTransform(context).Run(inst);

base.VisitComp(inst);
if (inst.IsLifted)
27 changes: 27 additions & 0 deletions ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
Original file line number Diff line number Diff line change
@@ -85,6 +85,33 @@ public bool Run(BinaryNumericInstruction bni)
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.:

0 comments on commit 9d22e3a

Please sign in to comment.