BinaryGcd switched to the best performing variant according to benchmarks.
This commit is contained in:
1 parent
be435b7760
commit
42447c4e43
9 files changed
+112
-166
No files matched your search
@@ -2,7 +2,6 @@ using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
using PerfectNumbers.Core.Cpu;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu;
|
||||
|
||||
@@ -1207,23 +1206,6 @@ internal static partial class PrimeOrderGpuHeuristics
|
||||
remainders[index] = ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponent);
|
||||
}
|
||||
|
||||
private static Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> GetPow2ModWideKernel(Accelerator accelerator)
|
||||
{
|
||||
var pool = _pow2ModWideKernel ??= [];
|
||||
if (pool.TryGetValue(accelerator, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(Pow2ModKernelWide);
|
||||
|
||||
var kernel = KernelUtil.GetKernel(loaded);
|
||||
|
||||
cached = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>();
|
||||
pool[accelerator] = cached;
|
||||
return cached;
|
||||
}
|
||||
|
||||
/// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers.
|
||||
internal static void Pow2ModKernelWide(Index1D index, ArrayView1D<GpuUInt128, Stride1D.Dense> exponents, GpuUInt128 modulus, ArrayView1D<GpuUInt128, Stride1D.Dense> remainders)
|
||||
{
|
||||
|
||||
@@ -121,35 +121,37 @@ internal static class PrimeTesterKernels
|
||||
|
||||
private static ulong BinaryGcdGpu(ulong u, ulong v)
|
||||
{
|
||||
// TODO: Replace this inline GPU binary GCD with the kernel extracted from
|
||||
// GpuUInt128BinaryGcdBenchmarks via GpuKernelPool so device callers reuse the
|
||||
// fully unrolled ladder instead of this branchy fallback.
|
||||
bool uIsZero = u == 0UL;
|
||||
bool vIsZero = v == 0UL;
|
||||
bool eitherZero = uIsZero | vIsZero;
|
||||
ulong zeroResult = uIsZero ? v : u;
|
||||
|
||||
ulong combined = u | v | 1UL;
|
||||
ulong combined = (u | v) | 1UL;
|
||||
int shift = XMath.TrailingZeroCount(combined);
|
||||
ulong currentU = u >> XMath.TrailingZeroCount(u | 1UL);
|
||||
ulong currentV = v >> XMath.TrailingZeroCount(v | 1UL);
|
||||
|
||||
ulong normalizedU = u >> XMath.TrailingZeroCount(u | 1UL);
|
||||
ulong normalizedV = v >> XMath.TrailingZeroCount(v | 1UL);
|
||||
|
||||
ulong currentU = normalizedU;
|
||||
ulong currentV = normalizedV;
|
||||
bool loopCondition = currentV != 0UL;
|
||||
|
||||
while (loopCondition)
|
||||
while (true)
|
||||
{
|
||||
currentV >>= XMath.TrailingZeroCount(currentV);
|
||||
ulong minValue = XMath.Min(currentU, currentV);
|
||||
ulong maxValue = XMath.Max(currentU, currentV);
|
||||
currentU = minValue;
|
||||
bool swap = currentU > currentV;
|
||||
ulong minValue = ConditionalSelect(currentU, currentV, swap);
|
||||
ulong maxValue = ConditionalSelect(currentV, currentU, swap);
|
||||
currentV = maxValue - minValue;
|
||||
loopCondition = currentV != 0UL;
|
||||
currentU = minValue;
|
||||
if (currentV == 0UL)
|
||||
{
|
||||
ulong gcd = currentU << shift;
|
||||
return eitherZero ? zeroResult : gcd;
|
||||
}
|
||||
}
|
||||
|
||||
ulong gcd = currentU << shift;
|
||||
return eitherZero ? zeroResult : gcd;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ConditionalSelect(ulong left, ulong right, bool useRight)
|
||||
{
|
||||
ulong mask = useRight ? ulong.MaxValue : 0UL;
|
||||
return left ^ ((left ^ right) & mask);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user