Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose the Sin, Cos, and SinCos methods on the Vector types #104848

Merged
merged 17 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2c29f1c
Allow using a more efficient algorithm if twice the vector size is ac…
tannergooding Jul 12, 2024
006a24a
Remove an unnecessary generic parameter from ExpDouble
tannergooding Jul 12, 2024
2e5d80a
Expose the Sin, Cos, and SinCos methods on the Vector types
tannergooding Jul 13, 2024
5e7012b
Use the vector Sin, Cos, and SinCos methods where possible
tannergooding Jul 13, 2024
19183c5
Adding tests covering the vector Sin, Cos, and SinCos APIs
tannergooding Jul 13, 2024
549ef80
Fix some small bugs in the Sin, Cos, and SinCos impls
tannergooding Jul 13, 2024
a1318a5
Ensure that very large inputs are handled
tannergooding Jul 15, 2024
d35f3ac
Ensure region is correctly adjusted when determining the sign of sin
tannergooding Jul 15, 2024
771cd7b
Merge remote-tracking branch 'dotnet/main' into fix-93513
tannergooding Jul 15, 2024
a71604b
Ensure that TernaryLogic lowering accounts for AND_NOT since it is no…
tannergooding Jul 15, 2024
1b0b07b
Don't vectorize too large SinPi or CosPi inputs for TensorPrimitives
tannergooding Jul 16, 2024
d52bc9b
Don't accelerate SinCosPi for the time being
tannergooding Jul 16, 2024
f225aa0
Don't accelerate TensorPrimitives.SinCos for the time being
tannergooding Jul 16, 2024
3a27c84
Don't include JIT changes, they were extracted to their own PR
tannergooding Jul 18, 2024
c3a88ea
Merge branch 'main' into fix-93513
tannergooding Jul 18, 2024
4e4a226
Merge branch 'main' into fix-93513
tannergooding Jul 19, 2024
d8f6587
Merge branch 'main' into fix-93513
tannergooding Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 245 additions & 1 deletion src/libraries/Common/tests/System/GenericMathTestMemberData.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,24 @@ public static void Cos<T>(ReadOnlySpan<T> x, Span<T> destination)
// 3. Reconstruction
// Hence, cos(x) = sin(x + pi/2) = (-1)^N * sin(f)

public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));

public static T Invoke(T x) => T.Cos(x);

public static Vector128<T> Invoke(Vector128<T> x)
{
#if NET9_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector128.Cos(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector128.Cos(x.AsSingle()).As<float, T>();
}
#else
if (typeof(T) == typeof(float))
{
return CosOperatorSingle.Invoke(x.AsSingle()).As<float, T>();
Expand All @@ -75,10 +87,22 @@ public static Vector128<T> Invoke(Vector128<T> x)
Debug.Assert(typeof(T) == typeof(double));
return CosOperatorDouble.Invoke(x.AsDouble()).As<double, T>();
}
#endif
}

public static Vector256<T> Invoke(Vector256<T> x)
{
#if NET9_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector256.Cos(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector256.Cos(x.AsSingle()).As<float, T>();
}
#else
if (typeof(T) == typeof(float))
{
return CosOperatorSingle.Invoke(x.AsSingle()).As<float, T>();
Expand All @@ -88,10 +112,22 @@ public static Vector256<T> Invoke(Vector256<T> x)
Debug.Assert(typeof(T) == typeof(double));
return CosOperatorDouble.Invoke(x.AsDouble()).As<double, T>();
}
#endif
}

public static Vector512<T> Invoke(Vector512<T> x)
{
#if NET9_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector512.Cos(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector512.Cos(x.AsSingle()).As<float, T>();
}
#else
if (typeof(T) == typeof(float))
{
return CosOperatorSingle.Invoke(x.AsSingle()).As<float, T>();
Expand All @@ -101,9 +137,25 @@ public static Vector512<T> Invoke(Vector512<T> x)
Debug.Assert(typeof(T) == typeof(double));
return CosOperatorDouble.Invoke(x.AsDouble()).As<double, T>();
}
#endif
}
}

#if NET9_0_OR_GREATER
// These are still used by CosPiOperator

private readonly struct CosOperatorSingle
{
internal const uint MaxVectorizedValue = 0x4A989680u;
internal const uint SignMask = 0x7FFFFFFFu;
}

private readonly struct CosOperatorDouble
{
internal const ulong SignMask = 0x7FFFFFFFFFFFFFFFul;
internal const ulong MaxVectorizedValue = 0x4160000000000000ul;
}
#else
/// <summary>float.Cos(x)</summary>
private readonly struct CosOperatorSingle : IUnaryOperator<float, float>
{
Expand Down Expand Up @@ -347,5 +399,6 @@ public static Vector512<double> Invoke(Vector512<double> x)
return (poly.AsUInt64() ^ odd).AsDouble();
}
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ public static void CosPi<T>(ReadOnlySpan<T> x, Span<T> destination)
private readonly struct CosPiOperator<T> : IUnaryOperator<T, T>
where T : ITrigonometricFunctions<T>
{
public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));

public static T Invoke(T x) => T.CosPi(x);

public static Vector128<T> Invoke(Vector128<T> x)
{
Vector128<T> xpi = x * Vector128.Create(T.Pi);

if (typeof(T) == typeof(float))
{
if (Vector128.GreaterThanAny(xpi.AsUInt32() & Vector128.Create(CosOperatorSingle.SignMask), Vector128.Create(CosOperatorSingle.MaxVectorizedValue)))
Expand All @@ -62,6 +64,7 @@ public static Vector128<T> Invoke(Vector128<T> x)
public static Vector256<T> Invoke(Vector256<T> x)
{
Vector256<T> xpi = x * Vector256.Create(T.Pi);

if (typeof(T) == typeof(float))
{
if (Vector256.GreaterThanAny(xpi.AsUInt32() & Vector256.Create(CosOperatorSingle.SignMask), Vector256.Create(CosOperatorSingle.MaxVectorizedValue)))
Expand All @@ -84,6 +87,7 @@ public static Vector256<T> Invoke(Vector256<T> x)
public static Vector512<T> Invoke(Vector512<T> x)
{
Vector512<T> xpi = x * Vector512.Create(T.Pi);

if (typeof(T) == typeof(float))
{
if (Vector512.GreaterThanAny(xpi.AsUInt32() & Vector512.Create(CosOperatorSingle.SignMask), Vector512.Create(CosOperatorSingle.MaxVectorizedValue)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,79 @@ private static Vector256<double> ApplyScalar<TOperator>(Vector256<double> double

private static Vector512<double> ApplyScalar<TOperator>(Vector512<double> doubles) where TOperator : IUnaryOperator<double, double> =>
Vector512.Create(ApplyScalar<TOperator>(doubles.GetLower()), ApplyScalar<TOperator>(doubles.GetUpper()));

private static (Vector128<float> First, Vector128<float> Second) Apply2xScalar<TOperator>(Vector128<float> floats)
where TOperator : IUnaryInputBinaryOutput<float>
{
(float firstRes0, float secondRes0) = TOperator.Invoke(floats[0]);
(float firstRes1, float secondRes1) = TOperator.Invoke(floats[1]);
(float firstRes2, float secondRes2) = TOperator.Invoke(floats[2]);
(float firstRes3, float secondRes3) = TOperator.Invoke(floats[3]);

return (
Vector128.Create(firstRes0, firstRes1, firstRes2, firstRes3),
Vector128.Create(secondRes0, secondRes1, secondRes2, secondRes3)
);
}

private static (Vector256<float> First, Vector256<float> Second) Apply2xScalar<TOperator>(Vector256<float> floats)
where TOperator : IUnaryInputBinaryOutput<float>
{
(Vector128<float> firstLower, Vector128<float> secondLower) = Apply2xScalar<TOperator>(floats.GetLower());
(Vector128<float> firstUpper, Vector128<float> secondUpper) = Apply2xScalar<TOperator>(floats.GetUpper());

return (
Vector256.Create(firstLower, firstUpper),
Vector256.Create(secondLower, secondUpper)
);
}

private static (Vector512<float> First, Vector512<float> Second) Apply2xScalar<TOperator>(Vector512<float> floats)
where TOperator : IUnaryInputBinaryOutput<float>
{
(Vector256<float> firstLower, Vector256<float> secondLower) = Apply2xScalar<TOperator>(floats.GetLower());
(Vector256<float> firstUpper, Vector256<float> secondUpper) = Apply2xScalar<TOperator>(floats.GetUpper());

return (
Vector512.Create(firstLower, firstUpper),
Vector512.Create(secondLower, secondUpper)
);
}

private static (Vector128<double> First, Vector128<double> Second) Apply2xScalar<TOperator>(Vector128<double> doubles)
where TOperator : IUnaryInputBinaryOutput<double>
{
(double firstRes0, double secondRes0) = TOperator.Invoke(doubles[0]);
(double firstRes1, double secondRes1) = TOperator.Invoke(doubles[1]);

return (
Vector128.Create(firstRes0, firstRes1),
Vector128.Create(secondRes0, secondRes1)
);
}

private static (Vector256<double> First, Vector256<double> Second) Apply2xScalar<TOperator>(Vector256<double> doubles)
where TOperator : IUnaryInputBinaryOutput<double>
{
(Vector128<double> firstLower, Vector128<double> secondLower) = Apply2xScalar<TOperator>(doubles.GetLower());
(Vector128<double> firstUpper, Vector128<double> secondUpper) = Apply2xScalar<TOperator>(doubles.GetUpper());

return (
Vector256.Create(firstLower, firstUpper),
Vector256.Create(secondLower, secondUpper)
);
}

private static (Vector512<double> First, Vector512<double> Second) Apply2xScalar<TOperator>(Vector512<double> doubles)
where TOperator : IUnaryInputBinaryOutput<double>
{
(Vector256<double> firstLower, Vector256<double> secondLower) = Apply2xScalar<TOperator>(doubles.GetLower());
(Vector256<double> firstUpper, Vector256<double> secondUpper) = Apply2xScalar<TOperator>(doubles.GetUpper());

return (
Vector512.Create(firstLower, firstUpper),
Vector512.Create(secondLower, secondUpper)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,24 @@ public static void Sin<T>(ReadOnlySpan<T> x, Span<T> destination)
//
// The term sin(f) can be approximated by using a polynomial

public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));

public static T Invoke(T x) => T.Sin(x);

public static Vector128<T> Invoke(Vector128<T> x)
{
#if NET9_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector128.Sin(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector128.Sin(x.AsSingle()).As<float, T>();
}
#else
if (typeof(T) == typeof(float))
{
return SinOperatorSingle.Invoke(x.AsSingle()).As<float, T>();
Expand All @@ -65,10 +77,22 @@ public static Vector128<T> Invoke(Vector128<T> x)
Debug.Assert(typeof(T) == typeof(double));
return SinOperatorDouble.Invoke(x.AsDouble()).As<double, T>();
}
#endif
}

public static Vector256<T> Invoke(Vector256<T> x)
{
#if NET9_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector256.Sin(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector256.Sin(x.AsSingle()).As<float, T>();
}
#else
if (typeof(T) == typeof(float))
{
return SinOperatorSingle.Invoke(x.AsSingle()).As<float, T>();
Expand All @@ -78,10 +102,22 @@ public static Vector256<T> Invoke(Vector256<T> x)
Debug.Assert(typeof(T) == typeof(double));
return SinOperatorDouble.Invoke(x.AsDouble()).As<double, T>();
}
#endif
}

public static Vector512<T> Invoke(Vector512<T> x)
{
#if NET9_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector512.Sin(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector512.Sin(x.AsSingle()).As<float, T>();
}
#else
if (typeof(T) == typeof(float))
{
return SinOperatorSingle.Invoke(x.AsSingle()).As<float, T>();
Expand All @@ -91,9 +127,25 @@ public static Vector512<T> Invoke(Vector512<T> x)
Debug.Assert(typeof(T) == typeof(double));
return SinOperatorDouble.Invoke(x.AsDouble()).As<double, T>();
}
#endif
}
}

#if NET9_0_OR_GREATER
// These are still used by SinPiOperator

private readonly struct SinOperatorSingle
{
internal const uint MaxVectorizedValue = 0x49800000u;
internal const uint SignMask = 0x7FFFFFFFu;
}

private readonly struct SinOperatorDouble
{
internal const ulong SignMask = 0x7FFFFFFFFFFFFFFFul;
internal const ulong MaxVectorizedValue = 0x4160000000000000ul;
}
#else
/// <summary>float.Sin(x)</summary>
private readonly struct SinOperatorSingle : IUnaryOperator<float, float>
{
Expand Down Expand Up @@ -334,5 +386,6 @@ public static Vector512<double> Invoke(Vector512<double> x)
return (poly.AsUInt64() ^ (x.AsUInt64() & Vector512.Create(~SignMask)) ^ odd).AsDouble();
}
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ public static void SinPi<T>(ReadOnlySpan<T> x, Span<T> destination)
private readonly struct SinPiOperator<T> : IUnaryOperator<T, T>
where T : ITrigonometricFunctions<T>
{
public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));

public static T Invoke(T x) => T.SinPi(x);

public static Vector128<T> Invoke(Vector128<T> x)
{
Vector128<T> xpi = x * Vector128.Create(T.Pi);

if (typeof(T) == typeof(float))
{
if (Vector128.GreaterThanAny(xpi.AsUInt32() & Vector128.Create(SinOperatorSingle.SignMask), Vector128.Create(SinOperatorSingle.MaxVectorizedValue)))
Expand All @@ -62,6 +64,7 @@ public static Vector128<T> Invoke(Vector128<T> x)
public static Vector256<T> Invoke(Vector256<T> x)
{
Vector256<T> xpi = x * Vector256.Create(T.Pi);

if (typeof(T) == typeof(float))
{
if (Vector256.GreaterThanAny(xpi.AsUInt32() & Vector256.Create(SinOperatorSingle.SignMask), Vector256.Create(SinOperatorSingle.MaxVectorizedValue)))
Expand All @@ -84,6 +87,7 @@ public static Vector256<T> Invoke(Vector256<T> x)
public static Vector512<T> Invoke(Vector512<T> x)
{
Vector512<T> xpi = x * Vector512.Create(T.Pi);

if (typeof(T) == typeof(float))
{
if (Vector512.GreaterThanAny(xpi.AsUInt32() & Vector512.Create(SinOperatorSingle.SignMask), Vector512.Create(SinOperatorSingle.MaxVectorizedValue)))
Expand Down
Loading
Loading