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

Vectorize TensorPrimitives.Pow, Exp2, Exp10, Cbrt, RootN, Hypot, Log(x,y), Log10 #97623

Merged
merged 7 commits into from
Jan 30, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -12736,12 +12736,14 @@ public static Vector512<float> Invoke(Vector512<float> x)
internal readonly struct Exp2Operator<T> : IUnaryOperator<T, T>
where T : IExponentialFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
private const double NaturalLog2 = 0.6931471805599453;

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

public static T Invoke(T x) => T.Exp2(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) => ExpOperator<T>.Invoke(x * Vector128.Create(T.CreateTruncating(NaturalLog2)));
public static Vector256<T> Invoke(Vector256<T> x) => ExpOperator<T>.Invoke(x * Vector256.Create(T.CreateTruncating(NaturalLog2)));
public static Vector512<T> Invoke(Vector512<T> x) => ExpOperator<T>.Invoke(x * Vector512.Create(T.CreateTruncating(NaturalLog2)));
}

/// <summary>T.Exp2M1(x)</summary>
Expand All @@ -12760,12 +12762,14 @@ public static Vector512<float> Invoke(Vector512<float> x)
internal readonly struct Exp10Operator<T> : IUnaryOperator<T, T>
where T : IExponentialFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
private const double NaturalLog10 = 2.302585092994046;

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

public static T Invoke(T x) => T.Exp10(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) => ExpOperator<T>.Invoke(x * Vector128.Create(T.CreateTruncating(NaturalLog10)));
public static Vector256<T> Invoke(Vector256<T> x) => ExpOperator<T>.Invoke(x * Vector256.Create(T.CreateTruncating(NaturalLog10)));
public static Vector512<T> Invoke(Vector512<T> x) => ExpOperator<T>.Invoke(x * Vector512.Create(T.CreateTruncating(NaturalLog10)));
}

/// <summary>T.Exp10M1(x)</summary>
Expand All @@ -12784,11 +12788,48 @@ public static Vector512<float> Invoke(Vector512<float> x)
internal readonly struct PowOperator<T> : IBinaryOperator<T>
where T : IPowerFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);

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

public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(y.AsSingle() * LogOperator<float>.Invoke(x.AsSingle())).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(y.AsDouble() * LogOperator<double>.Invoke(x.AsDouble())).As<double, T>();
}
}

public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(y.AsSingle() * LogOperator<float>.Invoke(x.AsSingle())).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(y.AsDouble() * LogOperator<double>.Invoke(x.AsDouble())).As<double, T>();
}
}

public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(y.AsSingle() * LogOperator<float>.Invoke(x.AsSingle())).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(y.AsDouble() * LogOperator<double>.Invoke(x.AsDouble())).As<double, T>();
}
}
}

/// <summary>T.Sqrt(x)</summary>
Expand All @@ -12806,22 +12847,59 @@ public static Vector512<float> Invoke(Vector512<float> x)
internal readonly struct CbrtOperator<T> : IUnaryOperator<T, T>
where T : IRootFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);

public static T Invoke(T x) => T.Cbrt(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 (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(LogOperator<float>.Invoke(x.AsSingle()) / Vector128.Create(3f)).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(LogOperator<double>.Invoke(x.AsDouble()) / Vector128.Create(3d)).As<double, T>();
}
}

public static Vector256<T> Invoke(Vector256<T> x)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(LogOperator<float>.Invoke(x.AsSingle()) / Vector256.Create(3f)).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(LogOperator<double>.Invoke(x.AsDouble()) / Vector256.Create(3d)).As<double, T>();
}
}

public static Vector512<T> Invoke(Vector512<T> x)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(LogOperator<float>.Invoke(x.AsSingle()) / Vector512.Create(3f)).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(LogOperator<double>.Invoke(x.AsDouble()) / Vector512.Create(3d)).As<double, T>();
}
}
}

/// <summary>T.Hypot(x, y)</summary>
internal readonly struct HypotOperator<T> : IBinaryOperator<T>
where T : IRootFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
public static bool Vectorizable => true;
public static T Invoke(T x, T y) => T.Hypot(x, y);
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y) => throw new NotSupportedException();
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y) => throw new NotSupportedException();
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y) => throw new NotSupportedException();
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y) => Vector128.Sqrt((x * x) + (y * y));
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y) => Vector256.Sqrt((x * x) + (y * y));
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y) => Vector512.Sqrt((x * x) + (y * y));
}

/// <summary>T.Acos(x)</summary>
Expand Down Expand Up @@ -14546,11 +14624,12 @@ public static Vector512<float> Invoke(Vector512<float> x)
internal readonly struct Log10Operator<T> : IUnaryOperator<T, T>
where T : ILogarithmicFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
private static readonly double s_log10 = Math.Log(10d);
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
public static bool Vectorizable => LogOperator<T>.Vectorizable;
public static T Invoke(T x) => T.Log10(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) => LogOperator<T>.Invoke(x) / Vector128.Create(T.CreateTruncating(s_log10));
public static Vector256<T> Invoke(Vector256<T> x) => LogOperator<T>.Invoke(x) / Vector256.Create(T.CreateTruncating(s_log10));
public static Vector512<T> Invoke(Vector512<T> x) => LogOperator<T>.Invoke(x) / Vector512.Create(T.CreateTruncating(s_log10));
}

/// <summary>T.LogP1(x)</summary>
Expand Down Expand Up @@ -14590,11 +14669,11 @@ public static Vector512<float> Invoke(Vector512<float> x)
internal readonly struct LogBaseOperator<T> : IBinaryOperator<T>
where T : ILogarithmicFunctions<T>
{
public static bool Vectorizable => false; // TODO: Vectorize
public static bool Vectorizable => LogOperator<T>.Vectorizable;
public static T Invoke(T x, T y) => T.Log(x, y);
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y) => throw new NotSupportedException();
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y) => throw new NotSupportedException();
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y) => throw new NotSupportedException();
public static Vector128<T> Invoke(Vector128<T> x, Vector128<T> y) => LogOperator<T>.Invoke(x) / LogOperator<T>.Invoke(y);
public static Vector256<T> Invoke(Vector256<T> x, Vector256<T> y) => LogOperator<T>.Invoke(x) / LogOperator<T>.Invoke(y);
public static Vector512<T> Invoke(Vector512<T> x, Vector512<T> y) => LogOperator<T>.Invoke(x) / LogOperator<T>.Invoke(y);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down Expand Up @@ -15063,13 +15142,48 @@ internal readonly struct RootNOperator<T>(int n) : IStatefulUnaryOperator<T> whe
{
private readonly int _n = n;

public static bool Vectorizable => false; // TODO: Vectorize
public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double);

public T Invoke(T x) => T.RootN(x, _n);

public Vector128<T> Invoke(Vector128<T> x) => throw new NotSupportedException();
public Vector256<T> Invoke(Vector256<T> x) => throw new NotSupportedException();
public Vector512<T> Invoke(Vector512<T> x) => throw new NotSupportedException();
public Vector128<T> Invoke(Vector128<T> x)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(LogOperator<float>.Invoke(x.AsSingle()) / Vector128.Create((float)_n)).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(LogOperator<double>.Invoke(x.AsDouble()) / Vector128.Create((double)_n)).As<double, T>();
}
}

public Vector256<T> Invoke(Vector256<T> x)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(LogOperator<float>.Invoke(x.AsSingle()) / Vector256.Create((float)_n)).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(LogOperator<double>.Invoke(x.AsDouble()) / Vector256.Create((double)_n)).As<double, T>();
}
}

public Vector512<T> Invoke(Vector512<T> x)
{
if (typeof(T) == typeof(float))
{
return ExpOperator<float>.Invoke(LogOperator<float>.Invoke(x.AsSingle()) / Vector512.Create((float)_n)).As<float, T>();
}
else
{
Debug.Assert(typeof(T) == typeof(double));
return ExpOperator<double>.Invoke(LogOperator<double>.Invoke(x.AsDouble()) / Vector512.Create((double)_n)).As<double, T>();
}
}
}

/// <summary>T.Round</summary>
Expand Down
Loading