[interp] Add more Math intrinsics (#33431)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Wed, 11 Mar 2020 22:14:59 +0000 (18:14 -0400)
committerGitHub <noreply@github.com>
Wed, 11 Mar 2020 22:14:59 +0000 (00:14 +0200)
Fixes https://github.com/dotnet/runtime/issues/33233

Co-authored-by: BrzVlad <BrzVlad@users.noreply.github.com>
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/interp/mintops.def
src/mono/mono/mini/interp/transform.c

index 4ae185f..ae35548 100644 (file)
@@ -7007,6 +7007,11 @@ call_newobj:
        sp [-1].data.f = mathfunc (sp [-1].data.f); \
        ++ip;
 
+#define MATH_BINOP(mathfunc) \
+       sp--; \
+       sp [-1].data.f = mathfunc (sp [-1].data.f, sp [0].data.f); \
+       ++ip;
+
                MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
@@ -7014,15 +7019,103 @@ call_newobj:
                MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CEILING) MATH_UNOP(ceil); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_EXP) MATH_UNOP(exp); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_FLOOR) MATH_UNOP(floor); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LOG) MATH_UNOP(log); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LOG2) MATH_UNOP(log2); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LOG10) MATH_UNOP(log10); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
 
+               MINT_IN_CASE(MINT_ATAN2) MATH_BINOP(atan2); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_POW) MATH_BINOP(pow); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_FMA)
+                       sp -= 2;
+                       sp [-1].data.f = fma (sp [-1].data.f, sp [0].data.f, sp [1].data.f);
+                       ip++;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SCALEB)
+                       sp--;
+                       sp [-1].data.f = scalbn (sp [-1].data.f, sp [0].data.i);
+                       ip++;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ILOGB) {
+                       int result;
+                       double x = sp [-1].data.f;
+                       if (FP_ILOGB0 != INT_MIN && x == 0.0)
+                               result = INT_MIN;
+                       else if (FP_ILOGBNAN != INT_MAX && isnan(x))
+                               result = INT_MAX;
+                       else
+                               result = ilogb (x);
+                       sp [-1].data.i = result;
+                       ip++;
+                       MINT_IN_BREAK;
+               }
+
+#define MATH_UNOPF(mathfunc) \
+       sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4); \
+       ++ip;
+
+#define MATH_BINOPF(mathfunc) \
+       sp--; \
+       sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4, sp [0].data.f_r4); \
+       ++ip;
+               MINT_IN_CASE(MINT_ABSF) MATH_UNOPF(fabsf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ASINF) MATH_UNOPF(asinf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ASINHF) MATH_UNOPF(asinhf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ACOSF) MATH_UNOPF(acosf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ACOSHF) MATH_UNOPF(acoshf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ATANF) MATH_UNOPF(atanf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ATANHF) MATH_UNOPF(atanhf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CEILINGF) MATH_UNOPF(ceilf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_COSF) MATH_UNOPF(cosf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CBRTF) MATH_UNOPF(cbrtf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_COSHF) MATH_UNOPF(coshf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_EXPF) MATH_UNOPF(expf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_FLOORF) MATH_UNOPF(floorf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LOGF) MATH_UNOPF(logf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LOG2F) MATH_UNOPF(log2f); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LOG10F) MATH_UNOPF(log10f); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SINF) MATH_UNOPF(sinf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SQRTF) MATH_UNOPF(sqrtf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SINHF) MATH_UNOPF(sinhf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_TANF) MATH_UNOPF(tanf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_TANHF) MATH_UNOPF(tanhf); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_ATAN2F) MATH_BINOPF(atan2f); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_POWF) MATH_BINOPF(powf); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_FMAF)
+                       sp -= 2;
+                       sp [-1].data.f_r4 = fmaf (sp [-1].data.f_r4, sp [0].data.f_r4, sp [1].data.f_r4);
+                       ip++;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SCALEBF)
+                       sp--;
+                       sp [-1].data.f_r4 = scalbnf (sp [-1].data.f_r4, sp [0].data.i);
+                       ip++;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ILOGBF) {
+                       int result;
+                       float x = sp [-1].data.f_r4;
+                       if (FP_ILOGB0 != INT_MIN && x == 0.0)
+                               result = INT_MIN;
+                       else if (FP_ILOGBNAN != INT_MAX && isnan(x))
+                               result = INT_MAX;
+                       else
+                               result = ilogbf (x);
+                       sp [-1].data.i = result;
+                       ip++;
+                       MINT_IN_BREAK;
+               }
+
                MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
                        MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]];
                        mono_interp_enum_hasflag (sp, klass);
index d79bd17..637ccf4 100644 (file)
@@ -762,6 +762,7 @@ OPDEF(MINT_LD_DELEGATE_INVOKE_IMPL, "ld_delegate_invoke_impl", 2, Pop0, Push1, M
 OPDEF(MINT_START_ABORT_PROT, "start_abort_protected", 1, Pop0, Push0, MintOpNoArgs)
 
 // Math intrinsics
+// double
 OPDEF(MINT_ABS, "abs", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ASIN, "asin", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ASINH, "asinh", 1, Pop1, Push1, MintOpNoArgs)
@@ -769,15 +770,54 @@ OPDEF(MINT_ACOS, "acos", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ACOSH, "acosh", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ATAN, "atan", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ATANH, "atanh", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ATAN2, "atan2", 1, Pop2, Push1, MintOpNoArgs)
+OPDEF(MINT_CEILING, "ceiling", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_COS, "cos", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_CBRT, "cbrt", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_COSH, "cosh", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_EXP, "exp", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_FMA, "fma", 1, Pop3, Push1, MintOpNoArgs)
+OPDEF(MINT_FLOOR, "floor", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ILOGB, "ilogb", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_LOG, "log", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_LOG2, "log2", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_LOG10, "log10", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_POW, "pow", 1, Pop2, Push1, MintOpNoArgs)
+OPDEF(MINT_SCALEB, "scaleb", 1, Pop2, Push1, MintOpNoArgs)
 OPDEF(MINT_SIN, "sin", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_SQRT, "sqrt", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_SINH, "sinh", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_TAN, "tan", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_TANH, "tanh", 1, Pop1, Push1, MintOpNoArgs)
 
+// float. These must be kept in the same order as their double counterpart
+OPDEF(MINT_ABSF, "absf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ASINF, "asinf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ASINHF, "asinhf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ACOSF, "acosf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ACOSHF, "acoshf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ATANF, "atanf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ATANHF, "atanhf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ATAN2F, "atan2f", 1, Pop2, Push1, MintOpNoArgs)
+OPDEF(MINT_CEILINGF, "ceilingf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_COSF, "cosf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_CBRTF, "cbrtf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_COSHF, "coshf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_EXPF, "expf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_FMAF, "fmaf", 1, Pop3, Push1, MintOpNoArgs)
+OPDEF(MINT_FLOORF, "floorf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ILOGBF, "ilogbf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_LOGF, "logf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_LOG2F, "log2f", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_LOG10F, "log10f", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_POWF, "powf", 1, Pop2, Push1, MintOpNoArgs)
+OPDEF(MINT_SCALEBF, "scalebf", 1, Pop2, Push1, MintOpNoArgs)
+OPDEF(MINT_SINF, "sinf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_SQRTF, "sqrtf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_SINHF, "sinhf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_TANF, "tanf", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_TANHF, "tanhf", 1, Pop1, Push1, MintOpNoArgs)
+
 OPDEF(MINT_PROF_ENTER, "prof_enter", 2, Pop0, Push0, MintOpNoArgs)
 OPDEF(MINT_PROF_EXIT, "prof_exit", 4, Pop1, Push0, MintOpShortAndInt)
 OPDEF(MINT_PROF_EXIT_VOID, "prof_exit_void", 4, Pop0, Push0, MintOpShortAndInt)
index d3f4bf0..ef209aa 100644 (file)
@@ -1447,45 +1447,82 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
        } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "ByReference`1")) {
                g_assert (!strcmp (tm, "get_Value"));
                *op = MINT_INTRINS_BYREFERENCE_GET_VALUE;
-       } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "Math") && csignature->param_count == 1 && csignature->params [0]->type == MONO_TYPE_R8) {
-               if (tm [0] == 'A') {
-                       if (strcmp (tm, "Abs") == 0 && csignature->params [0]->type == MONO_TYPE_R8) {
-                               *op = MINT_ABS;
-                       } else if (strcmp (tm, "Asin") == 0){
-                               *op = MINT_ASIN;
-                       } else if (strcmp (tm, "Asinh") == 0){
-                               *op = MINT_ASINH;
-                       } else if (strcmp (tm, "Acos") == 0){
-                               *op = MINT_ACOS;
-                       } else if (strcmp (tm, "Acosh") == 0){
-                               *op = MINT_ACOSH;
-                       } else if (strcmp (tm, "Atan") == 0){
-                               *op = MINT_ATAN;
-                       } else if (strcmp (tm, "Atanh") == 0){
-                               *op = MINT_ATANH;
-                       }
-               } else if (tm [0] == 'C') {
-                       if (strcmp (tm, "Cos") == 0) {
-                               *op = MINT_COS;
-                       } else if (strcmp (tm, "Cbrt") == 0){
-                               *op = MINT_CBRT;
-                       } else if (strcmp (tm, "Cosh") == 0){
-                               *op = MINT_COSH;
-                       }
-               } else if (tm [0] == 'S') {
-                       if (strcmp (tm, "Sin") == 0) {
-                               *op = MINT_SIN;
-                       } else if (strcmp (tm, "Sqrt") == 0) {
-                               *op = MINT_SQRT;
-                       } else if (strcmp (tm, "Sinh") == 0){
-                               *op = MINT_SINH;
-                       }
-               } else if (tm [0] == 'T') {
-                       if (strcmp (tm, "Tan") == 0) {
-                               *op = MINT_TAN;
-                       } else if (strcmp (tm, "Tanh") == 0){
-                               *op = MINT_TANH;
+       } else if (in_corlib && !strcmp (klass_name_space, "System") &&
+                       (!strcmp (klass_name, "Math") || !strcmp (klass_name, "MathF"))) {
+               gboolean is_float = strcmp (klass_name, "MathF") == 0;
+               int param_type = is_float ? MONO_TYPE_R4 : MONO_TYPE_R8;
+               // FIXME add also intrinsic for Round
+               if (csignature->param_count == 1 && csignature->params [0]->type == param_type) {
+                       // unops
+                       if (tm [0] == 'A') {
+                               if (strcmp (tm, "Abs") == 0) {
+                                       *op = MINT_ABS;
+                               } else if (strcmp (tm, "Asin") == 0){
+                                       *op = MINT_ASIN;
+                               } else if (strcmp (tm, "Asinh") == 0){
+                                       *op = MINT_ASINH;
+                               } else if (strcmp (tm, "Acos") == 0){
+                                       *op = MINT_ACOS;
+                               } else if (strcmp (tm, "Acosh") == 0){
+                                       *op = MINT_ACOSH;
+                               } else if (strcmp (tm, "Atan") == 0){
+                                       *op = MINT_ATAN;
+                               } else if (strcmp (tm, "Atanh") == 0){
+                                       *op = MINT_ATANH;
+                               }
+                       } else if (tm [0] == 'C') {
+                               if (strcmp (tm, "Ceiling") == 0) {
+                                       *op = MINT_CEILING;
+                               } else if (strcmp (tm, "Cos") == 0) {
+                                       *op = MINT_COS;
+                               } else if (strcmp (tm, "Cbrt") == 0){
+                                       *op = MINT_CBRT;
+                               } else if (strcmp (tm, "Cosh") == 0){
+                                       *op = MINT_COSH;
+                               }
+                       } else if (strcmp (tm, "Exp") == 0) {
+                               *op = MINT_EXP;
+                       } else if (strcmp (tm, "Floor") == 0) {
+                               *op = MINT_FLOOR;
+                       } else if (strcmp (tm, "ILogB") == 0) {
+                               *op = MINT_ILOGB;
+                       } else if (tm [0] == 'L') {
+                               if (strcmp (tm, "Log") == 0) {
+                                       *op = MINT_LOG;
+                               } else if (strcmp (tm, "Log2") == 0) {
+                                       *op = MINT_LOG2;
+                               } else if (strcmp (tm, "Log10") == 0) {
+                                       *op = MINT_LOG10;
+                               }
+                       } else if (tm [0] == 'S') {
+                               if (strcmp (tm, "Sin") == 0) {
+                                       *op = MINT_SIN;
+                               } else if (strcmp (tm, "Sqrt") == 0) {
+                                       *op = MINT_SQRT;
+                               } else if (strcmp (tm, "Sinh") == 0){
+                                       *op = MINT_SINH;
+                               }
+                       } else if (tm [0] == 'T') {
+                               if (strcmp (tm, "Tan") == 0) {
+                                       *op = MINT_TAN;
+                               } else if (strcmp (tm, "Tanh") == 0){
+                                       *op = MINT_TANH;
+                               }
                        }
+               } else if (csignature->param_count == 2 && csignature->params [0]->type == param_type && csignature->params [1]->type == param_type) {
+                       if (strcmp (tm, "Atan2") == 0)
+                               *op = MINT_ATAN2;
+                       else if (strcmp (tm, "Pow") == 0)
+                               *op = MINT_POW;
+               } else if (csignature->param_count == 3 && csignature->params [0]->type == param_type && csignature->params [1]->type == param_type && csignature->params [2]->type == param_type) {
+                       if (strcmp (tm, "FusedMultiplyAdd") == 0)
+                               *op = MINT_FMA;
+               } else if (csignature->param_count == 2 && csignature->params [0]->type == param_type && csignature->params [1]->type == MONO_TYPE_I4 && strcmp (tm, "ScaleB") == 0) {
+                       *op = MINT_SCALEB;
+               }
+
+               if (*op != -1 && is_float) {
+                       *op = *op + (MINT_ABSF - MINT_ABS);
                }
        } else if (in_corlib && !strcmp (klass_name_space, "System") && (!strcmp (klass_name, "Span`1") || !strcmp (klass_name, "ReadOnlySpan`1"))) {
                if (!strcmp (tm, "get_Item")) {