* 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/mempool-internals.h>
#include "aot-compiler.h"
#include "mini-llvm.h"
+#ifndef DISABLE_JIT
+
#ifdef __MINGW32__
#include <stddef.h>
gboolean external_symbols;
gboolean emit_dwarf;
int max_got_offset;
+ LLVMValueRef personality;
/* For AOT */
MonoAssembly *assembly;
LLVMContextRef context;
LLVMValueRef sentinel_exception;
void *di_builder, *cu;
+ GHashTable *objc_selector_to_var;
} MonoLLVMModule;
/*
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 "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) {
/*
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;
- ji = mono_aot_patch_info_dup (ji);
+ 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++) {
}
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);
}
/*
LLVMBasicBlockRef entry_bb, fail_bb, bb, code_start_bb, code_end_bb;
LLVMBasicBlockRef *bbs;
LLVMTypeRef rtype;
- LLVMBuilderRef builder;
+ LLVMBuilderRef builder = LLVMCreateBuilder ();
char *name;
int i;
name = g_strdup_printf ("BB_CODE_START");
code_start_bb = LLVMAppendBasicBlock (func, name);
g_free (name);
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, code_start_bb);
LLVMBuildRet (builder, LLVMBuildBitCast (builder, module->code_start, rtype, ""));
name = g_strdup_printf ("BB_CODE_END");
code_end_bb = LLVMAppendBasicBlock (func, name);
g_free (name);
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, code_end_bb);
LLVMBuildRet (builder, LLVMBuildBitCast (builder, module->code_end, rtype, ""));
g_free (name);
bbs [i] = bb;
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, bb);
m = (LLVMValueRef)g_hash_table_lookup (module->idx_to_lmethod, GINT_TO_POINTER (i));
}
fail_bb = LLVMAppendBasicBlock (func, "FAIL");
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, fail_bb);
LLVMBuildRet (builder, LLVMConstNull (rtype));
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, entry_bb);
switch_ins = LLVMBuildSwitch (builder, LLVMGetParam (func, 0), fail_bb, 0);
}
mark_as_used (module, func);
+
+ LLVMDisposeBuilder (builder);
}
/*
LLVMBasicBlockRef entry_bb, fail_bb, bb;
LLVMBasicBlockRef *bbs;
LLVMTypeRef rtype;
- LLVMBuilderRef builder;
+ LLVMBuilderRef builder = LLVMCreateBuilder ();
char *name;
int i;
g_free (name);
bbs [i] = bb;
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, bb);
LLVMBuildRet (builder, LLVMBuildBitCast (builder, m, rtype, ""));
}
fail_bb = LLVMAppendBasicBlock (func, "FAIL");
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, fail_bb);
LLVMBuildRet (builder, LLVMConstNull (rtype));
- builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, entry_bb);
switch_ins = LLVMBuildSwitch (builder, LLVMGetParam (func, 0), fail_bb, 0);
}
mark_as_used (module, func);
+ LLVMDisposeBuilder (builder);
}
/* Add a function to mark the beginning of LLVM code */
builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, entry_bb);
LLVMBuildRetVoid (builder);
+ LLVMDisposeBuilder (builder);
}
static LLVMValueRef
LLVMBuildRetVoid (builder);
LLVMVerifyFunction(func, LLVMAbortProcessAction);
+ LLVMDisposeBuilder (builder);
return func;
}
builder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (builder, entry_bb);
LLVMBuildRetVoid (builder);
+ LLVMDisposeBuilder (builder);
}
static void
LLVMBuildRet (builder, call);
g_hash_table_insert (ctx->module->idx_to_unbox_tramp, GINT_TO_POINTER (method_index), tramp);
+ LLVMDisposeBuilder (builder);
}
/*
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
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.
*/
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));
g_assert (personality);
} else {
#if LLVM_API_VERSION > 100
- 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));
+ 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);
+ }
#else
static gint32 mapping_inited;
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;
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(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");
}
break;
}
+ case OP_OBJC_GET_SELECTOR: {
+ const char *name = (const char*)ins->inst_p0;
+ LLVMValueRef 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_");
+ 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_");
+
+ indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, 0);
+ indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, 0);
+ LLVMSetInitializer (ref_var, LLVMConstGEP (name_var, indexes, 2));
+ LLVMSetLinkage (ref_var, LLVMPrivateLinkage);
+ 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] = LLVMBuildLoad (builder, var, "");
+ break;
+ }
/*
* SIMD
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 */
+ args [2] = LLVMConstInt (LLVMInt32Type (), 0xf1, FALSE);
+
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+ break;
+ }
+
#endif /* SIMD */
case OP_DUMMY_USE:
/* 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);
/*
ctx->is_linkonce = is_linkonce;
#if LLVM_API_VERSION > 100
- ctx->lmodule = LLVMModuleCreateWithName ("jit-module");
+ if (cfg->compile_aot)
+ ctx->lmodule = ctx->module->lmodule;
+ else
+ ctx->lmodule = LLVMModuleCreateWithName ("jit-module");
#else
ctx->lmodule = ctx->module->lmodule;
#endif
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')
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
if (cfg->compile_aot && !cfg->llvm_only)
mark_as_used (ctx->module, method);
- if (cfg->compile_aot && !cfg->llvm_only) {
+ if (!cfg->llvm_only) {
LLVMValueRef md_args [16];
LLVMValueRef md_node;
int method_index;
- method_index = mono_aot_get_method_index (cfg->orig_method);
+ if (cfg->compile_aot)
+ method_index = mono_aot_get_method_index (cfg->orig_method);
+ else
+ method_index = 1;
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);
p += 4;
table = (gint32*)p;
- g_assert (fde_count == 1);
+ g_assert (fde_count <= 2);
- /* The only table entry */
+ /* The first entry is the real method */
+ g_assert (table [0] == 1);
fde_offset = table [1];
- table += 2;
+ table += fde_count * 2;
/* Extra entry */
cfg->code_len = table [0];
fde_len = table [1] - fde_offset;
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);
+ arg_types [2] = LLVMInt32Type ();
+ 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];
module->llvm_only = llvm_only;
/* The first few entries are reserved */
module->max_got_offset = 16;
- module->context = LLVMContextCreate ();
+ 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:
*
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) {
char *verifier_err;
if (LLVMVerifyModule (module->lmodule, LLVMReturnStatusAction, &verifier_err)) {
+ printf ("%s\n", verifier_err);
g_assert_not_reached ();
}
}
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);
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 ();
}
/*
* 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 */