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;
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;
LLVMValueRef ex_var;
GHashTable *exc_meta;
GHashTable *method_to_callers;
+ GPtrArray *phi_values;
+ GPtrArray *bblock_list;
+ char *method_name;
} EmitContext;
typedef struct {
#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,
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:
*
static gboolean
type_is_unsigned (EmitContext *ctx, MonoType *t)
{
+ t = mini_get_underlying_type (t);
if (t->byref)
return FALSE;
switch (t->type) {
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 ();
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;
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;
}
/*
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:
*/
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 ++;
}
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;
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;
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) {
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
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:
*
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 : "");
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;
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);
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;
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
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 */
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;
default:
break;
}
-
- FAILURE:
- return;
}
/*
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);
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 ();
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
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;
}
}
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
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);
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);
} 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
}
}
- 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);
*/
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);
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;
* 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);
}
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;
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]);
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;
}
*builder_ref = ctx->builder;
-
- return;
- FAILURE:
- return;
}
static void
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));
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) {
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;
}
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)
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 {
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 {
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;
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) {
}
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
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);
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);
case OP_RCALL_REG:
case OP_VCALL_REG: {
process_call (ctx, bb, &builder, ins);
- CHECK_FAILURE (ctx);
break;
}
case OP_AOTCONST: {
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:
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;
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;
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:
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;
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);
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)
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;
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;
}
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;
}
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;
}
if (!klass) {
// FIXME:
- LLVM_FAILURE (ctx, "!klass");
+ set_failure (ctx, "!klass");
break;
}
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;
}
default:
g_assert_not_reached ();
}
- CHECK_FAILURE (ctx);
+ if (!ctx_ok (ctx))
+ break;
if (done)
break;
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);
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: {
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])
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));
}
if (bb == cfg->bb_entry)
ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry));
-
- return;
-
- FAILURE:
- return;
}
/*
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:
*
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 ();
/*
* 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.
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).
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
{
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
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)
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);
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;
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 */
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
continue;
process_bb (ctx, bb);
- CHECK_FAILURE (ctx);
+ if (!ctx_ok (ctx))
+ return;
}
g_hash_table_destroy (ctx->exc_meta);
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);
}
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);
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);
}
/*
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);
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);
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");
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);