Skip to content

Commit 8e211ce

Browse files
committed
Ensure that TensorPrimitives uses the in-box vector operations on .NET 9+
1 parent 0816d54 commit 8e211ce

19 files changed

+979
-632
lines changed

src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@
9797
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.LogP1.cs" />
9898
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Max.cs" />
9999
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MaxMagnitude.cs" />
100+
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MaxMagnitudeNumber.cs" />
100101
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MaxNumber.cs" />
101102
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Min.cs" />
102103
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MinMagnitude.cs" />
104+
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MinMagnitudeNumber.cs" />
103105
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MinNumber.cs" />
104106
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Multiply.cs" />
105107
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.MultiplyAdd.cs" />

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ public static float Max(ReadOnlySpan<float> x) =>
440440
/// </para>
441441
/// </remarks>
442442
public static void Max(ReadOnlySpan<float> x, ReadOnlySpan<float> y, Span<float> destination) =>
443-
InvokeSpanSpanIntoSpan<MaxPropagateNaNOperator_Single>(x, y, destination);
443+
InvokeSpanSpanIntoSpan<MaxOperator>(x, y, destination);
444444

445445
/// <summary>Searches for the single-precision floating-point number with the largest magnitude in the specified tensor.</summary>
446446
/// <param name="x">The tensor, represented as a span.</param>
@@ -476,7 +476,7 @@ public static float MaxMagnitude(ReadOnlySpan<float> x) =>
476476
/// </para>
477477
/// </remarks>
478478
public static void MaxMagnitude(ReadOnlySpan<float> x, ReadOnlySpan<float> y, Span<float> destination) =>
479-
InvokeSpanSpanIntoSpan<MaxMagnitudePropagateNaNOperator_Single>(x, y, destination);
479+
InvokeSpanSpanIntoSpan<MaxMagnitudeOperator>(x, y, destination);
480480

481481
/// <summary>Searches for the smallest single-precision floating-point number in the specified tensor.</summary>
482482
/// <param name="x">The tensor, represented as a span.</param>
@@ -517,7 +517,7 @@ public static float Min(ReadOnlySpan<float> x) =>
517517
/// </para>
518518
/// </remarks>
519519
public static void Min(ReadOnlySpan<float> x, ReadOnlySpan<float> y, Span<float> destination) =>
520-
InvokeSpanSpanIntoSpan<MinPropagateNaNOperator_Single>(x, y, destination);
520+
InvokeSpanSpanIntoSpan<MinOperator>(x, y, destination);
521521

522522
/// <summary>Searches for the single-precision floating-point number with the smallest magnitude in the specified tensor.</summary>
523523
/// <param name="x">The tensor, represented as a span.</param>
@@ -558,7 +558,7 @@ public static float MinMagnitude(ReadOnlySpan<float> x) =>
558558
/// </para>
559559
/// </remarks>
560560
public static void MinMagnitude(ReadOnlySpan<float> x, ReadOnlySpan<float> y, Span<float> destination) =>
561-
InvokeSpanSpanIntoSpan<MinMagnitudePropagateNaNOperator_Single>(x, y, destination);
561+
InvokeSpanSpanIntoSpan<MinMagnitudeOperator>(x, y, destination);
562562

563563
/// <summary>Computes the element-wise product of single-precision floating-point numbers in the specified tensors.</summary>
564564
/// <param name="x">The first tensor, represented as a span.</param>

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CopySign.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ public static void CopySign<T>(ReadOnlySpan<T> x, T sign, Span<T> destination)
4747

4848
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y)
4949
{
50+
#if NET9_0_OR_GREATER
51+
return Vector128.CopySign(x, y);
52+
#else
5053
if (typeof(T) == typeof(float))
5154
{
5255
return Vector128.ConditionalSelect(Vector128.Create(-0.0f).As<float, T>(), y, x);
@@ -71,10 +74,14 @@ public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y)
7174
}
7275

7376
return x;
77+
#endif
7478
}
7579

7680
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y)
7781
{
82+
#if NET9_0_OR_GREATER
83+
return Vector256.CopySign(x, y);
84+
#else
7885
if (typeof(T) == typeof(float))
7986
{
8087
return Vector256.ConditionalSelect(Vector256.Create(-0.0f).As<float, T>(), y, x);
@@ -99,10 +106,14 @@ public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y)
99106
}
100107

101108
return x;
109+
#endif
102110
}
103111

104112
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y)
105113
{
114+
#if NET9_0_OR_GREATER
115+
return Vector512.CopySign(x, y);
116+
#else
106117
if (typeof(T) == typeof(float))
107118
{
108119
return Vector512.ConditionalSelect(Vector512.Create(-0.0f).As<float, T>(), y, x);
@@ -127,6 +138,7 @@ public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y)
127138
}
128139

129140
return x;
141+
#endif
130142
}
131143
}
132144
}

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Runtime.Intrinsics;
56

67
namespace System.Numerics.Tensors
@@ -25,10 +26,59 @@ public static void DegreesToRadians<T>(ReadOnlySpan<T> x, Span<T> destination)
2526
private readonly struct DegreesToRadiansOperator<T> : IUnaryOperator<T, T> where T : ITrigonometricFunctions<T>
2627
{
2728
public static bool Vectorizable => true;
29+
2830
public static T Invoke(T x) => T.DegreesToRadians(x);
29-
public static Vector128<T> Invoke(Vector128<T> x) => (x * T.Pi) / T.CreateChecked(180);
30-
public static Vector256<T> Invoke(Vector256<T> x) => (x * T.Pi) / T.CreateChecked(180);
31-
public static Vector512<T> Invoke(Vector512<T> x) => (x * T.Pi) / T.CreateChecked(180);
31+
32+
public static Vector128<T> Invoke(Vector128<T> x)
33+
{
34+
#if NET9_0_OR_GREATER
35+
if (typeof(T) == typeof(double))
36+
{
37+
return Vector128.DegreesToRadians(x.AsDouble()).As<double, T>();
38+
}
39+
else
40+
{
41+
Debug.Assert(typeof(T) == typeof(float));
42+
return Vector128.DegreesToRadians(x.AsSingle()).As<float, T>();
43+
}
44+
#else
45+
return (x * T.Pi) / T.CreateChecked(180);
46+
#endif
47+
}
48+
49+
public static Vector256<T> Invoke(Vector256<T> x)
50+
{
51+
#if NET9_0_OR_GREATER
52+
if (typeof(T) == typeof(double))
53+
{
54+
return Vector256.DegreesToRadians(x.AsDouble()).As<double, T>();
55+
}
56+
else
57+
{
58+
Debug.Assert(typeof(T) == typeof(float));
59+
return Vector256.DegreesToRadians(x.AsSingle()).As<float, T>();
60+
}
61+
#else
62+
return (x * T.Pi) / T.CreateChecked(180);
63+
#endif
64+
}
65+
66+
public static Vector512<T> Invoke(Vector512<T> x)
67+
{
68+
#if NET9_0_OR_GREATER
69+
if (typeof(T) == typeof(double))
70+
{
71+
return Vector512.DegreesToRadians(x.AsDouble()).As<double, T>();
72+
}
73+
else
74+
{
75+
Debug.Assert(typeof(T) == typeof(float));
76+
return Vector512.DegreesToRadians(x.AsSingle()).As<float, T>();
77+
}
78+
#else
79+
return (x * T.Pi) / T.CreateChecked(180);
80+
#endif
81+
}
3282
}
3383
}
3484
}

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Runtime.Intrinsics;
56

67
namespace System.Numerics.Tensors
@@ -29,10 +30,59 @@ public static void Hypot<T>(ReadOnlySpan<T> x, ReadOnlySpan<T> y, Span<T> destin
2930
where T : IRootFunctions<T>
3031
{
3132
public static bool Vectorizable => true;
33+
3234
public static T Invoke(T x, T y) => T.Hypot(x, y);
33-
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y) => Vector128.Sqrt((x * x) + (y * y));
34-
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y) => Vector256.Sqrt((x * x) + (y * y));
35-
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y) => Vector512.Sqrt((x * x) + (y * y));
35+
36+
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y)
37+
{
38+
#if NET9_0_OR_GREATER
39+
if (typeof(T) == typeof(double))
40+
{
41+
return Vector128.Hypot(x.AsDouble(), y.AsDouble()).As<double, T>();
42+
}
43+
else
44+
{
45+
Debug.Assert(typeof(T) == typeof(float));
46+
return Vector128.Hypot(x.AsSingle(), y.AsSingle()).As<float, T>();
47+
}
48+
#else
49+
return Vector128.Sqrt((x * x) + (y * y));
50+
#endif
51+
}
52+
53+
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y)
54+
{
55+
#if NET9_0_OR_GREATER
56+
if (typeof(T) == typeof(double))
57+
{
58+
return Vector256.Hypot(x.AsDouble(), y.AsDouble()).As<double, T>();
59+
}
60+
else
61+
{
62+
Debug.Assert(typeof(T) == typeof(float));
63+
return Vector256.Hypot(x.AsSingle(), y.AsSingle()).As<float, T>();
64+
}
65+
#else
66+
return Vector256.Sqrt((x * x) + (y * y));
67+
#endif
68+
}
69+
70+
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y)
71+
{
72+
#if NET9_0_OR_GREATER
73+
if (typeof(T) == typeof(double))
74+
{
75+
return Vector512.Hypot(x.AsDouble(), y.AsDouble()).As<double, T>();
76+
}
77+
else
78+
{
79+
Debug.Assert(typeof(T) == typeof(float));
80+
return Vector512.Hypot(x.AsSingle(), y.AsSingle()).As<float, T>();
81+
}
82+
#else
83+
return Vector512.Sqrt((x * x) + (y * y));
84+
#endif
85+
}
3686
}
3787
}
3888
}

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Runtime.Intrinsics;
56

67
namespace System.Numerics.Tensors
@@ -75,9 +76,57 @@ public static void Lerp<T>(ReadOnlySpan<T> x, T y, ReadOnlySpan<T> amount, Span<
7576
private readonly struct LerpOperator<T> : ITernaryOperator<T> where T : IFloatingPointIeee754<T>
7677
{
7778
public static T Invoke(T x, T y, T amount) => T.Lerp(x, y, amount);
78-
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y, Vector128<T> amount) => (x * (Vector128<T>.One - amount)) + (y * amount);
79-
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y, Vector256<T> amount) => (x * (Vector256<T>.One - amount)) + (y * amount);
80-
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y, Vector512<T> amount) => (x * (Vector512<T>.One - amount)) + (y * amount);
79+
80+
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y, Vector128<T> amount)
81+
{
82+
#if NET9_0_OR_GREATER
83+
if (typeof(T) == typeof(double))
84+
{
85+
return Vector128.Lerp(x.AsDouble(), y.AsDouble(), amount.AsDouble()).As<double, T>();
86+
}
87+
else
88+
{
89+
Debug.Assert(typeof(T) == typeof(float));
90+
return Vector128.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As<float, T>();
91+
}
92+
#else
93+
return (x * (Vector128<T>.One - amount)) + (y * amount);
94+
#endif
95+
}
96+
97+
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y, Vector256<T> amount)
98+
{
99+
#if NET9_0_OR_GREATER
100+
if (typeof(T) == typeof(double))
101+
{
102+
return Vector256.Lerp(x.AsDouble(), y.AsDouble(), amount.AsDouble()).As<double, T>();
103+
}
104+
else
105+
{
106+
Debug.Assert(typeof(T) == typeof(float));
107+
return Vector256.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As<float, T>();
108+
}
109+
#else
110+
return (x * (Vector256<T>.One - amount)) + (y * amount);
111+
#endif
112+
}
113+
114+
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y, Vector512<T> amount)
115+
{
116+
#if NET9_0_OR_GREATER
117+
if (typeof(T) == typeof(double))
118+
{
119+
return Vector512.Lerp(x.AsDouble(), y.AsDouble(), amount.AsDouble()).As<double, T>();
120+
}
121+
else
122+
{
123+
Debug.Assert(typeof(T) == typeof(float));
124+
return Vector512.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As<float, T>();
125+
}
126+
#else
127+
return (x * (Vector512<T>.One - amount)) + (y * amount);
128+
#endif
129+
}
81130
}
82131
}
83132
}

0 commit comments

Comments
 (0)