2015-12-16 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Wed, 16 Dec 2015 19:05:39 +0000 (14:05 -0500)
committerZoltan Varga <vargaz@gmail.com>
Wed, 16 Dec 2015 19:11:28 +0000 (14:11 -0500)
Add beginnings for support for gsharedvt in llvmonly mode. Gsharedvt methods use a calling convention
where everything is passed and returned by ref, even normal types. I.e.

public int foo<T> (T t, int i);

becomes:

void foo (int *vret, T* t_addr, int *i_addr);

Not enabled yet.

* mini-llvm.c: Implement support for gsharedvt.

* ssa.c (mono_ssa_remove_gsharedvt): Same as mono_ssa_remove (), but only remove the
OP_VPHI nodes referencing gsharedvt variables, since they cannot be handled by the
llvm backend.

* mini-llvm.c (mono_llvm_create_vars): New backend function, similar to mono_arch_create_vars ().

* decompose.c (mono_decompose_vtype_opts): Decompose more opcodes in llvm mode so
opcodes using gsharedvt variables don't reach the llvm backend. Some, like OP_LDADDR and
vcalls, still do.

* method-to-ir.c (mono_allocate_gsharedvt_vars): New function to allocate gsharedvt locals,
extracted from mono_spill_global_vars () so it can be used in llvm mode too.

mono/mini/decompose.c
mono/mini/method-to-ir.c
mono/mini/mini-llvm.c
mono/mini/mini.c
mono/mini/mini.h
mono/mini/ssa.c

index 2dfff74b4fb6fbdf28dd94741eaef82865c8c795..2899a1e91838ffda2f0a30771e3a01e09f2b7e61 100644 (file)
@@ -1243,7 +1243,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        break;
                                }
                                case OP_VZERO:
-                                       if (COMPILE_LLVM (cfg))
+                                       if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
                                                break;
 
                                        g_assert (ins->klass);
@@ -1321,9 +1321,6 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                case OP_OUTARG_VTRETADDR: {
                                        MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
 
-                                       if (COMPILE_LLVM (cfg))
-                                               break;
-
                                        src_var = get_vreg_to_inst (cfg, call->inst.dreg);
                                        if (!src_var)
                                                src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
index a337597dae3a7ef306f7dcdc50e9b3c8bafd0758..a09bfe2f4033b09436e6135f96477d4ee69cadba 100644 (file)
@@ -13946,6 +13946,39 @@ mono_handle_global_vregs (MonoCompile *cfg)
                cfg->locals_start = cfg->num_varinfo;
 }
 
+/*
+ * mono_allocate_gsharedvt_vars:
+ *
+ *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
+ * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
+ */
+void
+mono_allocate_gsharedvt_vars (MonoCompile *cfg)
+{
+       int i;
+
+       cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
+
+       for (i = 0; i < cfg->num_varinfo; ++i) {
+               MonoInst *ins = cfg->varinfo [i];
+               int idx;
+
+               if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
+                       if (i >= cfg->locals_start) {
+                               /* Local */
+                               idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
+                               cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
+                               ins->opcode = OP_GSHAREDVT_LOCAL;
+                               ins->inst_imm = idx;
+                       } else {
+                               /* Arg */
+                               cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
+                               ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
+                       }
+               }
+       }
+}
+
 /**
  * mono_spill_global_vars:
  *
@@ -13966,7 +13999,6 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        MonoStackType stacktypes [128];
        MonoInst **live_range_start, **live_range_end;
        MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
-       int *gsharedvt_vreg_to_idx = NULL;
 
        *need_local_opts = FALSE;
 
@@ -14025,29 +14057,6 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                ins->flags |= MONO_INST_GC_TRACK;
                }
        }
-
-       if (cfg->gsharedvt) {
-               gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
-
-               for (i = 0; i < cfg->num_varinfo; ++i) {
-                       MonoInst *ins = cfg->varinfo [i];
-                       int idx;
-
-                       if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
-                               if (i >= cfg->locals_start) {
-                                       /* Local */
-                                       idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
-                                       gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
-                                       ins->opcode = OP_GSHAREDVT_LOCAL;
-                                       ins->inst_imm = idx;
-                               } else {
-                                       /* Arg */
-                                       gsharedvt_vreg_to_idx [ins->dreg] = -1;
-                                       ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
-                               }
-                       }
-               }
-       }
                
        /* FIXME: widening and truncation */
 
@@ -14124,16 +14133,16 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                ins->inst_offset = vtaddr->inst_offset;
                                        } else
                                                NOT_IMPLEMENTED;
-                               } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
+                               } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
                                        /* gsharedvt arg passed by ref */
                                        g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
 
                                        ins->opcode = OP_LOAD_MEMBASE;
                                        ins->inst_basereg = var->inst_basereg;
                                        ins->inst_offset = var->inst_offset;
-                               } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
+                               } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
                                        MonoInst *load, *load2, *load3;
-                                       int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
+                                       int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
                                        int reg1, reg2, reg3;
                                        MonoInst *info_var = cfg->gsharedvt_info_var;
                                        MonoInst *locals_var = cfg->gsharedvt_locals_var;
index c608faa5ce694c120655d18b5d8de285c0d7a753..8cbd01305f708e80256af5847d985c13b5fd5ed6 100644 (file)
@@ -11,6 +11,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/object-internals.h>
+#include <mono/metadata/abi-details.h>
 #include <mono/utils/mono-tls.h>
 #include <mono/utils/mono-dl.h>
 #include <mono/utils/mono-time.h>
@@ -522,6 +523,9 @@ type_to_llvm_arg_type (EmitContext *ctx, MonoType *t)
 {
        LLVMTypeRef ptype = type_to_llvm_type (ctx, t);
 
+       if (ctx->cfg->llvm_only)
+               return ptype;
+
        /*
         * This works on all abis except arm64/ios which passes multiple
         * arguments in one stack slot.
@@ -1270,6 +1274,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
        case LLVMArgVtypeRetAddr:
        case LLVMArgScalarRetAddr:
        case LLVMArgGsharedvtFixed:
+       case LLVMArgGsharedvtFixedVtype:
        case LLVMArgGsharedvtVariable:
                vretaddr = TRUE;
                ret_type = LLVMVoidType ();
@@ -1382,9 +1387,12 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                        g_assert_not_reached ();
                        break;
                case LLVMArgGsharedvtFixed:
-               case LLVMArgGsharedvtVariable:
+               case LLVMArgGsharedvtFixedVtype:
                        param_types [pindex ++] = LLVMPointerType (type_to_llvm_arg_type (ctx, ainfo->type), 0);
                        break;
+               case LLVMArgGsharedvtVariable:
+                       param_types [pindex ++] = LLVMPointerType (IntPtrType (), 0);
+                       break;
                default:
                        param_types [pindex ++] = type_to_llvm_arg_type (ctx, ainfo->type);
                        break;
@@ -1511,6 +1519,11 @@ get_aotconst_name (MonoJumpInfoType type, gconstpointer data, int got_offset)
        case MONO_PATCH_INFO_INTERNAL_METHOD:
                name = g_strdup_printf ("jit_icall_%s", data);
                break;
+       case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
+               MonoJumpInfoRgctxEntry *entry = (MonoJumpInfoRgctxEntry*)data;
+               name = g_strdup_printf ("RGCTX_SLOT_INDEX_%s", mono_rgctx_info_type_to_str (entry->info_type));
+               break;
+       }
        default:
                name = g_strdup_printf ("%s_%d", mono_ji_type_to_string (type), got_offset);
                break;
@@ -1520,7 +1533,7 @@ get_aotconst_name (MonoJumpInfoType type, gconstpointer data, int got_offset)
 }
 
 static LLVMValueRef
-get_aotconst (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data)
+get_aotconst_typed (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data, LLVMTypeRef llvm_type)
 {
        MonoCompile *cfg;
        guint32 got_offset;
@@ -1558,21 +1571,30 @@ get_aotconst (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data)
        got_entry_addr = LLVMBuildGEP (builder, ctx->module->got_var, indexes, 2, "");
 
        name = get_aotconst_name (type, data, got_offset);
-       load = LLVMBuildLoad (builder, got_entry_addr, name ? name : "");
+       if (llvm_type) {
+               load = convert (ctx, LLVMBuildLoad (builder, got_entry_addr, ""), llvm_type);
+               LLVMSetValueName (load, name ? name : "");
+       } else {
+               load = LLVMBuildLoad (builder, got_entry_addr, name ? name : "");
+       }
        g_free (name);
        //set_invariant_load_flag (load);
 
        return load;
 }
 
+static LLVMValueRef
+get_aotconst (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data)
+{
+       return get_aotconst_typed (ctx, type, data, NULL);
+}
+
 static LLVMValueRef
 get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gconstpointer data)
 {
        LLVMValueRef callee;
        char *callee_name;
        if (ctx->llvm_only) {
-               LLVMValueRef load;
-
                callee_name = mono_aot_get_direct_call_symbol (type, data);
                if (callee_name) {
                        /* Directly callable */
@@ -1593,9 +1615,7 @@ get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gcons
                /*
                 * Calls are made through the GOT.
                 */
-               load = get_aotconst (ctx, type, data);
-
-               return convert (ctx, load, LLVMPointerType (llvm_sig, 0));
+               return get_aotconst_typed (ctx, type, data, LLVMPointerType (llvm_sig, 0));
        } else {
                MonoJumpInfo *ji = NULL;
 
@@ -2201,6 +2221,8 @@ build_alloca (EmitContext *ctx, MonoType *t)
        MonoClass *k = mono_class_from_mono_type (t);
        int align;
 
+       g_assert (!mini_is_gsharedvt_variable_type (t));
+
        if (MONO_CLASS_IS_SIMD (ctx->cfg, k))
                align = 16;
        else
@@ -2213,6 +2235,35 @@ build_alloca (EmitContext *ctx, MonoType *t)
        return build_alloca_llvm_type (ctx, type_to_llvm_type (ctx, t), align);
 }
 
+static LLVMValueRef
+emit_gsharedvt_ldaddr (EmitContext *ctx, int vreg)
+{
+       /*
+        * gsharedvt local.
+        * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
+        */
+       MonoCompile *cfg = ctx->cfg;
+       LLVMBuilderRef builder = ctx->builder;
+       LLVMValueRef offset, offset_var;
+       LLVMValueRef info_var = ctx->values [cfg->gsharedvt_info_var->dreg];
+       LLVMValueRef locals_var = ctx->values [cfg->gsharedvt_locals_var->dreg];
+       LLVMValueRef ptr;
+       char *name;
+
+       g_assert (info_var);
+       g_assert (locals_var);
+
+       int idx = cfg->gsharedvt_vreg_to_idx [vreg] - 1;
+
+       offset = LLVMConstInt (LLVMInt32Type (), MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)), FALSE);
+       ptr = LLVMBuildAdd (builder, convert (ctx, info_var, IntPtrType ()), convert (ctx, offset, IntPtrType ()), "");
+
+       name = g_strdup_printf ("gsharedvt_local_%d_offset", vreg);
+       offset_var = LLVMBuildLoad (builder, convert (ctx, ptr, LLVMPointerType (LLVMInt32Type (), 0)), name);
+
+       return LLVMBuildAdd (builder, convert (ctx, locals_var, IntPtrType ()), convert (ctx, offset_var, IntPtrType ()), "");
+}
+
 /*
  * Put the global into the 'llvm.used' array to prevent it from being optimized away.
  */
@@ -2591,7 +2642,6 @@ emit_init_method (EmitContext *ctx)
        MonoCompile *cfg = ctx->cfg;
 
        ctx->module->max_inited_idx = MAX (ctx->module->max_inited_idx, cfg->method_index);
-       ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index);
 
        indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
        indexes [1] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, FALSE);
@@ -2716,7 +2766,8 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                MonoInst *var = cfg->varinfo [i];
                LLVMTypeRef vtype;
 
-               if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (mini_type_is_vtype (var->inst_vtype) && !MONO_CLASS_IS_SIMD (ctx->cfg, var->klass))) {
+               if (var->opcode == OP_GSHAREDVT_LOCAL || var->opcode == OP_GSHAREDVT_ARG_REGOFFSET) {
+               } else if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (mini_type_is_vtype (var->inst_vtype) && !MONO_CLASS_IS_SIMD (ctx->cfg, var->klass))) {
                        vtype = type_to_llvm_type (ctx, var->inst_vtype);
                        CHECK_FAILURE (ctx);
                        /* Could be already created by an OP_VPHI */
@@ -2810,6 +2861,20 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                        ctx->values [reg] = LLVMBuildLoad (builder, convert (ctx, arg, LLVMPointerType (type_to_llvm_type (ctx, ainfo->type), 0)), name);
                        break;
                }
+               case LLVMArgGsharedvtFixedVtype: {
+                       LLVMValueRef arg = LLVMGetParam (ctx->lmethod, pindex);
+
+                       if (names [i])
+                               name = g_strdup_printf ("vtype_arg_%s", names [i]);
+                       else
+                               name = g_strdup_printf ("vtype_arg_%d", i);
+
+                       /* Non-gsharedvt vtype argument passed by ref, the rest of the IR treats it as a vtype */
+                       g_assert (ctx->addresses [reg]);
+                       LLVMSetValueName (ctx->addresses [reg], name);
+                       LLVMBuildStore (builder, LLVMBuildLoad (builder, convert (ctx, arg, LLVMPointerType (type_to_llvm_type (ctx, ainfo->type), 0)), ""), ctx->addresses [reg]);
+                       break;
+               }
                case LLVMArgGsharedvtVariable:
                        /* The IR treats these as variables with addresses */
                        ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, pindex);
@@ -2958,7 +3023,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 || cinfo->ret.storage == LLVMArgGsharedvtFixed || cinfo->ret.storage == LLVMArgGsharedvtVariable);
+       vretaddr = (cinfo->ret.storage == LLVMArgVtypeRetAddr || cinfo->ret.storage == LLVMArgVtypeByRef || cinfo->ret.storage == LLVMArgScalarRetAddr || cinfo->ret.storage == LLVMArgGsharedvtFixed || cinfo->ret.storage == LLVMArgGsharedvtVariable || cinfo->ret.storage == LLVMArgGsharedvtFixedVtype);
 
        llvm_sig = sig_to_llvm_sig_full (ctx, sig, cinfo);
        CHECK_FAILURE (ctx);
@@ -2997,7 +3062,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                        }
                }
 
-               if (call->method && strstr (call->method->klass->name, "AsyncVoidMethodBuilder"))
+               if (!cfg->llvm_only && call->method && strstr (call->method->klass->name, "AsyncVoidMethodBuilder"))
                        /* LLVM miscompiles async methods */
                        LLVM_FAILURE (ctx, "#13734");
        } else if (calli) {
@@ -3115,14 +3180,29 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                args [cinfo->imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->module->ptr_type);
 #endif
        }
-       if (vretaddr) {
-               if (!addresses [call->inst.dreg])
-                       addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
-               g_assert (cinfo->vret_arg_pindex < nargs);
-               if (cinfo->ret.storage == LLVMArgVtypeByRef)
+       switch (cinfo->ret.storage) {
+       case LLVMArgGsharedvtVariable: {
+               MonoInst *var = get_vreg_to_inst (cfg, call->inst.dreg);
+
+               if (var && var->opcode == OP_GSHAREDVT_LOCAL) {
+                       args [cinfo->vret_arg_pindex] = convert (ctx, emit_gsharedvt_ldaddr (ctx, var->dreg), IntPtrType ());
+               } else {
+                       g_assert (addresses [call->inst.dreg]);
                        args [cinfo->vret_arg_pindex] = addresses [call->inst.dreg];
-               else
-                       args [cinfo->vret_arg_pindex] = LLVMBuildPtrToInt (builder, addresses [call->inst.dreg], IntPtrType (), "");
+               }
+               break;
+       }
+       default:
+               if (vretaddr) {
+                       if (!addresses [call->inst.dreg])
+                               addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+                       g_assert (cinfo->vret_arg_pindex < nargs);
+                       if (cinfo->ret.storage == LLVMArgVtypeByRef)
+                               args [cinfo->vret_arg_pindex] = addresses [call->inst.dreg];
+                       else
+                               args [cinfo->vret_arg_pindex] = LLVMBuildPtrToInt (builder, addresses [call->inst.dreg], IntPtrType (), "");
+               }
+               break;
        }
 
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
@@ -3165,6 +3245,15 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                case LLVMArgVtypeAsScalar:
                        g_assert_not_reached ();
                        break;
+               case LLVMArgGsharedvtFixed:
+               case LLVMArgGsharedvtFixedVtype:
+                       g_assert (addresses [reg]);
+                       args [pindex] = addresses [reg];
+                       break;
+               case LLVMArgGsharedvtVariable:
+                       g_assert (addresses [reg]);
+                       args [pindex] = convert (ctx, addresses [reg], LLVMPointerType (IntPtrType (), 0));
+                       break;
                default:
                        g_assert (args [pindex]);
                        if (i == 0 && sig->hasthis)
@@ -3254,9 +3343,11 @@ 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;
+       case LLVMArgGsharedvtFixed:
+       case LLVMArgGsharedvtFixedVtype:
+               values [ins->dreg] = LLVMBuildLoad (builder, convert_full (ctx, addresses [call->inst.dreg], LLVMPointerType (type_to_llvm_type (ctx, sig->ret), 0), FALSE), "");
                break;
        default:
                if (sig->ret->type != MONO_TYPE_VOID)
@@ -3827,7 +3918,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                if (spec [MONO_INST_SRC1] != ' ' && spec [MONO_INST_SRC1] != 'v') {
                        MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1);
 
-                       if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) {
+                       if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) && var->opcode != OP_GSHAREDVT_ARG_REGOFFSET) {
                                lhs = emit_volatile_load (ctx, ins->sreg1);
                        } else {
                                /* It is ok for SETRET to have an uninitialized argument */
@@ -3997,10 +4088,17 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        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)));
+                               /* sreg1 might not be set */
+                               if (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 LLVMArgGsharedvtFixedVtype: {
+                               /* Already set */
                                LLVMBuildRetVoid (builder);
                                break;
                        }
@@ -4915,6 +5013,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        if (var->opcode == OP_VTARG_ADDR) {
                                /* The variable contains the vtype address */
                                values [ins->dreg] = values [var->dreg];
+                       } else if (var->opcode == OP_GSHAREDVT_LOCAL) {
+                               values [ins->dreg] = emit_gsharedvt_ldaddr (ctx, var->dreg);
                        } else {
                                values [ins->dreg] = addresses [var->dreg];
                        }
@@ -5329,11 +5429,20 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                v = convert (ctx, values [ins->sreg1], argtype);
                                LLVMBuildStore (ctx->builder, v, loc);
                                addresses [ins->dreg] = loc;
+                       } else if (ainfo->storage == LLVMArgGsharedvtVariable) {
+                                       MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1);
+
+                                       if (var && var->opcode == OP_GSHAREDVT_LOCAL) {
+                                               addresses [ins->dreg] = convert (ctx, emit_gsharedvt_ldaddr (ctx, var->dreg), LLVMPointerType (IntPtrType (), 0));
+                                       } else {
+                                               g_assert (addresses [ins->sreg1]);
+                                               addresses [ins->dreg] = addresses [ins->sreg1];
+                                       }
                        } else {
                                if (!addresses [ins->sreg1]) {
                                        addresses [ins->sreg1] = build_alloca (ctx, t);
                                        g_assert (values [ins->sreg1]);
-                                       LLVMBuildStore (builder, values [ins->sreg1], addresses [ins->sreg1]);
+                                       LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], type_to_llvm_type (ctx, t)), addresses [ins->sreg1]);
                                }
                                addresses [ins->dreg] = addresses [ins->sreg1];
                        }
@@ -6071,6 +6180,8 @@ get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                if (sig->ret->type != MONO_TYPE_VOID) {
                        if (mini_is_gsharedvt_variable_type (sig->ret))
                                linfo->ret.storage = LLVMArgGsharedvtVariable;
+                       else if (mini_type_is_vtype (sig->ret))
+                               linfo->ret.storage = LLVMArgGsharedvtFixedVtype;
                        else
                                linfo->ret.storage = LLVMArgGsharedvtFixed;
                        linfo->vret_arg_index = pindex;
@@ -6083,6 +6194,8 @@ get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                                linfo->args [pindex].storage = LLVMArgNormal;
                        else if (mini_is_gsharedvt_variable_type (sig->params [i]))
                                linfo->args [pindex].storage = LLVMArgGsharedvtVariable;
+                       else if (mini_type_is_vtype (sig->params [i]))
+                               linfo->args [pindex].storage = LLVMArgGsharedvtFixedVtype;
                        else
                                linfo->args [pindex].storage = LLVMArgGsharedvtFixed;
                        linfo->args [pindex].type = sig->params [i];
@@ -6288,7 +6401,7 @@ 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) {
+               } else if (ainfo->storage == LLVMArgGsharedvtFixed || ainfo->storage == LLVMArgGsharedvtFixedVtype) {
                        if (names [i] && names [i][0] != '\0')
                                name = g_strdup_printf ("p_arg_%s", names [i]);
                        else
@@ -6549,6 +6662,8 @@ mono_llvm_emit_method (MonoCompile *cfg)
                ctx->builder = create_builder (ctx);
                LLVMPositionBuilderAtEnd (ctx->builder, ctx->init_bb);
 
+               ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index);
+
                // FIXME: beforefieldinit
                if (ctx->has_got_access || mono_class_get_cctor (cfg->method->klass)) {
                        emit_init_method (ctx);
@@ -6763,6 +6878,9 @@ mono_llvm_emit_call (MonoCompile *cfg, MonoCallInst *call)
                case LLVMArgScalarByRef:
                case LLVMArgAsIArgs:
                case LLVMArgAsFpArgs:
+               case LLVMArgGsharedvtVariable:
+               case LLVMArgGsharedvtFixed:
+               case LLVMArgGsharedvtFixedVtype:
                        MONO_INST_NEW (cfg, ins, OP_LLVM_OUTARG_VT);
                        ins->dreg = mono_alloc_ireg (cfg);
                        ins->sreg1 = in->dreg;
index 89ae9d56a9d79d181cfce419ff1ea90f65c36b95..0944d71381f19dd3607c01030ee4a7c380677a90 100644 (file)
@@ -2299,7 +2299,10 @@ mono_compile_create_vars (MonoCompile *cfg)
        if (cfg->verbose_level > 2)
                g_print ("locals done\n");
 
-       mono_arch_create_vars (cfg);
+       if (COMPILE_LLVM (cfg))
+               mono_llvm_create_vars (cfg);
+       else
+               mono_arch_create_vars (cfg);
 
        if (cfg->method->save_lmf && cfg->create_lmf_var) {
                MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
@@ -3408,6 +3411,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                // FIXME:
                cfg->disable_llvm = TRUE;
                cfg->exception_message = g_strdup ("gsharedvt");
+#if 0
+               if (!cfg->llvm_only) {
+                       cfg->disable_llvm = TRUE;
+                       cfg->exception_message = g_strdup ("gsharedvt");
+               }
+#endif
        }
 
        if (cfg->gshared) {
@@ -3828,6 +3837,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                return cfg;
        }
 
+       if (cfg->llvm_only && cfg->gsharedvt)
+               mono_ssa_remove_gsharedvt (cfg);
+
 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
        if (COMPILE_SOFT_FLOAT (cfg))
                mono_decompose_soft_float (cfg);
@@ -3907,6 +3919,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                MonoBasicBlock *bb;
                gboolean need_local_opts;
 
+               if (cfg->gsharedvt)
+                       mono_allocate_gsharedvt_vars (cfg);
+
                if (!COMPILE_LLVM (cfg)) {
                        mono_spill_global_vars (cfg, &need_local_opts);
 
index e27511ce33827a03b57829d9affd873a4c5adbc7..c8183d3c7934c6850295320eb9eb60ef830169f6 100644 (file)
@@ -741,8 +741,10 @@ typedef enum {
        LLVMArgVtypeByVal,
        LLVMArgVtypeRetAddr, /* On on cinfo->ret */
        LLVMArgGSharedVt,
-       /* Fixed sized argument passed to/returned from gsharedvt method by ref */
+       /* Fixed size argument passed to/returned from gsharedvt method by ref */
        LLVMArgGsharedvtFixed,
+       /* Fixed size vtype argument passed to/returned from gsharedvt method by ref */
+       LLVMArgGsharedvtFixedVtype,
        /* Variable sized argument passed to/returned from gsharedvt method by ref */
        LLVMArgGsharedvtVariable,
        /* Vtype passed as one int array argument */
@@ -1759,6 +1761,10 @@ typedef struct {
        /* DWARF location list for 'rgctx_var' */
        GSList *rgctx_loclist;
 
+       int *gsharedvt_vreg_to_idx;
+
+       GSList *signatures;
+
        /* GC Maps */
    
        /* The offsets of the locals area relative to the frame pointer */
@@ -2465,6 +2471,8 @@ gpointer          mini_get_nullified_class_init_trampoline (void);
 gpointer          mini_get_single_step_trampoline (void);
 gpointer          mini_get_breakpoint_trampoline (void);
 gpointer          mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp);
+gpointer          mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboolean caller_gsharedvt, gboolean add_unbox_tramp, gpointer *out_arg);
+gpointer          mini_create_llvmonly_ftndesc (gpointer addr, gpointer arg);
 gboolean          mini_jit_info_is_gsharedvt (MonoJitInfo *ji);
 gpointer*         mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_method, MonoMethod **impl_method, gpointer *out_aot_addr,
                                                                                   gboolean *out_need_rgctx_tramp, MonoMethod **variant_iface);
@@ -2512,6 +2520,7 @@ void              mono_decompose_array_access_opts (MonoCompile *cfg);
 void              mono_decompose_soft_float (MonoCompile *cfg);
 void              mono_handle_global_vregs (MonoCompile *cfg);
 void              mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts);
+void              mono_allocate_gsharedvt_vars (MonoCompile *cfg);
 void              mono_if_conversion (MonoCompile *cfg);
 
 /* virtual function delegate */
@@ -2759,6 +2768,7 @@ void        mono_compute_natural_loops          (MonoCompile *cfg);
 MonoBitSet* mono_compile_iterated_dfrontier     (MonoCompile *cfg, MonoBitSet *set);
 void        mono_ssa_compute                    (MonoCompile *cfg);
 void        mono_ssa_remove                     (MonoCompile *cfg);
+void        mono_ssa_remove_gsharedvt           (MonoCompile *cfg);
 void        mono_ssa_cprop                      (MonoCompile *cfg);
 void        mono_ssa_deadce                     (MonoCompile *cfg);
 void        mono_ssa_strength_reduction         (MonoCompile *cfg);
@@ -2931,6 +2941,8 @@ void mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *c
 
 gpointer mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig,
                                                                         gint32 vcall_offset, gboolean calli);
+MonoMethod* mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig);
+MonoMethod* mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig);
 
 /* SIMD support */
 
index 3e79b5e3916640cb0d6a3e9e7415b0b501ba6538..a29108872a4adbb4dfb50430f70595a6eb3c9b17 100644 (file)
@@ -477,6 +477,73 @@ mono_ssa_compute (MonoCompile *cfg)
        cfg->comp_done |= MONO_COMP_SSA;
 }
 
+/*
+ * mono_ssa_remove_gsharedvt:
+ *
+ *   Same as mono_ssa_remove, but only remove phi nodes for gsharedvt variables.
+ */
+void
+mono_ssa_remove_gsharedvt (MonoCompile *cfg)
+{
+       MonoInst *ins, *var, *move;
+       int i, j, first;
+
+       /*
+        * When compiling gsharedvt code, we need to get rid of the VPHI instructions,
+        * since they cannot be handled later in the llvm backend.
+        */
+       g_assert (cfg->comp_done & MONO_COMP_SSA);
+
+       for (i = 0; i < cfg->num_bblocks; ++i) {
+               MonoBasicBlock *bb = cfg->bblocks [i];
+
+               if (cfg->verbose_level >= 4)
+                       printf ("\nREMOVE SSA %d:\n", bb->block_num);
+
+               for (ins = bb->code; ins; ins = ins->next) {
+                       if (!(MONO_IS_PHI (ins) && ins->opcode == OP_VPHI && mini_is_gsharedvt_variable_type (&ins->klass->byval_arg)))
+                               continue;
+
+                       g_assert (ins->inst_phi_args [0] == bb->in_count);
+                       var = get_vreg_to_inst (cfg, ins->dreg);
+
+                       /* Check for PHI nodes where all the inputs are the same */
+                       first = ins->inst_phi_args [1];
+
+                       for (j = 1; j < bb->in_count; ++j)
+                               if (first != ins->inst_phi_args [j + 1])
+                                       break;
+
+                       if ((bb->in_count > 1) && (j == bb->in_count)) {
+                               ins->opcode = op_phi_to_move (ins->opcode);
+                               if (ins->opcode == OP_VMOVE)
+                                       g_assert (ins->klass);
+                               ins->sreg1 = first;
+                       } else {
+                               for (j = 0; j < bb->in_count; j++) {
+                                       MonoBasicBlock *pred = bb->in_bb [j];
+                                       int sreg = ins->inst_phi_args [j + 1];
+
+                                       if (cfg->verbose_level >= 4)
+                                               printf ("\tADD R%d <- R%d in BB%d\n", var->dreg, sreg, pred->block_num);
+                                       if (var->dreg != sreg) {
+                                               MONO_INST_NEW (cfg, move, op_phi_to_move (ins->opcode));
+                                               if (move->opcode == OP_VMOVE) {
+                                                       g_assert (ins->klass);
+                                                       move->klass = ins->klass;
+                                               }
+                                               move->dreg = var->dreg;
+                                               move->sreg1 = sreg;
+                                               mono_add_ins_to_end (pred, move);
+                                       }
+                               }
+
+                               NULLIFY_INS (ins);
+                       }
+               }
+       }
+}
+
 void
 mono_ssa_remove (MonoCompile *cfg)
 {