-/*
- * mini-llvm.c: llvm "Backend" for the mono JIT
+/**
+ * \file
+ * llvm "Backend" for the mono JIT
*
* Copyright 2009-2011 Novell Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
-#include "mini.h"
+#include "config.h"
+
#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/debug-mono-symfile.h>
+#include <mono/metadata/debug-internals.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/object-internals.h>
#include "aot-compiler.h"
#include "mini-llvm.h"
+#ifndef DISABLE_JIT
+
#ifdef __MINGW32__
#include <stddef.h>
LLVMValueRef rgctx_arg;
LLVMValueRef this_arg;
LLVMTypeRef *vreg_types;
+ gboolean *is_vphi;
LLVMTypeRef method_type;
LLVMBasicBlockRef init_bb, inited_bb;
gboolean *is_dead;
GPtrArray *bblock_list;
char *method_name;
GHashTable *jit_callees;
+ LLVMValueRef long_bb_break_var;
} EmitContext;
typedef struct {
return LLVMVectorType (LLVMInt8Type (), 16);
} else if (!strcmp (klass->name, "Vector16b")) {
return LLVMVectorType (LLVMInt8Type (), 16);
+ } else if (!strcmp (klass->name, "Vector2")) {
+ /* System.Numerics */
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector3")) {
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector4")) {
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector`1")) {
+ MonoType *etype = mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ switch (etype->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ return LLVMVectorType (LLVMInt8Type (), 16);
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ return LLVMVectorType (LLVMInt16Type (), 8);
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ return LLVMVectorType (LLVMInt32Type (), 4);
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ return LLVMVectorType (LLVMInt64Type (), 2);
+ case MONO_TYPE_R4:
+ return LLVMVectorType (LLVMFloatType (), 4);
+ case MONO_TYPE_R8:
+ return LLVMVectorType (LLVMDoubleType (), 2);
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
} else {
printf ("%s\n", klass->name);
NOT_IMPLEMENTED;
* This is needed on arm64 where HFAs are returned in
* registers.
*/
+ /* SIMD types have size 16 in mono_class_value_size () */
+ if (klass->simd_type)
+ nfields = 16/ esize;
size = nfields;
eltypes = g_new (LLVMTypeRef, size);
for (i = 0; i < size; ++i)
return LLVMInt16Type ();
case MONO_TYPE_U4:
return LLVMInt32Type ();
- case MONO_TYPE_BOOLEAN:
- return LLVMInt8Type ();
case MONO_TYPE_I8:
case MONO_TYPE_U8:
return LLVMInt64Type ();
- case MONO_TYPE_CHAR:
- return LLVMInt16Type ();
case MONO_TYPE_R4:
return LLVMFloatType ();
case MONO_TYPE_R8:
case MONO_TYPE_U:
return IntPtrType ();
case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_STRING:
case MONO_TYPE_PTR:
return ObjRefType ();
case MONO_TYPE_VAR:
return "llvm.x86.sse2.min.pd";
case OP_MINPS:
return "llvm.x86.sse.min.ps";
- case OP_PMIND_UN:
- return "llvm.x86.sse41.pminud";
- case OP_PMINW_UN:
- return "llvm.x86.sse41.pminuw";
- case OP_PMINB_UN:
- return "llvm.x86.sse2.pminu.b";
- case OP_PMINW:
- return "llvm.x86.sse2.pmins.w";
case OP_MAXPD:
return "llvm.x86.sse2.max.pd";
case OP_MAXPS:
return "llvm.x86.sse3.hsub.pd";
case OP_HSUBPS:
return "llvm.x86.sse3.hsub.ps";
- case OP_PMAXD_UN:
- return "llvm.x86.sse41.pmaxud";
- case OP_PMAXW_UN:
- return "llvm.x86.sse41.pmaxuw";
- case OP_PMAXB_UN:
- return "llvm.x86.sse2.pmaxu.b";
case OP_ADDSUBPS:
return "llvm.x86.sse3.addsub.ps";
case OP_ADDSUBPD:
return "llvm.x86.sse2.cvttpd2dq";
case OP_CVTTPS2DQ:
return "llvm.x86.sse2.cvttps2dq";
- case OP_COMPPS:
- return "llvm.x86.sse.cmp.ps";
- case OP_COMPPD:
- return "llvm.x86.sse2.cmp.pd";
case OP_PACKW:
return "llvm.x86.sse2.packsswb.128";
case OP_PACKD:
return "llvm.x86.sse2.pmulh.w";
case OP_PMULW_HIGH_UN:
return "llvm.x86.sse2.pmulhu.w";
+ case OP_DPPS:
+ return "llvm.x86.sse41.dpps";
#endif
default:
g_assert_not_reached ();
emit_volatile_load (EmitContext *ctx, int vreg)
{
MonoType *t;
+ LLVMValueRef v;
- LLVMValueRef v = LLVMBuildLoad (ctx->builder, ctx->addresses [vreg], "");
+#ifdef TARGET_ARM64
+ // FIXME: This hack is required because we pass the rgctx in a callee saved
+ // register on arm64 (x15), and llvm might keep the value in that register
+ // even through the register is marked as 'reserved' inside llvm.
+ if (ctx->cfg->rgctx_var && ctx->cfg->rgctx_var->dreg == vreg)
+ v = mono_llvm_build_load (ctx->builder, ctx->addresses [vreg], "", TRUE);
+ else
+ v = LLVMBuildLoad (ctx->builder, ctx->addresses [vreg], "");
+#else
+ v = LLVMBuildLoad (ctx->builder, ctx->addresses [vreg], "");
+#endif
t = ctx->vreg_cli_types [vreg];
if (t && !t->byref) {
/*
pindex ++;
break;
case LLVMArgAsIArgs:
- param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
+ if (ainfo->esize == 8)
+ param_types [pindex] = LLVMArrayType (LLVMInt64Type (), ainfo->nslots);
+ else
+ param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
pindex ++;
break;
case LLVMArgVtypeByRef:
MonoCompile *cfg;
guint32 got_offset;
LLVMValueRef indexes [2];
- MonoJumpInfo *ji;
LLVMValueRef got_entry_addr, load;
LLVMBuilderRef builder = ctx->builder;
char *name = NULL;
cfg = ctx->cfg;
- ji = g_new0 (MonoJumpInfo, 1);
- ji->type = type;
- ji->data.target = data;
+ MonoJumpInfo tmp_ji;
+ tmp_ji.type = type;
+ tmp_ji.data.target = data;
- MonoJumpInfo *old = ji;
- ji = mono_aot_patch_info_dup (ji);
- g_free (old);
+ MonoJumpInfo *ji = mono_aot_patch_info_dup (&tmp_ji);
ji->next = cfg->patch_info;
cfg->patch_info = ji;
static MonoExceptionClause *
get_most_deep_clause (MonoCompile *cfg, EmitContext *ctx, MonoBasicBlock *bb)
{
+ if (bb == cfg->bb_init)
+ return NULL;
// Since they're sorted by nesting we just need
// the first one that the bb is a member of
for (int i = 0; i < cfg->header->num_clauses; i++) {
clause = get_most_deep_clause (cfg, ctx, bb);
if (clause) {
- g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+ g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT);
/*
* Have to use an invoke instead of a call, branching to the
* handler bblock of the clause containing this bblock.
*/
- g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+ g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY || ec->flags == MONO_EXCEPTION_CLAUSE_FAULT);
tblock = cfg->cil_offset_to_bb [ec->handler_offset];
g_assert (tblock);
}
static LLVMValueRef
-emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting, BarrierKind barrier)
+emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, LLVMValueRef base, const char *name, gboolean is_faulting, BarrierKind barrier)
{
const char *intrins_name;
LLVMValueRef args [16], res;
#if LLVM_API_VERSION > 100
if (is_faulting && bb->region != -1 && !ctx->cfg->llvm_only) {
/* The llvm.mono.load/store intrinsics are not supported by this llvm version, emit an explicit null check instead */
- LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, addr, LLVMConstNull (LLVMTypeOf (addr)), "");
+ LLVMValueRef cmp;
+
+ cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, base, LLVMConstNull (LLVMTypeOf (base)), "");
emit_cond_system_exception (ctx, bb, "NullReferenceException", cmp);
*builder_ref = ctx->builder;
use_intrinsics = FALSE;
* LLVM will generate invalid code when encountering a load from a
* NULL address.
*/
- res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting, barrier);
+ if (barrier != LLVM_BARRIER_NONE)
+ res = mono_llvm_build_atomic_load (*builder_ref, addr, name, is_faulting, size, barrier);
+ else
+ res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting);
- /* Mark it with a custom metadata */
- /*
- if (is_faulting)
- set_metadata_flag (res, "mono.faulting.load");
- */
+ /* Mark it with a custom metadata */
+ /*
+ if (is_faulting)
+ set_metadata_flag (res, "mono.faulting.load");
+ */
- return res;
+ return res;
}
}
static LLVMValueRef
emit_load (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting)
{
- return emit_load_general (ctx, bb, builder_ref, size, addr, name, is_faulting, LLVM_BARRIER_NONE);
+ return emit_load_general (ctx, bb, builder_ref, size, addr, addr, name, is_faulting, LLVM_BARRIER_NONE);
}
static void
-emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting, BarrierKind barrier)
+emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting, BarrierKind barrier)
{
const char *intrins_name;
LLVMValueRef args [16];
#if LLVM_API_VERSION > 100
if (is_faulting && bb->region != -1 && !ctx->cfg->llvm_only) {
/* The llvm.mono.load/store intrinsics are not supported by this llvm version, emit an explicit null check instead */
- LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, addr, LLVMConstNull (LLVMTypeOf (addr)), "");
+ LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, base, LLVMConstNull (LLVMTypeOf (base)), "");
emit_cond_system_exception (ctx, bb, "NullReferenceException", cmp);
*builder_ref = ctx->builder;
use_intrinsics = FALSE;
}
static void
-emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting)
+emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting)
{
- emit_store_general (ctx, bb, builder_ref, size, value, addr, is_faulting, LLVM_BARRIER_NONE);
+ emit_store_general (ctx, bb, builder_ref, size, value, addr, base, is_faulting, LLVM_BARRIER_NONE);
}
/*
func = LLVMAddFunction (lmodule, module->get_method_symbol, LLVMFunctionType1 (rtype, LLVMInt32Type (), FALSE));
LLVMSetLinkage (func, LLVMExternalLinkage);
LLVMSetVisibility (func, LLVMHiddenVisibility);
- LLVMAddFunctionAttr (func, LLVMNoUnwindAttribute);
+ mono_llvm_add_func_attr (func, LLVM_ATTR_NO_UNWIND);
module->get_method = func;
entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
func = LLVMAddFunction (lmodule, module->get_unbox_tramp_symbol, LLVMFunctionType1 (rtype, LLVMInt32Type (), FALSE));
LLVMSetLinkage (func, LLVMExternalLinkage);
LLVMSetVisibility (func, LLVMHiddenVisibility);
- LLVMAddFunctionAttr (func, LLVMNoUnwindAttribute);
+ mono_llvm_add_func_attr (func, LLVM_ATTR_NO_UNWIND);
module->get_unbox_tramp = func;
entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
func = LLVMAddFunction (lmodule, "llvm_code_start", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
LLVMSetLinkage (func, LLVMInternalLinkage);
- LLVMAddFunctionAttr (func, LLVMNoUnwindAttribute);
+ mono_llvm_add_func_attr (func, LLVM_ATTR_NO_UNWIND);
module->code_start = func;
entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
builder = LLVMCreateBuilder ();
g_assert_not_reached ();
}
LLVMSetLinkage (func, LLVMInternalLinkage);
- LLVMAddFunctionAttr (func, LLVMNoInlineAttribute);
+ mono_llvm_add_func_attr (func, LLVM_ATTR_NO_INLINE);
mono_llvm_set_preserveall_cc (func);
entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
builder = LLVMCreateBuilder ();
func = LLVMAddFunction (lmodule, "llvm_code_end", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
LLVMSetLinkage (func, LLVMInternalLinkage);
- LLVMAddFunctionAttr (func, LLVMNoUnwindAttribute);
+ mono_llvm_add_func_attr (func, LLVM_ATTR_NO_UNWIND);
module->code_end = func;
entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
builder = LLVMCreateBuilder ();
tramp_name = g_strdup_printf ("ut_%s", method_name);
tramp = LLVMAddFunction (ctx->module->lmodule, tramp_name, method_type);
LLVMSetLinkage (tramp, LLVMInternalLinkage);
- LLVMAddFunctionAttr (tramp, LLVMOptimizeForSizeAttribute);
- //LLVMAddFunctionAttr (tramp, LLVMNoUnwindAttribute);
+ mono_llvm_add_func_attr (tramp, LLVM_ATTR_OPTIMIZE_FOR_SIZE);
+ //mono_llvm_add_func_attr (tramp, LLVM_ATTR_NO_UNWIND);
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);
+ mono_llvm_add_param_attr (LLVMGetParam (tramp, ctx->rgctx_arg_pindex), LLVM_ATTR_IN_REG);
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);
+ mono_llvm_add_param_attr (LLVMGetParam (tramp, linfo->vret_arg_pindex), LLVM_ATTR_STRUCT_RET);
+ mono_llvm_add_param_attr (LLVMGetParam (tramp, linfo->vret_arg_pindex), LLVM_ATTR_NO_ALIAS);
}
}
}
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_add_instr_attr (call, 1 + ctx->rgctx_arg_pindex, LLVM_ATTR_IN_REG);
if (linfo->ret.storage == LLVMArgVtypeByRef)
- LLVMAddInstrAttribute (call, 1 + linfo->vret_arg_pindex, LLVMStructRetAttribute);
+ mono_llvm_add_instr_attr (call, 1 + linfo->vret_arg_pindex, LLVM_ATTR_STRUCT_RET);
// FIXME: This causes assertions in clang
//mono_llvm_set_must_tail (call);
if (!ctx->imt_rgctx_loc)
ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->module->ptr_type, sizeof (gpointer));
LLVMBuildStore (builder, convert (ctx, ctx->values [call->rgctx_arg_reg], ctx->module->ptr_type), ctx->imt_rgctx_loc);
- args [cinfo->rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
+ args [cinfo->rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
#else
args [cinfo->rgctx_arg_pindex] = convert (ctx, values [call->rgctx_arg_reg], ctx->module->ptr_type);
#endif
if (!ctx->imt_rgctx_loc)
ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->module->ptr_type, sizeof (gpointer));
LLVMBuildStore (builder, convert (ctx, ctx->values [call->imt_arg_reg], ctx->module->ptr_type), ctx->imt_rgctx_loc);
- args [cinfo->imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
+ args [cinfo->imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
#else
args [cinfo->imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->module->ptr_type);
#endif
}
case LLVMArgAsIArgs:
g_assert (addresses [reg]);
- args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
+ if (ainfo->esize == 8)
+ args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (LLVMInt64Type (), ainfo->nslots), 0)), "");
+ else
+ args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
break;
case LLVMArgVtypeAsScalar:
g_assert_not_reached ();
lcall = emit_call (ctx, bb, &builder, callee, args, LLVMCountParamTypes (llvm_sig));
+ if (ins->opcode != OP_TAILCALL && LLVMGetInstructionOpcode (lcall) == LLVMCall)
+ mono_llvm_set_call_notail (lcall);
+
/*
* Modify cconv and parameter attributes to pass rgctx/imt correctly.
*/
mono_llvm_set_call_preserveall_cc (lcall);
if (cinfo->ret.storage == LLVMArgVtypeByRef)
- LLVMAddInstrAttribute (lcall, 1 + cinfo->vret_arg_pindex, LLVMStructRetAttribute);
+ mono_llvm_add_instr_attr (lcall, 1 + cinfo->vret_arg_pindex, LLVM_ATTR_STRUCT_RET);
if (!ctx->llvm_only && call->rgctx_arg_reg)
- LLVMAddInstrAttribute (lcall, 1 + cinfo->rgctx_arg_pindex, LLVMInRegAttribute);
+ mono_llvm_add_instr_attr (lcall, 1 + cinfo->rgctx_arg_pindex, LLVM_ATTR_IN_REG);
if (call->imt_arg_reg)
- LLVMAddInstrAttribute (lcall, 1 + cinfo->imt_arg_pindex, LLVMInRegAttribute);
+ mono_llvm_add_instr_attr (lcall, 1 + cinfo->imt_arg_pindex, LLVM_ATTR_IN_REG);
/* Add byval attributes if needed */
for (i = 0; i < sig->param_count; ++i) {
LLVMArgInfo *ainfo = &call->cinfo->args [i + sig->hasthis];
if (ainfo && ainfo->storage == LLVMArgVtypeByVal)
- LLVMAddInstrAttribute (lcall, 1 + ainfo->pindex, LLVMByValAttribute);
+ mono_llvm_add_instr_attr (lcall, 1 + ainfo->pindex, LLVM_ATTR_BY_VAL);
}
/*
MonoExceptionClause *group_cursor = group_start;
for (int i = 0; i < group_size; i ++) {
- if (!(group_cursor->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+ if (!(group_cursor->flags & MONO_EXCEPTION_CLAUSE_FINALLY || group_cursor->flags & MONO_EXCEPTION_CLAUSE_FAULT))
finally_only = FALSE;
group_cursor++;
LLVMValueRef switch_ins = LLVMBuildSwitch (lpadBuilder, match, resume_bb, group_size);
// else move to that target bb
- for (int i=0; i < group_size; i++) {
+ for (int i = 0; i < group_size; i++) {
MonoExceptionClause *clause = group_start + i;
int clause_index = clause - cfg->header->clauses;
MonoBasicBlock *handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->clause_to_handler, GINT_TO_POINTER (clause_index));
MonoExceptionClause *clause = &ctx->cfg->header->clauses [clause_index];
// Make exception available to catch blocks
- if (!(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
+ if (!(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags & MONO_EXCEPTION_CLAUSE_FAULT)) {
LLVMValueRef mono_exc = mono_llvm_emit_load_exception_call (ctx, ctx->builder);
g_assert (ctx->ex_var);
g_assert (personality);
} else {
#if LLVM_API_VERSION > 100
- personality = ctx->module->personality;
- if (!personality) {
- LLVMTypeRef personality_type = LLVMFunctionType (LLVMInt32Type (), NULL, 0, TRUE);
- personality = LLVMAddFunction (ctx->lmodule, "mono_personality", personality_type);
- LLVMAddFunctionAttr (personality, LLVMNoUnwindAttribute);
- LLVMBasicBlockRef entry_bb = LLVMAppendBasicBlock (personality, "ENTRY");
- LLVMBuilderRef builder2 = LLVMCreateBuilder ();
- LLVMPositionBuilderAtEnd (builder2, entry_bb);
- LLVMBuildRet (builder2, LLVMConstInt (LLVMInt32Type (), 0, FALSE));
- ctx->module->personality = personality;
- LLVMDisposeBuilder (builder2);
- }
+ /* Can't cache this as each method is in its own llvm module */
+ LLVMTypeRef personality_type = LLVMFunctionType (LLVMInt32Type (), NULL, 0, TRUE);
+ personality = LLVMAddFunction (ctx->lmodule, "mono_personality", personality_type);
+ mono_llvm_add_func_attr (personality, LLVM_ATTR_NO_UNWIND);
+ LLVMBasicBlockRef entry_bb = LLVMAppendBasicBlock (personality, "ENTRY");
+ LLVMBuilderRef builder2 = LLVMCreateBuilder ();
+ LLVMPositionBuilderAtEnd (builder2, entry_bb);
+ LLVMBuildRet (builder2, LLVMConstInt (LLVMInt32Type (), 0, FALSE));
+ LLVMDisposeBuilder (builder2);
#else
static gint32 mapping_inited;
}
/* Start a new bblock which CALL_HANDLER can branch to */
- target_bb = bblocks [bb->block_num].call_handler_target_bb;
- if (target_bb) {
- ctx->builder = builder = create_builder (ctx);
- LLVMPositionBuilderAtEnd (ctx->builder, target_bb);
+ ctx->builder = builder = create_builder (ctx);
+ LLVMPositionBuilderAtEnd (ctx->builder, target_bb);
- ctx->bblocks [bb->block_num].end_bblock = target_bb;
+ ctx->bblocks [bb->block_num].end_bblock = target_bb;
- /* Store the exception into the IL level exvar */
- if (bb->in_scount == 1) {
- g_assert (bb->in_scount == 1);
- exvar = bb->in_stack [0];
+ /* Store the exception into the IL level exvar */
+ if (bb->in_scount == 1) {
+ g_assert (bb->in_scount == 1);
+ exvar = bb->in_stack [0];
- // FIXME: This is shared with filter clauses ?
- g_assert (!values [exvar->dreg]);
+ // FIXME: This is shared with filter clauses ?
+ g_assert (!values [exvar->dreg]);
- g_assert (ctx->ex_var);
- values [exvar->dreg] = LLVMBuildLoad (builder, ctx->ex_var, "");
- emit_volatile_store (ctx, exvar->dreg);
- }
+ g_assert (ctx->ex_var);
+ values [exvar->dreg] = LLVMBuildLoad (builder, ctx->ex_var, "");
+ emit_volatile_store (ctx, exvar->dreg);
}
+
+ /* Make normal branches to the start of the clause branch to the new bblock */
+ bblocks [bb->block_num].bblock = target_bb;
}
static void
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.
+ * Start a new bblock.
+ * Prevent the bblocks to be merged by doing a volatile load + cond branch
+ * from localloc-ed memory.
*/
- //set_failure (ctx, "basic block too long");
+ if (!cfg->llvm_only)
+ ;//set_failure (ctx, "basic block too long");
+
+ if (!ctx->long_bb_break_var) {
+ ctx->long_bb_break_var = build_alloca_llvm_type_name (ctx, LLVMInt32Type (), 0, "long_bb_break");
+ mono_llvm_build_store (ctx->alloca_builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), ctx->long_bb_break_var, TRUE, LLVM_BARRIER_NONE);
+ }
+
cbb = gen_bb (ctx, "CONT_LONG_BB");
- LLVMBuildBr (ctx->builder, cbb);
+ LLVMBasicBlockRef dummy_bb = gen_bb (ctx, "CONT_LONG_BB_DUMMY");
+
+ LLVMValueRef load = mono_llvm_build_load (builder, ctx->long_bb_break_var, "", TRUE);
+ /*
+ * The long_bb_break_var is initialized to 0 in the prolog, so this branch will always go to 'cbb'
+ * but llvm doesn't know that, so the branch is not going to be eliminated.
+ */
+ LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntEQ, load, LLVMConstInt (LLVMInt32Type (), 0, FALSE), "");
+
+ LLVMBuildCondBr (builder, cmp, cbb, dummy_bb);
+
+ /* Emit a dummy false bblock which does nothing but contains a volatile store so it cannot be eliminated */
+ ctx->builder = builder = create_builder (ctx);
+ LLVMPositionBuilderAtEnd (builder, dummy_bb);
+ mono_llvm_build_store (builder, LLVMConstInt (LLVMInt32Type (), 1, FALSE), ctx->long_bb_break_var, TRUE, LLVM_BARRIER_NONE);
+ LLVMBuildBr (builder, cbb);
+
ctx->builder = builder = create_builder (ctx);
LLVMPositionBuilderAtEnd (builder, cbb);
ctx->bblocks [bb->block_num].end_bblock = cbb;
case OP_X86_LEA: {
LLVMValueRef v1, v2;
+ rhs = LLVMBuildSExt (builder, convert (ctx, rhs, LLVMInt32Type ()), LLVMInt64Type (), "");
+
v1 = LLVMBuildMul (builder, convert (ctx, rhs, IntPtrType ()), LLVMConstInt (IntPtrType (), (1 << ins->backend.shift_amount), FALSE), "");
v2 = LLVMBuildAdd (builder, convert (ctx, lhs, IntPtrType ()), v1, "");
values [ins->dreg] = LLVMBuildAdd (builder, v2, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), dname);
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)) {
addr = LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE);
+ base = addr;
} else {
/* _MEMBASE */
base = lhs;
addr = convert (ctx, addr, LLVMPointerType (t, 0));
- values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, dname, is_volatile);
+ values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, base, dname, is_volatile, LLVM_BARRIER_NONE);
if (!is_volatile && (ins->flags & MONO_INST_INVARIANT_LOAD)) {
/*
case OP_STORER8_MEMBASE_REG:
case OP_STORE_MEMBASE_REG: {
int size = 8;
- LLVMValueRef index, addr;
+ LLVMValueRef index, addr, base;
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);
+ base = values [ins->inst_destbasereg];
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, "");
+ addr = LLVMBuildGEP (builder, convert (ctx, base, 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, "");
+ addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
}
- emit_store (ctx, bb, &builder, size, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)), is_volatile);
+ emit_store (ctx, bb, &builder, size, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_volatile);
break;
}
case OP_STOREI8_MEMBASE_IMM:
case OP_STORE_MEMBASE_IMM: {
int size = 8;
- LLVMValueRef index, addr;
+ LLVMValueRef index, addr, base;
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);
+ base = values [ins->inst_destbasereg];
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, "");
+ addr = LLVMBuildGEP (builder, convert (ctx, base, 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, "");
+ addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
}
- emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), is_volatile);
+ emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_volatile);
break;
}
case OP_CHECK_THIS:
- emit_load (ctx, bb, &builder, sizeof (gpointer), convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE);
+ emit_load_general (ctx, bb, &builder, sizeof (gpointer), convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), lhs, "", TRUE, LLVM_BARRIER_NONE);
break;
case OP_OUTARG_VTRETADDR:
break;
values [ins->dreg] = LLVMBuildSelect (builder, v, lhs, rhs, dname);
break;
}
+
+/*
+ * See the ARM64 comment in mono/utils/atomic.h for an explanation of why this
+ * hack is necessary (for now).
+ */
+#ifdef TARGET_ARM64
+#define ARM64_ATOMIC_FENCE_FIX mono_llvm_build_fence (builder, LLVM_BARRIER_SEQ)
+#else
+#define ARM64_ATOMIC_FENCE_FIX
+#endif
+
case OP_ATOMIC_EXCHANGE_I4:
case OP_ATOMIC_EXCHANGE_I8: {
LLVMValueRef args [2];
args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
args [1] = convert (ctx, rhs, t);
+ ARM64_ATOMIC_FENCE_FIX;
values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
+ ARM64_ATOMIC_FENCE_FIX;
break;
}
case OP_ATOMIC_ADD_I4:
args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
args [1] = convert (ctx, rhs, t);
+ ARM64_ATOMIC_FENCE_FIX;
values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
+ ARM64_ATOMIC_FENCE_FIX;
break;
}
case OP_ATOMIC_CAS_I4:
args [1] = convert (ctx, values [ins->sreg3], t);
/* new value */
args [2] = convert (ctx, values [ins->sreg2], t);
+ ARM64_ATOMIC_FENCE_FIX;
val = mono_llvm_build_cmpxchg (builder, args [0], args [1], args [2]);
+ ARM64_ATOMIC_FENCE_FIX;
/* cmpxchg returns a pair */
values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, "");
break;
case OP_ATOMIC_LOAD_U8:
case OP_ATOMIC_LOAD_R4:
case OP_ATOMIC_LOAD_R8: {
- set_failure (ctx, "atomic mono.load intrinsic");
- break;
-#if 0
+#if LLVM_API_VERSION > 100
int size;
gboolean sext, zext;
LLVMTypeRef t;
addr = convert (ctx, addr, LLVMPointerType (t, 0));
- values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, dname, is_volatile, barrier);
+ ARM64_ATOMIC_FENCE_FIX;
+ values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, lhs, dname, is_volatile, barrier);
+ ARM64_ATOMIC_FENCE_FIX;
if (sext)
values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
else if (zext)
values [ins->dreg] = LLVMBuildZExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
break;
+#else
+ set_failure (ctx, "atomic mono.load intrinsic");
+ break;
#endif
}
case OP_ATOMIC_STORE_I1:
LLVMTypeRef t;
gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
- LLVMValueRef index, addr, value;
+ LLVMValueRef index, addr, value, base;
+#if LLVM_API_VERSION < 100
if (!cfg->llvm_only) {
set_failure (ctx, "atomic mono.store intrinsic");
break;
}
+#endif
if (!values [ins->inst_destbasereg]) {
set_failure (ctx, "inst_destbasereg");
t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
+ base = values [ins->inst_destbasereg];
index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
- addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+ addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
value = convert (ctx, values [ins->sreg1], t);
- emit_store_general (ctx, bb, &builder, size, value, addr, is_volatile, barrier);
+ ARM64_ATOMIC_FENCE_FIX;
+ emit_store_general (ctx, bb, &builder, size, value, addr, base, is_volatile, barrier);
+ ARM64_ATOMIC_FENCE_FIX;
break;
}
case OP_RELAXED_NOP: {
break;
}
- case OP_TLS_GET_REG: {
-#if defined(TARGET_AMD64) && defined(__linux__)
- // 257 == FS segment register
- LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 257);
- values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt64Type ()), ptrtype, ""), "");
-#elif defined(TARGET_AMD64) && defined(TARGET_OSX)
- /* See emit_tls_get_reg () */
- // 256 == GS segment register
- LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
- values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt32Type ()), ptrtype, ""), "");
-#else
- set_failure (ctx, "opcode tls-get");
- break;
-#endif
- break;
- }
-
- case OP_TLS_SET_REG: {
-#if defined(TARGET_AMD64) && defined(TARGET_OSX)
- /* See emit_tls_get_reg () */
- // 256 == GS segment register
- LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
- LLVMBuildStore (builder, convert (ctx, lhs, IntPtrType ()), LLVMBuildIntToPtr (builder, convert (ctx, rhs, LLVMInt32Type ()), ptrtype, ""));
-#else
- set_failure (ctx, "opcode tls-set-reg");
- break;
-#endif
- break;
- }
case OP_GC_SAFE_POINT: {
LLVMValueRef val, cmp, callee;
LLVMBasicBlockRef poll_bb, cont_bb;
* mono_threads_state_poll ();
* FIXME: Use a preserveall wrapper
*/
- val = mono_llvm_build_load (builder, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE, LLVM_BARRIER_NONE);
+ val = mono_llvm_build_load (builder, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE);
cmp = LLVMBuildICmp (builder, LLVMIntEQ, val, LLVMConstNull (LLVMTypeOf (val)), "");
poll_bb = gen_bb (ctx, "POLL_BB");
cont_bb = gen_bb (ctx, "CONT_BB");
const char *name = (const char*)ins->inst_p0;
LLVMValueRef var;
- if (!ctx->module->objc_selector_to_var)
+ if (!ctx->module->objc_selector_to_var) {
ctx->module->objc_selector_to_var = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ LLVMValueRef info_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), 8), "@OBJC_IMAGE_INFO");
+ int32_t objc_imageinfo [] = { 0, 16 };
+ LLVMSetInitializer (info_var, mono_llvm_create_constant_data_array ((uint8_t *) &objc_imageinfo, 8));
+ LLVMSetLinkage (info_var, LLVMPrivateLinkage);
+ LLVMSetExternallyInitialized (info_var, TRUE);
+ LLVMSetSection (info_var, "__DATA, __objc_imageinfo,regular,no_dead_strip");
+ LLVMSetAlignment (info_var, sizeof (mgreg_t));
+ mark_as_used (ctx->module, info_var);
+ }
+
var = g_hash_table_lookup (ctx->module->objc_selector_to_var, name);
if (!var) {
LLVMValueRef indexes [16];
- LLVMValueRef name_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), strlen (name) + 1), "@OBJC_METH_VAR_NAME");
+ LLVMValueRef name_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), strlen (name) + 1), "@OBJC_METH_VAR_NAME_");
LLVMSetInitializer (name_var, mono_llvm_create_constant_data_array ((const uint8_t*)name, strlen (name) + 1));
LLVMSetLinkage (name_var, LLVMPrivateLinkage);
LLVMSetSection (name_var, "__TEXT,__objc_methname,cstring_literals");
+ mark_as_used (ctx->module, name_var);
- LLVMValueRef ref_var = LLVMAddGlobal (ctx->lmodule, LLVMPointerType (LLVMInt8Type (), 0), "@OBJC_SELECTOR_REFERENCES");
+ LLVMValueRef ref_var = LLVMAddGlobal (ctx->lmodule, LLVMPointerType (LLVMInt8Type (), 0), "@OBJC_SELECTOR_REFERENCES_");
indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, 0);
indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, 0);
LLVMSetExternallyInitialized (ref_var, TRUE);
LLVMSetSection (ref_var, "__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
LLVMSetAlignment (ref_var, sizeof (mgreg_t));
+ mark_as_used (ctx->module, ref_var);
g_hash_table_insert (ctx->module->objc_selector_to_var, g_strdup (name), ref_var);
var = ref_var;
values [ins->dreg] = LLVMBuildBitCast (builder, v, rt, "");
break;
}
+ case OP_PMIND_UN:
+ case OP_PMINW_UN:
+ case OP_PMINB_UN: {
+ LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntULT, lhs, rhs, "");
+ values [ins->dreg] = LLVMBuildSelect (builder, cmp, lhs, rhs, "");
+ break;
+ }
+ case OP_PMAXD_UN:
+ case OP_PMAXW_UN:
+ case OP_PMAXB_UN: {
+ LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntUGT, lhs, rhs, "");
+ values [ins->dreg] = LLVMBuildSelect (builder, cmp, lhs, rhs, "");
+ break;
+ }
+ case OP_PMINW: {
+ LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntSLT, lhs, rhs, "");
+ values [ins->dreg] = LLVMBuildSelect (builder, cmp, lhs, rhs, "");
+ break;
+ }
case OP_MINPD:
case OP_MINPS:
case OP_MAXPD:
case OP_MAXPS:
case OP_ADDSUBPD:
case OP_ADDSUBPS:
- case OP_PMIND_UN:
- case OP_PMINW_UN:
- case OP_PMINB_UN:
- case OP_PMINW:
- case OP_PMAXD_UN:
- case OP_PMAXW_UN:
- case OP_PMAXB_UN:
case OP_HADDPD:
case OP_HADDPS:
case OP_HSUBPD:
values [ins->dreg] = LLVMBuildInsertElement (builder, values [ins->sreg1], convert (ctx, values [ins->sreg2], LLVMDoubleType ()), LLVMConstInt (LLVMInt32Type (), ins->inst_c0, FALSE), dname);
break;
+#if LLVM_API_VERSION > 100
+ case OP_CVTDQ2PD: {
+ LLVMValueRef indexes [16];
+
+ indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ indexes [1] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ LLVMValueRef mask = LLVMConstVector (indexes, 2);
+ LLVMValueRef shuffle = LLVMBuildShuffleVector (builder, lhs, LLVMConstNull (LLVMTypeOf (lhs)), mask, "");
+ values [ins->dreg] = LLVMBuildSIToFP (builder, shuffle, LLVMVectorType (LLVMDoubleType (), 2), dname);
+ break;
+ }
+ case OP_CVTPS2PD: {
+ LLVMValueRef indexes [16];
+
+ indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ indexes [1] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ LLVMValueRef mask = LLVMConstVector (indexes, 2);
+ LLVMValueRef shuffle = LLVMBuildShuffleVector (builder, lhs, LLVMConstNull (LLVMTypeOf (lhs)), mask, "");
+ values [ins->dreg] = LLVMBuildFPExt (builder, shuffle, LLVMVectorType (LLVMDoubleType (), 2), dname);
+ break;
+ }
+ case OP_CVTTPS2DQ:
+ values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMVectorType (LLVMInt32Type (), 4), dname);
+ break;
+#endif
+
+#if LLVM_API_VERSION <= 100
case OP_CVTDQ2PD:
+ case OP_CVTPS2PD:
+ case OP_CVTTPS2DQ:
+#endif
case OP_CVTDQ2PS:
case OP_CVTPD2DQ:
case OP_CVTPS2DQ:
case OP_CVTPD2PS:
- case OP_CVTPS2PD:
case OP_CVTTPD2DQ:
- case OP_CVTTPS2DQ:
case OP_EXTRACT_MASK:
case OP_SQRTPS:
case OP_SQRTPD:
values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), &v, 1, dname);
break;
}
-
case OP_COMPPS:
case OP_COMPPD: {
- LLVMValueRef args [3];
+ LLVMRealPredicate op;
- args [0] = lhs;
- args [1] = rhs;
- args [2] = LLVMConstInt (LLVMInt8Type (), ins->inst_c0, FALSE);
+ switch (ins->inst_c0) {
+ case SIMD_COMP_EQ:
+ op = LLVMRealOEQ;
+ break;
+ case SIMD_COMP_LT:
+ op = LLVMRealOLT;
+ break;
+ case SIMD_COMP_LE:
+ op = LLVMRealOLE;
+ break;
+ case SIMD_COMP_UNORD:
+ op = LLVMRealUNO;
+ break;
+ case SIMD_COMP_NEQ:
+ op = LLVMRealUNE;
+ break;
+ case SIMD_COMP_NLT:
+ op = LLVMRealUGE;
+ break;
+ case SIMD_COMP_NLE:
+ op = LLVMRealUGT;
+ break;
+ case SIMD_COMP_ORD:
+ op = LLVMRealORD;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+ LLVMValueRef cmp = LLVMBuildFCmp (builder, op, lhs, rhs, "");
+ if (ins->opcode == OP_COMPPD)
+ values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt64Type (), 2), ""), LLVMTypeOf (lhs), "");
+ else
+ values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt32Type (), 4), ""), LLVMTypeOf (lhs), "");
break;
}
-
case OP_ICONV_TO_X:
/* This is only used for implementing shifts by non-immediate */
values [ins->dreg] = lhs;
break;
}
+ case OP_DPPS: {
+ LLVMValueRef args [3];
+
+ args [0] = lhs;
+ args [1] = rhs;
+ /* 0xf1 == multiply all 4 elements, add them together, and store the result to the lowest element */
+#if LLVM_API_VERSION >= 500
+ args [2] = LLVMConstInt (LLVMInt8Type (), 0xf1, FALSE);
+#else
+ args [2] = LLVMConstInt (LLVMInt32Type (), 0xf1, FALSE);
+#endif
+
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+ break;
+ }
+
#endif /* SIMD */
case OP_DUMMY_USE:
LLVMValueRef val, switch_ins, callee;
GSList *bb_list;
BBInfo *info;
+ gboolean is_fault = MONO_REGION_FLAGS (bb->region) == MONO_EXCEPTION_CLAUSE_FAULT;
- handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
- g_assert (handler_bb);
- info = &bblocks [handler_bb->block_num];
- lhs = info->finally_ind;
- g_assert (lhs);
+ /*
+ * Fault clauses are like finally clauses, but they are only called if an exception is thrown.
+ */
+ if (!is_fault) {
+ handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
+ g_assert (handler_bb);
+ info = &bblocks [handler_bb->block_num];
+ lhs = info->finally_ind;
+ g_assert (lhs);
- bb_list = info->call_handler_return_bbs;
+ bb_list = info->call_handler_return_bbs;
- resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
+ resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
- /* Load the finally variable */
- val = LLVMBuildLoad (builder, lhs, "");
+ /* Load the finally variable */
+ val = LLVMBuildLoad (builder, lhs, "");
- /* Reset the variable */
- LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
+ /* Reset the variable */
+ LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
- /* Branch to either resume_bb, or to the bblocks in bb_list */
- switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
- /*
- * The other targets are added at the end to handle OP_CALL_HANDLER
- * opcodes processed later.
- */
- info->endfinally_switch_ins_list = g_slist_append_mempool (cfg->mempool, info->endfinally_switch_ins_list, switch_ins);
+ /* Branch to either resume_bb, or to the bblocks in bb_list */
+ switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
+ /*
+ * The other targets are added at the end to handle OP_CALL_HANDLER
+ * opcodes processed later.
+ */
+ info->endfinally_switch_ins_list = g_slist_append_mempool (cfg->mempool, info->endfinally_switch_ins_list, switch_ins);
- builder = ctx->builder = create_builder (ctx);
- LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+ builder = ctx->builder = create_builder (ctx);
+ LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+ }
if (ctx->llvm_only) {
emit_resume_eh (ctx, bb);
/* 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])
+ if (ctx->is_vphi [ins->dreg])
/* vtypes */
values [ins->dreg] = addresses [ins->dreg];
else
g_free (ctx->values);
g_free (ctx->addresses);
g_free (ctx->vreg_types);
+ g_free (ctx->is_vphi);
g_free (ctx->vreg_cli_types);
g_free (ctx->is_dead);
g_free (ctx->unreachable);
g_hash_table_destroy (ctx->region_to_handler);
g_hash_table_destroy (ctx->clause_to_handler);
g_hash_table_destroy (ctx->jit_callees);
+
+ GHashTableIter iter;
+ g_hash_table_iter_init (&iter, ctx->method_to_callers);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer)&l))
+ g_slist_free (l);
+
+ g_hash_table_destroy (ctx->method_to_callers);
+
g_free (ctx->method_name);
g_ptr_array_free (ctx->bblock_list, TRUE);
*/
ctx->addresses = g_new0 (LLVMValueRef, cfg->next_vreg);
ctx->vreg_types = g_new0 (LLVMTypeRef, cfg->next_vreg);
+ ctx->is_vphi = g_new0 (gboolean, cfg->next_vreg);
ctx->vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg);
ctx->phi_values = g_ptr_array_sized_new (256);
/*
if (cfg->compile_aot)
ctx->lmodule = ctx->module->lmodule;
else
- ctx->lmodule = LLVMModuleCreateWithName ("jit-module");
+ ctx->lmodule = LLVMModuleCreateWithName (g_strdup_printf ("jit-module-%s", cfg->method->name));
#else
ctx->lmodule = ctx->module->lmodule;
#endif
static int count = 0;
count ++;
- if (g_getenv ("LLVM_COUNT")) {
- if (count == atoi (g_getenv ("LLVM_COUNT"))) {
+ char *llvm_count_str = g_getenv ("LLVM_COUNT");
+ if (llvm_count_str) {
+ int lcount = atoi (llvm_count_str);
+ g_free (llvm_count_str);
+ if (count == lcount) {
printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
fflush (stdout);
last = TRUE;
}
- if (count > atoi (g_getenv ("LLVM_COUNT"))) {
+ if (count > lcount) {
set_failure (ctx, "count");
return;
}
LLVMSetFunctionCallConv (method, LLVMMono1CallConv);
LLVMSetLinkage (method, LLVMPrivateLinkage);
- LLVMAddFunctionAttr (method, LLVMUWTable);
+ mono_llvm_add_func_attr (method, LLVM_ATTR_UW_TABLE);
if (cfg->compile_aot) {
LLVMSetLinkage (method, LLVMInternalLinkage);
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) {
- set_failure (ctx, "non-finally/catch clause.");
+ if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) {
+ set_failure (ctx, "non-finally/catch/fault clause.");
return;
}
}
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);
+ mono_llvm_add_func_attr (method, LLVM_ATTR_NO_INLINE);
if (linfo->rgctx_arg) {
ctx->rgctx_arg = LLVMGetParam (method, linfo->rgctx_arg_pindex);
* CC_X86_64_Mono in X86CallingConv.td.
*/
if (!ctx->llvm_only)
- LLVMAddAttribute (ctx->rgctx_arg, LLVMInRegAttribute);
+ mono_llvm_add_param_attr (ctx->rgctx_arg, LLVM_ATTR_IN_REG);
LLVMSetValueName (ctx->rgctx_arg, "rgctx");
} else {
ctx->rgctx_arg_pindex = -1;
values [cfg->vret_addr->dreg] = LLVMGetParam (method, linfo->vret_arg_pindex);
LLVMSetValueName (values [cfg->vret_addr->dreg], "vret");
if (linfo->ret.storage == LLVMArgVtypeByRef) {
- LLVMAddAttribute (LLVMGetParam (method, linfo->vret_arg_pindex), LLVMStructRetAttribute);
- LLVMAddAttribute (LLVMGetParam (method, linfo->vret_arg_pindex), LLVMNoAliasAttribute);
+ mono_llvm_add_param_attr (LLVMGetParam (method, linfo->vret_arg_pindex), LLVM_ATTR_STRUCT_RET);
+ mono_llvm_add_param_attr (LLVMGetParam (method, linfo->vret_arg_pindex), LLVM_ATTR_NO_ALIAS);
}
}
names = g_new (char *, sig->param_count);
mono_method_get_param_names (cfg->method, (const char **) names);
+ /* Set parameter names/attributes */
for (i = 0; i < sig->param_count; ++i) {
LLVMArgInfo *ainfo = &linfo->args [i + sig->hasthis];
char *name;
g_free (name);
}
+ if (ainfo->storage == LLVMArgVtypeInReg && ainfo->pair_storage [0] == LLVMArgNone && ainfo->pair_storage [1] == LLVMArgNone)
+ continue;
+
values [cfg->args [i + sig->hasthis]->dreg] = LLVMGetParam (method, pindex);
if (ainfo->storage == LLVMArgGsharedvtFixed || ainfo->storage == LLVMArgGsharedvtFixedVtype) {
if (names [i] && names [i][0] != '\0')
LLVMSetValueName (values [cfg->args [i + sig->hasthis]->dreg], name);
g_free (name);
if (ainfo->storage == LLVMArgVtypeByVal)
- LLVMAddAttribute (LLVMGetParam (method, pindex), LLVMByValAttribute);
+ mono_llvm_add_param_attr (LLVMGetParam (method, pindex), LLVM_ATTR_BY_VAL);
if (ainfo->storage == LLVMArgVtypeByRef) {
/* For OP_LDADDR */
}
}
- /*
- * The INDIRECT flag added by OP_LDADDR inhibits optimizations, even if the LDADDR
- * was later optimized away, so clear these flags, and add them back for the still
- * present OP_LDADDR instructions.
- */
- for (i = 0; i < cfg->next_vreg; ++i) {
- MonoInst *ins;
-
- ins = get_vreg_to_inst (cfg, i);
- if (ins && ins != cfg->rgctx_var)
- ins->flags &= ~MONO_INST_INDIRECT;
- }
-
/*
* Make a first pass over the code to precreate PHI nodes/set INDIRECT flags.
*/
for (i = 0; i < ins->inst_phi_args [0]; i++) {
int sreg1 = ins->inst_phi_args [i + 1];
- if (sreg1 != -1)
+ if (sreg1 != -1) {
+ if (ins->opcode == OP_VPHI)
+ ctx->is_vphi [sreg1] = TRUE;
ctx->vreg_types [sreg1] = phi_type;
+ }
}
break;
}
LLVMValueRef switch_ins = (LLVMValueRef)l->data;
GSList *bb_list = info->call_handler_return_bbs;
- for (i = 0; i < g_slist_length (bb_list); ++i)
- LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), (LLVMBasicBlockRef)(g_slist_nth (bb_list, i)->data));
+ GSList *bb_list_iter;
+ i = 0;
+ for (bb_list_iter = bb_list; bb_list_iter; bb_list_iter = g_slist_next (bb_list_iter)) {
+ LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), (LLVMBasicBlockRef)bb_list_iter->data);
+ i ++;
+ }
}
}
ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index);
// FIXME: beforefieldinit
- if (ctx->has_got_access || mono_class_get_cctor (cfg->method->klass)) {
+ /*
+ * NATIVE_TO_MANAGED methods might be called on a thread not attached to the runtime, so they are initialized when loaded
+ * in load_method ().
+ */
+ if ((ctx->has_got_access || mono_class_get_cctor (cfg->method->klass)) && !(cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)) {
/*
* linkonce methods shouldn't have initialization,
* because they might belong to assemblies which
guint32 ei_len, i, nested_len;
gpointer *type_info;
gint32 *table;
+ guint8 *unw_info;
/*
* Decode the one element EH table emitted by the MonoException class
fde = (guint8*)eh_frame + fde_offset;
cie = (guint8*)table;
- mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info);
+ /* Compute lengths */
+ mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info, NULL, NULL, NULL);
+
+ ei = (MonoJitExceptionInfo *)g_malloc0 (info.ex_info_len * sizeof (MonoJitExceptionInfo));
+ type_info = (gpointer *)g_malloc0 (info.ex_info_len * sizeof (gpointer));
+ unw_info = (guint8*)g_malloc0 (info.unw_info_len);
+
+ mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info, ei, type_info, unw_info);
- cfg->encoded_unwind_ops = info.unw_info;
+ cfg->encoded_unwind_ops = unw_info;
cfg->encoded_unwind_ops_len = info.unw_info_len;
if (cfg->verbose_level > 1)
mono_print_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len);
cfg->llvm_this_offset = info.this_offset;
}
- ei = info.ex_info;
ei_len = info.ex_info_len;
- type_info = info.type_info;
// Nested clauses are currently disabled
nested_len = 0;
INTRINS_SSE_HADDPD,
INTRINS_SSE_HSUBPD,
INTRINS_SSE_ADDSUBPD,
- INTRINS_SSE_PMINUD,
- INTRINS_SSE_PMAXUD,
- INTRINS_SSE_PMINUW,
- INTRINS_SSE_PMINSW,
- INTRINS_SSE_PMAXUW,
INTRINS_SSE_PADDSW,
INTRINS_SSE_PSUBSW,
INTRINS_SSE_PADDUSW,
INTRINS_SSE_PAVGW,
INTRINS_SSE_PMULHW,
INTRINS_SSE_PMULHU,
- INTRINS_SSE_PMINUB,
- INTRINS_SSE_PMAXUB,
INTRINS_SE_PADDSB,
INTRINS_SSE_PSUBSB,
INTRINS_SSE_PADDUSB,
INTRINS_SSE_PSUBUSB,
INTRINS_SSE_PAVGB,
INTRINS_SSE_PAUSE,
+ INTRINS_SSE_DPPS,
#endif
INTRINS_NUM
} IntrinsicId;
{INTRINS_SSE_HADDPD, "llvm.x86.sse3.hadd.pd"},
{INTRINS_SSE_HSUBPD, "llvm.x86.sse3.hsub.pd"},
{INTRINS_SSE_ADDSUBPD, "llvm.x86.sse3.addsub.pd"},
- {INTRINS_SSE_PMINUD, "llvm.x86.sse41.pminud"},
- {INTRINS_SSE_PMAXUD, "llvm.x86.sse41.pmaxud"},
- {INTRINS_SSE_PMINUW, "llvm.x86.sse41.pminuw"},
- {INTRINS_SSE_PMINSW, "llvm.x86.sse2.pmins.w"},
- {INTRINS_SSE_PMAXUW, "llvm.x86.sse41.pmaxuw"},
{INTRINS_SSE_PADDSW, "llvm.x86.sse2.padds.w"},
{INTRINS_SSE_PSUBSW, "llvm.x86.sse2.psubs.w"},
{INTRINS_SSE_PADDUSW, "llvm.x86.sse2.paddus.w"},
{INTRINS_SSE_PAVGW, "llvm.x86.sse2.pavg.w"},
{INTRINS_SSE_PMULHW, "llvm.x86.sse2.pmulh.w"},
{INTRINS_SSE_PMULHU, "llvm.x86.sse2.pmulhu.w"},
- {INTRINS_SSE_PMINUB, "llvm.x86.sse2.pminu.b"},
- {INTRINS_SSE_PMAXUB, "llvm.x86.sse2.pmaxu.b"},
{INTRINS_SE_PADDSB, "llvm.x86.sse2.padds.b"},
{INTRINS_SSE_PSUBSB, "llvm.x86.sse2.psubs.b"},
{INTRINS_SSE_PADDUSB, "llvm.x86.sse2.paddus.b"},
{INTRINS_SSE_PSUBUSB, "llvm.x86.sse2.psubus.b"},
{INTRINS_SSE_PAVGB, "llvm.x86.sse2.pavg.b"},
- {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"}
+ {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"},
+ {INTRINS_SSE_DPPS, "llvm.x86.sse41.dpps"}
#endif
};
AddFunc (module, name, ret_type, arg_types, 2);
break;
/* SSE Binary ops */
- case INTRINS_SSE_PMINUD:
- case INTRINS_SSE_PMAXUD:
- add_sse_binary (module, name, MONO_TYPE_I4);
- break;
- case INTRINS_SSE_PMINUW:
- case INTRINS_SSE_PMINSW:
- case INTRINS_SSE_PMAXUW:
case INTRINS_SSE_PADDSW:
case INTRINS_SSE_PSUBSW:
case INTRINS_SSE_PADDUSW:
case INTRINS_SSE_ADDSUBPD:
add_sse_binary (module, name, MONO_TYPE_R8);
break;
- case INTRINS_SSE_PMINUB:
- case INTRINS_SSE_PMAXUB:
case INTRINS_SE_PADDSB:
case INTRINS_SSE_PSUBSB:
case INTRINS_SSE_PADDUSB:
case INTRINS_SSE_PAUSE:
AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
break;
+ case INTRINS_SSE_DPPS:
+ ret_type = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [0] = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [1] = type_to_simd_type (MONO_TYPE_R4);
+#if LLVM_API_VERSION >= 500
+ arg_types [2] = LLVMInt8Type ();
+#else
+ arg_types [2] = LLVMInt32Type ();
+#endif
+ AddFunc (module, name, ret_type, arg_types, 3);
+ break;
#endif
default:
g_assert_not_reached ();
AddFunc (module, "llvm_resume_unwind_trampoline", LLVMVoidType (), NULL, 0);
}
- /* SSE intrinsics */
-#if defined(TARGET_X86) || defined(TARGET_AMD64)
-
-#endif
-
/* Load/Store intrinsics */
{
LLVMTypeRef arg_types [5];
}
void
-mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only)
+mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, int initial_got_size, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only)
{
MonoLLVMModule *module = &aot_module;
module->static_link = static_link;
module->llvm_only = llvm_only;
/* The first few entries are reserved */
- module->max_got_offset = 16;
- module->context = LLVMContextCreate ();
+ module->max_got_offset = initial_got_size;
+ module->context = LLVMGetGlobalContext ();
if (llvm_only)
/* clang ignores our debug info because it has an invalid version */
module->emit_dwarf = FALSE;
-#if LLVM_API_VERSION > 100
- module->emit_dwarf = FALSE;
-#endif
-
add_intrinsics (module->lmodule);
add_types (module);
return res;
}
+static LLVMValueRef
+llvm_array_from_bytes (guint8 *values, int nvalues)
+{
+ int i;
+ LLVMValueRef res, *vals;
+
+ vals = g_new0 (LLVMValueRef, nvalues);
+ for (i = 0; i < nvalues; ++i)
+ vals [i] = LLVMConstInt (LLVMInt8Type (), values [i], FALSE);
+ res = LLVMConstArray (LLVMInt8Type (), vals, nvalues);
+ g_free (vals);
+ return res;
+}
/*
* mono_llvm_emit_aot_file_info:
*
LLVMSetVisibility (d, LLVMHiddenVisibility);
LLVMSetLinkage (d, LLVMInternalLinkage);
LLVMSetInitializer (d, mono_llvm_create_constant_data_array (data, data_len));
+ LLVMSetAlignment (d, 8);
mono_llvm_set_is_constant (d);
}
info = &module->aot_info;
/* Create an LLVM type to represent MonoAotFileInfo */
- nfields = 2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 15 + 5;
+ nfields = 2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 16 + 5;
eltypes = g_new (LLVMTypeRef, nfields);
tindex = 0;
eltypes [tindex ++] = LLVMInt32Type ();
eltypes [tindex ++] = LLVMArrayType (LLVMInt32Type (), MONO_AOT_TABLE_NUM);
for (i = 0; i < 4; ++i)
eltypes [tindex ++] = LLVMArrayType (LLVMInt32Type (), MONO_AOT_TRAMP_NUM);
+ eltypes [tindex ++] = LLVMArrayType (LLVMInt8Type (), 16);
g_assert (tindex == nfields);
file_info_type = LLVMStructCreateNamed (module->context, "MonoAotFileInfo");
LLVMStructSetBody (file_info_type, eltypes, nfields, FALSE);
if (info->trampoline_size [0]) {
fields [tindex ++] = AddJitGlobal (module, eltype, "specific_trampolines");
fields [tindex ++] = AddJitGlobal (module, eltype, "static_rgctx_trampolines");
- fields [tindex ++] = AddJitGlobal (module, eltype, "imt_thunks");
+ fields [tindex ++] = AddJitGlobal (module, eltype, "imt_trampolines");
fields [tindex ++] = AddJitGlobal (module, eltype, "gsharedvt_arg_trampolines");
} else {
fields [tindex ++] = LLVMConstNull (eltype);
fields [tindex ++] = llvm_array_from_uints (LLVMInt32Type (), info->trampoline_got_offset_base, MONO_AOT_TRAMP_NUM);
fields [tindex ++] = llvm_array_from_uints (LLVMInt32Type (), info->trampoline_size, MONO_AOT_TRAMP_NUM);
fields [tindex ++] = llvm_array_from_uints (LLVMInt32Type (), info->tramp_page_code_offsets, MONO_AOT_TRAMP_NUM);
+
+ fields [tindex ++] = llvm_array_from_bytes (info->aotid, 16);
g_assert (tindex == nfields);
LLVMSetInitializer (info_var, LLVMConstNamedStruct (file_info_type, fields, nfields));
while (g_hash_table_iter_next (&iter, (void**)&method, (void**)&callers)) {
LLVMValueRef lmethod;
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ continue;
+
lmethod = (LLVMValueRef)g_hash_table_lookup (module->method_to_lmethod, method);
if (lmethod) {
for (l = callers; l; l = l->next) {
if (!minfo)
return NULL;
- mono_debug_symfile_get_seq_points (minfo, &source_file, NULL, NULL, &sym_seq_points, &n_seq_points);
+ mono_debug_get_seq_points (minfo, &source_file, NULL, NULL, &sym_seq_points, &n_seq_points);
if (!source_file)
source_file = g_strdup ("<unknown>");
dir = g_path_get_dirname (source_file);
filename = g_path_get_basename (source_file);
#if LLVM_API_VERSION > 100
- return mono_llvm_di_create_function (module->di_builder, module->cu, cfg->method->name, name, dir, filename, n_seq_points ? sym_seq_points [0].line : 1);
+ return mono_llvm_di_create_function (module->di_builder, module->cu, method, cfg->method->name, name, dir, filename, n_seq_points ? sym_seq_points [0].line : 1);
#endif
ctx_args [0] = LLVMConstInt (LLVMInt32Type (), 0x29, FALSE);
MonoDebugSourceLocation *loc;
LLVMValueRef loc_md;
- loc = mono_debug_symfile_lookup_location (ctx->minfo, cil_code - cfg->header->code);
+ loc = mono_debug_method_lookup_location (ctx->minfo, cil_code - cfg->header->code);
if (loc) {
#if LLVM_API_VERSION > 100
loc_md = LLVMMDNode (md_args, nmd_args);
LLVMSetCurrentDebugLocation (builder, loc_md);
#endif
- mono_debug_symfile_free_location (loc);
+ mono_debug_free_source_location (loc);
}
}
}
MonoObject *target = mono_gchandle_get_target (jit_tls->thrown_exc);
mono_unhandled_exception (target);
- exit (mono_environment_exitcode_get ());
+ mono_invoke_unhandled_exception_hook (target);
+ g_assert_not_reached ();
}
/*
The mono JIT uses pointer sized iregs/double fregs, while LLVM uses precisely
typed registers, so we have to keep track of the precise LLVM type of each vreg.
This is made easier because the IR is already in SSA form.
- An additional problem is that our IR is not consistent with types, i.e. i32/ia64
+ An additional problem is that our IR is not consistent with types, i.e. i32/i64
types are frequently used incorrectly.
*/
* code.
* - use pointer types to help optimizations.
*/
+
+#else /* DISABLE_JIT */
+
+void
+mono_llvm_cleanup (void)
+{
+}
+
+void
+mono_llvm_free_domain_info (MonoDomain *domain)
+{
+}
+
+void
+mono_llvm_init (void)
+{
+}
+
+void
+default_mono_llvm_unhandled_exception (void)
+{
+}
+
+#endif /* DISABLE_JIT */