static guint32 current_cfg_tls_id;
static MonoLLVMModule jit_module, aot_module;
+static gboolean jit_module_inited;
+
+static void init_jit_module (void);
/*
* IntPtrType:
if (!callee) {
callee = LLVMAddFunction (ctx->module, callee_name, llvm_sig);
+ LLVMSetVisibility (callee, LLVMHiddenVisibility);
+
g_hash_table_insert (ctx->lmodule->plt_entries, (char*)callee_name, callee);
}
LLVMBuilderRef builder = *builder_ref;
// FIXME: Nested clauses
- if (bb->region && MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
+ if (bb->region != -1 && MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
MonoMethodHeader *header = mono_method_get_header (cfg->method);
// FIXME: Add a macro for this
int clause_index = (bb->region >> 8) - 1;
callee = get_plt_entry (ctx, sig, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_corlib_exception");
} else {
callee = LLVMAddFunction (ctx->module, "throw_corlib_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
-
+
+#ifdef TARGET_X86
+ /*
+ * LLVM generated code doesn't push the arguments, so we need another
+ * throw trampoline.
+ */
+ LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_llvm_throw_corlib_exception"));
+#else
LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_corlib_exception"));
+#endif
}
mono_memory_barrier ();
ctx->lmodule->throw_corlib_exception = callee;
}
+#ifdef TARGET_X86
+ args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token - MONO_TOKEN_TYPE_DEF, FALSE);
+#else
args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token, FALSE);
+#endif
/*
* FIXME: The offset is 0, this is not a problem for exception handling
* in general, because we don't llvm compile methods with handlers, its only
ctx->addresses [reg] = build_alloca (ctx, sig->params [i]);
emit_reg_to_vtype (ctx, builder, sig->params [i], ctx->addresses [reg], ainfo, regs);
+
+ if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (sig->params [i]))) {
+ /* Treat these as normal values */
+ ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
+ }
} else if (ainfo->storage == LLVMArgVtypeByVal) {
ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, pindexes [i]);
} else {
method_name = mono_aot_get_method_name (cfg);
debug_name = mono_aot_get_method_debug_name (cfg);
} else {
+ init_jit_module ();
ctx->lmodule = &jit_module;
method_name = mono_method_full_name (cfg->method, TRUE);
debug_name = NULL;
type_info = LLVMAddGlobal (module, LLVMInt32Type (), ti_name);
LLVMSetInitializer (type_info, LLVMConstInt (LLVMInt32Type (), clause_index, FALSE));
+ LLVMSetLinkage (type_info, LLVMPrivateLinkage);
+ LLVMSetVisibility (type_info, LLVMHiddenVisibility);
+
/*
* FIXME: llc currently generates incorrect data in the LSDA:
* .byte 0x9B # @TType format (indirect pcrel sdata4)
case OP_LOADU4_MEM:
case OP_LOAD_MEM: {
int size = 8;
- LLVMValueRef index;
+ LLVMValueRef index, addr;
LLVMTypeRef t;
gboolean sext = FALSE, zext = FALSE;
+ gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
dname = (char*)"";
/*
- * We emit volatile loads because otherwise LLVM will
- * generate invalid code when encountering a load from a
+ * We emit volatile loads for loads which can fault, because otherwise
+ * LLVM will generate invalid code when encountering a load from a
* NULL address.
- * FIXME: Avoid this somehow.
*/
- g_assert (ins->inst_offset % size == 0);
if ((ins->opcode == OP_LOADI8_MEM) || (ins->opcode == OP_LOAD_MEM) || (ins->opcode == OP_LOADI4_MEM) || (ins->opcode == OP_LOADU4_MEM) || (ins->opcode == OP_LOADU1_MEM) || (ins->opcode == OP_LOADU2_MEM)) {
- values [ins->dreg] = mono_llvm_build_volatile_load (builder, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), LLVMPointerType (t, 0)), dname);
+ addr = LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE);
} else if (ins->inst_offset == 0) {
- values [ins->dreg] = mono_llvm_build_volatile_load (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), dname);
+ addr = values [ins->inst_basereg];
+ } else if (ins->inst_offset % size != 0) {
+ /* Unaligned load */
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
} else {
index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
- values [ins->dreg] = mono_llvm_build_volatile_load (builder, LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), &index, 1, ""), dname);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), &index, 1, "");
}
+
+ addr = convert (ctx, addr, LLVMPointerType (t, 0));
+
+ values [ins->dreg] = mono_llvm_build_load (builder, addr, dname, is_volatile);
+
if (sext)
values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
else if (zext)
case OP_STORER8_MEMBASE_REG:
case OP_STORE_MEMBASE_REG: {
int size = 8;
- LLVMValueRef index;
+ LLVMValueRef index, addr;
LLVMTypeRef t;
gboolean sext = FALSE, zext = FALSE;
t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
- g_assert (ins->inst_offset % size == 0);
- index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
- LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], t), LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""));
+ if (ins->inst_offset % size != 0) {
+ /* Unaligned store */
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+ } else {
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+ }
+ LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)));
break;
}
case OP_STOREI8_MEMBASE_IMM:
case OP_STORE_MEMBASE_IMM: {
int size = 8;
- LLVMValueRef index;
+ LLVMValueRef index, addr;
LLVMTypeRef t;
gboolean sext = FALSE, zext = FALSE;
t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
- g_assert (ins->inst_offset % size == 0);
- index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
- LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""));
+ if (ins->inst_offset % size != 0) {
+ /* Unaligned store */
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+ } else {
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+ }
+ LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), addr);
break;
}
case OP_CHECK_THIS:
- mono_llvm_build_volatile_load (builder, convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "");
+ mono_llvm_build_load (builder, convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "", TRUE);
break;
case OP_OUTARG_VTRETADDR:
break;
guint32 got_offset;
LLVMValueRef indexes [2];
MonoJumpInfo *ji;
+ LLVMValueRef got_entry_addr;
/*
* FIXME: Can't allocate from the cfg mempool since that is freed if
indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
indexes [1] = LLVMConstInt (LLVMInt32Type (), (gssize)got_offset, FALSE);
- values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildGEP (builder, ctx->lmodule->got_var, indexes, 2, ""), dname);
+ got_entry_addr = LLVMBuildGEP (builder, ctx->lmodule->got_var, indexes, 2, "");
+
+ // FIXME: This doesn't work right now, because it must be
+ // paired with an invariant.end, and even then, its only in effect
+ // inside its basic block
+#if 0
+ {
+ LLVMValueRef args [3];
+ LLVMValueRef ptr, val;
+
+ ptr = LLVMBuildBitCast (builder, got_entry_addr, LLVMPointerType (LLVMInt8Type (), 0), "ptr");
+
+ args [0] = LLVMConstInt (LLVMInt64Type (), sizeof (gpointer), FALSE);
+ args [1] = ptr;
+ val = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.invariant.start"), args, 2, "");
+ }
+#endif
+
+ values [ins->dreg] = LLVMBuildLoad (builder, got_entry_addr, dname);
break;
}
case OP_NOT_REACHED:
callee = get_plt_entry (ctx, sig_to_llvm_sig (ctx, throw_sig, NULL), MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception");
} else {
callee = LLVMAddFunction (module, "mono_arch_throw_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
+
+#ifdef TARGET_X86
+ /*
+ * LLVM doesn't push the exception argument, so we need a different
+ * trampoline.
+ */
+ LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_llvm_throw_exception"));
+#else
LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception"));
+#endif
}
mono_memory_barrier ();
/* Can't delete the method if it has an alias, so only add it if successful */
if (debug_name) {
debug_alias = LLVMAddAlias (module, LLVMTypeOf (method), method, debug_name);
+ LLVMSetLinkage (debug_alias, LLVMInternalLinkage);
LLVMSetVisibility (debug_alias, LLVMHiddenVisibility);
}
LLVMAddFunction (module, "llvm.umul.with.overflow.i64", LLVMFunctionType (LLVMStructType (ovf_res_i64, 2, FALSE), ovf_params_i64, 2, FALSE));
}
+ {
+ LLVMTypeRef struct_ptr = LLVMPointerType (LLVMStructType (NULL, 0, FALSE), 0);
+ LLVMTypeRef invariant_start_params [] = { LLVMInt64Type (), LLVMPointerType (LLVMInt8Type (), 0) };
+ LLVMTypeRef invariant_end_params [] = { struct_ptr, LLVMInt64Type (), LLVMPointerType (LLVMInt8Type (), 0) };
+
+ LLVMAddFunction (module, "llvm.invariant.start", LLVMFunctionType (struct_ptr, invariant_start_params, 2, FALSE));
+
+ LLVMAddFunction (module, "llvm.invariant.end", LLVMFunctionType (LLVMVoidType (), invariant_end_params, 3, FALSE));
+ }
+
/* EH intrinsics */
{
LLVMTypeRef arg_types [2];
mono_llvm_init (void)
{
current_cfg_tls_id = TlsAlloc ();
+}
+
+static void
+init_jit_module (void)
+{
+ if (jit_module_inited)
+ return;
+
+ mono_loader_lock ();
+
+ if (jit_module_inited) {
+ mono_loader_unlock ();
+ return;
+ }
jit_module.module = LLVMModuleCreateWithName ("mono");
jit_module.llvm_types = g_hash_table_new (NULL, NULL);
LLVMAddGlobalMapping (ee, LLVMGetNamedFunction (jit_module.module, "mono_resume_unwind"), mono_resume_unwind);
+
+ jit_module_inited = TRUE;
+
+ mono_loader_unlock ();
}
void
mono_llvm_cleanup (void)
{
- mono_llvm_dispose_ee (ee);
+ if (ee)
+ mono_llvm_dispose_ee (ee);
- g_hash_table_destroy (jit_module.llvm_types);
+ if (jit_module.llvm_types)
+ g_hash_table_destroy (jit_module.llvm_types);
}
void
LLVMSetInitializer (aot_module.got_var, LLVMConstNull (got_type));
}
- /* Add a method to generate the 'methods' symbol needed by the AOT compiler */
- {
- LLVMValueRef methods_method = LLVMAddFunction (aot_module.module, "methods", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
- LLVMBasicBlockRef bb = LLVMAppendBasicBlock (methods_method, "BB_ENTRY");
- LLVMBuilderRef builder = LLVMCreateBuilder ();
- LLVMPositionBuilderAtEnd (builder, bb);
- LLVMBuildRetVoid (builder);
- }
-
/* Add a dummy personality function */
{
LLVMBasicBlockRef lbb;
mark_as_used (aot_module.module, real_got);
+ /* Delete the dummy got so it doesn't become a global */
+ LLVMDeleteGlobal (aot_module.got_var);
+
#if 0
{
char *verifier_err;