Cosmos/source/Cosmos.Core.Plugs/MemoryOperations/MemoryOperationsImpl.cs
2017-05-04 18:50:52 +01:00

187 lines
6.4 KiB
C#

#define COSMOSDEBUG
using System;
using System.Runtime.CompilerServices;
using Cosmos.IL2CPU.Plugs;
namespace Cosmos.Core.Plugs.MemoryOperations
{
[Plug(Target = typeof(Cosmos.Core.MemoryOperations))]
public unsafe class MemoryOperationsImpl
{
unsafe public static void Fill(byte* dest, int value, int size)
{
//Console.WriteLine("Filling array of size " + size + " with value 0x" + value.ToString("X"));
//Global.mDebugger.SendInternal("Filling array of size " + size + " with value " + value);
/* For very little sizes (until 15 bytes) we hand unroll the loop */
switch (size)
{
case 0:
return;
case 1:
*dest = (byte)value;
return;
case 2:
*(short*)dest = (short)value;
return;
case 3:
*(short*)dest = (short)value;
*(dest + 2) = (byte)value;
return;
case 4:
*(int*)dest = value;
return;
case 5:
*(int*)dest = value;
*(dest + 4) = (byte)value;
return;
case 6:
*(int*)dest = value;
*(short*)(dest + 4) = (short)value;
return;
case 7:
*(int*)dest = value;
*(short*)(dest + 4) = (short)value;
*(dest + 6) = (byte)value;
return;
case 8:
*(int*)dest = value;
*(int*)(dest + 4) = value;
return;
case 9:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(dest + 8) = (byte)value;
return;
case 10:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(short*)(dest + 8) = (short)value;
return;
case 11:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(short*)(dest + 8) = (short)value;
*(dest + 10) = (byte)value;
return;
case 12:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(int*)(dest + 8) = value;
return;
case 13:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(int*)(dest + 8) = value;
*(dest + 12) = (byte)value;
return;
case 14:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(int*)(dest + 8) = value;
*(short*)(dest + 12) = (byte)value;
return;
case 15:
*(int*)dest = value;
*(int*)(dest + 4) = value;
*(int*)(dest + 8) = value;
*(short*)(dest + 12) = (short)value;
*(dest + 14) = (byte)value;
return;
}
/*
* OK size is >= 16 it does not make any sense to do it with primitive types as C#
* has not a Int128 type, the Int128 operations will be done in assembler but we can
* do yet in the Managed world the two things:
* 1. Check of how many blocks of 16 bytes size is composed
* 2. If there are reaming bytes (that is size is not a perfect multiple of size)
* we do the Fill() using a simple managed for() loop of bytes
*/
int xBlocksNum;
int xByteRemaining;
#if NETSTANDARD1_5
xBlocksNum = size / 16;
xByteRemaining = size % 16;
#else
xBlocksNum = Math.DivRem(size, 16, out xByteRemaining);
#endif
//Global.mDebugger.SendInternal("size " + size + " is composed of " + BlocksNum + " block of 16 bytes with " + ByteRemaining + " remainder");
for (int i = 0; i < xByteRemaining; i++)
{
*(dest + i) = (byte)value;
}
/* Let's call the assembler version now to do the 16 byte block copies */
Cosmos.Core.MemoryOperations.Fill16Blocks(dest + xByteRemaining, value, xBlocksNum);
/*
* If needed there is yet space of optimization here for example:
* - you can check if size is a multiple of 64 and if yes use an yet more faster Fill64Blocks
* - or if it is not so try to see if it is a multiple of 32
* at point probably it would be better to move a lot of the logic to assembler
*/
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe public static void Fill(int[] dest, int value)
{
fixed (int* destPtr = dest)
{
Fill((byte*)destPtr, value, dest.Length * 4);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe public static void Fill(ushort[] dest, ushort value)
{
fixed (ushort* destPtr = dest)
{
/* Broadcast 'value' fill all the integer register (0x42 --> 0x42424242) */
int valueFiller = value * 0x10001;
Fill((byte*)destPtr, valueFiller, dest.Length * 2);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe public static void Fill(short[] dest, short value)
{
fixed (short* destPtr = dest)
{
/* Broadcast 'value' fill all the integer register (0x42 --> 0x42424242) */
int valueFiller = (ushort)value * 0x10001;
Fill((byte*)destPtr, valueFiller, dest.Length * 2);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe public static void Fill(byte[] dest, byte value)
{
fixed (byte* destPtr = dest)
{
/* Broadcast 'value' fill all the integer register (0x42 --> 0x42424242) */
int valueFiller = value * 0x1010101;
Fill(destPtr, valueFiller, dest.Length);
}
}
}
}