Add Vector3<TLane, TNumber>
This commit is contained in:
@@ -128,7 +128,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
get
|
get
|
||||||
{{
|
{{
|
||||||
RangeCheck(index);
|
RangeCheck(index);
|
||||||
return ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
return ref global::System.Runtime.CompilerServices.Unsafe.Add(ref {s_vectorComponents[0]}, index);
|
||||||
}}
|
}}
|
||||||
}}");
|
}}");
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,20 @@ internal struct SPMDJobWrapper<T, TNumber> : IJobParallelFor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal struct SPMDScalerJobWrapper<T, TNumber> : IJobParallelFor
|
||||||
|
where T : unmanaged, IJobSPMD<TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
public T innerJob;
|
||||||
|
public int totalCount;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Execute(int loopIndex, int threadIndex)
|
||||||
|
{
|
||||||
|
innerJob.Execute<ScalarLane<TNumber>>(loopIndex, threadIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class IJobParallelForSPMDExtensions
|
public static class IJobParallelForSPMDExtensions
|
||||||
{
|
{
|
||||||
public static void Run<T, TNumber>(this ref T job, int totalCount, int threadIndex)
|
public static void Run<T, TNumber>(this ref T job, int totalCount, int threadIndex)
|
||||||
@@ -68,13 +82,26 @@ public static class IJobParallelForSPMDExtensions
|
|||||||
where T : unmanaged, IJobSPMD<TNumber>
|
where T : unmanaged, IJobSPMD<TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
var warper = new SPMDJobWrapper<T, TNumber>
|
if (WideLane.IsSupported)
|
||||||
{
|
{
|
||||||
innerJob = job,
|
var warper = new SPMDJobWrapper<T, TNumber>
|
||||||
totalCount = totalCount,
|
{
|
||||||
};
|
innerJob = job,
|
||||||
|
totalCount = totalCount,
|
||||||
|
};
|
||||||
|
|
||||||
var iterations = (totalCount + WideLane<TNumber>.LaneWidth - 1) / WideLane<TNumber>.LaneWidth;
|
var iterations = (totalCount + WideLane<TNumber>.LaneWidth - 1) / WideLane<TNumber>.LaneWidth;
|
||||||
return jobScheduler.ScheduleParallel(ref warper, iterations, batchSize, threadIndex, dependency);
|
return jobScheduler.ScheduleParallel(ref warper, iterations, batchSize, threadIndex, dependency);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var warper = new SPMDScalerJobWrapper<T, TNumber>
|
||||||
|
{
|
||||||
|
innerJob = job,
|
||||||
|
totalCount = totalCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
return jobScheduler.ScheduleParallel(ref warper, totalCount, batchSize, threadIndex, dependency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
@@ -18,12 +16,20 @@ public interface ISPMD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - ReduceAdd
|
||||||
|
// - ReduceMin
|
||||||
|
// - ReduceMax
|
||||||
|
// - LeadingZeroCount
|
||||||
|
// - TrailingZeroCount
|
||||||
|
// - PopCount
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single-lane or multi-lane (vectorized) SPMD value and the operations supported on it.
|
/// Represents a single-lane or multi-lane (vectorized) SPMD value and the operations supported on it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TSelf">The concrete SPMD lane type implementing this interface.</typeparam>
|
/// <typeparam name="TSelf">The concrete SPMD lane type implementing this interface.</typeparam>
|
||||||
/// <typeparam name="TNumber">The underlying numeric element type.</typeparam>
|
/// <typeparam name="TNumber">The underlying numeric element type.</typeparam>
|
||||||
public interface ISPMD<TSelf, TNumber> : ISPMD
|
public interface ISPMD<TSelf, TNumber> : ISPMD, IEquatable<TSelf>
|
||||||
where TSelf : ISPMD<TSelf, TNumber>
|
where TSelf : ISPMD<TSelf, TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
@@ -159,13 +165,6 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The lane-wise sum.</returns>
|
/// <returns>The lane-wise sum.</returns>
|
||||||
static abstract TSelf operator +(TSelf a, TSelf b);
|
static abstract TSelf operator +(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a lane value and a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The lane value with the scalar added to each element.</returns>
|
|
||||||
static abstract TSelf operator +(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts two lane values element-wise.
|
/// Subtracts two lane values element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The first lane value.</param>
|
/// <param name="a">The first lane value.</param>
|
||||||
@@ -173,13 +172,6 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The lane-wise difference.</returns>
|
/// <returns>The lane-wise difference.</returns>
|
||||||
static abstract TSelf operator -(TSelf a, TSelf b);
|
static abstract TSelf operator -(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subtracts a scalar from a lane value element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The lane value with the scalar subtracted from each element.</returns>
|
|
||||||
static abstract TSelf operator -(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies two lane values element-wise.
|
/// Multiplies two lane values element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The first lane value.</param>
|
/// <param name="a">The first lane value.</param>
|
||||||
@@ -187,13 +179,6 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The lane-wise product.</returns>
|
/// <returns>The lane-wise product.</returns>
|
||||||
static abstract TSelf operator *(TSelf a, TSelf b);
|
static abstract TSelf operator *(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiplies a lane value by a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The lane value scaled by the scalar.</returns>
|
|
||||||
static abstract TSelf operator *(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Divides two lane values element-wise.
|
/// Divides two lane values element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The first lane value.</param>
|
/// <param name="a">The first lane value.</param>
|
||||||
@@ -201,26 +186,12 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The lane-wise quotient.</returns>
|
/// <returns>The lane-wise quotient.</returns>
|
||||||
static abstract TSelf operator /(TSelf a, TSelf b);
|
static abstract TSelf operator /(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Divides a lane value by a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The lane value divided by the scalar.</returns>
|
|
||||||
static abstract TSelf operator /(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the modulus of two lane values element-wise.
|
/// Computes the modulus of two lane values element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The first lane value.</param>
|
/// <param name="a">The first lane value.</param>
|
||||||
/// <param name="b">The second lane value.</param>
|
/// <param name="b">The second lane value.</param>
|
||||||
/// <returns>The lane-wise modulus.</returns>
|
/// <returns>The lane-wise modulus.</returns>
|
||||||
static abstract TSelf operator %(TSelf a, TSelf b);
|
static abstract TSelf operator %(TSelf a, TSelf b);
|
||||||
/// <summary>
|
|
||||||
/// Computes the modulus of a lane value and a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The lane value modulus scalar.</returns>
|
|
||||||
static abstract TSelf operator %(TSelf a, TNumber b);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Negates the lane value element-wise.
|
/// Negates the lane value element-wise.
|
||||||
@@ -237,13 +208,6 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The result of the bitwise AND.</returns>
|
/// <returns>The result of the bitwise AND.</returns>
|
||||||
static abstract TSelf operator &(TSelf a, TSelf b);
|
static abstract TSelf operator &(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the bitwise AND of a lane value and a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The result of the bitwise AND.</returns>
|
|
||||||
static abstract TSelf operator &(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the bitwise OR of two lane values element-wise.
|
/// Computes the bitwise OR of two lane values element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The first lane value.</param>
|
/// <param name="a">The first lane value.</param>
|
||||||
@@ -251,13 +215,6 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The result of the bitwise OR.</returns>
|
/// <returns>The result of the bitwise OR.</returns>
|
||||||
static abstract TSelf operator |(TSelf a, TSelf b);
|
static abstract TSelf operator |(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the bitwise OR of a lane value and a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The result of the bitwise OR.</returns>
|
|
||||||
static abstract TSelf operator |(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the bitwise XOR of two lane values element-wise.
|
/// Computes the bitwise XOR of two lane values element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The first lane value.</param>
|
/// <param name="a">The first lane value.</param>
|
||||||
@@ -265,18 +222,27 @@ public interface ISPMD<TSelf, TNumber> : ISPMD
|
|||||||
/// <returns>The result of the bitwise XOR.</returns>
|
/// <returns>The result of the bitwise XOR.</returns>
|
||||||
static abstract TSelf operator ^(TSelf a, TSelf b);
|
static abstract TSelf operator ^(TSelf a, TSelf b);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the bitwise XOR of a lane value and a scalar element-wise.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The lane value.</param>
|
|
||||||
/// <param name="b">The scalar value.</param>
|
|
||||||
/// <returns>The result of the bitwise XOR.</returns>
|
|
||||||
static abstract TSelf operator ^(TSelf a, TNumber b);
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the bitwise NOT of a lane value element-wise.
|
/// Computes the bitwise NOT of a lane value element-wise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The lane value.</param>
|
/// <param name="a">The lane value.</param>
|
||||||
/// <returns>The bitwise complement of the lane value.</returns>
|
/// <returns>The bitwise complement of the lane value.</returns>
|
||||||
static abstract TSelf operator ~(TSelf a);
|
static abstract TSelf operator ~(TSelf a);
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether two instances of the type are equal component-wise.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first value to compare.</param>
|
||||||
|
/// <param name="b">The second value to compare.</param>
|
||||||
|
/// <returns>All bits set where the elements are equal; otherwise, all bits cleared.</returns>
|
||||||
|
static abstract TSelf operator ==(TSelf a, TSelf b);
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether two instances of the type are not equal component-wise.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first value to compare.</param>
|
||||||
|
/// <param name="b">The second value to compare.</param>
|
||||||
|
/// <returns>All bits set where the elements are not equal; otherwise, all bits cleared.</returns>
|
||||||
|
static abstract TSelf operator !=(TSelf a, TSelf b);
|
||||||
|
|
||||||
|
static abstract implicit operator TSelf(TNumber value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the absolute value of the lane value element-wise.
|
/// Computes the absolute value of the lane value element-wise.
|
||||||
|
|||||||
153
Misaki.HighPerformance.Mathematics.SPMD/MathV.cs
Normal file
153
Misaki.HighPerformance.Mathematics.SPMD/MathV.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
public static unsafe partial class MathV
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> LoadVector3<TLane, TNumber>(TNumber* pSrc)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
var z = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
x[i] = pSrc[i * 3 + 0];
|
||||||
|
y[i] = pSrc[i * 3 + 1];
|
||||||
|
z[i] = pSrc[i * 3 + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(x),
|
||||||
|
y = TLane.Load(y),
|
||||||
|
z = TLane.Load(z)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(ref TNumber src)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return LoadVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(TNumber* pX, TNumber* pY, TNumber* pZ)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(pX),
|
||||||
|
y = TLane.Load(pY),
|
||||||
|
z = TLane.Load(pZ)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y, ref TNumber z)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(ref x),
|
||||||
|
y = TLane.Load(ref y),
|
||||||
|
z = TLane.Load(ref z)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Abs<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Abs(vector.x),
|
||||||
|
y = TLane.Abs(vector.y),
|
||||||
|
z = TLane.Abs(vector.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Dot<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane LengthSquared<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Dot(vector, vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Sqrt(vector.x),
|
||||||
|
y = TLane.Sqrt(vector.y),
|
||||||
|
z = TLane.Sqrt(vector.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Rsqrt(vector.x),
|
||||||
|
y = TLane.Rsqrt(vector.y),
|
||||||
|
z = TLane.Rsqrt(vector.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Normalize<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Cross<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = a.y * b.z - a.z * b.y,
|
||||||
|
y = a.z * b.x - a.x * b.z,
|
||||||
|
z = a.x * b.y - a.y * b.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Reflect<TLane, TNumber>(in Vector3<TLane, TNumber> incident, in Vector3<TLane, TNumber> normal)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var dot = Dot(incident, normal);
|
||||||
|
return incident - normal * (dot + dot);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
|||||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, TNumber>
|
||||||
where T : unmanaged, INumber<T>, IMinMaxValue<T>, IBitwiseOperators<T, T, T>
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
public readonly T value;
|
public readonly TNumber value;
|
||||||
|
|
||||||
public static int LaneWidth
|
public static int LaneWidth
|
||||||
{
|
{
|
||||||
@@ -16,77 +16,99 @@ public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
|||||||
get => 1;
|
get => 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalarLane<T> Zero
|
public static ScalarLane<TNumber> Zero
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new(T.Zero);
|
get => new(TNumber.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalarLane<T> One
|
public static ScalarLane<TNumber> One
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new(T.One);
|
get => new(TNumber.One);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalarLane<T> MinValue
|
public static ScalarLane<TNumber> MinValue
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new(T.MinValue);
|
get => new(TNumber.MinValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalarLane<T> MaxValue
|
public static ScalarLane<TNumber> MaxValue
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new(T.MaxValue);
|
get => new(TNumber.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly T this[int index]
|
public readonly TNumber this[int index]
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => value;
|
get => value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScalarLane(T value)
|
public ScalarLane(TNumber value)
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Create(T value) => new(value);
|
public static ScalarLane<TNumber> Create(TNumber value)
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Create(params ReadOnlySpan<T> values) => new(values[0]);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Create(Vector<T> value) => new(value[0]);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Sequence(T start, T step) => new(start);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Load(ref T value) => new(value);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Load(T* pValue) => new(*pValue);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void Store(ref T destination) => destination = value;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void Store(T* pDestination) => *pDestination = value;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int CompressStore(ScalarLane<T> mask, ref T destination)
|
|
||||||
{
|
{
|
||||||
return CompressStore(mask, (T*)Unsafe.AsPointer(in destination));
|
return new(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int CompressStore(ScalarLane<T> mask, T* pDestination)
|
public static ScalarLane<TNumber> Create(params ReadOnlySpan<TNumber> values)
|
||||||
{
|
{
|
||||||
if (mask.value != T.Zero)
|
return new(values[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Create(Vector<TNumber> value)
|
||||||
|
{
|
||||||
|
return new(value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Sequence(TNumber start, TNumber step)
|
||||||
|
{
|
||||||
|
return new(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Load(ref TNumber value)
|
||||||
|
{
|
||||||
|
return new(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Load(TNumber* pValue)
|
||||||
|
{
|
||||||
|
return new(*pValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly void Store(ref TNumber destination)
|
||||||
|
{
|
||||||
|
destination = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly void Store(TNumber* pDestination)
|
||||||
|
{
|
||||||
|
*pDestination = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int CompressStore(ScalarLane<TNumber> mask, ref TNumber destination)
|
||||||
|
{
|
||||||
|
return CompressStore(mask, (TNumber*)Unsafe.AsPointer(in destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int CompressStore(ScalarLane<TNumber> mask, TNumber* pDestination)
|
||||||
|
{
|
||||||
|
if (mask.value != TNumber.Zero)
|
||||||
{
|
{
|
||||||
*pDestination = value;
|
*pDestination = value;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -96,299 +118,358 @@ public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly Vector<T> AsVector() => Vector.Create(value);
|
public readonly Vector<TNumber> AsVector()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator +(ScalarLane<T> a, ScalarLane<T> b) => new(a.value + b.value);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator +(ScalarLane<T> a, T b) => new(a.value + b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator -(ScalarLane<T> a, ScalarLane<T> b) => new(a.value - b.value);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator -(ScalarLane<T> a, T b) => new(a.value - b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator *(ScalarLane<T> a, ScalarLane<T> b) => new(a.value * b.value);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator *(ScalarLane<T> a, T b) => new(a.value * b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator /(ScalarLane<T> a, ScalarLane<T> b) => new(a.value / b.value);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator /(ScalarLane<T> a, T b) => new(a.value / b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator %(ScalarLane<T> a, ScalarLane<T> b) => new(a.value % b.value);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator %(ScalarLane<T> a, T b) => new(a.value % b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator -(ScalarLane<T> a) => new(-a.value);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator &(ScalarLane<T> a, ScalarLane<T> b) => new(a.value & b.value);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator &(ScalarLane<T> a, T b) => new(a.value & b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator |(ScalarLane<T> a, ScalarLane<T> b) => new(a.value | b.value);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator |(ScalarLane<T> a, T b) => new(a.value | b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator ^(ScalarLane<T> a, ScalarLane<T> b) => new(a.value ^ b.value);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator ^(ScalarLane<T> a, T b) => new(a.value ^ b);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> operator ~(ScalarLane<T> a) => new(~a.value);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Abs(ScalarLane<T> value) => new(T.Abs(value.value));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Floor(ScalarLane<T> value)
|
|
||||||
{
|
{
|
||||||
// Note: INumber<T> does not provide Floor method, so we need to handle float and double specifically.
|
return Vector.Create(value);
|
||||||
// This is acceptable for performance because JIT generates specialized code for each T as long as they are struct.
|
}
|
||||||
// Which mean for ScalarLane<float>, typeof(T) == typeof(float) is always true and jit will optimize away the other branches.
|
|
||||||
if (typeof(T) == typeof(float))
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator +(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value + b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator -(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value - b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator *(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value * b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator /(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value / b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator %(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value % b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator -(ScalarLane<TNumber> a)
|
||||||
|
{
|
||||||
|
return new(-a.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator &(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value & b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator |(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value | b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator ^(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value ^ b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator ~(ScalarLane<TNumber> a)
|
||||||
|
{
|
||||||
|
return new(~a.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator ==(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value == b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator !=(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value != b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator ScalarLane<TNumber>(TNumber value)
|
||||||
|
{
|
||||||
|
return new(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Abs(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return new(TNumber.Abs(value.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Floor(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
// Note: INumber<TLane> does not provide Floor method, so we need to handle float and double specifically.
|
||||||
|
// This is acceptable for performance because JIT generates specialized code for each TLane as long as they are struct.
|
||||||
|
// Which mean for ScalarLane<float>, typeof(TLane) == typeof(float) is always true and jit will optimize away the other branches.
|
||||||
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Floor(f);
|
var result = MathF.Floor(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Floor(d);
|
var result = Math.Floor(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Frac(ScalarLane<T> value) => new(value.value - T.CreateTruncating(value.value));
|
public static ScalarLane<TNumber> Frac(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return new(value.value - TNumber.CreateTruncating(value.value));
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Sqrt(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Sqrt(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Sqrt(f);
|
var result = MathF.Sqrt(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Sqrt(d);
|
var result = Math.Sqrt(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Lerp(ScalarLane<T> a, ScalarLane<T> b, ScalarLane<T> t) => new(a.value + (b.value - a.value) * t.value);
|
public static ScalarLane<TNumber> Lerp(ScalarLane<TNumber> a, ScalarLane<TNumber> b, ScalarLane<TNumber> t)
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> MultipleAdd(ScalarLane<T> a, ScalarLane<T> b, ScalarLane<T> c) => new(T.MultiplyAddEstimate(a.value, b.value, c.value));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Min(ScalarLane<T> a, ScalarLane<T> b) => new(T.Min(a.value, b.value));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Max(ScalarLane<T> a, ScalarLane<T> b) => new(T.Max(a.value, b.value));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Clamp(ScalarLane<T> value, ScalarLane<T> min, ScalarLane<T> max) => new(T.Clamp(value.value, min.value, max.value));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Saturate(ScalarLane<T> value) => Clamp(value, new(T.Zero), new(T.One));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Sin(ScalarLane<T> value)
|
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
return new(a.value + (b.value - a.value) * t.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> MultipleAdd(ScalarLane<TNumber> a, ScalarLane<TNumber> b, ScalarLane<TNumber> c)
|
||||||
|
{
|
||||||
|
return new(TNumber.MultiplyAddEstimate(a.value, b.value, c.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Min(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(TNumber.Min(a.value, b.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Max(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(TNumber.Max(a.value, b.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Clamp(ScalarLane<TNumber> value, ScalarLane<TNumber> min, ScalarLane<TNumber> max)
|
||||||
|
{
|
||||||
|
return new(TNumber.Clamp(value.value, min.value, max.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Saturate(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return Clamp(value, new(TNumber.Zero), new(TNumber.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Sin(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Sin(f);
|
var result = MathF.Sin(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Sin(d);
|
var result = Math.Sin(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Cos(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Cos(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Cos(f);
|
var result = MathF.Cos(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Cos(d);
|
var result = Math.Cos(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static (ScalarLane<T> sin, ScalarLane<T> cos) SinCos(ScalarLane<T> value) => (Sin(value), Cos(value));
|
public static (ScalarLane<TNumber> sin, ScalarLane<TNumber> cos) SinCos(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return (Sin(value), Cos(value));
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Tan(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Tan(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Tan(f);
|
var result = MathF.Tan(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Tan(d);
|
var result = Math.Tan(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Asin(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Asin(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Asin(f);
|
var result = MathF.Asin(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Asin(d);
|
var result = Math.Asin(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Acos(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Acos(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Acos(f);
|
var result = MathF.Acos(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Acos(d);
|
var result = Math.Acos(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Atan(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Atan(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Atan(f);
|
var result = MathF.Atan(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Atan(d);
|
var result = Math.Atan(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Atan2(ScalarLane<T> y, ScalarLane<T> x)
|
public static ScalarLane<TNumber> Atan2(ScalarLane<TNumber> y, ScalarLane<TNumber> x)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var fy = Unsafe.As<ScalarLane<T>, float>(ref y);
|
var fy = Unsafe.As<ScalarLane<TNumber>, float>(ref y);
|
||||||
var fx = Unsafe.As<ScalarLane<T>, float>(ref x);
|
var fx = Unsafe.As<ScalarLane<TNumber>, float>(ref x);
|
||||||
var result = MathF.Atan2(fy, fx);
|
var result = MathF.Atan2(fy, fx);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var dy = Unsafe.As<ScalarLane<T>, double>(ref y);
|
var dy = Unsafe.As<ScalarLane<TNumber>, double>(ref y);
|
||||||
var dx = Unsafe.As<ScalarLane<T>, double>(ref x);
|
var dx = Unsafe.As<ScalarLane<TNumber>, double>(ref x);
|
||||||
var result = Math.Atan2(dy, dx);
|
var result = Math.Atan2(dy, dx);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Pow(ScalarLane<T> x, ScalarLane<T> y)
|
public static ScalarLane<TNumber> Pow(ScalarLane<TNumber> x, ScalarLane<TNumber> y)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var fx = Unsafe.As<ScalarLane<T>, float>(ref x);
|
var fx = Unsafe.As<ScalarLane<TNumber>, float>(ref x);
|
||||||
var fy = Unsafe.As<ScalarLane<T>, float>(ref y);
|
var fy = Unsafe.As<ScalarLane<TNumber>, float>(ref y);
|
||||||
var result = MathF.Pow(fx, fy);
|
var result = MathF.Pow(fx, fy);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var dx = Unsafe.As<ScalarLane<T>, double>(ref x);
|
var dx = Unsafe.As<ScalarLane<TNumber>, double>(ref x);
|
||||||
var dy = Unsafe.As<ScalarLane<T>, double>(ref y);
|
var dy = Unsafe.As<ScalarLane<TNumber>, double>(ref y);
|
||||||
var result = Math.Pow(dx, dy);
|
var result = Math.Pow(dx, dy);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Exp(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Exp(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Exp(f);
|
var result = MathF.Exp(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Log(d);
|
var result = Math.Log(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -396,167 +477,222 @@ public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
|||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Exp2(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Exp2(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
return Pow(new ScalarLane<T>(T.CreateChecked(2)), value);
|
return Pow(new ScalarLane<TNumber>(TNumber.CreateChecked(2)), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Log(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Log(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Log(f);
|
var result = MathF.Log(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Log(d);
|
var result = Math.Log(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Log2(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Log2(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Log2(f);
|
var result = MathF.Log2(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Log2(d);
|
var result = Math.Log2(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Ceil(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Ceil(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Ceiling(f);
|
var result = MathF.Ceiling(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Ceiling(d);
|
var result = Math.Ceiling(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(decimal))
|
else if (typeof(TNumber) == typeof(decimal))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, decimal>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, decimal>(ref value);
|
||||||
var result = Math.Ceiling(d);
|
var result = Math.Ceiling(d);
|
||||||
return Unsafe.As<decimal, ScalarLane<T>>(ref result);
|
return Unsafe.As<decimal, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Round(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Round(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Round(f);
|
var result = MathF.Round(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Round(d);
|
var result = Math.Round(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(decimal))
|
else if (typeof(TNumber) == typeof(decimal))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, decimal>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, decimal>(ref value);
|
||||||
var result = Math.Round(d);
|
var result = Math.Round(d);
|
||||||
return Unsafe.As<decimal, ScalarLane<T>>(ref result);
|
return Unsafe.As<decimal, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Trunc(ScalarLane<T> value)
|
public static ScalarLane<TNumber> Trunc(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(TNumber) == typeof(float))
|
||||||
{
|
{
|
||||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||||
var result = MathF.Truncate(f);
|
var result = MathF.Truncate(f);
|
||||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(double))
|
else if (typeof(TNumber) == typeof(double))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||||
var result = Math.Truncate(d);
|
var result = Math.Truncate(d);
|
||||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(decimal))
|
else if (typeof(TNumber) == typeof(decimal))
|
||||||
{
|
{
|
||||||
var d = Unsafe.As<ScalarLane<T>, decimal>(ref value);
|
var d = Unsafe.As<ScalarLane<TNumber>, decimal>(ref value);
|
||||||
var result = Math.Truncate(d);
|
var result = Math.Truncate(d);
|
||||||
return Unsafe.As<decimal, ScalarLane<T>>(ref result);
|
return Unsafe.As<decimal, ScalarLane<TNumber>>(ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Sign(ScalarLane<T> value) => new((value.value > T.Zero) ? T.One : (value.value < T.Zero) ? ~T.Zero : T.Zero);
|
public static ScalarLane<TNumber> Sign(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return new((value.value > TNumber.Zero) ? TNumber.One : (value.value < TNumber.Zero) ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> CopySign(ScalarLane<T> magnitude, ScalarLane<T> sign) => new(T.CopySign(magnitude.value, sign.value));
|
public static ScalarLane<TNumber> CopySign(ScalarLane<TNumber> magnitude, ScalarLane<TNumber> sign)
|
||||||
|
{
|
||||||
|
return new(TNumber.CopySign(magnitude.value, sign.value));
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Rcp(ScalarLane<T> value) => new(T.One / value.value);
|
public static ScalarLane<TNumber> Rcp(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return new(TNumber.One / value.value);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Rsqrt(ScalarLane<T> value) => Sqrt(Rcp(value));
|
public static ScalarLane<TNumber> Rsqrt(ScalarLane<TNumber> value)
|
||||||
|
{
|
||||||
|
return Sqrt(Rcp(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Select(ScalarLane<TNumber> conditionMask, ScalarLane<TNumber> ifTrue, ScalarLane<TNumber> ifFalse)
|
||||||
|
{
|
||||||
|
return new(conditionMask.value != TNumber.Zero ? ifTrue.value : ifFalse.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> GreaterThan(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value > b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> GreaterThanOrEqual(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value >= b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> LessThan(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value < b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> LessThanOrEqual(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value <= b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> Equal(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return new(a.value == b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Any(ScalarLane<TNumber> mask)
|
||||||
|
{
|
||||||
|
return mask.value != TNumber.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool All(ScalarLane<TNumber> mask)
|
||||||
|
{
|
||||||
|
return mask.value != TNumber.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool None(ScalarLane<TNumber> mask)
|
||||||
|
{
|
||||||
|
return mask.value == TNumber.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> Select(ScalarLane<T> conditionMask, ScalarLane<T> ifTrue, ScalarLane<T> ifFalse) => new(conditionMask.value != T.Zero ? ifTrue.value : ifFalse.value);
|
public bool Equals(ScalarLane<TNumber> other)
|
||||||
|
{
|
||||||
|
return value.Equals(other.value);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> GreaterThan(ScalarLane<T> a, ScalarLane<T> b) => new(a.value > b.value ? ~T.Zero : T.Zero);
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ScalarLane<TNumber> other && value.Equals(other.value);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> GreaterThanOrEqual(ScalarLane<T> a, ScalarLane<T> b) => new(a.value >= b.value ? ~T.Zero : T.Zero);
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return value.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<T> LessThan(ScalarLane<T> a, ScalarLane<T> b) => new(a.value < b.value ? ~T.Zero : T.Zero);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> LessThanOrEqual(ScalarLane<T> a, ScalarLane<T> b) => new(a.value <= b.value ? ~T.Zero : T.Zero);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ScalarLane<T> Equal(ScalarLane<T> a, ScalarLane<T> b) => new(a.value == b.value ? ~T.Zero : T.Zero);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool Any(ScalarLane<T> mask) => mask.value != T.Zero;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool All(ScalarLane<T> mask) => mask.value != T.Zero;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool None(ScalarLane<T> mask) => mask.value == T.Zero;
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return value.ToString() ?? string.Empty;
|
return value.ToString() ?? string.Empty;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
public static unsafe class ShuffleTableGenerator
|
internal static unsafe class ShuffleTableGenerator
|
||||||
{
|
{
|
||||||
public static uint* ComputeShuffleTable512_32Bit()
|
public static uint* ComputeShuffleTable512_32Bit()
|
||||||
{
|
{
|
||||||
|
|||||||
198
Misaki.HighPerformance.Mathematics.SPMD/Vector3.cs
Normal file
198
Misaki.HighPerformance.Mathematics.SPMD/Vector3.cs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
public unsafe struct Vector3<TLane, TNumber> : IEquatable<Vector3<TLane, TNumber>>
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
public TLane x;
|
||||||
|
public TLane y;
|
||||||
|
public TLane z;
|
||||||
|
|
||||||
|
public TLane this[int index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
RangeCheck(index);
|
||||||
|
return Unsafe.Add(ref x, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[Conditional("ENABLE_COLLECTION_CHECKS")]
|
||||||
|
private static void RangeCheck(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= 3)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector3.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* pDst)
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
var z = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
this.x.Store(x);
|
||||||
|
this.y.Store(y);
|
||||||
|
this.z.Store(z);
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
pDst[i * 3 + 0] = x[i];
|
||||||
|
pDst[i * 3 + 1] = y[i];
|
||||||
|
pDst[i * 3 + 2] = z[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber dst)
|
||||||
|
{
|
||||||
|
Store((TNumber*)Unsafe.AsPointer(ref dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* pX, TNumber* pY, TNumber* pZ)
|
||||||
|
{
|
||||||
|
x.Store(pX);
|
||||||
|
y.Store(pY);
|
||||||
|
z.Store(pZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber x, ref TNumber y, ref TNumber z)
|
||||||
|
{
|
||||||
|
this.x.Store(ref x);
|
||||||
|
this.y.Store(ref y);
|
||||||
|
this.z.Store(ref z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator +(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x + right.x,
|
||||||
|
y = left.y + right.y,
|
||||||
|
z = left.z + right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator +(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x + lane,
|
||||||
|
y = vector.y + lane,
|
||||||
|
z = vector.z + lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x - right.x,
|
||||||
|
y = left.y - right.y,
|
||||||
|
z = left.z - right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x - lane,
|
||||||
|
y = vector.y - lane,
|
||||||
|
z = vector.z - lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator *(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x * right.x,
|
||||||
|
y = left.y * right.y,
|
||||||
|
z = left.z * right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator *(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x * lane,
|
||||||
|
y = vector.y * lane,
|
||||||
|
z = vector.z * lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator /(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x / right.x,
|
||||||
|
y = left.y / right.y,
|
||||||
|
z = left.z / right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator == (in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x == right.x,
|
||||||
|
y = left.y == right.y,
|
||||||
|
z = left.z == right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator != (in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x != right.x,
|
||||||
|
y = left.y != right.y,
|
||||||
|
z = left.z != right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly bool Equals(Vector3<TLane, TNumber> other)
|
||||||
|
{
|
||||||
|
return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Vector3<TLane, TNumber> other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,9 @@ public class MathematicsBenchmark
|
|||||||
private float4 _fa = new float4(1, 2, 1, 2);
|
private float4 _fa = new float4(1, 2, 1, 2);
|
||||||
private float4 _fb = new float4(3, 4, 3, 4);
|
private float4 _fb = new float4(3, 4, 3, 4);
|
||||||
|
|
||||||
|
private Vector64<float> _va64 = Vector64.Create(1f, 2f);
|
||||||
|
private Vector64<float> _vb64 = Vector64.Create(3f, 4f);
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public Vector4 VectorAdd()
|
public Vector4 VectorAdd()
|
||||||
{
|
{
|
||||||
@@ -28,7 +31,7 @@ public class MathematicsBenchmark
|
|||||||
return _va;
|
return _va;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
//[Benchmark]
|
||||||
public float4 floatAdd()
|
public float4 floatAdd()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
@@ -38,6 +41,17 @@ public class MathematicsBenchmark
|
|||||||
|
|
||||||
return _fa;
|
return _fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Vector64<float> Vector64Add()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
_va64 += _vb64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _va64;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMA_BENCHMARK
|
#if FMA_BENCHMARK
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Misaki.HighPerformance.Jobs;
|
using Misaki.HighPerformance.Jobs;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Mathematics.SPMD;
|
using Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -60,8 +61,7 @@ internal unsafe struct NoiseJobMath : IJobParallelFor
|
|||||||
|
|
||||||
private static float2 GradientNoiseDirect(float2 uv)
|
private static float2 GradientNoiseDirect(float2 uv)
|
||||||
{
|
{
|
||||||
uv.x %= 289;
|
uv %= 289;
|
||||||
uv.y %= 289;
|
|
||||||
var x = (34 * uv.x + 1) * uv.x % 289 + uv.y;
|
var x = (34 * uv.x + 1) * uv.x % 289 + uv.y;
|
||||||
x = (34 * x + 1) * x % 289;
|
x = (34 * x + 1) * x % 289;
|
||||||
x = math.frac(x / 41) * 2 - 1;
|
x = math.frac(x / 41) * 2 - 1;
|
||||||
@@ -261,7 +261,7 @@ internal unsafe struct NoiseJobMathSPMD : IJobSPMD<float>
|
|||||||
|
|
||||||
var uvX = (indices % w) / w;
|
var uvX = (indices % w) / w;
|
||||||
var uvY = TLane.Floor(indices / w) / h;
|
var uvY = TLane.Floor(indices / w) / h;
|
||||||
|
|
||||||
var result = Noise(uvX, uvY);
|
var result = Noise(uvX, uvY);
|
||||||
result.Store(buffers + baseIndex);
|
result.Store(buffers + baseIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
BenchmarkDotNet.Running.BenchmarkRunner.Run<Misaki.HighPerformance.Test.Benchmark.SPMDBenchmark>();
|
BenchmarkDotNet.Running.BenchmarkRunner.Run<Misaki.HighPerformance.Test.Benchmark.MathematicsBenchmark>();
|
||||||
return;
|
|
||||||
@@ -39,7 +39,7 @@ public static class CompressStoreTest
|
|||||||
private unsafe static void TestPattern_Double(double[] input, bool[] keepPattern)
|
private unsafe static void TestPattern_Double(double[] input, bool[] keepPattern)
|
||||||
{
|
{
|
||||||
// 1. Setup Input Vector
|
// 1. Setup Input Vector
|
||||||
// Handle case where Vector<T> is smaller than 8 (e.g. 2 or 4)
|
// Handle case where Vector<TLane> is smaller than 8 (e.g. 2 or 4)
|
||||||
var vecSize = Vector<double>.Count;
|
var vecSize = Vector<double>.Count;
|
||||||
var safeInput = new double[vecSize];
|
var safeInput = new double[vecSize];
|
||||||
var safeMaskVal = new double[vecSize];
|
var safeMaskVal = new double[vecSize];
|
||||||
|
|||||||
60
Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs
Normal file
60
Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Test.UnitTest.Jobs;
|
||||||
|
|
||||||
|
internal unsafe struct DotProductJob : IJobSPMD<float>
|
||||||
|
{
|
||||||
|
public float3* arrayA; // source array 1
|
||||||
|
public float3* arrayB; // source array 2
|
||||||
|
public float* results; // output array (dot products)
|
||||||
|
|
||||||
|
public readonly void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
|
where TLane : ISPMD<TLane, float>
|
||||||
|
{
|
||||||
|
var vecA = MathV.LoadVector3<TLane, float>((float*)(arrayA + baseIndex));
|
||||||
|
var vecB = MathV.LoadVector3<TLane, float>((float*)(arrayB + baseIndex));
|
||||||
|
|
||||||
|
var dotResult = MathV.Dot(vecA, vecB);
|
||||||
|
dotResult.Store(results + baseIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SPMDTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public unsafe void TestSPMDVectorDot()
|
||||||
|
{
|
||||||
|
const int count = 1000;
|
||||||
|
|
||||||
|
var arrayA = (float3*)NativeMemory.Alloc((nuint)(sizeof(float3) * count));
|
||||||
|
var arrayB = (float3*)NativeMemory.Alloc((nuint)(sizeof(float3) * count));
|
||||||
|
var results = (float*)NativeMemory.Alloc(sizeof(float) * count);
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
arrayA[i] = new float3(i, i + 1, i + 2);
|
||||||
|
arrayB[i] = new float3(1, 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
var job = new DotProductJob
|
||||||
|
{
|
||||||
|
arrayA = arrayA,
|
||||||
|
arrayB = arrayB,
|
||||||
|
results = results
|
||||||
|
};
|
||||||
|
|
||||||
|
job.Run<DotProductJob, float>(count, -1);
|
||||||
|
|
||||||
|
// Verify first result: dot([0,1,2], [1,2,3]) = 0*1 + 1*2 + 2*3 = 8
|
||||||
|
Assert.AreEqual(8.0f, results[0], 0.001f);
|
||||||
|
// Verify last result: dot([999,1000,1001], [1,2,3]) = 999*1 + 1000*2 + 1001*3 = 6002
|
||||||
|
Assert.AreEqual(6002.0f, results[count - 1], 0.001f);
|
||||||
|
|
||||||
|
NativeMemory.Free(arrayA);
|
||||||
|
NativeMemory.Free(arrayB);
|
||||||
|
NativeMemory.Free(results);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance;
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
|
||||||
public struct Union<T0, T1>
|
|
||||||
where T0 : unmanaged
|
|
||||||
where T1 : unmanaged
|
|
||||||
{
|
|
||||||
[FieldOffset(0)]
|
|
||||||
public T0 v0;
|
|
||||||
|
|
||||||
[FieldOffset(0)]
|
|
||||||
public T1 v1;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user