From 93e46f0bb914df5a49fedb0855e0895bd9ae06d1 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sat, 4 Jan 2025 21:57:04 +0000 Subject: [PATCH 1/3] Use `Unsafe.BitCast` to avoid taking address --- .../System.Private.CoreLib/src/System/Array.cs | 16 ++++++++-------- .../src/System/SpanHelpers.T.cs | 17 ++++++++--------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs index d1806ea28a7ab1..6df854d28b5460 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs @@ -1513,7 +1513,7 @@ public static unsafe int IndexOf(T[] array, T value, int startIndex, int coun { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1521,7 +1521,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(ar { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1529,7 +1529,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(a { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1537,7 +1537,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(arr { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1758,7 +1758,7 @@ public static unsafe int LastIndexOf(T[] array, T value, int startIndex, int int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? endIndex : 0) + result; @@ -1768,7 +1768,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(ar int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? endIndex : 0) + result; @@ -1778,7 +1778,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(a int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? endIndex : 0) + result; @@ -1788,7 +1788,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(arr int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.As(ref value), + Unsafe.BitCast(value), count); return (result >= 0 ? endIndex : 0) + result; diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 0d61e3b662da7a..3893983d3cc0df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -29,34 +29,33 @@ public static unsafe void Fill(ref T refData, nuint numElements, T value) { // We have enough data for at least one vectorized write. - T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loops below. Vector vector; if (sizeof(T) == 1) { - vector = new Vector(Unsafe.As(ref tmp)); + vector = new Vector(Unsafe.BitCast(value)); } else if (sizeof(T) == 2) { - vector = (Vector)(new Vector(Unsafe.As(ref tmp))); + vector = (Vector)(new Vector(Unsafe.BitCast(value))); } else if (sizeof(T) == 4) { // special-case float since it's already passed in a SIMD reg vector = (typeof(T) == typeof(float)) - ? (Vector)(new Vector((float)(object)tmp!)) - : (Vector)(new Vector(Unsafe.As(ref tmp))); + ? (Vector)(new Vector(Unsafe.BitCast(value))) + : (Vector)(new Vector(Unsafe.BitCast(value))); } else if (sizeof(T) == 8) { // special-case double since it's already passed in a SIMD reg vector = (typeof(T) == typeof(double)) - ? (Vector)(new Vector((double)(object)tmp!)) - : (Vector)(new Vector(Unsafe.As(ref tmp))); + ? (Vector)(new Vector(Unsafe.BitCast(value))) + : (Vector)(new Vector(Unsafe.BitCast(value))); } else if (sizeof(T) == 16) { - Vector128 vec128 = Unsafe.As>(ref tmp); + Vector128 vec128 = Unsafe.BitCast>(value); if (Vector.Count == 16) { vector = vec128.AsVector(); @@ -75,7 +74,7 @@ public static unsafe void Fill(ref T refData, nuint numElements, T value) { if (Vector.Count == 32) { - vector = Unsafe.As>(ref tmp).AsVector(); + vector = Unsafe.BitCast>(value).AsVector(); } else { From 89f0c1fa8bee16f4398bb36ef8ceeea631feaa9c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 5 Jan 2025 19:55:37 +0000 Subject: [PATCH 2/3] Revert "Use `Unsafe.BitCast` to avoid taking address" This reverts commit 93e46f0bb914df5a49fedb0855e0895bd9ae06d1. --- .../System.Private.CoreLib/src/System/Array.cs | 16 ++++++++-------- .../src/System/SpanHelpers.T.cs | 17 +++++++++-------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs index 6df854d28b5460..d1806ea28a7ab1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs @@ -1513,7 +1513,7 @@ public static unsafe int IndexOf(T[] array, T value, int startIndex, int coun { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1521,7 +1521,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(ar { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1529,7 +1529,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(a { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1537,7 +1537,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(arr { int result = SpanHelpers.IndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), startIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? startIndex : 0) + result; } @@ -1758,7 +1758,7 @@ public static unsafe int LastIndexOf(T[] array, T value, int startIndex, int int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? endIndex : 0) + result; @@ -1768,7 +1768,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(ar int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? endIndex : 0) + result; @@ -1778,7 +1778,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(a int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? endIndex : 0) + result; @@ -1788,7 +1788,7 @@ ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(arr int endIndex = startIndex - count + 1; int result = SpanHelpers.LastIndexOfValueType( ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), endIndex), - Unsafe.BitCast(value), + Unsafe.As(ref value), count); return (result >= 0 ? endIndex : 0) + result; diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 3893983d3cc0df..0d61e3b662da7a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -29,33 +29,34 @@ public static unsafe void Fill(ref T refData, nuint numElements, T value) { // We have enough data for at least one vectorized write. + T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loops below. Vector vector; if (sizeof(T) == 1) { - vector = new Vector(Unsafe.BitCast(value)); + vector = new Vector(Unsafe.As(ref tmp)); } else if (sizeof(T) == 2) { - vector = (Vector)(new Vector(Unsafe.BitCast(value))); + vector = (Vector)(new Vector(Unsafe.As(ref tmp))); } else if (sizeof(T) == 4) { // special-case float since it's already passed in a SIMD reg vector = (typeof(T) == typeof(float)) - ? (Vector)(new Vector(Unsafe.BitCast(value))) - : (Vector)(new Vector(Unsafe.BitCast(value))); + ? (Vector)(new Vector((float)(object)tmp!)) + : (Vector)(new Vector(Unsafe.As(ref tmp))); } else if (sizeof(T) == 8) { // special-case double since it's already passed in a SIMD reg vector = (typeof(T) == typeof(double)) - ? (Vector)(new Vector(Unsafe.BitCast(value))) - : (Vector)(new Vector(Unsafe.BitCast(value))); + ? (Vector)(new Vector((double)(object)tmp!)) + : (Vector)(new Vector(Unsafe.As(ref tmp))); } else if (sizeof(T) == 16) { - Vector128 vec128 = Unsafe.BitCast>(value); + Vector128 vec128 = Unsafe.As>(ref tmp); if (Vector.Count == 16) { vector = vec128.AsVector(); @@ -74,7 +75,7 @@ public static unsafe void Fill(ref T refData, nuint numElements, T value) { if (Vector.Count == 32) { - vector = Unsafe.BitCast>(value).AsVector(); + vector = Unsafe.As>(ref tmp).AsVector(); } else { From 4973eed35ca4408a4fdb2a4e0422d8a26436d762 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 5 Jan 2025 20:49:56 +0000 Subject: [PATCH 3/3] fixes --- .../src/System/SpanHelpers.T.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 0d61e3b662da7a..5f8136a16cd89f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -34,29 +34,29 @@ public static unsafe void Fill(ref T refData, nuint numElements, T value) if (sizeof(T) == 1) { - vector = new Vector(Unsafe.As(ref tmp)); + vector = Vector.Create(Unsafe.As(ref tmp)); } else if (sizeof(T) == 2) { - vector = (Vector)(new Vector(Unsafe.As(ref tmp))); + vector = (Vector)Vector.Create(Unsafe.ReadUnaligned(ref Unsafe.As(ref tmp))); } else if (sizeof(T) == 4) { // special-case float since it's already passed in a SIMD reg vector = (typeof(T) == typeof(float)) - ? (Vector)(new Vector((float)(object)tmp!)) - : (Vector)(new Vector(Unsafe.As(ref tmp))); + ? (Vector)Vector.Create(Unsafe.BitCast(tmp)) + : (Vector)Vector.Create(Unsafe.ReadUnaligned(ref Unsafe.As(ref tmp))); } else if (sizeof(T) == 8) { // special-case double since it's already passed in a SIMD reg vector = (typeof(T) == typeof(double)) - ? (Vector)(new Vector((double)(object)tmp!)) - : (Vector)(new Vector(Unsafe.As(ref tmp))); + ? (Vector)Vector.Create(Unsafe.BitCast(tmp)) + : (Vector)Vector.Create(Unsafe.ReadUnaligned(ref Unsafe.As(ref tmp))); } else if (sizeof(T) == 16) { - Vector128 vec128 = Unsafe.As>(ref tmp); + Vector128 vec128 = Vector128.LoadUnsafe(ref Unsafe.As(ref tmp)); if (Vector.Count == 16) { vector = vec128.AsVector(); @@ -75,7 +75,7 @@ public static unsafe void Fill(ref T refData, nuint numElements, T value) { if (Vector.Count == 32) { - vector = Unsafe.As>(ref tmp).AsVector(); + vector = Vector256.LoadUnsafe(ref Unsafe.As(ref tmp)).AsVector(); } else {