extern void *memset(void *, int, size_t);
void bzero (void *to, size_t count) { memset (to, 0, count); }
+#endif
+
+#if LLVM_API_VERSION < 4
+#error "The version of the mono llvm repository is too old."
#endif
/*
}
}
+static LLVMTypeRef
+create_llvm_type_for_type (MonoClass *klass)
+{
+ int i, size, nfields, esize;
+ LLVMTypeRef *eltypes;
+ char *name;
+ MonoType *t;
+ LLVMTypeRef ltype;
+
+ t = &klass->byval_arg;
+
+ if (mini_type_is_hfa (t, &nfields, &esize)) {
+ /*
+ * This is needed on arm64 where HFAs are returned in
+ * registers.
+ */
+ size = nfields;
+ eltypes = g_new (LLVMTypeRef, size);
+ for (i = 0; i < size; ++i)
+ eltypes [i] = esize == 4 ? LLVMFloatType () : LLVMDoubleType ();
+ } else {
+ size = get_vtype_size (t);
+
+ eltypes = g_new (LLVMTypeRef, size);
+ for (i = 0; i < size; ++i)
+ eltypes [i] = LLVMInt8Type ();
+ }
+
+ name = mono_type_full_name (&klass->byval_arg);
+ ltype = LLVMStructCreateNamed (LLVMGetGlobalContext (), name);
+ LLVMStructSetBody (ltype, eltypes, size, FALSE);
+ g_free (eltypes);
+ g_free (name);
+
+ return ltype;
+}
+
/*
* type_to_llvm_type:
*
static LLVMTypeRef
type_to_llvm_type (EmitContext *ctx, MonoType *t)
{
- t = mini_replace_type (t);
-
if (t->byref)
return LLVMPointerType (LLVMInt8Type (), 0);
+
+ t = mini_get_underlying_type (ctx->cfg, t);
switch (t->type) {
case MONO_TYPE_VOID:
return LLVMVoidType ();
ltype = g_hash_table_lookup (ctx->lmodule->llvm_types, klass);
if (!ltype) {
- int i, size;
- LLVMTypeRef *eltypes;
- char *name;
-
- size = get_vtype_size (t);
-
- eltypes = g_new (LLVMTypeRef, size);
- for (i = 0; i < size; ++i)
- eltypes [i] = LLVMInt8Type ();
-
- name = mono_type_full_name (&klass->byval_arg);
- ltype = LLVMStructCreateNamed (LLVMGetGlobalContext (), name);
- LLVMStructSetBody (ltype, eltypes, size, FALSE);
+ ltype = create_llvm_type_for_type (klass);
g_hash_table_insert (ctx->lmodule->llvm_types, klass, ltype);
- g_free (eltypes);
- g_free (name);
}
return ltype;
}
* on the IL stack.
*/
static G_GNUC_UNUSED LLVMTypeRef
-llvm_type_to_stack_type (LLVMTypeRef type)
+llvm_type_to_stack_type (MonoCompile *cfg, LLVMTypeRef type)
{
if (type == NULL)
return NULL;
return LLVMInt32Type ();
else if (type == LLVMInt16Type ())
return LLVMInt32Type ();
- else if (type == LLVMFloatType ())
+ else if (!cfg->r4fp && type == LLVMFloatType ())
return LLVMDoubleType ();
else
return type;
return LLVMInt64Type ();
case OP_FCONV_TO_I1:
case OP_FCONV_TO_U1:
+ case OP_RCONV_TO_I1:
+ case OP_RCONV_TO_U1:
return LLVMInt8Type ();
case OP_FCONV_TO_I2:
case OP_FCONV_TO_U2:
+ case OP_RCONV_TO_I2:
+ case OP_RCONV_TO_U2:
return LLVMInt16Type ();
case OP_FCONV_TO_I:
case OP_FCONV_TO_U:
case OP_LOADI1_MEMBASE:
case OP_STOREI1_MEMBASE_REG:
case OP_STOREI1_MEMBASE_IMM:
+ case OP_ATOMIC_LOAD_I1:
+ case OP_ATOMIC_STORE_I1:
*size = 1;
*sext = TRUE;
return LLVMInt8Type ();
case OP_LOADU1_MEMBASE:
case OP_LOADU1_MEM:
+ case OP_ATOMIC_LOAD_U1:
+ case OP_ATOMIC_STORE_U1:
*size = 1;
*zext = TRUE;
return LLVMInt8Type ();
case OP_LOADI2_MEMBASE:
case OP_STOREI2_MEMBASE_REG:
case OP_STOREI2_MEMBASE_IMM:
+ case OP_ATOMIC_LOAD_I2:
+ case OP_ATOMIC_STORE_I2:
*size = 2;
*sext = TRUE;
return LLVMInt16Type ();
case OP_LOADU2_MEMBASE:
case OP_LOADU2_MEM:
+ case OP_ATOMIC_LOAD_U2:
+ case OP_ATOMIC_STORE_U2:
*size = 2;
*zext = TRUE;
return LLVMInt16Type ();
case OP_LOADU4_MEM:
case OP_STOREI4_MEMBASE_REG:
case OP_STOREI4_MEMBASE_IMM:
+ case OP_ATOMIC_LOAD_I4:
+ case OP_ATOMIC_STORE_I4:
+ case OP_ATOMIC_LOAD_U4:
+ case OP_ATOMIC_STORE_U4:
*size = 4;
return LLVMInt32Type ();
case OP_LOADI8_MEMBASE:
case OP_LOADI8_MEM:
case OP_STOREI8_MEMBASE_REG:
case OP_STOREI8_MEMBASE_IMM:
+ case OP_ATOMIC_LOAD_I8:
+ case OP_ATOMIC_STORE_I8:
+ case OP_ATOMIC_LOAD_U8:
+ case OP_ATOMIC_STORE_U8:
*size = 8;
return LLVMInt64Type ();
case OP_LOADR4_MEMBASE:
case OP_STORER4_MEMBASE_REG:
+ case OP_ATOMIC_LOAD_R4:
+ case OP_ATOMIC_STORE_R4:
*size = 4;
return LLVMFloatType ();
case OP_LOADR8_MEMBASE:
case OP_STORER8_MEMBASE_REG:
+ case OP_ATOMIC_LOAD_R8:
+ case OP_ATOMIC_STORE_R8:
*size = 8;
return LLVMDoubleType ();
case OP_LOAD_MEMBASE:
if (sinfo)
memset (sinfo, 0, sizeof (LLVMSigInfo));
- rtype = mini_replace_type (sig->ret);
+ rtype = mini_get_underlying_type (ctx->cfg, sig->ret);
ret_type = type_to_llvm_type (ctx, rtype);
CHECK_FAILURE (ctx);
- if (cinfo && cinfo->ret.storage == LLVMArgVtypeInReg) {
- /* LLVM models this by returning an aggregate value */
- if (cinfo->ret.pair_storage [0] == LLVMArgInIReg && cinfo->ret.pair_storage [1] == LLVMArgNone) {
- LLVMTypeRef members [2];
+ if (cinfo) {
+ if (cinfo->ret.storage == LLVMArgVtypeInReg) {
+ /* LLVM models this by returning an aggregate value */
+ if (cinfo->ret.pair_storage [0] == LLVMArgInIReg && cinfo->ret.pair_storage [1] == LLVMArgNone) {
+ LLVMTypeRef members [2];
- members [0] = IntPtrType ();
- ret_type = LLVMStructType (members, 1, FALSE);
- } else {
- g_assert_not_reached ();
+ members [0] = IntPtrType ();
+ ret_type = LLVMStructType (members, 1, FALSE);
+ } else {
+ g_assert_not_reached ();
+ }
+ } else if (cinfo->ret.storage == LLVMArgVtypeByVal) {
+ /* Vtype returned normally by val */
+ } else if (cinfo->ret.storage == LLVMArgFpStruct) {
+ /* Vtype returned as a fp struct */
+ LLVMTypeRef members [16];
+
+ /* Have to create our own structure since we don't map fp structures to LLVM fp structures yet */
+ for (i = 0; i < cinfo->ret.nslots; ++i)
+ members [i] = cinfo->ret.esize == 8 ? LLVMDoubleType () : LLVMFloatType ();
+ ret_type = LLVMStructType (members, cinfo->ret.nslots, FALSE);
+ } else if (mini_type_is_vtype (ctx->cfg, rtype)) {
+ g_assert (cinfo->ret.storage == LLVMArgVtypeRetAddr);
+ vretaddr = TRUE;
+ ret_type = LLVMVoidType ();
}
- } else if (cinfo && mini_type_is_vtype (ctx->cfg, rtype)) {
- g_assert (cinfo->ret.storage == LLVMArgVtypeRetAddr);
- vretaddr = TRUE;
- ret_type = LLVMVoidType ();
}
pindexes = g_new0 (int, sig->param_count);
- param_types = g_new0 (LLVMTypeRef, (sig->param_count * 2) + 3);
+ param_types = g_new0 (LLVMTypeRef, (sig->param_count * 8) + 3);
pindex = 0;
if (cinfo && cinfo->rgctx_arg) {
if (sinfo)
if (vretaddr && vret_arg_pindex == pindex)
param_types [pindex ++] = IntPtrType ();
for (i = 0; i < sig->param_count; ++i) {
+ LLVMArgInfo *ainfo = cinfo ? &cinfo->args [i + sig->hasthis] : NULL;
+
if (vretaddr && vret_arg_pindex == pindex)
param_types [pindex ++] = IntPtrType ();
pindexes [i] = pindex;
- if (cinfo && cinfo->args [i + sig->hasthis].storage == LLVMArgVtypeInReg) {
+
+ if (!ainfo) {
+ param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]);
+ continue;
+ }
+
+ switch (ainfo->storage) {
+ case LLVMArgVtypeInReg:
for (j = 0; j < 2; ++j) {
- switch (cinfo->args [i + sig->hasthis].pair_storage [j]) {
+ switch (ainfo->pair_storage [j]) {
case LLVMArgInIReg:
param_types [pindex ++] = LLVMIntType (sizeof (gpointer) * 8);
break;
g_assert_not_reached ();
}
}
- } else if (cinfo && cinfo->args [i + sig->hasthis].storage == LLVMArgVtypeByVal) {
+ break;
+ case LLVMArgVtypeByVal:
param_types [pindex] = type_to_llvm_arg_type (ctx, sig->params [i]);
CHECK_FAILURE (ctx);
param_types [pindex] = LLVMPointerType (param_types [pindex], 0);
pindex ++;
- } else {
+ break;
+ case LLVMArgAsIArgs:
+ param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
+ pindex ++;
+ break;
+ case LLVMArgAsFpArgs: {
+ int j;
+
+ for (j = 0; j < ainfo->nslots; ++j)
+ param_types [pindex + j] = ainfo->esize == 8 ? LLVMDoubleType () : LLVMFloatType ();
+ pindex += ainfo->nslots;
+ break;
+ }
+ default:
param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]);
- }
+ break;
+ }
}
if (vretaddr && vret_arg_pindex == pindex)
param_types [pindex ++] = IntPtrType ();
}
static LLVMValueRef
-emit_load (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting)
+emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting, BarrierKind barrier)
{
const char *intrins_name;
LLVMValueRef args [16], res;
LLVMTypeRef addr_type;
if (is_faulting && bb->region != -1) {
+ LLVMAtomicOrdering ordering;
+
+ switch (barrier) {
+ case LLVM_BARRIER_NONE:
+ ordering = LLVMAtomicOrderingNotAtomic;
+ break;
+ case LLVM_BARRIER_ACQ:
+ ordering = LLVMAtomicOrderingAcquire;
+ break;
+ case LLVM_BARRIER_SEQ:
+ ordering = LLVMAtomicOrderingSequentiallyConsistent;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
/*
* We handle loads which can fault by calling a mono specific intrinsic
* using an invoke, so they are handled properly inside try blocks.
args [0] = addr;
args [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
args [2] = LLVMConstInt (LLVMInt1Type (), TRUE, FALSE);
- res = emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 3);
+ args [3] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
+ res = emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 4);
if (addr_type == LLVMPointerType (LLVMDoubleType (), 0))
res = LLVMBuildBitCast (*builder_ref, res, LLVMDoubleType (), "");
* LLVM will generate invalid code when encountering a load from a
* NULL address.
*/
- res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting);
+ res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting, barrier);
/* Mark it with a custom metadata */
/*
}
}
+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);
+}
+
static void
-emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting)
+emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting, BarrierKind barrier)
{
const char *intrins_name;
LLVMValueRef args [16];
if (is_faulting && bb->region != -1) {
+ LLVMAtomicOrdering ordering;
+
+ switch (barrier) {
+ case LLVM_BARRIER_NONE:
+ ordering = LLVMAtomicOrderingNotAtomic;
+ break;
+ case LLVM_BARRIER_REL:
+ ordering = LLVMAtomicOrderingRelease;
+ break;
+ case LLVM_BARRIER_SEQ:
+ ordering = LLVMAtomicOrderingSequentiallyConsistent;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
switch (size) {
case 1:
intrins_name = "llvm.mono.store.i8.p0i8";
args [1] = addr;
args [2] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
args [3] = LLVMConstInt (LLVMInt1Type (), TRUE, FALSE);
- emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 4);
+ args [4] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
+ emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 5);
} else {
- LLVMBuildStore (*builder_ref, value, addr);
+ mono_llvm_build_store (*builder_ref, value, addr, is_faulting, barrier);
}
}
+static void
+emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting)
+{
+ emit_store_general (ctx, bb, builder_ref, size, value, addr, is_faulting, LLVM_BARRIER_NONE);
+}
+
/*
* emit_cond_system_exception:
*
}
/*
- * emit_reg_to_vtype:
+ * emit_args_to_vtype:
*
- * Emit code to store the vtype in the registers REGS to the address ADDRESS.
+ * Emit code to store the vtype in the arguments args to the address ADDRESS.
*/
static void
-emit_reg_to_vtype (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMValueRef address, LLVMArgInfo *ainfo, LLVMValueRef *regs)
+emit_args_to_vtype (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMValueRef address, LLVMArgInfo *ainfo, LLVMValueRef *args)
{
- int j, size;
+ int j, size, nslots;
size = get_vtype_size (t);
address = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (LLVMInt8Type (), 0), "");
}
- for (j = 0; j < 2; ++j) {
- LLVMValueRef index [2], addr;
+ if (ainfo->storage == LLVMArgAsFpArgs)
+ nslots = ainfo->nslots;
+ else
+ nslots = 2;
+
+ for (j = 0; j < nslots; ++j) {
+ LLVMValueRef index [2], addr, daddr;
int part_size = size > sizeof (gpointer) ? sizeof (gpointer) : size;
LLVMTypeRef part_type;
if (ainfo->pair_storage [j] == LLVMArgNone)
continue;
- part_type = LLVMIntType (part_size * 8);
- if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
- index [0] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
- addr = LLVMBuildGEP (builder, address, index, 1, "");
- } else {
- index [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
- index [1] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
- addr = LLVMBuildGEP (builder, address, index, 2, "");
- }
switch (ainfo->pair_storage [j]) {
- case LLVMArgInIReg:
- LLVMBuildStore (builder, convert (ctx, regs [j], part_type), LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (part_type, 0), ""));
+ case LLVMArgInIReg: {
+ part_type = LLVMIntType (part_size * 8);
+ if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
+ index [0] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
+ addr = LLVMBuildGEP (builder, address, index, 1, "");
+ } else {
+ daddr = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (IntPtrType (), 0), "");
+ index [0] = LLVMConstInt (LLVMInt32Type (), j, FALSE);
+ addr = LLVMBuildGEP (builder, daddr, index, 1, "");
+ }
+ LLVMBuildStore (builder, convert (ctx, args [j], part_type), LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (part_type, 0), ""));
break;
+ }
+ case LLVMArgInFPReg: {
+ LLVMTypeRef arg_type;
+
+ if (ainfo->esize == 8)
+ arg_type = LLVMDoubleType ();
+ else
+ arg_type = LLVMFloatType ();
+
+ index [0] = LLVMConstInt (LLVMInt32Type (), j, FALSE);
+ daddr = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (arg_type, 0), "");
+ addr = LLVMBuildGEP (builder, daddr, index, 1, "");
+ LLVMBuildStore (builder, args [j], addr);
+ break;
+ }
case LLVMArgNone:
break;
default:
}
/*
- * emit_vtype_to_reg:
+ * emit_vtype_to_args:
*
- * Emit code to load a vtype at address ADDRESS into registers. Store the registers
- * into REGS, and the number of registers into NREGS.
+ * Emit code to load a vtype at address ADDRESS into scalar arguments. Store the arguments
+ * into ARGS, and the number of arguments into NARGS.
*/
static void
-emit_vtype_to_reg (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMValueRef address, LLVMArgInfo *ainfo, LLVMValueRef *regs, guint32 *nregs)
+emit_vtype_to_args (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMValueRef address, LLVMArgInfo *ainfo, LLVMValueRef *args, guint32 *nargs)
{
int pindex = 0;
- int j, size;
+ int j, size, nslots;
+ LLVMTypeRef arg_type;
size = get_vtype_size (t);
- if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
+ if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t)))
address = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (LLVMInt8Type (), 0), "");
- }
- for (j = 0; j < 2; ++j) {
- LLVMValueRef index [2], addr;
+ if (ainfo->storage == LLVMArgAsFpArgs)
+ nslots = ainfo->nslots;
+ else
+ nslots = 2;
+ for (j = 0; j < nslots; ++j) {
+ LLVMValueRef index [2], addr, daddr;
int partsize = size > sizeof (gpointer) ? sizeof (gpointer) : size;
if (ainfo->pair_storage [j] == LLVMArgNone)
continue;
- if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
- index [0] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
- addr = LLVMBuildGEP (builder, address, index, 1, "");
- } else {
- index [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
- index [1] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
- addr = LLVMBuildGEP (builder, address, index, 2, "");
- }
switch (ainfo->pair_storage [j]) {
case LLVMArgInIReg:
- regs [pindex ++] = convert (ctx, LLVMBuildLoad (builder, LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (LLVMIntType (partsize * 8), 0), ""), ""), IntPtrType ());
+ if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
+ index [0] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
+ addr = LLVMBuildGEP (builder, address, index, 1, "");
+ } else {
+ daddr = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (IntPtrType (), 0), "");
+ index [0] = LLVMConstInt (LLVMInt32Type (), j, FALSE);
+ addr = LLVMBuildGEP (builder, daddr, index, 1, "");
+ }
+ args [pindex ++] = convert (ctx, LLVMBuildLoad (builder, LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (LLVMIntType (partsize * 8), 0), ""), ""), IntPtrType ());
+ break;
+ case LLVMArgInFPReg:
+ if (ainfo->esize == 8)
+ arg_type = LLVMDoubleType ();
+ else
+ arg_type = LLVMFloatType ();
+ daddr = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (arg_type, 0), "");
+ index [0] = LLVMConstInt (LLVMInt32Type (), j, FALSE);
+ addr = LLVMBuildGEP (builder, daddr, index, 1, "");
+ args [pindex ++] = LLVMBuildLoad (builder, addr, "");
break;
case LLVMArgNone:
break;
size -= sizeof (gpointer);
}
- *nregs = pindex;
+ *nargs = pindex;
}
static LLVMValueRef
LLVMArgInfo *ainfo = &linfo->args [i + sig->hasthis];
int reg = cfg->args [i + sig->hasthis]->dreg;
- if (ainfo->storage == LLVMArgVtypeInReg) {
- LLVMValueRef regs [2];
+ switch (ainfo->storage) {
+ case LLVMArgVtypeInReg:
+ case LLVMArgAsFpArgs: {
+ LLVMValueRef args [8];
+ int j;
- /*
- * Emit code to save the argument from the registers to
- * the real argument.
- */
+ /* The argument is received as a set of int/fp arguments, store them into the real argument */
+ memset (args, 0, sizeof (args));
pindex = ctx->pindexes [i];
- regs [0] = LLVMGetParam (ctx->lmethod, pindex);
- if (ainfo->pair_storage [1] != LLVMArgNone)
- regs [1] = LLVMGetParam (ctx->lmethod, pindex + 1);
- else
- regs [1] = NULL;
-
+ if (ainfo->storage == LLVMArgVtypeInReg) {
+ args [0] = LLVMGetParam (ctx->lmethod, pindex);
+ if (ainfo->pair_storage [1] != LLVMArgNone)
+ args [1] = LLVMGetParam (ctx->lmethod, pindex + 1);
+ } else {
+ g_assert (ainfo->nslots <= 8);
+ for (j = 0; j < ainfo->nslots; ++j)
+ args [j] = LLVMGetParam (ctx->lmethod, ctx->pindexes [i] + j);
+ }
ctx->addresses [reg] = build_alloca (ctx, sig->params [i]);
- emit_reg_to_vtype (ctx, builder, sig->params [i], ctx->addresses [reg], ainfo, regs);
+ emit_args_to_vtype (ctx, builder, sig->params [i], ctx->addresses [reg], ainfo, args);
- if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (sig->params [i]))) {
+ if (ainfo->storage == LLVMArgVtypeInReg && MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (sig->params [i]))) {
/* Treat these as normal values */
ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
}
- } else if (ainfo->storage == LLVMArgVtypeByVal) {
+ break;
+ }
+ case LLVMArgVtypeByVal: {
ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, ctx->pindexes [i]);
if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (sig->params [i]))) {
/* Treat these as normal values */
ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
}
- } else {
- ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i])), type_is_unsigned (ctx, sig->params [i]));
+ break;
+ }
+ case LLVMArgAsIArgs: {
+ LLVMValueRef arg = LLVMGetParam (ctx->lmethod, ctx->pindexes [i]);
+
+ ctx->addresses [reg] = build_alloca (ctx, sig->params [i]);
+
+ /* The argument is received as an array of ints, store it into the real argument */
+ LLVMBuildStore (ctx->builder, arg, convert (ctx, ctx->addresses [reg], LLVMPointerType (LLVMTypeOf (arg), 0)));
+ break;
+ }
+ default:
+ ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->params [i])), type_is_unsigned (ctx, sig->params [i]));
+ break;
}
}
*/
this_alloc = mono_llvm_build_alloca (builder, ThisType (), LLVMConstInt (LLVMInt32Type (), 1, FALSE), 0, "");
/* This volatile store will keep the alloca alive */
- mono_llvm_build_store (builder, ctx->values [cfg->args [0]->dreg], this_alloc, TRUE);
+ mono_llvm_build_store (builder, ctx->values [cfg->args [0]->dreg], this_alloc, TRUE, LLVM_BARRIER_NONE);
set_metadata_flag (this_alloc, "mono.this");
}
g_assert (ctx->addresses [cfg->rgctx_var->dreg]);
rgctx_alloc = ctx->addresses [cfg->rgctx_var->dreg];
/* This volatile store will keep the alloca alive */
- store = mono_llvm_build_store (builder, convert (ctx, ctx->rgctx_arg, IntPtrType ()), rgctx_alloc, TRUE);
+ store = mono_llvm_build_store (builder, convert (ctx, ctx->rgctx_arg, IntPtrType ()), rgctx_alloc, TRUE, LLVM_BARRIER_NONE);
set_metadata_flag (rgctx_alloc, "mono.this");
}
}
/* Have to export this for AOT */
-void
-mono_personality (void);
-
void
mono_personality (void)
{
llvm_sig = sig_to_llvm_sig_full (ctx, sig, cinfo, &sinfo);
CHECK_FAILURE (ctx);
- virtual = (ins->opcode == OP_VOIDCALL_MEMBASE || ins->opcode == OP_CALL_MEMBASE || ins->opcode == OP_VCALL_MEMBASE || ins->opcode == OP_LCALL_MEMBASE || ins->opcode == OP_FCALL_MEMBASE);
- calli = (ins->opcode == OP_VOIDCALL_REG || ins->opcode == OP_CALL_REG || ins->opcode == OP_VCALL_REG || ins->opcode == OP_LCALL_REG || ins->opcode == OP_FCALL_REG);
+ virtual = (ins->opcode == OP_VOIDCALL_MEMBASE || ins->opcode == OP_CALL_MEMBASE || ins->opcode == OP_VCALL_MEMBASE || ins->opcode == OP_LCALL_MEMBASE || ins->opcode == OP_FCALL_MEMBASE || ins->opcode == OP_RCALL_MEMBASE);
+ calli = !call->fptr_is_patch && (ins->opcode == OP_VOIDCALL_REG || ins->opcode == OP_CALL_REG || ins->opcode == OP_VCALL_REG || ins->opcode == OP_LCALL_REG || ins->opcode == OP_FCALL_REG || ins->opcode == OP_RCALL_REG);
/* FIXME: Avoid creating duplicate methods */
/*
* Collect and convert arguments
*/
- nargs = (sig->param_count * 2) + sig->hasthis + vretaddr + call->rgctx_reg + call->imt_arg_reg;
+ nargs = (sig->param_count * 16) + sig->hasthis + vretaddr + call->rgctx_reg + call->imt_arg_reg;
len = sizeof (LLVMValueRef) * nargs;
args = alloca (len);
memset (args, 0, len);
if (!ctx->imt_rgctx_loc)
ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->lmodule->ptr_type, sizeof (gpointer));
LLVMBuildStore (builder, convert (ctx, ctx->values [call->rgctx_arg_reg], ctx->lmodule->ptr_type), ctx->imt_rgctx_loc);
- args [sinfo.rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
+ args [sinfo.rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
#else
args [sinfo.rgctx_arg_pindex] = convert (ctx, values [call->rgctx_arg_reg], ctx->lmodule->ptr_type);
#endif
if (!ctx->imt_rgctx_loc)
ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->lmodule->ptr_type, sizeof (gpointer));
LLVMBuildStore (builder, convert (ctx, ctx->values [call->imt_arg_reg], ctx->lmodule->ptr_type), ctx->imt_rgctx_loc);
- args [sinfo.imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
+ args [sinfo.imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
#else
args [sinfo.imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->lmodule->ptr_type);
#endif
regpair = (guint32)(gssize)(l->data);
reg = regpair & 0xffffff;
args [pindex] = values [reg];
- if (ainfo->storage == LLVMArgVtypeInReg) {
- int j;
- LLVMValueRef regs [2];
- guint32 nregs;
-
- g_assert (ainfo);
+ switch (ainfo->storage) {
+ case LLVMArgVtypeInReg:
+ case LLVMArgAsFpArgs: {
+ guint32 nargs;
g_assert (addresses [reg]);
-
- emit_vtype_to_reg (ctx, builder, sig->params [i - sig->hasthis], addresses [reg], ainfo, regs, &nregs);
- for (j = 0; j < nregs; ++j)
- args [pindex ++] = regs [j];
+ emit_vtype_to_args (ctx, builder, sig->params [i - sig->hasthis], addresses [reg], ainfo, args + pindex, &nargs);
+ pindex += nargs;
// FIXME: alignment
// FIXME: Get rid of the VMOVE
- } else if (ainfo->storage == LLVMArgVtypeByVal) {
+ break;
+ }
+ case LLVMArgVtypeByVal:
g_assert (addresses [reg]);
args [pindex] = addresses [reg];
- } else {
+ break;
+ case LLVMArgAsIArgs:
+ g_assert (addresses [reg]);
+ args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
+ break;
+ default:
g_assert (args [pindex]);
if (i == 0 && sig->hasthis)
args [pindex] = convert (ctx, args [pindex], ThisType ());
else
args [pindex] = convert (ctx, args [pindex], type_to_llvm_arg_type (ctx, sig->params [i - sig->hasthis]));
+ break;
}
+ g_assert (pindex <= nargs);
l = l->next;
}
/*
* Convert the result
*/
- if (cinfo && cinfo->ret.storage == LLVMArgVtypeInReg) {
- LLVMValueRef regs [2];
+ if (cinfo) {
+ switch (cinfo->ret.storage) {
+ case LLVMArgVtypeInReg: {
+ LLVMValueRef regs [2];
- if (!addresses [ins->dreg])
- addresses [ins->dreg] = build_alloca (ctx, sig->ret);
+ if (!addresses [ins->dreg])
+ addresses [ins->dreg] = build_alloca (ctx, sig->ret);
- regs [0] = LLVMBuildExtractValue (builder, lcall, 0, "");
- if (cinfo->ret.pair_storage [1] != LLVMArgNone)
- regs [1] = LLVMBuildExtractValue (builder, lcall, 1, "");
-
- emit_reg_to_vtype (ctx, builder, sig->ret, addresses [ins->dreg], &cinfo->ret, regs);
- } else if (sig->ret->type != MONO_TYPE_VOID && !vretaddr) {
- /* If the method returns an unsigned value, need to zext it */
+ regs [0] = LLVMBuildExtractValue (builder, lcall, 0, "");
+ if (cinfo->ret.pair_storage [1] != LLVMArgNone)
+ regs [1] = LLVMBuildExtractValue (builder, lcall, 1, "");
+ emit_args_to_vtype (ctx, builder, sig->ret, addresses [ins->dreg], &cinfo->ret, regs);
+ break;
+ }
+ case LLVMArgVtypeByVal:
+ if (!addresses [call->inst.dreg])
+ addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+ LLVMBuildStore (builder, lcall, addresses [call->inst.dreg]);
+ break;
+ case LLVMArgFpStruct:
+ if (!addresses [call->inst.dreg])
+ addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+ LLVMBuildStore (builder, lcall, convert_full (ctx, addresses [call->inst.dreg], LLVMPointerType (LLVMTypeOf (lcall), 0), FALSE));
+ break;
+ default:
+ if (sig->ret->type != MONO_TYPE_VOID && !vretaddr)
+ /* If the method returns an unsigned value, need to zext it */
+ values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->ret)), type_is_unsigned (ctx, sig->ret));
+ break;
+ }
+ } else {
+ if (sig->ret->type != MONO_TYPE_VOID && !vretaddr)
+ /* If the method returns an unsigned value, need to zext it */
+ values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->ret)), type_is_unsigned (ctx, sig->ret));
+ }
- values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->ret)), type_is_unsigned (ctx, sig->ret));
+ if (vretaddr) {
+ if (!addresses [call->inst.dreg])
+ addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+ g_assert (sinfo.vret_arg_pindex < nargs);
+ args [sinfo.vret_arg_pindex] = LLVMBuildPtrToInt (builder, addresses [call->inst.dreg], IntPtrType (), "");
}
*builder_ref = ctx->builder;
LLVMValueRef method = ctx->lmethod;
LLVMValueRef *values = ctx->values;
LLVMValueRef *addresses = ctx->addresses;
- int i;
LLVMCallInfo *linfo = ctx->linfo;
LLVMModuleRef module = ctx->module;
BBInfo *bblocks = ctx->bblocks;
values [ins->dreg] = LLVMConstReal (LLVMDoubleType (), *(double*)ins->inst_p0);
break;
case OP_R4CONST:
- values [ins->dreg] = LLVMConstFPExt (LLVMConstReal (LLVMFloatType (), *(float*)ins->inst_p0), LLVMDoubleType ());
+ if (cfg->r4fp)
+ values [ins->dreg] = LLVMConstReal (LLVMFloatType (), *(float*)ins->inst_p0);
+ else
+ values [ins->dreg] = LLVMConstFPExt (LLVMConstReal (LLVMFloatType (), *(float*)ins->inst_p0), LLVMDoubleType ());
break;
case OP_DUMMY_ICONST:
values [ins->dreg] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
break;
}
+ if (linfo->ret.storage == LLVMArgVtypeByVal) {
+ LLVMValueRef retval;
+
+ g_assert (addresses [ins->sreg1]);
+ retval = LLVMBuildLoad (builder, addresses [ins->sreg1], "");
+ LLVMBuildRet (builder, retval);
+ break;
+ }
+
if (linfo->ret.storage == LLVMArgVtypeRetAddr) {
LLVMBuildRetVoid (builder);
break;
}
+ if (linfo->ret.storage == LLVMArgFpStruct) {
+ LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (method)));
+ LLVMValueRef retval;
+
+ g_assert (addresses [ins->sreg1]);
+ retval = LLVMBuildLoad (builder, convert (ctx, addresses [ins->sreg1], LLVMPointerType (ret_type, 0)), "");
+ LLVMBuildRet (builder, retval);
+ break;
+ }
+
if (!lhs || ctx->is_dead [ins->sreg1]) {
/*
* The method did not set its return value, probably because it
break;
case OP_ICOMPARE:
case OP_FCOMPARE:
+ case OP_RCOMPARE:
case OP_LCOMPARE:
case OP_COMPARE:
case OP_ICOMPARE_IMM:
}
/* We use COMPARE+SETcc/Bcc, llvm uses SETcc+br cond */
- if (ins->opcode == OP_FCOMPARE)
+ if (ins->opcode == OP_FCOMPARE) {
cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMDoubleType ()), convert (ctx, rhs, LLVMDoubleType ()), "");
- else if (ins->opcode == OP_COMPARE_IMM) {
+ } else if (ins->opcode == OP_RCOMPARE) {
+ cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMFloatType ()), convert (ctx, rhs, LLVMFloatType ()), "");
+ } else if (ins->opcode == OP_COMPARE_IMM) {
if (LLVMGetTypeKind (LLVMTypeOf (lhs)) == LLVMPointerTypeKind && ins->inst_imm == 0)
cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], lhs, LLVMConstNull (LLVMTypeOf (lhs)), "");
else
values [ins->dreg] = LLVMBuildZExt (builder, cmp, LLVMInt32Type (), dname);
break;
}
+ case OP_RCEQ:
+ case OP_RCLT:
+ case OP_RCLT_UN:
+ case OP_RCGT:
+ case OP_RCGT_UN: {
+ CompRelation rel;
+ LLVMValueRef cmp;
+
+ rel = mono_opcode_to_cond (ins->opcode);
+
+ cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMFloatType ()), convert (ctx, rhs, LLVMFloatType ()), "");
+ values [ins->dreg] = LLVMBuildZExt (builder, cmp, LLVMInt32Type (), dname);
+ break;
+ }
case OP_PHI:
case OP_FPHI:
case OP_VPHI:
g_assert (lhs);
values [ins->dreg] = lhs;
break;
- case OP_FMOVE: {
+ case OP_FMOVE:
+ case OP_RMOVE: {
MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
g_assert (lhs);
}
break;
}
+ case OP_MOVE_F_TO_I4: {
+ values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildFPTrunc (builder, lhs, LLVMFloatType (), ""), LLVMInt32Type (), "");
+ break;
+ }
+ case OP_MOVE_I4_TO_F: {
+ values [ins->dreg] = LLVMBuildFPExt (builder, LLVMBuildBitCast (builder, lhs, LLVMFloatType (), ""), LLVMDoubleType (), "");
+ break;
+ }
+ case OP_MOVE_F_TO_I8: {
+ values [ins->dreg] = LLVMBuildBitCast (builder, lhs, LLVMInt64Type (), "");
+ break;
+ }
+ case OP_MOVE_I8_TO_F: {
+ values [ins->dreg] = LLVMBuildBitCast (builder, lhs, LLVMDoubleType (), "");
+ break;
+ }
case OP_IADD:
case OP_ISUB:
case OP_IAND:
lhs = convert (ctx, lhs, regtype_to_llvm_type (spec [MONO_INST_DEST]));
rhs = convert (ctx, rhs, regtype_to_llvm_type (spec [MONO_INST_DEST]));
+#ifdef MONO_ARCH_NEED_DIV_CHECK
+ switch (ins->opcode) {
+ case OP_IDIV:
+ case OP_LDIV:
+ case OP_IREM:
+ case OP_LREM:
+ case OP_IDIV_UN:
+ case OP_LDIV_UN:
+ case OP_IREM_UN:
+ case OP_LREM_UN: {
+ LLVMValueRef cmp;
+
+ cmp = LLVMBuildICmp (builder, LLVMIntEQ, rhs, LLVMConstInt (LLVMTypeOf (rhs), 0, FALSE), "");
+ emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp);
+ CHECK_FAILURE (ctx);
+ builder = ctx->builder;
+ break;
+ }
+ default:
+ break;
+ }
+#endif
+
switch (ins->opcode) {
case OP_IADD:
case OP_LADD:
values [ins->dreg] = LLVMBuildUDiv (builder, lhs, rhs, dname);
break;
case OP_FDIV:
+ case OP_RDIV:
values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, dname);
break;
case OP_IAND:
g_assert_not_reached ();
}
break;
+ case OP_RADD:
+ case OP_RSUB:
+ case OP_RMUL:
+ case OP_RDIV: {
+ lhs = convert (ctx, lhs, LLVMFloatType ());
+ rhs = convert (ctx, rhs, LLVMFloatType ());
+ switch (ins->opcode) {
+ case OP_RADD:
+ values [ins->dreg] = LLVMBuildFAdd (builder, lhs, rhs, dname);
+ break;
+ case OP_RSUB:
+ values [ins->dreg] = LLVMBuildFSub (builder, lhs, rhs, dname);
+ break;
+ case OP_RMUL:
+ values [ins->dreg] = LLVMBuildFMul (builder, lhs, rhs, dname);
+ break;
+ case OP_RDIV:
+ values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, dname);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ }
case OP_IADD_IMM:
case OP_ISUB_IMM:
case OP_IMUL_IMM:
lhs = convert (ctx, lhs, LLVMDoubleType ());
values [ins->dreg] = LLVMBuildFSub (builder, LLVMConstReal (LLVMDoubleType (), 0.0), lhs, dname);
break;
+ case OP_RNEG:
+ lhs = convert (ctx, lhs, LLVMFloatType ());
+ values [ins->dreg] = LLVMBuildFSub (builder, LLVMConstReal (LLVMFloatType (), 0.0), lhs, dname);
+ break;
case OP_INOT: {
guint32 v = 0xffffffff;
values [ins->dreg] = LLVMBuildXor (builder, LLVMConstInt (LLVMInt32Type (), v, FALSE), convert (ctx, lhs, LLVMInt32Type ()), dname);
values [ins->dreg] = LLVMBuildZExt (builder, lhs, LLVMInt64Type (), dname);
break;
case OP_FCONV_TO_I4:
+ case OP_RCONV_TO_I4:
values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMInt32Type (), dname);
break;
case OP_FCONV_TO_I1:
+ case OP_RCONV_TO_I1:
values [ins->dreg] = LLVMBuildSExt (builder, LLVMBuildFPToSI (builder, lhs, LLVMInt8Type (), dname), LLVMInt32Type (), "");
break;
case OP_FCONV_TO_U1:
+ case OP_RCONV_TO_U1:
values [ins->dreg] = LLVMBuildZExt (builder, LLVMBuildFPToUI (builder, lhs, LLVMInt8Type (), dname), LLVMInt32Type (), "");
break;
case OP_FCONV_TO_I2:
+ case OP_RCONV_TO_I2:
values [ins->dreg] = LLVMBuildSExt (builder, LLVMBuildFPToSI (builder, lhs, LLVMInt16Type (), dname), LLVMInt32Type (), "");
break;
case OP_FCONV_TO_U2:
+ case OP_RCONV_TO_U2:
values [ins->dreg] = LLVMBuildZExt (builder, LLVMBuildFPToUI (builder, lhs, LLVMInt16Type (), dname), LLVMInt32Type (), "");
break;
case OP_FCONV_TO_I8:
+ case OP_RCONV_TO_I8:
values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMInt64Type (), dname);
break;
case OP_FCONV_TO_I:
case OP_ICONV_TO_R4:
case OP_LCONV_TO_R4:
v = LLVMBuildSIToFP (builder, lhs, LLVMFloatType (), "");
- values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
+ if (cfg->r4fp)
+ values [ins->dreg] = v;
+ else
+ values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
break;
case OP_FCONV_TO_R4:
v = LLVMBuildFPTrunc (builder, lhs, LLVMFloatType (), "");
- values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
+ if (cfg->r4fp)
+ values [ins->dreg] = v;
+ else
+ values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
+ break;
+ case OP_RCONV_TO_R8:
+ values [ins->dreg] = LLVMBuildFPExt (builder, lhs, LLVMDoubleType (), dname);
+ break;
+ case OP_RCONV_TO_R4:
+ values [ins->dreg] = lhs;
break;
case OP_SEXT_I4:
values [ins->dreg] = LLVMBuildSExt (builder, convert (ctx, lhs, LLVMInt32Type ()), LLVMInt64Type (), dname);
values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
else if (zext)
values [ins->dreg] = LLVMBuildZExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
- else if (ins->opcode == OP_LOADR4_MEMBASE)
+ else if (!cfg->r4fp && ins->opcode == OP_LOADR4_MEMBASE)
values [ins->dreg] = LLVMBuildFPExt (builder, values [ins->dreg], LLVMDoubleType (), dname);
break;
}
case OP_CALL:
case OP_LCALL:
case OP_FCALL:
+ case OP_RCALL:
case OP_VCALL:
case OP_VOIDCALL_MEMBASE:
case OP_CALL_MEMBASE:
case OP_LCALL_MEMBASE:
case OP_FCALL_MEMBASE:
+ case OP_RCALL_MEMBASE:
case OP_VCALL_MEMBASE:
case OP_VOIDCALL_REG:
case OP_CALL_REG:
case OP_LCALL_REG:
case OP_FCALL_REG:
+ case OP_RCALL_REG:
case OP_VCALL_REG: {
process_call (ctx, bb, &builder, ins);
CHECK_FAILURE (ctx);
/* new value */
args [2] = convert (ctx, values [ins->sreg2], t);
val = mono_llvm_build_cmpxchg (builder, args [0], args [1], args [2]);
-#if LLVM_API_VERSION >= 1
/* cmpxchg returns a pair */
values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, "");
-#else
- values [ins->dreg] = val;
-#endif
break;
}
case OP_MEMORY_BARRIER: {
mono_llvm_build_fence (builder, (BarrierKind) ins->backend.memory_barrier_kind);
break;
}
+ case OP_ATOMIC_LOAD_I1:
+ case OP_ATOMIC_LOAD_I2:
+ case OP_ATOMIC_LOAD_I4:
+ case OP_ATOMIC_LOAD_I8:
+ case OP_ATOMIC_LOAD_U1:
+ case OP_ATOMIC_LOAD_U2:
+ case OP_ATOMIC_LOAD_U4:
+ case OP_ATOMIC_LOAD_U8:
+ case OP_ATOMIC_LOAD_R4:
+ case OP_ATOMIC_LOAD_R8: {
+ LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
+
+ int size;
+ gboolean sext, zext;
+ LLVMTypeRef t;
+ gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
+ BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
+ LLVMValueRef index, addr;
+
+ t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
+
+ if (sext || zext)
+ dname = (char *)"";
+
+ if (ins->inst_offset != 0) {
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, lhs, LLVMPointerType (t, 0)), &index, 1, "");
+ } else {
+ addr = lhs;
+ }
+
+ addr = convert (ctx, addr, LLVMPointerType (t, 0));
+
+ values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, dname, is_volatile, barrier);
+
+ 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;
+ }
+ case OP_ATOMIC_STORE_I1:
+ case OP_ATOMIC_STORE_I2:
+ case OP_ATOMIC_STORE_I4:
+ case OP_ATOMIC_STORE_I8:
+ case OP_ATOMIC_STORE_U1:
+ case OP_ATOMIC_STORE_U2:
+ case OP_ATOMIC_STORE_U4:
+ case OP_ATOMIC_STORE_U8:
+ case OP_ATOMIC_STORE_R4:
+ case OP_ATOMIC_STORE_R8: {
+ LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
+
+ int size;
+ gboolean sext, zext;
+ LLVMTypeRef t;
+ gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
+ BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
+ LLVMValueRef index, addr, value;
+
+ if (!values [ins->inst_destbasereg])
+ LLVM_FAILURE (ctx, "inst_destbasereg");
+
+ t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
+
+ index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
+ addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+ value = convert (ctx, values [ins->sreg1], t);
+
+ emit_store_general (ctx, bb, &builder, size, value, addr, is_volatile, barrier);
+ break;
+ }
case OP_RELAXED_NOP: {
#if defined(TARGET_AMD64) || defined(TARGET_X86)
emit_call (ctx, bb, &builder, LLVMGetNamedFunction (ctx->module, "llvm.x86.sse2.pause"), NULL, 0);
case OP_EXPAND_R8: {
LLVMTypeRef t = simd_op_to_llvm_type (ins->opcode);
LLVMValueRef mask [16], v;
+ int i;
for (i = 0; i < 16; ++i)
mask [i] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
break;
}
- case OP_ICONV_TO_R8_RAW:
- /* Same as OP_ICONV_TO_R8 */
- values [ins->dreg] = convert (ctx, LLVMBuildBitCast (builder, lhs, LLVMFloatType (), ""), LLVMDoubleType ());
- break;
-
case OP_COMPPS:
case OP_COMPPD: {
LLVMValueRef args [3];
if (cfg->compile_aot) {
LLVMSetLinkage (method, LLVMInternalLinkage);
-#if LLVM_API_VERSION == 0
- /* This causes an assertion in later LLVM versions */
- LLVMSetVisibility (method, LLVMHiddenVisibility);
-#endif
if (ctx->lmodule->external_symbols) {
LLVMSetLinkage (method, LLVMExternalLinkage);
LLVMSetVisibility (method, LLVMHiddenVisibility);
if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
LLVM_FAILURE (ctx, "non-finally/catch clause.");
}
+ if (header->num_clauses || (cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING))
+ /* We can't handle inlined methods with clauses */
+ LLVMAddFunctionAttr (method, LLVMNoInlineAttribute);
if (linfo->rgctx_arg) {
ctx->rgctx_arg = LLVMGetParam (method, sinfo.rgctx_arg_pindex);
case OP_FPHI:
case OP_VPHI:
case OP_XPHI: {
- LLVMTypeRef phi_type = llvm_type_to_stack_type (type_to_llvm_type (ctx, &ins->klass->byval_arg));
+ LLVMTypeRef phi_type = llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, &ins->klass->byval_arg));
CHECK_FAILURE (ctx);
}
case LLVMArgVtypeByVal:
case LLVMArgVtypeInReg:
+ case LLVMArgAsIArgs:
+ case LLVMArgAsFpArgs:
MONO_INST_NEW (cfg, ins, OP_LLVM_OUTARG_VT);
ins->dreg = mono_alloc_ireg (cfg);
ins->sreg1 = in->dreg;
arg_types [0] = LLVMPointerType (LLVMIntType (i * 8), 0);
arg_types [1] = LLVMInt32Type ();
arg_types [2] = LLVMInt1Type ();
+ arg_types [3] = LLVMInt32Type ();
sprintf (name, "llvm.mono.load.i%d.p0i%d", i * 8, i * 8);
- LLVMAddFunction (module, name, LLVMFunctionType (LLVMIntType (i * 8), arg_types, 3, FALSE));
+ LLVMAddFunction (module, name, LLVMFunctionType (LLVMIntType (i * 8), arg_types, 4, FALSE));
arg_types [0] = LLVMIntType (i * 8);
arg_types [1] = LLVMPointerType (LLVMIntType (i * 8), 0);
arg_types [2] = LLVMInt32Type ();
arg_types [3] = LLVMInt1Type ();
+ arg_types [4] = LLVMInt32Type ();
sprintf (name, "llvm.mono.store.i%d.p0i%d", i * 8, i * 8);
- LLVMAddFunction (module, name, LLVMFunctionType (LLVMVoidType (), arg_types, 4, FALSE));
+ LLVMAddFunction (module, name, LLVMFunctionType (LLVMVoidType (), arg_types, 5, FALSE));
}
}
}
lbuilder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (lbuilder, lbb);
LLVMBuildRetVoid (lbuilder);
+ mark_as_used (&aot_module, personality);
}
aot_module.llvm_types = g_hash_table_new (NULL, NULL);
/*
AOT SUPPORT:
- Emit LLVM bytecode into a .bc file, compile it using llc into a .s file, then
- append the AOT data structures to that file. For methods which cannot be
- handled by LLVM, the normal JIT compiled versions are used.
+ Emit LLVM bytecode into a .bc file, compile it using llc into a .s file, then link
+ it with the file containing the methods emitted by the JIT and the AOT data
+ structures.
*/
/* FIXME: Normalize some aspects of the mono IR to allow easier translation, like: