diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index a95a2dcadb622e..1acb0313e0f7d5 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1267,7 +1267,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: @@ -1282,7 +1284,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 df1df1c881c73f..8e60c2531ec144 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -4317,6 +4317,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); @@ -4334,6 +4353,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); @@ -9026,10 +9064,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 86c7d445dabba1..a9df7fb12c3ff0 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -200,7 +200,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 d085abd6361e27..53fe18f54e109c 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -689,7 +689,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 b7dcf9eacd88ef..a5608367da1d28 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6969,6 +6969,23 @@ 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 @@ -6984,6 +7001,23 @@ 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.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs index e11de4412941e5..e7b345f8df5650 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenFromKnownValuesTests.cs @@ -106,8 +106,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 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 cf481d8999649a..c0f3f9e5c67819 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 @@ -481,7 +481,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 ef7a6fc4e84fd3..6a34f012b62452 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 @@ -395,6 +395,31 @@ public static bool IsAddressGreaterThan([AllowNull] ref T left, [AllowNull] r // 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 T left, [AllowNull] ref T right) + { + throw new PlatformNotSupportedException(); + + // 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 . @@ -418,6 +443,31 @@ public static bool IsAddressLessThan([AllowNull] ref T left, [AllowNull] ref // 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 T left, [AllowNull] ref T right) + { + throw new PlatformNotSupportedException(); + + // 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 4ce70d7407d2f3..4e89045d22a327 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs @@ -192,7 +192,7 @@ internal static int IndexOfAnyVectorized(ref short sea // 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 "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 @@ -245,7 +245,7 @@ internal static int IndexOfAnyVectorized(ref short sea // 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 "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 @@ -309,7 +309,7 @@ internal static int LastIndexOfAnyVectorized(ref short // 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 @@ -360,7 +360,7 @@ internal static int LastIndexOfAnyVectorized(ref short // 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 @@ -421,7 +421,7 @@ internal static int IndexOfAnyVectorized(ref byte searchSpace, int sea // 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 @@ -470,7 +470,7 @@ internal static int IndexOfAnyVectorized(ref byte searchSpace, int sea // 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 @@ -531,7 +531,7 @@ internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int // 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 @@ -580,7 +580,7 @@ internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int // 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 @@ -642,7 +642,7 @@ internal static int IndexOfAnyVectorizedAnyByte(ref byte 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 "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 @@ -694,7 +694,7 @@ internal static int IndexOfAnyVectorizedAnyByte(ref byte 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 "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 @@ -756,7 +756,7 @@ internal static int LastIndexOfAnyVectorizedAnyByte(ref byte searchSpa // 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 @@ -808,7 +808,7 @@ internal static int LastIndexOfAnyVectorizedAnyByte(ref byte searchSpa // 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/SpanHelpers.Packed.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs index 2f70f00959c1c4..072e4b83f26e81 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs @@ -124,7 +124,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 @@ -175,7 +175,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 @@ -233,7 +233,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 @@ -324,7 +324,7 @@ private static int IndexOf(ref short searchSpace, short value, int len // 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 @@ -377,7 +377,7 @@ private static int IndexOf(ref short searchSpace, short value, int len // 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 @@ -437,7 +437,7 @@ private static int IndexOf(ref short searchSpace, short value, int len // 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 @@ -537,7 +537,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 @@ -591,7 +591,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 @@ -652,7 +652,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 @@ -755,7 +755,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 @@ -810,7 +810,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 @@ -872,7 +872,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 @@ -956,7 +956,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 @@ -1010,7 +1010,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 @@ -1071,7 +1071,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 0806bbc95daa33..20d344614ebe6d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -1385,7 +1385,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 % Vector512.Count != 0) @@ -1415,7 +1415,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) @@ -1445,7 +1445,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) @@ -1575,7 +1575,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 % 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) @@ -1782,7 +1782,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) @@ -1814,7 +1814,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) @@ -1846,7 +1846,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) @@ -1989,7 +1989,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) @@ -2021,7 +2021,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) @@ -2053,7 +2053,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) @@ -2146,7 +2146,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) @@ -2180,7 +2180,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) @@ -2214,7 +2214,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) @@ -2310,7 +2310,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) @@ -2345,7 +2345,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) @@ -2380,7 +2380,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) @@ -3774,7 +3774,7 @@ public static int CountValueType(ref T current, T value, int length) where T count += BitOperations.PopCount(Vector512.Equals(Vector512.LoadUnsafe(ref current), targetVector).ExtractMostSignificantBits()); current = ref Unsafe.Add(ref current, Vector512.Count); } - while (!Unsafe.IsAddressGreaterThan(ref current, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref current, ref oneVectorAwayFromEnd)); // If there are just a few elements remaining, then processing these elements by the scalar loop // is cheaper than doing bitmask + popcount on the full last vector. To avoid complicated type @@ -3802,7 +3802,7 @@ public static int CountValueType(ref T current, T value, int length) where T count += BitOperations.PopCount(Vector256.Equals(Vector256.LoadUnsafe(ref current), targetVector).ExtractMostSignificantBits()); current = ref Unsafe.Add(ref current, Vector256.Count); } - while (!Unsafe.IsAddressGreaterThan(ref current, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref current, ref oneVectorAwayFromEnd)); // If there are just a few elements remaining, then processing these elements by the scalar loop // is cheaper than doing bitmask + popcount on the full last vector. To avoid complicated type @@ -3830,7 +3830,7 @@ public static int CountValueType(ref T current, T value, int length) where T count += BitOperations.PopCount(Vector128.Equals(Vector128.LoadUnsafe(ref current), targetVector).ExtractMostSignificantBits()); current = ref Unsafe.Add(ref current, Vector128.Count); } - while (!Unsafe.IsAddressGreaterThan(ref current, ref oneVectorAwayFromEnd)); + while (Unsafe.IsAddressLessThanOrEqualTo(ref current, ref oneVectorAwayFromEnd)); uint remaining = (uint)Unsafe.ByteOffset(ref current, ref end) / (uint)Unsafe.SizeOf(); if (remaining > Vector128.Count / 2) 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 31df908d9afb0c..670b7e90465a4d 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 @@ -82,7 +82,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) @@ -112,7 +112,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) @@ -146,7 +146,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) @@ -270,7 +270,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) @@ -342,7 +342,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) @@ -415,7 +415,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.CompilerServices.Unsafe/tests/UnsafeTests.cs b/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs index 8d596482766a40..ee5e9ac3d057a4 100644 --- a/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs +++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs @@ -690,6 +690,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() { @@ -709,6 +728,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() { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index fcf0e7e159bd63..e3fa538863a82c 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13241,7 +13241,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 T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref T right) { throw null; } + public static bool IsAddressGreaterThanOrEqualTo([System.Diagnostics.CodeAnalysis.AllowNull] ref T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref T right) { throw null; } public static bool IsAddressLessThan([System.Diagnostics.CodeAnalysis.AllowNull] ref T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref T right) { throw null; } + public static bool IsAddressLessThanOrEqualTo([System.Diagnostics.CodeAnalysis.AllowNull] ref T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref T right) { throw null; } public static bool IsNullRef(ref T source) { throw null; } public static ref T NullRef() { throw null; } public static T ReadUnaligned(ref byte source) { throw null; } diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index bc52e37f2dd213..4669c06770a629 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2273,6 +2273,20 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; + } else if (!strcmp (tm, "IsAddressLessThanOrEqualTo")) { + MonoGenericContext *ctx = mono_method_get_context (target_method); + g_assert (ctx); + g_assert (ctx->method_inst); + g_assert (ctx->method_inst->type_argc == 1); + + MonoClass *k = mono_defaults.boolean_class; + interp_add_ins (td, MINT_CLE_UN_P); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_type (td, stack_type [mono_mint_type (m_class_get_byval_arg (k))], k); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 5; + return TRUE; } else if (!strcmp (tm, "IsAddressGreaterThan")) { MonoGenericContext *ctx = mono_method_get_context (target_method); g_assert (ctx); @@ -2286,6 +2300,19 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; + } else if (!strcmp (tm, "IsAddressGreaterThanOrEqualTo")) { + MonoGenericContext *ctx = mono_method_get_context (target_method); + g_assert (ctx); + g_assert (ctx->method_inst); + g_assert (ctx->method_inst->type_argc == 1); + + interp_add_ins (td, MINT_CGE_UN_P); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 5; + return TRUE; } else if (!strcmp (tm, "SizeOf")) { MonoGenericContext *ctx = mono_method_get_context (target_method); g_assert (ctx); diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 68dc78bd22bc4d..cc4dd913db3768 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -466,6 +466,16 @@ emit_unsafe_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg); EMIT_NEW_UNALU (cfg, ins, OP_PCLT_UN, dreg, -1); return ins; + } else if (!strcmp (cmethod->name, "IsAddressLessThanOrEqualTo")) { + g_assert (ctx); + g_assert (ctx->method_inst); + g_assert (ctx->method_inst->type_argc == 1); + g_assert (fsig->param_count == 2); + + int dreg = alloc_ireg (cfg); + EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg); + EMIT_NEW_UNALU (cfg, ins, OP_PCLE_UN, dreg, -1); + return ins; } else if (!strcmp (cmethod->name, "IsAddressGreaterThan")) { g_assert (ctx); g_assert (ctx->method_inst); @@ -476,6 +486,16 @@ emit_unsafe_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg); EMIT_NEW_UNALU (cfg, ins, OP_PCGT_UN, dreg, -1); return ins; + } else if (!strcmp (cmethod->name, "IsAddressGreaterThanOrEqualTo")) { + g_assert (ctx); + g_assert (ctx->method_inst); + g_assert (ctx->method_inst->type_argc == 1); + g_assert (fsig->param_count == 2); + + int dreg = alloc_ireg (cfg); + EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg); + EMIT_NEW_UNALU (cfg, ins, OP_PCGE_UN, dreg, -1); + return ins; } else if (!strcmp (cmethod->name, "Add")) { g_assert (ctx); g_assert (ctx->method_inst); diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 7483e028159d43..0e2897b77112ea 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -1827,7 +1827,9 @@ enum { #define OP_PCLT OP_LCLT #define OP_PCGT OP_LCGT #define OP_PCLT_UN OP_LCLT_UN +#define OP_PCLE_UN OP_LCLE_UN #define OP_PCGT_UN OP_LCGT_UN +#define OP_PCGE_UN OP_LCGE_UN #define OP_PBNE_UN OP_LBNE_UN #define OP_PBGE_UN OP_LBGE_UN #define OP_PBLT_UN OP_LBLT_UN @@ -1858,7 +1860,9 @@ enum { #define OP_PCLT OP_ICLT #define OP_PCGT OP_ICGT #define OP_PCLT_UN OP_ICLT_UN +#define OP_PCLE_UN OP_ICLE_UN #define OP_PCGT_UN OP_ICGT_UN +#define OP_PCGE_UN OP_ICGE_UN #define OP_PBNE_UN OP_IBNE_UN #define OP_PBGE_UN OP_IBGE_UN #define OP_PBLT_UN OP_IBLT_UN