Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9311378
Initial plan
Copilot Jan 26, 2026
6847744
Add vectorized Asin implementation for TensorPrimitives
Copilot Jan 26, 2026
b6501fe
Implement Asin vectorization internally without adding public APIs
Copilot Jan 26, 2026
108d874
Restore public Vector Asin APIs with proper ref assembly support
Copilot Jan 26, 2026
8cb6803
Add tolerance for Asin tests matching Sin/Cos
Copilot Jan 27, 2026
7943b00
Adjust Asin test tolerance to account for algorithm precision
Copilot Jan 27, 2026
7e0c5d1
Vectorize Acos operation for TensorPrimitives
Copilot Jan 27, 2026
71e1be3
Vectorize Atan operation for TensorPrimitives following Asin/Acos pat…
Copilot Jan 27, 2026
1bbc861
Vectorize Atan2 operation for TensorPrimitives following binary op pa…
Copilot Jan 27, 2026
6fa33c1
Fix redundant recip variable in Atan2 implementation
Copilot Jan 27, 2026
60668a7
Add vectorized Asinh support to TensorPrimitives
Copilot Jan 27, 2026
316e81b
Vectorize Acosh operation for TensorPrimitives following Asinh pattern
Copilot Jan 27, 2026
dafe823
Vectorize Atanh operation for TensorPrimitives following Asinh/Acosh …
Copilot Jan 29, 2026
7040114
Add test tolerances for AsinPi, AcosPi, AtanPi, and Atan2Pi functions
Copilot Jan 29, 2026
955b91c
Fix Atan2 quadrant handling by using atan(y/x) directly
Copilot Jan 29, 2026
53e088a
Fix IEEE 754 special value handling for Atan2 and Atanh
Copilot Jan 29, 2026
a94eea8
Fix TensorExtensionsTwoSpanInSpanOut tests for Atan2/Atan2Pi
Copilot Jan 29, 2026
5e68168
Merge branch 'main' into copilot/port-amd-vector-implementations
stephentoub Feb 3, 2026
decfa9c
Simplify TensorPrimitives vectorization for NET11_0 only
Copilot Feb 3, 2026
c0dd9ab
Merge branch 'main' into copilot/port-amd-vector-implementations
stephentoub Feb 5, 2026
b496a03
Fix AMD AOCL-LibM source attribution headers in VectorMath.cs
Copilot Feb 5, 2026
9b8ab06
Revert to scalar fallback for Asin - need guidance on implementation …
Copilot Feb 5, 2026
d4e4220
Implement proper AMD AOCL-LibM ports for Asin, Acos, Atan
Copilot Feb 6, 2026
35b50f2
Port AMD atanh polynomial and update headers for remaining functions
Copilot Feb 6, 2026
70515de
Port AMD single-precision implementations for asinf, acosf, atanf, at…
Copilot Feb 6, 2026
4789d6f
Fix AtanSingle Remez(2,2) polynomial evaluation
Copilot Feb 6, 2026
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.Intrinsics;

namespace System.Numerics.Tensors
Expand Down Expand Up @@ -29,11 +30,79 @@ public static void Acos<T>(ReadOnlySpan<T> x, Span<T> destination)
private readonly struct AcosOperator<T> : IUnaryOperator<T, T>
where T : ITrigonometricFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
// This code is based on `vrs4_acosf` and `acosf` from amd/aocl-libm-ose
// Copyright (C) 2008-2022 Advanced Micro Devices, Inc. All rights reserved.
//
// Licensed under the BSD 3-Clause "New" or "Revised" License
// See THIRD-PARTY-NOTICES.TXT for the full license text

// Implementation Notes
// --------------------
// The input domain should be in the [-1, +1] else a domain error is displayed
//
// acos(x) = pi/2 - asin(x) when |x| <= 0.5
// acos(x) = 2*asin(sqrt((1-x)/2)) when x > 0.5
// acos(x) = pi - 2*asin(sqrt((1+x)/2)) when x < -0.5

#if NET11_0_OR_GREATER
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));
#else
public static bool Vectorizable => false;
#endif

public static T Invoke(T x) => T.Acos(x);
public static Vector128<T> Invoke(Vector128<T> x) => throw new NotSupportedException();
public static Vector256<T> Invoke(Vector256<T> x) => throw new NotSupportedException();
public static Vector512<T> Invoke(Vector512<T> x) => throw new NotSupportedException();

public static Vector128<T> Invoke(Vector128<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector128.Acos(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector128.Acos(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector256<T> Invoke(Vector256<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector256.Acos(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector256.Acos(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector512<T> Invoke(Vector512<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector512.Acos(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector512.Acos(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.Intrinsics;

namespace System.Numerics.Tensors
Expand All @@ -26,14 +27,79 @@ public static void Acosh<T>(ReadOnlySpan<T> x, Span<T> destination)
InvokeSpanIntoSpan<T, AcoshOperator<T>>(x, destination);

/// <summary>T.Acosh(x)</summary>
private readonly struct AcoshOperator<T> : IUnaryOperator<T, T>
internal readonly struct AcoshOperator<T> : IUnaryOperator<T, T>
where T : IHyperbolicFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
// This code is based on `acoshf` from amd/aocl-libm-ose
// Copyright (C) 2021-2022 Advanced Micro Devices, Inc. All rights reserved.
//
// Licensed under the BSD 3-Clause "New" or "Revised" License
// See THIRD-PARTY-NOTICES.TXT for the full license text

// Implementation Notes
// --------------------
// acosh(x) = log(x + sqrt(x^2 - 1))
// Domain: x >= 1

#if NET11_0_OR_GREATER
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));
#else
public static bool Vectorizable => false;
#endif

public static T Invoke(T x) => T.Acosh(x);
public static Vector128<T> Invoke(Vector128<T> x) => throw new NotSupportedException();
public static Vector256<T> Invoke(Vector256<T> x) => throw new NotSupportedException();
public static Vector512<T> Invoke(Vector512<T> x) => throw new NotSupportedException();

public static Vector128<T> Invoke(Vector128<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector128.Acosh(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector128.Acosh(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector256<T> Invoke(Vector256<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector256.Acosh(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector256.Acosh(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector512<T> Invoke(Vector512<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector512.Acosh(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector512.Acosh(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.Intrinsics;

namespace System.Numerics.Tensors
Expand Down Expand Up @@ -29,11 +30,83 @@ public static void Asin<T>(ReadOnlySpan<T> x, Span<T> destination)
private readonly struct AsinOperator<T> : IUnaryOperator<T, T>
where T : ITrigonometricFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
// This code is based on `vrs4_asinf` and `asinf` from amd/aocl-libm-ose
// Copyright (C) 2008-2022 Advanced Micro Devices, Inc. All rights reserved.
//
// Licensed under the BSD 3-Clause "New" or "Revised" License
// See THIRD-PARTY-NOTICES.TXT for the full license text

// Implementation Notes
// --------------------
// The input domain should be in the [-1, +1] else a domain error is displayed
//
// asin(-x) = -asin(x)
// asin(x) = pi/2-2*asin(sqrt(1/2*(1-x))) when x > 1/2
//
// y = abs(x)
// asin(y) = asin(g) when y <= 0.5, where g = y*y
// = pi/2-asin(g) when y > 0.5, where g = 1/2*(1-y), y = -2*sqrt(g)
// The term asin(f) is approximated by using a polynomial

#if NET11_0_OR_GREATER
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));
#else
public static bool Vectorizable => false;
#endif

public static T Invoke(T x) => T.Asin(x);
public static Vector128<T> Invoke(Vector128<T> x) => throw new NotSupportedException();
public static Vector256<T> Invoke(Vector256<T> x) => throw new NotSupportedException();
public static Vector512<T> Invoke(Vector512<T> x) => throw new NotSupportedException();

public static Vector128<T> Invoke(Vector128<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector128.Asin(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector128.Asin(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector256<T> Invoke(Vector256<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector256.Asin(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector256.Asin(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector512<T> Invoke(Vector512<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector512.Asin(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector512.Asin(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.Intrinsics;

namespace System.Numerics.Tensors
Expand Down Expand Up @@ -29,11 +30,75 @@ public static void Asinh<T>(ReadOnlySpan<T> x, Span<T> destination)
internal readonly struct AsinhOperator<T> : IUnaryOperator<T, T>
where T : IHyperbolicFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
// This code is based on `asinhf` from amd/aocl-libm-ose
// Copyright (C) 2021-2022 Advanced Micro Devices, Inc. All rights reserved.
//
// Licensed under the BSD 3-Clause "New" or "Revised" License
// See THIRD-PARTY-NOTICES.TXT for the full license text

// Implementation Notes
// --------------------
// asinh(x) = sign(x) * log(|x| + sqrt(x^2 + 1))

#if NET11_0_OR_GREATER
public static bool Vectorizable => (typeof(T) == typeof(float))
|| (typeof(T) == typeof(double));
#else
public static bool Vectorizable => false;
#endif

public static T Invoke(T x) => T.Asinh(x);
public static Vector128<T> Invoke(Vector128<T> x) => throw new NotSupportedException();
public static Vector256<T> Invoke(Vector256<T> x) => throw new NotSupportedException();
public static Vector512<T> Invoke(Vector512<T> x) => throw new NotSupportedException();

public static Vector128<T> Invoke(Vector128<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector128.Asinh(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector128.Asinh(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector256<T> Invoke(Vector256<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector256.Asinh(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector256.Asinh(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}

public static Vector512<T> Invoke(Vector512<T> x)
{
#if NET11_0_OR_GREATER
if (typeof(T) == typeof(double))
{
return Vector512.Asinh(x.AsDouble()).As<double, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(float));
return Vector512.Asinh(x.AsSingle()).As<float, T>();
}
#else
throw new NotSupportedException();
#endif
}
}
}
}
Loading
Loading