Refactor GPU-compatible Mul64 handling

This commit is contained in:
Marek Lemańczyk committed 2025-09-29 22:35:46 +02:00
1 parent b677e6cdec
commit f63254f0f0
4 files changed
+191 -12

No files matched your search

+12 -4
View File
@@ -241,7 +241,9 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
}
GpuUInt128 k = kStart + (GpuUInt128)idx;
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
GpuUInt128 q = twoP;
q.Mul64(k);
q.Add(GpuUInt128.One);
// Small-cycles in-kernel early rejection from device table
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
@@ -395,7 +397,9 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
}
GpuUInt128 k = kStart + (GpuUInt128)idx;
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
GpuUInt128 q = twoP;
q.Mul64(k);
q.Add(GpuUInt128.One);
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
{
ulong cycle = smallCycles[(int)q.Low];
@@ -539,7 +543,9 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
}
GpuUInt128 k = kStart + (GpuUInt128)idx;
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
GpuUInt128 q = twoP;
q.Mul64(k);
q.Add(GpuUInt128.One);
// Small-cycles in-kernel early rejection from device table
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
@@ -621,7 +627,9 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
}
GpuUInt128 k = kStart + (GpuUInt128)idx;
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
GpuUInt128 q = twoP;
q.Mul64(k);
q.Add(GpuUInt128.One);
// Small-cycles in-kernel early rejection from device table
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
{
+12 -6
View File
@@ -19,6 +19,13 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
Low = low;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public GpuUInt128(ulong low)
{
High = 0UL;
Low = low;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public GpuUInt128(UInt128 value)
{
@@ -36,7 +43,7 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
public static implicit operator GpuUInt128(UInt128 value) => new(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator GpuUInt128(ulong value) => new(0UL, value);
public static implicit operator GpuUInt128(ulong value) => new(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator UInt128(GpuUInt128 value) =>
@@ -395,13 +402,12 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly GpuUInt128 Mul64(GpuUInt128 other)
public void Mul64(GpuUInt128 other)
{
// Multiply this.Low (assumed 64-bit value) by full 128-bit other
ulong a = Low;
ulong low = a * other.Low;
ulong high = a * other.High + MulHigh(a, other.Low);
return new(high, low);
ulong operand = Low;
Low = operand * other.Low;
High = operand * other.High + MulHigh(operand, other.Low);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+10 -2
View File
@@ -155,8 +155,8 @@ public static class ULongExtensions
step3 = (step3 << 1) % 3UL;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt128 Mul64(this ulong a, ulong b) => ((UInt128)a.MulHigh(b) << 64) | (UInt128)(a * b);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt128 Mul64(this ulong a, ulong b) => ((UInt128)a.MulHigh(b) << 64) | (UInt128)(a * b);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong MulHigh(this ulong x, ulong y)
@@ -174,6 +174,14 @@ public static class ULongExtensions
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong MulHighGpuCompatible(this ulong x, ulong y)
{
GpuUInt128 product = new(x);
product.Mul64(new GpuUInt128(y));
return product.High;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong ModPow64(this ulong value, ulong exponent, ulong modulus)
{