From 76b0d236276d66fc870b6dd3bd4fc97f5fd13a54 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 24 Apr 2026 14:01:42 +0200 Subject: [PATCH] Use safe Span.Slice loop pattern in NumericsHelpers.DangerousMakeOnesComplement Rewrites the V512/V256/V128 cascades in DangerousMakeOnesComplement to use the safe `while (data.Length >= Vector{N}.Count) { ...; data = data.Slice(Vector{N}.Count); }` pattern, replacing `Vector{N}.LoadUnsafe` / `StoreUnsafe` / `Unsafe.Add(ref, offset)` with `Vector{N}.Create(span)` and `vector.CopyTo(span)`. The new shape is recognized by the JIT loop optimization that elides bounds checks on this exact pattern, so the resulting codegen is equivalent (or better) to the previous unsafe form while removing the use of `Unsafe` / unmanaged-style ref arithmetic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/System/Numerics/NumericsHelpers.cs | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/NumericsHelpers.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/NumericsHelpers.cs index 0f8414d3d00a98..7547f50e35d91c 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/NumericsHelpers.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/NumericsHelpers.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Intrinsics; namespace System.Numerics @@ -143,33 +141,30 @@ public static void DangerousMakeOnesComplement(Span d) // AAAAAAAAAAA // where A = ~X - int offset = 0; - ref nuint start = ref MemoryMarshal.GetReference(d); - - while (Vector512.IsHardwareAccelerated && d.Length - offset >= Vector512.Count) + while (Vector512.IsHardwareAccelerated && d.Length >= Vector512.Count) { - Vector512 complement = ~Vector512.LoadUnsafe(ref start, (nuint)offset); - Vector512.StoreUnsafe(complement, ref start, (nuint)offset); - offset += Vector512.Count; + Vector512 complement = ~Vector512.Create(d); + complement.CopyTo(d); + d = d.Slice(Vector512.Count); } - while (Vector256.IsHardwareAccelerated && d.Length - offset >= Vector256.Count) + while (Vector256.IsHardwareAccelerated && d.Length >= Vector256.Count) { - Vector256 complement = ~Vector256.LoadUnsafe(ref start, (nuint)offset); - Vector256.StoreUnsafe(complement, ref start, (nuint)offset); - offset += Vector256.Count; + Vector256 complement = ~Vector256.Create(d); + complement.CopyTo(d); + d = d.Slice(Vector256.Count); } - while (Vector128.IsHardwareAccelerated && d.Length - offset >= Vector128.Count) + while (Vector128.IsHardwareAccelerated && d.Length >= Vector128.Count) { - Vector128 complement = ~Vector128.LoadUnsafe(ref start, (nuint)offset); - Vector128.StoreUnsafe(complement, ref start, (nuint)offset); - offset += Vector128.Count; + Vector128 complement = ~Vector128.Create(d); + complement.CopyTo(d); + d = d.Slice(Vector128.Count); } - for (; offset < d.Length; offset++) + for (int i = 0; i < d.Length; i++) { - d[offset] = ~d[offset]; + d[i] = ~d[i]; } }