summaryrefslogtreecommitdiff
path: root/tests/src/JIT/Performance
diff options
context:
space:
mode:
authorFei Peng <fei.peng@intel.com>2018-08-06 15:10:50 -0700
committerTanner Gooding <tagoo@outlook.com>2018-08-10 13:26:03 -0700
commitb9028b31caba6e69d1fab99bd1219ae879782802 (patch)
tree1dddf91ee9606cf661f5b52525fa04279bb735b4 /tests/src/JIT/Performance
parenta69e1653ed0734cb0d0192abe302978ee0115b4d (diff)
downloadcoreclr-b9028b31caba6e69d1fab99bd1219ae879782802.tar.gz
coreclr-b9028b31caba6e69d1fab99bd1219ae879782802.tar.bz2
coreclr-b9028b31caba6e69d1fab99bd1219ae879782802.zip
Add SoA raytracer as a CQ test for Intel hardware intrinsic
Diffstat (limited to 'tests/src/JIT/Performance')
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Camera.cs30
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Color.cs20
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ColorPacket.cs58
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Intersections.cs43
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/LightPacket.cs20
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPacket.cs18
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPool.cs68
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.cs243
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.csproj58
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PlanePacket.cs35
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ProducerConsumerCollectionBase.cs107
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Program.cs177
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/RayPacket.cs19
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Scene.cs51
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/SpherePacket.cs40
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surface.cs27
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surfaces.cs61
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Vector.cs18
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorMath.cs107
-rw-r--r--tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorPacket.cs164
20 files changed, 1364 insertions, 0 deletions
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Camera.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Camera.cs
new file mode 100644
index 0000000000..42f3c8baac
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Camera.cs
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics;
+internal class Camera
+{
+
+ public Camera(VectorPacket256 pos, VectorPacket256 forward, VectorPacket256 up, VectorPacket256 right) { Pos = pos; Forward = forward; Up = up; Right = right; }
+
+ public VectorPacket256 Pos;
+ public VectorPacket256 Forward;
+ public VectorPacket256 Up;
+ public VectorPacket256 Right;
+
+ public static Camera Create(VectorPacket256 pos, VectorPacket256 lookAt)
+ {
+ VectorPacket256 forward = (lookAt - pos).Normalize();
+ VectorPacket256 down = new VectorPacket256(SetZeroVector256<float>(), SetAllVector256<float>(-1), SetZeroVector256<float>());
+ Vector256<float> OnePointFive = SetAllVector256<float>(1.5f);
+ VectorPacket256 right = OnePointFive * VectorPacket256.CrossProduct(forward, down).Normalize();
+ VectorPacket256 up = OnePointFive * VectorPacket256.CrossProduct(forward, right).Normalize();
+
+ return new Camera(pos, forward, up, right);
+ }
+
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Color.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Color.cs
new file mode 100644
index 0000000000..85d19d6891
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Color.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+internal struct Color
+{
+ public float R { get; }
+ public float G { get; }
+ public float B { get; }
+
+ public static readonly Color Background = new Color(0, 0, 0);
+
+ public Color(float _r, float _g, float _b)
+ {
+ R = _r;
+ G = _g;
+ B = _b;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ColorPacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ColorPacket.cs
new file mode 100644
index 0000000000..3aa36171aa
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ColorPacket.cs
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+using ColorPacket256 = VectorPacket256;
+
+internal static class ColorPacket256Helper
+{
+
+ private static readonly Vector256<float> One = SetAllVector256<float>(1.0f);
+ private static readonly Vector256<float> Max = SetAllVector256<float>(255.0f);
+ public static Int32RGBPacket256 ConvertToIntRGB(this VectorPacket256 colors)
+ {
+
+ var rsMask = Compare(colors.Xs, One, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var gsMask = Compare(colors.Ys, One, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var bsMask = Compare(colors.Zs, One, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+
+ var rs = BlendVariable(colors.Xs, One, rsMask);
+ var gs = BlendVariable(colors.Ys, One, gsMask);
+ var bs = BlendVariable(colors.Zs, One, bsMask);
+
+ var rsInt = ConvertToVector256Int32(Multiply(rs, Max));
+ var gsInt = ConvertToVector256Int32(Multiply(gs, Max));
+ var bsInt = ConvertToVector256Int32(Multiply(bs, Max));
+
+ return new Int32RGBPacket256(rsInt, gsInt, bsInt);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ColorPacket256 Times(ColorPacket256 left, ColorPacket256 right)
+ {
+ return new VectorPacket256(Multiply(left.Xs, right.Xs), Multiply(left.Ys, right.Ys), Multiply(left.Zs, right.Zs));
+ }
+
+ public static readonly ColorPacket256 BackgroundColor = new ColorPacket256(SetZeroVector256<float>());
+ public static readonly ColorPacket256 DefaultColor = new ColorPacket256(SetZeroVector256<float>());
+}
+
+internal struct Int32RGBPacket256
+{
+ public Vector256<int> Rs;
+ public Vector256<int> Gs;
+ public Vector256<int> Bs;
+
+ public Int32RGBPacket256(Vector256<int> rs, Vector256<int> gs, Vector256<int> bs)
+ {
+ Rs = rs;
+ Gs = gs;
+ Bs = bs;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Intersections.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Intersections.cs
new file mode 100644
index 0000000000..54e4d2d4dc
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Intersections.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Avx2;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+using System;
+
+internal struct Intersections
+{
+ public Vector256<float> Distances;
+ public Vector256<int> ThingIndices;
+
+ public static readonly Vector256<float> NullDistance = SetAllVector256<float>(float.MaxValue);
+ public static readonly Vector256<int> NullIndex = SetAllVector256<int>(-1);
+
+ public Intersections(Vector256<float> dis, Vector256<int> things)
+ {
+ Distances = dis;
+ ThingIndices = things;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool AllNullIntersections()
+ {
+ return AllNullIntersections(Distances);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool AllNullIntersections(Vector256<float> dis)
+ {
+ var cmp = Compare(dis, NullDistance, FloatComparisonMode.EqualOrderedNonSignaling);
+ var zero = SetZeroVector256<int>();
+ // efficiently generate an all-one mask vector by lower latency AVX2 ComapreEqual
+ var mask = Avx2.CompareEqual(zero, zero);
+ return TestC(cmp, StaticCast<int, float>(mask));
+ }
+
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/LightPacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/LightPacket.cs
new file mode 100644
index 0000000000..0b12ca434a
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/LightPacket.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.CompilerServices;
+using ColorPacket256 = VectorPacket256;
+
+internal class LightPacket256
+{
+ public VectorPacket256 Positions;
+ public ColorPacket256 Colors;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public LightPacket256(Vector pos, Color col)
+ {
+ Positions = new VectorPacket256(pos.X, pos.Y, pos.Z);
+ Colors = new ColorPacket256(col.R, col.G, col.B);
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPacket.cs
new file mode 100644
index 0000000000..85bd1a0800
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPacket.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics;
+
+internal abstract class ObjectPacket256
+{
+ public Surface Surface { get; }
+ public abstract Vector256<float> Intersect(RayPacket256 rayPacket256);
+ public abstract VectorPacket256 Normals(VectorPacket256 pos);
+
+ public ObjectPacket256(Surface surface)
+ {
+ Surface = surface;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPool.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPool.cs
new file mode 100644
index 0000000000..29be23238b
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ObjectPool.cs
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace System.Collections.Concurrent
+{
+ /// <summary>Provides a thread-safe object pool.</summary>
+ /// <typeparam name="T">Specifies the type of the elements stored in the pool.</typeparam>
+ [DebuggerDisplay("Count={Count}")]
+ [DebuggerTypeProxy(typeof(IProducerConsumerCollection_DebugView<>))]
+ public sealed class ObjectPool<T> : ProducerConsumerCollectionBase<T>
+ {
+ private readonly Func<T> _generator;
+
+ /// <summary>Initializes an instance of the ObjectPool class.</summary>
+ /// <param name="generator">The function used to create items when no items exist in the pool.</param>
+ public ObjectPool(Func<T> generator) : this(generator, new ConcurrentQueue<T>()) { }
+
+ /// <summary>Initializes an instance of the ObjectPool class.</summary>
+ /// <param name="generator">The function used to create items when no items exist in the pool.</param>
+ /// <param name="collection">The collection used to store the elements of the pool.</param>
+ public ObjectPool(Func<T> generator, IProducerConsumerCollection<T> collection)
+ : base(collection)
+ {
+ if (generator == null) throw new ArgumentNullException("generator");
+ _generator = generator;
+ }
+
+ /// <summary>Adds the provided item into the pool.</summary>
+ /// <param name="item">The item to be added.</param>
+ public void PutObject(T item) { base.TryAdd(item); }
+
+ /// <summary>Gets an item from the pool.</summary>
+ /// <returns>The removed or created item.</returns>
+ /// <remarks>If the pool is empty, a new item will be created and returned.</remarks>
+ public T GetObject()
+ {
+ T value;
+ return base.TryTake(out value) ? value : _generator();
+ }
+
+ /// <summary>Clears the object pool, returning all of the data that was in the pool.</summary>
+ /// <returns>An array containing all of the elements in the pool.</returns>
+ public T[] ToArrayAndClear()
+ {
+ var items = new List<T>();
+ T value;
+ while (base.TryTake(out value)) items.Add(value);
+ return items.ToArray();
+ }
+
+ protected override bool TryAdd(T item)
+ {
+ PutObject(item);
+ return true;
+ }
+
+ protected override bool TryTake(out T item)
+ {
+ item = GetObject();
+ return true;
+ }
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.cs
new file mode 100644
index 0000000000..ba52a472a0
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.cs
@@ -0,0 +1,243 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Avx2;
+using static System.Runtime.Intrinsics.X86.Sse2;
+using System.Runtime.Intrinsics;
+using System;
+
+using ColorPacket256 = VectorPacket256;
+
+internal class Packet256Tracer
+{
+ public int Width { get; }
+ public int Height { get; }
+ private static readonly int MaxDepth = 5;
+
+ private static readonly Vector256<float> SevenToZero = SetVector256(7f, 6f, 5f, 4f, 3f, 2f, 1f, 0f);
+
+ public Packet256Tracer(int width, int height)
+ {
+ if ((width % VectorPacket256.Packet256Size) != 0)
+ {
+ width += VectorPacket256.Packet256Size - (width % VectorPacket256.Packet256Size);
+ }
+ Width = width;
+ Height = height;
+ }
+
+ internal unsafe void RenderVectorized(Scene scene, int* rgb)
+ {
+ Camera camera = scene.Camera;
+ // Iterate y then x in order to preserve cache locality.
+ for (int y = 0; y < Height; y++)
+ {
+ int stride = y * Width;
+ for (int x = 0; x < Width; x += VectorPacket256.Packet256Size)
+ {
+ float fx = x;
+ Vector256<float> Xs = Add(SetAllVector256(fx), SevenToZero);
+ var dirs = GetPoints(Xs, SetAllVector256<float>(y), camera);
+ var rayPacket256 = new RayPacket256(camera.Pos, dirs);
+ var SoAcolors = TraceRay(rayPacket256, scene, depth: 0);
+
+ var AoS = SoAcolors.Transpose();
+ var intAoS = AoS.ConvertToIntRGB();
+
+ int* output = &rgb[(x + stride) * 3]; // Each pixel has 3 fields (RGB)
+ {
+ Store(output, intAoS.Rs);
+ Store(output + 8, intAoS.Gs);
+ Store(output + 16, intAoS.Bs);
+ }
+
+ }
+ }
+
+ }
+
+ private ColorPacket256 TraceRay(RayPacket256 rayPacket256, Scene scene, int depth)
+ {
+ var isect = MinIntersections(rayPacket256, scene);
+ if (isect.AllNullIntersections())
+ {
+ return ColorPacket256Helper.BackgroundColor;
+ }
+ var color = Shade(isect, rayPacket256, scene, depth);
+ var isNull = Compare(isect.Distances, Intersections.NullDistance, FloatComparisonMode.EqualOrderedNonSignaling);
+ var backgroundColor = ColorPacket256Helper.BackgroundColor.Xs;
+ return new ColorPacket256(BlendVariable(color.Xs, backgroundColor, isNull),
+ BlendVariable(color.Ys, backgroundColor, isNull),
+ BlendVariable(color.Zs, backgroundColor, isNull));
+ }
+
+ private Vector256<float> TestRay(RayPacket256 rayPacket256, Scene scene)
+ {
+ var isect = MinIntersections(rayPacket256, scene);
+ if (isect.AllNullIntersections())
+ {
+ return SetZeroVector256<float>();
+ }
+ var isNull = Compare(isect.Distances, Intersections.NullDistance, FloatComparisonMode.EqualOrderedNonSignaling);
+ return BlendVariable(isect.Distances, SetZeroVector256<float>(), isNull);
+ }
+
+ private Intersections MinIntersections(RayPacket256 rayPacket256, Scene scene)
+ {
+ Intersections mins = new Intersections(Intersections.NullDistance, Intersections.NullIndex);
+ for (int i = 0; i < scene.Things.Length; i++)
+ {
+ Vector256<float> distance = scene.Things[i].Intersect(rayPacket256);
+
+ if (!Intersections.AllNullIntersections(distance))
+ {
+ var notNullMask = Compare(distance, Intersections.NullDistance, FloatComparisonMode.NotEqualOrderedNonSignaling);
+ var nullMinMask = Compare(mins.Distances, Intersections.NullDistance, FloatComparisonMode.EqualOrderedNonSignaling);
+
+ var lessMinMask = Compare(mins.Distances, distance, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var minMask = And(notNullMask, Or(nullMinMask, lessMinMask));
+ var minDis = BlendVariable(mins.Distances, distance, minMask);
+ var minIndices = StaticCast<float, int>(BlendVariable(StaticCast<int, float>(mins.ThingIndices),
+ StaticCast<int, float>(SetAllVector256<int>(i)),
+ minMask));
+ mins.Distances = minDis;
+ mins.ThingIndices = minIndices;
+ }
+ }
+ return mins;
+ }
+
+ private ColorPacket256 Shade(Intersections isect, RayPacket256 rays, Scene scene, int depth)
+ {
+
+ var ds = rays.Dirs;
+ var pos = isect.Distances * ds + rays.Starts;
+ var normals = scene.Normals(isect.ThingIndices, pos);
+ var reflectDirs = ds - (Multiply(VectorPacket256.DotProduct(normals, ds), SetAllVector256<float>(2)) * normals);
+ var colors = GetNaturalColor(isect.ThingIndices, pos, normals, reflectDirs, scene);
+
+ if (depth >= MaxDepth)
+ {
+ return colors + new ColorPacket256(.5f, .5f, .5f);
+ }
+
+ return colors + GetReflectionColor(isect.ThingIndices, pos + (SetAllVector256<float>(0.001f) * reflectDirs), normals, reflectDirs, scene, depth);
+ }
+
+ private ColorPacket256 GetNaturalColor(Vector256<int> things, VectorPacket256 pos, VectorPacket256 norms, VectorPacket256 rds, Scene scene)
+ {
+ var colors = ColorPacket256Helper.DefaultColor;
+ for (int i = 0; i < scene.Lights.Length; i++)
+ {
+ var lights = scene.Lights[i];
+ var zero = SetZeroVector256<float>();
+ var colorPacket = lights.Colors;
+ var ldis = lights.Positions - pos;
+ var livec = ldis.Normalize();
+ var neatIsectDis = TestRay(new RayPacket256(pos, livec), scene);
+
+ // is in shadow?
+ var mask1 = Compare(neatIsectDis, ldis.Lengths, FloatComparisonMode.LessThanOrEqualOrderedNonSignaling);
+ var mask2 = Compare(neatIsectDis, zero, FloatComparisonMode.NotEqualOrderedNonSignaling);
+ var isInShadow = And(mask1, mask2);
+
+ Vector256<float> illum = VectorPacket256.DotProduct(livec, norms);
+ Vector256<float> illumGraterThanZero = Compare(illum, zero, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var tmpColor1 = illum * colorPacket;
+ var defaultRGB = zero;
+ Vector256<float> lcolorR = BlendVariable(defaultRGB, tmpColor1.Xs, illumGraterThanZero);
+ Vector256<float> lcolorG = BlendVariable(defaultRGB, tmpColor1.Ys, illumGraterThanZero);
+ Vector256<float> lcolorB = BlendVariable(defaultRGB, tmpColor1.Zs, illumGraterThanZero);
+ ColorPacket256 lcolor = new ColorPacket256(lcolorR, lcolorG, lcolorB);
+
+ Vector256<float> specular = VectorPacket256.DotProduct(livec, rds.Normalize());
+ Vector256<float> specularGraterThanZero = Compare(specular, zero, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+
+ var difColor = new ColorPacket256(1, 1, 1);
+ var splColor = new ColorPacket256(1, 1, 1);
+ var roughness = SetAllVector256<float>(1);
+
+ for (int j = 0; j < scene.Things.Length; j++)
+ {
+ Vector256<float> thingMask = StaticCast<int, float>(CompareEqual(things, SetAllVector256<int>(j)));
+ var rgh = SetAllVector256<float>(scene.Things[j].Surface.Roughness);
+ var dif = scene.Things[j].Surface.Diffuse(pos);
+ var spl = scene.Things[j].Surface.Specular;
+
+ roughness = BlendVariable(roughness, rgh, thingMask);
+
+ difColor.Xs = BlendVariable(difColor.Xs, dif.Xs, thingMask);
+ difColor.Ys = BlendVariable(difColor.Ys, dif.Ys, thingMask);
+ difColor.Zs = BlendVariable(difColor.Zs, dif.Zs, thingMask);
+
+ splColor.Xs = BlendVariable(splColor.Xs, spl.Xs, thingMask);
+ splColor.Ys = BlendVariable(splColor.Ys, spl.Ys, thingMask);
+ splColor.Zs = BlendVariable(splColor.Zs, spl.Zs, thingMask);
+ }
+
+ var tmpColor2 = VectorMath.Pow(specular, roughness) * colorPacket;
+ Vector256<float> scolorR = BlendVariable(defaultRGB, tmpColor2.Xs, specularGraterThanZero);
+ Vector256<float> scolorG = BlendVariable(defaultRGB, tmpColor2.Ys, specularGraterThanZero);
+ Vector256<float> scolorB = BlendVariable(defaultRGB, tmpColor2.Zs, specularGraterThanZero);
+ ColorPacket256 scolor = new ColorPacket256(scolorR, scolorG, scolorB);
+
+ var oldColor = colors;
+
+ colors = colors + ColorPacket256Helper.Times(difColor, lcolor) + ColorPacket256Helper.Times(splColor, scolor);
+
+ colors = new ColorPacket256(BlendVariable(colors.Xs, oldColor.Xs, isInShadow), BlendVariable(colors.Ys, oldColor.Ys, isInShadow), BlendVariable(colors.Zs, oldColor.Zs, isInShadow));
+
+ }
+ return colors;
+ }
+
+ private ColorPacket256 GetReflectionColor(Vector256<int> things, VectorPacket256 pos, VectorPacket256 norms, VectorPacket256 rds, Scene scene, int depth)
+ {
+ return scene.Reflect(things, pos) * TraceRay(new RayPacket256(pos, rds), scene, depth + 1);
+ }
+
+ private readonly static Vector256<float> ConstTwo = SetAllVector256(2.0f);
+
+ private VectorPacket256 GetPoints(Vector256<float> x, Vector256<float> y, Camera camera)
+ {
+ var widthVector = SetAllVector256<float>(Width);
+ var heightVector = SetAllVector256<float>(Height);
+
+ var widthRate1 = Divide(widthVector, ConstTwo);
+ var widthRate2 = Multiply(widthVector, ConstTwo);
+
+ var heightRate1 = Divide(heightVector, ConstTwo);
+ var heightRate2 = Multiply(heightVector, ConstTwo);
+
+ var recenteredX = Divide(Subtract(x, widthRate1), widthRate2);
+ var recenteredY = Subtract(SetZeroVector256<float>(), Divide(Subtract(y, heightRate1), heightRate2));
+
+ var result = camera.Forward + (recenteredX * camera.Right) + (recenteredY * camera.Up);
+
+ return result.Normalize();
+ }
+
+ internal readonly Scene DefaultScene = CreateDefaultScene();
+
+ private static Scene CreateDefaultScene()
+ {
+ ObjectPacket256[] things = {
+ new SpherePacket256(new VectorPacket256(-0.5f, 1f, 1.5f), SetAllVector256(0.5f), Surfaces.MatteShiny),
+ new SpherePacket256(new VectorPacket256(0f, 1f, -0.25f), SetAllVector256(1f), Surfaces.Shiny),
+ new PlanePacket256((new VectorPacket256(0, 1, 0)), SetAllVector256(0f), Surfaces.CheckerBoard)
+ };
+
+ LightPacket256[] lights = {
+ new LightPacket256(new Vector(-2f,2.5f,0f),new Color(.5f,.45f,.41f)),
+ new LightPacket256(new Vector(2,4.5f,2), new Color(.99f,.95f,.8f))
+ };
+
+ Camera camera = Camera.Create(new VectorPacket256(2.75f, 2f, 3.75f), new VectorPacket256(-0.6f, .5f, 0f));
+
+ return new Scene(things, lights, camera);
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.csproj b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.csproj
new file mode 100644
index 0000000000..54118803a9
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PacketTracer.csproj
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.1</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetTargetMoniker>.NETStandard,Version=v1.4</NuGetTargetMoniker>
+ <NuGetTargetMonikerShort>netstandard1.4</NuGetTargetMonikerShort>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+ <PropertyGroup>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Camera.cs" />
+ <Compile Include="Color.cs" />
+ <Compile Include="ColorPacket.cs" />
+ <Compile Include="Intersections.cs" />
+ <Compile Include="LightPacket.cs" />
+ <Compile Include="ObjectPacket.cs" />
+ <Compile Include="ObjectPool.cs" />
+ <Compile Include="PacketTracer.cs" />
+ <Compile Include="PlanePacket.cs" />
+ <Compile Include="ProducerConsumerCollectionBase.cs" />
+ <Compile Include="RayPacket.cs" />
+ <Compile Include="Scene.cs" />
+ <Compile Include="SpherePacket.cs" />
+ <Compile Include="Surface.cs" />
+ <Compile Include="Surfaces.cs" />
+ <Compile Include="Vector.cs" />
+ <Compile Include="VectorPacket.cs" />
+ <Compile Include="VectorMath.cs" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+ <PropertyGroup>
+ <ProjectAssetsFile>$(JitPackagesConfigFileDirectory)benchmark+intrinsic\obj\project.assets.json</ProjectAssetsFile>
+ </PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PlanePacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PlanePacket.cs
new file mode 100644
index 0000000000..0269367955
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/PlanePacket.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+internal sealed class PlanePacket256 : ObjectPacket256
+{
+ public VectorPacket256 Norms;
+ public Vector256<float> Offsets;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public PlanePacket256(VectorPacket256 norms, Vector256<float> offsets, Surface surface) : base(surface)
+ {
+ Norms = norms;
+ Offsets = offsets;
+ }
+
+ public override VectorPacket256 Normals(VectorPacket256 pos)
+ {
+ return Norms;
+ }
+
+ public override Vector256<float> Intersect(RayPacket256 rayPacket256)
+ {
+ var denom = VectorPacket256.DotProduct(Norms, rayPacket256.Dirs);
+ var dist = Divide(Add(VectorPacket256.DotProduct(Norms, rayPacket256.Starts), Offsets), Subtract(SetZeroVector256<float>(), denom));
+ var gtMask = Compare(denom, SetZeroVector256<float>(), FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ return BlendVariable(dist, Intersections.NullDistance, gtMask);
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ProducerConsumerCollectionBase.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ProducerConsumerCollectionBase.cs
new file mode 100644
index 0000000000..fee736397d
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/ProducerConsumerCollectionBase.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace System.Collections.Concurrent
+{
+ /// <summary>Debug view for the IProducerConsumerCollection.</summary>
+ /// <typeparam name="T">Specifies the type of the data being aggregated.</typeparam>
+ internal sealed class IProducerConsumerCollection_DebugView<T>
+ {
+ private IProducerConsumerCollection<T> _collection;
+
+ public IProducerConsumerCollection_DebugView(IProducerConsumerCollection<T> collection)
+ {
+ _collection = collection;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ public T[] Values { get { return _collection.ToArray(); } }
+ }
+
+ /// <summary>
+ /// Provides a base implementation for producer-consumer collections that wrap other
+ /// producer-consumer collections.
+ /// </summary>
+ /// <typeparam name="T">Specifies the type of elements in the collection.</typeparam>
+ public abstract class ProducerConsumerCollectionBase<T> : IProducerConsumerCollection<T>
+ {
+ private readonly IProducerConsumerCollection<T> _contained;
+
+ /// <summary>Initializes the ProducerConsumerCollectionBase instance.</summary>
+ /// <param name="contained">The collection to be wrapped by this instance.</param>
+ protected ProducerConsumerCollectionBase(IProducerConsumerCollection<T> contained)
+ {
+ if (contained == null) throw new ArgumentNullException("contained");
+ _contained = contained;
+ }
+
+ /// <summary>Gets the contained collection.</summary>
+ protected IProducerConsumerCollection<T> ContainedCollection { get { return _contained; } }
+
+ /// <summary>Attempts to add the specified value to the end of the deque.</summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>true if the item could be added; otherwise, false.</returns>
+ protected virtual bool TryAdd(T item) { return _contained.TryAdd(item); }
+
+ /// <summary>Attempts to remove and return an item from the collection.</summary>
+ /// <param name="item">
+ /// When this method returns, if the operation was successful, item contains the item removed. If
+ /// no item was available to be removed, the value is unspecified.
+ /// </param>
+ /// <returns>
+ /// true if an element was removed and returned from the collection; otherwise, false.
+ /// </returns>
+ protected virtual bool TryTake(out T item) { return _contained.TryTake(out item); }
+
+ /// <summary>Attempts to add the specified value to the end of the deque.</summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>true if the item could be added; otherwise, false.</returns>
+ bool IProducerConsumerCollection<T>.TryAdd(T item) { return TryAdd(item); }
+
+ /// <summary>Attempts to remove and return an item from the collection.</summary>
+ /// <param name="item">
+ /// When this method returns, if the operation was successful, item contains the item removed. If
+ /// no item was available to be removed, the value is unspecified.
+ /// </param>
+ /// <returns>
+ /// true if an element was removed and returned from the collection; otherwise, false.
+ /// </returns>
+ bool IProducerConsumerCollection<T>.TryTake(out T item) { return TryTake(out item); }
+
+ /// <summary>Gets the number of elements contained in the collection.</summary>
+ public int Count { get { return _contained.Count; } }
+
+ /// <summary>Creates an array containing the contents of the collection.</summary>
+ /// <returns>The array.</returns>
+ public T[] ToArray() { return _contained.ToArray(); }
+
+ /// <summary>Copies the contents of the collection to an array.</summary>
+ /// <param name="array">The array to which the data should be copied.</param>
+ /// <param name="index">The starting index at which data should be copied.</param>
+ public void CopyTo(T[] array, int index) { _contained.CopyTo(array, index); }
+
+ /// <summary>Copies the contents of the collection to an array.</summary>
+ /// <param name="array">The array to which the data should be copied.</param>
+ /// <param name="index">The starting index at which data should be copied.</param>
+ void ICollection.CopyTo(Array array, int index) { _contained.CopyTo(array, index); }
+
+ /// <summary>Gets an enumerator for the collection.</summary>
+ /// <returns>An enumerator.</returns>
+ public IEnumerator<T> GetEnumerator() { return _contained.GetEnumerator(); }
+
+ /// <summary>Gets an enumerator for the collection.</summary>
+ /// <returns>An enumerator.</returns>
+ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
+
+ /// <summary>Gets whether the collection is synchronized.</summary>
+ bool ICollection.IsSynchronized { get { return _contained.IsSynchronized; } }
+
+ /// <summary>Gets the synchronization root object for the collection.</summary>
+ object ICollection.SyncRoot { get { return _contained.SyncRoot; } }
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Program.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Program.cs
new file mode 100644
index 0000000000..3ae923a9b1
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Program.cs
@@ -0,0 +1,177 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Concurrent;
+using System.Runtime.Intrinsics.X86;
+//using Microsoft.Xunit.Performance;
+
+//[assembly: OptimizeForBenchmarks]
+
+class Program
+{
+#if DEBUG
+
+ private const int RunningTime = 200;
+ private const int Width = 248;
+ private const int Height = 248;
+ private const int Iterations = 1;
+ private const int MaxIterations = 1000;
+
+#else
+
+ private const int RunningTime = 1000;
+ private const int Width = 248;
+ private const int Height = 248;
+ private const int Iterations = 7;
+ private const int MaxIterations = 1000;
+
+#endif
+
+ private double _framesPerSecond;
+ private bool _parallel;
+ private bool _showThreads;
+ private static int _width, _height;
+ private int _degreeOfParallelism = Environment.ProcessorCount;
+ private int _frames;
+ private CancellationTokenSource _cancellation;
+ private ObjectPool<int[]> _freeBuffers;
+
+ public Program()
+ {
+ _width = Width;
+ _height = Height;
+ _parallel = false;
+ _showThreads = false;
+ _freeBuffers = new ObjectPool<int[]>(() => new int[_width * 3 * _height]); // Each pixel has 3 fields (RGB)
+ }
+
+ static unsafe int Main(string[] args)
+ {
+ if (Avx2.IsSupported)
+ {
+ var r = new Program();
+ // We can use `RenderTo` to generate a picture in a PPM file for debugging
+ // r.RenderTo("./pic.ppm", true);
+ bool result = r.Run();
+ return (result ? 100 : -1);
+ }
+ return 100;
+ }
+
+ private void RenderTest()
+ {
+ _cancellation = new CancellationTokenSource(RunningTime);
+ RenderLoop(MaxIterations);
+ }
+
+ private void RenderBench()
+ {
+ _cancellation = new CancellationTokenSource();
+ RenderLoop(Iterations);
+ }
+
+ private unsafe void RenderLoop(int iterations)
+ {
+ // Create a ray tracer, and create a reference to "sphere2" that we are going to bounce
+ var packetTracer = new Packet256Tracer(_width, _height);
+ var scene = packetTracer.DefaultScene;
+ var sphere2 = (SpherePacket256)scene.Things[0]; // The first item is assumed to be our sphere
+ var baseY = sphere2.Radiuses;
+ sphere2.Centers.Ys = sphere2.Radiuses;
+
+ // Timing determines how fast the ball bounces as well as diagnostics frames/second info
+ var renderingTime = new Stopwatch();
+ var totalTime = Stopwatch.StartNew();
+
+ // Keep rendering until the iteration count is hit
+ for (_frames = 0; _frames < iterations; _frames++)
+ {
+ // Or the rendering task has been canceled
+ if (_cancellation.IsCancellationRequested)
+ {
+ break;
+ }
+
+ // Get the next buffer
+ var rgbBuffer = _freeBuffers.GetObject();
+
+ // Determine the new position of the sphere based on the current time elapsed
+ float dy2 = 0.8f * MathF.Abs(MathF.Sin((float)(totalTime.ElapsedMilliseconds * Math.PI / 3000)));
+ sphere2.Centers.Ys = Avx.Add(baseY, Avx.SetAllVector256(dy2));
+
+ // Render the scene
+ renderingTime.Reset();
+ renderingTime.Start();
+ ParallelOptions options = new ParallelOptions
+ {
+ MaxDegreeOfParallelism = _degreeOfParallelism,
+ CancellationToken = _cancellation.Token
+ };
+ fixed (int* ptr = rgbBuffer)
+ {
+ packetTracer.RenderVectorized(scene, ptr);
+ }
+
+ renderingTime.Stop();
+
+ _framesPerSecond = (1000.0 / renderingTime.ElapsedMilliseconds);
+ _freeBuffers.PutObject(rgbBuffer);
+ }
+ }
+
+ public bool Run()
+ {
+ RenderTest();
+ Console.WriteLine("{0} frames, {1} frames/sec",
+ _frames,
+ _framesPerSecond.ToString("F2"));
+ return true;
+ }
+
+ private unsafe void RenderTo(string fileName, bool wirteToFile)
+ {
+ var packetTracer = new Packet256Tracer(_width, _height);
+ var scene = packetTracer.DefaultScene;
+ var rgb = new int[_width * 3 * _height];
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ fixed (int* ptr = rgb)
+ {
+ packetTracer.RenderVectorized(scene, ptr);
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
+ ts.Hours, ts.Minutes, ts.Seconds,
+ ts.Milliseconds / 10);
+ Console.WriteLine("RunTime " + elapsedTime);
+
+ if (wirteToFile)
+ {
+ using (var file = new System.IO.StreamWriter(fileName))
+ {
+ file.WriteLine("P3");
+ file.WriteLine(_width + " " + _height);
+ file.WriteLine("255");
+
+ for (int i = 0; i < _height; i++)
+ {
+ for (int j = 0; j < _width; j++)
+ {
+ // Each pixel has 3 fields (RGB)
+ int pos = (i * _width + j) * 3;
+ file.Write(rgb[pos] + " " + rgb[pos + 1] + " " + rgb[pos + 2] + " ");
+ }
+ file.WriteLine();
+ }
+ }
+
+ }
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/RayPacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/RayPacket.cs
new file mode 100644
index 0000000000..75559c3461
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/RayPacket.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+
+internal class RayPacket256
+{
+ public VectorPacket256 Starts;
+ public VectorPacket256 Dirs;
+
+ public RayPacket256(VectorPacket256 starts, VectorPacket256 dirs)
+ {
+ Starts = starts;
+ Dirs = dirs;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Scene.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Scene.cs
new file mode 100644
index 0000000000..9edbb946b1
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Scene.cs
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Collections.Generic;
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Avx2;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+using System;
+
+internal class Scene
+{
+ public ObjectPacket256[] Things;
+ public LightPacket256[] Lights;
+ public Camera Camera;
+
+ public Scene(ObjectPacket256[] things, LightPacket256[] lights, Camera camera) { Things = things; Lights = lights; Camera = camera; }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 Normals(Vector256<int> things, VectorPacket256 pos)
+ {
+ VectorPacket256 norms = new VectorPacket256(1, 1, 1);
+
+ for (int i = 0; i < Things.Length; i++)
+ {
+ Vector256<float> mask = StaticCast<int, float>(CompareEqual(things, SetAllVector256<int>(i)));
+ var n = Things[i].Normals(pos);
+ norms.Xs = BlendVariable(norms.Xs, n.Xs, mask);
+ norms.Ys = BlendVariable(norms.Ys, n.Ys, mask);
+ norms.Zs = BlendVariable(norms.Zs, n.Zs, mask);
+ }
+
+ return norms;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector256<float> Reflect(Vector256<int> things, VectorPacket256 pos)
+ {
+ Vector256<float> rfl = SetAllVector256<float>(1);
+ for (int i = 0; i < Things.Length; i++)
+ {
+ Vector256<float> mask = StaticCast<int, float>(CompareEqual(things, SetAllVector256<int>(i)));
+ rfl = BlendVariable(rfl, Things[i].Surface.Reflect(pos), mask);
+ }
+ return rfl;
+ }
+
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/SpherePacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/SpherePacket.cs
new file mode 100644
index 0000000000..b1e2b496a7
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/SpherePacket.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+internal sealed class SpherePacket256 : ObjectPacket256
+{
+ public VectorPacket256 Centers;
+ public Vector256<float> Radiuses;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public SpherePacket256(VectorPacket256 centers, Vector256<float> radiuses, Surface surface) : base(surface)
+ {
+ Centers = centers;
+ Radiuses = radiuses;
+ }
+
+ public override VectorPacket256 Normals(VectorPacket256 pos)
+ {
+ return (pos - Centers).Normalize();
+ }
+
+ public override Vector256<float> Intersect(RayPacket256 rayPacket256)
+ {
+ var eo = Centers - rayPacket256.Starts;
+ var v = VectorPacket256.DotProduct(eo, rayPacket256.Dirs);
+ var zero = SetZeroVector256<float>();
+ var vLessZeroMask = Compare(v, zero, FloatComparisonMode.LessThanOrderedNonSignaling);
+ var discs = Subtract(Multiply(Radiuses, Radiuses), Subtract(VectorPacket256.DotProduct(eo, eo), Multiply(v, v)));
+ var discLessZeroMask = Compare(discs, zero, FloatComparisonMode.LessThanOrderedNonSignaling);
+ var dists = BlendVariable(Subtract(v, Sqrt(discs)), zero, Or(vLessZeroMask, discLessZeroMask));
+ var isZero = Compare(dists, zero, FloatComparisonMode.EqualOrderedNonSignaling);
+ return BlendVariable(dists, Intersections.NullDistance, isZero);
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surface.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surface.cs
new file mode 100644
index 0000000000..35e04bd842
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surface.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics;
+using System;
+using ColorPacket256 = VectorPacket256;
+
+internal class Surface
+{
+ public Func<VectorPacket256, ColorPacket256> Diffuse;
+ public VectorPacket256 Specular;
+ public Func<VectorPacket256, Vector256<float>> Reflect;
+ public float Roughness;
+
+ public Surface(Func<VectorPacket256, ColorPacket256> Diffuse,
+ VectorPacket256 Specular,
+ Func<VectorPacket256, Vector256<float>> Reflect,
+ float Roughness)
+ {
+ this.Diffuse = Diffuse;
+ this.Specular = Specular;
+ this.Reflect = Reflect;
+ this.Roughness = Roughness;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surfaces.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surfaces.cs
new file mode 100644
index 0000000000..7e467ae34e
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Surfaces.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using ColorPacket256 = VectorPacket256;
+
+using System;
+
+internal static class Surfaces
+{
+
+ private static readonly ColorPacket256 White = new ColorPacket256(SetAllVector256(1.0f));
+ private static readonly ColorPacket256 Black = new ColorPacket256(0.02f, 0.0f, 0.14f);
+ // Only works with X-Z plane.
+ public static readonly Surface CheckerBoard =
+ new Surface(
+ delegate (VectorPacket256 pos)
+ {
+ var floored = ConvertToVector256Int32(Add(Floor(pos.Zs), Floor(pos.Xs)));
+ var modMask = SetAllVector256<int>(1);
+ var evenMaskint = Avx2.And(floored, modMask);
+ var evenMask = Avx2.CompareEqual(evenMaskint, modMask);
+
+ var resultX = BlendVariable(Black.Xs, White.Xs, StaticCast<int, float>(evenMask));
+ var resultY = BlendVariable(Black.Ys, White.Ys, StaticCast<int, float>(evenMask));
+ var resultZ = BlendVariable(Black.Zs, White.Zs, StaticCast<int, float>(evenMask));
+
+ return new ColorPacket256(resultX, resultY, resultZ);
+ },
+ new VectorPacket256(1f, 1f, 1f),
+ delegate (VectorPacket256 pos)
+ {
+ var floored = ConvertToVector256Int32(Add(Floor(pos.Zs), Floor(pos.Xs)));
+ var modMask = SetAllVector256<int>(1);
+ var evenMaskUint = Avx2.And(floored, modMask);
+ var evenMask = Avx2.CompareEqual(evenMaskUint, modMask);
+
+ return BlendVariable(SetAllVector256(0.5f), SetAllVector256(0.1f), StaticCast<int, float>(evenMask));
+ },
+ 150f);
+
+
+
+ public static readonly Surface Shiny =
+ new Surface(
+ delegate (VectorPacket256 pos) { return new VectorPacket256(1f, 1f, 1f); },
+ new VectorPacket256(.5f, .5f, .5f),
+ delegate (VectorPacket256 pos) { return SetAllVector256<float>(0.7f); },
+ 250f);
+
+ public static readonly Surface MatteShiny =
+ new Surface(
+ delegate (VectorPacket256 pos) { return new VectorPacket256(1f, 1f, 1f); },
+ new VectorPacket256(.25f, .25f, .25f),
+ delegate (VectorPacket256 pos) { return SetAllVector256<float>(0.7f); },
+ 250f);
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Vector.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Vector.cs
new file mode 100644
index 0000000000..ec27d823f8
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/Vector.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+internal struct Vector
+{
+ public float X { get; set; }
+ public float Y { get; set; }
+ public float Z { get; set; }
+
+ public Vector(float x, float y, float z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorMath.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorMath.cs
new file mode 100644
index 0000000000..51c87605aa
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorMath.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+using System;
+
+public static class VectorMath
+{
+ static readonly Vector256<float> MaxValue = SetAllVector256<float>(88.0f);
+ static readonly Vector256<float> MinValue = SetAllVector256<float>(-88.0f);
+ static readonly Vector256<float> Log2 = SetAllVector256<float>(1.44269502f);
+ static readonly Vector256<float> C1 = SetAllVector256<float>(0.693359375f);
+ static readonly Vector256<float> C2 = SetAllVector256<float>(-0.0002121944417f);
+ static readonly Vector256<float> P0 = SetAllVector256<float>(0.0001987569121f);
+ static readonly Vector256<float> P1 = SetAllVector256<float>(0.001398199936f);
+ static readonly Vector256<float> P2 = SetAllVector256<float>(0.008333452046f);
+ static readonly Vector256<float> P3 = SetAllVector256<float>(0.04166579619f);
+ static readonly Vector256<float> P4 = SetAllVector256<float>(0.1666666567f);
+ static readonly Vector256<float> LogP0 = SetAllVector256<float>(0.07037683576f);
+ static readonly Vector256<float> LogP1 = SetAllVector256<float>(-0.1151461005f);
+ static readonly Vector256<float> LogP2 = SetAllVector256<float>(0.1167699844f);
+ static readonly Vector256<float> LogP3 = SetAllVector256<float>(-0.1242014095f);
+ static readonly Vector256<float> LogP4 = SetAllVector256<float>(0.1424932331f);
+ static readonly Vector256<float> LogP5 = SetAllVector256<float>(-0.1666805744f);
+ static readonly Vector256<float> LogP6 = SetAllVector256<float>(0.2000071406f);
+ static readonly Vector256<float> LogP7 = SetAllVector256<float>(-0.2499999404f);
+ static readonly Vector256<float> LogP8 = SetAllVector256<float>(0.3333333135f);
+ static readonly Vector256<float> LogQ1 = SetAllVector256<float>(-0.0002121944417f);
+ static readonly Vector256<float> LogQ2 = SetAllVector256<float>(0.693359375f);
+ static readonly Vector256<float> Point5 = SetAllVector256<float>(0.5f);
+ static readonly Vector256<float> Sqrthf = SetAllVector256<float>(0.7071067691f);
+ static readonly Vector256<float> One = SetAllVector256<float>(1.0f);
+ static readonly Vector256<int> Ox7 = SetAllVector256<int>(127);
+ static readonly Vector256<int> MinNormPos = SetAllVector256<int>(8388608);
+ static readonly Vector256<int> MantMask = SetAllVector256<int>(-2139095041);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256<float> Pow(Vector256<float> left, Vector256<float> right)
+ {
+ return Exp(Multiply(right, Log(left)));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256<float> Exp(Vector256<float> value)
+ {
+ value = Min(value, MaxValue);
+ value = Max(value, MinValue);
+ Vector256<float> fx = Multiply(value, Log2);
+ fx = Floor(Add(fx, Point5));
+
+ Vector256<float> tmp = Multiply(fx, C1);
+ Vector256<float> z = Multiply(fx, C2);
+ Vector256<float> x = Subtract(value, tmp);
+ x = Subtract(x, z);
+ z = Multiply(x, x);
+ Vector256<float> y = P0;
+ y = Add(Multiply(y, x), P1);
+ y = Add(Multiply(y, x), P2);
+ y = Add(Multiply(y, x), P3);
+ y = Add(Multiply(y, x), P4);
+ y = Add(Multiply(y, x), Point5);
+ y = Add(Add(Multiply(y, z), x), One);
+
+ Vector256<int> pow2n = ConvertToVector256Int32(fx);
+ pow2n = Avx2.Add(pow2n, Ox7);
+ pow2n = Avx2.ShiftLeftLogical(pow2n, 23);
+
+ return Multiply(y, StaticCast<int, float>(pow2n));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256<float> Log(Vector256<float> value)
+ {
+ Vector256<float> invalidMask = Compare(value, SetZeroVector256<float>(), FloatComparisonMode.LessThanOrEqualOrderedNonSignaling);
+ Vector256<float> x = Max(value, StaticCast<int, float>(MinNormPos));
+ Vector256<int> ei = Avx2.ShiftRightLogical(StaticCast<float, int>(x), 23);
+ x = Or(And(x, StaticCast<int, float>(MantMask)), Point5);
+ ei = Avx2.Subtract(ei, Ox7);
+ Vector256<float> e = Add(ConvertToVector256Single(ei), One);
+ Vector256<float> mask = Compare(x, Sqrthf, FloatComparisonMode.LessThanOrderedNonSignaling);
+ Vector256<float> tmp = And(x, mask);
+ x = Subtract(x, One);
+ e = Subtract(e, And(One, mask));
+ x = Add(x, tmp);
+ Vector256<float> z = Multiply(x, x);
+ Vector256<float> y = LogP0;
+ y = Add(Multiply(y, x), LogP1);
+ y = Add(Multiply(y, x), LogP2);
+ y = Add(Multiply(y, x), LogP3);
+ y = Add(Multiply(y, x), LogP4);
+ y = Add(Multiply(y, x), LogP5);
+ y = Add(Multiply(y, x), LogP6);
+ y = Add(Multiply(y, x), LogP7);
+ y = Add(Multiply(y, x), LogP8);
+ y = Multiply(Multiply(y, x), z);
+ y = Add(y, Multiply(e, LogQ1));
+ y = Subtract(y, Multiply(z, Point5));
+ x = Add(Add(x, y), Multiply(e, LogQ2));
+ return Or(x, invalidMask);
+ }
+
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorPacket.cs b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorPacket.cs
new file mode 100644
index 0000000000..e0c2cb5239
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/HWIntrinsic/X86/PacketTracer/VectorPacket.cs
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Sse;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+using System;
+
+internal class VectorPacket256
+{
+ public Vector256<float> Xs;
+ public Vector256<float> Ys;
+ public Vector256<float> Zs;
+ public Vector256<float> Lengths
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return Sqrt(DotProduct(this, this));
+ }
+ }
+
+
+ public readonly static int Packet256Size = 8;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256(Vector256<float> init)
+ {
+ Xs = init;
+ Ys = init;
+ Zs = init;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256(float xs, float ys, float zs)
+ {
+ Xs = SetAllVector256(xs);
+ Ys = SetAllVector256(ys);
+ Zs = SetAllVector256(zs);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256(Vector256<float> _Xs, Vector256<float> _ys, Vector256<float> _Zs)
+ {
+ Xs = _Xs;
+ Ys = _ys;
+ Zs = _Zs;
+ }
+
+ // Convert AoS vectors to SoA Packet256
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe VectorPacket256(float* vectors)
+ {
+ Vector256<float> m03 = ExtendToVector256<float>(LoadVector128(&vectors[0])); // load lower halves
+ Vector256<float> m14 = ExtendToVector256<float>(LoadVector128(&vectors[4]));
+ Vector256<float> m25 = ExtendToVector256<float>(LoadVector128(&vectors[8]));
+ m03 = InsertVector128(m03, &vectors[12], 1); // load higher halves
+ m14 = InsertVector128(m14, &vectors[16], 1);
+ m25 = InsertVector128(m25, &vectors[20], 1);
+
+ var xy = Shuffle(m14, m25, 2 << 6 | 1 << 4 | 3 << 2 | 2);
+ var yz = Shuffle(m03, m14, 1 << 6 | 0 << 4 | 2 << 2 | 1);
+ var _Xs = Shuffle(m03, xy, 2 << 6 | 0 << 4 | 3 << 2 | 0);
+ var _ys = Shuffle(yz, xy, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+ var _Zs = Shuffle(yz, m25, 3 << 6 | 0 << 4 | 3 << 2 | 1);
+
+ Xs = _Xs;
+ Ys = _ys;
+ Zs = _Zs;
+ }
+
+ // Convert SoA VectorPacket256 to AoS
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 Transpose()
+ {
+ var rxy = Shuffle(Xs, Ys, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var ryz = Shuffle(Ys, Zs, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+ var rzx = Shuffle(Zs, Xs, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+
+ var r03 = Shuffle(rxy, rzx, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var r14 = Shuffle(ryz, rxy, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+ var r25 = Shuffle(rzx, ryz, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+
+ var m0 = GetLowerHalf<float>(r03);
+ var m1 = GetLowerHalf<float>(r14);
+ var m2 = GetLowerHalf<float>(r25);
+ var m3 = ExtractVector128(r03, 1);
+ var m4 = ExtractVector128(r14, 1);
+ var m5 = ExtractVector128(r25, 1);
+
+ var _Xs = SetHighLow(m1, m0);
+ var _ys = SetHighLow(m3, m2);
+ var _Zs = SetHighLow(m5, m4);
+
+ return new VectorPacket256(_Xs, _ys, _Zs);
+ }
+
+ // Convert SoA VectorPacket256 to an incomplete AoS
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 FastTranspose()
+ {
+ var rxy = Shuffle(Xs, Ys, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var ryz = Shuffle(Ys, Zs, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+ var rzx = Shuffle(Zs, Xs, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+
+ var r03 = Shuffle(rxy, rzx, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var r14 = Shuffle(ryz, rxy, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+ var r25 = Shuffle(rzx, ryz, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+
+ return new VectorPacket256(r03, r14, r25);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator +(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Add(left.Xs, right.Xs), Add(left.Ys, right.Ys), Add(left.Zs, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator -(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Subtract(left.Xs, right.Xs), Subtract(left.Ys, right.Ys), Subtract(left.Zs, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator /(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Divide(left.Xs, right.Xs), Divide(left.Ys, right.Ys), Divide(left.Zs, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256<float> DotProduct(VectorPacket256 left, VectorPacket256 right)
+ {
+ var x2 = Multiply(left.Xs, right.Xs);
+ var y2 = Multiply(left.Ys, right.Ys);
+ var z2 = Multiply(left.Zs, right.Zs);
+ return Add(Add(x2, y2), z2);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 CrossProduct(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Subtract(Multiply(left.Ys, right.Zs), Multiply(left.Zs, right.Ys)),
+ Subtract(Multiply(left.Zs, right.Xs), Multiply(left.Xs, right.Zs)),
+ Subtract(Multiply(left.Xs, right.Ys), Multiply(left.Ys, right.Xs)));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator *(Vector256<float> left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Multiply(left, right.Xs), Multiply(left, right.Ys), Multiply(left, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 Normalize()
+ {
+ var length = this.Lengths;
+ return new VectorPacket256(Divide(Xs, length), Divide(Ys, length), Divide(Zs, length));
+ }
+}