[jit] refactor basic block ordering in separate function
[mono.git] / mono / mini / mini.c
index 35dd472d63baa155f232a6635036fc1c2de36891..850d2d68e45bfbe76c051e087833729d876a5441 100644 (file)
@@ -666,6 +666,8 @@ mono_op_imm_to_op (int opcode)
                return OP_LSUB;
        case OP_IMUL_IMM:
                return OP_IMUL;
+       case OP_LMUL_IMM:
+               return OP_LMUL;
        case OP_AND_IMM:
 #if SIZEOF_REGISTER == 4
                return OP_IAND;
@@ -710,10 +712,16 @@ mono_op_imm_to_op (int opcode)
                return OP_LSHR_UN;
        case OP_IDIV_IMM:
                return OP_IDIV;
+       case OP_LDIV_IMM:
+               return OP_LDIV;
        case OP_IDIV_UN_IMM:
                return OP_IDIV_UN;
+       case OP_LDIV_UN_IMM:
+               return OP_LDIV_UN;
        case OP_IREM_UN_IMM:
                return OP_IREM_UN;
+       case OP_LREM_UN_IMM:
+               return OP_LREM_UN;
        case OP_IREM_IMM:
                return OP_IREM;
        case OP_LREM_IMM:
@@ -763,10 +771,29 @@ mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
 {
        int opcode2 = mono_op_imm_to_op (ins->opcode);
        MonoInst *temp;
+       guint32 dreg;
+       const char *spec = INS_INFO (ins->opcode);
+
+       if (spec [MONO_INST_SRC2] == 'l') {
+               dreg = mono_alloc_lreg (cfg);
+
+               /* Load the 64bit constant using decomposed ops */
+               MONO_INST_NEW (cfg, temp, OP_ICONST);
+               temp->inst_c0 = ins->inst_ls_word;
+               temp->dreg = MONO_LVREG_LS (dreg);
+               mono_bblock_insert_before_ins (bb, ins, temp);
+
+               MONO_INST_NEW (cfg, temp, OP_ICONST);
+               temp->inst_c0 = ins->inst_ms_word;
+               temp->dreg = MONO_LVREG_MS (dreg);
+       } else {
+               dreg = mono_alloc_ireg (cfg);
+
+               MONO_INST_NEW (cfg, temp, OP_ICONST);
+               temp->inst_c0 = ins->inst_imm;
+               temp->dreg = dreg;
+       }
 
-       MONO_INST_NEW (cfg, temp, OP_ICONST);
-       temp->inst_c0 = ins->inst_imm;
-       temp->dreg = mono_alloc_ireg (cfg);
        mono_bblock_insert_before_ins (bb, ins, temp);
 
        if (opcode2 == -1)
@@ -774,9 +801,9 @@ mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
        ins->opcode = opcode2;
 
        if (ins->opcode == OP_LOCALLOC)
-               ins->sreg1 = temp->dreg;
+               ins->sreg1 = dreg;
        else
-               ins->sreg2 = temp->dreg;
+               ins->sreg2 = dreg;
 
        bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg);
 }
@@ -1181,7 +1208,7 @@ mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
 /*
  * mini_method_verify:
  * 
- * Verify the method using the new verfier.
+ * Verify the method using the verfier.
  * 
  * Returns true if the method is invalid. 
  */
@@ -1190,7 +1217,6 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
 {
        GSList *tmp, *res;
        gboolean is_fulltrust;
-       MonoLoaderError *error;
 
        if (method->verification_success)
                return FALSE;
@@ -1203,11 +1229,13 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
 
        res = mono_method_verify_with_current_settings (method, cfg->skip_visibility, is_fulltrust);
 
-       if ((error = mono_loader_get_last_error ())) {
-               if (fail_compile)
-                       cfg->exception_type = error->exception_type;
-               else
+       if (mono_loader_get_last_error ()) {
+               if (fail_compile) {
+                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+                       mono_error_set_from_loader_error (&cfg->error);
+               } else {
                        mono_loader_clear_error ();
+               }
                if (res)
                        mono_free_verify_list (res);
                return TRUE;
@@ -1229,8 +1257,21 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
                        if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && (!is_fulltrust || info->exception_type == MONO_EXCEPTION_METHOD_ACCESS || info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)) {
                                if (fail_compile) {
                                        char *method_name = mono_method_full_name (method, TRUE);
-                                       cfg->exception_type = info->exception_type;
-                                       cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
+                                       char *msg = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
+
+                                       if (info->exception_type == MONO_EXCEPTION_METHOD_ACCESS)
+                                               mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "%s", msg);
+                                       else if (info->exception_type == info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)
+                                               mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "%s", msg);
+                                       else if (info->exception_type == MONO_EXCEPTION_UNVERIFIABLE_IL)
+                                               mono_error_set_generic_error (&cfg->error, "System.Security", "VerificationException", msg);
+                                       if (!mono_error_ok (&cfg->error)) {
+                                               mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+                                               g_free (msg);
+                                       } else {
+                                               cfg->exception_type = info->exception_type;
+                                               cfg->exception_message = msg;
+                                       }
                                        g_free (method_name);
                                }
                                mono_free_verify_list (res);
@@ -2568,7 +2609,7 @@ mono_codegen (MonoCompile *cfg)
 #endif
  
        if (cfg->verbose_level > 0) {
-               char* nm = mono_method_full_name (cfg->method, TRUE);
+               char* nm = mono_method_get_full_name (cfg->method);
                char *opt_descr = mono_opt_descr (cfg->opt);
                g_print ("Method %s emitted at %p to %p (code length %d) [%s] with opts %s\n", 
                                 nm, 
@@ -2670,6 +2711,42 @@ compute_reachable (MonoBasicBlock *bb)
        }
 }
 
+static void mono_bb_ordering (MonoCompile *cfg)
+{
+       int dfn = 0;
+       /* Depth-first ordering on basic blocks */
+       cfg->bblocks = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
+
+       cfg->max_block_num = cfg->num_bblocks;
+
+       df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
+       if (cfg->num_bblocks != dfn + 1) {
+               MonoBasicBlock *bb;
+
+               cfg->num_bblocks = dfn + 1;
+
+               /* remove unreachable code, because the code in them may be 
+                * inconsistent  (access to dead variables for example) */
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
+                       bb->flags &= ~BB_VISITED;
+               compute_reachable (cfg->bb_entry);
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
+                       if (bb->flags & BB_EXCEPTION_HANDLER)
+                               compute_reachable (bb);
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                       if (!(bb->flags & BB_VISITED)) {
+                               if (cfg->verbose_level > 1)
+                                       g_print ("found unreachable code in BB%d\n", bb->block_num);
+                               bb->code = bb->last_ins = NULL;
+                               while (bb->out_count)
+                                       mono_unlink_bblock (cfg, bb, bb->out_bb [0]);
+                       }
+               }
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
+                       bb->flags &= ~BB_VISITED;
+       }
+}
+
 static void
 mono_handle_out_of_line_bblock (MonoCompile *cfg)
 {
@@ -3260,7 +3337,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        MonoMethodSignature *sig;
        MonoError err;
        MonoCompile *cfg;
-       int dfn, i, code_size_ratio;
+       int i, code_size_ratio;
        gboolean try_generic_shared, try_llvm = FALSE;
        MonoMethod *method_to_compile, *method_to_register;
        gboolean method_is_gshared = FALSE;
@@ -3445,13 +3522,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
 
        header = cfg->header;
        if (!header) {
-               MonoLoaderError *error;
-
-               if ((error = mono_loader_get_last_error ())) {
-                       cfg->exception_type = error->exception_type;
+               if (mono_loader_get_last_error ()) {
+                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+                       mono_error_set_from_loader_error (&cfg->error);
                } else {
-                       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
-                       cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
+                       mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name));
                }
                if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
@@ -3561,7 +3636,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        if (cfg->verbose_level > 0) {
                char *method_name;
 
-               method_name = mono_method_full_name (method, TRUE);
+               method_name = mono_method_get_full_name (method);
                g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->gshared && !cfg->gsharedvt) ? "gshared " : "", method_name);
                /*
                if (COMPILE_LLVM (cfg))
@@ -3681,7 +3756,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        /* Should be done before branch opts */
        if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
                mono_local_cprop (cfg);
-
+       /*
+        * Should be done after cprop which can do strength reduction on
+        * some of these ops, after propagating immediates.
+        */
+       if (cfg->has_emulated_ops)
+               mono_local_emulate_ops (cfg);
        if (cfg->opt & MONO_OPT_BRANCH)
                mono_optimize_branches (cfg);
 
@@ -3697,38 +3777,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
 
        mono_threads_safepoint ();
 
-       /* Depth-first ordering on basic blocks */
-       cfg->bblocks = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
-
-       cfg->max_block_num = cfg->num_bblocks;
-
-       dfn = 0;
-       df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
-       if (cfg->num_bblocks != dfn + 1) {
-               MonoBasicBlock *bb;
-
-               cfg->num_bblocks = dfn + 1;
-
-               /* remove unreachable code, because the code in them may be 
-                * inconsistent  (access to dead variables for example) */
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
-                       bb->flags &= ~BB_VISITED;
-               compute_reachable (cfg->bb_entry);
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
-                       if (bb->flags & BB_EXCEPTION_HANDLER)
-                               compute_reachable (bb);
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       if (!(bb->flags & BB_VISITED)) {
-                               if (cfg->verbose_level > 1)
-                                       g_print ("found unreachable code in BB%d\n", bb->block_num);
-                               bb->code = bb->last_ins = NULL;
-                               while (bb->out_count)
-                                       mono_unlink_bblock (cfg, bb, bb->out_bb [0]);
-                       }
-               }
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
-                       bb->flags &= ~BB_VISITED;
-       }
+       mono_bb_ordering (cfg);
 
        if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) {
                /* 
@@ -4103,6 +4152,14 @@ mono_cfg_set_exception (MonoCompile *cfg, int type)
        cfg->exception_type = type;
 }
 
+/* Assumes ownership of the MSG argument */
+void
+mono_cfg_set_exception_invalid_program (MonoCompile *cfg, char *msg)
+{
+       mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+       mono_error_set_generic_error (&cfg->error, "System", "InvalidProgramException", msg);
+}
+
 #endif /* DISABLE_JIT */
 
 static MonoJitInfo*
@@ -4132,13 +4189,38 @@ create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
        return jinfo;
 }
 
+GTimer *mono_time_track_start ()
+{
+       return g_timer_new ();
+}
+
+void mono_time_track_end (double *time, GTimer *timer)
+{
+       g_timer_stop (timer);
+       *time += g_timer_elapsed (timer, NULL);
+       g_timer_destroy (timer);
+}
+
+void mono_update_jit_stats (MonoCompile *cfg)
+{
+       mono_jit_stats.allocate_var += cfg->stat_allocate_var;
+       mono_jit_stats.locals_stack_size += cfg->stat_locals_stack_size;
+       mono_jit_stats.basic_blocks += cfg->stat_basic_blocks;
+       mono_jit_stats.max_basic_blocks = MAX (cfg->stat_basic_blocks, mono_jit_stats.max_basic_blocks);
+       mono_jit_stats.cil_code_size += cfg->stat_cil_code_size;
+       mono_jit_stats.regvars += cfg->stat_n_regvars;
+       mono_jit_stats.inlineable_methods += cfg->stat_inlineable_methods;
+       mono_jit_stats.inlined_methods += cfg->stat_inlined_methods;
+       mono_jit_stats.code_reallocs += cfg->stat_code_reallocs;
+}
+
 /*
  * mono_jit_compile_method_inner:
  *
  *   Main entry point for the JIT.
  */
 gpointer
-mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoError *error)
 {
        MonoCompile *cfg;
        gpointer code = NULL;
@@ -4149,6 +4231,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        GTimer *jit_timer;
        MonoMethod *prof_method, *shared;
 
+       mono_error_init (error);
+
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
            (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
                MonoMethod *nm;
@@ -4211,7 +4295,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
                full_name = mono_method_full_name (method, TRUE);
                msg = g_strdup_printf ("Unrecognizable runtime implemented method '%s'", full_name);
-               *jit_ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", msg);
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", msg);
+               mono_error_set_exception_instance (error, ex);
                g_free (full_name);
                g_free (msg);
                return NULL;
@@ -4254,21 +4339,19 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                char *fullname = mono_method_full_name (method, TRUE);
                char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
 
-               *jit_ex = mono_get_exception_execution_engine (msg);
+               ex = mono_get_exception_execution_engine (msg);
+               mono_error_set_exception_instance (error, ex);
                g_free (fullname);
                g_free (msg);
                
                return NULL;
        }
 
-       jit_timer = g_timer_new ();
-
+       jit_timer = mono_time_track_start ();
        cfg = mini_method_compile (method, opt, target_domain, JIT_FLAG_RUN_CCTORS, 0, -1);
-       prof_method = cfg->method;
+       mono_time_track_end (&mono_jit_stats.jit_time, jit_timer);
 
-       g_timer_stop (jit_timer);
-       mono_jit_stats.jit_time += g_timer_elapsed (jit_timer, NULL);
-       g_timer_destroy (jit_timer);
+       prof_method = cfg->method;
 
        switch (cfg->exception_type) {
        case MONO_EXCEPTION_NONE:
@@ -4279,53 +4362,26 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        case MONO_EXCEPTION_FILE_NOT_FOUND:
        case MONO_EXCEPTION_BAD_IMAGE: {
                /* Throw a type load exception if needed */
-               MonoLoaderError *error = mono_loader_get_last_error ();
-
-               if (error) {
-                       ex = mono_loader_error_prepare_exception (error);
+               if (cfg->exception_ptr) {
+                       ex = mono_class_get_exception_for_failure ((MonoClass *)cfg->exception_ptr);
                } else {
-                       if (cfg->exception_ptr) {
-                               ex = mono_class_get_exception_for_failure ((MonoClass *)cfg->exception_ptr);
-                       } else {
-                               if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
-                                       ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
-                               else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
-                                       ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
-                               else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
-                                       ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
-                               else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
-                                       ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.IO", "FileNotFoundException", cfg->exception_message);
-                               else if (cfg->exception_type == MONO_EXCEPTION_BAD_IMAGE)
-                                       ex = mono_get_exception_bad_image_format (cfg->exception_message);
-                               else
-                                       g_assert_not_reached ();
-                       }
+                       if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
+                               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
+                       else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
+                               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
+                       else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
+                               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
+                       else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
+                               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.IO", "FileNotFoundException", cfg->exception_message);
+                       else if (cfg->exception_type == MONO_EXCEPTION_BAD_IMAGE)
+                               ex = mono_get_exception_bad_image_format (cfg->exception_message);
+                       else
+                               g_assert_not_reached ();
                }
                break;
        }
-       case MONO_EXCEPTION_INVALID_PROGRAM:
-               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
-               break;
-       case MONO_EXCEPTION_UNVERIFIABLE_IL:
-               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
-               break;
-       case MONO_EXCEPTION_METHOD_ACCESS:
-               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
-               break;
-       case MONO_EXCEPTION_FIELD_ACCESS:
-               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
-               break;
-       case MONO_EXCEPTION_OBJECT_SUPPLIED: {
-               MonoException *exp = (MonoException *)cfg->exception_ptr;
-               MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
-
-               ex = exp;
-               break;
-       }
-       case MONO_EXCEPTION_OUT_OF_MEMORY:
-               ex = mono_domain_get ()->out_of_memory_ex;
-               break;
        case MONO_EXCEPTION_MONO_ERROR:
+               // FIXME: MonoError has no copy ctor
                g_assert (!mono_error_ok (&cfg->error));
                ex = mono_error_convert_to_exception (&cfg->error);
                break;
@@ -4338,7 +4394,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
 
                mono_destroy_compile (cfg);
-               *jit_ex = ex;
+               mono_error_set_exception_instance (error, ex);
 
                return NULL;
        }
@@ -4383,15 +4439,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
         * Update global stats while holding a lock, instead of doing many
         * InterlockedIncrement operations during JITting.
         */
-       mono_jit_stats.allocate_var += cfg->stat_allocate_var;
-       mono_jit_stats.locals_stack_size += cfg->stat_locals_stack_size;
-       mono_jit_stats.basic_blocks += cfg->stat_basic_blocks;
-       mono_jit_stats.max_basic_blocks = MAX (cfg->stat_basic_blocks, mono_jit_stats.max_basic_blocks);
-       mono_jit_stats.cil_code_size += cfg->stat_cil_code_size;
-       mono_jit_stats.regvars += cfg->stat_n_regvars;
-       mono_jit_stats.inlineable_methods += cfg->stat_inlineable_methods;
-       mono_jit_stats.inlined_methods += cfg->stat_inlined_methods;
-       mono_jit_stats.code_reallocs += cfg->stat_code_reallocs;
+       mono_update_jit_stats (cfg);
 
        mono_destroy_compile (cfg);
 
@@ -4435,7 +4483,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        if (!vtable) {
                ex = mono_class_get_exception_for_failure (method->klass);
                g_assert (ex);
-               *jit_ex = ex;
+               mono_error_set_exception_instance (error, ex);
                return NULL;
        }
 
@@ -4455,7 +4503,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        ex = mono_runtime_class_init_full (vtable, FALSE);
        if (ex) {
-               *jit_ex = ex;
+               mono_error_set_exception_instance (error, ex);
                return NULL;
        }
        return code;