From 411457c4c7a92a011900a9832f99a51fbc016914 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 12 Nov 2020 22:28:34 +0100 Subject: [PATCH] #1240: Add support for Unsafe comparison intrinsics: `AreSame`, `IsAddressLessThan`, `IsAddressGreaterThan` --- .../TestCases/ILPretty/Unsafe.cs | 6 ++-- .../CSharp/ExpressionBuilder.cs | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs index b41a57146..a0a33c755 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs @@ -389,19 +389,19 @@ namespace System.Runtime.CompilerServices [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AreSame(ref T left, ref T right) { - return (ref left) == (ref right); + return Unsafe.AreSame(ref left, ref right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsAddressGreaterThan(ref T left, ref T right) { - return (ref left) > (ref right); + return Unsafe.IsAddressGreaterThan(ref left, ref right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsAddressLessThan(ref T left, ref T right) { - return (ref left) < (ref right); + return Unsafe.IsAddressLessThan(ref left, ref right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 3f8f3867a..a7f24f423 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -786,6 +786,41 @@ namespace ICSharpCode.Decompiler.CSharp } return ErrorExpression("Nullable comparisons with three-valued-logic not supported in C#"); } + if (inst.InputType == StackType.Ref) + { + // Reference comparison using Unsafe intrinsics + Debug.Assert(!inst.IsLifted); + (string methodName, bool negate) = inst.Kind switch { + ComparisonKind.Equality => ("AreSame", false), + ComparisonKind.Inequality => ("AreSame", true), + ComparisonKind.LessThan => ("IsAddressLessThan", false), + ComparisonKind.LessThanOrEqual => ("IsAddressGreaterThan", true), + ComparisonKind.GreaterThan => ("IsAddressGreaterThan", false), + ComparisonKind.GreaterThanOrEqual => ("IsAddressLessThan", true), + _ => throw new InvalidOperationException("Invalid ComparisonKind") + }; + var left = Translate(inst.Left); + var right = Translate(inst.Right); + if (left.Type.Kind != TypeKind.ByReference || !NormalizeTypeVisitor.TypeErasure.EquivalentTypes(left.Type, right.Type)) + { + IType commonRefType = new ByReferenceType(compilation.FindType(KnownTypeCode.Byte)); + left = left.ConvertTo(commonRefType, this); + right = right.ConvertTo(commonRefType, this); + } + IType boolType = compilation.FindType(KnownTypeCode.Boolean); + TranslatedExpression expr = CallUnsafeIntrinsic( + name: methodName, + arguments: new Expression[] { left, right }, + returnType: boolType, + inst: inst + ); + if (negate) + { + expr = new UnaryOperatorExpression(UnaryOperatorType.Not, expr) + .WithoutILInstruction().WithRR(new ResolveResult(boolType)); + } + return expr; + } if (inst.Kind.IsEqualityOrInequality()) { var result = TranslateCeq(inst, out bool negateOutput);