[llvm] Use a separate calling convention for gsharedvt methods in llvmonly mode,...
authorZoltan Varga <vargaz@gmail.com>
Tue, 8 Dec 2015 22:12:13 +0000 (17:12 -0500)
committerZoltan Varga <vargaz@gmail.com>
Tue, 8 Dec 2015 22:12:28 +0000 (17:12 -0500)
mono/mini/mini-llvm.c
mono/mini/mini-llvm.h
mono/mini/mini.h

index c8694f83f8780de216bbcb66d8787389ca2f75ce..c608faa5ce694c120655d18b5d8de285c0d7a753 100644 (file)
@@ -1269,6 +1269,8 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                break;
        case LLVMArgVtypeRetAddr:
        case LLVMArgScalarRetAddr:
+       case LLVMArgGsharedvtFixed:
+       case LLVMArgGsharedvtVariable:
                vretaddr = TRUE;
                ret_type = LLVMVoidType ();
                break;
@@ -1379,6 +1381,10 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                case LLVMArgVtypeAsScalar:
                        g_assert_not_reached ();
                        break;
+               case LLVMArgGsharedvtFixed:
+               case LLVMArgGsharedvtVariable:
+                       param_types [pindex ++] = LLVMPointerType (type_to_llvm_arg_type (ctx, ainfo->type), 0);
+                       break;
                default:
                        param_types [pindex ++] = type_to_llvm_arg_type (ctx, ainfo->type);
                        break;
@@ -2792,6 +2798,22 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                case LLVMArgVtypeAsScalar:
                        g_assert_not_reached ();
                        break;
+               case LLVMArgGsharedvtFixed: {
+                       /* These are non-gsharedvt arguments passed by ref, the rest of the IR treats them as scalars */
+                       LLVMValueRef arg = LLVMGetParam (ctx->lmethod, pindex);
+
+                       if (names [i])
+                               name = g_strdup_printf ("arg_%s", names [i]);
+                       else
+                               name = g_strdup_printf ("arg_%d", i);
+
+                       ctx->values [reg] = LLVMBuildLoad (builder, convert (ctx, arg, LLVMPointerType (type_to_llvm_type (ctx, ainfo->type), 0)), name);
+                       break;
+               }
+               case LLVMArgGsharedvtVariable:
+                       /* The IR treats these as variables with addresses */
+                       ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, pindex);
+                       break;
                default:
                        ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, ainfo->type)), type_is_unsigned (ctx, ainfo->type));
                        break;
@@ -2936,7 +2958,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        if (call->imt_arg_reg)
                cinfo->imt_arg = TRUE;
 
-       vretaddr = (cinfo->ret.storage == LLVMArgVtypeRetAddr || cinfo->ret.storage == LLVMArgVtypeByRef || cinfo->ret.storage == LLVMArgScalarRetAddr);
+       vretaddr = (cinfo->ret.storage == LLVMArgVtypeRetAddr || cinfo->ret.storage == LLVMArgVtypeByRef || cinfo->ret.storage == LLVMArgScalarRetAddr || cinfo->ret.storage == LLVMArgGsharedvtFixed || cinfo->ret.storage == LLVMArgGsharedvtVariable);
 
        llvm_sig = sig_to_llvm_sig_full (ctx, sig, cinfo);
        CHECK_FAILURE (ctx);
@@ -3232,6 +3254,10 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                /* Normal scalar returned using a vtype return argument */
                values [ins->dreg] = LLVMBuildLoad (builder, convert_full (ctx, addresses [call->inst.dreg], LLVMPointerType (type_to_llvm_type (ctx, sig->ret), 0), FALSE), "");
                break;
+       case LLVMArgGsharedvtFixed:
+       case LLVMArgGsharedvtVariable:
+               g_assert_not_reached ();
+               break;
        default:
                if (sig->ret->type != MONO_TYPE_VOID)
                        /* If the method returns an unsigned value, need to zext it */
@@ -3968,6 +3994,21 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                LLVMBuildRetVoid (builder);
                                break;
                        }
+                       case LLVMArgGsharedvtFixed: {
+                               LLVMTypeRef ret_type = type_to_llvm_type (ctx, sig->ret);
+                               /* The return value is in lhs, need to store to the vret argument */
+                               g_assert (lhs);
+                               g_assert (cfg->vret_addr);
+                               g_assert (values [cfg->vret_addr->dreg]);
+                               LLVMBuildStore (builder, convert (ctx, lhs, ret_type), convert (ctx, values [cfg->vret_addr->dreg], LLVMPointerType (ret_type, 0)));
+                               LLVMBuildRetVoid (builder);
+                               break;
+                       }
+                       case LLVMArgGsharedvtVariable: {
+                               /* Already set */
+                               LLVMBuildRetVoid (builder);
+                               break;
+                       }
                        case LLVMArgVtypeRetAddr: {
                                LLVMBuildRetVoid (builder);
                                break;
@@ -6011,6 +6052,46 @@ get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
        LLVMCallInfo *linfo;
        int i;
 
+       if (cfg->gsharedvt && cfg->llvm_only && mini_is_gsharedvt_variable_signature (sig)) {
+               int i, n, pindex;
+
+               /*
+                * Gsharedvt methods have the following calling convention:
+                * - all arguments are passed by ref, even non generic ones
+                * - the return value is returned by ref too, using a vret
+                *   argument passed after 'this'.
+                */
+               n = sig->param_count + sig->hasthis;
+               linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
+
+               pindex = 0;
+               if (sig->hasthis)
+                       linfo->args [pindex ++].storage = LLVMArgNormal;
+
+               if (sig->ret->type != MONO_TYPE_VOID) {
+                       if (mini_is_gsharedvt_variable_type (sig->ret))
+                               linfo->ret.storage = LLVMArgGsharedvtVariable;
+                       else
+                               linfo->ret.storage = LLVMArgGsharedvtFixed;
+                       linfo->vret_arg_index = pindex;
+               } else {
+                       linfo->ret.storage = LLVMArgNone;
+               }
+
+               for (i = 0; i < sig->param_count; ++i) {
+                       if (sig->params [i]->byref)
+                               linfo->args [pindex].storage = LLVMArgNormal;
+                       else if (mini_is_gsharedvt_variable_type (sig->params [i]))
+                               linfo->args [pindex].storage = LLVMArgGsharedvtVariable;
+                       else
+                               linfo->args [pindex].storage = LLVMArgGsharedvtFixed;
+                       linfo->args [pindex].type = sig->params [i];
+                       pindex ++;
+               }
+               return linfo;
+       }
+
+
        linfo = mono_arch_get_llvm_call_info (cfg, sig);
        for (i = 0; i < sig->param_count; ++i)
                linfo->args [i + sig->hasthis].type = sig->params [i];
@@ -6207,6 +6288,11 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                name = g_strdup_printf ("p_arg_%s", names [i]);
                        else
                                name = g_strdup_printf ("p_arg_%d", i);
+               } else if (ainfo->storage == LLVMArgGsharedvtFixed) {
+                       if (names [i] && names [i][0] != '\0')
+                               name = g_strdup_printf ("p_arg_%s", names [i]);
+                       else
+                               name = g_strdup_printf ("p_arg_%d", i);
                } else {
                        if (names [i] && names [i][0] != '\0')
                                name = g_strdup_printf ("arg_%s", names [i]);
@@ -6588,6 +6674,30 @@ mono_llvm_emit_method (MonoCompile *cfg)
        mono_loader_unlock ();
 }
 
+/*
+ * mono_llvm_create_vars:
+ *
+ *   Same as mono_arch_create_vars () for LLVM.
+ */
+void
+mono_llvm_create_vars (MonoCompile *cfg)
+{
+       MonoMethodSignature *sig;
+
+       sig = mono_method_signature (cfg->method);
+       if (cfg->gsharedvt && cfg->llvm_only) {
+               if (mini_is_gsharedvt_variable_signature (sig) && sig->ret->type != MONO_TYPE_VOID) {
+                       cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
+                       if (G_UNLIKELY (cfg->verbose_level > 1)) {
+                               printf ("vret_addr = ");
+                               mono_print_ins (cfg->vret_addr);
+                       }
+               }
+       } else {
+               mono_arch_create_vars (cfg);
+       }
+}
+
 /*
  * mono_llvm_emit_call:
  *
index 3e36b0a9bc087893ae42ef364bc79e94230a497a..bf7bdb0e4d4e803ae65620e51f692c3285205322 100644 (file)
@@ -26,6 +26,7 @@ void     mono_llvm_clear_exception (void);
 MonoObject *mono_llvm_load_exception (void);
 void     mono_llvm_reset_exception (void);
 void     mono_llvm_raise_exception (MonoException *e);
+void     mono_llvm_create_vars (MonoCompile *cfg);
 
 gboolean mini_llvm_init                     (void);
 
index 8978cdef2636a9d1870a99ebd554a163f047eb82..06b86f5b7f1ee7d85224d8826e2b9a88424d4012 100644 (file)
@@ -741,6 +741,10 @@ typedef enum {
        LLVMArgVtypeByVal,
        LLVMArgVtypeRetAddr, /* On on cinfo->ret */
        LLVMArgGSharedVt,
+       /* Fixed sized argument passed to/returned from gsharedvt method by ref */
+       LLVMArgGsharedvtFixed,
+       /* Variable sized argument passed to/returned from gsharedvt method by ref */
+       LLVMArgGsharedvtVariable,
        /* Vtype passed as one int array argument */
        LLVMArgAsIArgs,
        /* Vtype passed as a set of fp arguments */