SSE and SSE2 CompareGreaterThan methods properly handle NaN inputs
The following System.Runtime.Intrinsics.X86.Sse and System.Runtime.Intrinsics.X86.Sse2 methods have been fixed to properly handle NaN
inputs and match the hardware behavior of the equivalent methods in the System.Runtime.Intrinsics.X86.Avx class:
CompareGreaterThan
CompareGreaterThanOrEqual
CompareNotGreaterThan
CompareNotGreaterThanOrEqual
CompareScalarGreaterThan
CompareScalarGreaterThanOrEqual
CompareScalarNotGreaterThan
CompareScalarNotGreaterThanOrEqual
Change description
Previously, NaN
inputs to the listed Sse and Sse2 methods returned an incorrect result. The result also differed from the result generated by the corresponding method in the Avx class.
Starting in .NET 5, these methods correctly handle NaN
inputs and return the same results as the corresponding methods in the Avx class.
The Streaming SIMD Extensions (SSE) and Streaming SIMD Extensions 2 (SSE2) Instruction Set Architectures (ISAs) don't provide direct hardware support for these comparison methods, so they're implemented in software. Previously, the methods were improperly implemented, and they incorrectly handled NaN
inputs. For code ported from native, the incorrect behavior may introduce bugs. For a 256-bit code path, the methods can also produce different results to the equivalent methods in the Avx class.
As an example of how the methods were previously incorrect, you can implement CompareNotGreaterThan(x,y)
as CompareLessThanOrEqual(x,y)
for regular integers. However, for NaN
inputs, that logic computes the wrong result. Instead, using CompareNotLessThan(y,x)
compares the numbers correctly and takes NaN
inputs into consideration.
Version introduced
5.0
Recommended action
If the previous behavior was a bug, no change is required.
If the previous behavior was desired, you can maintain that behavior by changing the relevant invocation as follows:
CompareGreaterThan(x,y)
->CompareNotLessThanOrEqual(x,y)
CompareGreaterThanOrEqual(x,y)
->CompareNotLessThan(x,y)
CompareNotGreaterThan(x,y)
->CompareLessThanOrEqual(x,y)
CompareNotGreaterThanOrEqual(x,y)
->CompareLessThan(x,y)
CompareScalarGreaterThan(x,y)
->CompareScalarNotLessThanOrEqual(x,y)
CompareScalarGreaterThanOrEqual(x,y)
->CompareScalarNotLessThan(x,y)
CompareScalarNotGreaterThan(x,y)
->CompareScalarLessThanOrEqual(x,y)
CompareScalarNotGreaterThanOrEqual(x,y)
->CompareScalarLessThan(x,y)
Affected APIs
System.Runtime.Intrinsics.X86.Sse.CompareGreaterThan(Vector128<Single>, Vector128<Single>)
System.Runtime.Intrinsics.X86.Sse.CompareGreaterThanOrEqual(Vector128<Single>, Vector128<Single>)
System.Runtime.Intrinsics.X86.Sse.CompareNotGreaterThan(Vector128<Single>, Vector128<Single>)
System.Runtime.Intrinsics.X86.Sse.CompareNotGreaterThanOrEqual(Vector128<Single>, Vector128<Single>)
System.Runtime.Intrinsics.X86.Sse.CompareScalarGreaterThan(Vector128<Single>, Vector128<Single>)
System.Runtime.Intrinsics.X86.Sse.CompareScalarNotGreaterThan(Vector128<Single>, Vector128<Single>)
System.Runtime.Intrinsics.X86.Sse2.CompareGreaterThan(Vector128<Double>, Vector128<Double>)
System.Runtime.Intrinsics.X86.Sse2.CompareGreaterThanOrEqual(Vector128<Double>, Vector128<Double>)
System.Runtime.Intrinsics.X86.Sse2.CompareNotGreaterThan(Vector128<Double>, Vector128<Double>)
System.Runtime.Intrinsics.X86.Sse2.CompareScalarGreaterThan(Vector128<Double>, Vector128<Double>)
System.Runtime.Intrinsics.X86.Sse2.CompareScalarNotGreaterThan(Vector128<Double>, Vector128<Double>)