Esempio n. 1
0
 static bool IBinaryNumber <int> .IsPow2(int value)
 => BitOperations.IsPow2(value);
Esempio n. 2
0
        //
        // IBinaryNumber
        //

        /// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" />
        public static bool IsPow2(uint value) => BitOperations.IsPow2(value);
Esempio n. 3
0
        //
        // IBinaryNumber
        //

        /// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" />
        public static bool IsPow2(long value) => BitOperations.IsPow2(value);
Esempio n. 4
0
 static bool IBinaryNumber <byte> .IsPow2(byte value)
 => BitOperations.IsPow2((uint)value);
Esempio n. 5
0
 static bool IBinaryNumber <ushort> .IsPow2(ushort value)
 => BitOperations.IsPow2((uint)value);
Esempio n. 6
0
 /// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" />
 public static bool IsPow2(sbyte value) => BitOperations.IsPow2(value);
Esempio n. 7
0
        //
        // IBinaryNumber
        //

        /// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" />
        public static bool IsPow2(byte value) => BitOperations.IsPow2((uint)value);
Esempio n. 8
0
 static bool IBinaryNumber <ulong> .IsPow2(ulong value)
 => BitOperations.IsPow2(value);
Esempio n. 9
0
 static bool IBinaryNumber <sbyte> .IsPow2(sbyte value)
 => BitOperations.IsPow2(value);
Esempio n. 10
0
 static bool IBinaryNumber <short> .IsPow2(short value)
 => BitOperations.IsPow2(value);
Esempio n. 11
0
        //
        // IBinaryNumber
        //

        /// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" />
        public static bool IsPow2(ushort value) => BitOperations.IsPow2((uint)value);
Esempio n. 12
0
        public static void Fill <T>(ref T refData, nuint numElements, T value)
        {
            // Early checks to see if it's even possible to vectorize - JIT will turn these checks into consts.
            // - T cannot contain references (GC can't track references in vectors)
            // - Vectorization must be hardware-accelerated
            // - T's size must not exceed the vector's size
            // - T's size must be a whole power of 2

            if (RuntimeHelpers.IsReferenceOrContainsReferences <T>())
            {
                goto CannotVectorize;
            }
            if (!Vector.IsHardwareAccelerated)
            {
                goto CannotVectorize;
            }
            if (Unsafe.SizeOf <T>() > Vector <byte> .Count)
            {
                goto CannotVectorize;
            }
            if (!BitOperations.IsPow2(Unsafe.SizeOf <T>()))
            {
                goto CannotVectorize;
            }

            if (numElements >= (uint)(Vector <byte> .Count / Unsafe.SizeOf <T>()))
            {
                // 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 (Unsafe.SizeOf <T>() == 1)
                {
                    vector = new Vector <byte>(Unsafe.As <T, byte>(ref tmp));
                }
                else if (Unsafe.SizeOf <T>() == 2)
                {
                    vector = (Vector <byte>)(new Vector <ushort>(Unsafe.As <T, ushort>(ref tmp)));
                }
                else if (Unsafe.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)));
                }
                else if (Unsafe.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)));
                }
                else if (Unsafe.SizeOf <T>() == 16)
                {
                    Vector128 <byte> vec128 = Unsafe.As <T, Vector128 <byte> >(ref tmp);
                    if (Vector <byte> .Count == 16)
                    {
                        vector = vec128.AsVector();
                    }
                    else if (Vector <byte> .Count == 32)
                    {
                        vector = Vector256.Create(vec128, vec128).AsVector();
                    }
                    else
                    {
                        Debug.Fail("Vector<T> isn't 128 or 256 bits in size?");
                        goto CannotVectorize;
                    }
                }
                else if (Unsafe.SizeOf <T>() == 32)
                {
                    if (Vector <byte> .Count == 32)
                    {
                        vector = Unsafe.As <T, Vector256 <byte> >(ref tmp).AsVector();
                    }
                    else
                    {
                        Debug.Fail("Vector<T> isn't 256 bits in size?");
                        goto CannotVectorize;
                    }
                }
                else
                {
                    Debug.Fail("Vector<T> is greater than 256 bits in size?");
                    goto CannotVectorize;
                }

                ref byte refDataAsBytes   = ref Unsafe.As <T, byte>(ref refData);
                nuint    totalByteLength  = numElements * (nuint)Unsafe.SizeOf <T>();                        // get this calculation ready ahead of time
                nuint    stopLoopAtOffset = totalByteLength & (nuint)(nint)(2 * (int)-Vector <byte> .Count); // intentional sign extension carries the negative bit
                nuint    offset           = 0;

                // Loop, writing 2 vectors at a time.
                // Compare 'numElements' rather than 'stopLoopAtOffset' because we don't want a dependency
                // on the very recently calculated 'stopLoopAtOffset' value.

                if (numElements >= (uint)(2 * Vector <byte> .Count / Unsafe.SizeOf <T>()))
                {
                    do
                    {
                        Unsafe.WriteUnaligned(ref Unsafe.AddByteOffset(ref refDataAsBytes, offset), vector);
                        Unsafe.WriteUnaligned(ref Unsafe.AddByteOffset(ref refDataAsBytes, offset + (nuint)Vector <byte> .Count), vector);
                        offset += (uint)(2 * Vector <byte> .Count);
                    } while (offset < stopLoopAtOffset);
                }

                // At this point, if any data remains to be written, it's strictly less than
                // 2 * sizeof(Vector) bytes. The loop above had us write an even number of vectors.
                // If the total byte length instead involves us writing an odd number of vectors, write
                // one additional vector now. The bit check below tells us if we're in an "odd vector
                // count" situation.

                if ((totalByteLength & (nuint)Vector <byte> .Count) != 0)
                {
                    Unsafe.WriteUnaligned(ref Unsafe.AddByteOffset(ref refDataAsBytes, offset), vector);
                }

                // It's possible that some small buffer remains to be populated - something that won't
                // fit an entire vector's worth of data. Instead of falling back to a loop, we'll write
                // a vector at the very end of the buffer. This may involve overwriting previously
                // populated data, which is fine since we're splatting the same value for all entries.
                // There's no need to perform a length check here because we already performed this
                // check before entering the vectorized code path.

                Unsafe.WriteUnaligned(ref Unsafe.AddByteOffset(ref refDataAsBytes, totalByteLength - (nuint)Vector <byte> .Count), vector);

                // And we're done!

                return;
            }