Skip to content

Commit 176336a

Browse files
committed
feat(int64): add UnmanagedSpan overloads and fix SimdMatMul
**SimdMatMul.cs** - Replaced slow scalar fallback for large arrays with UnmanagedSpan.Clear() - Before: for loop clearing one element at a time when outputSize > int.MaxValue - After: vectorized UnmanagedSpan.Clear() for all sizes **IArraySlice.cs** - Added: `void CopyTo<T>(UnmanagedSpan<T> destination) where T : unmanaged` **ArraySlice<T>.cs** - Added: constructor `ArraySlice(UnmanagedMemoryBlock<T>, UnmanagedSpan<T>)` - Added: `bool TryCopyTo(UnmanagedSpan<T> destination)` - Added: `void CopyTo(UnmanagedSpan<T> destination)` - Added: `void CopyTo(UnmanagedSpan<T> destination, long sourceOffset)` - Added: `void CopyTo(UnmanagedSpan<T> destination, long sourceOffset, long sourceLength)` - Added: explicit interface `IArraySlice.CopyTo<T1>(UnmanagedSpan<T1> destination)` All overloads support long indexing for arrays exceeding int.MaxValue elements.
1 parent 7b09239 commit 176336a

3 files changed

Lines changed: 97 additions & 10 deletions

File tree

src/NumSharp.Core/Backends/Kernels/SimdMatMul.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Runtime.InteropServices;
44
using System.Runtime.Intrinsics;
55
using System.Runtime.Intrinsics.X86;
6+
using NumSharp.Utilities;
67

78
namespace NumSharp.Backends.Kernels
89
{
@@ -42,16 +43,8 @@ public static class SimdMatMul
4243
public static unsafe void MatMulFloat(float* A, float* B, float* C, long M, long N, long K)
4344
{
4445

45-
// Zero output
46-
long outputSize = M * N;
47-
if (outputSize <= int.MaxValue)
48-
new Span<float>(C, (int)outputSize).Clear();
49-
else
50-
{
51-
// Clear in chunks for very large outputs
52-
for (long i = 0; i < outputSize; i++)
53-
C[i] = 0f;
54-
}
46+
// Zero output using UnmanagedSpan for long indexing support
47+
new UnmanagedSpan<float>(C, M * N).Clear();
5548

5649
// Small matrices: use simple IKJ loop (blocking overhead not worth it)
5750
if (M <= BLOCKING_THRESHOLD && N <= BLOCKING_THRESHOLD && K <= BLOCKING_THRESHOLD)

src/NumSharp.Core/Backends/Unmanaged/ArraySlice`1.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ public ArraySlice(UnmanagedMemoryBlock<T> memoryBlock, Span<T> slice)
6464
VoidAddress = Address = (T*)Unsafe.AsPointer(ref slice.GetPinnableReference());
6565
}
6666

67+
/// <summary>
68+
/// Creates a sliced <see cref="ArraySlice{T}"/> from an UnmanagedSpan.
69+
/// Supports long indexing for arrays &gt; 2B elements.
70+
/// </summary>
71+
public ArraySlice(UnmanagedMemoryBlock<T> memoryBlock, UnmanagedSpan<T> slice)
72+
{
73+
MemoryBlock = memoryBlock;
74+
IsSlice = true;
75+
Count = slice.Length;
76+
VoidAddress = Address = (T*)Unsafe.AsPointer(ref slice.GetPinnableReference());
77+
}
78+
6779
/// <summary>
6880
/// Creates a sliced <see cref="ArraySlice{T}"/>.
6981
/// </summary>
@@ -313,6 +325,69 @@ public void CopyTo(Span<T> destination, long sourceOffset, long sourceLength)
313325
CopyTo(destination, sourceOffset, sourceLength);
314326
}
315327

328+
/// <summary>
329+
/// Tries to copy this slice's contents to an UnmanagedSpan destination.
330+
/// Supports long indexing for arrays &gt; 2B elements.
331+
/// </summary>
332+
/// <param name="destination">The destination span.</param>
333+
/// <returns>True if the copy succeeded, false if destination is too short.</returns>
334+
public bool TryCopyTo(UnmanagedSpan<T> destination)
335+
{
336+
if ((ulong)Count > (ulong)destination.Length)
337+
return false;
338+
339+
Buffer.MemoryCopy(Unsafe.AsPointer(ref destination.GetPinnableReference()), Address, destination.Length * ItemLength, Count * ItemLength);
340+
return true;
341+
}
342+
343+
/// <summary>
344+
/// Copies this slice's contents to an UnmanagedSpan destination.
345+
/// Supports long indexing for arrays &gt; 2B elements.
346+
/// </summary>
347+
/// <param name="destination">The destination span.</param>
348+
[MethodImpl(OptimizeAndInline)]
349+
public void CopyTo(UnmanagedSpan<T> destination)
350+
{
351+
if ((ulong)Count <= (ulong)destination.Length)
352+
{
353+
Buffer.MemoryCopy(Unsafe.AsPointer(ref destination.GetPinnableReference()), Address, destination.Length * ItemLength, Count * ItemLength);
354+
}
355+
else
356+
{
357+
throw new ArgumentException("Destination was too short.");
358+
}
359+
}
360+
361+
/// <summary>
362+
/// Copies a portion of this slice to an UnmanagedSpan destination.
363+
/// Supports long indexing for arrays &gt; 2B elements.
364+
/// </summary>
365+
/// <param name="destination">The destination span.</param>
366+
/// <param name="sourceOffset">Offset in source (element count, not bytes).</param>
367+
[MethodImpl(OptimizeAndInline)]
368+
public void CopyTo(UnmanagedSpan<T> destination, long sourceOffset)
369+
{
370+
CopyTo(destination, sourceOffset, Count - sourceOffset);
371+
}
372+
373+
/// <summary>
374+
/// Copies a portion of this slice to an UnmanagedSpan destination.
375+
/// Supports long indexing for arrays &gt; 2B elements.
376+
/// </summary>
377+
/// <param name="destination">The destination span.</param>
378+
/// <param name="sourceOffset">Offset in source (element count, not bytes).</param>
379+
/// <param name="sourceLength">Number of elements to copy.</param>
380+
[MethodImpl(OptimizeAndInline)]
381+
public void CopyTo(UnmanagedSpan<T> destination, long sourceOffset, long sourceLength)
382+
{
383+
if ((ulong)sourceOffset > (ulong)Count || (ulong)sourceLength > (ulong)(Count - sourceOffset))
384+
throw new ArgumentOutOfRangeException();
385+
if ((ulong)sourceLength > (ulong)destination.Length)
386+
throw new ArgumentException("Destination was too short.");
387+
388+
Buffer.MemoryCopy(Unsafe.AsPointer(ref destination.GetPinnableReference()), Address + sourceOffset, destination.Length * ItemLength, sourceLength * ItemLength);
389+
}
390+
316391
[EditorBrowsable(EditorBrowsableState.Never)]
317392
[MethodImpl(Inline)]
318393
public ref T GetPinnableReference() => ref Unsafe.AsRef<T>(Address);
@@ -387,6 +462,18 @@ void IArraySlice.CopyTo<T1>(Span<T1> destination)
387462
this.CopyTo(Unsafe.AsPointer(ref destination.GetPinnableReference()));
388463
}
389464

465+
/// <summary>
466+
/// Copies this slice's contents to an UnmanagedSpan destination.
467+
/// Supports long indexing for arrays &gt; 2B elements.
468+
/// </summary>
469+
/// <param name="destination"></param>
470+
void IArraySlice.CopyTo<T1>(UnmanagedSpan<T1> destination)
471+
{
472+
if ((ulong)Count > (ulong)destination.Length)
473+
throw new ArgumentException("Destination was too short.");
474+
Buffer.MemoryCopy(Unsafe.AsPointer(ref destination.GetPinnableReference()), VoidAddress, destination.Length * InfoOf<T1>.Size, Count * ItemLength);
475+
}
476+
390477
/// <summary>
391478
/// Gets pinnable reference of the first item in the memory block storage.
392479
/// </summary>

src/NumSharp.Core/Backends/Unmanaged/Interfaces/IArraySlice.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ public interface IArraySlice : IMemoryBlock, ICloneable, IEnumerable
5252
/// <param name="destination"></param>
5353
void CopyTo<T>(Span<T> destination);
5454

55+
/// <summary>
56+
/// Copies this slice's contents to an UnmanagedSpan destination.
57+
/// Supports long indexing for arrays &gt; 2B elements.
58+
/// </summary>
59+
/// <param name="destination"></param>
60+
void CopyTo<T>(UnmanagedSpan<T> destination) where T : unmanaged;
61+
5562
/// <summary>
5663
/// Gets pinnable reference of the first item in the memory block storage.
5764
/// </summary>

0 commit comments

Comments
 (0)