[llvm] Fix intrinsic Selector.GetHandle support. (#4103)
[mono.git] / mono / mini / mini-llvm.c
index ca0d573b041d0159ee8801a1f0d2e15ad721ab3c..aac470915ef0fae8057cef9ff3775ccef36d2537 100644 (file)
@@ -6,7 +6,8 @@
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mini.h"
+#include "config.h"
+
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/debug-mono-symfile.h>
 #include <mono/metadata/mempool-internals.h>
@@ -33,6 +34,8 @@
 #include "aot-compiler.h"
 #include "mini-llvm.h"
 
+#ifndef DISABLE_JIT
+
 #ifdef __MINGW32__
 
 #include <stddef.h>
@@ -148,6 +151,7 @@ typedef struct {
        LLVMValueRef rgctx_arg;
        LLVMValueRef this_arg;
        LLVMTypeRef *vreg_types;
+       gboolean *is_vphi;
        LLVMTypeRef method_type;
        LLVMBasicBlockRef init_bb, inited_bb;
        gboolean *is_dead;
@@ -170,6 +174,7 @@ typedef struct {
        GPtrArray *bblock_list;
        char *method_name;
        GHashTable *jit_callees;
+       LLVMValueRef long_bb_break_var;
 } EmitContext;
 
 typedef struct {
@@ -353,6 +358,36 @@ simd_class_to_llvm_type (EmitContext *ctx, MonoClass *klass)
                return LLVMVectorType (LLVMInt8Type (), 16);
        } else if (!strcmp (klass->name, "Vector16b")) {
                return LLVMVectorType (LLVMInt8Type (), 16);
+       } else if (!strcmp (klass->name, "Vector2")) {
+               /* System.Numerics */
+               return LLVMVectorType (LLVMFloatType (), 4);
+       } else if (!strcmp (klass->name, "Vector3")) {
+               return LLVMVectorType (LLVMFloatType (), 4);
+       } else if (!strcmp (klass->name, "Vector4")) {
+               return LLVMVectorType (LLVMFloatType (), 4);
+       } else if (!strcmp (klass->name, "Vector`1")) {
+               MonoType *etype = mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+               switch (etype->type) {
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+                       return LLVMVectorType (LLVMInt8Type (), 16);
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+                       return LLVMVectorType (LLVMInt16Type (), 8);
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+                       return LLVMVectorType (LLVMInt32Type (), 4);
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+                       return LLVMVectorType (LLVMInt64Type (), 2);
+               case MONO_TYPE_R4:
+                       return LLVMVectorType (LLVMFloatType (), 4);
+               case MONO_TYPE_R8:
+                       return LLVMVectorType (LLVMDoubleType (), 2);
+               default:
+                       g_assert_not_reached ();
+                       return NULL;
+               }
        } else {
                printf ("%s\n", klass->name);
                NOT_IMPLEMENTED;
@@ -911,6 +946,8 @@ simd_op_to_intrins (int opcode)
                return "llvm.x86.sse2.pmulh.w";
        case OP_PMULW_HIGH_UN:
                return "llvm.x86.sse2.pmulhu.w";
+       case OP_DPPS:
+               return "llvm.x86.sse41.dpps";
 #endif
        default:
                g_assert_not_reached ();
@@ -1739,6 +1776,8 @@ get_handler_clause (MonoCompile *cfg, MonoBasicBlock *bb)
 static MonoExceptionClause *
 get_most_deep_clause (MonoCompile *cfg, EmitContext *ctx, MonoBasicBlock *bb)
 {
+       if (bb == cfg->bb_init)
+               return NULL;
        // Since they're sorted by nesting we just need
        // the first one that the bb is a member of
        for (int i = 0; i < cfg->header->num_clauses; i++) {
@@ -3483,6 +3522,9 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
 
        lcall = emit_call (ctx, bb, &builder, callee, args, LLVMCountParamTypes (llvm_sig));
 
+       if (ins->opcode != OP_TAILCALL && LLVMGetInstructionOpcode (lcall) == LLVMCall)
+               mono_llvm_set_call_notail (lcall);
+
        /*
         * Modify cconv and parameter attributes to pass rgctx/imt correctly.
         */
@@ -3887,7 +3929,7 @@ emit_landing_pad (EmitContext *ctx, int group_index, int group_size)
                LLVMValueRef switch_ins = LLVMBuildSwitch (lpadBuilder, match, resume_bb, group_size);
 
                // else move to that target bb
-               for (int i=0; i < group_size; i++) {
+               for (int i = 0; i < group_size; i++) {
                        MonoExceptionClause *clause = group_start + i;
                        int clause_index = clause - cfg->header->clauses;
                        MonoBasicBlock *handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->clause_to_handler, GINT_TO_POINTER (clause_index));
@@ -4150,14 +4192,36 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                if (nins > 1000) {
                        /*
                         * Some steps in llc are non-linear in the size of basic blocks, see #5714.
-                        * Start a new bblock. If the llvm optimization passes merge these, we
-                        * can work around that by doing a volatile load + cond branch from
-                        * localloc-ed memory.
+                        * Start a new bblock.
+                        * Prevent the bblocks to be merged by doing a volatile load + cond branch
+                        * from localloc-ed memory.
                         */
                        if (!cfg->llvm_only)
-                               set_failure (ctx, "basic block too long");
+                               ;//set_failure (ctx, "basic block too long");
+
+                       if (!ctx->long_bb_break_var) {
+                               ctx->long_bb_break_var = build_alloca_llvm_type_name (ctx, LLVMInt32Type (), 0, "long_bb_break");
+                               mono_llvm_build_store (ctx->alloca_builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), ctx->long_bb_break_var, TRUE, LLVM_BARRIER_NONE);
+                       }
+
                        cbb = gen_bb (ctx, "CONT_LONG_BB");
-                       LLVMBuildBr (ctx->builder, cbb);
+                       LLVMBasicBlockRef dummy_bb = gen_bb (ctx, "CONT_LONG_BB_DUMMY");
+
+                       LLVMValueRef load = mono_llvm_build_load (builder, ctx->long_bb_break_var, "", TRUE);
+                       /*
+                        * The long_bb_break_var is initialized to 0 in the prolog, so this branch will always go to 'cbb'
+                        * but llvm doesn't know that, so the branch is not going to be eliminated.
+                        */
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntEQ, load, LLVMConstInt (LLVMInt32Type (), 0, FALSE), "");
+
+                       LLVMBuildCondBr (builder, cmp, cbb, dummy_bb);
+
+                       /* Emit a dummy false bblock which does nothing but contains a volatile store so it cannot be eliminated */
+                       ctx->builder = builder = create_builder (ctx);
+                       LLVMPositionBuilderAtEnd (builder, dummy_bb);
+                       mono_llvm_build_store (builder, LLVMConstInt (LLVMInt32Type (), 1, FALSE), ctx->long_bb_break_var, TRUE, LLVM_BARRIER_NONE);
+                       LLVMBuildBr (builder, cbb);
+
                        ctx->builder = builder = create_builder (ctx);
                        LLVMPositionBuilderAtEnd (builder, cbb);
                        ctx->bblocks [bb->block_num].end_bblock = cbb;
@@ -5807,8 +5871,19 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        const char *name = (const char*)ins->inst_p0;
                        LLVMValueRef var;
 
-                       if (!ctx->module->objc_selector_to_var)
+                       if (!ctx->module->objc_selector_to_var) {
                                ctx->module->objc_selector_to_var = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+                               LLVMValueRef info_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), 8), "@OBJC_IMAGE_INFO");
+                               int32_t objc_imageinfo [] = { 0, 16 };
+                               LLVMSetInitializer (info_var, mono_llvm_create_constant_data_array ((uint8_t *) &objc_imageinfo, 8));
+                               LLVMSetLinkage (info_var, LLVMPrivateLinkage);
+                               LLVMSetExternallyInitialized (info_var, TRUE);
+                               LLVMSetSection (info_var, "__DATA, __objc_imageinfo,regular,no_dead_strip");
+                               LLVMSetAlignment (info_var, sizeof (mgreg_t));
+                               mark_as_used (ctx->module, info_var);
+                       }
+
                        var = g_hash_table_lookup (ctx->module->objc_selector_to_var, name);
                        if (!var) {
                                LLVMValueRef indexes [16];
@@ -6409,6 +6484,18 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        break;
                }
 
+               case OP_DPPS: {
+                       LLVMValueRef args [3];
+
+                       args [0] = lhs;
+                       args [1] = rhs;
+                       /* 0xf1 == multiply all 4 elements, add them together, and store the result to the lowest element */
+                       args [2] = LLVMConstInt (LLVMInt32Type (), 0xf1, FALSE);
+
+                       values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+                       break;
+               }
+
 #endif /* SIMD */
 
                case OP_DUMMY_USE:
@@ -6543,7 +6630,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                /* Convert the value to the type required by phi nodes */
                if (spec [MONO_INST_DEST] != ' ' && !MONO_IS_STORE_MEMBASE (ins) && ctx->vreg_types [ins->dreg]) {
-                       if (!values [ins->dreg])
+                       if (ctx->is_vphi [ins->dreg])
                                /* vtypes */
                                values [ins->dreg] = addresses [ins->dreg];
                        else
@@ -6692,6 +6779,7 @@ free_ctx (EmitContext *ctx)
        g_free (ctx->values);
        g_free (ctx->addresses);
        g_free (ctx->vreg_types);
+       g_free (ctx->is_vphi);
        g_free (ctx->vreg_cli_types);
        g_free (ctx->is_dead);
        g_free (ctx->unreachable);
@@ -6752,6 +6840,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
         */
        ctx->addresses = g_new0 (LLVMValueRef, cfg->next_vreg);
        ctx->vreg_types = g_new0 (LLVMTypeRef, cfg->next_vreg);
+       ctx->is_vphi = g_new0 (gboolean, cfg->next_vreg);
        ctx->vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg);
        ctx->phi_values = g_ptr_array_sized_new (256);
        /* 
@@ -7100,8 +7189,11 @@ emit_method_inner (EmitContext *ctx)
                                for (i = 0; i < ins->inst_phi_args [0]; i++) {
                                        int sreg1 = ins->inst_phi_args [i + 1];
                                        
-                                       if (sreg1 != -1)
+                                       if (sreg1 != -1) {
+                                               if (ins->opcode == OP_VPHI)
+                                                       ctx->is_vphi [sreg1] = TRUE;
                                                ctx->vreg_types [sreg1] = phi_type;
+                                       }
                                }
                                break;
                                }
@@ -7249,8 +7341,12 @@ emit_method_inner (EmitContext *ctx)
                        LLVMValueRef switch_ins = (LLVMValueRef)l->data;
                        GSList *bb_list = info->call_handler_return_bbs;
 
-                       for (i = 0; i < g_slist_length (bb_list); ++i)
-                               LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), (LLVMBasicBlockRef)(g_slist_nth (bb_list, i)->data));
+                       GSList *bb_list_iter;
+                       i = 0;
+                       for (bb_list_iter = bb_list; bb_list_iter; bb_list_iter = g_slist_next (bb_list_iter)) {
+                               LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), (LLVMBasicBlockRef)bb_list_iter->data);
+                               i ++;
+                       }
                }
        }
 
@@ -7821,6 +7917,7 @@ typedef enum {
        INTRINS_SSE_PSUBUSB,
        INTRINS_SSE_PAVGB,
        INTRINS_SSE_PAUSE,
+       INTRINS_SSE_DPPS,
 #endif
        INTRINS_NUM
 } IntrinsicId;
@@ -7902,7 +7999,8 @@ static IntrinsicDesc intrinsics[] = {
        {INTRINS_SSE_PADDUSB, "llvm.x86.sse2.paddus.b"},
        {INTRINS_SSE_PSUBUSB, "llvm.x86.sse2.psubus.b"},
        {INTRINS_SSE_PAVGB, "llvm.x86.sse2.pavg.b"},
-       {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"}
+       {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"},
+       {INTRINS_SSE_DPPS, "llvm.x86.sse41.dpps"}
 #endif
 };
 
@@ -8135,6 +8233,13 @@ add_intrinsic (LLVMModuleRef module, int id)
        case INTRINS_SSE_PAUSE:
                AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
                break;
+       case INTRINS_SSE_DPPS:
+               ret_type = type_to_simd_type (MONO_TYPE_R4);
+               arg_types [0] = type_to_simd_type (MONO_TYPE_R4);
+               arg_types [1] = type_to_simd_type (MONO_TYPE_R4);
+               arg_types [2] = LLVMInt32Type ();
+               AddFunc (module, name, ret_type, arg_types, 3);
+               break;
 #endif
        default:
                g_assert_not_reached ();
@@ -8358,7 +8463,7 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix,
        module->llvm_only = llvm_only;
        /* The first few entries are reserved */
        module->max_got_offset = 16;
-       module->context = LLVMContextCreate ();
+       module->context = LLVMGetGlobalContext ();
 
        if (llvm_only)
                /* clang ignores our debug info because it has an invalid version */
@@ -8611,7 +8716,7 @@ emit_aot_file_info (MonoLLVMModule *module)
        if (info->trampoline_size [0]) {
                fields [tindex ++] = AddJitGlobal (module, eltype, "specific_trampolines");
                fields [tindex ++] = AddJitGlobal (module, eltype, "static_rgctx_trampolines");
-               fields [tindex ++] = AddJitGlobal (module, eltype, "imt_thunks");
+               fields [tindex ++] = AddJitGlobal (module, eltype, "imt_trampolines");
                fields [tindex ++] = AddJitGlobal (module, eltype, "gsharedvt_arg_trampolines");
        } else {
                fields [tindex ++] = LLVMConstNull (eltype);
@@ -9166,3 +9271,27 @@ default_mono_llvm_unhandled_exception (void)
  *   code.
  * - use pointer types to help optimizations.
  */
+
+#else /* DISABLE_JIT */
+
+void
+mono_llvm_cleanup (void)
+{
+}
+
+void
+mono_llvm_free_domain_info (MonoDomain *domain)
+{
+}
+
+void
+mono_llvm_init (void)
+{
+}
+
+void
+default_mono_llvm_unhandled_exception (void)
+{
+}
+
+#endif /* DISABLE_JIT */