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:
*
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
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;
}
/*
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]) {
ctx->addresses [var->dreg] = build_alloca (ctx, 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;
}
*builder_ref = ctx->builder;
-
- return;
- FAILURE:
- return;
}
static void
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;
}
* can work around that by doing a volatile load + cond branch from
* localloc-ed memory.
*/
- //LLVM_FAILURE (ctx, "basic block too long");
+ //set_failure (ctx, "basic block too long");
cbb = gen_bb (ctx, "CONT_LONG_BB");
LLVMBuildBr (ctx->builder, cbb);
ctx->builder = builder = create_builder (ctx);
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;
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
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: {
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;
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: {
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, is_linkonce = 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 = NULL;
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 (is_linkonce) {
+ if (ctx->is_linkonce) {
LLVMSetLinkage (method, LLVMLinkOnceAnyLinkage);
LLVMSetVisibility (method, LLVMDefaultVisibility);
}
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) || cfg->no_inline)
/* We can't handle inlined methods with clauses */
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);
}
/*