Enhance mathematical capabilities and job system
Added new numeric types for unsigned integers, including uint2, uint3, and uint4, along with their matrix types. Added a new `quaternion` struct with constructors and methods for creating and manipulating quaternions. Added methods for projecting and reflecting vectors, enhancing geometric operations. Added utility functions for generating orthonormal bases and changing vector signs. Added comprehensive unit tests for new mathematical functions and quaternion operations. Added a high-performance job scheduling system with job management features and worker thread management. Added new structs for job execution, allowing efficient job scheduling and execution. Added utility functions for job execution, including methods for obtaining unique job IDs. Changed access modifiers and property definitions in several files for improved clarity and maintainability. Changed property definitions and method implementations in `ImageInfo.cs`, `ImageResult.cs`, and `ImageResultFloat.cs` for better readability. Changed memory management functions in `CRuntime.cs` and improved memory allocation tracking in `MemoryStats.cs`. Changed the project file to include references to necessary projects and enable unsafe code blocks. Removed the `WorkerThreadPool.cs` file, integrating worker thread management directly into the `JobScheduler`. Removed the `float4` struct and its associated methods and properties, transitioning to a new code generation strategy. Removed the `float4.tt` template and other related files, indicating a shift in code generation approach. Removed the `Vectorize.cs` file, indicating a change in how vector operations are handled. Updated the `.gitignore` file to include IDE-specific settings. Updated various XML files to define project components and structure. Updated the `AllocationManager.cs` to improve memory allocation management and introduce new strategies. Updated the `UnsafeArray.cs`, `UnsafeHashMap.cs`, and `UnsafeList.cs` to enhance performance and safety in unsafe contexts. Updated error handling and function pointer management in `MemoryLeakException.cs` and `FunctionPointer.cs`. Updated the `AssemblyInfo.cs` file to include global using directives for better code organization.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Misaki.HighPerformance.Mathematics.CodeGen.Models;
|
||||
using System.Text;
|
||||
|
||||
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
||||
{
|
||||
internal abstract class GeneratorBase
|
||||
{
|
||||
protected const string INLINE_METHOD_ATTRIBUTE = "[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]";
|
||||
|
||||
protected readonly StringBuilder sourceBuilder = new();
|
||||
protected NumericTypeInfo typeInfo = null!;
|
||||
|
||||
public string Generate(NumericTypeInfo typeInfo)
|
||||
{
|
||||
this.typeInfo = typeInfo;
|
||||
sourceBuilder.Clear();
|
||||
|
||||
Initialize();
|
||||
|
||||
GenerateHeader();
|
||||
GenerateNamespaceStart();
|
||||
GenerateTypeStart();
|
||||
|
||||
GenerateBody();
|
||||
|
||||
GenerateTypeEnd();
|
||||
GenerateNamespaceEnd();
|
||||
|
||||
return sourceBuilder.ToString();
|
||||
}
|
||||
|
||||
protected virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void GenerateHeader()
|
||||
{
|
||||
sourceBuilder.AppendLine("// <auto-generated/>");
|
||||
}
|
||||
|
||||
protected virtual void GenerateNamespaceStart()
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
namespace {typeInfo.TypeSymbol.ContainingNamespace.ToDisplayString()}
|
||||
{{");
|
||||
}
|
||||
|
||||
protected virtual void GenerateTypeStart()
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
[global::System.Runtime.CompilerServices.SkipLocalsInit]
|
||||
public partial struct {typeInfo.TypeSymbol.Name} : global::System.IEquatable<{typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>
|
||||
{{");
|
||||
}
|
||||
|
||||
protected abstract void GenerateBody();
|
||||
|
||||
protected virtual void GenerateTypeEnd()
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
}}");
|
||||
}
|
||||
|
||||
protected virtual void GenerateNamespaceEnd()
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
}}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,752 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
||||
{
|
||||
internal class MatrixGenerator : GeneratorBase
|
||||
{
|
||||
private readonly string[] _matrixComponents = new[] { "c0", "c1", "c2", "c3" };
|
||||
private readonly string[] _vectorComponents = new[] { "x", "y", "z", "w" };
|
||||
|
||||
protected override void GenerateBody()
|
||||
{
|
||||
GenerateField();
|
||||
if (typeInfo.Arithmetic)
|
||||
{
|
||||
GenerateUnitMatrix();
|
||||
}
|
||||
GenerateConstructors();
|
||||
GenerateUnsafeMethod();
|
||||
GenerateOverrideMethod();
|
||||
if (typeInfo.Arithmetic)
|
||||
{
|
||||
GenerateArithmeticOperators();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void GenerateTypeEnd()
|
||||
{
|
||||
base.GenerateTypeEnd();
|
||||
sourceBuilder.AppendLine();
|
||||
GenerateMathMethod();
|
||||
}
|
||||
|
||||
private void GenerateField()
|
||||
{
|
||||
for (var i = 0; i < typeInfo.Column; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
public {typeInfo.ComponentTypeFullName} {_matrixComponents[i]};");
|
||||
}
|
||||
|
||||
sourceBuilder.AppendLine();
|
||||
sourceBuilder.AppendLine($@"
|
||||
public unsafe ref {typeInfo.ComponentTypeFullName} this[int index] {{
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
get => ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateUnitMatrix()
|
||||
{
|
||||
if (typeInfo.Column == typeInfo.Row)
|
||||
{
|
||||
var tempSB = new StringBuilder();
|
||||
for (var i = 0; i < typeInfo.Column; i++)
|
||||
{
|
||||
tempSB.Append($"new {typeInfo.ComponentTypeFullName}(");
|
||||
for (var j = 0; j < typeInfo.Row; j++)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
tempSB.Append("1");
|
||||
}
|
||||
else
|
||||
{
|
||||
tempSB.Append("0");
|
||||
}
|
||||
if (j < typeInfo.Row - 1)
|
||||
{
|
||||
tempSB.Append(", ");
|
||||
}
|
||||
}
|
||||
tempSB.Append(")");
|
||||
if (i < typeInfo.Column - 1)
|
||||
{
|
||||
tempSB.Append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeInfo.TypeFullName} identity => new {typeInfo.TypeFullName}({string.Join(", ", tempSB.ToString())});");
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeInfo.TypeFullName} zero => default;");
|
||||
sourceBuilder.AppendLine();
|
||||
}
|
||||
|
||||
private void GenerateConstructors()
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
public unsafe {typeInfo.TypeName}(in global::System.ReadOnlySpan<{typeInfo.ComponentTypeFullName}> values)
|
||||
{{
|
||||
if (values.Length < {typeInfo.Column})
|
||||
{{
|
||||
throw new global::System.ArgumentException($""Expected at least {typeInfo.Column} values, but got {{values.Length}}"", nameof(values));
|
||||
}}
|
||||
|
||||
fixed ({typeInfo.TypeName}* pThis = &this)
|
||||
fixed ({typeInfo.ComponentTypeFullName}* pValues = values)
|
||||
{{
|
||||
*pThis = *({typeInfo.TypeName}*)pValues;
|
||||
}}
|
||||
}}");
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public {typeInfo.TypeName}({typeInfo.ComponentTypeFullName} value)
|
||||
{{");
|
||||
for (var i = 0; i < typeInfo.Column; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
this.{_matrixComponents[i]} = value;");
|
||||
}
|
||||
sourceBuilder.AppendLine(@"
|
||||
}");
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public {typeInfo.TypeName}({string.Join(", ", Enumerable.Range(0, typeInfo.Column).Select(i => $"{typeInfo.ComponentTypeFullName} c{i}"))})
|
||||
{{");
|
||||
for (var i = 0; i < typeInfo.Column; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
this.{_matrixComponents[i]} = c{i};");
|
||||
}
|
||||
sourceBuilder.Append(@"
|
||||
}");
|
||||
|
||||
if (typeInfo.ElementTypeSymbol != null)
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
public unsafe {typeInfo.TypeName}(in global::System.ReadOnlySpan<{typeInfo.ElementTypeFullName}> values)
|
||||
{{
|
||||
if (values.Length < {typeInfo.Column * typeInfo.Row})
|
||||
{{
|
||||
throw new global::System.ArgumentException($""Expected at least {typeInfo.Column * typeInfo.Row} values, but got {{values.Length}}"", nameof(values));
|
||||
}}
|
||||
|
||||
fixed ({typeInfo.TypeName}* pThis = &this)
|
||||
fixed ({typeInfo.ElementTypeFullName}* pValues = values)
|
||||
{{
|
||||
*pThis = *({typeInfo.TypeName}*)pValues;
|
||||
}}
|
||||
}}");
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public {typeInfo.TypeName}({typeInfo.ElementTypeFullName} value)
|
||||
{{");
|
||||
for (var c = 0; c < typeInfo.Column; c++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
this.{_matrixComponents[c]} = value;");
|
||||
}
|
||||
sourceBuilder.AppendLine($@"
|
||||
}}");
|
||||
|
||||
var tempSB = new StringBuilder();
|
||||
for (var r = 0; r < typeInfo.Row; r++)
|
||||
{
|
||||
for (var c = 0; c < typeInfo.Column; c++)
|
||||
{
|
||||
tempSB.Append($"{typeInfo.ElementTypeFullName} m{r}{c}");
|
||||
if (!(r == typeInfo.Row - 1 && c == typeInfo.Column - 1))
|
||||
{
|
||||
tempSB.Append(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public {typeInfo.TypeName}({tempSB})
|
||||
{{");
|
||||
for (var c = 0; c < typeInfo.Column; c++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
this.{_matrixComponents[c]} = new({string.Join(", ", Enumerable.Range(0, typeInfo.Row).Select(r => $"m{r}{c}"))});");
|
||||
}
|
||||
sourceBuilder.AppendLine($@"
|
||||
}}");
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateUnsafeMethod()
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public unsafe {typeInfo.ComponentTypeFullName}* AsPointer()
|
||||
{{
|
||||
return ({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public unsafe global::System.Span<{typeInfo.ComponentTypeFullName}> AsSpan()
|
||||
{{
|
||||
return new global::System.Span<{typeInfo.ComponentTypeFullName}>(AsPointer(), {typeInfo.Column});
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateOverrideMethod()
|
||||
{
|
||||
var components = _matrixComponents.Take(typeInfo.Column).ToArray();
|
||||
sourceBuilder.AppendLine($@"
|
||||
public override readonly string ToString()
|
||||
{{
|
||||
return $""({string.Join(", ", components.Select(c => $"{c}: {{this.{c}}}"))})"";
|
||||
}}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{{
|
||||
return global::System.HashCode.Combine({string.Join(", ", components.Select(c => $"this.{c}"))});
|
||||
}}
|
||||
|
||||
public override readonly bool Equals(object? obj)
|
||||
{{
|
||||
return obj is {typeInfo.TypeFullName} value && Equals(value);
|
||||
}}
|
||||
|
||||
public readonly bool Equals({typeInfo.TypeFullName} other)
|
||||
{{
|
||||
return {string.Join(" && ", components.Select(c => $"this.{c}.Equals(other.{c})"))};
|
||||
}}
|
||||
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row}x{typeInfo.Column} operator ==({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", components.Select(c => $"lhs.{c} == rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row}x{typeInfo.Column} operator !=({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", components.Select(c => $"lhs.{c} != rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static implicit operator {typeInfo.TypeFullName}(global::System.ReadOnlySpan<{typeInfo.ComponentTypeFullName}> value)
|
||||
{{
|
||||
return new {typeInfo.TypeFullName}(value);
|
||||
}}
|
||||
|
||||
public static implicit operator {typeInfo.TypeFullName}({typeInfo.ComponentTypeFullName} value)
|
||||
{{
|
||||
return new(value);
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateArithmeticOperators()
|
||||
{
|
||||
// Add
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator +({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} + rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator +({typeInfo.TypeFullName} lhs, {typeInfo.ComponentTypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} + rhs"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator +({typeInfo.ComponentTypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs + rhs.{c}"))});
|
||||
}}");
|
||||
|
||||
// Subtract
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator -({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} - rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator -({typeInfo.TypeFullName} lhs, {typeInfo.ComponentTypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} - rhs"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator -({typeInfo.ComponentTypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs - rhs.{c}"))});
|
||||
}}");
|
||||
|
||||
// Multiply
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator *({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} * rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator *({typeInfo.TypeFullName} lhs, {typeInfo.ComponentTypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} * rhs"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator *({typeInfo.ComponentTypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs * rhs.{c}"))});
|
||||
}}");
|
||||
|
||||
// Divide
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator /({typeInfo.ComponentTypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs / rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator /({typeInfo.TypeFullName} lhs, {typeInfo.ComponentTypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} / rhs"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator /({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} / rhs.{c}"))});
|
||||
}}");
|
||||
|
||||
// Modulus
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator %({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} % rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator %({typeInfo.TypeFullName} lhs, {typeInfo.ComponentTypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} % rhs"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator %({typeInfo.ComponentTypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs % rhs.{c}"))});
|
||||
}}");
|
||||
|
||||
// Unary operators
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator +({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
return value;
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator -({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"-value.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator ++({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"value.{c} + 1"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator --({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"value.{c} - 1"))});
|
||||
}}");
|
||||
|
||||
// Comparison operators
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row}x{typeInfo.Column} operator <({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} < rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row}x{typeInfo.Column} operator <=({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} <= rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row}x{typeInfo.Column} operator >({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} > rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row}x{typeInfo.Column} operator >=({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} >= rhs.{c}"))});
|
||||
}}");
|
||||
|
||||
// Bitwise operators
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} operator <<({typeInfo.TypeFullName} lhs, int shift)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} << shift"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator >>({typeInfo.TypeFullName} lhs, int shift)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} >> shift"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator &({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} & rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator |({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} | rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator ^({typeInfo.TypeFullName} lhs, {typeInfo.TypeFullName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"lhs.{c} ^ rhs.{c}"))});
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} operator ~({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
return new({string.Join(", ", _matrixComponents.Take(typeInfo.Column).Select(c => $"~value.{c}"))});
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateMathMethod()
|
||||
{
|
||||
if (typeInfo.ElementTypeSymbol == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public static partial class math
|
||||
{{
|
||||
public static {typeInfo.TypePrefix}{typeInfo.Column}x{typeInfo.Row} transpose({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
return new {typeInfo.TypePrefix}{typeInfo.Column}x{typeInfo.Row}(");
|
||||
for (var i = 0; i < typeInfo.Column; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
{string.Join(", ", _matrixComponents.Take(typeInfo.Row).Select((c, j) => $"value.{_matrixComponents[i]}.{_vectorComponents[j]}"))}");
|
||||
if (i < typeInfo.Column - 1)
|
||||
{
|
||||
sourceBuilder.Append(",");
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceBuilder.Append(");");
|
||||
}
|
||||
}
|
||||
sourceBuilder.AppendLine($@"
|
||||
}}");
|
||||
|
||||
if (typeInfo.Arithmetic)
|
||||
{
|
||||
if (typeInfo.Row == typeInfo.Column)
|
||||
{
|
||||
GenerateDeterminantMethod();
|
||||
|
||||
if (typeInfo.CanInverse)
|
||||
{
|
||||
if (typeInfo.Row == 2)
|
||||
{
|
||||
GenerateInverse2x2Method();
|
||||
}
|
||||
else if (typeInfo.Row == 3)
|
||||
{
|
||||
GenerateInverse3x3Method();
|
||||
}
|
||||
else if (typeInfo.Row == 4)
|
||||
{
|
||||
GenerateInverse4x4Method();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenerateMulMethod();
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateInverse2x2Method()
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} inverse({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
var c0 = value.{_matrixComponents[0]};
|
||||
var c1 = value.{_matrixComponents[1]};
|
||||
|
||||
// elements
|
||||
var m00 = c0.x;
|
||||
var m01 = c1.x;
|
||||
var m10 = c0.y;
|
||||
var m11 = c1.y;
|
||||
|
||||
var det = m00 * m11 - m01 * m10;
|
||||
if (det == 0.0f)
|
||||
{{
|
||||
throw new System.InvalidOperationException(""Matrix is singular"");
|
||||
}}
|
||||
|
||||
var invDet = 1.0f / det;
|
||||
|
||||
// adjugate: [ d -b; -c a ]
|
||||
return new(new(m11 * invDet, -m10 * invDet), new(-m01 * invDet, m00 * invDet));
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateInverse3x3Method()
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} inverse({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
var c0 = value.{_matrixComponents[0]};
|
||||
var c1 = value.{_matrixComponents[1]};
|
||||
var c2 = value.{_matrixComponents[2]};
|
||||
|
||||
var a00 = c0.x;
|
||||
var a01 = c1.x;
|
||||
var a02 = c2.x;
|
||||
var a10 = c0.y;
|
||||
var a11 = c1.y;
|
||||
var a12 = c2.y;
|
||||
var a20 = c0.z;
|
||||
var a21 = c1.z;
|
||||
var a22 = c2.z;
|
||||
|
||||
// cofactors (adjugate transposed)
|
||||
var c00 = a11 * a22 - a12 * a21;
|
||||
var c01 = - (a10 * a22 - a12 * a20);
|
||||
var c02 = a10 * a21 - a11 * a20;
|
||||
|
||||
var c10 = - (a01 * a22 - a02 * a21);
|
||||
var c11 = a00 * a22 - a02 * a20;
|
||||
var c12 = - (a00 * a21 - a01 * a20);
|
||||
|
||||
var c20 = a01 * a12 - a02 * a11;
|
||||
var c21 = - (a00 * a12 - a02 * a10);
|
||||
var c22 = a00 * a11 - a01 * a10;
|
||||
|
||||
var det = a00 * c00 + a01 * c01 + a02 * c02;
|
||||
if (det == 0.0f)
|
||||
{{
|
||||
throw new System.InvalidOperationException(""Matrix is singular"");
|
||||
}}
|
||||
|
||||
var invDet = 1.0f / det;
|
||||
|
||||
// adjugate is transpose of cofactor matrix (we computed cofactors already)
|
||||
return new(new(c00 * invDet, c10 * invDet, c20 * invDet), new(c01 * invDet, c11 * invDet, c21 * invDet), new(c02 * invDet, c12 * invDet, c22 * invDet));
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateInverse4x4Method()
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeInfo.TypeFullName} inverse({typeInfo.TypeFullName} value)
|
||||
{{
|
||||
var c0 = value.{_matrixComponents[0]};
|
||||
var c1 = value.{_matrixComponents[1]};
|
||||
var c2 = value.{_matrixComponents[2]};
|
||||
var c3 = value.{_matrixComponents[3]};
|
||||
|
||||
// movelh
|
||||
var r0y_r1y_r0x_r1x = shuffle(c1, c0, ShuffleComponent.LeftX, ShuffleComponent.LeftY, ShuffleComponent.RightX, ShuffleComponent.RightY);
|
||||
var r0z_r1z_r0w_r1w = shuffle(c2, c3, ShuffleComponent.LeftX, ShuffleComponent.LeftY, ShuffleComponent.RightX, ShuffleComponent.RightY);
|
||||
// movehl
|
||||
var r2y_r3y_r2x_r3x = shuffle(c1, c0, ShuffleComponent.LeftZ, ShuffleComponent.LeftW, ShuffleComponent.RightZ, ShuffleComponent.RightW);
|
||||
var r2z_r3z_r2w_r3w = shuffle(c2, c3, ShuffleComponent.LeftZ, ShuffleComponent.LeftW, ShuffleComponent.RightZ, ShuffleComponent.RightW);
|
||||
|
||||
var r1y_r2y_r1x_r2x = shuffle(c1, c0, ShuffleComponent.LeftY, ShuffleComponent.LeftZ, ShuffleComponent.RightY, ShuffleComponent.RightZ);
|
||||
var r1z_r2z_r1w_r2w = shuffle(c2, c3, ShuffleComponent.LeftY, ShuffleComponent.LeftZ, ShuffleComponent.RightY, ShuffleComponent.RightZ);
|
||||
var r3y_r0y_r3x_r0x = shuffle(c1, c0, ShuffleComponent.LeftW, ShuffleComponent.LeftX, ShuffleComponent.RightW, ShuffleComponent.RightX);
|
||||
var r3z_r0z_r3w_r0w = shuffle(c2, c3, ShuffleComponent.LeftW, ShuffleComponent.LeftX, ShuffleComponent.RightW, ShuffleComponent.RightX);
|
||||
|
||||
var r0_wzyx = shuffle(r0z_r1z_r0w_r1w, r0y_r1y_r0x_r1x, ShuffleComponent.LeftZ, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.RightZ);
|
||||
var r1_wzyx = shuffle(r0z_r1z_r0w_r1w, r0y_r1y_r0x_r1x, ShuffleComponent.LeftW, ShuffleComponent.LeftY, ShuffleComponent.RightY, ShuffleComponent.RightW);
|
||||
var r2_wzyx = shuffle(r2z_r3z_r2w_r3w, r2y_r3y_r2x_r3x, ShuffleComponent.LeftZ, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.RightZ);
|
||||
var r3_wzyx = shuffle(r2z_r3z_r2w_r3w, r2y_r3y_r2x_r3x, ShuffleComponent.LeftW, ShuffleComponent.LeftY, ShuffleComponent.RightY, ShuffleComponent.RightW);
|
||||
var r0_xyzw = shuffle(r0y_r1y_r0x_r1x, r0z_r1z_r0w_r1w, ShuffleComponent.LeftZ, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.RightZ);
|
||||
|
||||
// Calculate remaining inner term pairs. inner terms have zw=-xy, so we only have to calculate xy and can pack two pairs per vector.
|
||||
var inner12_23 = r1y_r2y_r1x_r2x * r2z_r3z_r2w_r3w - r1z_r2z_r1w_r2w * r2y_r3y_r2x_r3x;
|
||||
var inner02_13 = r0y_r1y_r0x_r1x * r2z_r3z_r2w_r3w - r0z_r1z_r0w_r1w * r2y_r3y_r2x_r3x;
|
||||
var inner30_01 = r3z_r0z_r3w_r0w * r0y_r1y_r0x_r1x - r3y_r0y_r3x_r0x * r0z_r1z_r0w_r1w;
|
||||
|
||||
// Expand inner terms back to 4 components. zw signs still need to be flipped
|
||||
var inner12 = shuffle(inner12_23, inner12_23, ShuffleComponent.LeftX, ShuffleComponent.LeftZ, ShuffleComponent.RightZ, ShuffleComponent.RightX);
|
||||
var inner23 = shuffle(inner12_23, inner12_23, ShuffleComponent.LeftY, ShuffleComponent.LeftW, ShuffleComponent.RightW, ShuffleComponent.RightY);
|
||||
|
||||
var inner02 = shuffle(inner02_13, inner02_13, ShuffleComponent.LeftX, ShuffleComponent.LeftZ, ShuffleComponent.RightZ, ShuffleComponent.RightX);
|
||||
var inner13 = shuffle(inner02_13, inner02_13, ShuffleComponent.LeftY, ShuffleComponent.LeftW, ShuffleComponent.RightW, ShuffleComponent.RightY);
|
||||
|
||||
// Calculate minors
|
||||
var minors0 = r3_wzyx * inner12 - r2_wzyx * inner13 + r1_wzyx * inner23;
|
||||
|
||||
var denom = r0_xyzw * minors0;
|
||||
|
||||
// Horizontal sum of denominator. Free sign flip of z and w compensates for missing flip in inner terms.
|
||||
denom = denom + shuffle(denom, denom, ShuffleComponent.LeftY, ShuffleComponent.LeftX, ShuffleComponent.RightW, ShuffleComponent.RightZ); // x+y x+y z+w z+w
|
||||
denom = denom - shuffle(denom, denom, ShuffleComponent.LeftZ, ShuffleComponent.LeftZ, ShuffleComponent.RightX, ShuffleComponent.RightX); // x+y-z-w x+y-z-w z+w-x-y z+w-x-y
|
||||
|
||||
var rcp_denom_ppnn = 1 / denom;
|
||||
{typeInfo.TypeFullName} res;
|
||||
res.{_matrixComponents[0]} = minors0 * rcp_denom_ppnn;
|
||||
|
||||
var inner30 = shuffle(inner30_01, inner30_01, ShuffleComponent.LeftX, ShuffleComponent.LeftZ, ShuffleComponent.RightZ, ShuffleComponent.RightX);
|
||||
var inner01 = shuffle(inner30_01, inner30_01, ShuffleComponent.LeftY, ShuffleComponent.LeftW, ShuffleComponent.RightW, ShuffleComponent.RightY);
|
||||
|
||||
var minors1 = r2_wzyx * inner30 - r0_wzyx * inner23 - r3_wzyx * inner02;
|
||||
res.{_matrixComponents[1]} = minors1 * rcp_denom_ppnn;
|
||||
|
||||
var minors2 = r0_wzyx * inner13 - r1_wzyx * inner30 - r3_wzyx * inner01;
|
||||
res.{_matrixComponents[2]} = minors2 * rcp_denom_ppnn;
|
||||
|
||||
var minors3 = r1_wzyx * inner02 - r0_wzyx * inner12 + r2_wzyx * inner01;
|
||||
res.{_matrixComponents[3]} = minors3 * rcp_denom_ppnn;
|
||||
return res;
|
||||
}}
|
||||
|
||||
public static {typeInfo.TypeFullName} fastinverse({typeInfo.TypeFullName} m)
|
||||
{{
|
||||
var c0 = m.c0;
|
||||
var c1 = m.c1;
|
||||
var c2 = m.c2;
|
||||
var pos = m.c3;
|
||||
|
||||
var zero = default({typeInfo.ComponentTypeFullName});
|
||||
|
||||
// unpacklo
|
||||
var t0 = shuffle(c0, c2, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.LeftY, ShuffleComponent.RightY);
|
||||
var t1 = shuffle(c1, zero, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.LeftY, ShuffleComponent.RightY);
|
||||
// unpackhi
|
||||
var t2 = shuffle(c0, c2, ShuffleComponent.LeftZ, ShuffleComponent.RightZ, ShuffleComponent.LeftW, ShuffleComponent.RightW);
|
||||
var t3 = shuffle(c1, zero, ShuffleComponent.LeftZ, ShuffleComponent.RightZ, ShuffleComponent.LeftW, ShuffleComponent.RightW);
|
||||
|
||||
var r0 = shuffle(t0, t1, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.LeftY, ShuffleComponent.RightY);
|
||||
var r1 = shuffle(t0, t1, ShuffleComponent.LeftZ, ShuffleComponent.RightZ, ShuffleComponent.LeftW, ShuffleComponent.RightW);
|
||||
var r2 = shuffle(t2, t3, ShuffleComponent.LeftX, ShuffleComponent.RightX, ShuffleComponent.LeftY, ShuffleComponent.RightY);
|
||||
|
||||
pos = -(r0 * pos.x + r1 * pos.y + r2 * pos.z);
|
||||
pos.w = 1.0f;
|
||||
|
||||
return new(r0, r1, r2, pos);
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateDeterminantMethod()
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeInfo.ElementTypeFullName} determinant({typeInfo.TypeFullName} value)
|
||||
{{");
|
||||
for (var i = 0; i < typeInfo.Column; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
var {_matrixComponents[i]} = value.{_matrixComponents[i]};");
|
||||
}
|
||||
|
||||
sourceBuilder.AppendLine();
|
||||
|
||||
string Elem(int r, int c) => $"{_matrixComponents[c]}.{_vectorComponents[r]}";
|
||||
|
||||
// recursive function that returns a string for determinant of submatrix defined by rowIndices and colIndices
|
||||
string DetExpr(List<int> rows, List<int> cols)
|
||||
{
|
||||
var m = rows.Count;
|
||||
if (m == 1)
|
||||
{
|
||||
return Elem(rows[0], cols[0]);
|
||||
}
|
||||
if (m == 2)
|
||||
{
|
||||
// a b
|
||||
// c d -> a*d - b*c
|
||||
var a = Elem(rows[0], cols[0]);
|
||||
var b = Elem(rows[0], cols[1]);
|
||||
var c = Elem(rows[1], cols[0]);
|
||||
var d = Elem(rows[1], cols[1]);
|
||||
return $"({a} * {d} - {b} * {c})";
|
||||
}
|
||||
|
||||
// expand along the first row (rows[0])
|
||||
var sb = new StringBuilder();
|
||||
for (var j = 0; j < m; ++j)
|
||||
{
|
||||
var col = cols[j];
|
||||
var aij = Elem(rows[0], col);
|
||||
|
||||
// build minor indices
|
||||
var subRows = new List<int>(rows.Skip(1));
|
||||
var subCols = new List<int>(cols.Where((_, idx) => idx != j));
|
||||
|
||||
var subDet = DetExpr(subRows, subCols);
|
||||
var sign = ((0 + j) % 2 == 0) ? 1 : -1;
|
||||
if (sign == 1)
|
||||
sb.Append($"{aij} * {subDet}");
|
||||
else
|
||||
sb.Append($"-({aij} * {subDet})");
|
||||
|
||||
if (j != m - 1)
|
||||
sb.Append(" + ");
|
||||
}
|
||||
return $"({sb})";
|
||||
}
|
||||
|
||||
var rowsList = Enumerable.Range(0, typeInfo.Row).ToList();
|
||||
var colsList = Enumerable.Range(0, typeInfo.Row).ToList();
|
||||
var expr = DetExpr(rowsList, colsList);
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
return ({typeInfo.ElementTypeFullName}){expr};
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateMulMethod()
|
||||
{
|
||||
var lhsType = typeInfo.TypeFullName;
|
||||
var lhsRows = typeInfo.Row;
|
||||
var lhsCols = typeInfo.Column;
|
||||
var typePrefix = typeInfo.TypePrefix;
|
||||
|
||||
// Matrix-Vector Multiplication: RxC * C-element vector = R-element vector
|
||||
var rhsVectorType = $"{typePrefix}{lhsCols}";
|
||||
var resultVectorType = $"{typePrefix}{lhsRows}";
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {resultVectorType} mul({lhsType} m, {rhsVectorType} v)
|
||||
{{
|
||||
return {string.Join(" + ", Enumerable.Range(0, lhsCols).Select(c => $"m.{_matrixComponents[c]} * v.{_vectorComponents[c]}"))};
|
||||
}}");
|
||||
|
||||
// Vector-Matrix Multiplication: R-element vector * RxC = C-element vector
|
||||
var lhsVectorType = $"{typePrefix}{lhsRows}";
|
||||
var resultVectorTypeT = $"{typePrefix}{lhsCols}";
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {resultVectorTypeT} mul({lhsVectorType} v, {lhsType} m)
|
||||
{{
|
||||
return new {resultVectorTypeT}({string.Join(", ", Enumerable.Range(0, lhsCols).Select(c => $"dot(v, m.{_matrixComponents[c]})"))});
|
||||
}}");
|
||||
|
||||
// Matrix-Matrix Multiplication
|
||||
for (var rhsRows = 2; rhsRows <= 4; rhsRows++)
|
||||
{
|
||||
if (lhsCols != rhsRows)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var rhsCols = 2; rhsCols <= 4; rhsCols++)
|
||||
{
|
||||
var rhsType = $"{typePrefix}{rhsRows}x{rhsCols}";
|
||||
var resultType = $"{typePrefix}{lhsRows}x{rhsCols}";
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {resultType} mul({lhsType} lhs, {rhsType} rhs)
|
||||
{{
|
||||
return new {resultType}({string.Join(", ", Enumerable.Range(0, rhsCols).Select(c => $"mul(lhs, rhs.{_matrixComponents[c]})"))});
|
||||
}}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
||||
{
|
||||
internal class VectorGenerator : GeneratorBase
|
||||
{
|
||||
private readonly string[] _vectorComponents = new[] { "x", "y", "z", "w" };
|
||||
private int _vectorBitsSize;
|
||||
private int _missingComponents;
|
||||
|
||||
private readonly List<(string signature, string assignment)> _constructorSignatures = new();
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
var componentSize = typeInfo.ComponentSize;
|
||||
var typeSize = componentSize * typeInfo.Row * typeInfo.Column;
|
||||
var vectorBytesSize = typeSize switch
|
||||
{
|
||||
<= 16 => 16,
|
||||
<= 32 => 32,
|
||||
_ => 64,
|
||||
};
|
||||
|
||||
_vectorBitsSize = vectorBytesSize * 8;
|
||||
_missingComponents = (vectorBytesSize - typeSize) / componentSize;
|
||||
}
|
||||
|
||||
protected override void GenerateBody()
|
||||
{
|
||||
GenerateField();
|
||||
if (typeInfo.Arithmetic)
|
||||
{
|
||||
GenerateUnitVector();
|
||||
}
|
||||
GenerateConstructors();
|
||||
GenerateUnsafeMethod();
|
||||
GenerateOverrideMethod();
|
||||
if (typeInfo.Arithmetic)
|
||||
{
|
||||
GenerateArithmeticOperators();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(typeInfo.TypePrefix))
|
||||
{
|
||||
GenerateSwizzleProperties();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void GenerateTypeEnd()
|
||||
{
|
||||
base.GenerateTypeEnd();
|
||||
|
||||
if (typeInfo.Arithmetic)
|
||||
{
|
||||
sourceBuilder.AppendLine();
|
||||
GenerateVectorExtension();
|
||||
GenerateMathMethod();
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateField()
|
||||
{
|
||||
for (var i = 0; i < typeInfo.Row; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
public {typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {_vectorComponents[i]};");
|
||||
}
|
||||
|
||||
sourceBuilder.AppendLine();
|
||||
sourceBuilder.AppendLine($@"
|
||||
public unsafe ref {typeInfo.ComponentTypeFullName} this[int index]
|
||||
{{
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
get => ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
||||
}}");
|
||||
}
|
||||
|
||||
private static List<List<int>> GetPartitions(int target)
|
||||
{
|
||||
var result = new List<List<int>>();
|
||||
void Recurse(List<int> current, int sum)
|
||||
{
|
||||
if (sum == target)
|
||||
{
|
||||
result.Add(new List<int>(current));
|
||||
return;
|
||||
}
|
||||
for (var i = 1; i <= 3; i++)
|
||||
{
|
||||
if (sum + i <= target)
|
||||
{
|
||||
current.Add(i);
|
||||
Recurse(current, sum + i);
|
||||
current.RemoveAt(current.Count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Recurse(new(), 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<List<int>> GetPermutations(List<int> list)
|
||||
{
|
||||
if (list.Count == 1)
|
||||
yield return new List<int>(list);
|
||||
else
|
||||
{
|
||||
var seen = new HashSet<string>();
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
var head = list[i];
|
||||
var tail = new List<int>(list);
|
||||
tail.RemoveAt(i);
|
||||
foreach (var perm in GetPermutations(tail))
|
||||
{
|
||||
perm.Insert(0, head);
|
||||
var key = string.Join(",", perm);
|
||||
if (seen.Add(key))
|
||||
yield return perm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateUnitVector()
|
||||
{
|
||||
var typeFullName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeFullName} one => new {typeFullName}({string.Join(", ", Enumerable.Repeat("1", typeInfo.Row))});");
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeFullName} zero => default;");
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeFullName} unitX => new {typeFullName}({string.Join(", ", Enumerable.Repeat("0", typeInfo.Row - 1).Prepend("1"))});");
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeFullName} unitY => new {typeFullName}({string.Join(", ", Enumerable.Repeat("0", typeInfo.Row - 2).Prepend("0, 1"))});");
|
||||
|
||||
if (typeInfo.Row > 2)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeFullName} unitZ => new {typeFullName}({string.Join(", ", Enumerable.Repeat("0", typeInfo.Row - 3).Prepend("0, 0, 1"))});");
|
||||
}
|
||||
|
||||
if (typeInfo.Row > 3)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
public static {typeFullName} unitW => new {typeFullName}({string.Join(", ", Enumerable.Repeat("0", typeInfo.Row - 4).Prepend("0, 0, 0, 1"))});");
|
||||
}
|
||||
|
||||
sourceBuilder.AppendLine();
|
||||
}
|
||||
|
||||
private void GenerateConstructors()
|
||||
{
|
||||
var typeName = typeInfo.TypeName;
|
||||
var componentType = typeInfo.ComponentTypeFullName;
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
public unsafe {typeName}(global::System.ReadOnlySpan<{componentType}> values)
|
||||
{{
|
||||
if (values.Length < {typeInfo.Row})
|
||||
{{
|
||||
throw new global::System.ArgumentException($""Expected at least {typeInfo.Row} values, but got {{values.Length}}"", nameof(values));
|
||||
}}
|
||||
|
||||
fixed ({typeName}* pThis = &this)
|
||||
fixed ({componentType}* pValues = values)
|
||||
{{
|
||||
*pThis = *({typeName}*)pValues;
|
||||
}}
|
||||
}}");
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
public {typeName}({componentType} value)
|
||||
{{
|
||||
this = Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row).Select(_ => "value"))});
|
||||
}}");
|
||||
|
||||
if (string.IsNullOrEmpty(typeInfo.TypePrefix))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var partitions = GetPartitions(typeInfo.Row);
|
||||
var seenSignatures = new HashSet<string>();
|
||||
|
||||
foreach (var partition in partitions)
|
||||
{
|
||||
foreach (var perm in GetPermutations(partition))
|
||||
{
|
||||
var paramNames = new List<string>();
|
||||
var paramList = new List<string>();
|
||||
var assignments = new List<string>();
|
||||
var fieldOffset = 0;
|
||||
for (var i = 0; i < perm.Count; i++)
|
||||
{
|
||||
var size = perm[i];
|
||||
var type = size == 1 ? componentType : $"{typeInfo.TypePrefix}{size}";
|
||||
var name = string.Empty;
|
||||
for (var j = 0; j < size; j++)
|
||||
{
|
||||
name += $"{_vectorComponents[fieldOffset + j]}";
|
||||
}
|
||||
paramNames.Add(name);
|
||||
paramList.Add($"{type} {name}");
|
||||
for (var j = 0; j < size; j++)
|
||||
{
|
||||
var source = size == 1 ? name : $"{name}.{_vectorComponents[j]}";
|
||||
assignments.Add(source);
|
||||
}
|
||||
fieldOffset += size;
|
||||
}
|
||||
|
||||
var signature = string.Join(", ", paramList);
|
||||
if (!seenSignatures.Add(signature))
|
||||
continue;
|
||||
|
||||
var assignment = string.Join(", ", assignments);
|
||||
_constructorSignatures.Add((signature, assignment));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (signature, assignment) in _constructorSignatures)
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
public {typeName}({signature})
|
||||
{{
|
||||
this = Create({assignment});
|
||||
}}");
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row).Select((_, i) => $"{typeInfo.ComponentTypeFullName} {_vectorComponents[i]}"))})
|
||||
{{");
|
||||
|
||||
if (typeInfo.VectorType != null)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
global::System.Span<{typeInfo.ComponentTypeFullName}> span = [{string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"{_vectorComponents[i]}" : "default"))}];
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create(global::System.Runtime.CompilerServices.Unsafe.As<global::System.Span<{typeInfo.ComponentTypeFullName}>, global::System.ReadOnlySpan<{typeInfo.VectorTypeFullName}>>(ref span));");
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"{_vectorComponents[i]}" : "default"))});");
|
||||
}
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
ref var address = ref global::System.Runtime.CompilerServices.Unsafe.As<global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{typeInfo.VectorTypeFullName}>, byte>(ref vector);
|
||||
return global::System.Runtime.CompilerServices.Unsafe.ReadUnaligned<{typeInfo.TypeFullName}>(ref address);
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateUnsafeMethod()
|
||||
{
|
||||
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public unsafe {componentType}* AsPointer()
|
||||
{{
|
||||
return ({componentType}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public unsafe global::System.Span<{componentType}> AsSpan()
|
||||
{{
|
||||
return new global::System.Span<{componentType}>(AsPointer(), {typeInfo.Row});
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateOverrideMethod()
|
||||
{
|
||||
var typeName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var components = _vectorComponents.Take(typeInfo.Row).ToArray();
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public override readonly string ToString()
|
||||
{{
|
||||
return $""({string.Join(", ", components.Select(c => $"{c}: {{this.{c}}}"))})"";
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public override readonly int GetHashCode()
|
||||
{{
|
||||
return global::System.HashCode.Combine({string.Join(", ", components.Select(c => $"this.{c}"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public override readonly bool Equals(object? obj)
|
||||
{{
|
||||
return obj is {typeName} value && Equals(value);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public readonly bool Equals({typeName} other)
|
||||
{{
|
||||
return {string.Join(" && ", components.Select(c => $"this.{c}.Equals(other.{c})"))};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row} operator ==({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", components.Select(c => $"lhs.{c} == rhs.{c}"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row} operator !=({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new({string.Join(", ", components.Select(c => $"lhs.{c} != rhs.{c}"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static implicit operator {typeName}(global::System.ReadOnlySpan<{componentType}> value)
|
||||
{{
|
||||
return new {typeName}(value);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static implicit operator {typeName}({componentType} value)
|
||||
{{
|
||||
return new(value);
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateArithmeticOperators()
|
||||
{
|
||||
var typeName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var typeSimpleName = typeInfo.TypeSymbol.Name;
|
||||
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var asResult = $"As{typeSimpleName}()";
|
||||
|
||||
// Add
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator +({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = lhs.AsVector{_vectorBitsSize}() + rhs.AsVector{_vectorBitsSize}();
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator +({typeName} lhs, {componentType} rhs)
|
||||
{{
|
||||
return lhs + new {typeName}(rhs);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator +({componentType} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new {typeName}(lhs) + rhs;
|
||||
}}");
|
||||
|
||||
// Subtract
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator -({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = lhs.AsVector{_vectorBitsSize}() - rhs.AsVector{_vectorBitsSize}();
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator -({typeName} lhs, {componentType} rhs)
|
||||
{{
|
||||
return lhs - new {typeName}(rhs);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator -({componentType} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new {typeName}(lhs) - rhs;
|
||||
}}");
|
||||
|
||||
// Multiply
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator *({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = lhs.AsVector{_vectorBitsSize}() * rhs.AsVector{_vectorBitsSize}();
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator *({typeName} lhs, {componentType} rhs)
|
||||
{{
|
||||
var vector = lhs.AsVector{_vectorBitsSize}() * rhs;
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator *({componentType} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new {typeName}(lhs) * rhs;
|
||||
}}");
|
||||
|
||||
// Divide
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator /({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = lhs.AsVector{_vectorBitsSize}() / rhs.AsVector{_vectorBitsSize}();
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator /({typeName} lhs, {componentType} rhs)
|
||||
{{
|
||||
var vector = lhs.AsVector{_vectorBitsSize}() / rhs;
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator /({componentType} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new {typeName}(lhs) / rhs;
|
||||
}}");
|
||||
|
||||
// Modulus
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator %({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new {typeName}({string.Join(", ", _vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} % rhs.{c}"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator %({typeName} lhs, {componentType} rhs)
|
||||
{{
|
||||
return lhs % new {typeName}(rhs);
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator %({componentType} lhs, {typeName} rhs)
|
||||
{{
|
||||
return new {typeName}(lhs) % rhs;
|
||||
}}");
|
||||
|
||||
// Unary operators
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator +({typeName} value)
|
||||
{{
|
||||
return value;
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator -({typeName} value)
|
||||
{{
|
||||
var vector = -value.AsVector{_vectorBitsSize}();
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator ++({typeName} value)
|
||||
{{
|
||||
var vector = value.AsVector{_vectorBitsSize}() + global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create<{componentType}>(1);
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator --({typeName} value)
|
||||
{{
|
||||
var vector = value.AsVector{_vectorBitsSize}() - global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create<{componentType}>(1);
|
||||
return vector.{asResult};
|
||||
}}");
|
||||
|
||||
// Comparison operators
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static bool{typeInfo.Row} operator <({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.LessThan(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return new({string.Join(", ", _vectorComponents.Take(typeInfo.Row).Select((_, i) => $"vector[{i}] != 0"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static bool{typeInfo.Row} operator <=({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.LessThanOrEqual(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return new({string.Join(", ", _vectorComponents.Take(typeInfo.Row).Select((_, i) => $"vector[{i}] != 0"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static bool{typeInfo.Row} operator >({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.GreaterThan(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return new({string.Join(", ", _vectorComponents.Take(typeInfo.Row).Select((_, i) => $"vector[{i}] != 0"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static bool{typeInfo.Row} operator >=({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.GreaterThanOrEqual(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return new({string.Join(", ", _vectorComponents.Take(typeInfo.Row).Select((_, i) => $"vector[{i}] != 0"))});
|
||||
}}");
|
||||
|
||||
// Bitwise operators
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator <<({typeName} x, int n)
|
||||
{{
|
||||
var vector = x.AsVector{_vectorBitsSize}() << n;
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator >>({typeName} x, int n)
|
||||
{{
|
||||
var vector = x.AsVector{_vectorBitsSize}() >> n;
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator &({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.BitwiseAnd(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator |({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.BitwiseOr(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator ^({typeName} lhs, {typeName} rhs)
|
||||
{{
|
||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Xor(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}());
|
||||
return vector.{asResult};
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} operator ~({typeName} value)
|
||||
{{
|
||||
unchecked
|
||||
{{
|
||||
return value ^ new {typeName}(({componentType})-1);
|
||||
}}
|
||||
}}");
|
||||
}
|
||||
|
||||
private IEnumerable<string> GenerateSwizzles(IEnumerable<string> pool, int maxLen)
|
||||
{
|
||||
IEnumerable<string> Recurse(string prefix, int depth)
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
yield return prefix;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var c in pool)
|
||||
{
|
||||
foreach (var s in Recurse(prefix + c, depth - 1))
|
||||
{
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Enumerable.Range(2, maxLen - 1).SelectMany(len => Recurse(string.Empty, len));
|
||||
}
|
||||
|
||||
private void GenerateSwizzleProperties()
|
||||
{
|
||||
var validComponents = _vectorComponents.Take(typeInfo.Row).ToArray();
|
||||
var swizzles = GenerateSwizzles(validComponents, _vectorComponents.Length);
|
||||
foreach (var swizzle in swizzles)
|
||||
{
|
||||
var targetDim = swizzle.Length;
|
||||
var targetStruct = $"{typeInfo.TypePrefix}{targetDim}";
|
||||
sourceBuilder.AppendLine($@"
|
||||
public readonly {targetStruct} {swizzle}
|
||||
{{
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
get => new({string.Join(", ", swizzle.Select(c => $"this.{c}"))});
|
||||
}}");
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateVectorExtension()
|
||||
{
|
||||
var typeName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var typeSimpleName = typeInfo.TypeSymbol.Name;
|
||||
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public static partial class VectorInterop
|
||||
{{
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}> AsVector{_vectorBitsSize}(this {typeName} value)
|
||||
{{");
|
||||
var fullTypeName = $"{typeInfo.TypePrefix}{typeInfo.Row + _missingComponents}";
|
||||
sourceBuilder.Append($@"
|
||||
return global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"value.{_vectorComponents[i]}" : "1"))});
|
||||
}}
|
||||
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeName} As{typeSimpleName}(this global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}> value)
|
||||
{{");
|
||||
sourceBuilder.AppendLine($@"
|
||||
ref var address = ref global::System.Runtime.CompilerServices.Unsafe.As<global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}>, byte>(ref value);
|
||||
return global::System.Runtime.CompilerServices.Unsafe.ReadUnaligned<{typeName}>(ref address);
|
||||
}}
|
||||
}}");
|
||||
}
|
||||
|
||||
private void GenerateMathMethod()
|
||||
{
|
||||
var typeFullName = typeInfo.TypeFullName;
|
||||
var typePrefix = typeInfo.TypePrefix;
|
||||
var componentTypeFullName = typeInfo.ComponentTypeFullName;
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
public static partial class math
|
||||
{{");
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
public static {typeFullName} {typeInfo.TypeName}({componentTypeFullName} value)
|
||||
{{
|
||||
return {typeFullName}.Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row).Select(_ => "value"))});
|
||||
}}");
|
||||
|
||||
foreach (var (signature, assignment) in _constructorSignatures)
|
||||
{
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typeFullName} {typeInfo.TypeName}({signature})
|
||||
{{
|
||||
return {typeFullName}.Create({assignment});
|
||||
}}");
|
||||
}
|
||||
|
||||
sourceBuilder.AppendLine($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {componentTypeFullName} shuffle({typeFullName} left, {typeFullName} right, ShuffleComponent x)
|
||||
{{
|
||||
return select_shuffle_component(left, right, x);
|
||||
}}");
|
||||
|
||||
for (var i = 1; i < typeInfo.Row; i++)
|
||||
{
|
||||
var dimension = i + 1;
|
||||
sourceBuilder.Append($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
public static {typePrefix}{dimension} shuffle({typeFullName} left, {typeFullName} right, {string.Join(", ", Enumerable.Range(0, dimension).Select(x => $"ShuffleComponent {_vectorComponents[x]}"))})
|
||||
{{
|
||||
return new {typePrefix}{dimension}(");
|
||||
for (var j = 0; j < dimension; j++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
select_shuffle_component(left, right, {_vectorComponents[j]})");
|
||||
if (j < dimension - 1)
|
||||
{
|
||||
sourceBuilder.Append(",");
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceBuilder.Append(");");
|
||||
}
|
||||
}
|
||||
sourceBuilder.AppendLine($@"
|
||||
}}");
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
{INLINE_METHOD_ATTRIBUTE}
|
||||
internal static {componentTypeFullName} select_shuffle_component({typeFullName} a, {typeFullName} b, ShuffleComponent component)
|
||||
{{
|
||||
switch(component)
|
||||
{{");
|
||||
|
||||
for (var i = 0; i < typeInfo.Row; i++)
|
||||
{
|
||||
sourceBuilder.Append($@"
|
||||
case ShuffleComponent.Left{_vectorComponents[i].ToUpper()}:
|
||||
return a.{_vectorComponents[i]};
|
||||
case ShuffleComponent.Right{_vectorComponents[i].ToUpper()}:
|
||||
return b.{_vectorComponents[i]};");
|
||||
}
|
||||
|
||||
sourceBuilder.Append($@"
|
||||
default:
|
||||
throw new System.ArgumentException(""Invalid shuffle component: "" + component);
|
||||
}}
|
||||
}}
|
||||
}}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user