Major namespace migration from SPMD to HPC across all code, templates, and projects. Introduced Misaki.HighPerformance.HPC.Generator with Roslyn-based source generators for SIMD code (e.g., AVX2), including attribute and method generators. Renamed MultipleAdd to MultiplyAdd in all lanes and updated usages. Added AVX2 utility methods via codegen. Updated tests, benchmarks, and project references to use the new framework. Improved SIMD memory utilities and modernized project files. Removed legacy SPMD project from the solution.
482 lines
18 KiB
Plaintext
482 lines
18 KiB
Plaintext
<#@ import namespace="System.Text" #>
|
|
<#+
|
|
private const string TLane = "TLane";
|
|
private const string TNumber = "TNumber";
|
|
|
|
private string TLaneRestrictions = $@"where {TLane} : ISPMDLane<{TLane}, {TNumber}>";
|
|
private string TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>";
|
|
|
|
private int[] dimensions = new int[] { 2, 3, 4 };
|
|
private char[] components = new char[] { 'x', 'y', 'z', 'w' };
|
|
|
|
public string Indent(string str, int spaces)
|
|
{
|
|
var indent = new string(' ', spaces);
|
|
return indent + str;
|
|
}
|
|
|
|
private string ForEachDimension(int maxDimension, int indentation, string spliter, Action<int, StringBuilder> action, bool spliterOnFirst = true)
|
|
{
|
|
var sb = new StringBuilder();
|
|
for (var dimension = 0; dimension < maxDimension; dimension++)
|
|
{
|
|
if ((dimension > 0 || spliterOnFirst) && indentation > 0)
|
|
{
|
|
sb.Append(new string(' ', indentation));
|
|
}
|
|
|
|
action(dimension, sb);
|
|
if (dimension < maxDimension - 1)
|
|
{
|
|
sb.Append(spliter);
|
|
}
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public StringBuilder GenerateVectorType(int dimension)
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
var typeName = $"Vector{dimension}<{TLane}, {TNumber}>";
|
|
|
|
sb.AppendLine(@$"
|
|
public unsafe struct {typeName} : IEquatable<{typeName}>
|
|
{TLaneRestrictions}
|
|
{TNumberRestrictions}
|
|
{{
|
|
{ForEachDimension(dimension, 4, Environment.NewLine, (dim, sb) => sb.Append($"public {TLane} {components[dim]};"))}
|
|
|
|
public static {typeName} Zero
|
|
{{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 16, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = {TLane}.Zero,"))}
|
|
}};
|
|
}}
|
|
}}
|
|
|
|
public static {typeName} One
|
|
{{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 16, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = {TLane}.One,"))}
|
|
}};
|
|
}}
|
|
}}
|
|
|
|
public {TLane} this[int index]
|
|
{{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get
|
|
{{
|
|
RangeCheck(index);
|
|
return Unsafe.Add(ref x, index);
|
|
}}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
[Conditional(""MHP_ENABLE_SAFETY_CHECKS"")]
|
|
private static void RangeCheck(int index)
|
|
{{
|
|
if (index < 0 || index >= {dimension})
|
|
{{
|
|
throw new IndexOutOfRangeException($""Index {{index}} is out of range for Vector{dimension}."");
|
|
}}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Store({TNumber}* pDst)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Store(pDst + {dim} * TLane.LaneWidth);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Store(ref {TNumber} dst)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Store(ref Unsafe.Add(ref dst, {dim} * TLane.LaneWidth));"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Store({ForEachDimension(dimension, 1, ",", (dim, sb) => sb.Append($"{TNumber}* p{components[dim]}"), false)})
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Store(p{components[dim]});"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Store({ForEachDimension(dimension, 1, ",", (dim, sb) => sb.Append($"ref {TNumber} {components[dim]}"), false)})
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"this.{components[dim]}.Store(ref {components[dim]});"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void CompressStore({TNumber}* pDst, {typeName} mask)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.CompressStore(pDst + {dim} * TLane.LaneWidth, mask.{components[dim]});"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void CompressStore(ref {TNumber} dst, {typeName} mask)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.CompressStore(ref Unsafe.Add(ref dst, {dim} * TLane.LaneWidth), mask.{components[dim]});"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Scatter({TNumber}* pDst, {TLane} indices)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Scatter(pDst + {dim}, indices);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Scatter({TNumber}* pDst, int* pIndices)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Scatter(pDst + {dim}, pIndices);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Scatter(ref {TNumber} dst, {TLane} indices)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Scatter(ref Unsafe.Add(ref dst, {dim}), indices);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Scatter(ref {TNumber} dst, int* pIndices)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Scatter(ref Unsafe.Add(ref dst, {dim}), pIndices);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void MaskScatter({TNumber}* pDst, {TLane} indices, {TLane} mask)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.MaskScatter(pDst + {dim}, indices, mask);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void MaskScatter({TNumber}* pDst, int* pIndices, {TLane} mask)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.MaskScatter(pDst + {dim}, pIndices, mask);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void MaskScatter(ref {TNumber} dst, {TLane} indices, {TLane} mask)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.MaskScatter(ref Unsafe.Add(ref dst, {dim}), indices, mask);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void MaskScatter(ref {TNumber} dst, int* pIndices, {TLane} mask)
|
|
{{
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.MaskScatter(ref Unsafe.Add(ref dst, {dim}), pIndices, mask);"))}
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator -(in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = -vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator +(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} + right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator +(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} + lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator +({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane + vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator -(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} - right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator -(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} - lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator -({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane - vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator *(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} * right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator *(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} * lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator *({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane * vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator /(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} / right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator /(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} / lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator /({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane / vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator ==(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} == right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator ==(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} == lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator ==({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane == vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator !=(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} != right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator !=(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} != lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator !=({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane != vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator >(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} > right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator >(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} > lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator >({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane > vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator >=(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} >= right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator >=(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} >= lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator >=({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane >= vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator <(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} < right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator <(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} < lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator <({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane < vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator <=(in {typeName} left, in {typeName} right)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} <= right.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator <=(in {typeName} vector, {TLane} lane)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} <= lane,"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static {typeName} operator <=({TLane} lane, in {typeName} vector)
|
|
{{
|
|
return new {typeName}
|
|
{{
|
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane <= vector.{components[dim]},"))}
|
|
}};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public readonly bool Equals({typeName} other)
|
|
{{
|
|
return {ForEachDimension(dimension, 0, " && ", (dim, sb) => sb.Append($"this.{components[dim]}.Equals(other.{components[dim]})"), false)};
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public override readonly bool Equals(object? obj)
|
|
{{
|
|
return obj is {typeName} other && Equals(other);
|
|
}}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public override readonly int GetHashCode()
|
|
{{
|
|
var hash = new HashCode();
|
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"hash.Add({components[dim]});"))}
|
|
return hash.ToHashCode();
|
|
}}
|
|
}}");
|
|
|
|
return sb;
|
|
}
|
|
#> |