[interpreter] add floating point support to icall trampoline, add basic-math.cs to...
authorBernhard Urban <bernhard.urban@xamarin.com>
Mon, 27 Feb 2017 16:55:54 +0000 (17:55 +0100)
committerBernhard Urban <bernhard.urban@xamarin.com>
Tue, 28 Feb 2017 21:59:28 +0000 (22:59 +0100)
mono/mini/Makefile.am.in
mono/mini/interpreter/interp.c
mono/mini/tramp-amd64.c

index a76cd6ac6ee5638d1271cd4af4cb8c9b8e5ad313..b82a4560ca398affb0784ae939ece03950aac689 100755 (executable)
@@ -536,6 +536,7 @@ iregtests = \
        basic-calls.exe \
        objects.exe \
        arrays.exe \
+       basic-math.exe \
        generics.exe
 
 if X86
index 6693cbd6d312833e63288e4b4da315149bef4f5e..e604233bec0e86cf9dca044dfa24597b21b33a83 100644 (file)
@@ -733,8 +733,9 @@ struct _MethodArguments {
        size_t ilen;
        gpointer *iargs;
        size_t flen;
-       gpointer *fargs;
+       double *fargs;
        gpointer *retval;
+       size_t is_float_ret;
 };
 
 typedef struct _MethodArguments MethodArguments;
@@ -771,6 +772,9 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
                case MONO_TYPE_GENERICINST:
                        margs->ilen++;
                        break;
+               case MONO_TYPE_R8:
+                       margs->flen++;
+                       break;
                default:
                        g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
                }
@@ -779,14 +783,18 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
        if (margs->ilen > 0)
                margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
 
+       if (margs->flen > 0)
+               margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
+
        if (margs->ilen > 6)
-               g_error ("build_args_from_sig: TODO, more than 6 iregs: %d\n", margs->ilen);
+               g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
 
-       if (margs->flen > 0)
-               g_error ("build_args_from_sig: TODO, allocate floats: %d\n", margs->flen);
+       if (margs->flen > 3)
+               g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
 
 
        size_t int_i = 0;
+       size_t int_f = 0;
 
        if (sig->hasthis) {
                margs->iargs [0] = frame->stack_args->data.p;
@@ -820,15 +828,45 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
 #endif
                        int_i++;
                        break;
+               case MONO_TYPE_R8:
+                       margs->fargs [int_f] = frame->stack_args [i].data.f;
+                       int_f++;
+                       break;
                default:
                        g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
                }
        }
 
-       if (sig->ret->type != MONO_TYPE_VOID) {
-               margs->retval = &(frame->retval->data.p);
-       } else {
-               margs->retval = NULL;
+       switch (sig->ret->type) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_STRING:
+               case MONO_TYPE_I8:
+               case MONO_TYPE_VALUETYPE:
+               case MONO_TYPE_GENERICINST:
+                       margs->retval = &(frame->retval->data.p);
+                       break;
+               case MONO_TYPE_R8:
+                       margs->retval = &(frame->retval->data.p);
+                       margs->is_float_ret = 1;
+                       break;
+               case MONO_TYPE_VOID:
+                       margs->retval = NULL;
+                       break;
+               default:
+                       g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
        }
 
        return margs;
index b143645fb7d83c9d70d04ac4e9f6d2f9d81b9ded..68ea4b323a0c6a41b77df19fdb83bd673c31734f 100644 (file)
@@ -983,10 +983,12 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
 {
 #ifdef ENABLE_INTERPRETER
        const int gregs_num = 6;
-       guint8 *start = NULL, *code, *exits [gregs_num], *leave_tramp;
+       const int fregs_num = 3;
+       guint8 *start = NULL, *code, *label_gexits [gregs_num], *label_fexits [fregs_num], *label_leave_tramp [3], *label_is_float_ret;
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops = NULL;
-       static int arg_regs[] = {AMD64_ARG_REG1, AMD64_ARG_REG2, AMD64_ARG_REG3, AMD64_ARG_REG4, AMD64_R8, AMD64_R9};
+       static int garg_regs[] = {AMD64_ARG_REG1, AMD64_ARG_REG2, AMD64_ARG_REG3, AMD64_ARG_REG4, AMD64_R8, AMD64_R9};
+       static int farg_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD64_XMM2};
        int i, offset = 0;
 
        start = code = (guint8 *) mono_global_codeman_reserve (256);
@@ -1002,6 +1004,26 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, 8);
        
        /* TODO: do float stuff first */
+       /* move flen into RAX */ // TODO: struct offset
+       amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 16, 8);
+       /* load pointer to fregs into R11 */ // TODO: struct offset
+       amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 24, 8);
+
+       for (i = 0; i < fregs_num; ++i) {
+               amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
+               label_fexits [i] = code;
+               x86_branch8 (code, X86_CC_Z, 0, FALSE);
+
+               amd64_sse_movsd_reg_membase (code, farg_regs [i], AMD64_R11, i * sizeof (double));
+               amd64_dec_reg_size (code, AMD64_RAX, 1);
+       }
+
+       for (i = 0; i < fregs_num; i++) {
+               x86_patch (label_fexits [i], code);
+       }
+
+       /* load pointer to MethodArguments* into R11 */
+       amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, 8);
 
        /* move ilen into RAX */ // TODO: struct offset
        amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 0, 8);
@@ -1010,7 +1032,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
 
        for (i = 0; i < gregs_num; i++) {
                amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
-               exits [i] = code;
+               label_gexits [i] = code;
                x86_branch8 (code, X86_CC_Z, 0, FALSE);
 
 #ifdef TARGET_WIN32
@@ -1018,7 +1040,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
 #else
                if (i < 6) {
 #endif
-                       amd64_mov_reg_membase (code, arg_regs [i], AMD64_R11, i * sizeof (gpointer), 8);
+                       amd64_mov_reg_membase (code, garg_regs [i], AMD64_R11, i * sizeof (gpointer), 8);
                } else {
                        g_error ("not tested yet.");
                        amd64_push_reg (code, AMD64_RAX);
@@ -1031,7 +1053,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        }
 
        for (i = 0; i < gregs_num; i++) {
-               x86_patch (exits [i], code);
+               x86_patch (label_gexits [i], code);
        }
 
 
@@ -1041,21 +1063,56 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        /* call into native function */
        amd64_call_reg (code, AMD64_R11);
 
+       /* load MethodArguments */
+       amd64_pop_reg (code, AMD64_R11);
+       amd64_push_reg (code, AMD64_R11);
+
+       /* load is_float_ret */ // TODO: struct offset
+       amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x28, 8);
+
+       /* check if a float return value is expected */
+       amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
+
+       label_is_float_ret = code;
+       x86_branch8 (code, X86_CC_NZ, 0, FALSE);
+
+
+
+       /* greg return */
        /* load MethodArguments */
        amd64_pop_reg (code, AMD64_R11);
        /* load retval */ // TODO: struct offset
        amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x20, 8);
 
        amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
-       leave_tramp = code;
+       label_leave_tramp [0] = code;
        x86_branch8 (code, X86_CC_Z, 0, FALSE);
 
        amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RAX, 8);
 
-       x86_patch (leave_tramp, code);
-       amd64_ret (code);
+       label_leave_tramp [1] = code;
+       x86_jump8 (code, 0);
+
 
 
+       /* freg return */
+       x86_patch (label_is_float_ret, code);
+       /* load MethodArguments */
+       amd64_pop_reg (code, AMD64_R11);
+       /* load retval */ // TODO: struct offset
+       amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x20, 8);
+
+       amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
+       label_leave_tramp [2] = code;
+       x86_branch8 (code, X86_CC_Z, 0, FALSE);
+
+       amd64_sse_movsd_membase_reg (code, AMD64_R11, 0, AMD64_XMM0);
+
+
+       for (i = 0; i < 3; i++)
+               x86_patch (label_leave_tramp [i], code);
+       amd64_ret (code);
+
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);