}
}
+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:
*
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:
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 && cinfo->ret.storage == LLVMArgVtypeByVal) {
- /* Vtype returned normally by val */
- } 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);
if (vretaddr && vret_arg_pindex == pindex)
param_types [pindex ++] = IntPtrType ();
pindexes [i] = pindex;
- if (ainfo && ainfo->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 (ainfo->pair_storage [j]) {
case LLVMArgInIReg:
g_assert_not_reached ();
}
}
- } else if (ainfo && ainfo->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 if (ainfo && ainfo->storage == LLVMArgAsIArgs) {
+ break;
+ case LLVMArgAsIArgs:
param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
pindex ++;
- } else if (ainfo && ainfo->storage == LLVMArgAsFpArgs) {
+ break;
+ case LLVMArgAsFpArgs: {
int j;
for (j = 0; j < ainfo->nslots; ++j)
param_types [pindex + j] = ainfo->esize == 8 ? LLVMDoubleType () : LLVMFloatType ();
pindex += ainfo->nslots;
- } else {
+ 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 ();
nslots = 2;
for (j = 0; j < nslots; ++j) {
- LLVMValueRef index [2], addr;
+ LLVMValueRef index [2], addr, daddr;
int part_size = size > sizeof (gpointer) ? sizeof (gpointer) : size;
LLVMTypeRef part_type;
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, "");
+ 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: {
- LLVMValueRef daddr;
LLVMTypeRef arg_type;
if (ainfo->esize == 8)
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, "");
+ 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;
LLVMArgInfo *ainfo = &linfo->args [i + sig->hasthis];
int reg = cfg->args [i + sig->hasthis]->dreg;
- if (ainfo->storage == LLVMArgVtypeInReg || ainfo->storage == LLVMArgAsFpArgs) {
+ switch (ainfo->storage) {
+ case LLVMArgVtypeInReg:
+ case LLVMArgAsFpArgs: {
LLVMValueRef args [8];
int j;
/* 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 if (ainfo->storage == LLVMArgAsIArgs) {
+ 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)));
- } 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;
+ }
+ 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;
}
}
}
/* 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 */
regpair = (guint32)(gssize)(l->data);
reg = regpair & 0xffffff;
args [pindex] = values [reg];
- if (ainfo->storage == LLVMArgVtypeInReg || ainfo->storage == LLVMArgAsFpArgs) {
+ switch (ainfo->storage) {
+ case LLVMArgVtypeInReg:
+ case LLVMArgAsFpArgs: {
guint32 nargs;
g_assert (addresses [reg]);
// 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 if (ainfo->storage == LLVMArgAsIArgs) {
+ break;
+ case LLVMArgAsIArgs:
g_assert (addresses [reg]);
args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
- } else {
+ 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;
}
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);
-
- 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);
- } else if (cinfo && cinfo->ret.storage == LLVMArgVtypeByVal) {
- if (!addresses [call->inst.dreg])
- addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
- LLVMBuildStore (builder, lcall, addresses [call->inst.dreg]);
- } else if (sig->ret->type != MONO_TYPE_VOID && !vretaddr) {
- /* If the method returns an unsigned value, need to zext it */
+ if (!addresses [ins->dreg])
+ addresses [ins->dreg] = build_alloca (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));
+ 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));
}
if (vretaddr) {
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 == 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);
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);
case OP_ATOMIC_LOAD_U8:
case OP_ATOMIC_LOAD_R4:
case OP_ATOMIC_LOAD_R8: {
+ LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
#if LLVM_API_VERSION >= 4
int size;
gboolean sext, zext;
case OP_ATOMIC_STORE_U8:
case OP_ATOMIC_STORE_R4:
case OP_ATOMIC_STORE_R8: {
+ LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
#if LLVM_API_VERSION >= 4
int size;
gboolean sext, zext;
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 (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);
lbuilder = LLVMCreateBuilder ();
LLVMPositionBuilderAtEnd (lbuilder, lbb);
LLVMBuildRetVoid (lbuilder);
+ mark_as_used (&aot_module, personality);
}
aot_module.llvm_types = g_hash_table_new (NULL, NULL);