using System.Numerics; using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { [Config(typeof(Config.ShortClr))] public class UInt32ToSingle { private float[] data; private const int Count = 32; [GlobalSetup] public void Setup() { this.data = new float[Count]; } [Benchmark(Baseline = true)] public void MagicMethod() { ref Vector b = ref Unsafe.As>(ref this.data[0]); int n = Count / Vector.Count; var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f var mask = new Vector(255); for (int i = 0; i < n; i++) { // union { float f; uint32_t i; } u; // u.f = 32768.0f + x * (255.0f / 256.0f); // return (uint8_t)u.i; ref Vector df = ref Unsafe.Add(ref b, i); var vi = Vector.AsVectorUInt32(df); vi &= mask; vi |= magicInt; var vf = Vector.AsVectorSingle(vi); vf = (vf - magicFloat) * bVec; df = vf; } } [Benchmark] public void StandardSimd() { int n = Count / Vector.Count; ref Vector bf = ref Unsafe.As>(ref this.data[0]); ref Vector bu = ref Unsafe.As, Vector>(ref bf); var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { Vector u = Unsafe.Add(ref bu, i); Vector v = Vector.ConvertToSingle(u); v *= scale; Unsafe.Add(ref bf, i) = v; } } [Benchmark] public void StandardSimdFromInt() { int n = Count / Vector.Count; ref Vector bf = ref Unsafe.As>(ref this.data[0]); ref Vector bu = ref Unsafe.As, Vector>(ref bf); var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { Vector u = Unsafe.Add(ref bu, i); Vector v = Vector.ConvertToSingle(u); v *= scale; Unsafe.Add(ref bf, i) = v; } } [Benchmark] public void StandardSimdFromInt_RefCast() { int n = Count / Vector.Count; ref Vector bf = ref Unsafe.As>(ref this.data[0]); ref Vector bu = ref Unsafe.As, Vector>(ref bf); var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { ref Vector fRef = ref Unsafe.Add(ref bf, i); Vector du = Vector.AsVectorInt32(fRef); Vector v = Vector.ConvertToSingle(du); v *= scale; fRef = v; } } } }