[jit] Add parameter type checks to the SIMD intrinsics to make sure we are handling...
[mono.git] / mono / mini / simd-intrinsics.c
index 091f6b4073cb90cd768495ae34c8052eb7846348..2240a94cc67521fc623f0b65b7c085152754597b 100644 (file)
@@ -1959,6 +1959,7 @@ emit_vector_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu
 {
        const SimdIntrinsic *intrins;
        MonoMethodSignature *sig = mono_method_signature (cmethod);
+       MonoType *type = &cmethod->klass->byval_arg;
 
        /*
         * Vector2/3/4 are handled the same way, since the underlying SIMD type is the same (4 * r4).
@@ -1976,16 +1977,26 @@ emit_vector_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu
        }
 
        switch (intrins->name) {
-       case SN_ctor:
+       case SN_ctor: {
+               gboolean match = TRUE;
+               for (int i = 0; i < fsig->param_count; ++i)
+                       if (fsig->params [i]->type != MONO_TYPE_R4)
+                               match = FALSE;
+               if (!match)
+                       break;
                return simd_intrinsic_emit_ctor (intrins, cfg, cmethod, args);
-               break;
+       }
        case SN_Equals:
+               if (!(fsig->param_count == 1 && fsig->ret->type == MONO_TYPE_BOOLEAN && fsig->params [0] == type))
+                       break;
                return simd_intrinsic_emit_equality (intrins, cfg, cmethod, args);
-               break;
        case SN_SquareRoot:
+               if (!(fsig->param_count == 1 && fsig->ret == type && fsig->params [0] == type))
+                       break;
                return simd_intrinsic_emit_unary (intrins, cfg, cmethod, args);
-               break;
        case SN_Dot:
+               if (!(fsig->param_count == 2 && fsig->ret->type == MONO_TYPE_R4 && fsig->params [0] == type && fsig->params [1] == type))
+                       break;
                if (COMPILE_LLVM (cfg)) {
                        MonoInst *ins;
 
@@ -1999,6 +2010,9 @@ emit_vector_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu
                MonoInst *sub;
                MonoInst *zero;
 
+               if (!(fsig->param_count == 1 && fsig->ret == type && fsig->params [0] == type))
+                       break;
+
                MONO_INST_NEW (cfg, zero, OP_XZERO);
                zero->dreg = alloc_xreg (cfg);
                zero->klass = cmethod->klass;
@@ -2013,11 +2027,18 @@ emit_vector_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu
        case SN_op_Division:
        case SN_op_Multiply:
        case SN_op_Subtraction:
+               if (!(fsig->param_count == 2 && fsig->ret == type && (fsig->params [0] == type || fsig->params [0]->type == MONO_TYPE_R4) && (fsig->params [1] == type || fsig->params [1]->type == MONO_TYPE_R4)))
+                       break;
                return simd_intrinsic_emit_binary (intrins, cfg, cmethod, args);
        default:
                break;
        }
 
+       if (cfg->verbose_level > 1) {
+               char *name = mono_method_full_name (cmethod, TRUE);
+               printf ("  SIMD method %s not handled.\n", name);
+               g_free (name);
+       }
        return NULL;
 }
 
@@ -2045,7 +2066,7 @@ static MonoInst*
 emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
        const SimdIntrinsic *intrins;
-       MonoType *etype;
+       MonoType *type, *etype;
        MonoInst *ins;
        int size, len, index;
 
@@ -2055,6 +2076,7 @@ emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                return NULL;
        }
 
+       type = &cmethod->klass->byval_arg;
        etype = mono_class_get_context (cmethod->klass)->class_inst->type_argv [0];
        size = mono_class_value_size (mono_class_from_mono_type (etype), NULL);
        g_assert (size);
@@ -2071,10 +2093,14 @@ emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
 
        switch (intrins->name) {
        case SN_get_Count:
+               if (!(fsig->param_count == 0 && fsig->ret->type == MONO_TYPE_I4))
+                       break;
                EMIT_NEW_ICONST (cfg, ins, len);
                return ins;
        case SN_get_AllOnes:
        case SN_get_Zero:
+               if (!(fsig->param_count == 0 && mono_metadata_type_equal (fsig->ret, type)))
+                       break;
                return simd_intrinsic_emit_const (intrins, cfg, cmethod, args);
        case SN_get_Item:
                g_assert (fsig->param_count == 1);
@@ -2187,26 +2213,29 @@ emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        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);
+       case SN_op_Addition:
+       case SN_op_Subtraction:
+       case SN_op_Multiply:
+       case SN_op_Division: {
+               if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->ret, fsig->params [0]) && mono_metadata_type_equal (fsig->params [0], fsig->params [1])))
+                       break;
+               int op = 0;
+               switch (intrins->name) {
+               case SN_op_Addition:
+                       op = type_to_padd_op (etype);
+                       break;
+               case SN_op_Subtraction:
+                       op = type_to_psub_op (etype);
+                       break;
+               case SN_op_Multiply:
+                       op = type_to_pmul_op (etype);
+                       break;
+               case SN_op_Division:
+                       op = type_to_pdiv_op (etype);
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
                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;
@@ -2243,6 +2272,12 @@ emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                break;
        }
 
+       if (cfg->verbose_level > 1) {
+               char *name = mono_method_full_name (cmethod, TRUE);
+               printf ("  SIMD method %s not handled.\n", name);
+               g_free (name);
+       }
+
        return NULL;
 }