Optimize Span.Fill (dotnet/coreclr#9441)
authorAhson Ahmed Khan <ahsonkhan@users.noreply.github.com>
Fri, 10 Feb 2017 00:34:27 +0000 (16:34 -0800)
committerJan Kotas <jkotas@microsoft.com>
Fri, 10 Feb 2017 00:34:27 +0000 (16:34 -0800)
Commit migrated from https://github.com/dotnet/coreclr/commit/1e76ef05c028be15bb79eb98f2a379b3746f3445

src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
src/coreclr/src/mscorlib/src/System/Span.cs
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/mscorlib.h

index b212f45..adfa015 100644 (file)
@@ -76,5 +76,18 @@ namespace System.Runtime.CompilerServices
             // See getILIntrinsicImplementationForUnsafe for how this happens.  
             throw new InvalidOperationException();
         }
+
+        /// <summary>
+        /// Initializes a block of memory at the given location with a given initial value 
+        /// without assuming architecture dependent alignment of the address.
+        /// </summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void InitBlockUnaligned(ref byte startAddress, byte value, uint byteCount)
+        {
+            // The body of this function will be replaced by the EE with unsafe code!!!
+            // See getILIntrinsicImplementationForUnsafe for how this happens.  
+            throw new InvalidOperationException();
+        }
     }
 }
index 16467c3..c77a199 100644 (file)
@@ -231,6 +231,7 @@ namespace System
         /// <summary>
         /// Clears the contents of this span.
         /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void Clear()
         {
             // TODO: Optimize - https://github.com/dotnet/coreclr/issues/9161
@@ -245,10 +246,48 @@ namespace System
         /// </summary>
         public void Fill(T value)
         {
-            // TODO: Optimize - https://github.com/dotnet/coreclr/issues/9161
-            for (int i = 0; i < _length; i++)
+            int length = _length;
+
+            if (length == 0)
+                return;
+
+            if (Unsafe.SizeOf<T>() == 1)
+            {
+                byte fill = Unsafe.As<T, byte>(ref value);
+                ref byte r = ref Unsafe.As<T, byte>(ref _pointer.Value);
+                Unsafe.InitBlockUnaligned(ref r, fill, (uint)length);
+            }
+            else
             {
-                this[i] = value;
+                ref T r = ref DangerousGetPinnableReference();
+
+                // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16
+
+                // Simple loop unrolling
+                int i = 0;
+                for (; i < (length & ~7); i += 8)
+                {
+                    Unsafe.Add<T>(ref r, i + 0) = value;
+                    Unsafe.Add<T>(ref r, i + 1) = value;
+                    Unsafe.Add<T>(ref r, i + 2) = value;
+                    Unsafe.Add<T>(ref r, i + 3) = value;
+                    Unsafe.Add<T>(ref r, i + 4) = value;
+                    Unsafe.Add<T>(ref r, i + 5) = value;
+                    Unsafe.Add<T>(ref r, i + 6) = value;
+                    Unsafe.Add<T>(ref r, i + 7) = value;
+                }
+                if (i < (length & ~3))
+                {
+                    Unsafe.Add<T>(ref r, i + 0) = value;
+                    Unsafe.Add<T>(ref r, i + 1) = value;
+                    Unsafe.Add<T>(ref r, i + 2) = value;
+                    Unsafe.Add<T>(ref r, i + 3) = value;
+                    i += 4;
+                }
+                for (; i < length; i++)
+                {
+                    Unsafe.Add<T>(ref r, i) = value;
+                }
             }
         }
 
index d80b60e..5afb89b 100644 (file)
@@ -7144,6 +7144,16 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
         methInfo->options = (CorInfoOptions)0;
         return true;
     }
+    else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
+    {
+        static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_LDARG_2, CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01, CEE_PREFIX1, (CEE_INITBLK & 0xFF), CEE_RET };
+        methInfo->ILCode = const_cast<BYTE*>(ilcode);
+        methInfo->ILCodeSize = sizeof(ilcode);
+        methInfo->maxStack = 3;
+        methInfo->EHcount = 0;
+        methInfo->options = (CorInfoOptions)0;
+        return true;
+    }
 
     return false;
 }
index ca6b5e3..78eab6c 100644 (file)
@@ -1205,6 +1205,7 @@ DEFINE_METHOD(UNSAFE,               SIZEOF,                 SizeOf, NoSig)
 DEFINE_METHOD(UNSAFE,               BYREF_AS,               As, NoSig)
 DEFINE_METHOD(UNSAFE,               BYREF_ADD,              Add, NoSig)
 DEFINE_METHOD(UNSAFE,               BYREF_ARE_SAME,         AreSame, NoSig)
+DEFINE_METHOD(UNSAFE,               BYREF_INIT_BLOCK_UNALIGNED, InitBlockUnaligned, NoSig)
 #endif
 
 DEFINE_CLASS(INTERLOCKED,           Threading,              Interlocked)