#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mempool-internals.h>
+#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
+#endif
#include "llvm-c/Core.h"
#include "llvm-c/ExecutionEngine.h"
MonoMethodSignature *sig;
GSList *builders;
GHashTable *region_to_handler;
+ LLVMBuilderRef alloca_builder;
+ LLVMValueRef last_alloca;
char temp_name [32];
} EmitContext;
case OP_IMUL_OVF_UN:
return LLVMInt32Type ();
case OP_LADD_OVF:
+ case OP_LADD_OVF_UN:
case OP_LSUB_OVF:
case OP_LSUB_OVF_UN:
case OP_LMUL_OVF:
simd_op_to_intrins (int opcode)
{
switch (opcode) {
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
case OP_MINPD:
return "llvm.x86.sse2.min.pd";
case OP_MINPS:
return "llvm.x86.sse41.pmaxuw";
case OP_PMAXB_UN:
return "llvm.x86.sse41.pmaxub";
+#endif
default:
g_assert_not_reached ();
return NULL;
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
while (mono_is_power_of_two (align) == -1)
align ++;
- return mono_llvm_build_alloca (ctx->builder, type_to_llvm_type (ctx, t), NULL, align, "");
+ /*
+ * Have to place all alloca's at the end of the entry bb, since otherwise they would
+ * get executed every time control reaches them.
+ */
+ LLVMPositionBuilder (ctx->alloca_builder, get_bb (ctx, ctx->cfg->bb_entry), ctx->last_alloca);
+
+ ctx->last_alloca = mono_llvm_build_alloca (ctx->alloca_builder, type_to_llvm_type (ctx, t), NULL, align, "");
+ return ctx->last_alloca;
}
/*
LLVMCallInfo *linfo = ctx->linfo;
MonoBasicBlock *bb;
+ ctx->alloca_builder = create_builder (ctx);
+
/*
* Handle indirect/volatile variables by allocating memory for them
* using 'alloca', and storing their address in a temporary.
}
}
+ if (cfg->vret_addr)
+ emit_volatile_store (ctx, cfg->vret_addr->dreg);
if (sig->hasthis)
emit_volatile_store (ctx, cfg->args [0]->dreg);
for (i = 0; i < sig->param_count; ++i)
FAILURE:
;
}
+
+/* Have to export this for AOT */
+void
+mono_personality (void);
-static void
+void
mono_personality (void)
{
/* Not used */
LLVMValueRef eh_selector, eh_exception, personality, args [4];
MonoInst *exvar;
static gint32 mapping_inited;
+ static int ti_generator;
+ char ti_name [128];
+ MonoClass **ti;
+ LLVMValueRef type_info;
+ int clause_index;
if (!bblocks [bb->block_num].invoke_target) {
/*
eh_selector = LLVMGetNamedFunction (module, "llvm.eh.selector");
- personality = LLVMGetNamedFunction (module, "mono_personality");
- if (InterlockedCompareExchange (&mapping_inited, 1, 0) == 0)
- LLVMAddGlobalMapping (ee, personality, mono_personality);
+ if (cfg->compile_aot) {
+ /* Use a dummy personality function */
+ personality = LLVMGetNamedFunction (module, "mono_aot_personality");
+ g_assert (personality);
+ } else {
+ personality = LLVMGetNamedFunction (module, "mono_personality");
+ if (InterlockedCompareExchange (&mapping_inited, 1, 0) == 0)
+ LLVMAddGlobalMapping (ee, personality, mono_personality);
+ }
i8ptr = LLVMPointerType (LLVMInt8Type (), 0);
+
+ clause_index = (mono_get_block_region_notry (cfg, bb->region) >> 8) - 1;
+
+ /*
+ * Create the type info
+ */
+ sprintf (ti_name, "type_info_%d", ti_generator);
+ ti_generator ++;
+
+ if (cfg->compile_aot) {
+ /* decode_eh_frame () in aot-runtime.c will decode this */
+ type_info = LLVMAddGlobal (module, LLVMInt32Type (), ti_name);
+ LLVMSetInitializer (type_info, LLVMConstInt (LLVMInt32Type (), clause_index, FALSE));
+
+ /*
+ * FIXME: llc currently generates incorrect data in the LSDA:
+ * .byte 0x9B # @TType format (indirect pcrel sdata4)
+ * and later:
+ * .quad type_info_1 # TypeInfo
+ */
+ LLVM_FAILURE (ctx, "aot+clauses");
+ } else {
+ /* exception_cb will decode this */
+ ti = g_malloc (sizeof (MonoExceptionClause));
+ memcpy (ti, &mono_method_get_header (cfg->method)->clauses [clause_index], sizeof (MonoExceptionClause));
+
+ type_info = LLVMAddGlobal (module, i8ptr, ti_name);
+
+ LLVMAddGlobalMapping (ee, type_info, ti);
+ }
+
args [0] = LLVMConstNull (i8ptr);
args [1] = LLVMConstBitCast (personality, i8ptr);
- args [2] = LLVMConstNull (i8ptr);
- args [3] = LLVMConstNull (LLVMInt32Type ());
+ args [2] = type_info;
LLVMBuildCall (builder, eh_selector, args, 3, "");
/* Store the exception into the exvar */
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_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;
llvm_sig = sig_to_llvm_sig (ctx, sig, cinfo);
CHECK_FAILURE (ctx);
- if (call->rgctx_reg) {
- LLVM_FAILURE (ctx, "rgctx reg");
- }
-
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);
calli = (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);
MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, call->fptr);
if (abs_ji) {
/*
- * The monitor entry/exit trampolines have their
- * own calling convention, and call->signature
- * doesn't include the argument.
+ * The monitor entry/exit 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_EXIT)
LLVM_FAILURE (ctx, "monitor enter/exit");
+#endif
target = mono_resolve_patch_target (cfg->method, cfg->domain, NULL, abs_ji, FALSE);
LLVMAddGlobalMapping (ee, callee, target);
}
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:
}
*/
+ case OP_ABS: {
+ LLVMValueRef args [1];
+
+ args [0] = lhs;
+ values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "fabs"), args, 1, dname);
+ break;
+ }
+
case OP_IMIN:
case OP_LMIN: {
LLVMValueRef v = LLVMBuildICmp (builder, LLVMIntSLE, lhs, rhs, "");
case OP_IMUL_OVF_UN:
#if SIZEOF_VOID_P == 8
case OP_LADD_OVF:
+ case OP_LADD_OVF_UN:
case OP_LSUB_OVF:
case OP_LSUB_OVF_UN:
case OP_LMUL_OVF:
/*
* SIMD
*/
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
case OP_XZERO: {
values [ins->dreg] = LLVMConstNull (type_to_llvm_type (ctx, &ins->klass->byval_arg));
break;
values [ins->dreg] = LLVMBuildExtractElement (builder, lhs, LLVMConstInt (LLVMInt32Type (), ins->inst_c0, FALSE), "");
break;
}
+#endif
case OP_DUMMY_USE:
break;
/*
* EXCEPTION HANDLING
*/
+ case OP_IMPLICIT_EXCEPTION:
+ /* This marks a place where an implicit exception can happen */
+ if (bb->region != -1)
+ LLVM_FAILURE (ctx, "implicit-exception");
+ break;
case OP_THROW: {
MonoMethodSignature *throw_sig;
LLVMValueRef callee, arg;
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 ();
if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID)
LLVMBuildRetVoid (builder);
+
+ if (bb == cfg->bb_entry)
+ ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry));
}
/* Add incoming phi values */
{
MonoCompile *cfg;
MonoJitExceptionInfo *ei;
- guint32 ei_len;
+ guint32 ei_len, i;
+ gpointer *type_info;
cfg = TlsGetValue (current_cfg_tls_id);
g_assert (cfg);
* An alternative would be to save it directly, and modify our unwinder to work
* with it.
*/
- cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len);
+ cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info);
cfg->llvm_ex_info = mono_mempool_alloc0 (cfg->mempool, ei_len * sizeof (MonoJitExceptionInfo));
cfg->llvm_ex_info_len = ei_len;
memcpy (cfg->llvm_ex_info, ei, ei_len * sizeof (MonoJitExceptionInfo));
+ /* Fill the rest of the information from the type info */
+ for (i = 0; i < ei_len; ++i) {
+ MonoExceptionClause *clause = type_info [i];
+
+ cfg->llvm_ex_info [i].flags = clause->flags;
+ cfg->llvm_ex_info [i].data.catch_class = clause->data.catch_class;
+ }
+
g_free (ei);
}
LLVMAddFunction (module, "llvm.sin.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
LLVMAddFunction (module, "llvm.cos.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
LLVMAddFunction (module, "llvm.sqrt.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
+
+ /* This isn't an intrinsic, instead llvm seems to special case it by name */
+ LLVMAddFunction (module, "fabs", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
}
{
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];
LLVMBuildRetVoid (builder);
}
+ /* Add a dummy personality function */
+ {
+ LLVMBasicBlockRef lbb;
+ LLVMBuilderRef lbuilder;
+ LLVMValueRef personality;
+
+ personality = LLVMAddFunction (aot_module.module, "mono_aot_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
+ LLVMSetLinkage (personality, LLVMPrivateLinkage);
+ lbb = LLVMAppendBasicBlock (personality, "BB0");
+ lbuilder = LLVMCreateBuilder ();
+ LLVMPositionBuilderAtEnd (lbuilder, lbb);
+ LLVMBuildRetVoid (lbuilder);
+ }
+
aot_module.llvm_types = g_hash_table_new (NULL, NULL);
aot_module.plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
}