* [simd] Rename SimdIntrinsc->SimdIntrinsic.
* [ji] Add beginnings of support for the SIMD types in the System.Numerics assembly.
Add intrinsics for the methods marked [JitIntrinsic] in the System.Numerics.Vector2 class. Generalize some code in simd-intrinsic.c
so it works both with System.Numerics and Mono.Simd types.
* [jit] Add support for System.Numerics.Vector4.
* [jit] Add support for System.Numerics.Vector3.
* [jit] Add tests for the JIT intrinsics in System.Numerics.Vectors.
* [jit] Implement System.Numerics.Vector.IsHardwareAccelerated intrinsics.
* [jit] Fix the implementation of System.Numerics.Vector.IsHardwareAccelerated, it should return true.
* [jit] Implement some support for the SIMD intrinsics in System.Numerics.Vector<T>.
* [jit] Disable the usage of the Vector SIMD intrinsics when using r4fp until support for it is implemented.
* [jit] Fix llvm support for the Vector<T> intrinsics.
* [jit] Disable the Vector<T> tests since they don't compile yet.
* [jit] Add an optimization for the typeof(T)==typeof(<concrete type>) construct common in some generics code.
* [simd] Only return true from IsHardwareAccelerated () if simd_supported_versions is non-zero.
* [simd] Add support for add/sub/mul/div operations on Vector<T>.
real_size = field_offsets [i] + size;
}
+ /* Make SIMD types as big as a SIMD register since they can be stored into using simd stores */
+ if (klass->simd_type)
+ real_size = MAX (real_size, sizeof (MonoObject) + 16);
instance_size = MAX (real_size, instance_size);
if (instance_size & (min_align - 1)) {
if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
if (!strncmp (name, "Vector", 6))
klass->simd_type = !strcmp (name + 6, "2d") || !strcmp (name + 6, "2ul") || !strcmp (name + 6, "2l") || !strcmp (name + 6, "4f") || !strcmp (name + 6, "4ui") || !strcmp (name + 6, "4i") || !strcmp (name + 6, "8s") || !strcmp (name + 6, "8us") || !strcmp (name + 6, "16b") || !strcmp (name + 6, "16sb");
+ } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
+ if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
+ klass->simd_type = 1;
+ } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (nspace, "System.Numerics")) {
+ if (!strcmp (name, "Vector`1"))
+ klass->simd_type = 1;
}
mono_loader_unlock ();
klass->this_arg.byref = TRUE;
klass->enumtype = gklass->enumtype;
klass->valuetype = gklass->valuetype;
+ klass->simd_type = gklass->simd_type;
klass->cast_class = klass->element_class = klass;
generics.cs \
generics-variant-types.il\
basic-simd.cs \
+ basic-vectors.cs \
aot-tests.cs \
gc-test.cs \
gshared.cs
-regtests_UNIVERSAL=basic.exe basic-float.exe basic-long.exe basic-calls.exe objects.exe arrays.exe basic-math.exe exceptions.exe iltests.exe devirtualization.exe generics.exe basic-simd.exe
+regtests_UNIVERSAL=basic.exe basic-float.exe basic-long.exe basic-calls.exe objects.exe arrays.exe basic-math.exe exceptions.exe iltests.exe devirtualization.exe generics.exe basic-simd.exe basic-vectors.exe
if INSTALL_MOBILE_STATIC
regtests= \
basic-simd.exe: basic-simd.cs TestDriver.dll
$(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:$(CLASS)/Mono.Simd.dll
+basic-vectors.exe: basic-vectors.cs TestDriver.dll
+ $(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:$(CLASS)/System.Numerics.dll
+
nacl.exe: nacl.cs TestDriver.dll
$(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:$(CLASS)/Mono.Simd.dll
--- /dev/null
+using System;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+/*
+ * Tests for the SIMD intrinsics in the System.Numerics.Vectors assembly.
+ */
+public class VectorTests {
+
+#if !MOBILE
+ public static int Main (string[] args) {
+ return TestDriver.RunTests (typeof (VectorTests), args);
+ }
+#endif
+
+ //
+ // Vector2 tests
+ //
+
+ public static int test_0_vector2_ctor_1 () {
+ var v = new Vector2 (1.0f);
+
+ if (v.X != 1.0f)
+ return 1;
+ if (v.Y != 1.0f)
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_vector2_ctor_2 () {
+ var v = new Vector2 (1.0f, 2.0f);
+
+ if (v.X != 1.0f)
+ return 1;
+ if (v.Y != 2.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static bool vector2_equals (Vector2 v1, Vector2 v2) {
+ // cmpeqps+pmovmskb
+ return v1.Equals (v2);
+ }
+
+ public static int test_0_vector2_equals () {
+ var v1 = new Vector2 (1.0f, 2.0f);
+ var v2 = new Vector2 (2.0f, 2.0f);
+
+ if (vector2_equals (v1, v2))
+ return 1;
+ if (!vector2_equals (v1, v1))
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static float vector2_dot (Vector2 v1, Vector2 v2) {
+ return Vector2.Dot (v1, v2);
+ }
+
+ public static int test_0_vector2_dot () {
+ var v1 = new Vector2 (1.0f, 1.0f);
+ var v2 = new Vector2 (2.0f, 2.0f);
+
+ float f = vector2_dot (v1, v2);
+ if (f != 4.0f)
+ return 1;
+ f = vector2_dot (v1, v1);
+ if (f != 2.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_min (Vector2 v1, Vector2 v2) {
+ return Vector2.Min (v1, v2);
+ }
+
+ public static int test_0_vector2_min () {
+ var v1 = new Vector2 (1.0f, 1.0f);
+ var v2 = new Vector2 (2.0f, 2.0f);
+
+ var v3 = vector2_min (v1, v2);
+ if (v3.X != 1.0f || v3.Y != 1.0f)
+ return 1;
+ v3 = vector2_min (v2, v2);
+ if (v3.X != 2.0f || v3.Y != 2.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_max (Vector2 v1, Vector2 v2) {
+ return Vector2.Max (v1, v2);
+ }
+
+ public static int test_0_vector2_max () {
+ var v1 = new Vector2 (1.0f, 1.0f);
+ var v2 = new Vector2 (2.0f, 2.0f);
+
+ var v3 = vector2_max (v1, v2);
+ if (v3.X != 2.0f || v3.Y != 2.0f)
+ return 1;
+ v3 = vector2_min (v1, v1);
+ if (v3.X != 1.0f || v3.Y != 1.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_abs (Vector2 v1) {
+ return Vector2.Abs (v1);
+ }
+
+ public static int test_0_vector2_abs () {
+ var v1 = new Vector2 (-1.0f, -2.0f);
+ var v2 = new Vector2 (1.0f, 2.0f);
+
+ var v3 = vector2_abs (v1);
+ if (v3.X != 1.0f || v3.Y != 2.0f)
+ return 1;
+ v3 = vector2_abs (v2);
+ if (v3.X != 1.0f || v3.Y != 2.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_sqrt (Vector2 v1) {
+ return Vector2.SquareRoot (v1);
+ }
+
+ public static int test_0_vector2_sqrt () {
+ var v1 = new Vector2 (1.0f, 0.0f);
+
+ var v3 = vector2_sqrt (v1);
+ if (v3.X != 1.0f || v3.Y != 0.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_add (Vector2 v1, Vector2 v2) {
+ return v1 + v2;
+ }
+
+ public static int test_0_vector2_add () {
+ var v1 = new Vector2 (1.0f, 2.0f);
+ var v2 = new Vector2 (3.0f, 4.0f);
+
+ var v3 = vector2_add (v1, v2);
+ if (v3.X != 4.0f || v3.Y != 6.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_sub (Vector2 v1, Vector2 v2) {
+ return v1 - v2;
+ }
+
+ public static int test_0_vector2_sub () {
+ var v1 = new Vector2 (1.0f, 2.0f);
+ var v2 = new Vector2 (3.0f, 5.0f);
+
+ var v3 = vector2_sub (v2, v1);
+ if (v3.X != 2.0f || v3.Y != 3.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_mul (Vector2 v1, Vector2 v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector2_mul () {
+ var v1 = new Vector2 (1.0f, 2.0f);
+ var v2 = new Vector2 (3.0f, 5.0f);
+
+ var v3 = vector2_mul (v2, v1);
+ if (v3.X != 3.0f || v3.Y != 10.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_mul_left (float v1, Vector2 v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector2_mul_left () {
+ var v1 = new Vector2 (3.0f, 5.0f);
+
+ var v3 = vector2_mul_left (2.0f, v1);
+ if (v3.X != 6.0f || v3.Y != 10.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_mul_right (Vector2 v1, float v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector2_mul_right () {
+ var v1 = new Vector2 (3.0f, 5.0f);
+
+ var v3 = vector2_mul_right (v1, 2.0f);
+ if (v3.X != 6.0f || v3.Y != 10.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_div (Vector2 v1, Vector2 v2) {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector2_div () {
+ var v1 = new Vector2 (9.0f, 10.0f);
+ var v2 = new Vector2 (3.0f, 5.0f);
+
+ var v3 = vector2_div (v1, v2);
+ if (v3.X != 3.0f || v3.Y != 2.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector2 vector2_div_right (Vector2 v1, float v2) {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector2_div_right () {
+ var v1 = new Vector2 (9.0f, 15.0f);
+
+ var v3 = vector2_div_right (v1, 3.0f);
+ if (v3.X != 3.0f || v3.Y != 5.0f)
+ return 1;
+ return 0;
+ }
+
+ //
+ // Vector4 tests
+ //
+
+ public static int test_0_vector4_ctor_1 () {
+ var v = new Vector4 (1.0f);
+
+ if (v.X != 1.0f)
+ return 1;
+ if (v.Y != 1.0f)
+ return 2;
+ if (v.Z != 1.0f)
+ return 3;
+ if (v.W != 1.0f)
+ return 4;
+ return 0;
+ }
+
+ public static int test_0_vector4_ctor_2 () {
+ var v = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+
+ if (v.X != 1.0f)
+ return 1;
+ if (v.Y != 2.0f)
+ return 2;
+ if (v.Z != 3.0f)
+ return 3;
+ if (v.W != 4.0f)
+ return 4;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static bool vector4_equals (Vector4 v1, Vector4 v2) {
+ // cmpeqps+pmovmskb
+ return v1.Equals (v2);
+ }
+
+ public static int test_0_vector4_equals () {
+ var v1 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+ var v2 = new Vector4 (2.0f, 2.0f, 2.0f, 2.0f);
+
+ if (vector4_equals (v1, v2))
+ return 1;
+ if (!vector4_equals (v1, v1))
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static float vector4_dot (Vector4 v1, Vector4 v2) {
+ return Vector4.Dot (v1, v2);
+ }
+
+ public static int test_0_vector4_dot () {
+ var v1 = new Vector4 (1.0f, 1.0f, 1.0f, 1.0f);
+ var v2 = new Vector4 (2.0f, 2.0f, 2.0f, 2.0f);
+
+ float f = vector4_dot (v1, v2);
+ if (f != 8.0f)
+ return 1;
+ f = vector4_dot (v1, v1);
+ if (f != 4.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_min (Vector4 v1, Vector4 v2) {
+ return Vector4.Min (v1, v2);
+ }
+
+ public static int test_0_vector4_min () {
+ var v1 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+ var v2 = new Vector4 (5.0f, 6.0f, 7.0f, 8.0f);
+
+ var v3 = vector4_min (v1, v2);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f || v3.W != 4.0f)
+ return 1;
+ v3 = vector4_min (v2, v2);
+ if (v3.X != 5.0f || v3.Y != 6.0f || v3.Z != 7.0f || v3.W != 8.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_max (Vector4 v1, Vector4 v2) {
+ return Vector4.Max (v1, v2);
+ }
+
+ public static int test_0_vector4_max () {
+ var v1 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+ var v2 = new Vector4 (5.0f, 6.0f, 7.0f, 8.0f);
+
+ var v3 = vector4_max (v1, v2);
+ if (v3.X != 5.0f || v3.Y != 6.0f || v3.Z != 7.0f || v3.W != 8.0f)
+ return 1;
+ v3 = vector4_max (v1, v1);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f || v3.W != 4.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_abs (Vector4 v1) {
+ return Vector4.Abs (v1);
+ }
+
+ public static int test_0_vector4_abs () {
+ var v1 = new Vector4 (-1.0f, -2.0f, -3.0f, -4.0f);
+ var v2 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+
+ var v3 = vector4_abs (v1);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f || v3.W != 4.0f)
+ return 1;
+ v3 = vector4_abs (v2);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f || v3.W != 4.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_sqrt (Vector4 v1) {
+ return Vector4.SquareRoot (v1);
+ }
+
+ public static int test_0_vector4_sqrt () {
+ var v1 = new Vector4 (1.0f, 0.0f, 1.0f, 0.0f);
+
+ var v3 = vector4_sqrt (v1);
+ if (v3.X != 1.0f || v3.Y != 0.0f || v3.Z != 1.0f || v3.W != 0.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_add (Vector4 v1, Vector4 v2) {
+ return v1 + v2;
+ }
+
+ public static int test_0_vector4_add () {
+ var v1 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+ var v2 = new Vector4 (5.0f, 6.0f, 7.0f, 8.0f);
+
+ var v3 = vector4_add (v1, v2);
+ if (v3.X != 6.0f || v3.Y != 8.0f || v3.Z != 10.0f || v3.W != 12.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_sub (Vector4 v1, Vector4 v2) {
+ return v1 - v2;
+ }
+
+ public static int test_0_vector4_sub () {
+ var v1 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+ var v2 = new Vector4 (3.0f, 5.0f, 7.0f, 9.0f);
+
+ var v3 = vector4_sub (v2, v1);
+ if (v3.X != 2.0f || v3.Y != 3.0f || v3.Z != 4.0f || v3.W != 5.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_mul (Vector4 v1, Vector4 v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector4_mul () {
+ var v1 = new Vector4 (1.0f, 2.0f, 3.0f, 4.0f);
+ var v2 = new Vector4 (3.0f, 5.0f, 6.0f, 7.0f);
+
+ var v3 = vector4_mul (v2, v1);
+ if (v3.X != 3.0f || v3.Y != 10.0f || v3.Z != 18.0f || v3.W != 28.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_mul_left (float v1, Vector4 v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector4_mul_left () {
+ var v1 = new Vector4 (3.0f, 5.0f, 6.0f, 7.0f);
+
+ var v3 = vector4_mul_left (2.0f, v1);
+ if (v3.X != 6.0f || v3.Y != 10.0f || v3.Z != 12.0f || v3.W != 14.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_mul_right (Vector4 v1, float v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector4_mul_right () {
+ var v1 = new Vector4 (3.0f, 5.0f, 6.0f, 7.0f);
+
+ var v3 = vector4_mul_right (v1, 2.0f);
+ if (v3.X != 6.0f || v3.Y != 10.0f || v3.Z != 12.0f || v3.W != 14.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_div (Vector4 v1, Vector4 v2) {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector4_div () {
+ var v1 = new Vector4 (9.0f, 10.0f, 12.0f, 21.0f);
+ var v2 = new Vector4 (3.0f, 5.0f, 6.0f, 7.0f);
+
+ var v3 = vector4_div (v1, v2);
+ if (v3.X != 3.0f || v3.Y != 2.0f || v3.Z != 2.0f || v3.W != 3.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector4 vector4_div_right (Vector4 v1, float v2) {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector4_div_right () {
+ var v1 = new Vector4 (9.0f, 15.0f, 21.0f, 30.0f);
+
+ var v3 = vector4_div_right (v1, 3.0f);
+ if (v3.X != 3.0f || v3.Y != 5.0f || v3.Z != 7.0f || v3.W != 10.0f)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector4_length () {
+ var v = new Vector4 (2.0f, 2.0f, 2.0f, 2.0f);
+ return v.Length () == 4.0f ? 0 : 1;
+ }
+
+ //
+ // Vector3 tests
+ //
+
+ public static int test_0_vector3_ctor_1 () {
+ var v = new Vector3 (1.0f);
+
+ if (v.X != 1.0f)
+ return 1;
+ if (v.Y != 1.0f)
+ return 2;
+ if (v.Z != 1.0f)
+ return 3;
+ return 0;
+ }
+
+ public static int test_0_vector3_ctor_2 () {
+ var v = new Vector3 (1.0f, 2.0f, 3.0f);
+
+ if (v.X != 1.0f)
+ return 1;
+ if (v.Y != 2.0f)
+ return 2;
+ if (v.Z != 3.0f)
+ return 3;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static bool vector3_equals (Vector3 v1, Vector3 v2) {
+ // cmpeqps+pmovmskb
+ return v1.Equals (v2);
+ }
+
+ public static int test_0_vector3_equals () {
+ var v1 = new Vector3 (1.0f, 2.0f, 3.0f);
+ var v2 = new Vector3 (2.0f, 2.0f, 2.0f);
+
+ if (vector3_equals (v1, v2))
+ return 1;
+ if (!vector3_equals (v1, v1))
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static float vector3_dot (Vector3 v1, Vector3 v2) {
+ return Vector3.Dot (v1, v2);
+ }
+
+ public static int test_0_vector3_dot () {
+ var v1 = new Vector3 (1.0f, 1.0f, 1.0f);
+ var v2 = new Vector3 (2.0f, 2.0f, 2.0f);
+
+ float f = vector3_dot (v1, v2);
+ if (f != 6.0f)
+ return 1;
+ f = vector3_dot (v1, v1);
+ if (f != 3.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_min (Vector3 v1, Vector3 v2) {
+ return Vector3.Min (v1, v2);
+ }
+
+ public static int test_0_vector3_min () {
+ var v1 = new Vector3 (1.0f, 2.0f, 3.0f);
+ var v2 = new Vector3 (5.0f, 6.0f, 7.0f);
+
+ var v3 = vector3_min (v1, v2);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f)
+ return 1;
+ v3 = vector3_min (v2, v2);
+ if (v3.X != 5.0f || v3.Y != 6.0f || v3.Z != 7.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_max (Vector3 v1, Vector3 v2) {
+ return Vector3.Max (v1, v2);
+ }
+
+ public static int test_0_vector3_max () {
+ var v1 = new Vector3 (1.0f, 2.0f, 3.0f);
+ var v2 = new Vector3 (5.0f, 6.0f, 7.0f);
+
+ var v3 = vector3_max (v1, v2);
+ if (v3.X != 5.0f || v3.Y != 6.0f || v3.Z != 7.0f)
+ return 1;
+ v3 = vector3_max (v1, v1);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_abs (Vector3 v1) {
+ return Vector3.Abs (v1);
+ }
+
+ public static int test_0_vector3_abs () {
+ var v1 = new Vector3 (-1.0f, -2.0f, -3.0f);
+ var v2 = new Vector3 (1.0f, 2.0f, 3.0f);
+
+ var v3 = vector3_abs (v1);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f)
+ return 1;
+ v3 = vector3_abs (v2);
+ if (v3.X != 1.0f || v3.Y != 2.0f || v3.Z != 3.0f)
+ return 2;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_sqrt (Vector3 v1) {
+ return Vector3.SquareRoot (v1);
+ }
+
+ public static int test_0_vector3_sqrt () {
+ var v1 = new Vector3 (1.0f, 0.0f, 1.0f);
+
+ var v3 = vector3_sqrt (v1);
+ if (v3.X != 1.0f || v3.Y != 0.0f || v3.Z != 1.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_add (Vector3 v1, Vector3 v2) {
+ return v1 + v2;
+ }
+
+ public static int test_0_vector3_add () {
+ var v1 = new Vector3 (1.0f, 2.0f, 3.0f);
+ var v2 = new Vector3 (5.0f, 6.0f, 7.0f);
+
+ var v3 = vector3_add (v1, v2);
+ if (v3.X != 6.0f || v3.Y != 8.0f || v3.Z != 10.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_sub (Vector3 v1, Vector3 v2) {
+ return v1 - v2;
+ }
+
+ public static int test_0_vector3_sub () {
+ var v1 = new Vector3 (1.0f, 2.0f, 3.0f);
+ var v2 = new Vector3 (3.0f, 5.0f, 7.0f);
+
+ var v3 = vector3_sub (v2, v1);
+ if (v3.X != 2.0f || v3.Y != 3.0f || v3.Z != 4.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_mul (Vector3 v1, Vector3 v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector3_mul () {
+ var v1 = new Vector3 (1.0f, 2.0f, 3.0f);
+ var v2 = new Vector3 (3.0f, 5.0f, 6.0f);
+
+ var v3 = vector3_mul (v2, v1);
+ if (v3.X != 3.0f || v3.Y != 10.0f || v3.Z != 18.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_mul_left (float v1, Vector3 v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector3_mul_left () {
+ var v1 = new Vector3 (3.0f, 5.0f, 6.0f);
+
+ var v3 = vector3_mul_left (2.0f, v1);
+ if (v3.X != 6.0f || v3.Y != 10.0f || v3.Z != 12.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_mul_right (Vector3 v1, float v2) {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector3_mul_right () {
+ var v1 = new Vector3 (3.0f, 5.0f, 6.0f);
+
+ var v3 = vector3_mul_right (v1, 2.0f);
+ if (v3.X != 6.0f || v3.Y != 10.0f || v3.Z != 12.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_div (Vector3 v1, Vector3 v2) {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector3_div () {
+ var v1 = new Vector3 (9.0f, 10.0f, 12.0f);
+ var v2 = new Vector3 (3.0f, 5.0f, 6.0f);
+
+ var v3 = vector3_div (v1, v2);
+ if (v3.X != 3.0f || v3.Y != 2.0f || v3.Z != 2.0f)
+ return 1;
+ return 0;
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector3 vector3_div_right (Vector3 v1, float v2) {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector3_div_right () {
+ var v1 = new Vector3 (9.0f, 15.0f, 21.0f);
+
+ var v3 = vector3_div_right (v1, 3.0f);
+ if (v3.X != 3.0f || v3.Y != 5.0f || v3.Z != 7.0f)
+ return 1;
+ return 0;
+ }
+
+#if FALSE
+ //
+ // Vector<T>
+ //
+
+ public static int test_0_vector_t_count () {
+ // This assumes a 16 byte simd register size
+ if (Vector<byte>.Count != 16)
+ return 1;
+ if (Vector<short>.Count != 8)
+ return 2;
+ if (Vector<int>.Count != 4)
+ return 3;
+ if (Vector<long>.Count != 2)
+ return 4;
+ return 0;
+ }
+
+ public static int test_0_vector_t_zero () {
+ var v = Vector<byte>.Zero;
+ for (int i = 0; i < Vector<byte>.Count; ++i)
+ if (v [i] != 0)
+ return 1;
+ var v2 = Vector<double>.Zero;
+ for (int i = 0; i < Vector<double>.Count; ++i)
+ if (v2 [i] != 0.0)
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i1_accessor () {
+ var elems = new byte [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ var v = new Vector<byte> (elems, 0);
+ for (int i = 0; i < Vector<byte>.Count; ++i)
+ if (v [i] != i + 1)
+ return 1;
+ if (v [0] != 1)
+ return 2;
+ if (v [1] != 2)
+ return 2;
+ if (v [15] != 16)
+ return 2;
+ try {
+ int r = v [-1];
+ return 3;
+ } catch (IndexOutOfRangeException) {
+ }
+ try {
+ int r = v [16];
+ return 4;
+ } catch (IndexOutOfRangeException) {
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i4_accessor () {
+ var elems = new int [] { 1, 2, 3, 4 };
+ var v = new Vector<int> (elems, 0);
+ for (int i = 0; i < Vector<int>.Count; ++i)
+ if (v [i] != i + 1)
+ return 1;
+ if (v [0] != 1)
+ return 2;
+ if (v [1] != 2)
+ return 2;
+ if (v [3] != 4)
+ return 2;
+ try {
+ int r = v [-1];
+ return 3;
+ } catch (IndexOutOfRangeException) {
+ }
+ try {
+ int r = v [Vector<int>.Count];
+ return 4;
+ } catch (IndexOutOfRangeException) {
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i8_accessor () {
+ var elems = new long [] { 1, 2 };
+ var v = new Vector<long> (elems, 0);
+ for (int i = 0; i < Vector<long>.Count; ++i)
+ if (v [i] != i + 1)
+ return 1;
+ if (v [0] != 1)
+ return 2;
+ if (v [1] != 2)
+ return 2;
+ try {
+ var r = v [-1];
+ return 3;
+ } catch (IndexOutOfRangeException) {
+ }
+ try {
+ var r = v [Vector<long>.Count];
+ return 4;
+ } catch (IndexOutOfRangeException) {
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_r8_accessor () {
+ var elems = new double [] { 1.0, 2.0 };
+ var v = new Vector<double> (elems, 0);
+ for (int i = 0; i < Vector<double>.Count; ++i)
+ if (v [i] != (double)i + 1.0)
+ return 1;
+ if (v [0] != 1.0)
+ return 2;
+ if (v [1] != 2.0)
+ return 2;
+ try {
+ var r = v [-1];
+ return 3;
+ } catch (IndexOutOfRangeException) {
+ }
+ try {
+ var r = v [Vector<double>.Count];
+ return 4;
+ } catch (IndexOutOfRangeException) {
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i1_ctor_3 () {
+ var v = new Vector<byte> (5);
+ for (int i = 0; i < 16; ++i)
+ if (v [i] != 5)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i2_ctor_3 () {
+ var v = new Vector<short> (5);
+ for (int i = 0; i < 8; ++i)
+ if (v [i] != 5)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i4_ctor_3 () {
+ var v = new Vector<int> (0xffffeee);
+ for (int i = 0; i < 4; ++i)
+ if (v [i] != 0xffffeee)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i8_ctor_3 () {
+ var v = new Vector<long> (0xffffeeeeabcdefL);
+ for (int i = 0; i < 2; ++i)
+ if (v [i] != 0xffffeeeeabcdefL)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_r4_ctor_3 () {
+ var v = new Vector<float> (0.5f);
+ for (int i = 0; i < 4; ++i) {
+ if (v [i] != 0.5f)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_r8_ctor_3 () {
+ var v = new Vector<double> (0.5f);
+ for (int i = 0; i < 2; ++i) {
+ if (v [i] != 0.5f)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i1_ctor () {
+ var elems = new byte [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
+ var v = new Vector<byte> (elems, 16);
+ for (int i = 0; i < 16; ++i)
+ if (v [i] != i)
+ return 1;
+ try {
+ var v2 = new Vector<byte> (elems, 16 + 4);
+ return 2;
+ } catch (IndexOutOfRangeException) {
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i1_ctor_2 () {
+ var elems = new byte [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ var v = new Vector<byte> (elems);
+ for (int i = 0; i < 16; ++i)
+ if (v [i] != i + 1)
+ return 1;
+ try {
+ var elems2 = new byte [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+ var v2 = new Vector<byte> (elems2);
+ return 2;
+ } catch (IndexOutOfRangeException) {
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_r4_equal () {
+ var elems1 = new float [4] { 1.0f, 1.0f, 1.0f, 1.0f };
+ var v1 = new Vector<float> (elems1);
+ var elems2 = new float [4] { 1.0f, 2.0f, 1.0f, 2.0f };
+ var v2 = new Vector<float> (elems2);
+ Vector<int> v = Vector.Equals (v1, v2);
+ if (v [0] != -1 || v [1] != 0 || v [2] != -1 || v [3] != 0)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_r8_equal () {
+ var elems1 = new double [] { 1.0f, 1.0f };
+ var v1 = new Vector<double> (elems1);
+ var elems2 = new double [] { 1.0f, 2.0f };
+ var v2 = new Vector<double> (elems2);
+ Vector<long> v = Vector.Equals (v1, v2);
+ if (v [0] != -1 || v [1] != 0)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i8_equal () {
+ var elems1 = new long [] { 1, 1 };
+ var v1 = new Vector<long> (elems1);
+ var elems2 = new long [] { 1, 2 };
+ var v2 = new Vector<long> (elems2);
+ Vector<long> v = Vector.Equals (v1, v2);
+ if (v [0] != -1 || v [1] != 0)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i4_equal () {
+ var elems1 = new int [] { 1, 1, 1, 1 };
+ var v1 = new Vector<int> (elems1);
+ var elems2 = new int [] { 1, 2, 1, 2 };
+ var v2 = new Vector<int> (elems2);
+ Vector<int> v = Vector.Equals (v1, v2);
+ if (v [0] != -1 || v [1] != 0 || v [2] != -1 || v[3] != 0)
+ return 1;
+ return 0;
+ }
+
+ /*
+ public static int test_0_vector_t_u4_equal () {
+ var elems1 = new uint [] { 1, 1, 1, 1 };
+ var v1 = new Vector<uint> (elems1);
+ var elems2 = new uint [] { 1, 2, 1, 2 };
+ var v2 = new Vector<uint> (elems2);
+ Vector<uint> v = Vector.Equals (v1, v2);
+ if (v [0] != 0xffffffff || v [1] != 0 || v [2] != 0xffffffff || v[3] != 0)
+ return 1;
+ return 0;
+ }
+ */
+
+ public static int test_0_vector_t_i2_equal () {
+ var elems1 = new short [] { 1, 1, 1, 1, 1, 1, 1, 1 };
+ var v1 = new Vector<short> (elems1);
+ var elems2 = new short [] { 1, 2, 1, 2, 1, 2, 1, 2 };
+ var v2 = new Vector<short> (elems2);
+ Vector<short> v = Vector.Equals (v1, v2);
+ for (int i = 0; i < Vector<short>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_u2_equal () {
+ var elems1 = new ushort [] { 1, 1, 1, 1, 1, 1, 1, 1 };
+ var v1 = new Vector<ushort> (elems1);
+ var elems2 = new ushort [] { 1, 2, 1, 2, 1, 2, 1, 2 };
+ var v2 = new Vector<ushort> (elems2);
+ Vector<ushort> v = Vector.Equals (v1, v2);
+ for (int i = 0; i < Vector<ushort>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != 0xffff)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i1_equal () {
+ var elems1 = new sbyte [] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ var v1 = new Vector<sbyte> (elems1);
+ var elems2 = new sbyte [] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
+ var v2 = new Vector<sbyte> (elems2);
+ Vector<sbyte> v = Vector.Equals (v1, v2);
+ for (int i = 0; i < Vector<sbyte>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_u1_equal () {
+ var elems1 = new byte [] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ var v1 = new Vector<byte> (elems1);
+ var elems2 = new byte [] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
+ var v2 = new Vector<byte> (elems2);
+ Vector<byte> v = Vector.Equals (v1, v2);
+ for (int i = 0; i < Vector<byte>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != 0xff)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ /* op_Explicit () -> Vector<int32> */
+
+ public static int test_0_vector_t_cast_vector_int32 () {
+ var v1 = new Vector<long> (new long [] { 0x123456789abcdef0L, 0x23456789abcdef01L });
+ var v = (Vector<int>)v1;
+ if ((uint)v [0] != 0x9abcdef0 || (uint)v [1] != 0x12345678)
+ return 1;
+ if ((uint)v [2] != 0xabcdef01 || (uint)v [3] != 0x23456789)
+ return 2;
+ return 0;
+ }
+
+ /* Vector.GreaterThanOrEqual */
+
+ public static int test_0_vector_t_i1_ge () {
+ var elems1 = new sbyte [] { 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1 };
+ var v1 = new Vector<sbyte> (elems1);
+ var elems2 = new sbyte [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v2 = new Vector<sbyte> (elems2);
+ Vector<sbyte> v = Vector.GreaterThanOrEqual (v1, v2);
+ for (int i = 0; i < Vector<sbyte>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i2_ge () {
+ var elems1 = new short [] { 1, 1, 0, 1, 1, 1, 0, 1 };
+ var v1 = new Vector<short> (elems1);
+ var elems2 = new short [] { 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v2 = new Vector<short> (elems2);
+ Vector<short> v = Vector.GreaterThanOrEqual (v1, v2);
+ for (int i = 0; i < Vector<short>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ public static int test_0_vector_t_i4_ge () {
+ var elems1 = new int [] { 1, 1, 0, 1 };
+ var v1 = new Vector<int> (elems1);
+ var elems2 = new int [] { 0, 2, 0, 2 };
+ var v2 = new Vector<int> (elems2);
+ Vector<int> v = Vector.GreaterThanOrEqual (v1, v2);
+ if (v [0] != -1 || v [1] != 0 || v [2] != -1 || v[3] != 0)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i8_ge () {
+ var elems1 = new long [] { 1, 1 };
+ var v1 = new Vector<long> (elems1);
+ var elems2 = new long [] { 0, 1 };
+ var v2 = new Vector<long> (elems2);
+ Vector<long> v = Vector.GreaterThanOrEqual (v1, v2);
+ if (v [0] != -1 || v [1] != -1)
+ return 1;
+ return 0;
+ }
+
+ /* Vector.LessThan */
+
+ public static int test_0_vector_t_i1_lt () {
+ var elems1 = new sbyte [] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ var v1 = new Vector<sbyte> (elems1);
+ var elems2 = new sbyte [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v2 = new Vector<sbyte> (elems2);
+ Vector<sbyte> v = Vector.LessThan (v2, v1);
+ for (int i = 0; i < Vector<sbyte>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Vector.GreaterThan */
+
+ public static int test_0_vector_t_i1_gt () {
+ var elems1 = new sbyte [] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ var v1 = new Vector<sbyte> (elems1);
+ var elems2 = new sbyte [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v2 = new Vector<sbyte> (elems2);
+ Vector<sbyte> v = Vector.GreaterThan (v1, v2);
+ for (int i = 0; i < Vector<sbyte>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Vector.LessThanOrEqual */
+ public static int test_0_vector_t_i1_le () {
+ var elems1 = new sbyte [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v1 = new Vector<sbyte> (elems1);
+ var elems2 = new sbyte [] { 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1 };
+ var v2 = new Vector<sbyte> (elems2);
+ Vector<sbyte> v = Vector.LessThanOrEqual (v1, v2);
+ for (int i = 0; i < Vector<sbyte>.Count; ++i) {
+ if (i % 2 == 0 && v [i] != -1)
+ return 1;
+ if (i % 2 == 1 && v [i] != 0)
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Vector.Abs */
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector<T> vector_t_abs<T> (Vector<T> v1) where T: struct {
+ return Vector.Abs (v1);
+ }
+
+ public static int test_0_vector_t_u1_abs () {
+ var elems1 = new byte [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v1 = new Vector<byte> (elems1);
+
+ if (vector_t_abs (v1) != v1)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_u2_abs () {
+ var elems1 = new ushort [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v1 = new Vector<ushort> (elems1);
+
+ if (vector_t_abs (v1) != v1)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_u4_abs () {
+ var elems1 = new uint [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v1 = new Vector<uint> (elems1);
+
+ if (vector_t_abs (v1) != v1)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_u8_abs () {
+ var elems1 = new ulong [] { 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2 };
+ var v1 = new Vector<ulong> (elems1);
+
+ if (vector_t_abs (v1) != v1)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_t_i1_abs () {
+ var elems1 = new sbyte [] { 1, -2, 1, -2, 1, -2, 1, -2, 1, -2, 1, -2, 1, -2, 1, -2 };
+ var v1 = new Vector<sbyte> (elems1);
+ var elems2 = new sbyte [] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
+ var v2 = new Vector<sbyte> (elems2);
+
+ if (vector_t_abs (v1) != v2)
+ return 1;
+ return 0;
+ }
+
+ // Vector<T>.Add
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector<T> vector_add<T> (Vector<T> v1, Vector<T> v2) where T: struct {
+ return v1 + v2;
+ }
+
+ public static int test_0_vector_byte_add () {
+ var v1 = new Vector<byte> (new byte[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 });
+ var v2 = new Vector<byte> (new byte[] { 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_sbyte_add () {
+ var v1 = new Vector<sbyte> (new sbyte[] { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1 });
+ var v2 = new Vector<sbyte> (new sbyte[] { 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, -2 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_ushort_add () {
+ var v1 = new Vector<ushort> (new ushort[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 });
+ var v2 = new Vector<ushort> (new ushort[] { 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_short_add () {
+ var v1 = new Vector<short> (new short[] { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1 });
+ var v2 = new Vector<short> (new short[] { 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, -2 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_uint_add () {
+ var v1 = new Vector<uint> (new uint[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 });
+ var v2 = new Vector<uint> (new uint[] { 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_int_add () {
+ var v1 = new Vector<int> (new int[] { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1 });
+ var v2 = new Vector<int> (new int[] { 2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 2, 2, 2, -2, 2, -2 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_double_add () {
+ var v1 = new Vector<double> (new double[] { 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0 });
+ var v2 = new Vector<double> (new double[] { 2.0, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0, 2.0, 2.0, -2.0, 2.0, -2.0 });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_float_add () {
+ var v1 = new Vector<float> (new float[] { 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f });
+ var v2 = new Vector<float> (new float[] { 2.0f, -2.0f, 2.0f, -2.0f, 2.0f, -2.0f, 2.0f, -2.0f, 2.0f, -2.0f, 2.0f, 2.0f, 2.0f, -2.0f, 2.0f, -2.0f });
+
+ var res = vector_add (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ // Vector<T>.op_Subtraction
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector<T> vector_sub<T> (Vector<T> v1, Vector<T> v2) where T: struct {
+ return v1 - v2;
+ }
+
+ public static int test_0_vector_byte_sub () {
+ var v1 = new Vector<byte> (new byte[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 });
+
+ var res = vector_sub (v1, v1);
+ if (res != Vector<byte>.Zero)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_double_sub () {
+ var v1 = new Vector<double> (new double[] { 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0 });
+
+ var res = vector_sub (v1, v1);
+ if (res != Vector<double>.Zero)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_float_sub () {
+ var v1 = new Vector<float> (new float[] { 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f });
+
+ var res = vector_sub (v1, v1);
+ if (res != Vector<float>.Zero)
+ return 1;
+ return 0;
+ }
+
+ // Vector<T>.op_Multiply
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector<T> vector_mul<T> (Vector<T> v1, Vector<T> v2) where T: struct {
+ return v1 * v2;
+ }
+
+ public static int test_0_vector_int_mul () {
+ var v1 = new Vector<int> (new int[] { 1, 2, -1, 2, 1, 2, -1, 2, 1, -2, 1, 2, 1, 2, -1, 2 });
+ var v2 = new Vector<int> (new int[] { 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4 });
+
+ var res = vector_mul (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_double_mul () {
+ var v1 = new Vector<double> (new double[] { 2.0, -1.0, 2.0, -1.0 });
+ var v2 = new Vector<double> (new double[] { 4.0, 1.0, 4.0, 1.0 });
+
+ var res = vector_mul (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_float_mul () {
+ var v1 = new Vector<float> (new float[] { 2.0f, -1.0f, 2.0f, -1.0f });
+ var v2 = new Vector<float> (new float[] { 4.0f, 1.0f, 4.0f, 1.0f });
+
+ var res = vector_mul (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ // Vector<T>.op_Division
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static Vector<T> vector_div<T> (Vector<T> v1, Vector<T> v2) where T: struct {
+ return v1 / v2;
+ }
+
+ public static int test_0_vector_double_div () {
+ var v1 = new Vector<double> (new double[] { 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0 });
+ var v2 = new Vector<double> (new double[] { 1.0, 1.0, 1.0, 1.0 });
+
+ var res = vector_div (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+ public static int test_0_vector_float_div () {
+ var v1 = new Vector<float> (new float[] { 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f });
+ var v2 = new Vector<float> (new float[] { 1.0f, 1.0f, 1.0f, 1.0f });
+
+ var res = vector_div (v1, v1);
+ if (res != v2)
+ return 1;
+ return 0;
+ }
+
+#endif
+
+}
return NULL;
}
}
+ if ((arg1->opcode == OP_PCONST) && (arg2->opcode == OP_PCONST) && ins->next) {
+ MonoInst *next = ins->next;
+
+ if (next->opcode == OP_LCEQ) {
+ gboolean res = arg1->inst_p0 == arg2->inst_p0;
+ if (overwrite) {
+ NULLIFY_INS (ins);
+ next->opcode = OP_ICONST;
+ next->inst_c0 = res;
+ MONO_INST_NULLIFY_SREGS (next);
+ } else {
+ ALLOC_DEST (cfg, dest, ins);
+ dest->opcode = OP_ICONST;
+ dest->inst_c0 = res;
+ }
+ break;
+ }
+ }
break;
}
case OP_FMOVE:
xmove: dest:x src1:x len:5
xzero: dest:x len:5
+xones: dest:x len:5
iconv_to_x: dest:x src1:i len:5
extract_i4: dest:i src1:x len:5
return vreg;
}
+static inline guint32
+alloc_xreg (MonoCompile *cfg)
+{
+ return alloc_ireg (cfg);
+}
+
static inline guint32
alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
{
/* FIXME: Make is_inst_imm a macro */
/* FIXME: Make is_inst_imm take an opcode argument */
/* is_inst_imm is only needed for binops */
- if ((((def->opcode == OP_ICONST) || ((sizeof (gpointer) == 8) && (def->opcode == OP_I8CONST))) &&
+ if ((((def->opcode == OP_ICONST) || ((sizeof (gpointer) == 8) && (def->opcode == OP_I8CONST)) || (def->opcode == OP_PCONST)) &&
(((srcindex == 0) && (ins->sreg2 == -1)) || mono_arch_is_inst_imm (def->inst_c0))) ||
(!MONO_ARCH_USE_FPSTACK && (def->opcode == OP_R8CONST))) {
guint32 opcode2;
/* srcindex == 1 -> binop, ins->sreg2 == -1 -> unop */
- if ((srcindex == 1) && (ins->sreg1 != -1) && defs [ins->sreg1] && (defs [ins->sreg1]->opcode == OP_ICONST) && defs [ins->sreg2]) {
+ if ((srcindex == 1) && (ins->sreg1 != -1) && defs [ins->sreg1] &&
+ ((defs [ins->sreg1]->opcode == OP_ICONST) || defs [ins->sreg1]->opcode == OP_PCONST) &&
+ defs [ins->sreg2]) {
/* Both arguments are constants, perform cfold */
mono_constant_fold_ins (cfg, ins, defs [ins->sreg1], defs [ins->sreg2], TRUE);
} else if ((srcindex == 0) && (ins->sreg2 != -1) && defs [ins->sreg2]) {
dummy_arg1.inst_c0 = 1;
mono_constant_fold_ins (cfg, ins, &dummy_arg1, NULL, TRUE);
+ } else if (srcindex == 0 && ins->opcode == OP_COMPARE && defs [ins->sreg1]->opcode == OP_PCONST && defs [ins->sreg2] && defs [ins->sreg2]->opcode == OP_PCONST) {
+ /* typeof(T) == typeof(..) */
+ mono_constant_fold_ins (cfg, ins, defs [ins->sreg1], defs [ins->sreg2], TRUE);
}
}
return TRUE;
}
-static MonoInst*
+MonoInst*
mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
{
MonoInst *ins;
* all inputs:
* http://everything2.com/?node_id=1051618
*/
+ } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
+ EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
+ MONO_INST_NEW (cfg, ins, OP_PCEQ);
+ ins->dreg = alloc_preg (cfg);
+ ins->type = STACK_I4;
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
} else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
!strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
!strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
}
/* Common call */
- INLINE_FAILURE ("call");
+ if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
+ INLINE_FAILURE ("call");
ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
imt_arg, vtable_arg);
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+ if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
+ ins = mono_emit_simd_field_load (cfg, field, sp [0]);
+ if (ins) {
+ *sp++ = ins;
+ ins_flag = 0;
+ ip += 5;
+ break;
+ }
+ }
+
if (mini_is_gsharedvt_klass (klass)) {
MonoInst *offset_ins;
case OP_XZERO:
amd64_sse_pxor_reg_reg (code, ins->dreg, ins->dreg);
break;
+ case OP_XONES:
+ amd64_sse_pcmpeqb_reg_reg (code, ins->dreg, ins->dreg);
+ break;
case OP_ICONV_TO_R4_RAW:
amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
+ amd64_sse_cvtss2sd_reg_reg (code, ins->dreg, ins->dreg);
break;
case OP_FCONV_TO_R8_X:
ins->sreg1 = last_ins->sreg1;
}
break;
+ case OP_LOADX_MEMBASE:
+ if (last_ins && last_ins->opcode == OP_STOREX_MEMBASE &&
+ ins->inst_basereg == last_ins->inst_destbasereg &&
+ ins->inst_offset == last_ins->inst_offset) {
+ if (ins->dreg == last_ins->sreg1) {
+ MONO_DELETE_INS (bb, ins);
+ break;
+ } else {
+ ins->opcode = OP_XMOVE;
+ ins->sreg1 = last_ins->sreg1;
+ }
+ }
+ break;
case OP_MOVE:
case OP_FMOVE:
/*
return LLVMVectorType (LLVMInt8Type (), 16);
} else if (!strcmp (klass->name, "Vector16b")) {
return LLVMVectorType (LLVMInt8Type (), 16);
+ } else if (!strcmp (klass->name, "Vector2")) {
+ /* System.Numerics */
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector3")) {
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector4")) {
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector`1")) {
+ MonoType *etype = mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ switch (etype->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ return LLVMVectorType (LLVMInt8Type (), 16);
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ return LLVMVectorType (LLVMInt16Type (), 8);
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ return LLVMVectorType (LLVMInt32Type (), 4);
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ return LLVMVectorType (LLVMInt64Type (), 2);
+ case MONO_TYPE_R4:
+ return LLVMVectorType (LLVMFloatType (), 4);
+ case MONO_TYPE_R8:
+ return LLVMVectorType (LLVMDoubleType (), 2);
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
} else {
printf ("%s\n", klass->name);
NOT_IMPLEMENTED;
return "llvm.x86.sse2.pmulh.w";
case OP_PMULW_HIGH_UN:
return "llvm.x86.sse2.pmulhu.w";
+ case OP_DPPS:
+ return "llvm.x86.sse41.dpps";
#endif
default:
g_assert_not_reached ();
break;
}
+ case OP_DPPS: {
+ LLVMValueRef args [3];
+
+ args [0] = lhs;
+ args [1] = rhs;
+ /* 0xf1 == multiply all 4 elements, add them together, and store the result to the lowest element */
+ args [2] = LLVMConstInt (LLVMInt32Type (), 0xf1, FALSE);
+
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+ break;
+ }
+
#endif /* SIMD */
case OP_DUMMY_USE:
INTRINS_SSE_PSUBUSB,
INTRINS_SSE_PAVGB,
INTRINS_SSE_PAUSE,
+ INTRINS_SSE_DPPS,
#endif
INTRINS_NUM
} IntrinsicId;
{INTRINS_SSE_PADDUSB, "llvm.x86.sse2.paddus.b"},
{INTRINS_SSE_PSUBUSB, "llvm.x86.sse2.psubus.b"},
{INTRINS_SSE_PAVGB, "llvm.x86.sse2.pavg.b"},
- {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"}
+ {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"},
+ {INTRINS_SSE_DPPS, "llvm.x86.sse41.dpps"}
#endif
};
case INTRINS_SSE_PAUSE:
AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
break;
+ case INTRINS_SSE_DPPS:
+ ret_type = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [0] = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [1] = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [2] = LLVMInt32Type ();
+ AddFunc (module, name, ret_type, arg_types, 3);
+ break;
#endif
default:
g_assert_not_reached ();
MINI_OP(OP_CVTTPD2DQ, "cvttpd2dq", XREG, XREG, NONE)
MINI_OP(OP_CVTTPS2DQ, "cvttps2dq", XREG, XREG, NONE)
+/* r4 dot product */
+/* multiply all 4 single precision float elements, add them together, and store the result to the lowest element */
+MINI_OP(OP_DPPS, "dpps", XREG, XREG, XREG)
+
#endif
MINI_OP(OP_XMOVE, "xmove", XREG, XREG, NONE)
MINI_OP(OP_XZERO, "xzero", XREG, NONE, NONE)
+MINI_OP(OP_XONES, "xones", XREG, NONE, NONE)
MINI_OP(OP_XPHI, "xphi", XREG, NONE, NONE)
/*
case MONO_TYPE_TYPEDBYREF:
return OP_LOADV_MEMBASE;
case MONO_TYPE_GENERICINST:
+ if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
+ return OP_LOADX_MEMBASE;
if (mono_type_generic_inst_is_valuetype (type))
return OP_LOADV_MEMBASE;
else
/* FIXME: Add more instructions */
/* INEG sets the condition codes, and the OP_LNEG decomposition depends on this on x86 */
-#define MONO_INS_HAS_NO_SIDE_EFFECT(ins) (MONO_IS_MOVE (ins) || (ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || MONO_IS_ZERO (ins) || (ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_R8CONST) || (ins->opcode == OP_LADD_IMM) || (ins->opcode == OP_ISUB_IMM) || (ins->opcode == OP_IADD_IMM) || (ins->opcode == OP_LNEG) || (ins->opcode == OP_ISUB) || (ins->opcode == OP_CMOV_IGE) || (ins->opcode == OP_ISHL_IMM) || (ins->opcode == OP_ISHR_IMM) || (ins->opcode == OP_ISHR_UN_IMM) || (ins->opcode == OP_IAND_IMM) || (ins->opcode == OP_ICONV_TO_U1) || (ins->opcode == OP_ICONV_TO_I1) || (ins->opcode == OP_SEXT_I4) || (ins->opcode == OP_LCONV_TO_U1) || (ins->opcode == OP_ICONV_TO_U2) || (ins->opcode == OP_ICONV_TO_I2) || (ins->opcode == OP_LCONV_TO_I2) || (ins->opcode == OP_LDADDR) || (ins->opcode == OP_PHI) || (ins->opcode == OP_NOP) || (ins->opcode == OP_ZEXT_I4) || (ins->opcode == OP_NOT_NULL) || (ins->opcode == OP_IL_SEQ_POINT))
+#define MONO_INS_HAS_NO_SIDE_EFFECT(ins) (MONO_IS_MOVE (ins) || (ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || MONO_IS_ZERO (ins) || (ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_R8CONST) || (ins->opcode == OP_LADD_IMM) || (ins->opcode == OP_ISUB_IMM) || (ins->opcode == OP_IADD_IMM) || (ins->opcode == OP_LNEG) || (ins->opcode == OP_ISUB) || (ins->opcode == OP_CMOV_IGE) || (ins->opcode == OP_ISHL_IMM) || (ins->opcode == OP_ISHR_IMM) || (ins->opcode == OP_ISHR_UN_IMM) || (ins->opcode == OP_IAND_IMM) || (ins->opcode == OP_ICONV_TO_U1) || (ins->opcode == OP_ICONV_TO_I1) || (ins->opcode == OP_SEXT_I4) || (ins->opcode == OP_LCONV_TO_U1) || (ins->opcode == OP_ICONV_TO_U2) || (ins->opcode == OP_ICONV_TO_I2) || (ins->opcode == OP_LCONV_TO_I2) || (ins->opcode == OP_LDADDR) || (ins->opcode == OP_PHI) || (ins->opcode == OP_NOP) || (ins->opcode == OP_ZEXT_I4) || (ins->opcode == OP_NOT_NULL) || (ins->opcode == OP_IL_SEQ_POINT) || (ins->opcode == OP_XZERO))
#define MONO_INS_IS_PCONST_NULL(ins) ((ins)->opcode == OP_PCONST && (ins)->inst_p0 == 0)
void mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align);
void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
+MonoInst* mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck);
CompRelation mono_opcode_to_cond (int opcode) MONO_LLVM_INTERNAL;
CompType mono_opcode_to_type (int opcode, int cmp_opcode);
CompRelation mono_negate_cond (CompRelation cond);
const char *mono_arch_xregname (int reg);
void mono_simd_simplify_indirection (MonoCompile *cfg);
MonoInst* mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
+MonoInst* mono_emit_simd_field_load (MonoCompile *cfg, MonoClassField *field, MonoInst *addr);
guint32 mono_arch_cpu_enumerate_simd_versions (void);
void mono_simd_intrinsics_init (void);
guint8 simd_version_flags;
guint8 simd_emit_mode : 4;
guint8 flags : 4;
-} SimdIntrinsc;
+} SimdIntrinsic;
-static const SimdIntrinsc vector4f_intrinsics[] = {
+static const SimdIntrinsic vector4f_intrinsics[] = {
{ SN_ctor, OP_EXPAND_R4, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_AddSub, OP_ADDSUBPS, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY},
{ SN_AndNot, OP_ANDNPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY},
{ SN_set_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }
};
-static const SimdIntrinsc vector2d_intrinsics[] = {
+static const SimdIntrinsic vector2d_intrinsics[] = {
{ SN_ctor, OP_EXPAND_R8, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_AddSub, OP_ADDSUBPD, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY,},
{ SN_AndNot, OP_ANDNPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector2ul_intrinsics[] = {
+static const SimdIntrinsic vector2ul_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I8, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_CompareEqual, OP_PCMPEQQ, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY },
{ SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED },
{ SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector2l_intrinsics[] = {
+static const SimdIntrinsic vector2l_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I8, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_CompareEqual, OP_PCMPEQQ, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY },
{ SN_CompareGreaterThan, OP_PCMPGTQ, SIMD_VERSION_SSE42, SIMD_EMIT_BINARY },
{ SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector4ui_intrinsics[] = {
+static const SimdIntrinsic vector4ui_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I4, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_ArithmeticRightShift, OP_PSARD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT },
{ SN_CompareEqual, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_set_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector4i_intrinsics[] = {
+static const SimdIntrinsic vector4i_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I4, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_CompareEqual, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_CompareGreaterThan, OP_PCMPGTD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_set_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector8us_intrinsics[] = {
+static const SimdIntrinsic vector8us_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I2, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_AddWithSaturation, OP_PADDW_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_ArithmeticRightShift, OP_PSARW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT },
{ SN_set_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector8s_intrinsics[] = {
+static const SimdIntrinsic vector8s_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I2, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_AddWithSaturation, OP_PADDW_SAT, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_CompareEqual, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_set_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER },
};
-static const SimdIntrinsc vector16b_intrinsics[] = {
+static const SimdIntrinsic vector16b_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I1, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_AddWithSaturation, OP_PADDB_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_Average, OP_PAVGB_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
Missing:
setters
*/
-static const SimdIntrinsc vector16sb_intrinsics[] = {
+static const SimdIntrinsic vector16sb_intrinsics[] = {
{ SN_ctor, OP_EXPAND_I1, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR },
{ SN_AddWithSaturation, OP_PADDB_SAT, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
{ SN_CompareEqual, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
static guint32 simd_supported_versions;
+static MonoInst* emit_sys_numerics_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
+static MonoInst* emit_sys_numerics_vectors_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
+
/*TODO match using number of parameters as well*/
static int
simd_intrinsic_compare_by_name (const void *key, const void *value)
{
- return strcmp (key, method_name (((SimdIntrinsc *)value)->name));
+ return strcmp (key, method_name (((SimdIntrinsic *)value)->name));
}
typedef enum {
static int
get_simd_vreg (MonoCompile *cfg, MonoMethod *cmethod, MonoInst *src)
{
+ const char *spec = INS_INFO (src->opcode);
+
if (src->opcode == OP_XMOVE) {
return src->sreg1;
- } else if (src->type == STACK_VTYPE) {
+ } else if (spec [MONO_INST_DEST] == 'x') {
return src->dreg;
}
g_warning ("get_simd_vreg:: could not infer source simd vreg for op");
* This function will load the value if needed.
*/
static int
-load_simd_vreg (MonoCompile *cfg, MonoMethod *cmethod, MonoInst *src, gboolean *indirect)
+load_simd_vreg_class (MonoCompile *cfg, MonoClass *klass, MonoInst *src, gboolean *indirect)
{
+ const char *spec = INS_INFO (src->opcode);
+
if (indirect)
*indirect = FALSE;
if (src->opcode == OP_XMOVE) {
int res = ((MonoInst*)src->inst_p0)->dreg;
NULLIFY_INS (src);
return res;
- } else if (src->type == STACK_VTYPE) {
+ } else if (spec [MONO_INST_DEST] == 'x') {
return src->dreg;
} else if (src->type == STACK_PTR || src->type == STACK_MP) {
MonoInst *ins;
*indirect = TRUE;
MONO_INST_NEW (cfg, ins, OP_LOADX_MEMBASE);
- ins->klass = cmethod->klass;
+ ins->klass = klass;
ins->sreg1 = src->dreg;
ins->type = STACK_VTYPE;
ins->dreg = alloc_ireg (cfg);
g_assert_not_reached ();
}
+static int
+load_simd_vreg (MonoCompile *cfg, MonoMethod *cmethod, MonoInst *src, gboolean *indirect)
+{
+ return load_simd_vreg_class (cfg, cmethod->klass, src, indirect);
+}
+
/*We share the var with fconv_to_r8_x to save some stack space.*/
static MonoInst*
get_double_spill_area (MonoCompile *cfg)
}
static int
-get_simd_vreg_or_expanded_scalar (MonoCompile *cfg, MonoMethod *cmethod, MonoInst *src, int position)
+type_to_comp_op (MonoType *t)
+{
+ switch (t->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ return OP_PCMPEQB;
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ return OP_PCMPEQW;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ return OP_PCMPEQD;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ return OP_PCMPEQQ;
+ case MONO_TYPE_R4:
+ return OP_COMPPS;
+ case MONO_TYPE_R8:
+ return OP_COMPPD;
+ default:
+ g_assert_not_reached ();
+ return -1;
+ }
+}
+
+static int
+type_to_gt_op (MonoType *t)
+{
+ switch (t->type) {
+ case MONO_TYPE_I1:
+ return OP_PCMPGTB;
+ case MONO_TYPE_I2:
+ return OP_PCMPGTW;
+ case MONO_TYPE_I4:
+ return OP_PCMPGTD;
+ case MONO_TYPE_I8:
+ return OP_PCMPGTQ;
+ default:
+ return -1;
+ }
+}
+
+static int
+type_to_padd_op (MonoType *t)
+{
+ switch (t->type) {
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I1:
+ return OP_PADDB;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2:
+ return OP_PADDW;
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I4:
+ return OP_PADDD;
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ return OP_PADDQ;
+ case MONO_TYPE_R4:
+ return OP_ADDPS;
+ case MONO_TYPE_R8:
+ return OP_ADDPD;
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int
+type_to_psub_op (MonoType *t)
+{
+ switch (t->type) {
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I1:
+ return OP_PSUBB;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2:
+ return OP_PSUBW;
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I4:
+ return OP_PSUBD;
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ return OP_PSUBQ;
+ case MONO_TYPE_R4:
+ return OP_SUBPS;
+ case MONO_TYPE_R8:
+ return OP_SUBPD;
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int
+type_to_pmul_op (MonoType *t)
+{
+ switch (t->type) {
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2:
+ return OP_PMULW;
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I4:
+ return OP_PMULD;
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ return OP_PMULQ;
+ case MONO_TYPE_R4:
+ return OP_MULPS;
+ case MONO_TYPE_R8:
+ return OP_MULPD;
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int
+type_to_pdiv_op (MonoType *t)
+{
+ switch (t->type) {
+ case MONO_TYPE_R4:
+ return OP_DIVPS;
+ case MONO_TYPE_R8:
+ return OP_DIVPD;
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int
+get_simd_vreg_or_expanded_scalar (MonoCompile *cfg, MonoClass *klass, MonoType *param_type, MonoInst *src)
{
MonoInst *ins;
- MonoMethodSignature *sig = mono_method_signature (cmethod);
int expand_op;
- g_assert (sig->param_count == 2);
- g_assert (position == 0 || position == 1);
+ if (mono_class_from_mono_type (param_type)->simd_type)
+ return get_simd_vreg (cfg, NULL, src);
- if (mono_class_from_mono_type (sig->params [position])->simd_type)
- return get_simd_vreg (cfg, cmethod, src);
-
- expand_op = mono_type_to_expand_op (sig->params [position]);
+ expand_op = mono_type_to_expand_op (param_type);
MONO_INST_NEW (cfg, ins, expand_op);
- ins->klass = cmethod->klass;
+ ins->klass = klass;
ins->sreg1 = src->dreg;
ins->type = STACK_VTYPE;
ins->dreg = alloc_ireg (cfg);
return ins->dreg;
}
+/*
+ * simd_intrinsic_emit_binary_op:
+ *
+ * Emit a binary SIMD opcode.
+ * @LHS/@RHS are the two arguments, they can be either a SIMD type or a scalar one. Scalar arguments are
+ * expanded to the SIMD type.
+ */
static MonoInst*
-simd_intrinsic_emit_binary (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_binary_op (MonoCompile *cfg, int opcode, int flags, MonoClass *klass, MonoType *lhs_type, MonoType *rhs_type, MonoInst *lhs, MonoInst *rhs)
{
MonoInst* ins;
int left_vreg, right_vreg;
- left_vreg = get_simd_vreg_or_expanded_scalar (cfg, cmethod, args [0], 0);
- right_vreg = get_simd_vreg_or_expanded_scalar (cfg, cmethod, args [1], 1);
-
+ left_vreg = get_simd_vreg_or_expanded_scalar (cfg, klass, lhs_type, lhs);
+ right_vreg = get_simd_vreg_or_expanded_scalar (cfg, klass, rhs_type, rhs);
- MONO_INST_NEW (cfg, ins, intrinsic->opcode);
- ins->klass = cmethod->klass;
+ MONO_INST_NEW (cfg, ins, opcode);
+ ins->klass = klass;
ins->sreg1 = left_vreg;
ins->sreg2 = right_vreg;
ins->type = STACK_VTYPE;
ins->dreg = alloc_ireg (cfg);
- ins->inst_c0 = intrinsic->flags;
+ ins->inst_c0 = flags;
MONO_ADD_INS (cfg->cbb, ins);
return ins;
}
static MonoInst*
-simd_intrinsic_emit_unary (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_binary (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+{
+ MonoMethodSignature *sig = mono_method_signature (cmethod);
+
+ g_assert (sig->param_count == 2);
+
+ return simd_intrinsic_emit_binary_op (cfg, intrinsic->opcode, intrinsic->flags, cmethod->klass, sig->params [0], sig->params [1], args [0], args [1]);
+}
+
+static MonoInst*
+simd_intrinsic_emit_unary (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst* ins;
int vreg;
}
static MonoInst*
-simd_intrinsic_emit_setter (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_setter (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
MonoMethodSignature *sig = mono_method_signature (cmethod);
return ins;
}
+/*
+ * simd_intrinsic_emit_getter_op:
+ *
+ * Emit IR for loading an element of a SIMD value.
+ *
+ * @klass is the simd type, @type is the element type.
+ */
static MonoInst*
-simd_intrinsic_emit_getter (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_getter_op (MonoCompile *cfg, int index, MonoClass *klass, MonoType *type, MonoInst *arg)
{
MonoInst *ins;
- MonoMethodSignature *sig = mono_method_signature (cmethod);
- int vreg, shift_bits = mono_type_elements_shift_bits (sig->ret);
+ int vreg, shift_bits;
- vreg = load_simd_vreg (cfg, cmethod, args [0], NULL);
+ vreg = load_simd_vreg_class (cfg, klass, arg, NULL);
+
+ if (type->type == MONO_TYPE_I8 || type->type == MONO_TYPE_U8 || type->type == MONO_TYPE_R8) {
+ MonoInst *ins;
+ gboolean is_r8 = type->type == MONO_TYPE_R8;
+
+ MONO_INST_NEW (cfg, ins, is_r8 ? OP_EXTRACT_R8 : OP_EXTRACT_I8);
+ ins->klass = klass;
+ ins->sreg1 = vreg;
+ ins->inst_c0 = index;
+ if (is_r8) {
+ ins->type = STACK_R8;
+ ins->dreg = alloc_freg (cfg);
+ ins->backend.spill_var = get_double_spill_area (cfg);
+ } else {
+ ins->type = STACK_I8;
+ ins->dreg = alloc_lreg (cfg);
+ }
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
+ }
+
+ shift_bits = mono_type_elements_shift_bits (type);
- if ((intrinsic->opcode >> shift_bits) && !cfg->compile_llvm) {
+ if ((index >> shift_bits) && !cfg->compile_llvm) {
MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
- ins->klass = cmethod->klass;
+ ins->klass = klass;
ins->sreg1 = vreg;
- ins->inst_c0 = intrinsic->opcode >> shift_bits;
+ ins->inst_c0 = index >> shift_bits;
ins->type = STACK_VTYPE;
ins->dreg = vreg = alloc_ireg (cfg);
MONO_ADD_INS (cfg->cbb, ins);
}
- MONO_INST_NEW (cfg, ins, mono_type_to_extract_op (sig->ret));
- ins->klass = cmethod->klass;
+ MONO_INST_NEW (cfg, ins, mono_type_to_extract_op (type));
+ ins->klass = klass;
ins->sreg1 = vreg;
ins->type = STACK_I4;
ins->dreg = vreg = alloc_ireg (cfg);
if (cfg->compile_llvm)
- ins->inst_c0 = intrinsic->opcode;
+ ins->inst_c0 = index;
else
- ins->inst_c0 = intrinsic->opcode & ((1 << shift_bits) - 1);
+ ins->inst_c0 = index & ((1 << shift_bits) - 1);
MONO_ADD_INS (cfg->cbb, ins);
- if (sig->ret->type == MONO_TYPE_R4) {
+ if (type->type == MONO_TYPE_R4) {
MONO_INST_NEW (cfg, ins, cfg->r4fp ? OP_ICONV_TO_R4_RAW : OP_MOVE_I4_TO_F);
ins->klass = mono_defaults.single_class;
ins->sreg1 = vreg;
}
static MonoInst*
-simd_intrinsic_emit_long_getter (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_getter (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+{
+ MonoMethodSignature *sig = mono_method_signature (cmethod);
+
+ return simd_intrinsic_emit_getter_op (cfg, intrinsic->opcode, cmethod->klass, sig->ret, args [0]);
+}
+
+static MonoInst*
+simd_intrinsic_emit_long_getter (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
int vreg;
}
static MonoInst*
-simd_intrinsic_emit_ctor (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_ctor (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins = NULL;
int i, addr_reg;
MonoMethodSignature *sig = mono_method_signature (cmethod);
int store_op = mono_type_to_store_membase (cfg, sig->params [0]);
int arg_size = mono_type_size (sig->params [0], &i);
+ int opcode;
if (sig->param_count == 1) {
int dreg;
dreg = alloc_ireg (cfg);
}
- MONO_INST_NEW (cfg, ins, intrinsic->opcode);
+ if (intrinsic)
+ opcode = intrinsic->opcode;
+ else
+ opcode = mono_type_to_expand_op (sig->params [0]);
+ MONO_INST_NEW (cfg, ins, opcode);
ins->klass = cmethod->klass;
ins->sreg1 = args [1]->dreg;
ins->type = STACK_VTYPE;
EMIT_NEW_STORE_MEMBASE (cfg, ins, store_op, addr_reg, i * arg_size, args [i + 1]->dreg);
}
+ if (sig->param_count * arg_size < 16) {
+ /* If there are not enough arguments, fill the rest with 0s */
+ for (i = sig->param_count; i < 16 / arg_size; ++i) {
+ switch (arg_size) {
+ case 4:
+ MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, addr_reg, i * arg_size, 0);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ }
+
if (is_ldaddr) { /*Eliminate LDADDR if it's initing a local var*/
int vreg = ((MonoInst*)args [0]->inst_p0)->dreg;
NULLIFY_INS (args [0]);
}
static MonoInst*
-simd_intrinsic_emit_cast (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_cast (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
+ MonoClass *klass;
int vreg;
vreg = get_simd_vreg (cfg, cmethod, args [0]);
- //TODO macroize this
+ if (cmethod->is_inflated)
+ /* Vector<T> */
+ klass = mono_class_from_mono_type (mono_method_signature (cmethod)->ret);
+ else
+ klass = cmethod->klass;
+
MONO_INST_NEW (cfg, ins, OP_XMOVE);
- ins->klass = cmethod->klass;
+ ins->klass = klass;
ins->type = STACK_VTYPE;
ins->sreg1 = vreg;
ins->dreg = alloc_ireg (cfg);
}
static MonoInst*
-simd_intrinsic_emit_shift (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_shift (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
int vreg, vreg2 = -1, opcode = intrinsic->opcode;
}
static MonoInst*
-simd_intrinsic_emit_equality (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_equality_op (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args, int opcode, int flags)
{
MonoInst* ins;
int left_vreg, right_vreg, tmp_vreg;
- left_vreg = get_simd_vreg (cfg, cmethod, args [0]);
+ left_vreg = load_simd_vreg (cfg, cmethod, args [0], NULL);
right_vreg = get_simd_vreg (cfg, cmethod, args [1]);
-
- MONO_INST_NEW (cfg, ins, intrinsic->opcode);
+ MONO_INST_NEW (cfg, ins, opcode);
ins->klass = cmethod->klass;
ins->sreg1 = left_vreg;
ins->sreg2 = right_vreg;
ins->type = STACK_VTYPE;
ins->klass = cmethod->klass;
ins->dreg = tmp_vreg = alloc_ireg (cfg);
- ins->inst_c0 = intrinsic->flags;
+ ins->inst_c0 = flags;
MONO_ADD_INS (cfg->cbb, ins);
/*FIXME the next ops are SSE specific*/
MONO_ADD_INS (cfg->cbb, ins);
/*FP ops have a not equal instruction, which means that we must test the results with OR semantics.*/
- if (mono_op_is_packed_compare (intrinsic->opcode) || intrinsic->flags == SIMD_COMP_EQ) {
+ if (mono_op_is_packed_compare (opcode) || flags == SIMD_COMP_EQ) {
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_vreg, 0xFFFF);
- NEW_UNALU (cfg, ins, intrinsic->flags == SIMD_COMP_EQ ? OP_CEQ : OP_CLT_UN, tmp_vreg, -1);
+ NEW_UNALU (cfg, ins, flags == SIMD_COMP_EQ ? OP_CEQ : OP_CLT_UN, tmp_vreg, -1);
} else {
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_vreg, 0);
NEW_UNALU (cfg, ins, OP_CGT_UN, tmp_vreg, -1);
return ins;
}
+static MonoInst*
+simd_intrinsic_emit_equality (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+{
+ return simd_intrinsic_emit_equality_op (cfg, cmethod, args, intrinsic->opcode, intrinsic->flags);
+}
static MonoInst*
-simd_intrinsic_emit_shuffle (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_shuffle (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
int vreg, vreg2 = -1;
}
static MonoInst*
-simd_intrinsic_emit_load_aligned (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_load_aligned (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
}
static MonoInst*
-simd_intrinsic_emit_store (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_store (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
int vreg;
}
static MonoInst*
-simd_intrinsic_emit_extract_mask (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_extract_mask (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
int vreg;
}
static MonoInst*
-simd_intrinsic_emit_prefetch (const SimdIntrinsc *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+simd_intrinsic_emit_prefetch (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
{
MonoInst *ins;
return ins;
}
+static MonoInst*
+simd_intrinsic_emit_const (const SimdIntrinsic *intrinsic, MonoCompile *cfg, MonoMethod *cmethod, MonoInst **args)
+{
+ MonoInst *ins;
+
+ MONO_INST_NEW (cfg, ins, intrinsic->opcode);
+ ins->klass = cmethod->klass;
+ ins->type = STACK_VTYPE;
+ ins->dreg = alloc_xreg (cfg);
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
+}
+
static const char *
simd_version_name (guint32 version)
{
}
static MonoInst*
-emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args, const SimdIntrinsc *intrinsics, guint32 size)
+emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args, const SimdIntrinsic *intrinsics, guint32 size)
{
- const SimdIntrinsc *result = (const SimdIntrinsc *)mono_binary_search (cmethod->name, intrinsics, size, sizeof (SimdIntrinsc), &simd_intrinsic_compare_by_name);
+ const SimdIntrinsic *result = (const SimdIntrinsic *)mono_binary_search (cmethod->name, intrinsics, size, sizeof (SimdIntrinsic), &simd_intrinsic_compare_by_name);
if (!result) {
DEBUG (printf ("function doesn't have a simd intrinsic %s::%s/%d\n", cmethod->klass->name, cmethod->name, fsig->param_count));
return NULL;
return NULL;
}
+static gboolean
+is_sys_numerics_assembly (MonoAssembly *assembly)
+{
+ return !strcmp ("System.Numerics", assembly->aname.name);
+}
+
+static gboolean
+is_sys_numerics_vectors_assembly (MonoAssembly *assembly)
+{
+ return !strcmp ("System.Numerics.Vectors", assembly->aname.name);
+}
+
MonoInst*
mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
const char *class_name;
+ if (is_sys_numerics_assembly (cmethod->klass->image->assembly))
+ return emit_sys_numerics_intrinsics (cfg, cmethod, fsig, args);
+
+ if (is_sys_numerics_vectors_assembly (cmethod->klass->image->assembly))
+ return emit_sys_numerics_vectors_intrinsics (cfg, cmethod, fsig, args);
+
if (strcmp ("Mono.Simd", cmethod->klass->image->assembly->aname.name) ||
strcmp ("Mono.Simd", cmethod->klass->name_space))
return NULL;
cfg->uses_simd_intrinsics = 1;
if (!strcmp ("Vector2d", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector2d_intrinsics, sizeof (vector2d_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector2d_intrinsics, sizeof (vector2d_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector4f", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector4f_intrinsics, sizeof (vector4f_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector4f_intrinsics, sizeof (vector4f_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector2ul", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector2ul_intrinsics, sizeof (vector2ul_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector2ul_intrinsics, sizeof (vector2ul_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector2l", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector2l_intrinsics, sizeof (vector2l_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector2l_intrinsics, sizeof (vector2l_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector4ui", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector4ui_intrinsics, sizeof (vector4ui_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector4ui_intrinsics, sizeof (vector4ui_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector4i", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector4i_intrinsics, sizeof (vector4i_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector4i_intrinsics, sizeof (vector4i_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector8us", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector8us_intrinsics, sizeof (vector8us_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector8us_intrinsics, sizeof (vector8us_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector8s", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector8s_intrinsics, sizeof (vector8s_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector8s_intrinsics, sizeof (vector8s_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector16b", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector16b_intrinsics, sizeof (vector16b_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector16b_intrinsics, sizeof (vector16b_intrinsics) / sizeof (SimdIntrinsic));
if (!strcmp ("Vector16sb", class_name))
- return emit_intrinsics (cfg, cmethod, fsig, args, vector16sb_intrinsics, sizeof (vector16sb_intrinsics) / sizeof (SimdIntrinsc));
+ return emit_intrinsics (cfg, cmethod, fsig, args, vector16sb_intrinsics, sizeof (vector16sb_intrinsics) / sizeof (SimdIntrinsic));
+
+ return NULL;
+}
+
+// The entries should be ordered by name
+// System.Numerics.Vector2/Vector3/Vector4
+static const SimdIntrinsic vector2_intrinsics[] = {
+ { SN_ctor, OP_EXPAND_R4 },
+ { SN_Abs },
+ { SN_Dot, OP_DPPS },
+ { SN_Equals, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ },
+ { SN_Max, OP_MAXPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
+ { SN_Min, OP_MINPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
+ { SN_SquareRoot, OP_SQRTPS, SIMD_VERSION_SSE1, SIMD_EMIT_UNARY },
+ { SN_op_Addition, OP_ADDPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
+ { SN_op_Division, OP_DIVPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
+ { SN_op_Multiply, OP_MULPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
+ { SN_op_Subtraction, OP_SUBPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY },
+};
+
+static MonoInst*
+emit_vector_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ const SimdIntrinsic *intrins;
+ MonoMethodSignature *sig = mono_method_signature (cmethod);
+
+ /*
+ * Vector2/3/4 are handled the same way, since the underlying SIMD type is the same (4 * r4).
+ */
+ intrins = (const SimdIntrinsic*)mono_binary_search (cmethod->name, vector2_intrinsics, sizeof (vector2_intrinsics) / sizeof (SimdIntrinsic), sizeof (SimdIntrinsic), &simd_intrinsic_compare_by_name);
+ if (!intrins) {
+ //printf ("%s\n", mono_method_full_name (cmethod, 1));
+ return NULL;
+ }
+
+ if (cfg->verbose_level > 1) {
+ char *name = mono_method_full_name (cmethod, TRUE);
+ printf (" SIMD intrinsic %s\n", name);
+ g_free (name);
+ }
+
+ switch (intrins->name) {
+ case SN_ctor:
+ return simd_intrinsic_emit_ctor (intrins, cfg, cmethod, args);
+ break;
+ case SN_Equals:
+ return simd_intrinsic_emit_equality (intrins, cfg, cmethod, args);
+ break;
+ case SN_SquareRoot:
+ return simd_intrinsic_emit_unary (intrins, cfg, cmethod, args);
+ break;
+ case SN_Dot:
+ if (COMPILE_LLVM (cfg)) {
+ MonoInst *ins;
+
+ ins = simd_intrinsic_emit_binary (intrins, cfg, cmethod, args);
+ /* The end result is in the lowest element */
+ return simd_intrinsic_emit_getter_op (cfg, 0, cmethod->klass, mono_method_signature (cmethod)->ret, ins);
+ }
+ break;
+ case SN_Abs: {
+ // abs(x) = max(x, sub(0,x))
+ MonoInst *sub;
+ MonoInst *zero;
+
+ MONO_INST_NEW (cfg, zero, OP_XZERO);
+ zero->dreg = alloc_xreg (cfg);
+ zero->klass = cmethod->klass;
+ MONO_ADD_INS (cfg->cbb, zero);
+
+ sub = simd_intrinsic_emit_binary_op (cfg, OP_SUBPS, 0, cmethod->klass, sig->params [0], sig->params [0], zero, args [0]);
+ return simd_intrinsic_emit_binary_op (cfg, OP_MAXPS, 0, cmethod->klass, sig->params [0], sig->params [0], args [0], sub);
+ }
+ case SN_Max:
+ case SN_Min:
+ case SN_op_Addition:
+ case SN_op_Division:
+ case SN_op_Multiply:
+ case SN_op_Subtraction:
+ return simd_intrinsic_emit_binary (intrins, cfg, cmethod, args);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static const SimdIntrinsic vector_t_intrinsics[] = {
+ { SN_ctor },
+ { SN_Abs },
+ { SN_Equals },
+ { SN_GreaterThan },
+ { SN_GreaterThanOrEqual },
+ { SN_LessThan },
+ { SN_LessThanOrEqual },
+ { SN_get_AllOnes, OP_XONES },
+ { SN_get_Count },
+ { SN_get_Item },
+ { SN_get_Zero, OP_XZERO },
+ { SN_op_Addition },
+ { SN_op_Division },
+ { SN_op_Explicit },
+ { SN_op_Multiply },
+ { SN_op_Subtraction }
+};
+
+static MonoInst*
+emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ const SimdIntrinsic *intrins;
+ MonoType *etype;
+ MonoInst *ins;
+ int size, len, index;
+
+ intrins = (const SimdIntrinsic*)mono_binary_search (cmethod->name, vector_t_intrinsics, sizeof (vector_t_intrinsics) / sizeof (SimdIntrinsic), sizeof (SimdIntrinsic), &simd_intrinsic_compare_by_name);
+ if (!intrins) {
+ //printf ("%s\n", mono_method_full_name (cmethod, 1));
+ return NULL;
+ }
+
+ if (cfg->verbose_level > 1) {
+ char *name = mono_method_full_name (cmethod, TRUE);
+ printf (" SIMD intrinsic %s\n", name);
+ g_free (name);
+ }
+
+ etype = cmethod->klass->generic_class->context.class_inst->type_argv [0];
+ size = mono_class_value_size (mono_class_from_mono_type (etype), NULL);
+ g_assert (size);
+ len = 16 / size;
+
+ switch (intrins->name) {
+ case SN_get_Count:
+ EMIT_NEW_ICONST (cfg, ins, len);
+ return ins;
+ case SN_get_AllOnes:
+ case SN_get_Zero:
+ return simd_intrinsic_emit_const (intrins, cfg, cmethod, args);
+ case SN_get_Item:
+ g_assert (fsig->param_count == 1);
+ if (args [1]->opcode != OP_ICONST)
+ return NULL;
+ index = args [1]->inst_c0;
+ if (index < 0 || index >= len)
+ return NULL;
+ return simd_intrinsic_emit_getter_op (cfg, index, cmethod->klass, etype, args [0]);
+ case SN_ctor:
+ if (fsig->param_count == 1 && mono_metadata_type_equal (fsig->params [0], etype))
+ return simd_intrinsic_emit_ctor (NULL, cfg, cmethod, args);
+ if ((fsig->param_count == 1 || fsig->param_count == 2) && (fsig->params [0]->type == MONO_TYPE_SZARRAY)) {
+ MonoInst *array_ins = args [1];
+ MonoInst *index_ins;
+ MonoInst *ldelema_ins;
+ MonoInst *var;
+ int end_index_reg;
+
+ /* .ctor (T[]) or .ctor (T[], index) */
+
+ if (fsig->param_count == 2) {
+ index_ins = args [2];
+ } else {
+ EMIT_NEW_ICONST (cfg, index_ins, 0);
+ }
+
+ /* Emit index check for the end (index + len - 1 < array length) */
+ end_index_reg = alloc_ireg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, ins, OP_IADD_IMM, end_index_reg, index_ins->dreg, len - 1);
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_ins->dreg, MonoArray, max_length, end_index_reg);
+
+ /* Load the array slice into the simd reg */
+ ldelema_ins = mini_emit_ldelema_1_ins (cfg, mono_class_from_mono_type (etype), array_ins, index_ins, TRUE);
+ g_assert (args [0]->opcode == OP_LDADDR);
+ var = args [0]->inst_p0;
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADX_MEMBASE, var->dreg, ldelema_ins->dreg, 0);
+ ins->klass = cmethod->klass;
+ return args [0];
+ }
+ break;
+ case SN_op_Explicit:
+ return simd_intrinsic_emit_cast (intrins, cfg, cmethod, args);
+ case SN_Equals:
+ if (fsig->param_count == 1)
+ return simd_intrinsic_emit_equality_op (cfg, cmethod, args, type_to_comp_op (etype), SIMD_COMP_EQ);
+ if (fsig->param_count == 2)
+ return simd_intrinsic_emit_binary_op (cfg, type_to_comp_op (etype), 0, cmethod->klass, fsig->params [0], fsig->params [1], args [0], args [1]);
+ break;
+
+ case SN_GreaterThan:
+ case SN_GreaterThanOrEqual:
+ case SN_LessThan: {
+ MonoInst *cmp1, *cmp2;
+ int eq_op, gt_op;
+
+ switch (etype->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_I8:
+ break;
+ default:
+ return NULL;
+ }
+
+ eq_op = type_to_comp_op (etype);
+ gt_op = type_to_gt_op (etype);
+
+ switch (intrins->name) {
+ case SN_GreaterThan:
+ return simd_intrinsic_emit_binary_op (cfg, gt_op, 0, cmethod->klass, fsig->params [0], fsig->params [1], args [0], args [1]);
+ case SN_LessThanOrEqual:
+ return simd_intrinsic_emit_binary_op (cfg, gt_op, 0, cmethod->klass, fsig->params [0], fsig->params [1], args [1], args [0]);
+ case SN_GreaterThanOrEqual:
+ cmp1 = simd_intrinsic_emit_binary_op (cfg, eq_op, 0, cmethod->klass, fsig->params [0], fsig->params [1], args [0], args [1]);
+ cmp2 = simd_intrinsic_emit_binary_op (cfg, gt_op, 0, cmethod->klass, fsig->params [0], fsig->params [1], args [0], args [1]);
+ return simd_intrinsic_emit_binary_op (cfg, OP_POR, 0, cmethod->klass, fsig->params [0], fsig->params [1], cmp1, cmp2);
+ case SN_LessThan:
+ cmp1 = simd_intrinsic_emit_binary_op (cfg, eq_op, 0, cmethod->klass, fsig->params [0], fsig->params [1], args [1], args [0]);
+ cmp2 = simd_intrinsic_emit_binary_op (cfg, gt_op, 0, cmethod->klass, fsig->params [0], fsig->params [1], args [1], args [0]);
+ return simd_intrinsic_emit_binary_op (cfg, OP_POR, 0, cmethod->klass, fsig->params [0], fsig->params [1], cmp1, cmp2);
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ case SN_Abs:
+ /* Vector<T>.Abs */
+ switch (etype->type) {
+ case MONO_TYPE_U1:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_U8: {
+ MonoInst *ins;
+
+ /* No-op */
+ MONO_INST_NEW (cfg, ins, OP_XMOVE);
+ ins->klass = cmethod->klass;
+ ins->type = STACK_VTYPE;
+ ins->sreg1 = args [0]->dreg;
+ ins->dreg = alloc_xreg (cfg);
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
+ }
+ default:
+ break;
+ }
+ break;
+ case SN_op_Addition: {
+ int op = type_to_padd_op (etype);
+ if (op != -1)
+ return simd_intrinsic_emit_binary_op (cfg, op, 0, cmethod->klass, fsig->params [0], fsig->params [0], args [0], args [1]);
+ break;
+ }
+ case SN_op_Subtraction: {
+ int op = type_to_psub_op (etype);
+ if (op != -1)
+ return simd_intrinsic_emit_binary_op (cfg, op, 0, cmethod->klass, fsig->params [0], fsig->params [0], args [0], args [1]);
+ break;
+ }
+ case SN_op_Multiply: {
+ int op = type_to_pmul_op (etype);
+ if (op != -1)
+ return simd_intrinsic_emit_binary_op (cfg, op, 0, cmethod->klass, fsig->params [0], fsig->params [0], args [0], args [1]);
+ break;
+ }
+ case SN_op_Division: {
+ int op = type_to_pdiv_op (etype);
+ if (op != -1)
+ return simd_intrinsic_emit_binary_op (cfg, op, 0, cmethod->klass, fsig->params [0], fsig->params [0], args [0], args [1]);
+ break;
+ }
+ default:
+ break;
+ }
return NULL;
}
+/*
+ * emit_sys_numerics_intrinsics:
+ *
+ * Emit intrinsics for the System.Numerics assembly.
+ */
+static MonoInst*
+emit_sys_numerics_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ const char *nspace = cmethod->klass->name_space;
+ const char *class_name = cmethod->klass->name;
+
+ if (cfg->r4fp)
+ // FIXME:
+ return NULL;
+
+ if (!strcmp ("Vector2", class_name) || !strcmp ("Vector4", class_name) || !strcmp ("Vector3", class_name))
+ return emit_vector_intrinsics (cfg, cmethod, fsig, args);
+
+ if (!strcmp ("Vector`1", class_name))
+ return emit_vector_t_intrinsics (cfg, cmethod, fsig, args);
+
+ if (!strcmp ("System.Numerics", nspace) && !strcmp ("Vector", class_name)) {
+ if (!strcmp (cmethod->name, "get_IsHardwareAccelerated")) {
+ MonoInst *ins;
+
+ if (simd_supported_versions)
+ EMIT_NEW_ICONST (cfg, ins, 1);
+ else
+ EMIT_NEW_ICONST (cfg, ins, 0);
+ ins->type = STACK_I4;
+ return ins;
+ }
+ }
+
+ return NULL;
+}
+
+static MonoInst*
+emit_sys_numerics_vectors_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ const char *class_name = cmethod->klass->name;
+
+ if (cfg->r4fp)
+ // FIXME:
+ return NULL;
+
+ if (!strcmp (class_name, "Vector`1"))
+ return emit_vector_t_intrinsics (cfg, cmethod, fsig, args);
+ return NULL;
+}
+
+MonoInst*
+mono_emit_simd_field_load (MonoCompile *cfg, MonoClassField *field, MonoInst *addr)
+{
+ if (cfg->r4fp)
+ // FIXME:
+ return NULL;
+
+ if (is_sys_numerics_assembly (field->parent->image->assembly)) {
+ int index = -1;
+
+ if (!strcmp (field->parent->name, "Vector2") ||
+ !strcmp (field->parent->name, "Vector3") ||
+ !strcmp (field->parent->name, "Vector4")) {
+ if (!strcmp (field->name, "X"))
+ index = 0;
+ else if (!strcmp (field->name, "Y"))
+ index = 1;
+ else if (!strcmp (field->name, "Z"))
+ index = 2;
+ else if (!strcmp (field->name, "W"))
+ index = 3;
+ }
+
+ if (index != -1) {
+ if (cfg->verbose_level > 1)
+ printf (" SIMD intrinsic field access: %s\n", field->name);
+
+ return simd_intrinsic_emit_getter_op (cfg, index, field->parent, mono_field_get_type (field), addr);
+ }
+ }
+ return NULL;
+}
+
#endif /* DISABLE_JIT */
+
+#else
+
+MonoInst*
+mono_emit_simd_field_load (MonoCompile *cfg, MonoClassField *field, MonoInst *addr)
+{
+ return NULL;
+}
+
#endif /* MONO_ARCH_SIMD_INTRINSICS */
+SIMD_METHOD("Abs", SN_Abs)
SIMD_METHOD("AddSub", SN_AddSub)
SIMD_METHOD("AddWithSaturation", SN_AddWithSaturation)
SIMD_METHOD("AndNot", SN_AndNot)
SIMD_METHOD("ConvertToInt", SN_ConvertToInt)
SIMD_METHOD("ConvertToIntTruncated", SN_ConvertToIntTruncated)
SIMD_METHOD(".ctor", SN_ctor)
+SIMD_METHOD("Dot", SN_Dot)
SIMD_METHOD("Duplicate", SN_Duplicate)
SIMD_METHOD("DuplicateHigh", SN_DuplicateHigh)
SIMD_METHOD("DuplicateLow", SN_DuplicateLow)
+SIMD_METHOD("Equals", SN_Equals)
SIMD_METHOD("ExtractByteMask", SN_ExtractByteMask)
+SIMD_METHOD("GreaterThan", SN_GreaterThan)
+SIMD_METHOD("GreaterThanOrEqual", SN_GreaterThanOrEqual)
+SIMD_METHOD("LessThan", SN_LessThan)
+SIMD_METHOD("LessThanOrEqual", SN_LessThanOrEqual)
+SIMD_METHOD("get_AllOnes", SN_get_AllOnes)
+SIMD_METHOD("get_Count", SN_get_Count)
+SIMD_METHOD("get_Item", SN_get_Item)
SIMD_METHOD("get_W", SN_get_W)
SIMD_METHOD("get_X", SN_get_X)
SIMD_METHOD("get_Y", SN_get_Y)
SIMD_METHOD("get_Z", SN_get_Z)
+SIMD_METHOD("get_Zero", SN_get_Zero)
SIMD_METHOD("get_V0", SN_get_V0)
SIMD_METHOD("get_V1", SN_get_V1)
SIMD_METHOD("get_V2", SN_get_V2)
SIMD_METHOD("SignedPackWithSignedSaturation", SN_SignedPackWithSignedSaturation)
SIMD_METHOD("SignedPackWithUnsignedSaturation", SN_SignedPackWithUnsignedSaturation)
SIMD_METHOD("Sqrt", SN_Sqrt)
+SIMD_METHOD("SquareRoot", SN_SquareRoot)
SIMD_METHOD("StoreAligned", SN_StoreAligned)
SIMD_METHOD("StoreNonTemporal", SN_StoreNonTemporal)
SIMD_METHOD("SubtractWithSaturation", SN_SubtractWithSaturation)