Generate the push/pop LMF code as IR on architectures which support it. Currently...
authorZoltan Varga <vargaz@gmail.com>
Sat, 20 Jul 2013 14:05:38 +0000 (16:05 +0200)
committerZoltan Varga <vargaz@gmail.com>
Sat, 20 Jul 2013 14:05:48 +0000 (16:05 +0200)
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-amd64.h
mono/mini/mini.c
mono/mini/mini.h

index b6a5704ceae663b8d78fb79ef12f9fcd35c494cb..585a995b4910a99da260a10857efb77d48a235d4 100644 (file)
@@ -1868,6 +1868,82 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so
        }
 }
 
+/*
+ * emit_push_lmf:
+ *
+ *   Emit IR to push the current LMF onto the LMF stack.
+ */
+static void
+emit_push_lmf (MonoCompile *cfg)
+{
+#if defined(MONO_ARCH_ENABLE_LMF_IR)
+       /*
+        * Emit IR to push the LMF:
+        * lmf_addr = <lmf_addr from tls>
+        * lmf->lmf_addr = lmf_addr
+        * lmf->prev_lmf = *lmf_addr
+        * *lmf_addr = lmf
+        */
+       int lmf_reg, lmf_addr_reg, prev_lmf_reg;
+       MonoInst *ins, *lmf_ins;
+
+       if (!mono_arch_enable_lmf_ir (cfg))
+               return;
+
+       lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
+       if (lmf_ins)
+               MONO_ADD_INS (cfg->cbb, lmf_ins);
+       else
+               lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
+       lmf_addr_reg = lmf_ins->dreg;
+
+       EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
+       lmf_reg = ins->dreg;
+       /* Save lmf_addr */
+       if (!cfg->lmf_addr_var)
+               cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+       EMIT_NEW_UNALU (cfg, ins, OP_MOVE, cfg->lmf_addr_var->dreg, lmf_ins->dreg);
+       prev_lmf_reg = alloc_preg (cfg);
+       /* Save previous_lmf */
+       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_addr_reg, 0);
+       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
+       /* Set new lmf */
+       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, lmf_reg);
+#endif
+}
+
+/*
+ * emit_push_lmf:
+ *
+ *   Emit IR to pop the current LMF from the LMF stack.
+ */
+static void
+emit_pop_lmf (MonoCompile *cfg)
+{
+#if defined(MONO_ARCH_ENABLE_LMF_IR)
+       int lmf_reg, lmf_addr_reg, prev_lmf_reg;
+       MonoInst *ins;
+
+       if (!mono_arch_enable_lmf_ir (cfg))
+               return;
+
+       /*
+        * Emit IR to pop the LMF:
+        * *(lmf->lmf_addr) = lmf->prev_lmf
+        */
+       cfg->cbb = cfg->bb_exit;
+       EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
+       lmf_reg = ins->dreg;
+       /* This could be called before emit_push_lmf () */
+       if (!cfg->lmf_addr_var)
+               cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+       lmf_addr_reg = cfg->lmf_addr_var->dreg;
+       prev_lmf_reg = alloc_preg (cfg);
+       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
+#endif
+}
+
 static int
 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
 {
@@ -8282,6 +8358,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cfg->ret_var_set = TRUE;
                                } 
                        } else {
+                               if (cfg->lmf_var && cfg->cbb->in_count)
+                                       emit_pop_lmf (cfg);
+
                                if (cfg->ret) {
                                        MonoType *ret_type = mono_method_signature (method)->ret;
 
@@ -11643,6 +11722,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                bblock->next_bb = end_bblock;
        }
 
+       if (cfg->lmf_var) {
+               cfg->cbb = init_localsbb;
+               emit_push_lmf (cfg);
+       }
+
        if (cfg->method == method && cfg->domainvar) {
                MonoInst *store;
                MonoInst *get_domain;
index 6081373b581fd82261dba5cd55cf8bf0d5de092f..89506c79f82407b676ad86c89f849cbfb77194a1 100644 (file)
@@ -2010,13 +2010,6 @@ mono_arch_create_vars (MonoCompile *cfg)
        cfg->arch.no_pushes = TRUE;
 #endif
 
-       if (cfg->method->save_lmf) {
-               MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
-               lmf_var->flags |= MONO_INST_VOLATILE;
-               lmf_var->flags |= MONO_INST_LMF;
-               cfg->arch.lmf_var = lmf_var;
-       }
-
 #ifndef MONO_AMD64_NO_PUSHES
        cfg->arch_eh_jit_info = 1;
 #endif
@@ -3736,14 +3729,13 @@ emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args
                        amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
                }
        } else {
+#ifdef HOST_WIN32
                if (lmf_addr_tls_offset != -1) {
                        /* Load lmf quicky using the FS register */
                        code = mono_amd64_emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
-#ifdef HOST_WIN32
                        /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
                        /* FIXME: Add a separate key for LMF to avoid this */
                        amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
-#endif
                }
                else {
                        /* 
@@ -3764,13 +3756,18 @@ emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args
                /* Set new lmf */
                amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
                amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, sizeof(gpointer));
+#else
+               /* Already handled by the MONO_ARCH_ENABLE_LMF_IR code in method-to-ir.c */
+               /* FIXME: Use this on win32 as well */
+               return code;
+#endif
        }
 
        return code;
 }
 
 /*
- * emit_save_lmf:
+ * emit_restore_lmf:
  *
  *   Emit code to pop an LMF structure from the LMF stack.
  */
@@ -3787,15 +3784,30 @@ emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
                x86_prefix (code, X86_FS_PREFIX);
                amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
        } else {
+#ifdef HOST_WIN32
                /* Restore previous lmf */
                amd64_mov_reg_membase (code, AMD64_RCX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
                amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof(gpointer));
                amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof(gpointer));
+#else
+               /* Already done in IR */
+               return code;
+#endif
        }
 
        return code;
 }
 
+gboolean
+mono_arch_enable_lmf_ir (MonoCompile *cfg)
+{
+#if !defined(TARGET_WIN32) && !defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       return TRUE;
+#else
+       return FALSE;
+#endif
+}
+
 #define REAL_PRINT_REG(text,reg) \
 mono_assert (reg >= 0); \
 amd64_push_reg (code, AMD64_RAX); \
@@ -4942,7 +4954,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                }
                case OP_AMD64_SAVE_SP_TO_LMF: {
-                       MonoInst *lmf_var = cfg->arch.lmf_var;
+                       MonoInst *lmf_var = cfg->lmf_var;
                        amd64_mov_membase_reg (code, cfg->frame_reg, lmf_var->inst_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
                        break;
                }
@@ -6561,7 +6573,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        int alloc_size, pos, i, cfa_offset, quad, max_epilog_size;
        guint8 *code;
        CallInfo *cinfo;
-       MonoInst *lmf_var = cfg->arch.lmf_var;
+       MonoInst *lmf_var = cfg->lmf_var;
        gboolean args_clobbered = FALSE;
        gboolean trace = FALSE;
 #ifdef __native_client_codegen__
@@ -7125,7 +7137,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        guint8 *code;
        int max_epilog_size;
        CallInfo *cinfo;
-       gint32 lmf_offset = cfg->arch.lmf_var ? ((MonoInst*)cfg->arch.lmf_var)->inst_offset : -1;
+       gint32 lmf_offset = cfg->lmf_var ? ((MonoInst*)cfg->lmf_var)->inst_offset : -1;
        
        max_epilog_size = get_max_epilog_size (cfg);
 
index fd84eab37980bca3d71852d67c18a20f1bdfbc50..f9a19c6779121a18abaf42481673e8149b19e62a 100644 (file)
@@ -203,7 +203,6 @@ typedef struct MonoCompileArch {
 #endif
        gpointer seq_point_info_var;
        gpointer ss_trigger_page_var;
-       gpointer lmf_var;
 } MonoCompileArch;
 
 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->rax = (gsize)exc; } while (0)
@@ -396,6 +395,7 @@ typedef struct MonoCompileArch {
 #define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
 #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
 #define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1
+#define MONO_ARCH_ENABLE_LMF_IR 1
 
 #ifdef TARGET_OSX
 #define MONO_ARCH_HAVE_TLS_GET_REG 1
index ef6fe466cd73dc3c954862830e3c19fe7b7336c4..d5c9989337b3708a8fc2b6cf6e55675cb49c8b77 100644 (file)
@@ -2870,6 +2870,9 @@ mini_get_tls_offset (MonoJitTlsKey key)
        case TLS_KEY_LMF:
                offset = mono_get_lmf_tls_offset ();
                break;
+       case TLS_KEY_LMF_ADDR:
+               offset = mono_get_lmf_addr_tls_offset ();
+               break;
        default:
                g_assert_not_reached ();
                offset = -1;
@@ -2939,6 +2942,12 @@ mono_get_lmf_intrinsic (MonoCompile* cfg)
        return mono_create_tls_get (cfg, TLS_KEY_LMF);
 }
 
+MonoInst*
+mono_get_lmf_addr_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
+}
+
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -3610,6 +3619,13 @@ mono_compile_create_vars (MonoCompile *cfg)
        if (cfg->verbose_level > 2)
                g_print ("locals done\n");
 
+       if (cfg->method->save_lmf && ARCH_ENABLE_LMF_IR) {
+               MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+               lmf_var->flags |= MONO_INST_VOLATILE;
+               lmf_var->flags |= MONO_INST_LMF;
+               cfg->lmf_var = lmf_var;
+       }
+
        mono_arch_create_vars (cfg);
 }
 
index cb41ce2885e9fae6adb8a0bc5f568eab553ac8fc..ce1fc4e0e1fcd30a7bab11121917cfa777cf6591 100644 (file)
@@ -1053,7 +1053,8 @@ typedef enum {
        TLS_KEY_JIT_TLS = 1,
        /* mono_domain_get () */
        TLS_KEY_DOMAIN = 2,
-       TLS_KEY_LMF = 3
+       TLS_KEY_LMF = 3,
+       TLS_KEY_LMF_ADDR = 4
 } MonoJitTlsKey;
 
 /*
@@ -1386,6 +1387,9 @@ typedef struct {
        /* For native-to-managed wrappers, the saved old domain */
        MonoInst *orig_domain_var;
 
+       MonoInst *lmf_var;
+       MonoInst *lmf_addr_var;
+
        unsigned char   *cil_start;
 #ifdef __native_client_codegen__
        /* this alloc is not aligned, native_code */
@@ -1970,6 +1974,7 @@ MonoInst* mono_get_jit_tls_intrinsic        (MonoCompile *cfg) MONO_INTERNAL;
 MonoInst* mono_get_domain_intrinsic         (MonoCompile* cfg) MONO_INTERNAL;
 MonoInst* mono_get_thread_intrinsic         (MonoCompile* cfg) MONO_INTERNAL;
 MonoInst* mono_get_lmf_intrinsic            (MonoCompile* cfg) MONO_INTERNAL;
+MonoInst* mono_get_lmf_addr_intrinsic       (MonoCompile* cfg) MONO_INTERNAL;
 GList    *mono_varlist_insert_sorted        (MonoCompile *cfg, GList *list, MonoMethodVar *mv, int sort_type) MONO_INTERNAL;
 GList    *mono_varlist_sort                 (MonoCompile *cfg, GList *list, int sort_type) MONO_INTERNAL;
 void      mono_analyze_liveness             (MonoCompile *cfg) MONO_INTERNAL;
@@ -2261,6 +2266,7 @@ gboolean  mono_arch_gsharedvt_sig_supported     (MonoMethodSignature *sig) MONO_
 gpointer  mono_arch_get_gsharedvt_trampoline    (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
 gpointer  mono_arch_get_gsharedvt_call_info     (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) MONO_INTERNAL;
 gboolean  mono_arch_opcode_needs_emulation      (MonoCompile *cfg, int opcode) MONO_INTERNAL;
+gboolean  mono_arch_enable_lmf_ir               (MonoCompile *cfg) MONO_INTERNAL;
 
 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
 gboolean  mono_arch_is_soft_float               (void) MONO_INTERNAL;
@@ -2766,4 +2772,14 @@ gboolean SIG_HANDLER_SIGNATURE (mono_chain_signal) MONO_INTERNAL;
 #define ARCH_HAVE_TLS_GET_REG 0
 #endif
 
+/*
+ * When this is set, the code to push/pop the LMF from the LMF stack is generated as IR
+ * instead of being generated in emit_prolog ()/emit_epilog ().
+ */
+#ifdef MONO_ARCH_ENABLE_LMF_IR
+#define ARCH_ENABLE_LMF_IR 1
+#else
+#define ARCH_ENABLE_LMF_IR 0
+#endif
+
 #endif /* __MONO_MINI_H__ */