X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-llvm.c;h=e15a5d09102eefc8420a0e140b2e9fc92d463718;hb=efc6803ce0798961dbb98ff75abcdd1e622eb457;hp=62e58eab9376a519bc6cfcaccfd2bd44df358a5a;hpb=f7fd77fa10cf833cfe79d761fd905a6a2b6df4f6;p=mono.git diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 62e58eab937..e15a5d09102 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -78,7 +78,7 @@ typedef struct { const char *jit_got_symbol; const char *eh_frame_symbol; LLVMValueRef get_method, get_unbox_tramp; - LLVMValueRef init_method, init_method_gshared_rgctx, init_method_gshared_this; + LLVMValueRef init_method, init_method_gshared_mrgctx, init_method_gshared_this, init_method_gshared_vtable; LLVMValueRef code_start, code_end; LLVMValueRef inited_var; int max_inited_idx, max_method_idx; @@ -143,11 +143,13 @@ typedef struct { LLVMValueRef rgctx_arg; LLVMValueRef this_arg; LLVMTypeRef *vreg_types; + LLVMTypeRef method_type; LLVMBasicBlockRef init_bb, inited_bb; gboolean *is_dead; gboolean *unreachable; gboolean llvm_only; gboolean has_got_access; + gboolean is_linkonce; int this_arg_pindex, rgctx_arg_pindex; LLVMValueRef imt_rgctx_loc; GHashTable *llvm_types; @@ -159,6 +161,9 @@ typedef struct { LLVMValueRef ex_var; GHashTable *exc_meta; GHashTable *method_to_callers; + GPtrArray *phi_values; + GPtrArray *bblock_list; + char *method_name; } EmitContext; typedef struct { @@ -220,17 +225,7 @@ llvm_ins_info[] = { #define IS_TARGET_AMD64 0 #endif -#define LLVM_FAILURE(ctx, reason) do { \ - TRACE_FAILURE (reason); \ - (ctx)->cfg->exception_message = g_strdup (reason); \ - (ctx)->cfg->disable_llvm = TRUE; \ - goto FAILURE; \ -} while (0) - -#define CHECK_FAILURE(ctx) do { \ - if ((ctx)->cfg->disable_llvm) \ - goto FAILURE; \ -} while (0) +#define ctx_ok(ctx) (!(ctx)->cfg->disable_llvm) static LLVMIntPredicate cond_to_llvm_cond [] = { LLVMIntEQ, @@ -271,6 +266,15 @@ static void emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsign static LLVMValueRef emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, const char *name); static void emit_dbg_info (MonoLLVMModule *module, const char *filename, const char *cu_name); + +static inline void +set_failure (EmitContext *ctx, const char *message) +{ + TRACE_FAILURE (reason); + ctx->cfg->exception_message = g_strdup (message); + ctx->cfg->disable_llvm = TRUE; +} + /* * IntPtrType: * @@ -499,6 +503,7 @@ type_to_llvm_type (EmitContext *ctx, MonoType *t) static gboolean type_is_unsigned (EmitContext *ctx, MonoType *t) { + t = mini_get_underlying_type (t); if (t->byref) return FALSE; switch (t->type) { @@ -634,6 +639,8 @@ op_to_llvm_type (int opcode) case OP_RCONV_TO_I2: case OP_RCONV_TO_U2: return LLVMInt16Type (); + case OP_RCONV_TO_U4: + return LLVMInt32Type (); case OP_FCONV_TO_I: case OP_FCONV_TO_U: return sizeof (gpointer) == 8 ? LLVMInt64Type () : LLVMInt32Type (); @@ -1182,7 +1189,8 @@ sig_to_llvm_sig_no_cinfo (EmitContext *ctx, MonoMethodSignature *sig) rtype = mini_get_underlying_type (sig->ret); ret_type = type_to_llvm_type (ctx, rtype); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return NULL; param_types = g_new0 (LLVMTypeRef, (sig->param_count * 8) + 3); pindex = 0; @@ -1192,17 +1200,15 @@ sig_to_llvm_sig_no_cinfo (EmitContext *ctx, MonoMethodSignature *sig) for (i = 0; i < sig->param_count; ++i) param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) { + g_free (param_types); + return NULL; + } res = LLVMFunctionType (ret_type, param_types, pindex, FALSE); g_free (param_types); return res; - - FAILURE: - g_free (param_types); - - return NULL; } /* @@ -1226,7 +1232,8 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * rtype = mini_get_underlying_type (sig->ret); ret_type = type_to_llvm_type (ctx, rtype); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return NULL; switch (cinfo->ret.storage) { case LLVMArgVtypeInReg: @@ -1293,7 +1300,10 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * */ cinfo->vret_arg_pindex = pindex; param_types [pindex] = type_to_llvm_arg_type (ctx, sig->ret); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) { + g_free (param_types); + return NULL; + } param_types [pindex] = LLVMPointerType (param_types [pindex], 0); pindex ++; } @@ -1360,7 +1370,8 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * break; case LLVMArgVtypeByVal: param_types [pindex] = type_to_llvm_arg_type (ctx, ainfo->type); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; param_types [pindex] = LLVMPointerType (param_types [pindex], 0); pindex ++; break; @@ -1371,7 +1382,8 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * case LLVMArgVtypeByRef: case LLVMArgScalarByRef: param_types [pindex] = type_to_llvm_arg_type (ctx, ainfo->type); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; param_types [pindex] = LLVMPointerType (param_types [pindex], 0); pindex ++; break; @@ -1400,6 +1412,10 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * break; } } + if (!ctx_ok (ctx)) { + g_free (param_types); + return NULL; + } if (vretaddr && vret_arg_pindex == pindex) param_types [pindex ++] = IntPtrType (); if (ctx->llvm_only && cinfo->rgctx_arg) { @@ -1409,17 +1425,10 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * pindex ++; } - CHECK_FAILURE (ctx); - res = LLVMFunctionType (ret_type, param_types, pindex, FALSE); g_free (param_types); return res; - - FAILURE: - g_free (param_types); - - return NULL; } static LLVMTypeRef @@ -1497,6 +1506,26 @@ LLVMFunctionType3 (LLVMTypeRef ReturnType, return LLVMFunctionType (ReturnType, param_types, 3, IsVarArg); } +static G_GNUC_UNUSED LLVMTypeRef +LLVMFunctionType5 (LLVMTypeRef ReturnType, + LLVMTypeRef ParamType1, + LLVMTypeRef ParamType2, + LLVMTypeRef ParamType3, + LLVMTypeRef ParamType4, + LLVMTypeRef ParamType5, + int IsVarArg) +{ + LLVMTypeRef param_types [5]; + + param_types [0] = ParamType1; + param_types [1] = ParamType2; + param_types [2] = ParamType3; + param_types [3] = ParamType4; + param_types [4] = ParamType5; + + return LLVMFunctionType (ReturnType, param_types, 5, IsVarArg); +} + /* * create_builder: * @@ -1574,7 +1603,8 @@ get_aotconst_typed (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data, name = get_aotconst_name (type, data, got_offset); if (llvm_type) { - load = convert (ctx, LLVMBuildLoad (builder, got_entry_addr, ""), llvm_type); + load = LLVMBuildLoad (builder, got_entry_addr, ""); + load = convert (ctx, load, llvm_type); LLVMSetValueName (load, name ? name : ""); } else { load = LLVMBuildLoad (builder, got_entry_addr, name ? name : ""); @@ -1609,6 +1639,10 @@ get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gcons g_hash_table_insert (ctx->module->direct_callables, (char*)callee_name, callee); } else { + /* LLVMTypeRef's are uniqued */ + if (LLVMGetElementType (LLVMTypeOf (callee)) != llvm_sig) + return LLVMConstBitCast (callee, LLVMPointerType (llvm_sig, 0)); + g_free (callee_name); } return callee; @@ -2001,7 +2035,7 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex if (!sig) sig = LLVMFunctionType1 (LLVMVoidType (), LLVMInt32Type (), FALSE); - callee = get_callee (ctx, sig, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_llvm_throw_corlib_exception"); + callee = get_callee (ctx, sig, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_llvm_throw_corlib_exception"); LLVMBuildBr (builder, ex2_bb); @@ -2484,6 +2518,8 @@ emit_init_icall_wrapper (MonoLLVMModule *module, const char *name, const char *i sig = LLVMFunctionType2 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), FALSE); break; case 1: + case 3: + /* mrgctx/vtable */ func = LLVMAddFunction (lmodule, name, LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), IntPtrType (), FALSE)); sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE); break; @@ -2548,8 +2584,9 @@ static void emit_init_icall_wrappers (MonoLLVMModule *module) { module->init_method = emit_init_icall_wrapper (module, "init_method", "mono_aot_init_llvm_method", 0); - module->init_method_gshared_rgctx = emit_init_icall_wrapper (module, "init_method_gshared_rgctx", "mono_aot_init_gshared_method_rgctx", 1); + module->init_method_gshared_mrgctx = emit_init_icall_wrapper (module, "init_method_gshared_mrgctx", "mono_aot_init_gshared_method_mrgctx", 1); module->init_method_gshared_this = emit_init_icall_wrapper (module, "init_method_gshared_this", "mono_aot_init_gshared_method_this", 2); + module->init_method_gshared_vtable = emit_init_icall_wrapper (module, "init_method_gshared_vtable", "mono_aot_init_gshared_method_vtable", 3); } static void @@ -2605,7 +2642,8 @@ emit_div_check (EmitContext *ctx, LLVMBuilderRef builder, MonoBasicBlock *bb, Mo cmp = LLVMBuildICmp (builder, LLVMIntEQ, rhs, LLVMConstInt (LLVMTypeOf (rhs), 0, FALSE), ""); emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; builder = ctx->builder; /* b == -1 && a == 0x80000000 */ @@ -2616,7 +2654,8 @@ emit_div_check (EmitContext *ctx, LLVMBuilderRef builder, MonoBasicBlock *bb, Mo cmp = LLVMBuildICmp (builder, LLVMIntEQ, LLVMBuildAnd (builder, cond1, cond2, ""), LLVMConstInt (LLVMInt1Type (), 1, FALSE), ""); emit_cond_system_exception (ctx, bb, "OverflowException", cmp); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; builder = ctx->builder; } break; @@ -2624,9 +2663,6 @@ emit_div_check (EmitContext *ctx, LLVMBuilderRef builder, MonoBasicBlock *bb, Mo default: break; } - - FAILURE: - return; } /* @@ -2664,10 +2700,16 @@ emit_init_method (EmitContext *ctx) LLVMPositionBuilderAtEnd (ctx->builder, notinited_bb); // FIXME: Cache - if (ctx->rgctx_arg) { + if (ctx->rgctx_arg && cfg->method->is_inflated && mono_method_get_context (cfg->method)->method_inst) { args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0); args [1] = convert (ctx, ctx->rgctx_arg, IntPtrType ()); - callee = ctx->module->init_method_gshared_rgctx; + callee = ctx->module->init_method_gshared_mrgctx; + call = LLVMBuildCall (builder, callee, args, 2, ""); + } else if (ctx->rgctx_arg) { + /* A vtable is passed as the rgctx argument */ + args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0); + args [1] = convert (ctx, ctx->rgctx_arg, IntPtrType ()); + callee = ctx->module->init_method_gshared_vtable; call = LLVMBuildCall (builder, callee, args, 2, ""); } else if (cfg->gshared) { args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0); @@ -2702,15 +2744,26 @@ emit_unbox_tramp (EmitContext *ctx, const char *method_name, LLVMTypeRef method_ LLVMValueRef tramp, call, *args; LLVMBuilderRef builder; LLVMBasicBlockRef lbb; + LLVMCallInfo *linfo; char *tramp_name; int i, nargs; tramp_name = g_strdup_printf ("ut_%s", method_name); tramp = LLVMAddFunction (ctx->module->lmodule, tramp_name, method_type); LLVMSetLinkage (tramp, LLVMInternalLinkage); - LLVMAddFunctionAttr (tramp, LLVMNoUnwindAttribute); + LLVMAddFunctionAttr (tramp, LLVMOptimizeForSizeAttribute); + //LLVMAddFunctionAttr (tramp, LLVMNoUnwindAttribute); + linfo = ctx->linfo; + // FIXME: Reduce code duplication with mono_llvm_compile_method () etc. if (!ctx->llvm_only && ctx->rgctx_arg_pindex != -1) LLVMAddAttribute (LLVMGetParam (tramp, ctx->rgctx_arg_pindex), LLVMInRegAttribute); + if (ctx->cfg->vret_addr) { + LLVMSetValueName (LLVMGetParam (tramp, linfo->vret_arg_pindex), "vret"); + if (linfo->ret.storage == LLVMArgVtypeByRef) { + LLVMAddAttribute (LLVMGetParam (tramp, linfo->vret_arg_pindex), LLVMStructRetAttribute); + LLVMAddAttribute (LLVMGetParam (tramp, linfo->vret_arg_pindex), LLVMNoAliasAttribute); + } + } lbb = LLVMAppendBasicBlock (tramp, ""); builder = LLVMCreateBuilder (); @@ -2731,7 +2784,11 @@ emit_unbox_tramp (EmitContext *ctx, const char *method_name, LLVMTypeRef method_ call = LLVMBuildCall (builder, method, args, nargs, ""); if (!ctx->llvm_only && ctx->rgctx_arg_pindex != -1) LLVMAddInstrAttribute (call, 1 + ctx->rgctx_arg_pindex, LLVMInRegAttribute); - mono_llvm_set_must_tail (call); + if (linfo->ret.storage == LLVMArgVtypeByRef) + LLVMAddInstrAttribute (call, 1 + linfo->vret_arg_pindex, LLVMStructRetAttribute); + + // FIXME: This causes assertions in clang + //mono_llvm_set_must_tail (call); if (LLVMGetReturnType (method_type) == LLVMVoidType ()) LLVMBuildRetVoid (builder); else @@ -2771,10 +2828,13 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) 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); + if (!ctx_ok (ctx)) + return; /* Could be already created by an OP_VPHI */ - if (!ctx->addresses [var->dreg]) + if (!ctx->addresses [var->dreg]) { ctx->addresses [var->dreg] = build_alloca (ctx, var->inst_vtype); + //LLVMSetValueName (ctx->addresses [var->dreg], g_strdup_printf ("vreg_loc_%d", var->dreg)); + } ctx->vreg_cli_types [var->dreg] = var->inst_vtype; } } @@ -2989,12 +3049,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) sprintf (name, "BB%d_CALL_HANDLER_TARGET", bb->block_num); ctx->bblocks [bb->block_num].call_handler_target_bb = LLVMAppendBasicBlock (ctx->lmethod, name); } - - FAILURE: - goto CLEANUP; - - CLEANUP: - ctx->builder = old_builder; + ctx->builder = old_builder; } static void @@ -3017,8 +3072,10 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, gboolean is_virtual, calli, preserveall; LLVMBuilderRef builder = *builder_ref; - if (call->signature->call_convention != MONO_CALL_DEFAULT) - LLVM_FAILURE (ctx, "non-default callconv"); + if (call->signature->call_convention != MONO_CALL_DEFAULT) { + set_failure (ctx, "non-default callconv"); + return; + } cinfo = call->cinfo; g_assert (cinfo); @@ -3030,7 +3087,8 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, 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); + if (!ctx_ok (ctx)) + return; is_virtual = (ins->opcode == OP_VOIDCALL_MEMBASE || ins->opcode == OP_CALL_MEMBASE || ins->opcode == OP_VCALL_MEMBASE || ins->opcode == OP_LCALL_MEMBASE || ins->opcode == OP_FCALL_MEMBASE || ins->opcode == OP_RCALL_MEMBASE); calli = !call->fptr_is_patch && (ins->opcode == OP_VOIDCALL_REG || ins->opcode == OP_CALL_REG || ins->opcode == OP_VCALL_REG || ins->opcode == OP_LCALL_REG || ins->opcode == OP_FCALL_REG || ins->opcode == OP_RCALL_REG); @@ -3045,9 +3103,10 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, } else { if (cfg->compile_aot) { callee = get_callee (ctx, llvm_sig, MONO_PATCH_INFO_METHOD, call->method); - if (!callee) - LLVM_FAILURE (ctx, "can't encode patch"); - + if (!callee) { + set_failure (ctx, "can't encode patch"); + return; + } if (cfg->llvm_only && call->method->klass->image->assembly == ctx->module->assembly) { /* * Collect instructions representing the callee into a hash so they can be replaced @@ -3068,9 +3127,11 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, } } - if (!cfg->llvm_only && 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"); + set_failure (ctx, "#13734"); + return; + } } else if (calli) { } else { MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr); @@ -3087,8 +3148,10 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, */ if (cfg->compile_aot) { callee = get_callee (ctx, llvm_sig, MONO_PATCH_INFO_INTERNAL_METHOD, (char*)info->name); - if (!callee) - LLVM_FAILURE (ctx, "can't encode patch"); + if (!callee) { + set_failure (ctx, "can't encode patch"); + return; + } } else { callee = LLVMAddFunction (lmodule, "", llvm_sig); target = (gpointer)mono_icall_get_wrapper (info); @@ -3101,12 +3164,16 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, MonoJumpInfo *abs_ji = (MonoJumpInfo*)g_hash_table_lookup (cfg->abs_patches, call->fptr); if (abs_ji) { callee = get_callee (ctx, llvm_sig, abs_ji->type, abs_ji->data.target); - if (!callee) - LLVM_FAILURE (ctx, "can't encode patch"); + if (!callee) { + set_failure (ctx, "can't encode patch"); + return; + } } } - if (!callee) - LLVM_FAILURE (ctx, "aot"); + if (!callee) { + set_failure (ctx, "aot"); + return; + } } else { callee = LLVMAddFunction (lmodule, "", llvm_sig); target = NULL; @@ -3117,11 +3184,6 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, * FIXME: Some trampolines might have * their own calling convention on some platforms. */ -#ifndef TARGET_AMD64 - if (abs_ji->type == MONO_PATCH_INFO_MONITOR_ENTER || abs_ji->type == MONO_PATCH_INFO_MONITOR_ENTER_V4 || - abs_ji->type == MONO_PATCH_INFO_MONITOR_EXIT) - LLVM_FAILURE (ctx, "trampoline with own cconv"); -#endif target = mono_resolve_patch_target (cfg->method, cfg->domain, NULL, abs_ji, FALSE); LLVMAddGlobalMapping (ctx->module->ee, callee, target); } @@ -3211,6 +3273,14 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, break; } + /* + * Sometimes the same method is called with two different signatures (i.e. with and without 'this'), so + * use the real callee for argument type conversion. + */ + LLVMTypeRef callee_type = LLVMGetElementType (LLVMTypeOf (callee)); + LLVMTypeRef *param_types = (LLVMTypeRef*)g_alloca (sizeof (LLVMTypeRef) * LLVMCountParamTypes (callee_type)); + LLVMGetParamTypes (callee_type, param_types); + for (i = 0; i < sig->param_count + sig->hasthis; ++i) { guint32 regpair; int reg, pindex; @@ -3259,7 +3329,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, case LLVMArgGsharedvtFixed: case LLVMArgGsharedvtFixedVtype: g_assert (addresses [reg]); - args [pindex] = addresses [reg]; + args [pindex] = convert (ctx, addresses [reg], LLVMPointerType (type_to_llvm_arg_type (ctx, ainfo->type), 0)); break; case LLVMArgGsharedvtVariable: g_assert (addresses [reg]); @@ -3268,7 +3338,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, default: g_assert (args [pindex]); if (i == 0 && sig->hasthis) - args [pindex] = convert (ctx, args [pindex], ThisType ()); + args [pindex] = convert (ctx, args [pindex], param_types [pindex]); else args [pindex] = convert (ctx, args [pindex], type_to_llvm_arg_type (ctx, ainfo->type)); break; @@ -3370,10 +3440,6 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, } *builder_ref = ctx->builder; - - return; - FAILURE: - return; } static void @@ -3388,7 +3454,7 @@ emit_llvmonly_throw (EmitContext *ctx, MonoBasicBlock *bb, gboolean rethrow, LLV LLVMTypeRef fun_sig = LLVMFunctionType1 (LLVMVoidType (), exc_type, FALSE); if (ctx->cfg->compile_aot) { - callee = get_callee (ctx, fun_sig, MONO_PATCH_INFO_INTERNAL_METHOD, icall_name); + callee = get_callee (ctx, fun_sig, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name); } else { callee = LLVMAddFunction (ctx->lmodule, icall_name, fun_sig); LLVMAddGlobalMapping (ctx->module->ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, icall_name)); @@ -3530,13 +3596,24 @@ mono_llvm_emit_match_exception_call (EmitContext *ctx, LLVMBuilderRef builder, g ctx->builder = builder; - const int num_args = 3; + const int num_args = 5; LLVMValueRef args [num_args]; args [0] = convert (ctx, get_aotconst (ctx, MONO_PATCH_INFO_AOT_JIT_INFO, GINT_TO_POINTER (ctx->cfg->method_index)), IntPtrType ()); args [1] = LLVMConstInt (LLVMInt32Type (), region_start, 0); args [2] = LLVMConstInt (LLVMInt32Type (), region_end, 0); + if (ctx->cfg->rgctx_var) { + LLVMValueRef rgctx_alloc = ctx->addresses [ctx->cfg->rgctx_var->dreg]; + g_assert (rgctx_alloc); + args [3] = LLVMBuildLoad (builder, convert (ctx, rgctx_alloc, LLVMPointerType (IntPtrType (), 0)), ""); + } else { + args [3] = LLVMConstInt (IntPtrType (), 0, 0); + } + if (ctx->this_arg) + args [4] = convert (ctx, ctx->this_arg, IntPtrType ()); + else + args [4] = LLVMConstInt (IntPtrType (), 0, 0); - LLVMTypeRef match_sig = LLVMFunctionType3 (LLVMInt32Type (), IntPtrType (), LLVMInt32Type (), LLVMInt32Type (), FALSE); + LLVMTypeRef match_sig = LLVMFunctionType5 (LLVMInt32Type (), IntPtrType (), LLVMInt32Type (), LLVMInt32Type (), IntPtrType (), IntPtrType (), FALSE); LLVMValueRef callee = ctx->module->match_exc; if (!callee) { @@ -3889,18 +3966,21 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) ctx->builder = builder; LLVMPositionBuilderAtEnd (builder, cbb); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return; if (bb->flags & BB_EXCEPTION_HANDLER) { if (!ctx->llvm_only && !bblocks [bb->block_num].invoke_target) { - LLVM_FAILURE (ctx, "handler without invokes"); + set_failure (ctx, "handler without invokes"); + return; } if (ctx->llvm_only) emit_llvmonly_handler_start (ctx, bb, cbb); else emit_handler_start (ctx, bb, builder); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return; builder = ctx->builder; } @@ -3914,9 +3994,20 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) emit_dbg_loc (ctx, builder, ins->cil_code); nins ++; - if (nins > 3000 && builder == starting_builder) { - /* some steps in llc are non-linear in the size of basic blocks, see #5714 */ - LLVM_FAILURE (ctx, "basic block too long"); + 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. + */ + //set_failure (ctx, "basic block too long"); + cbb = gen_bb (ctx, "CONT_LONG_BB"); + LLVMBuildBr (ctx->builder, cbb); + ctx->builder = builder = create_builder (ctx); + LLVMPositionBuilderAtEnd (builder, cbb); + ctx->bblocks [bb->block_num].end_bblock = cbb; + nins = 0; } if (has_terminator) @@ -3935,8 +4026,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) lhs = emit_volatile_load (ctx, ins->sreg1); } else { /* It is ok for SETRET to have an uninitialized argument */ - if (!values [ins->sreg1] && ins->opcode != OP_SETRET) - LLVM_FAILURE (ctx, "sreg1"); + if (!values [ins->sreg1] && ins->opcode != OP_SETRET) { + set_failure (ctx, "sreg1"); + return; + } lhs = values [ins->sreg1]; } } else { @@ -3948,8 +4041,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) { rhs = emit_volatile_load (ctx, ins->sreg2); } else { - if (!values [ins->sreg2]) - LLVM_FAILURE (ctx, "sreg2"); + if (!values [ins->sreg2]) { + set_failure (ctx, "sreg2"); + return; + } rhs = values [ins->sreg2]; } } else { @@ -4264,20 +4359,25 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) emit_volatile_store (ctx, ins->next->dreg); } else if (MONO_IS_COND_EXC (ins->next)) { emit_cond_system_exception (ctx, bb, (const char*)ins->next->inst_p1, cmp); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; builder = ctx->builder; } else { - LLVM_FAILURE (ctx, "next"); + set_failure (ctx, "next"); + break; } ins = ins->next; break; } case OP_FCEQ: + case OP_FCNEQ: case OP_FCLT: case OP_FCLT_UN: case OP_FCGT: - case OP_FCGT_UN: { + case OP_FCGT_UN: + case OP_FCGE: + case OP_FCLE: { CompRelation rel; LLVMValueRef cmp; @@ -4430,7 +4530,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) rhs = convert (ctx, rhs, regtype_to_llvm_type (spec [MONO_INST_DEST])); emit_div_check (ctx, builder, bb, ins, lhs, rhs); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; builder = ctx->builder; switch (ins->opcode) { @@ -4568,7 +4669,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) } emit_div_check (ctx, builder, bb, ins, lhs, imm); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; builder = ctx->builder; #if SIZEOF_VOID_P == 4 @@ -4731,6 +4833,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) case OP_RCONV_TO_U2: values [ins->dreg] = LLVMBuildZExt (builder, LLVMBuildFPToUI (builder, lhs, LLVMInt16Type (), dname), LLVMInt32Type (), ""); break; + case OP_RCONV_TO_U4: + values [ins->dreg] = LLVMBuildFPToUI (builder, lhs, LLVMInt32Type (), dname); + break; case OP_FCONV_TO_I8: case OP_RCONV_TO_I8: values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMInt64Type (), dname); @@ -4905,8 +5010,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) gboolean sext = FALSE, zext = FALSE; gboolean is_volatile = (ins->flags & MONO_INST_FAULT); - if (!values [ins->inst_destbasereg]) - LLVM_FAILURE (ctx, "inst_destbasereg"); + if (!values [ins->inst_destbasereg]) { + set_failure (ctx, "inst_destbasereg"); + break; + } t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext); @@ -4971,7 +5078,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) case OP_RCALL_REG: case OP_VCALL_REG: { process_call (ctx, bb, &builder, ins); - CHECK_FAILURE (ctx); break; } case OP_AOTCONST: { @@ -5011,7 +5117,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) name = get_aotconst_name (ji->type, ji->data.target, got_offset); values [ins->dreg] = LLVMBuildLoad (builder, got_entry_addr, name); g_free (name); - set_invariant_load_flag (values [ins->dreg]); + /* Can't use this in llvmonly mode since the got slots are initialized by the methods themselves */ + if (!cfg->llvm_only) + set_invariant_load_flag (values [ins->dreg]); break; } case OP_NOT_REACHED: @@ -5059,15 +5167,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) case OP_SQRT: { LLVMValueRef args [1]; -#if 0 - /* This no longer seems to happen */ - /* - * LLVM optimizes sqrt(nan) into undefined in - * lib/Analysis/ConstantFolding.cpp - * Also, sqrt(NegativeInfinity) is optimized into 0. - */ - LLVM_FAILURE (ctx, "sqrt"); -#endif args [0] = convert (ctx, lhs, LLVMDoubleType ()); values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (lmodule, "llvm.sqrt.f64"), args, 1, dname); break; @@ -5186,8 +5285,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) case OP_ATOMIC_LOAD_U8: case OP_ATOMIC_LOAD_R4: case OP_ATOMIC_LOAD_R8: { - LLVM_FAILURE (ctx, "atomic mono.load intrinsic"); - + set_failure (ctx, "atomic mono.load intrinsic"); + break; +#if 0 int size; gboolean sext, zext; LLVMTypeRef t; @@ -5216,6 +5316,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) else if (zext) values [ins->dreg] = LLVMBuildZExt (builder, values [ins->dreg], LLVMInt32Type (), dname); break; +#endif } case OP_ATOMIC_STORE_I1: case OP_ATOMIC_STORE_I2: @@ -5227,8 +5328,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) case OP_ATOMIC_STORE_U8: case OP_ATOMIC_STORE_R4: case OP_ATOMIC_STORE_R8: { - LLVM_FAILURE (ctx, "atomic mono.store intrinsic"); - + set_failure (ctx, "atomic mono.store intrinsic"); + break; +#if 0 int size; gboolean sext, zext; LLVMTypeRef t; @@ -5236,8 +5338,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind; LLVMValueRef index, addr, value; - if (!values [ins->inst_destbasereg]) - LLVM_FAILURE (ctx, "inst_destbasereg"); + if (!values [ins->inst_destbasereg]) { + set_failure (ctx, "inst_destbasereg"); + break; + } t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext); @@ -5247,6 +5351,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) emit_store_general (ctx, bb, &builder, size, value, addr, is_volatile, barrier); break; +#endif } case OP_RELAXED_NOP: { #if defined(TARGET_AMD64) || defined(TARGET_X86) @@ -5275,7 +5380,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256); values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, LLVMConstInt (IntPtrType (), offset, TRUE), ptrtype, ""), ""); #else - LLVM_FAILURE (ctx, "opcode tls-get"); + set_failure (ctx, "opcode tls-get"); + break; #endif break; @@ -5287,7 +5393,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256); values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt32Type ()), ptrtype, ""), ""); #else - LLVM_FAILURE (ctx, "opcode tls-get"); + set_failure (ctx, "opcode tls-get"); + break; #endif break; } @@ -5299,7 +5406,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256); LLVMBuildStore (builder, convert (ctx, lhs, IntPtrType ()), LLVMBuildIntToPtr (builder, convert (ctx, rhs, LLVMInt32Type ()), ptrtype, "")); #else - LLVM_FAILURE (ctx, "opcode tls-set-reg"); + set_failure (ctx, "opcode tls-set-reg"); + break; #endif break; } @@ -5332,7 +5440,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, dname); ovf = LLVMBuildExtractValue (builder, val, 1, ""); emit_cond_system_exception (ctx, bb, "OverflowException", ovf); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; builder = ctx->builder; break; } @@ -5350,7 +5459,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (!klass) { // FIXME: - LLVM_FAILURE (ctx, "!klass"); + set_failure (ctx, "!klass"); break; } @@ -5377,13 +5486,13 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (!klass) { // FIXME: - LLVM_FAILURE (ctx, "!klass"); + set_failure (ctx, "!klass"); break; } if (mini_is_gsharedvt_klass (klass)) { // FIXME: - LLVM_FAILURE (ctx, "gsharedvt"); + set_failure (ctx, "gsharedvt"); break; } @@ -5423,7 +5532,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) default: g_assert_not_reached (); } - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + break; if (done) break; @@ -5460,6 +5570,13 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) g_assert (addresses [ins->sreg1]); addresses [ins->dreg] = addresses [ins->sreg1]; } + } else if (ainfo->storage == LLVMArgGsharedvtFixed) { + if (!addresses [ins->sreg1]) { + addresses [ins->sreg1] = build_alloca (ctx, t); + g_assert (values [ins->sreg1]); + } + LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], LLVMGetElementType (LLVMTypeOf (addresses [ins->sreg1]))), addresses [ins->sreg1]); + addresses [ins->dreg] = addresses [ins->sreg1]; } else { if (!addresses [ins->sreg1]) { addresses [ins->sreg1] = build_alloca (ctx, t); @@ -5987,7 +6104,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) case OP_IMPLICIT_EXCEPTION: /* This marks a place where an implicit exception can happen */ if (bb->region != -1) - LLVM_FAILURE (ctx, "implicit-exception"); + set_failure (ctx, "implicit-exception"); break; case OP_THROW: case OP_RETHROW: { @@ -6084,15 +6201,20 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) has_terminator = TRUE; break; } + case OP_IL_SEQ_POINT: + break; default: { char reason [128]; sprintf (reason, "opcode %s", mono_inst_name (ins->opcode)); - LLVM_FAILURE (ctx, reason); + set_failure (ctx, reason); break; } } + if (!ctx_ok (ctx)) + break; + /* 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]) @@ -6107,6 +6229,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) emit_volatile_store (ctx, ins->dreg); } + if (!ctx_ok (ctx)) + return; + if (!has_terminator && bb->next_bb && (bb == cfg->bb_entry || bb->in_count > 0)) { LLVMBuildBr (builder, get_bb (ctx, bb->next_bb)); } @@ -6118,11 +6243,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (bb == cfg->bb_entry) ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry)); - - return; - - FAILURE: - return; } /* @@ -6235,6 +6355,35 @@ get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) return linfo; } +static void +emit_method_inner (EmitContext *ctx); + +static void +free_ctx (EmitContext *ctx) +{ + GSList *l; + + g_free (ctx->values); + g_free (ctx->addresses); + g_free (ctx->vreg_types); + g_free (ctx->vreg_cli_types); + g_free (ctx->is_dead); + g_free (ctx->unreachable); + g_ptr_array_free (ctx->phi_values, TRUE); + g_free (ctx->bblocks); + g_hash_table_destroy (ctx->region_to_handler); + g_hash_table_destroy (ctx->clause_to_handler); + g_free (ctx->method_name); + g_ptr_array_free (ctx->bblock_list, TRUE); + + for (l = ctx->builders; l; l = l->next) { + LLVMBuilderRef builder = (LLVMBuilderRef)l->data; + LLVMDisposeBuilder (builder); + } + + g_free (ctx); +} + /* * mono_llvm_emit_method: * @@ -6244,23 +6393,9 @@ void mono_llvm_emit_method (MonoCompile *cfg) { EmitContext *ctx; - MonoMethodSignature *sig; - MonoBasicBlock *bb; - LLVMTypeRef method_type; - LLVMValueRef method = NULL; char *method_name; - LLVMValueRef *values; - int i, max_block_num, bb_index; - gboolean last = FALSE; - GPtrArray *phi_values; - LLVMCallInfo *linfo; - GSList *l; - LLVMModuleRef lmodule; - BBInfo *bblocks; - GPtrArray *bblock_list; - MonoMethodHeader *header; - MonoExceptionClause *clause; - char **names; + gboolean is_linkonce = FALSE; + int i; /* The code below might acquire the loader lock, so use it for global locking */ mono_loader_lock (); @@ -6275,7 +6410,7 @@ mono_llvm_emit_method (MonoCompile *cfg) /* * This maps vregs to the LLVM instruction defining them */ - values = g_new0 (LLVMValueRef, cfg->next_vreg); + ctx->values = g_new0 (LLVMValueRef, cfg->next_vreg); /* * This maps vregs for volatile variables to the LLVM instruction defining their * address. @@ -6283,7 +6418,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->vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg); - phi_values = g_ptr_array_sized_new (256); + ctx->phi_values = g_ptr_array_sized_new (256); /* * This signals whenever the vreg was defined by a phi node with no input vars * (i.e. all its input bblocks end with NOT_REACHABLE). @@ -6291,28 +6426,98 @@ mono_llvm_emit_method (MonoCompile *cfg) ctx->is_dead = g_new0 (gboolean, cfg->next_vreg); /* Whenever the bblock is unreachable */ ctx->unreachable = g_new0 (gboolean, cfg->max_block_num); - bblock_list = g_ptr_array_sized_new (256); + ctx->bblock_list = g_ptr_array_sized_new (256); - ctx->values = values; ctx->region_to_handler = g_hash_table_new (NULL, NULL); ctx->clause_to_handler = g_hash_table_new (NULL, NULL); ctx->method_to_callers = g_hash_table_new (NULL, NULL); - - if (cfg->compile_aot) { + if (cfg->compile_aot) { ctx->module = &aot_module; - method_name = mono_aot_get_method_name (cfg); + + method_name = NULL; + /* + * Allow the linker to discard duplicate copies of wrappers, generic instances etc. by using the 'linkonce' + * linkage for them. This requires the following: + * - the method needs to have a unique mangled name + * - llvmonly mode, since the code in aot-runtime.c would initialize got slots in the wrong aot image etc. + */ + is_linkonce = ctx->module->llvm_only && ctx->module->static_link && mono_aot_is_linkonce_method (cfg->method); + if (is_linkonce) { + method_name = mono_aot_get_mangled_method_name (cfg->method); + if (!method_name) + is_linkonce = FALSE; + /* + if (method_name) + printf ("%s %s\n", mono_method_full_name (cfg->method, 1), method_name); + else + printf ("%s\n", mono_method_full_name (cfg->method, 1)); + */ + } + if (!method_name) + method_name = mono_aot_get_method_name (cfg); cfg->llvm_method_name = g_strdup (method_name); } else { init_jit_module (cfg->domain); ctx->module = (MonoLLVMModule*)domain_jit_info (cfg->domain)->llvm_module; method_name = mono_method_full_name (cfg->method, TRUE); } + ctx->method_name = method_name; + ctx->is_linkonce = is_linkonce; - lmodule = ctx->lmodule = ctx->module->lmodule; + ctx->lmodule = ctx->module->lmodule; ctx->llvm_only = ctx->module->llvm_only; - if (cfg->gsharedvt && !cfg->llvm_only) - LLVM_FAILURE (ctx, "gsharedvt"); + emit_method_inner (ctx); + + if (!ctx_ok (ctx)) { + if (ctx->lmethod) { + /* Need to add unused phi nodes as they can be referenced by other values */ + LLVMBasicBlockRef phi_bb = LLVMAppendBasicBlock (ctx->lmethod, "PHI_BB"); + LLVMBuilderRef builder; + + builder = create_builder (ctx); + LLVMPositionBuilderAtEnd (builder, phi_bb); + + for (i = 0; i < ctx->phi_values->len; ++i) { + LLVMValueRef v = (LLVMValueRef)g_ptr_array_index (ctx->phi_values, i); + if (LLVMGetInstructionParent (v) == NULL) + LLVMInsertIntoBuilder (builder, v); + } + + LLVMDeleteFunction (ctx->lmethod); + } + } + + free_ctx (ctx); + + mono_native_tls_set_value (current_cfg_tls_id, NULL); + + mono_loader_unlock (); +} + +static void +emit_method_inner (EmitContext *ctx) +{ + MonoCompile *cfg = ctx->cfg; + MonoMethodSignature *sig; + MonoBasicBlock *bb; + LLVMTypeRef method_type; + LLVMValueRef method = NULL; + LLVMValueRef *values = ctx->values; + int i, max_block_num, bb_index; + gboolean last = FALSE; + LLVMCallInfo *linfo; + LLVMModuleRef lmodule = ctx->lmodule; + BBInfo *bblocks; + GPtrArray *bblock_list = ctx->bblock_list; + MonoMethodHeader *header; + MonoExceptionClause *clause; + char **names; + + if (cfg->gsharedvt && !cfg->llvm_only) { + set_failure (ctx, "gsharedvt"); + return; + } #if 1 { @@ -6325,8 +6530,10 @@ mono_llvm_emit_method (MonoCompile *cfg) fflush (stdout); last = TRUE; } - if (count > atoi (g_getenv ("LLVM_COUNT"))) - LLVM_FAILURE (ctx, ""); + if (count > atoi (g_getenv ("LLVM_COUNT"))) { + set_failure (ctx, "count"); + return; + } } } #endif @@ -6336,14 +6543,16 @@ mono_llvm_emit_method (MonoCompile *cfg) linfo = get_llvm_call_info (cfg, sig); ctx->linfo = linfo; - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return; if (cfg->rgctx_var) linfo->rgctx_arg = TRUE; - method_type = sig_to_llvm_sig_full (ctx, sig, linfo); - CHECK_FAILURE (ctx); + ctx->method_type = method_type = sig_to_llvm_sig_full (ctx, sig, linfo); + if (!ctx_ok (ctx)) + return; - method = LLVMAddFunction (lmodule, method_name, method_type); + method = LLVMAddFunction (lmodule, ctx->method_name, method_type); ctx->lmethod = method; if (!cfg->llvm_only) @@ -6358,23 +6567,33 @@ mono_llvm_emit_method (MonoCompile *cfg) LLVMSetLinkage (method, LLVMExternalLinkage); LLVMSetVisibility (method, LLVMHiddenVisibility); } + if (ctx->is_linkonce) { + LLVMSetLinkage (method, LLVMLinkOnceAnyLinkage); + LLVMSetVisibility (method, LLVMDefaultVisibility); + } } else { LLVMSetLinkage (method, LLVMPrivateLinkage); } - if (cfg->method->save_lmf && !cfg->llvm_only) - LLVM_FAILURE (ctx, "lmf"); + if (cfg->method->save_lmf && !cfg->llvm_only) { + set_failure (ctx, "lmf"); + return; + } - if (sig->pinvoke && cfg->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && !cfg->llvm_only) - LLVM_FAILURE (ctx, "pinvoke signature"); + if (sig->pinvoke && cfg->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && !cfg->llvm_only) { + set_failure (ctx, "pinvoke signature"); + return; + } header = cfg->header; for (i = 0; i < header->num_clauses; ++i) { clause = &header->clauses [i]; - if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) - LLVM_FAILURE (ctx, "non-finally/catch clause."); + if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) { + set_failure (ctx, "non-finally/catch clause."); + return; + } } - if (header->num_clauses || (cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) + if (header->num_clauses || (cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) || cfg->no_inline) /* We can't handle inlined methods with clauses */ LLVMAddFunctionAttr (method, LLVMNoInlineAttribute); @@ -6457,7 +6676,7 @@ mono_llvm_emit_method (MonoCompile *cfg) if (ctx->module->emit_dwarf && cfg->compile_aot && mono_debug_enabled ()) { ctx->minfo = mono_debug_lookup_method (cfg->method); - ctx->dbg_md = emit_dbg_subprogram (ctx, cfg, method, method_name); + ctx->dbg_md = emit_dbg_subprogram (ctx, cfg, method, ctx->method_name); } max_block_num = 0; @@ -6509,7 +6728,8 @@ mono_llvm_emit_method (MonoCompile *cfg) case OP_XPHI: { LLVMTypeRef phi_type = llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, &ins->klass->byval_arg)); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return; if (ins->opcode == OP_VPHI) { /* Treat valuetype PHI nodes as operating on the address itself */ @@ -6528,7 +6748,7 @@ mono_llvm_emit_method (MonoCompile *cfg) if (ins->opcode == OP_VPHI) ctx->addresses [ins->dreg] = values [ins->dreg]; - g_ptr_array_add (phi_values, values [ins->dreg]); + g_ptr_array_add (ctx->phi_values, values [ins->dreg]); /* * Set the expected type of the incoming arguments since these have @@ -6608,7 +6828,8 @@ mono_llvm_emit_method (MonoCompile *cfg) continue; process_bb (ctx, bb); - CHECK_FAILURE (ctx); + if (!ctx_ok (ctx)) + return; } g_hash_table_destroy (ctx->exc_meta); @@ -6634,17 +6855,20 @@ mono_llvm_emit_method (MonoCompile *cfg) if (ctx->unreachable [node->in_bb->block_num]) continue; - if (!values [sreg1]) + if (!values [sreg1]) { /* Can happen with values in EH clauses */ - LLVM_FAILURE (ctx, "incoming phi sreg1"); + set_failure (ctx, "incoming phi sreg1"); + return; + } if (phi->opcode == OP_VPHI) { g_assert (LLVMTypeOf (ctx->addresses [sreg1]) == LLVMTypeOf (values [phi->dreg])); LLVMAddIncoming (values [phi->dreg], &ctx->addresses [sreg1], &in_bb, 1); } else { - if (LLVMTypeOf (values [sreg1]) != LLVMTypeOf (values [phi->dreg])) - // FIXME: - LLVM_FAILURE (ctx, "incoming phi arg type mismatch"); + if (LLVMTypeOf (values [sreg1]) != LLVMTypeOf (values [phi->dreg])) { + set_failure (ctx, "incoming phi arg type mismatch"); + return; + } g_assert (LLVMTypeOf (values [sreg1]) == LLVMTypeOf (values [phi->dreg])); LLVMAddIncoming (values [phi->dreg], &values [sreg1], &in_bb, 1); } @@ -6730,13 +6954,13 @@ mono_llvm_emit_method (MonoCompile *cfg) if (cfg->compile_aot && !cfg->llvm_only) mark_as_used (ctx->module, method); - if (cfg->compile_aot) { + if (cfg->compile_aot && !cfg->llvm_only) { LLVMValueRef md_args [16]; LLVMValueRef md_node; int method_index; method_index = mono_aot_get_method_index (cfg->orig_method); - md_args [0] = LLVMMDString (method_name, strlen (method_name)); + md_args [0] = LLVMMDString (ctx->method_name, strlen (ctx->method_name)); md_args [1] = LLVMConstInt (LLVMInt32Type (), method_index, FALSE); md_node = LLVMMDNode (md_args, 2); LLVMAddNamedMetadataOperand (lmodule, "mono.function_indexes", md_node); @@ -6746,78 +6970,30 @@ mono_llvm_emit_method (MonoCompile *cfg) if (cfg->compile_aot) { /* Don't generate native code, keep the LLVM IR */ if (cfg->verbose_level) - printf ("%s emitted as %s\n", mono_method_full_name (cfg->method, TRUE), method_name); + printf ("%s emitted as %s\n", mono_method_full_name (cfg->method, TRUE), ctx->method_name); - int err = LLVMVerifyFunction(method, LLVMPrintMessageAction); + int err = LLVMVerifyFunction(ctx->lmethod, LLVMPrintMessageAction); g_assert (err == 0); } else { //LLVMVerifyFunction(method, 0); - mono_llvm_optimize_method (ctx->module->mono_ee, method); + mono_llvm_optimize_method (ctx->module->mono_ee, ctx->lmethod); if (cfg->verbose_level > 1) - mono_llvm_dump_value (method); + mono_llvm_dump_value (ctx->lmethod); - cfg->native_code = (unsigned char*)LLVMGetPointerToGlobal (ctx->module->ee, method); + cfg->native_code = (unsigned char*)LLVMGetPointerToGlobal (ctx->module->ee, ctx->lmethod); /* Set by emit_cb */ g_assert (cfg->code_len); - - /* FIXME: Free the LLVM IL for the function */ } if (ctx->module->method_to_lmethod) - g_hash_table_insert (ctx->module->method_to_lmethod, cfg->method, method); + g_hash_table_insert (ctx->module->method_to_lmethod, cfg->method, ctx->lmethod); if (ctx->module->idx_to_lmethod) - g_hash_table_insert (ctx->module->idx_to_lmethod, GINT_TO_POINTER (cfg->method_index), method); + g_hash_table_insert (ctx->module->idx_to_lmethod, GINT_TO_POINTER (cfg->method_index), ctx->lmethod); if (ctx->llvm_only && cfg->orig_method->klass->valuetype && !(cfg->orig_method->flags & METHOD_ATTRIBUTE_STATIC)) - emit_unbox_tramp (ctx, method_name, method_type, method, cfg->method_index); - - goto CLEANUP; - - FAILURE: - - if (method) { - /* Need to add unused phi nodes as they can be referenced by other values */ - LLVMBasicBlockRef phi_bb = LLVMAppendBasicBlock (method, "PHI_BB"); - LLVMBuilderRef builder; - - builder = create_builder (ctx); - LLVMPositionBuilderAtEnd (builder, phi_bb); - - for (i = 0; i < phi_values->len; ++i) { - LLVMValueRef v = (LLVMValueRef)g_ptr_array_index (phi_values, i); - if (LLVMGetInstructionParent (v) == NULL) - LLVMInsertIntoBuilder (builder, v); - } - - LLVMDeleteFunction (method); - } - - CLEANUP: - g_free (values); - g_free (ctx->addresses); - g_free (ctx->vreg_types); - g_free (ctx->vreg_cli_types); - g_free (ctx->is_dead); - g_free (ctx->unreachable); - g_ptr_array_free (phi_values, TRUE); - g_free (ctx->bblocks); - g_hash_table_destroy (ctx->region_to_handler); - g_hash_table_destroy (ctx->clause_to_handler); - g_free (method_name); - g_ptr_array_free (bblock_list, TRUE); - - for (l = ctx->builders; l; l = l->next) { - LLVMBuilderRef builder = (LLVMBuilderRef)l->data; - LLVMDisposeBuilder (builder); - } - - g_free (ctx); - - mono_native_tls_set_value (current_cfg_tls_id, NULL); - - mono_loader_unlock (); + emit_unbox_tramp (ctx, ctx->method_name, ctx->method_type, ctx->lmethod, cfg->method_index); } /* @@ -6833,7 +7009,7 @@ mono_llvm_create_vars (MonoCompile *cfg) 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_get_int32_class ()->byval_arg, OP_ARG); + cfg->vret_addr = mono_compile_create_var (cfg, &mono_get_intptr_class ()->byval_arg, OP_ARG); if (G_UNLIKELY (cfg->verbose_level > 1)) { printf ("vret_addr = "); mono_print_ins (cfg->vret_addr); @@ -7458,6 +7634,10 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, module->max_got_offset = 16; module->context = LLVMContextCreate (); + if (llvm_only) + /* clang ignores our debug info because it has an invalid version */ + module->emit_dwarf = FALSE; + add_intrinsics (module->lmodule); add_types (module); @@ -7651,16 +7831,21 @@ emit_aot_file_info (MonoLLVMModule *module) fields [tindex ++] = AddJitGlobal (module, eltype, "method_addresses"); else fields [tindex ++] = LLVMConstNull (eltype); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "blob"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "class_name_table"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "class_info_offsets"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "method_info_offsets"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "ex_info_offsets"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "extra_method_info_offsets"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "extra_method_table"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "got_info_offsets"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "llvm_got_info_offsets"); - fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "image_table"); + if (info->flags & MONO_AOT_FILE_FLAG_SEPARATE_DATA) { + for (i = 0; i < MONO_AOT_TABLE_NUM; ++i) + fields [tindex ++] = LLVMConstNull (eltype); + } else { + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "blob"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "class_name_table"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "class_info_offsets"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "method_info_offsets"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "ex_info_offsets"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "extra_method_info_offsets"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "extra_method_table"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "got_info_offsets"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "llvm_got_info_offsets"); + fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "image_table"); + } /* Not needed (mem_end) */ fields [tindex ++] = LLVMConstNull (eltype); fields [tindex ++] = LLVMGetNamedGlobal (lmodule, "assembly_guid"); @@ -7676,7 +7861,7 @@ emit_aot_file_info (MonoLLVMModule *module) fields [tindex ++] = LLVMConstNull (eltype); fields [tindex ++] = LLVMConstNull (eltype); } - if (module->static_link) + if (module->static_link && !module->llvm_only) fields [tindex ++] = AddJitGlobal (module, eltype, "globals"); else fields [tindex ++] = LLVMConstNull (eltype);