diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs index 1fc80f847..8f0aa9432 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs @@ -16,8 +16,7 @@ namespace Issue3465 private static bool Test3465() { Program program = GetProgram(); - Program program2 = programNull; - return System.Runtime.CompilerServices.Unsafe.As(ref program) > System.Runtime.CompilerServices.Unsafe.As(ref program2); + return System.Runtime.CompilerServices.Unsafe.As(ref program) > System.Runtime.CompilerServices.Unsafe.As(ref programNull); } } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index a741ed160..4fb99a4c9 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1112,7 +1112,7 @@ namespace ICSharpCode.Decompiler.CSharp { // Unsafe.As(ref left) op Unsafe.As(ref right) // TTo Unsafe.As(ref TFrom source) - var uintptr = compilation.FindType(KnownTypeCode.UIntPtr); + var integerType = compilation.FindType(inst.Sign == Sign.Signed ? KnownTypeCode.IntPtr : KnownTypeCode.UIntPtr); left = WrapInUnsafeAs(left, inst.Left); right = WrapInUnsafeAs(right, inst.Right); @@ -1120,7 +1120,7 @@ namespace ICSharpCode.Decompiler.CSharp { var type = expr.Type; expr = WrapInRef(expr, new ByReferenceType(type)); - return CallUnsafeIntrinsic("As", [expr], uintptr, typeArguments: [type, uintptr]); + return CallUnsafeIntrinsic("As", [expr], integerType, typeArguments: [type, integerType]); } } return new BinaryOperatorExpression(left.Expression, op, right.Expression) diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 7cba9c60f..5f5e45528 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -1248,11 +1248,14 @@ namespace ICSharpCode.Decompiler.IL } } - StackType PeekStackType(int i = 0) + StackType PeekStackType() { - if (expressionStack.Count > i) - return expressionStack[^(i + 1)].ResultType; - return currentStack.Skip(i).FirstOrDefault()?.StackType ?? StackType.Unknown; + if (expressionStack.Count > 0) + return expressionStack.Last().ResultType; + if (currentStack.IsEmpty) + return StackType.Unknown; + else + return currentStack.Peek().StackType; } sealed class CollectStackVariablesVisitor : ILVisitor @@ -1842,8 +1845,7 @@ namespace ICSharpCode.Decompiler.IL ILInstruction Comparison(ComparisonKind kind, bool un = false) { - var stackType = PeekStackType(); - if (!kind.IsEqualityOrInequality() && stackType == StackType.O && stackType == PeekStackType(1)) + if (!kind.IsEqualityOrInequality() && PeekStackType() == StackType.O) { FlushExpressionStack(); } diff --git a/ICSharpCode.Decompiler/IL/Instructions/Comp.cs b/ICSharpCode.Decompiler/IL/Instructions/Comp.cs index b5ce1aed5..26c482c57 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Comp.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Comp.cs @@ -235,7 +235,23 @@ namespace ICSharpCode.Decompiler.IL // ExpressionBuilder translates comp.o(a op b) for op not in (==, !=) into // Unsafe.As(ref a) op Unsafe.As(ref b), which requires that a and b are variables // and not expressions. Returning false in those cases prevents inlining. - return kind.IsEqualityOrInequality() || this.InputType != StackType.O; + // However if one of the arguments is LdNull, then we don't need the Unsafe.As trickery, and can always inline. + if (kind.IsEqualityOrInequality() || this.InputType != StackType.O) + { + // OK, won't need Unsafe.As. + return true; + } + if (expressionBeingMoved is LdLoc || expressionBeingMoved.MatchLdsFld(out _)) + { + // OK, can use variable/field name with Unsafe.As(ref x) + return true; + } + if (Sign != Sign.Signed && (expressionBeingMoved is LdNull || Left is LdNull || Right is LdNull)) + { + // OK, this is the "compare with null" special case that doesn't need Unsafe.As() + return true; + } + return false; } } }