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>(T[] array, T value, int startIndex, int coun
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.As<T, byte>(ref value),
+                        Unsafe.BitCast<T, byte>(value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1521,7 +1521,7 @@ ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(ar
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.As<T, short>(ref value),
+                        Unsafe.BitCast<T, short>(value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1529,7 +1529,7 @@ ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(a
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.As<T, int>(ref value),
+                        Unsafe.BitCast<T, int>(value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1537,7 +1537,7 @@ ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(arr
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, long>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.As<T, long>(ref value),
+                        Unsafe.BitCast<T, long>(value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1758,7 +1758,7 @@ public static unsafe int LastIndexOf<T>(T[] array, T value, int startIndex, int
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.As<T, byte>(ref value),
+                        Unsafe.BitCast<T, byte>(value),
                         count);
 
                     return (result >= 0 ? endIndex : 0) + result;
@@ -1768,7 +1768,7 @@ ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(ar
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.As<T, short>(ref value),
+                        Unsafe.BitCast<T, short>(value),
                         count);
 
                     return (result >= 0 ? endIndex : 0) + result;
@@ -1778,7 +1778,7 @@ ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(a
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.As<T, int>(ref value),
+                        Unsafe.BitCast<T, int>(value),
                         count);
 
                     return (result >= 0 ? endIndex : 0) + result;
@@ -1788,7 +1788,7 @@ ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(arr
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, long>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.As<T, long>(ref value),
+                        Unsafe.BitCast<T, long>(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<T>(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<byte> vector;
 
                 if (sizeof(T) == 1)
                 {
-                    vector = new Vector<byte>(Unsafe.As<T, byte>(ref tmp));
+                    vector = new Vector<byte>(Unsafe.BitCast<T, byte>(value));
                 }
                 else if (sizeof(T) == 2)
                 {
-                    vector = (Vector<byte>)(new Vector<ushort>(Unsafe.As<T, ushort>(ref tmp)));
+                    vector = (Vector<byte>)(new Vector<ushort>(Unsafe.BitCast<T, ushort>(value)));
                 }
                 else if (sizeof(T) == 4)
                 {
                     // special-case float since it's already passed in a SIMD reg
                     vector = (typeof(T) == typeof(float))
-                        ? (Vector<byte>)(new Vector<float>((float)(object)tmp!))
-                        : (Vector<byte>)(new Vector<uint>(Unsafe.As<T, uint>(ref tmp)));
+                        ? (Vector<byte>)(new Vector<float>(Unsafe.BitCast<T, float>(value)))
+                        : (Vector<byte>)(new Vector<uint>(Unsafe.BitCast<T, uint>(value)));
                 }
                 else if (sizeof(T) == 8)
                 {
                     // special-case double since it's already passed in a SIMD reg
                     vector = (typeof(T) == typeof(double))
-                        ? (Vector<byte>)(new Vector<double>((double)(object)tmp!))
-                        : (Vector<byte>)(new Vector<ulong>(Unsafe.As<T, ulong>(ref tmp)));
+                        ? (Vector<byte>)(new Vector<double>(Unsafe.BitCast<T, double>(value)))
+                        : (Vector<byte>)(new Vector<ulong>(Unsafe.BitCast<T, ulong>(value)));
                 }
                 else if (sizeof(T) == 16)
                 {
-                    Vector128<byte> vec128 = Unsafe.As<T, Vector128<byte>>(ref tmp);
+                    Vector128<byte> vec128 = Unsafe.BitCast<T, Vector128<byte>>(value);
                     if (Vector<byte>.Count == 16)
                     {
                         vector = vec128.AsVector();
@@ -75,7 +74,7 @@ public static unsafe void Fill<T>(ref T refData, nuint numElements, T value)
                 {
                     if (Vector<byte>.Count == 32)
                     {
-                        vector = Unsafe.As<T, Vector256<byte>>(ref tmp).AsVector();
+                        vector = Unsafe.BitCast<T, Vector256<byte>>(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>(T[] array, T value, int startIndex, int coun
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.BitCast<T, byte>(value),
+                        Unsafe.As<T, byte>(ref value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1521,7 +1521,7 @@ ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(ar
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.BitCast<T, short>(value),
+                        Unsafe.As<T, short>(ref value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1529,7 +1529,7 @@ ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(a
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.BitCast<T, int>(value),
+                        Unsafe.As<T, int>(ref value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1537,7 +1537,7 @@ ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(arr
                 {
                     int result = SpanHelpers.IndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, long>(ref MemoryMarshal.GetArrayDataReference(array)), startIndex),
-                        Unsafe.BitCast<T, long>(value),
+                        Unsafe.As<T, long>(ref value),
                         count);
                     return (result >= 0 ? startIndex : 0) + result;
                 }
@@ -1758,7 +1758,7 @@ public static unsafe int LastIndexOf<T>(T[] array, T value, int startIndex, int
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.BitCast<T, byte>(value),
+                        Unsafe.As<T, byte>(ref value),
                         count);
 
                     return (result >= 0 ? endIndex : 0) + result;
@@ -1768,7 +1768,7 @@ ref Unsafe.Add(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetArrayDataReference(ar
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.BitCast<T, short>(value),
+                        Unsafe.As<T, short>(ref value),
                         count);
 
                     return (result >= 0 ? endIndex : 0) + result;
@@ -1778,7 +1778,7 @@ ref Unsafe.Add(ref Unsafe.As<T, short>(ref MemoryMarshal.GetArrayDataReference(a
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.BitCast<T, int>(value),
+                        Unsafe.As<T, int>(ref value),
                         count);
 
                     return (result >= 0 ? endIndex : 0) + result;
@@ -1788,7 +1788,7 @@ ref Unsafe.Add(ref Unsafe.As<T, int>(ref MemoryMarshal.GetArrayDataReference(arr
                     int endIndex = startIndex - count + 1;
                     int result = SpanHelpers.LastIndexOfValueType(
                         ref Unsafe.Add(ref Unsafe.As<T, long>(ref MemoryMarshal.GetArrayDataReference(array)), endIndex),
-                        Unsafe.BitCast<T, long>(value),
+                        Unsafe.As<T, long>(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<T>(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<byte> vector;
 
                 if (sizeof(T) == 1)
                 {
-                    vector = new Vector<byte>(Unsafe.BitCast<T, byte>(value));
+                    vector = new Vector<byte>(Unsafe.As<T, byte>(ref tmp));
                 }
                 else if (sizeof(T) == 2)
                 {
-                    vector = (Vector<byte>)(new Vector<ushort>(Unsafe.BitCast<T, ushort>(value)));
+                    vector = (Vector<byte>)(new Vector<ushort>(Unsafe.As<T, ushort>(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<byte>)(new Vector<float>(Unsafe.BitCast<T, float>(value)))
-                        : (Vector<byte>)(new Vector<uint>(Unsafe.BitCast<T, uint>(value)));
+                        ? (Vector<byte>)(new Vector<float>((float)(object)tmp!))
+                        : (Vector<byte>)(new Vector<uint>(Unsafe.As<T, uint>(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<byte>)(new Vector<double>(Unsafe.BitCast<T, double>(value)))
-                        : (Vector<byte>)(new Vector<ulong>(Unsafe.BitCast<T, ulong>(value)));
+                        ? (Vector<byte>)(new Vector<double>((double)(object)tmp!))
+                        : (Vector<byte>)(new Vector<ulong>(Unsafe.As<T, ulong>(ref tmp)));
                 }
                 else if (sizeof(T) == 16)
                 {
-                    Vector128<byte> vec128 = Unsafe.BitCast<T, Vector128<byte>>(value);
+                    Vector128<byte> vec128 = Unsafe.As<T, Vector128<byte>>(ref tmp);
                     if (Vector<byte>.Count == 16)
                     {
                         vector = vec128.AsVector();
@@ -74,7 +75,7 @@ public static unsafe void Fill<T>(ref T refData, nuint numElements, T value)
                 {
                     if (Vector<byte>.Count == 32)
                     {
-                        vector = Unsafe.BitCast<T, Vector256<byte>>(value).AsVector();
+                        vector = Unsafe.As<T, Vector256<byte>>(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<T>(ref T refData, nuint numElements, T value)
 
                 if (sizeof(T) == 1)
                 {
-                    vector = new Vector<byte>(Unsafe.As<T, byte>(ref tmp));
+                    vector = Vector.Create(Unsafe.As<T, byte>(ref tmp));
                 }
                 else if (sizeof(T) == 2)
                 {
-                    vector = (Vector<byte>)(new Vector<ushort>(Unsafe.As<T, ushort>(ref tmp)));
+                    vector = (Vector<byte>)Vector.Create(Unsafe.ReadUnaligned<ushort>(ref Unsafe.As<T, byte>(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<byte>)(new Vector<float>((float)(object)tmp!))
-                        : (Vector<byte>)(new Vector<uint>(Unsafe.As<T, uint>(ref tmp)));
+                        ? (Vector<byte>)Vector.Create(Unsafe.BitCast<T, float>(tmp))
+                        : (Vector<byte>)Vector.Create(Unsafe.ReadUnaligned<uint>(ref Unsafe.As<T, byte>(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<byte>)(new Vector<double>((double)(object)tmp!))
-                        : (Vector<byte>)(new Vector<ulong>(Unsafe.As<T, ulong>(ref tmp)));
+                        ? (Vector<byte>)Vector.Create(Unsafe.BitCast<T, double>(tmp))
+                        : (Vector<byte>)Vector.Create(Unsafe.ReadUnaligned<ulong>(ref Unsafe.As<T, byte>(ref tmp)));
                 }
                 else if (sizeof(T) == 16)
                 {
-                    Vector128<byte> vec128 = Unsafe.As<T, Vector128<byte>>(ref tmp);
+                    Vector128<byte> vec128 = Vector128.LoadUnsafe(ref Unsafe.As<T, byte>(ref tmp));
                     if (Vector<byte>.Count == 16)
                     {
                         vector = vec128.AsVector();
@@ -75,7 +75,7 @@ public static unsafe void Fill<T>(ref T refData, nuint numElements, T value)
                 {
                     if (Vector<byte>.Count == 32)
                     {
-                        vector = Unsafe.As<T, Vector256<byte>>(ref tmp).AsVector();
+                        vector = Vector256.LoadUnsafe(ref Unsafe.As<T, byte>(ref tmp)).AsVector();
                     }
                     else
                     {