From 65eba1d96205e9d29e464ff2e7c0e50d8fefacf0 Mon Sep 17 00:00:00 2001 From: Hamish Arblaster Date: Fri, 18 Jul 2025 12:48:56 +1000 Subject: [PATCH 1/6] Implement Unsafe. IsAddressLessThanOrEqualTo & Unsafe.IsAddressGreaterThanOrEqualTo Copied from https://github.com/dotnet/runtime/pull/89156 (@stephentoub wrote it), but without mono intrinsicification --- .../vectorization-guidelines.md | 18 +++---- src/coreclr/jit/fgbasic.cpp | 4 ++ src/coreclr/jit/importercalls.cpp | 46 ++++++++++++++++ src/coreclr/jit/namedintrinsiclist.h | 2 + .../TypeSystem/IL/Stubs/UnsafeIntrinsics.cs | 16 ++++++ src/coreclr/vm/corelib.h | 2 + src/coreclr/vm/jitinterface.cpp | 38 +++++++++++++- .../Frozen/FrozenFromKnownValuesTests.cs | 6 +-- .../System.Linq/src/System/Linq/Range.cs | 2 +- .../Collections/Generic/ArraySortHelper.cs | 2 +- .../System/Runtime/CompilerServices/Unsafe.cs | 52 +++++++++++++++++++ .../SearchValues/IndexOfAnyAsciiSearcher.cs | 24 ++++----- .../System/SearchValues/ProbabilisticMap.cs | 6 +-- .../SearchValues/Strings/Helpers/RabinKarp.cs | 2 +- .../src/System/SpanHelpers.Packed.cs | 30 +++++------ .../src/System/SpanHelpers.T.cs | 36 ++++++------- .../src/System/Text/Ascii.Equality.cs | 12 ++--- .../System.Runtime/ref/System.Runtime.cs | 2 + .../UnsafeTests.cs | 38 ++++++++++++++ 19 files changed, 267 insertions(+), 71 deletions(-) diff --git a/docs/coding-guidelines/vectorization-guidelines.md b/docs/coding-guidelines/vectorization-guidelines.md index ab85676263afd6..f8fa0479353c26 100644 --- a/docs/coding-guidelines/vectorization-guidelines.md +++ b/docs/coding-guidelines/vectorization-guidelines.md @@ -161,15 +161,15 @@ To reduce the number of comparisons for small inputs, we can re-arrange it in th void OptimalCodeStructure(ReadOnlySpan buffer) { if (!Vector128.IsHardwareAccelerated || buffer.Length < Vector128.Count) - { + { // scalar code path - } + } else if (!Vector256.IsHardwareAccelerated || buffer.Length < Vector256.Count) - { + { // Vector128 code path - } + } else - { + { // Vector256 code path } } @@ -523,7 +523,7 @@ int ManagedReferencesSum(int[] buffer) Vector128 sum = Vector128.Zero; - while (!Unsafe.IsAddressGreaterThan(ref current, ref oneVectorAwayFromEnd)) + while (Unsafe.IsAddressLessThanOrEqualTo(ref current, ref oneVectorAwayFromEnd)) { sum += Vector128.LoadUnsafe(ref current); @@ -561,7 +561,7 @@ do return ...; } -while (!Unsafe.IsAddressLessThan(ref currentSearchSpace, ref searchSpace)); +while (Unsafe.IsAddressGreaterThanOrEqualTo(ref currentSearchSpace, ref searchSpace)); ``` It was part of `LastIndexOf` implementation, where we were iterating from the end to the beginning of the buffer. In the last iteration of the loop, `currentSearchSpace` could become a pointer to unknown memory that lied before the beginning of the buffer: @@ -573,7 +573,7 @@ currentSearchSpace = ref Unsafe.Subtract(ref currentSearchSpace, Vector128(ref T searchSpace, ref T current, Vector128 e uint mostSignificantBits = equals.ExtractMostSignificantBits(); int index = BitOperations.TrailingZeroCount(mostSignificantBits); - + return elementOffset + index; } ``` diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 4fa17a9c6c8207..bf9f3070d7a744 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1301,7 +1301,9 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed case NI_SRCS_UNSAFE_AreSame: case NI_SRCS_UNSAFE_ByteOffset: case NI_SRCS_UNSAFE_IsAddressGreaterThan: + case NI_SRCS_UNSAFE_IsAddressGreaterThanOrEqualTo: case NI_SRCS_UNSAFE_IsAddressLessThan: + case NI_SRCS_UNSAFE_IsAddressLessThanOrEqualTo: case NI_SRCS_UNSAFE_IsNullRef: case NI_SRCS_UNSAFE_Subtract: case NI_SRCS_UNSAFE_SubtractByteOffset: @@ -1316,7 +1318,9 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed { case NI_SRCS_UNSAFE_AreSame: case NI_SRCS_UNSAFE_IsAddressGreaterThan: + case NI_SRCS_UNSAFE_IsAddressGreaterThanOrEqualTo: case NI_SRCS_UNSAFE_IsAddressLessThan: + case NI_SRCS_UNSAFE_IsAddressLessThanOrEqualTo: case NI_SRCS_UNSAFE_IsNullRef: { fgObserveInlineConstants(opcode, pushedStack, isInlining); diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index cbdb15e9a63d9d..ba4ac99f4a89ef 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -5491,6 +5491,25 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, return gtFoldExpr(tmp); } + case NI_SRCS_UNSAFE_IsAddressGreaterThanOrEqualTo: + { + assert(sig->sigInst.methInstCount == 1); + + // ldarg.0 + // ldarg.1 + // clt.un + // ldc.i4.0 + // ceq + // ret + + GenTree* op2 = impPopStack().val; + GenTree* op1 = impPopStack().val; + + GenTree* tmp = gtNewOperNode(GT_GE, TYP_INT, op1, op2); + tmp->gtFlags |= GTF_UNSIGNED; + return gtFoldExpr(tmp); + } + case NI_SRCS_UNSAFE_IsAddressLessThan: { assert(sig->sigInst.methInstCount == 1); @@ -5508,6 +5527,25 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, return gtFoldExpr(tmp); } + case NI_SRCS_UNSAFE_IsAddressLessThanOrEqualTo: + { + assert(sig->sigInst.methInstCount == 1); + + // ldarg.0 + // ldarg.1 + // cgt.un + // ldc.i4.0 + // ceq + // ret + + GenTree* op2 = impPopStack().val; + GenTree* op1 = impPopStack().val; + + GenTree* tmp = gtNewOperNode(GT_LE, TYP_INT, op1, op2); + tmp->gtFlags |= GTF_UNSIGNED; + return gtFoldExpr(tmp); + } + case NI_SRCS_UNSAFE_IsNullRef: { assert(sig->sigInst.methInstCount == 1); @@ -10703,10 +10741,18 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_SRCS_UNSAFE_IsAddressGreaterThan; } + else if (strcmp(methodName, "IsAddressGreaterThanOrEqualTo") == 0) + { + result = NI_SRCS_UNSAFE_IsAddressGreaterThanOrEqualTo; + } else if (strcmp(methodName, "IsAddressLessThan") == 0) { result = NI_SRCS_UNSAFE_IsAddressLessThan; } + else if (strcmp(methodName, "IsAddressLessThanOrEqualTo") == 0) + { + result = NI_SRCS_UNSAFE_IsAddressLessThanOrEqualTo; + } else if (strcmp(methodName, "IsNullRef") == 0) { result = NI_SRCS_UNSAFE_IsNullRef; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 71a7124e0974ac..aa56003f25acc1 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -221,7 +221,9 @@ enum NamedIntrinsic : unsigned short NI_SRCS_UNSAFE_InitBlock, NI_SRCS_UNSAFE_InitBlockUnaligned, NI_SRCS_UNSAFE_IsAddressGreaterThan, + NI_SRCS_UNSAFE_IsAddressGreaterThanOrEqualTo, NI_SRCS_UNSAFE_IsAddressLessThan, + NI_SRCS_UNSAFE_IsAddressLessThanOrEqualTo, NI_SRCS_UNSAFE_IsNullRef, NI_SRCS_UNSAFE_NullRef, NI_SRCS_UNSAFE_Read, diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs index 2b90323728049f..334206020e63cf 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs @@ -59,12 +59,28 @@ public static MethodIL EmitIL(MethodDesc method) (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsAddressGreaterThanOrEqualTo": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), + (byte)ILOpcode.ldc_i4_0, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), + (byte)ILOpcode.ret }, Array.Empty(), null); case "IsAddressLessThan": return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsAddressLessThanOrEqualTo": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), + (byte)ILOpcode.ldc_i4_0, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), + (byte)ILOpcode.ret }, Array.Empty(), null); case "ByteOffset": return new ILStubMethodIL(method, new byte[] { diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 16cd41fd7e90f4..5a1a44151e2d27 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -773,7 +773,9 @@ DEFINE_METHOD(UNSAFE, BYREF_COPY_BLOCK, CopyBlock, SM_RefByt DEFINE_METHOD(UNSAFE, PTR_COPY_BLOCK_UNALIGNED, CopyBlockUnaligned, SM_PtrVoid_PtrVoid_UInt_RetVoid) DEFINE_METHOD(UNSAFE, BYREF_COPY_BLOCK_UNALIGNED, CopyBlockUnaligned, SM_RefByte_RefByte_UInt_RetVoid) DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_GREATER_THAN, IsAddressGreaterThan, NoSig) +DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_GREATER_THAN_OR_EQUAL_TO, IsAddressGreaterThanOrEqualTo, NoSig) DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_LESS_THAN, IsAddressLessThan, NoSig) +DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_LESS_THAN_OR_EQUAL_TO, IsAddressLessThanOrEqualTo, NoSig) DEFINE_METHOD(UNSAFE, BYREF_INIT_BLOCK, InitBlockUnaligned, SM_RefByte_Byte_UInt_RetVoid) DEFINE_METHOD(UNSAFE, PTR_INIT_BLOCK, InitBlock, SM_PtrVoid_Byte_UInt_RetVoid) DEFINE_METHOD(UNSAFE, BYREF_INIT_BLOCK_UNALIGNED, InitBlock, SM_RefByte_Byte_UInt_RetVoid) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 7e818028899d9f..1a7f67e5f0888b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6894,6 +6894,23 @@ static bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn, return true; } + else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN_OR_EQUAL_TO)->GetMemberDef()) + { + // Compare the two arguments + static const BYTE ilcode[] = + { + CEE_LDARG_0, + CEE_LDARG_1, + CEE_PREFIX1, (CEE_CLT_UN & 0xFF), + CEE_LDC_I4_0, + CEE_PREFIX1, (CEE_CEQ & 0xFF), + CEE_RET + }; + + setILIntrinsicMethodInfo(methInfo,const_cast(ilcode),sizeof(ilcode), 2); + + return true; + } else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef()) { // Compare the two arguments @@ -6909,6 +6926,23 @@ static bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn, return true; } + else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN_OR_EQUAL_TO)->GetMemberDef()) + { + // Compare the two arguments + static const BYTE ilcode[] = + { + CEE_LDARG_0, + CEE_LDARG_1, + CEE_PREFIX1, (CEE_CGT_UN & 0xFF), + CEE_LDC_I4_0, + CEE_PREFIX1, (CEE_CEQ & 0xFF), + CEE_RET + }; + + setILIntrinsicMethodInfo(methInfo,const_cast(ilcode),sizeof(ilcode), 2); + + return true; + } else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_NULLREF)->GetMemberDef()) { static const BYTE ilcode[] = @@ -8663,7 +8697,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) else if (pObjMT->IsSharedByGenericInstantiations() || pBaseMT->IsSharedByGenericInstantiations()) { MethodTable* pCanonBaseMT = pBaseMT->GetCanonicalMethodTable(); - + // Check to see if the derived class implements multiple variants of a matching interface. // If so, we cannot predict exactly which implementation is in use here. MethodTable::InterfaceMapIterator it = pObjMT->IterateInterfaceMap(); @@ -8686,7 +8720,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) } } } - + if (canonicallyMatchingInterfacesFound == 0) { // The object doesn't implement the interface... diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs index dc4e2b9e89dbee..7d026a9ef4d813 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs @@ -117,8 +117,8 @@ public static IEnumerable StringStringData() => new[] { "AsPointer", "As", "AsRef", "Add", "AddByteOffset", "Copy", "CopyBlock", "CopyBlockUnaligned", "InitBlock", "InitBlockUnaligned", "Read", "Write", - "ReadUnaligned", "WriteUnaligned", "AreSame", "IsAddressGreaterThan", "IsAddressLessThan", "ByteOffset", "NullRef", "IsNullRef", "SkipInit", - "Subtract", "SubtractByteOffset", "Unbox", + "ReadUnaligned", "WriteUnaligned", "AreSame", "IsAddressGreaterThan", "IsAddressGreaterThanOrEqualTo", "IsAddressLessThan", "IsAddressLessThanOrEqualTo", + "ByteOffset", "NullRef", "IsNullRef", "SkipInit", "Subtract", "SubtractByteOffset", "Unbox", }, // from https://raw.githubusercontent.com/dotnet/roslyn/0456b4adc6939e366e7c509318b3ac6a85cda496/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenLengthBasedSwitchTests.cs @@ -153,7 +153,7 @@ public static IEnumerable StringStringData() => Enumerable.Range(0, 100).Select(i => $"{i:D2}ABCDEFGH\U0001F600").ToArray(), // left justified substring non-ascii Enumerable.Range(0, 100).Select(i => $"ABCDEFGH\U0001F600{i:D2}").ToArray(), // right justified substring non-ascii Enumerable.Range(0, 20).Select(i => i.ToString("D2")).Select(s => (char)(s[0] + 128) + "" + (char)(s[1] + 128)).ToArray(), // left-justified non-ascii - + Enumerable.Range(0, 10).Select(i => $"{i}ABCDefgh").ToArray(), // left justified single char ascii, mixed casing Enumerable.Range(0, 10).Select(i => $"ABCDefgh{i}").ToArray(), // right justified single char ascii, mixed casing Enumerable.Range(0, 100).Select(i => $"{i:D2}ABCDefgh").ToArray(), // left justified substring ascii, mixed casing diff --git a/src/libraries/System.Linq/src/System/Linq/Range.cs b/src/libraries/System.Linq/src/System/Linq/Range.cs index 24da4789b1cb5b..7c5bae3f395e80 100644 --- a/src/libraries/System.Linq/src/System/Linq/Range.cs +++ b/src/libraries/System.Linq/src/System/Linq/Range.cs @@ -97,7 +97,7 @@ private static void FillIncrementing(Span destination, T value) where T : current += increment; pos = ref Unsafe.Add(ref pos, Vector.Count); } - while (!Unsafe.IsAddressGreaterThan(ref pos, ref oneVectorFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref pos, ref oneVectorFromEnd)); value = current[0]; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs index 9c336d924c75d8..eb4c3828cd930e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs @@ -487,7 +487,7 @@ private static unsafe int PickPivotAndPartition(Span keys) while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && LessThan(ref pivot, ref rightRef = ref Unsafe.Add(ref rightRef, -1))) ; } - if (!Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) + if (Unsafe.IsAddressGreaterThanOrEqualTo(ref leftRef, ref rightRef)) { break; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 3d97a654124205..12362e0ff615c3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -404,6 +404,32 @@ public static bool IsAddressGreaterThan([AllowNull] ref readonly T left, [All // ret } + /// + /// Determines whether the memory address referenced by is greater than + /// or equal to the memory address referenced by . + /// + /// + /// This check is conceptually similar to "(void*)(&left) >= (void*)(&right)". + /// + [Intrinsic] + // CoreCLR:CoreCLR:METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN_OR_EQUAL_TO + // AOT:IsAddressGreaterThanOrEqualTo + // Mono:IsAddressGreaterThanOrEqualTo + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsAddressGreaterThanOrEqualTo([AllowNull] ref readonly T left, [AllowNull] ref readonly T right) + where T : allows ref struct + { + return !IsAddressLessThan(in left, in right); + + // ldarg.0 + // ldarg.1 + // clt.un + // ldc.i4.0 + // ceq + // ret + } + /// /// Determines whether the memory address referenced by is less than /// the memory address referenced by . @@ -428,6 +454,32 @@ public static bool IsAddressLessThan([AllowNull] ref readonly T left, [AllowN // ret } + /// + /// Determines whether the memory address referenced by is less than + /// or equal to the memory address referenced by . + /// + /// + /// This check is conceptually similar to "(void*)(&left) <= (void*)(&right)". + /// + [Intrinsic] + // CoreCLR:METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN_OR_EQUAL_TO + // AOT:IsAddressLessThanOrEqualTo + // Mono:IsAddressLessThanOrEqualTo + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsAddressLessThanOrEqualTo([AllowNull] ref readonly T left, [AllowNull] ref readonly T right) + where T : allows ref struct + { + return !IsAddressGreaterThan(in left, in right); + + // ldarg.0 + // ldarg.1 + // cgt.un + // ldc.i4.0 + // ceq + // ret + } + /// /// Initializes a block of memory at the given location with a given initial value. /// diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs index 7f8393f483179e..3808fb037410c9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs @@ -321,7 +321,7 @@ private static TResult IndexOfAnyCores into a Vector256 is cheap compared to the lookup, we can effectively double the throughput. // If the input length is a multiple of 32, don't consume the last 32 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength - (2 * Vector256.Count)); do @@ -374,7 +374,7 @@ private static TResult IndexOfAnyCores into a Vector128 is cheap compared to the lookup, we can effectively double the throughput. // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength - (2 * Vector128.Count)); do @@ -453,7 +453,7 @@ public static int LastIndexOfAny(ref // As packing two Vector256s into a Vector256 is cheap compared to the lookup, we can effectively double the throughput. // If the input length is a multiple of 32, don't consume the last 32 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "!IsAddressLessThan". + // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "IsAddressGreaterThanOrEqualTo". ref short twoVectorsAfterStart = ref Unsafe.Add(ref searchSpace, 2 * Vector256.Count); do @@ -504,7 +504,7 @@ public static int LastIndexOfAny(ref // As packing two Vector128s into a Vector128 is cheap compared to the lookup, we can effectively double the throughput. // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "!IsAddressLessThan". + // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "IsAddressGreaterThanOrEqualTo". ref short twoVectorsAfterStart = ref Unsafe.Add(ref searchSpace, 2 * Vector128.Count); do @@ -604,7 +604,7 @@ private static TResult IndexOfAnyCore" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref byte vectorAwayFromEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength - Vector256.Count); do @@ -653,7 +653,7 @@ private static TResult IndexOfAnyCore" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref byte vectorAwayFromEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength - Vector128.Count); do @@ -729,7 +729,7 @@ public static int LastIndexOfAny(ref byte searchSpac // Process the input in chunks of 32 bytes. // If the input length is a multiple of 32, don't consume the last 32 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "!IsAddressLessThan". + // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "IsAddressGreaterThanOrEqualTo". ref byte vectorAfterStart = ref Unsafe.Add(ref searchSpace, Vector256.Count); do @@ -778,7 +778,7 @@ public static int LastIndexOfAny(ref byte searchSpac // Process the input in chunks of 16 bytes. // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "!IsAddressLessThan". + // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "IsAddressGreaterThanOrEqualTo". ref byte vectorAfterStart = ref Unsafe.Add(ref searchSpace, Vector128.Count); do @@ -876,7 +876,7 @@ private static TResult IndexOfAnyCore(ref byte // Process the input in chunks of 32 bytes. // If the input length is a multiple of 32, don't consume the last 32 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref byte vectorAwayFromEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength - Vector256.Count); do @@ -928,7 +928,7 @@ private static TResult IndexOfAnyCore(ref byte // Process the input in chunks of 16 bytes. // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref byte vectorAwayFromEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength - Vector128.Count); do @@ -1004,7 +1004,7 @@ public static int LastIndexOfAny(ref byte searchSpace, int searchSpace // Process the input in chunks of 32 bytes. // If the input length is a multiple of 32, don't consume the last 32 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "!IsAddressLessThan". + // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "IsAddressGreaterThanOrEqualTo". ref byte vectorAfterStart = ref Unsafe.Add(ref searchSpace, Vector256.Count); do @@ -1056,7 +1056,7 @@ public static int LastIndexOfAny(ref byte searchSpace, int searchSpace // Process the input in chunks of 16 bytes. // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "!IsAddressLessThan". + // ">" instead of ">=" above, and why "IsAddressGreaterThan" is used instead of "IsAddressGreaterThanOrEqualTo". ref byte vectorAfterStart = ref Unsafe.Add(ref searchSpace, Vector128.Count); do diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs index 9a4e3dd0b735b2..0b09377b503e17 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs @@ -626,7 +626,7 @@ private static int LastIndexOfAnyVectorizedAvx512(ref char sea } } - if (!Unsafe.IsAddressGreaterThan(ref cur, ref lastStartVector)) + if (Unsafe.IsAddressLessThanOrEqualTo(ref cur, ref lastStartVector)) { if (Unsafe.AreSame(ref cur, ref searchSpace)) { @@ -715,7 +715,7 @@ private static int LastIndexOfAnyVectorized(ref char searchSpa } } - if (!Unsafe.IsAddressGreaterThan(ref cur, ref lastStartVectorAvx2)) + if (Unsafe.IsAddressLessThanOrEqualTo(ref cur, ref lastStartVectorAvx2)) { if (Unsafe.AreSame(ref cur, ref searchSpace)) { @@ -757,7 +757,7 @@ private static int LastIndexOfAnyVectorized(ref char searchSpa } } - if (!Unsafe.IsAddressGreaterThan(ref cur, ref lastStartVector)) + if (Unsafe.IsAddressLessThanOrEqualTo(ref cur, ref lastStartVector)) { if (Unsafe.AreSame(ref cur, ref searchSpace)) { diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/RabinKarp.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/RabinKarp.cs index d8970655cb31b7..086061ffe01641 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/RabinKarp.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/RabinKarp.cs @@ -142,7 +142,7 @@ private readonly int IndexOfAnyCore(ReadOnlySpan span) } } - if (!Unsafe.IsAddressLessThan(ref current, ref end)) + if (Unsafe.IsAddressGreaterThanOrEqualTo(ref current, ref end)) { break; } diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs index 52eb1b0b2bedce..70f03605d66a32 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs @@ -156,7 +156,7 @@ public static bool Contains(ref short searchSpace, short value, int length) // Process the input in chunks of 64 characters (2 * Vector512). // If the input length is a multiple of 64, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector512.Count)); do @@ -205,7 +205,7 @@ public static bool Contains(ref short searchSpace, short value, int length) // Process the input in chunks of 32 characters (2 * Vector256). // If the input length is a multiple of 32, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector256.Count)); do @@ -263,7 +263,7 @@ public static bool Contains(ref short searchSpace, short value, int length) // Process the input in chunks of 16 characters (2 * Vector128). // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector128.Count)); do @@ -355,7 +355,7 @@ private static int IndexOf(ref short searchSpace, short va // Process the input in chunks of 64 characters (2 * Vector512). // If the input length is a multiple of 64, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector512.Count)); do @@ -404,7 +404,7 @@ private static int IndexOf(ref short searchSpace, short va // Process the input in chunks of 32 characters (2 * Vector256). // If the input length is a multiple of 32, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector256.Count)); do @@ -464,7 +464,7 @@ private static int IndexOf(ref short searchSpace, short va // Process the input in chunks of 16 characters (2 * Vector128). // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector128.Count)); do @@ -565,7 +565,7 @@ private static int IndexOfAny(ref short searchSpace, short // Process the input in chunks of 64 characters (2 * Vector512). // If the input length is a multiple of 64, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector512.Count)); do @@ -617,7 +617,7 @@ private static int IndexOfAny(ref short searchSpace, short // Process the input in chunks of 32 characters (2 * Vector256). // If the input length is a multiple of 32, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector256.Count)); do @@ -678,7 +678,7 @@ private static int IndexOfAny(ref short searchSpace, short // Process the input in chunks of 16 characters (2 * Vector128). // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector128.Count)); do @@ -781,7 +781,7 @@ private static int IndexOfAny(ref short searchSpace, short value0, sho // Process the input in chunks of 64 characters (2 * Vector512). // If the input length is a multiple of 64, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector512.Count)); do @@ -834,7 +834,7 @@ private static int IndexOfAny(ref short searchSpace, short value0, sho // Process the input in chunks of 32 characters (2 * Vector256). // If the input length is a multiple of 32, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector256.Count)); do @@ -896,7 +896,7 @@ private static int IndexOfAny(ref short searchSpace, short value0, sho // Process the input in chunks of 16 characters (2 * Vector128). // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector128.Count)); do @@ -980,7 +980,7 @@ private static int IndexOfAnyInRange(ref short searchSpace, short lowI // Process the input in chunks of 64 characters (2 * Vector512). // If the input length is a multiple of 64, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector512.Count)); do @@ -1030,7 +1030,7 @@ private static int IndexOfAnyInRange(ref short searchSpace, short lowI // Process the input in chunks of 32 characters (2 * Vector256). // If the input length is a multiple of 32, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector256.Count)); do @@ -1091,7 +1091,7 @@ private static int IndexOfAnyInRange(ref short searchSpace, short lowI // Process the input in chunks of 16 characters (2 * Vector128). // If the input length is a multiple of 16, don't consume the last 16 characters in this loop. // Let the fallback below handle it instead. This is why the condition is - // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "!IsAddressGreaterThan". + // ">" instead of ">=" above, and why "IsAddressLessThan" is used instead of "IsAddressLessThanOrEqualTo". ref short twoVectorsAwayFromEnd = ref Unsafe.Add(ref searchSpace, length - (2 * Vector128.Count)); do diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index c29adea608902a..cf8e536c5fded1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -1383,7 +1383,7 @@ internal static bool NonPackedContainsValueType(ref T searchSpace, T value, i currentSearchSpace = ref Unsafe.Add(ref currentSearchSpace, Vector512.Count); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector512.Count != 0) @@ -1414,7 +1414,7 @@ internal static bool NonPackedContainsValueType(ref T searchSpace, T value, i return true; } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector256.Count != 0) @@ -1444,7 +1444,7 @@ internal static bool NonPackedContainsValueType(ref T searchSpace, T value, i return true; } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the first vector in the search space. if ((uint)length % Vector128.Count != 0) @@ -1574,7 +1574,7 @@ internal static int NonPackedIndexOfValueType(ref TValue searc currentSearchSpace = ref Unsafe.Add(ref currentSearchSpace, Vector512.Count); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector512.Count != 0) @@ -1605,7 +1605,7 @@ internal static int NonPackedIndexOfValueType(ref TValue searc return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector256.Count != 0) @@ -1635,7 +1635,7 @@ internal static int NonPackedIndexOfValueType(ref TValue searc return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the first vector in the search space. if ((uint)length % Vector128.Count != 0) @@ -1800,7 +1800,7 @@ internal static int NonPackedIndexOfAnyValueType(ref TValue se return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector512.Count != 0) @@ -1832,7 +1832,7 @@ internal static int NonPackedIndexOfAnyValueType(ref TValue se return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector256.Count != 0) @@ -1864,7 +1864,7 @@ internal static int NonPackedIndexOfAnyValueType(ref TValue se return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the first vector in the search space. if ((uint)length % Vector128.Count != 0) @@ -2007,7 +2007,7 @@ internal static int NonPackedIndexOfAnyValueType(ref TValue se return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector512.Count != 0) @@ -2039,7 +2039,7 @@ internal static int NonPackedIndexOfAnyValueType(ref TValue se return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector256.Count != 0) @@ -2071,7 +2071,7 @@ internal static int NonPackedIndexOfAnyValueType(ref TValue se return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the first vector in the search space. if ((uint)length % Vector128.Count != 0) @@ -2164,7 +2164,7 @@ private static int IndexOfAnyValueType(ref TValue searchSpace, return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector512.Count != 0) @@ -2198,7 +2198,7 @@ private static int IndexOfAnyValueType(ref TValue searchSpace, return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector256.Count != 0) @@ -2232,7 +2232,7 @@ private static int IndexOfAnyValueType(ref TValue searchSpace, return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the first vector in the search space. if ((uint)length % Vector128.Count != 0) @@ -2328,7 +2328,7 @@ private static int IndexOfAnyValueType(ref TValue searchSpace, return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector512.Count != 0) @@ -2363,7 +2363,7 @@ private static int IndexOfAnyValueType(ref TValue searchSpace, return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the last vector in the search space. if ((uint)length % Vector256.Count != 0) @@ -2398,7 +2398,7 @@ private static int IndexOfAnyValueType(ref TValue searchSpace, return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, equals); } - while (!Unsafe.IsAddressGreaterThan(ref currentSearchSpace, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentSearchSpace, ref oneVectorAwayFromEnd)); // If any elements remain, process the first vector in the search space. if ((uint)length % Vector128.Count != 0) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Equality.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Equality.cs index 77c3d8de92fb23..3814ba3fe622b3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Equality.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Equality.cs @@ -83,7 +83,7 @@ private static bool Equals(ref TLeft left, ref TRight ri currentRightSearchSpace = ref Unsafe.Add(ref currentRightSearchSpace, Vector512.Count); currentLeftSearchSpace = ref Unsafe.Add(ref currentLeftSearchSpace, Vector512.Count); } - while (!Unsafe.IsAddressGreaterThan(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); // If any elements remain, process the last vector in the search space. if (length % (uint)Vector512.Count != 0) @@ -113,7 +113,7 @@ private static bool Equals(ref TLeft left, ref TRight ri currentRightSearchSpace = ref Unsafe.Add(ref currentRightSearchSpace, Vector256.Count); currentLeftSearchSpace = ref Unsafe.Add(ref currentLeftSearchSpace, Vector256.Count); } - while (!Unsafe.IsAddressGreaterThan(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); // If any elements remain, process the last vector in the search space. if (length % (uint)Vector256.Count != 0) @@ -147,7 +147,7 @@ private static bool Equals(ref TLeft left, ref TRight ri currentRightSearchSpace = ref Unsafe.Add(ref currentRightSearchSpace, (uint)Vector128.Count); currentLeftSearchSpace = ref Unsafe.Add(ref currentLeftSearchSpace, TLoader.Count128); } - while (!Unsafe.IsAddressGreaterThan(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); // If any elements remain, process the last vector in the search space. if (length % (uint)Vector128.Count != 0) @@ -274,7 +274,7 @@ private static bool EqualsIgnoreCase(ref TLeft left, ref currentRightSearchSpace = ref Unsafe.Add(ref currentRightSearchSpace, (uint)Vector512.Count); currentLeftSearchSpace = ref Unsafe.Add(ref currentLeftSearchSpace, TLoader.Count512); } - while (!Unsafe.IsAddressGreaterThan(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); // If any elements remain, process the last vector in the search space. if (length % (uint)Vector512.Count != 0) @@ -346,7 +346,7 @@ private static bool EqualsIgnoreCase(ref TLeft left, ref currentRightSearchSpace = ref Unsafe.Add(ref currentRightSearchSpace, (uint)Vector256.Count); currentLeftSearchSpace = ref Unsafe.Add(ref currentLeftSearchSpace, TLoader.Count256); } - while (!Unsafe.IsAddressGreaterThan(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); // If any elements remain, process the last vector in the search space. if (length % (uint)Vector256.Count != 0) @@ -419,7 +419,7 @@ private static bool EqualsIgnoreCase(ref TLeft left, ref currentRightSearchSpace = ref Unsafe.Add(ref currentRightSearchSpace, (uint)Vector128.Count); currentLeftSearchSpace = ref Unsafe.Add(ref currentLeftSearchSpace, TLoader.Count128); } - while (!Unsafe.IsAddressGreaterThan(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref currentRightSearchSpace, ref oneVectorAwayFromRightEnd)); // If any elements remain, process the last vector in the search space. if (length % (uint)Vector128.Count != 0) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 8ba41f11d65e45..793f8274263dc6 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -14012,7 +14012,9 @@ public static void InitBlockUnaligned(ref byte startAddress, byte value, uint by [System.CLSCompliantAttribute(false)] public unsafe static void InitBlockUnaligned(void* startAddress, byte value, uint byteCount) { } public static bool IsAddressGreaterThan([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; } + public static bool IsAddressGreaterThanOrEqualTo([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; } public static bool IsAddressLessThan([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; } + public static bool IsAddressLessThanOrEqualTo([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; } public static bool IsNullRef(ref readonly T source) where T : allows ref struct { throw null; } public static ref T NullRef() where T : allows ref struct { throw null; } public static T ReadUnaligned(scoped ref readonly byte source) where T : allows ref struct { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs index 3d45fe2fbe0527..b5bec7f9357f62 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs @@ -805,6 +805,25 @@ public static unsafe void RefIsAddressGreaterThan() Assert.False(Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef(null), ref Unsafe.AsRef(null))); } + [Fact] + public static unsafe void RefIsAddressGreaterThanOrEqualTo() + { + int[] a = new int[2]; + + Assert.True(Unsafe.IsAddressGreaterThanOrEqualTo(ref a[0], ref a[0])); + Assert.False(Unsafe.IsAddressGreaterThanOrEqualTo(ref a[0], ref a[1])); + Assert.True(Unsafe.IsAddressGreaterThanOrEqualTo(ref a[1], ref a[0])); + Assert.True(Unsafe.IsAddressGreaterThanOrEqualTo(ref a[1], ref a[1])); + + // The following tests ensure that we're using unsigned comparison logic + + Assert.False(Unsafe.IsAddressGreaterThanOrEqualTo(ref Unsafe.AsRef((void*)(1)), ref Unsafe.AsRef((void*)(-1)))); + Assert.True(Unsafe.IsAddressGreaterThanOrEqualTo(ref Unsafe.AsRef((void*)(-1)), ref Unsafe.AsRef((void*)(1)))); + Assert.True(Unsafe.IsAddressGreaterThanOrEqualTo(ref Unsafe.AsRef((void*)(int.MinValue)), ref Unsafe.AsRef((void*)(int.MaxValue)))); + Assert.False(Unsafe.IsAddressGreaterThanOrEqualTo(ref Unsafe.AsRef((void*)(int.MaxValue)), ref Unsafe.AsRef((void*)(int.MinValue)))); + Assert.True(Unsafe.IsAddressGreaterThanOrEqualTo(ref Unsafe.AsRef(null), ref Unsafe.AsRef(null))); + } + [Fact] public static unsafe void RefIsAddressLessThan() { @@ -824,6 +843,25 @@ public static unsafe void RefIsAddressLessThan() Assert.False(Unsafe.IsAddressLessThan(ref Unsafe.AsRef(null), ref Unsafe.AsRef(null))); } + [Fact] + public static unsafe void RefIsAddressLessThanOrEqualTo() + { + int[] a = new int[2]; + + Assert.True(Unsafe.IsAddressLessThanOrEqualTo(ref a[0], ref a[0])); + Assert.True(Unsafe.IsAddressLessThanOrEqualTo(ref a[0], ref a[1])); + Assert.False(Unsafe.IsAddressLessThanOrEqualTo(ref a[1], ref a[0])); + Assert.True(Unsafe.IsAddressLessThanOrEqualTo(ref a[1], ref a[1])); + + // The following tests ensure that we're using unsigned comparison logic + + Assert.True(Unsafe.IsAddressLessThanOrEqualTo(ref Unsafe.AsRef((void*)(1)), ref Unsafe.AsRef((void*)(-1)))); + Assert.False(Unsafe.IsAddressLessThanOrEqualTo(ref Unsafe.AsRef((void*)(-1)), ref Unsafe.AsRef((void*)(1)))); + Assert.False(Unsafe.IsAddressLessThanOrEqualTo(ref Unsafe.AsRef((void*)(int.MinValue)), ref Unsafe.AsRef((void*)(int.MaxValue)))); + Assert.True(Unsafe.IsAddressLessThanOrEqualTo(ref Unsafe.AsRef((void*)(int.MaxValue)), ref Unsafe.AsRef((void*)(int.MinValue)))); + Assert.True(Unsafe.IsAddressLessThanOrEqualTo(ref Unsafe.AsRef(null), ref Unsafe.AsRef(null))); + } + [Fact] public static unsafe void ReadUnaligned_ByRef_Int32() { From 11a9a00e5c8c669d1a710444ce710cf89601d1a1 Mon Sep 17 00:00:00 2001 From: Hamish Arblaster Date: Fri, 18 Jul 2025 13:01:52 +1000 Subject: [PATCH 2/6] Update vectorization-guidelines.md Revert unintentional whitespace changes --- docs/coding-guidelines/vectorization-guidelines.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/coding-guidelines/vectorization-guidelines.md b/docs/coding-guidelines/vectorization-guidelines.md index f8fa0479353c26..9ac773872947a9 100644 --- a/docs/coding-guidelines/vectorization-guidelines.md +++ b/docs/coding-guidelines/vectorization-guidelines.md @@ -161,15 +161,15 @@ To reduce the number of comparisons for small inputs, we can re-arrange it in th void OptimalCodeStructure(ReadOnlySpan buffer) { if (!Vector128.IsHardwareAccelerated || buffer.Length < Vector128.Count) - { + { // scalar code path - } + } else if (!Vector256.IsHardwareAccelerated || buffer.Length < Vector256.Count) - { + { // Vector128 code path - } + } else - { + { // Vector256 code path } } @@ -890,7 +890,7 @@ unsafe int ComputeFirstIndex(ref T searchSpace, ref T current, Vector128 e uint mostSignificantBits = equals.ExtractMostSignificantBits(); int index = BitOperations.TrailingZeroCount(mostSignificantBits); - + return elementOffset + index; } ``` From 03b2a8dbdb55be78666a19da48baed9fefe536b3 Mon Sep 17 00:00:00 2001 From: Hamish Arblaster Date: Fri, 18 Jul 2025 13:02:41 +1000 Subject: [PATCH 3/6] Update FrozenFromKnownValuesTests.cs Revert unintentional whitespace changes --- .../tests/Frozen/FrozenFromKnownValuesTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs index 7d026a9ef4d813..f055f856e78ed5 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs @@ -153,7 +153,7 @@ public static IEnumerable StringStringData() => Enumerable.Range(0, 100).Select(i => $"{i:D2}ABCDEFGH\U0001F600").ToArray(), // left justified substring non-ascii Enumerable.Range(0, 100).Select(i => $"ABCDEFGH\U0001F600{i:D2}").ToArray(), // right justified substring non-ascii Enumerable.Range(0, 20).Select(i => i.ToString("D2")).Select(s => (char)(s[0] + 128) + "" + (char)(s[1] + 128)).ToArray(), // left-justified non-ascii - + Enumerable.Range(0, 10).Select(i => $"{i}ABCDefgh").ToArray(), // left justified single char ascii, mixed casing Enumerable.Range(0, 10).Select(i => $"ABCDefgh{i}").ToArray(), // right justified single char ascii, mixed casing Enumerable.Range(0, 100).Select(i => $"{i:D2}ABCDefgh").ToArray(), // left justified substring ascii, mixed casing From 3059bde454c22f4821ea39aaed4da245507e9b24 Mon Sep 17 00:00:00 2001 From: Hamish Arblaster Date: Sat, 26 Jul 2025 19:29:53 +1000 Subject: [PATCH 4/6] Implement feedback --- src/coreclr/vm/corelib.h | 2 -- src/coreclr/vm/jitinterface.cpp | 34 ------------------- .../System/Runtime/CompilerServices/Unsafe.cs | 14 -------- 3 files changed, 50 deletions(-) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 3c3fdb57d02639..5b894a5312d97c 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -774,9 +774,7 @@ DEFINE_METHOD(UNSAFE, BYREF_COPY_BLOCK, CopyBlock, SM_RefByt DEFINE_METHOD(UNSAFE, PTR_COPY_BLOCK_UNALIGNED, CopyBlockUnaligned, SM_PtrVoid_PtrVoid_UInt_RetVoid) DEFINE_METHOD(UNSAFE, BYREF_COPY_BLOCK_UNALIGNED, CopyBlockUnaligned, SM_RefByte_RefByte_UInt_RetVoid) DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_GREATER_THAN, IsAddressGreaterThan, NoSig) -DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_GREATER_THAN_OR_EQUAL_TO, IsAddressGreaterThanOrEqualTo, NoSig) DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_LESS_THAN, IsAddressLessThan, NoSig) -DEFINE_METHOD(UNSAFE, BYREF_IS_ADDRESS_LESS_THAN_OR_EQUAL_TO, IsAddressLessThanOrEqualTo, NoSig) DEFINE_METHOD(UNSAFE, BYREF_INIT_BLOCK, InitBlockUnaligned, SM_RefByte_Byte_UInt_RetVoid) DEFINE_METHOD(UNSAFE, PTR_INIT_BLOCK, InitBlock, SM_PtrVoid_Byte_UInt_RetVoid) DEFINE_METHOD(UNSAFE, BYREF_INIT_BLOCK_UNALIGNED, InitBlock, SM_RefByte_Byte_UInt_RetVoid) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 147a554d4e1c63..d186607e50968a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6895,23 +6895,6 @@ static bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn, return true; } - else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN_OR_EQUAL_TO)->GetMemberDef()) - { - // Compare the two arguments - static const BYTE ilcode[] = - { - CEE_LDARG_0, - CEE_LDARG_1, - CEE_PREFIX1, (CEE_CLT_UN & 0xFF), - CEE_LDC_I4_0, - CEE_PREFIX1, (CEE_CEQ & 0xFF), - CEE_RET - }; - - setILIntrinsicMethodInfo(methInfo,const_cast(ilcode),sizeof(ilcode), 2); - - return true; - } else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef()) { // Compare the two arguments @@ -6927,23 +6910,6 @@ static bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn, return true; } - else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN_OR_EQUAL_TO)->GetMemberDef()) - { - // Compare the two arguments - static const BYTE ilcode[] = - { - CEE_LDARG_0, - CEE_LDARG_1, - CEE_PREFIX1, (CEE_CGT_UN & 0xFF), - CEE_LDC_I4_0, - CEE_PREFIX1, (CEE_CEQ & 0xFF), - CEE_RET - }; - - setILIntrinsicMethodInfo(methInfo,const_cast(ilcode),sizeof(ilcode), 2); - - return true; - } else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_NULLREF)->GetMemberDef()) { static const BYTE ilcode[] = diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 12362e0ff615c3..59ffb9c158f692 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -421,13 +421,6 @@ public static bool IsAddressGreaterThanOrEqualTo([AllowNull] ref readonly T l where T : allows ref struct { return !IsAddressLessThan(in left, in right); - - // ldarg.0 - // ldarg.1 - // clt.un - // ldc.i4.0 - // ceq - // ret } /// @@ -471,13 +464,6 @@ public static bool IsAddressLessThanOrEqualTo([AllowNull] ref readonly T left where T : allows ref struct { return !IsAddressGreaterThan(in left, in right); - - // ldarg.0 - // ldarg.1 - // cgt.un - // ldc.i4.0 - // ceq - // ret } /// From be5044b03f45fe3832d97f72e0b35dbb3ab62127 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 26 Jul 2025 12:47:14 -0700 Subject: [PATCH 5/6] Apply suggestions from code review --- .../TypeSystem/IL/Stubs/UnsafeIntrinsics.cs | 16 ---------------- .../tests/Frozen/FrozenFromKnownValuesTests.cs | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs index 334206020e63cf..2b90323728049f 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs @@ -59,28 +59,12 @@ public static MethodIL EmitIL(MethodDesc method) (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), (byte)ILOpcode.ret }, Array.Empty(), null); - case "IsAddressGreaterThanOrEqualTo": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), - (byte)ILOpcode.ldc_i4_0, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), - (byte)ILOpcode.ret }, Array.Empty(), null); case "IsAddressLessThan": return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), (byte)ILOpcode.ret }, Array.Empty(), null); - case "IsAddressLessThanOrEqualTo": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), - (byte)ILOpcode.ldc_i4_0, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), - (byte)ILOpcode.ret }, Array.Empty(), null); case "ByteOffset": return new ILStubMethodIL(method, new byte[] { diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs index f055f856e78ed5..dc4e2b9e89dbee 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs @@ -117,8 +117,8 @@ public static IEnumerable StringStringData() => new[] { "AsPointer", "As", "AsRef", "Add", "AddByteOffset", "Copy", "CopyBlock", "CopyBlockUnaligned", "InitBlock", "InitBlockUnaligned", "Read", "Write", - "ReadUnaligned", "WriteUnaligned", "AreSame", "IsAddressGreaterThan", "IsAddressGreaterThanOrEqualTo", "IsAddressLessThan", "IsAddressLessThanOrEqualTo", - "ByteOffset", "NullRef", "IsNullRef", "SkipInit", "Subtract", "SubtractByteOffset", "Unbox", + "ReadUnaligned", "WriteUnaligned", "AreSame", "IsAddressGreaterThan", "IsAddressLessThan", "ByteOffset", "NullRef", "IsNullRef", "SkipInit", + "Subtract", "SubtractByteOffset", "Unbox", }, // from https://raw.githubusercontent.com/dotnet/roslyn/0456b4adc6939e366e7c509318b3ac6a85cda496/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenLengthBasedSwitchTests.cs From 2f7a6e197c33f20034f5ef46ff2e428cb2e760bf Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 26 Jul 2025 12:48:43 -0700 Subject: [PATCH 6/6] Apply suggestions from code review --- .../src/System/Runtime/CompilerServices/Unsafe.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 59ffb9c158f692..0f8358c917fb49 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -412,9 +412,6 @@ public static bool IsAddressGreaterThan([AllowNull] ref readonly T left, [All /// This check is conceptually similar to "(void*)(&left) >= (void*)(&right)". /// [Intrinsic] - // CoreCLR:CoreCLR:METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN_OR_EQUAL_TO - // AOT:IsAddressGreaterThanOrEqualTo - // Mono:IsAddressGreaterThanOrEqualTo [NonVersionable] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsAddressGreaterThanOrEqualTo([AllowNull] ref readonly T left, [AllowNull] ref readonly T right) @@ -455,9 +452,6 @@ public static bool IsAddressLessThan([AllowNull] ref readonly T left, [AllowN /// This check is conceptually similar to "(void*)(&left) <= (void*)(&right)". /// [Intrinsic] - // CoreCLR:METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN_OR_EQUAL_TO - // AOT:IsAddressLessThanOrEqualTo - // Mono:IsAddressLessThanOrEqualTo [NonVersionable] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsAddressLessThanOrEqualTo([AllowNull] ref readonly T left, [AllowNull] ref readonly T right)