Refactor SPMD lane abstraction and add gather support

- Rename ISPMD interfaces to ISPMDLane for clarity
- Add gather and mask load methods to ISPMDLane, implement for ScalarLane and WideLane
- Add GetUnsafePtr() for direct pointer access
- Update MathV and vector types to use new interface and gather methods
- Update SPMD job interfaces and implementations to ISPMDLane
- Improve hash codes, range checks, and safety checks in vector types
- Update codegen templates for new interface/methods
- Refactor SPMD jobs to use gather methods for efficient vectorized access
This commit is contained in:
2026-04-25 11:50:51 +09:00
parent cfd01eb9b6
commit 9f7507ba71
18 changed files with 772 additions and 300 deletions

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Mathematics.SPMD;
[StructLayout(LayoutKind.Sequential)]
public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, TNumber>
public readonly unsafe struct ScalarLane<TNumber> : ISPMDLane<ScalarLane<TNumber>, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
public readonly TNumber value;
@@ -19,25 +19,25 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
public static ScalarLane<TNumber> Zero
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(TNumber.Zero);
get => new ScalarLane<TNumber>(TNumber.Zero);
}
public static ScalarLane<TNumber> One
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(TNumber.One);
get => new ScalarLane<TNumber>(TNumber.One);
}
public static ScalarLane<TNumber> MinValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(TNumber.MinValue);
get => new ScalarLane<TNumber>(TNumber.MinValue);
}
public static ScalarLane<TNumber> MaxValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(TNumber.MaxValue);
get => new ScalarLane<TNumber>(TNumber.MaxValue);
}
public readonly TNumber this[int index]
@@ -54,39 +54,76 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Create(TNumber value)
{
return new(value);
return new ScalarLane<TNumber>(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Create(params ReadOnlySpan<TNumber> values)
{
return new(values[0]);
return new ScalarLane<TNumber>(values[0]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Create(Vector<TNumber> value)
{
return new(value[0]);
return new ScalarLane<TNumber>(value[0]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Sequence(TNumber start, TNumber step)
{
return new(start);
return new ScalarLane<TNumber>(start);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Load(ref TNumber value)
{
return new(value);
return new ScalarLane<TNumber>(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Load(TNumber* pValue)
{
return new(*pValue);
return new ScalarLane<TNumber>(*pValue);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> MaskLoad(ScalarLane<TNumber> mask, ref TNumber value)
{
return new ScalarLane<TNumber>(mask.value != TNumber.Zero ? value : TNumber.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> MaskLoad(ScalarLane<TNumber> mask, TNumber* pValue)
{
return new ScalarLane<TNumber>(mask.value != TNumber.Zero ? *pValue : TNumber.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Gather(TNumber* pData, ScalarLane<TNumber> indices, int scale)
{
return new ScalarLane<TNumber>(pData[int.CreateTruncating(indices.value) * scale / sizeof(TNumber)]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Gather(TNumber* pData, int* pIndices, int scale)
{
return new ScalarLane<TNumber>(pData[pIndices[0] * scale / sizeof(TNumber)]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Gather(ref TNumber baseAddress, ScalarLane<TNumber> indices, int scale)
{
return new ScalarLane<TNumber>(Unsafe.Add(ref baseAddress, int.CreateTruncating(indices.value) * scale / sizeof(TNumber)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Gather(ref TNumber baseAddress, ref int baseIndex, int scale)
{
return new ScalarLane<TNumber>(Unsafe.Add(ref baseAddress, int.CreateTruncating(baseIndex) * scale / sizeof(TNumber)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly void Store(ref TNumber destination)
{
@@ -123,9 +160,15 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
return Vector.Create(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly TNumber* GetUnsafePtr()
{
return (TNumber*)Unsafe.AsPointer(ref Unsafe.AsRef(in value));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TOther Cast<TOther, TOtherNumber>()
where TOther : ISPMD<TOther, TOtherNumber>
where TOther : ISPMDLane<TOther, TOtherNumber>
where TOtherNumber : unmanaged, INumber<TOtherNumber>, IBinaryNumber<TOtherNumber>, IMinMaxValue<TOtherNumber>, IBitwiseOperators<TOtherNumber, TOtherNumber, TOtherNumber>
{
return TOther.Create(TOtherNumber.CreateChecked(value));
@@ -133,7 +176,7 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TOther BitCast<TOther, TOtherNumber>()
where TOther : ISPMD<TOther, TOtherNumber>
where TOther : ISPMDLane<TOther, TOtherNumber>
where TOtherNumber : unmanaged, INumber<TOtherNumber>, IBinaryNumber<TOtherNumber>, IMinMaxValue<TOtherNumber>, IBitwiseOperators<TOtherNumber, TOtherNumber, TOtherNumber>
{
return Unsafe.BitCast<ScalarLane<TNumber>, TOther>(this);
@@ -142,61 +185,61 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator +(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value + b.value);
return new ScalarLane<TNumber>(a.value + b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator -(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value - b.value);
return new ScalarLane<TNumber>(a.value - b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator *(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value * b.value);
return new ScalarLane<TNumber>(a.value * b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator /(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value / b.value);
return new ScalarLane<TNumber>(a.value / b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator %(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value % b.value);
return new ScalarLane<TNumber>(a.value % b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator -(ScalarLane<TNumber> a)
{
return new(-a.value);
return new ScalarLane<TNumber>(-a.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator &(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value & b.value);
return new ScalarLane<TNumber>(a.value & b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator |(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value | b.value);
return new ScalarLane<TNumber>(a.value | b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator ^(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
{
return new(a.value ^ b.value);
return new ScalarLane<TNumber>(a.value ^ b.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> operator ~(ScalarLane<TNumber> a)
{
return new(~a.value);
return new ScalarLane<TNumber>(~a.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -240,7 +283,7 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ScalarLane<TNumber>(TNumber value)
{
return new(value);
return new ScalarLane<TNumber>(value);
}
@@ -248,7 +291,7 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Abs(ScalarLane<TNumber> value)
{
return new(TNumber.Abs(value.value));
return new ScalarLane<TNumber>(TNumber.Abs(value.value));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -276,7 +319,7 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Frac(ScalarLane<TNumber> value)
{
return new(value.value - TNumber.CreateTruncating(value.value));
return new ScalarLane<TNumber>(value.value - TNumber.CreateTruncating(value.value));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -301,37 +344,37 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Lerp(ScalarLane<TNumber> a, ScalarLane<TNumber> b, ScalarLane<TNumber> t)
{
return new(a.value + (b.value - a.value) * t.value);
return new ScalarLane<TNumber>(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));
return new ScalarLane<TNumber>(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));
return new ScalarLane<TNumber>(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));
return new ScalarLane<TNumber>(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));
return new ScalarLane<TNumber>(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));
return Clamp(value, new ScalarLane<TNumber>(TNumber.Zero), new ScalarLane<TNumber>(TNumber.One));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -638,19 +681,19 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Sign(ScalarLane<TNumber> value)
{
return new((value.value > TNumber.Zero) ? TNumber.One : (value.value < TNumber.Zero) ? ~TNumber.Zero : TNumber.Zero);
return new ScalarLane<TNumber>((value.value > TNumber.Zero) ? TNumber.One : (value.value < TNumber.Zero) ? ~TNumber.Zero : TNumber.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> CopySign(ScalarLane<TNumber> magnitude, ScalarLane<TNumber> sign)
{
return new(TNumber.CopySign(magnitude.value, sign.value));
return new ScalarLane<TNumber>(TNumber.CopySign(magnitude.value, sign.value));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarLane<TNumber> Rcp(ScalarLane<TNumber> value)
{
return new(TNumber.One / value.value);
return new ScalarLane<TNumber>(TNumber.One / value.value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -662,37 +705,37 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
[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);
return new ScalarLane<TNumber>(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);
return new ScalarLane<TNumber>(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);
return new ScalarLane<TNumber>(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);
return new ScalarLane<TNumber>(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);
return new ScalarLane<TNumber>(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);
return new ScalarLane<TNumber>(a.value == b.value ? ~TNumber.Zero : TNumber.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]