Refactor SPMD to HPC; add SIMD source generators

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.
This commit is contained in:
2026-05-06 13:43:58 +09:00
parent d3e497c7d8
commit c8f78f9d02
36 changed files with 895 additions and 130 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension="gen.cs" #>
using Misaki.HighPerformance.Jobs;
using System.Numerics;
namespace Misaki.HighPerformance.HPC;
<#
const string TLane = "TLane";
const string TNumber = "TNumber";
const string GenericParameters = $"{TLane}, {TNumber}";
var TLaneRestrictions = $@"where {TLane} : ISPMDLane<{TLane}, {TNumber}>";
var TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>";
for (var i = 0; i < 8; i++) { #>
/// <summary>
/// A job interface for Single Program Multiple Data (SPMD) execution, allowing for efficient parallel processing of data across multiple lanes.
/// </summary>
/// <remarks>
/// Always use TNumber0 as the primary type for determining lane width and job scheduling, even if it's not used in the job execution.
/// </remarks>
<#= ForEachDimension(i + 1, j => @$"/// <typeparam name=""TNumber{j}"">The first numeric type used in the SPMD job.</typeparam>", Environment.NewLine) #>
public interface IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
<#= GetTNumberRestrictions(i + 1) #>
{
void Execute<<#= ForEachDimension(i + 1, j => $"TLane{j}") #>>(TLane0 indices, TLane0 mask, ref readonly JobExecutionContext ctx)
<#= GetTLaneRestrictions(i + 1, " ") #>;
}
internal struct SPMDJobWrapper<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> : IJobParallelFor
where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
<#= GetTNumberRestrictions(i + 1) #>
{
public T innerJob;
public int totalIteration;
public void Execute(int loopIndex, ref readonly JobExecutionContext ctx)
{
var baseIndex = loopIndex * WideLane<TNumber0>.LaneWidth;
var indices = WideLane<TNumber0>.Sequence(TNumber0.CreateTruncating(baseIndex), TNumber0.One);
var mask = indices < TNumber0.CreateTruncating(totalIteration);
innerJob.Execute<<#= ForEachDimension(i + 1, j => $"WideLane<TNumber{j}>") #>>(indices, mask, in ctx);
}
}
internal struct SPMDScalerJobWrapper<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> : IJobParallelFor
where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
<#= GetTNumberRestrictions(i + 1) #>
{
public T innerJob;
public int totalIteration;
public void Execute(int loopIndex, ref readonly JobExecutionContext ctx)
{
innerJob.Execute<<#= ForEachDimension(i + 1, j => $"ScalarLane<TNumber{j}>") #>>(TNumber0.CreateTruncating(loopIndex), ScalarLane<TNumber0>.AllBitsSet, in ctx);
}
}
<# } #>
public static class IJobParallelForSPMDExtensions
{
<# for (var i = 0; i < 8; i++) { #>
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
/// <remarks>
/// Always use TNumber0 as the primary type for determining lane width and job scheduling, even if it's not used in the job execution.
/// </remarks>
<#= ForEachDimension(i + 1, j => @$" /// <typeparam name=""TNumber{j}"">The first numeric type used in the SPMD job.</typeparam>", Environment.NewLine) #>
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
<#= GetTNumberRestrictions(i + 1, " ") #>
{
if (WideLane.IsSupported)
{
var iterations = (totalIteration + WideLane<TNumber0>.LaneWidth - 1) / WideLane<TNumber0>.LaneWidth;
for (var loopIndex = 0; loopIndex < iterations; loopIndex++)
{
var baseIndex = loopIndex * WideLane<TNumber0>.LaneWidth;
var indices = WideLane<TNumber0>.Sequence(TNumber0.CreateTruncating(baseIndex), TNumber0.One);
var mask = indices < TNumber0.CreateTruncating(totalIteration);
job.Execute<<#= ForEachDimension(i + 1, j => $"WideLane<TNumber{j}>") #>>(indices, mask, in ctx);
}
}
else
{
for (var loopIndex = 0; loopIndex < totalIteration; loopIndex++)
{
job.Execute<<#= ForEachDimension(i + 1, j => $"ScalarLane<TNumber{j}>") #>>(TNumber0.CreateTruncating(loopIndex), ScalarLane<TNumber0>.AllBitsSet, in ctx);
}
}
}
/// <summary>
/// Schedule the SPMD job for parallel execution across multiple threads, with the specified total count, batch size, and job execution context.
/// </summary>
<#= ForEachDimension(i + 1, j => @$" /// <typeparam name=""TNumber{j}"">The first numeric type used in the SPMD job.</typeparam>", Environment.NewLine) #>
/// <remarks>
/// Always use TNumber0 as the primary type for determining lane width and job scheduling, even if it's not used in the job execution.
/// </remarks>
/// <param name="jobScheduler">The job scheduler to use for scheduling the job.</param>
/// <param name="job">The SPMD job to schedule.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="batchSize">The number of iterations to execute in each batch for parallel execution.</param>
/// <param name="preferLocal">Whether to prefer scheduling the job on the local thread for better cache locality.</param>
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
<#= GetTNumberRestrictions(i + 1, " ") #>
{
if (WideLane.IsSupported)
{
var warper = new SPMDJobWrapper<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
{
innerJob = job,
totalIteration = totalIteration,
};
var iterations = (totalIteration + WideLane<TNumber0>.LaneWidth - 1) / WideLane<TNumber0>.LaneWidth;
return jobScheduler.ScheduleParallelFor(ref warper, iterations, batchSize, preferLocal, priority, dependencies);
}
else
{
var warper = new SPMDScalerJobWrapper<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
{
innerJob = job,
totalIteration = totalIteration,
};
return jobScheduler.ScheduleParallelFor(ref warper, totalIteration, batchSize, preferLocal, priority, dependencies);
}
}
<# } #>
}
<#+
public string ForEachDimension(int dimension, Func<int, string> action, string spliter = ", ")
{
return string.Join(spliter, Enumerable.Range(0, dimension).Select(i => action(i)));
}
public string GetTNumberRestrictions(int dimension, string space = " ")
{
var sb = new StringBuilder();
for (var i = 0; i < dimension; i++)
{
sb.Append(space + $@"where TNumber{i} : unmanaged, INumber<TNumber{i}>, IBinaryNumber<TNumber{i}>, IMinMaxValue<TNumber{i}>, IBitwiseOperators<TNumber{i}, TNumber{i}, TNumber{i}>");
if (i < dimension - 1)
{
sb.AppendLine();
}
}
return sb.ToString();
}
public string GetTLaneRestrictions(int dimension, string space = " ")
{
var sb = new StringBuilder();
for (var i = 0; i < dimension; i++)
{
sb.Append(space + $@"where TLane{i} : unmanaged, ISPMDLane<TLane{i}, TNumber{i}>");
if (i < dimension - 1)
{
sb.AppendLine();
}
}
return sb.ToString();
}
#>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,543 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".gen.cs" #>
/// <auto-generated/>
/// This code is automatically generated by a T4 template.
/// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
/// </auto-generated>
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Misaki.HighPerformance.HPC;
<#
const string TLane = "TLane";
const string TNumber = "TNumber";
const string GenericParameters = $"{TLane}, {TNumber}";
var dimensions = new int[] { 2, 3, 4 };
var components = new char[] { 'x', 'y', 'z', 'w' };
var TLaneRestrictions = $@"where {TLane} : unmanaged, ISPMDLane<{TLane}, {TNumber}>";
var TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>";
#>
public static unsafe partial class MathV
{
<# foreach (int dimension in dimensions) {
var vectorType = $"Vector{dimension}<{TLane}, {TNumber}>";
#>
# region Vector<#= dimension #>
// Creation Functions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Create<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"in {TLane} {components[i]}") #>)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= components[i] #>,
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> CreateVector<#= dimension #><<#= GenericParameters #>>(in <#= TLane #> value)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = value,
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(<#= TNumber #>* pSrc)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Load(pSrc + <#= i #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> src)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return LoadVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref src));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> MaskLoadVector<#= dimension #><<#= GenericParameters #>>(<#= TNumber #>* pSrc, <#= TLane #> mask)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.MaskLoad(pSrc + <#= i #>, mask),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> MaskLoadVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> src, <#= TLane #> mask)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return MaskLoadVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref src), mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Load<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"TNumber* p{components[i]}") #>)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Load(p<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Load<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"ref TNumber {components[i]}") #>)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Load(ref <#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(<#= TNumber #>* pData, <#= TLane #> indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new Vector<#= dimension #><TLane, TNumber>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Gather(pData + <#= i #>, indices, scale),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(<#= TNumber #>* pData, int* pIndices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new Vector<#= dimension #><TLane, TNumber>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Gather(pData + <#= i #>, pIndices, scale),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> baseAddress, <#= TLane #> indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return GatherVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref baseAddress), indices, scale);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> baseAddress, ref int baseIndex, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return GatherVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), scale);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> MaskGatherVector<#= dimension #><TLane, TNumber>(<#= TNumber #>* pData, <#= TLane #> indices, <#= TLane #> mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
return new Vector<#= dimension #><TLane, TNumber>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.MaskGather(pData + <#= i #>, indices, mask, scale),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> MaskGatherVector<#= dimension #><TLane, TNumber>(<#= TNumber #>* pData, int* pIndices, <#= TLane #> mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
return new Vector<#= dimension #><TLane, TNumber>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.MaskGather(pData + <#= i #>, pIndices, mask, scale),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> MaskGatherVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> baseAddress, <#= TLane #> indices, <#= TLane #> mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return MaskGatherVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref baseAddress), indices, mask, scale);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> MaskGatherVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> baseAddress, ref int baseIndex, <#= TLane #> mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return MaskGatherVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), mask, scale);
}
// Math Functions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Abs<<#= GenericParameters #>>(in Vector<#= dimension #><TLane, <#= TNumber #>> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Abs(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= TLane #> Dot<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return <#= ForEachDimension(dimension, i => $"a.{components[i]} * b.{components[i]}", " + ") #>;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Sin<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Sin(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Cos<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Cos(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SinCos<<#= GenericParameters #>>(in <#= vectorType #> vector, out <#= vectorType #> sin, out <#= vectorType #> cos)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= TLane #>.SinCos(vector.<#= components[i] #>, out sin.<#= components[i] #>, out cos.<#= components[i] #>);
<# } #>
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Sqrt<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Sqrt(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Tan<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Tan(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Asin<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Asin(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Acos<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Acos(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Atan<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Atan(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Atan2<<#= GenericParameters #>>(in <#= vectorType #> x, in <#= vectorType #> y)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Atan2(x.<#= components[i] #>, y.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Rsqrt<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Rsqrt(vector.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Normalize<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return vector * <#= TLane #>.Rsqrt(Dot(vector, vector));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Reflect<<#= GenericParameters #>>(in <#= vectorType #> incident, in <#= vectorType #> normal)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
var dot = Dot(incident, normal);
return incident - normal * (dot + dot);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Min<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Min(a.<#= components[i] #>, b.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Max<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Max(a.<#= components[i] #>, b.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Clamp<<#= GenericParameters #>>(in <#= vectorType #> value, in <#= vectorType #> min, in <#= vectorType #> max)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return Min(Max(value, min), max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Saturate<<#= GenericParameters #>>(in <#= vectorType #> value)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return Clamp(value, CreateVector<#= dimension #><<#= GenericParameters #>>(<#= TLane #>.Zero), CreateVector<#= dimension #><<#= GenericParameters #>>(<#= TLane #>.One));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Lerp<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b, <#= TLane #> t)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return a + (b - a) * t;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= TLane #> Length<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return <#= TLane #>.Sqrt(Dot(vector, vector));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= TLane #> LengthSquared<<#= GenericParameters #>>(in <#= vectorType #> vector)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return Dot(vector, vector);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= TLane #> Distance<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
var diff = b - a;
return <#= TLane #>.Sqrt(Dot(diff, diff));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= TLane #> DistanceSquared<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
var diff = b - a;
return Dot(diff, diff);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Step<<#= GenericParameters #>>(in <#= vectorType #> edge, in <#= vectorType #> value)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return Select(value >= edge, <#= vectorType #>.One, <#= vectorType #>.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Smoothstep<<#= GenericParameters #>>(<#= vectorType #> xMin, <#= vectorType #> xMax, <#= vectorType #> x)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
var t = Saturate((x - xMin) / (xMax - xMin));
var two = <#= TLane #>.Create(<#= TNumber #>.CreateTruncating(2));
var three = <#= TLane #>.Create(<#= TNumber #>.CreateTruncating(3));
return t * t * (CreateVector<#= dimension #><<#= GenericParameters #>>(three) - (CreateVector<#= dimension #><<#= GenericParameters #>>(two) * t));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Select<<#= GenericParameters #>>(<#= TLane #> condition, in <#= vectorType #> isTrue, in <#= vectorType #> isFalse)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Select(condition, isTrue.<#= components[i] #>, isFalse.<#= components[i] #>),
<# } #>
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static <#= vectorType #> Select<<#= GenericParameters #>>(<#= vectorType #> condition, in <#= vectorType #> isTrue, in <#= vectorType #> isFalse)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new <#= vectorType #>
{
<# for (int i = 0; i < dimension; i++) { #>
<#= components[i] #> = <#= TLane #>.Select(condition.<#= components[i] #>, isTrue.<#= components[i] #>, isFalse.<#= components[i] #>),
<# } #>
};
}
# endregion
<# } #>
# region Vector3 Specific
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3<<#= GenericParameters #>> Cross<<#= GenericParameters #>>(in Vector3<<#= GenericParameters #>> a, in Vector3<<#= GenericParameters #>> b)
<#= TLaneRestrictions #>
<#= TNumberRestrictions #>
{
return new Vector3<<#= GenericParameters #>>
{
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,
};
}
# endregion
}
<#+
public string ForEachDimension(int dimension, Func<int, string> action, string spliter = ", ")
{
return string.Join(spliter, Enumerable.Range(0, dimension).Select(i => action(i)));
}
#>

View File

@@ -0,0 +1,490 @@
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
public unsafe struct Vector2<TLane, TNumber> : IEquatable<Vector2<TLane, TNumber>>
where TLane : ISPMDLane<TLane, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
public TLane x;
public TLane y;
public static Vector2<TLane, TNumber> Zero
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Vector2<TLane, TNumber>
{
x = TLane.Zero,
y = TLane.Zero,
};
}
}
public static Vector2<TLane, TNumber> One
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Vector2<TLane, TNumber>
{
x = TLane.One,
y = 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 >= 2)
{
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector2.");
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(TNumber* pDst)
{
x.Store(pDst + 0 * TLane.LaneWidth);
y.Store(pDst + 1 * TLane.LaneWidth);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(ref TNumber dst)
{
x.Store(ref Unsafe.Add(ref dst, 0 * TLane.LaneWidth));
y.Store(ref Unsafe.Add(ref dst, 1 * TLane.LaneWidth));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(TNumber* px, TNumber* py)
{
x.Store(px);
y.Store(py);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(ref TNumber x, ref TNumber y)
{
this.x.Store(ref x);
this.y.Store(ref y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CompressStore(TNumber* pDst, Vector2<TLane, TNumber> mask)
{
x.CompressStore(pDst + 0 * TLane.LaneWidth, mask.x);
y.CompressStore(pDst + 1 * TLane.LaneWidth, mask.y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CompressStore(ref TNumber dst, Vector2<TLane, TNumber> mask)
{
x.CompressStore(ref Unsafe.Add(ref dst, 0 * TLane.LaneWidth), mask.x);
y.CompressStore(ref Unsafe.Add(ref dst, 1 * TLane.LaneWidth), mask.y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(TNumber* pDst, TLane indices)
{
x.Scatter(pDst + 0, indices);
y.Scatter(pDst + 1, indices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(TNumber* pDst, int* pIndices)
{
x.Scatter(pDst + 0, pIndices);
y.Scatter(pDst + 1, pIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(ref TNumber dst, TLane indices)
{
x.Scatter(ref Unsafe.Add(ref dst, 0), indices);
y.Scatter(ref Unsafe.Add(ref dst, 1), indices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(ref TNumber dst, int* pIndices)
{
x.Scatter(ref Unsafe.Add(ref dst, 0), pIndices);
y.Scatter(ref Unsafe.Add(ref dst, 1), pIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(TNumber* pDst, TLane indices, TLane mask)
{
x.MaskScatter(pDst + 0, indices, mask);
y.MaskScatter(pDst + 1, indices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(TNumber* pDst, int* pIndices, TLane mask)
{
x.MaskScatter(pDst + 0, pIndices, mask);
y.MaskScatter(pDst + 1, pIndices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(ref TNumber dst, TLane indices, TLane mask)
{
x.MaskScatter(ref Unsafe.Add(ref dst, 0), indices, mask);
y.MaskScatter(ref Unsafe.Add(ref dst, 1), indices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(ref TNumber dst, int* pIndices, TLane mask)
{
x.MaskScatter(ref Unsafe.Add(ref dst, 0), pIndices, mask);
y.MaskScatter(ref Unsafe.Add(ref dst, 1), pIndices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator -(in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = -vector.x,
y = -vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator +(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x + right.x,
y = left.y + right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator +(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x + lane,
y = vector.y + lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator +(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane + vector.x,
y = lane + vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator -(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x - right.x,
y = left.y - right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator -(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x - lane,
y = vector.y - lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator -(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane - vector.x,
y = lane - vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator *(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x * right.x,
y = left.y * right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator *(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x * lane,
y = vector.y * lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator *(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane * vector.x,
y = lane * vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator /(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x / right.x,
y = left.y / right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator /(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x / lane,
y = vector.y / lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator /(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane / vector.x,
y = lane / vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator ==(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x == right.x,
y = left.y == right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator ==(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x == lane,
y = vector.y == lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator ==(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane == vector.x,
y = lane == vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator !=(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x != right.x,
y = left.y != right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator !=(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x != lane,
y = vector.y != lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator !=(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane != vector.x,
y = lane != vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator >(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x > right.x,
y = left.y > right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator >(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x > lane,
y = vector.y > lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator >(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane > vector.x,
y = lane > vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator >=(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x >= right.x,
y = left.y >= right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator >=(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x >= lane,
y = vector.y >= lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator >=(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane >= vector.x,
y = lane >= vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator <(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x < right.x,
y = left.y < right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator <(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x < lane,
y = vector.y < lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator <(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane < vector.x,
y = lane < vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator <=(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
{
return new Vector2<TLane, TNumber>
{
x = left.x <= right.x,
y = left.y <= right.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator <=(in Vector2<TLane, TNumber> vector, TLane lane)
{
return new Vector2<TLane, TNumber>
{
x = vector.x <= lane,
y = vector.y <= lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2<TLane, TNumber> operator <=(TLane lane, in Vector2<TLane, TNumber> vector)
{
return new Vector2<TLane, TNumber>
{
x = lane <= vector.x,
y = lane <= vector.y,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Vector2<TLane, TNumber> other)
{
return this.x.Equals(other.x) && this.y.Equals(other.y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly bool Equals(object? obj)
{
return obj is Vector2<TLane, TNumber> other && Equals(other);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly int GetHashCode()
{
var hash = new HashCode();
hash.Add(x);
hash.Add(y);
return hash.ToHashCode();
}
}

View File

@@ -0,0 +1,13 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ include file="Vector{T}Helper.ttinclude" #>
<#@ output extension=".gen.cs" #>
<#
var code = GenerateVectorType(2);
#>
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
<#= code #>

View File

@@ -0,0 +1,539 @@
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
public unsafe struct Vector3<TLane, TNumber> : IEquatable<Vector3<TLane, TNumber>>
where TLane : ISPMDLane<TLane, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
public TLane x;
public TLane y;
public TLane z;
public static Vector3<TLane, TNumber> Zero
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Vector3<TLane, TNumber>
{
x = TLane.Zero,
y = TLane.Zero,
z = TLane.Zero,
};
}
}
public static Vector3<TLane, TNumber> One
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Vector3<TLane, TNumber>
{
x = TLane.One,
y = TLane.One,
z = 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 >= 3)
{
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector3.");
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(TNumber* pDst)
{
x.Store(pDst + 0 * TLane.LaneWidth);
y.Store(pDst + 1 * TLane.LaneWidth);
z.Store(pDst + 2 * TLane.LaneWidth);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(ref TNumber dst)
{
x.Store(ref Unsafe.Add(ref dst, 0 * TLane.LaneWidth));
y.Store(ref Unsafe.Add(ref dst, 1 * TLane.LaneWidth));
z.Store(ref Unsafe.Add(ref dst, 2 * TLane.LaneWidth));
}
[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 void CompressStore(TNumber* pDst, Vector3<TLane, TNumber> mask)
{
x.CompressStore(pDst + 0 * TLane.LaneWidth, mask.x);
y.CompressStore(pDst + 1 * TLane.LaneWidth, mask.y);
z.CompressStore(pDst + 2 * TLane.LaneWidth, mask.z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CompressStore(ref TNumber dst, Vector3<TLane, TNumber> mask)
{
x.CompressStore(ref Unsafe.Add(ref dst, 0 * TLane.LaneWidth), mask.x);
y.CompressStore(ref Unsafe.Add(ref dst, 1 * TLane.LaneWidth), mask.y);
z.CompressStore(ref Unsafe.Add(ref dst, 2 * TLane.LaneWidth), mask.z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(TNumber* pDst, TLane indices)
{
x.Scatter(pDst + 0, indices);
y.Scatter(pDst + 1, indices);
z.Scatter(pDst + 2, indices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(TNumber* pDst, int* pIndices)
{
x.Scatter(pDst + 0, pIndices);
y.Scatter(pDst + 1, pIndices);
z.Scatter(pDst + 2, pIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(ref TNumber dst, TLane indices)
{
x.Scatter(ref Unsafe.Add(ref dst, 0), indices);
y.Scatter(ref Unsafe.Add(ref dst, 1), indices);
z.Scatter(ref Unsafe.Add(ref dst, 2), indices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(ref TNumber dst, int* pIndices)
{
x.Scatter(ref Unsafe.Add(ref dst, 0), pIndices);
y.Scatter(ref Unsafe.Add(ref dst, 1), pIndices);
z.Scatter(ref Unsafe.Add(ref dst, 2), pIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(TNumber* pDst, TLane indices, TLane mask)
{
x.MaskScatter(pDst + 0, indices, mask);
y.MaskScatter(pDst + 1, indices, mask);
z.MaskScatter(pDst + 2, indices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(TNumber* pDst, int* pIndices, TLane mask)
{
x.MaskScatter(pDst + 0, pIndices, mask);
y.MaskScatter(pDst + 1, pIndices, mask);
z.MaskScatter(pDst + 2, pIndices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(ref TNumber dst, TLane indices, TLane mask)
{
x.MaskScatter(ref Unsafe.Add(ref dst, 0), indices, mask);
y.MaskScatter(ref Unsafe.Add(ref dst, 1), indices, mask);
z.MaskScatter(ref Unsafe.Add(ref dst, 2), indices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(ref TNumber dst, int* pIndices, TLane mask)
{
x.MaskScatter(ref Unsafe.Add(ref dst, 0), pIndices, mask);
y.MaskScatter(ref Unsafe.Add(ref dst, 1), pIndices, mask);
z.MaskScatter(ref Unsafe.Add(ref dst, 2), pIndices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = -vector.x,
y = -vector.y,
z = -vector.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 +(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane + vector.x,
y = lane + vector.y,
z = lane + vector.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 -(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane - vector.x,
y = lane - vector.y,
z = lane - vector.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 *(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane * vector.x,
y = lane * vector.y,
z = lane * vector.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 /(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane / vector.x,
y = lane / vector.y,
z = lane / vector.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 ==(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane == vector.x,
y = lane == vector.y,
z = lane == vector.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 !=(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane != vector.x,
y = lane != vector.y,
z = lane != vector.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 >(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane > vector.x,
y = lane > vector.y,
z = lane > vector.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 >=(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane >= vector.x,
y = lane >= vector.y,
z = lane >= vector.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 <(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane < vector.x,
y = lane < vector.y,
z = lane < vector.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 <=(TLane lane, in Vector3<TLane, TNumber> vector)
{
return new Vector3<TLane, TNumber>
{
x = lane <= vector.x,
y = lane <= vector.y,
z = lane <= vector.z,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Vector3<TLane, TNumber> other)
{
return this.x.Equals(other.x) && this.y.Equals(other.y) && this.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 readonly int GetHashCode()
{
var hash = new HashCode();
hash.Add(x);
hash.Add(y);
hash.Add(z);
return hash.ToHashCode();
}
}

View File

@@ -0,0 +1,13 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ include file="Vector{T}Helper.ttinclude" #>
<#@ output extension=".gen.cs" #>
<#
var code = GenerateVectorType(3);
#>
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
<#= code #>

View File

@@ -0,0 +1,588 @@
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
public unsafe struct Vector4<TLane, TNumber> : IEquatable<Vector4<TLane, TNumber>>
where TLane : ISPMDLane<TLane, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
public TLane x;
public TLane y;
public TLane z;
public TLane w;
public static Vector4<TLane, TNumber> Zero
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Vector4<TLane, TNumber>
{
x = TLane.Zero,
y = TLane.Zero,
z = TLane.Zero,
w = TLane.Zero,
};
}
}
public static Vector4<TLane, TNumber> One
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Vector4<TLane, TNumber>
{
x = TLane.One,
y = TLane.One,
z = TLane.One,
w = 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 >= 4)
{
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector4.");
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(TNumber* pDst)
{
x.Store(pDst + 0 * TLane.LaneWidth);
y.Store(pDst + 1 * TLane.LaneWidth);
z.Store(pDst + 2 * TLane.LaneWidth);
w.Store(pDst + 3 * TLane.LaneWidth);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(ref TNumber dst)
{
x.Store(ref Unsafe.Add(ref dst, 0 * TLane.LaneWidth));
y.Store(ref Unsafe.Add(ref dst, 1 * TLane.LaneWidth));
z.Store(ref Unsafe.Add(ref dst, 2 * TLane.LaneWidth));
w.Store(ref Unsafe.Add(ref dst, 3 * TLane.LaneWidth));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(TNumber* px, TNumber* py, TNumber* pz, TNumber* pw)
{
x.Store(px);
y.Store(py);
z.Store(pz);
w.Store(pw);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Store(ref TNumber x, ref TNumber y, ref TNumber z, ref TNumber w)
{
this.x.Store(ref x);
this.y.Store(ref y);
this.z.Store(ref z);
this.w.Store(ref w);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CompressStore(TNumber* pDst, Vector4<TLane, TNumber> mask)
{
x.CompressStore(pDst + 0 * TLane.LaneWidth, mask.x);
y.CompressStore(pDst + 1 * TLane.LaneWidth, mask.y);
z.CompressStore(pDst + 2 * TLane.LaneWidth, mask.z);
w.CompressStore(pDst + 3 * TLane.LaneWidth, mask.w);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CompressStore(ref TNumber dst, Vector4<TLane, TNumber> mask)
{
x.CompressStore(ref Unsafe.Add(ref dst, 0 * TLane.LaneWidth), mask.x);
y.CompressStore(ref Unsafe.Add(ref dst, 1 * TLane.LaneWidth), mask.y);
z.CompressStore(ref Unsafe.Add(ref dst, 2 * TLane.LaneWidth), mask.z);
w.CompressStore(ref Unsafe.Add(ref dst, 3 * TLane.LaneWidth), mask.w);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(TNumber* pDst, TLane indices)
{
x.Scatter(pDst + 0, indices);
y.Scatter(pDst + 1, indices);
z.Scatter(pDst + 2, indices);
w.Scatter(pDst + 3, indices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(TNumber* pDst, int* pIndices)
{
x.Scatter(pDst + 0, pIndices);
y.Scatter(pDst + 1, pIndices);
z.Scatter(pDst + 2, pIndices);
w.Scatter(pDst + 3, pIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(ref TNumber dst, TLane indices)
{
x.Scatter(ref Unsafe.Add(ref dst, 0), indices);
y.Scatter(ref Unsafe.Add(ref dst, 1), indices);
z.Scatter(ref Unsafe.Add(ref dst, 2), indices);
w.Scatter(ref Unsafe.Add(ref dst, 3), indices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Scatter(ref TNumber dst, int* pIndices)
{
x.Scatter(ref Unsafe.Add(ref dst, 0), pIndices);
y.Scatter(ref Unsafe.Add(ref dst, 1), pIndices);
z.Scatter(ref Unsafe.Add(ref dst, 2), pIndices);
w.Scatter(ref Unsafe.Add(ref dst, 3), pIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(TNumber* pDst, TLane indices, TLane mask)
{
x.MaskScatter(pDst + 0, indices, mask);
y.MaskScatter(pDst + 1, indices, mask);
z.MaskScatter(pDst + 2, indices, mask);
w.MaskScatter(pDst + 3, indices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(TNumber* pDst, int* pIndices, TLane mask)
{
x.MaskScatter(pDst + 0, pIndices, mask);
y.MaskScatter(pDst + 1, pIndices, mask);
z.MaskScatter(pDst + 2, pIndices, mask);
w.MaskScatter(pDst + 3, pIndices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(ref TNumber dst, TLane indices, TLane mask)
{
x.MaskScatter(ref Unsafe.Add(ref dst, 0), indices, mask);
y.MaskScatter(ref Unsafe.Add(ref dst, 1), indices, mask);
z.MaskScatter(ref Unsafe.Add(ref dst, 2), indices, mask);
w.MaskScatter(ref Unsafe.Add(ref dst, 3), indices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MaskScatter(ref TNumber dst, int* pIndices, TLane mask)
{
x.MaskScatter(ref Unsafe.Add(ref dst, 0), pIndices, mask);
y.MaskScatter(ref Unsafe.Add(ref dst, 1), pIndices, mask);
z.MaskScatter(ref Unsafe.Add(ref dst, 2), pIndices, mask);
w.MaskScatter(ref Unsafe.Add(ref dst, 3), pIndices, mask);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator -(in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = -vector.x,
y = -vector.y,
z = -vector.z,
w = -vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator +(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x + right.x,
y = left.y + right.y,
z = left.z + right.z,
w = left.w + right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator +(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x + lane,
y = vector.y + lane,
z = vector.z + lane,
w = vector.w + lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator +(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane + vector.x,
y = lane + vector.y,
z = lane + vector.z,
w = lane + vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator -(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x - right.x,
y = left.y - right.y,
z = left.z - right.z,
w = left.w - right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator -(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x - lane,
y = vector.y - lane,
z = vector.z - lane,
w = vector.w - lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator -(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane - vector.x,
y = lane - vector.y,
z = lane - vector.z,
w = lane - vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator *(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x * right.x,
y = left.y * right.y,
z = left.z * right.z,
w = left.w * right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator *(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x * lane,
y = vector.y * lane,
z = vector.z * lane,
w = vector.w * lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator *(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane * vector.x,
y = lane * vector.y,
z = lane * vector.z,
w = lane * vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator /(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x / right.x,
y = left.y / right.y,
z = left.z / right.z,
w = left.w / right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator /(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x / lane,
y = vector.y / lane,
z = vector.z / lane,
w = vector.w / lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator /(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane / vector.x,
y = lane / vector.y,
z = lane / vector.z,
w = lane / vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator ==(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x == right.x,
y = left.y == right.y,
z = left.z == right.z,
w = left.w == right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator ==(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x == lane,
y = vector.y == lane,
z = vector.z == lane,
w = vector.w == lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator ==(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane == vector.x,
y = lane == vector.y,
z = lane == vector.z,
w = lane == vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator !=(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x != right.x,
y = left.y != right.y,
z = left.z != right.z,
w = left.w != right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator !=(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x != lane,
y = vector.y != lane,
z = vector.z != lane,
w = vector.w != lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator !=(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane != vector.x,
y = lane != vector.y,
z = lane != vector.z,
w = lane != vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator >(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x > right.x,
y = left.y > right.y,
z = left.z > right.z,
w = left.w > right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator >(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x > lane,
y = vector.y > lane,
z = vector.z > lane,
w = vector.w > lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator >(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane > vector.x,
y = lane > vector.y,
z = lane > vector.z,
w = lane > vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator >=(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x >= right.x,
y = left.y >= right.y,
z = left.z >= right.z,
w = left.w >= right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator >=(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x >= lane,
y = vector.y >= lane,
z = vector.z >= lane,
w = vector.w >= lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator >=(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane >= vector.x,
y = lane >= vector.y,
z = lane >= vector.z,
w = lane >= vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator <(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x < right.x,
y = left.y < right.y,
z = left.z < right.z,
w = left.w < right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator <(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x < lane,
y = vector.y < lane,
z = vector.z < lane,
w = vector.w < lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator <(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane < vector.x,
y = lane < vector.y,
z = lane < vector.z,
w = lane < vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator <=(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
{
return new Vector4<TLane, TNumber>
{
x = left.x <= right.x,
y = left.y <= right.y,
z = left.z <= right.z,
w = left.w <= right.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator <=(in Vector4<TLane, TNumber> vector, TLane lane)
{
return new Vector4<TLane, TNumber>
{
x = vector.x <= lane,
y = vector.y <= lane,
z = vector.z <= lane,
w = vector.w <= lane,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4<TLane, TNumber> operator <=(TLane lane, in Vector4<TLane, TNumber> vector)
{
return new Vector4<TLane, TNumber>
{
x = lane <= vector.x,
y = lane <= vector.y,
z = lane <= vector.z,
w = lane <= vector.w,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Vector4<TLane, TNumber> other)
{
return this.x.Equals(other.x) && this.y.Equals(other.y) && this.z.Equals(other.z) && this.w.Equals(other.w);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly bool Equals(object? obj)
{
return obj is Vector4<TLane, TNumber> other && Equals(other);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly int GetHashCode()
{
var hash = new HashCode();
hash.Add(x);
hash.Add(y);
hash.Add(z);
hash.Add(w);
return hash.ToHashCode();
}
}

View File

@@ -0,0 +1,13 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ include file="Vector{T}Helper.ttinclude" #>
<#@ output extension=".gen.cs" #>
<#
var code = GenerateVectorType(4);
#>
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
<#= code #>

View File

@@ -0,0 +1,482 @@
<#@ 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;
}
#>

View File

@@ -0,0 +1,63 @@
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
public readonly unsafe partial struct WideLane<TNumber> : ISPMDLane<WideLane<TNumber>, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TOther Cast<TOther, TOtherNumber>()
where TOther : ISPMDLane<TOther, TOtherNumber>
where TOtherNumber : unmanaged, INumber<TOtherNumber>, IBinaryNumber<TOtherNumber>, IMinMaxValue<TOtherNumber>, IBitwiseOperators<TOtherNumber, TOtherNumber, TOtherNumber>
{
if (typeof(TNumber) == typeof(float) && typeof(TOtherNumber) == typeof(int))
{
return Unsafe.BitCast<Vector<int>, TOther>(Vector.ConvertToInt32(Unsafe.BitCast<Vector<TNumber>, Vector<float>>(value)));
}
if (typeof(TNumber) == typeof(float) && typeof(TOtherNumber) == typeof(uint))
{
return Unsafe.BitCast<Vector<uint>, TOther>(Vector.ConvertToUInt32(Unsafe.BitCast<Vector<TNumber>, Vector<float>>(value)));
}
if (typeof(TNumber) == typeof(double) && typeof(TOtherNumber) == typeof(long))
{
return Unsafe.BitCast<Vector<long>, TOther>(Vector.ConvertToInt64(Unsafe.BitCast<Vector<TNumber>, Vector<double>>(value)));
}
if (typeof(TNumber) == typeof(double) && typeof(TOtherNumber) == typeof(ulong))
{
return Unsafe.BitCast<Vector<ulong>, TOther>(Vector.ConvertToUInt64(Unsafe.BitCast<Vector<TNumber>, Vector<double>>(value)));
}
if (typeof(TNumber) == typeof(int) && typeof(TOtherNumber) == typeof(float))
{
return Unsafe.BitCast<Vector<float>, TOther>(Vector.ConvertToSingle(Unsafe.BitCast<Vector<TNumber>, Vector<int>>(value)));
}
if (typeof(TNumber) == typeof(uint) && typeof(TOtherNumber) == typeof(float))
{
return Unsafe.BitCast<Vector<float>, TOther>(Vector.ConvertToSingle(Unsafe.BitCast<Vector<TNumber>, Vector<uint>>(value)));
}
if (typeof(TNumber) == typeof(long) && typeof(TOtherNumber) == typeof(double))
{
return Unsafe.BitCast<Vector<double>, TOther>(Vector.ConvertToDouble(Unsafe.BitCast<Vector<TNumber>, Vector<long>>(value)));
}
if (typeof(TNumber) == typeof(ulong) && typeof(TOtherNumber) == typeof(double))
{
return Unsafe.BitCast<Vector<double>, TOther>(Vector.ConvertToDouble(Unsafe.BitCast<Vector<TNumber>, Vector<ulong>>(value)));
}
var casted = stackalloc TOtherNumber[LaneWidth];
for (var i = 0; (i < LaneWidth) && (i < TOther.LaneWidth); i++)
{
casted[i] = TOtherNumber.CreateTruncating(value[i]);
}
return TOther.Load(casted);
}
}

View File

@@ -0,0 +1,57 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".gen.cs" #>
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.HPC;
<#
var conversions = new CastRoute[]
{
new CastRoute { From = "float", To = "int", Method = "Vector.ConvertToInt32" },
new CastRoute { From = "float", To = "uint", Method = "Vector.ConvertToUInt32" },
new CastRoute { From = "double", To = "long", Method = "Vector.ConvertToInt64" },
new CastRoute { From = "double", To = "ulong", Method = "Vector.ConvertToUInt64" },
new CastRoute { From = "int", To = "float", Method = "Vector.ConvertToSingle" },
new CastRoute { From = "uint", To = "float", Method = "Vector.ConvertToSingle" },
new CastRoute { From = "long", To = "double", Method = "Vector.ConvertToDouble" },
new CastRoute { From = "ulong", To = "double", Method = "Vector.ConvertToDouble" },
};
#>
public readonly unsafe partial struct WideLane<TNumber> : ISPMDLane<WideLane<TNumber>, TNumber>
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TOther Cast<TOther, TOtherNumber>()
where TOther : ISPMDLane<TOther, TOtherNumber>
where TOtherNumber : unmanaged, INumber<TOtherNumber>, IBinaryNumber<TOtherNumber>, IMinMaxValue<TOtherNumber>, IBitwiseOperators<TOtherNumber, TOtherNumber, TOtherNumber>
{
<# foreach (var c in conversions) { #>
if (typeof(TNumber) == typeof(<#= c.From #>) && typeof(TOtherNumber) == typeof(<#= c.To #>))
{
return Unsafe.BitCast<Vector<<#= c.To #>>, TOther>(<#= c.Method #>(Unsafe.BitCast<Vector<TNumber>, Vector<<#= c.From #>>>(value)));
}
<# } #>
var casted = stackalloc TOtherNumber[LaneWidth];
for (var i = 0; (i < LaneWidth) && (i < TOther.LaneWidth); i++)
{
casted[i] = TOtherNumber.CreateTruncating(value[i]);
}
return TOther.Load(casted);
}
}
<#+
public struct CastRoute
{
public string From;
public string To;
public string Method;
}
#>