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
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 ();
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 && 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 ();
return lcall;
}
-#if LLVM_API_VERSION >= 4
-#define EXTRA_MONO_LOAD_STORE_ARGS 1
-#else
-#define EXTRA_MONO_LOAD_STORE_ARGS 0
-#endif
-
static LLVMValueRef
emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting, BarrierKind barrier)
{
LLVMTypeRef addr_type;
if (is_faulting && bb->region != -1) {
-#if LLVM_API_VERSION >= 4
LLVMAtomicOrdering ordering;
switch (barrier) {
g_assert_not_reached ();
break;
}
-#endif
/*
* We handle loads which can fault by calling a mono specific intrinsic
args [0] = addr;
args [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
args [2] = LLVMConstInt (LLVMInt1Type (), TRUE, FALSE);
-#if LLVM_API_VERSION >= 4
args [3] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
-#endif
- res = emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 3 + EXTRA_MONO_LOAD_STORE_ARGS);
+ 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 (), "");
LLVMValueRef args [16];
if (is_faulting && bb->region != -1) {
-#if LLVM_API_VERSION >= 4
LLVMAtomicOrdering ordering;
switch (barrier) {
g_assert_not_reached ();
break;
}
-#endif
switch (size) {
case 1:
args [1] = addr;
args [2] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
args [3] = LLVMConstInt (LLVMInt1Type (), TRUE, FALSE);
-#if LLVM_API_VERSION >= 4
args [4] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
-#endif
- emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 4 + EXTRA_MONO_LOAD_STORE_ARGS);
+ emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 5);
} else {
mono_llvm_build_store (*builder_ref, value, addr, is_faulting, barrier);
}
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 {
+ 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;
}
}
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 || ins->opcode == OP_RCALL_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 || ins->opcode == OP_RCALL_REG);
+ 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);
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;
}
+ 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_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 */
- 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));
+ 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) {
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
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] = LLVMBuildURem (builder, lhs, rhs, dname);
break;
case OP_IDIV:
- case OP_LDIV: {
-#ifdef MONO_ARCH_NEED_DIV_CHECK
- 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;
-#endif
+ case OP_LDIV:
values [ins->dreg] = LLVMBuildSDiv (builder, lhs, rhs, dname);
break;
- }
case OP_IDIV_UN:
- case OP_LDIV_UN: {
-#ifdef MONO_ARCH_NEED_DIV_CHECK
- 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;
-#endif
+ case OP_LDIV_UN:
values [ins->dreg] = LLVMBuildUDiv (builder, lhs, rhs, dname);
break;
- }
case OP_FDIV:
case OP_RDIV:
values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, dname);
/* 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: {
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;
LLVMTypeRef t;
values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
else if (zext)
values [ins->dreg] = LLVMBuildZExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
-#else
- LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
-#endif
break;
}
case OP_ATOMIC_STORE_I1:
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;
LLVMTypeRef t;
emit_store_general (ctx, bb, &builder, size, value, addr, is_volatile, barrier);
break;
-#else
- LLVM_FAILURE (ctx, "atomic mono.store intrinsic");
-#endif
- break;
}
case OP_RELAXED_NOP: {
#if defined(TARGET_AMD64) || defined(TARGET_X86)
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);
arg_types [0] = LLVMPointerType (LLVMIntType (i * 8), 0);
arg_types [1] = LLVMInt32Type ();
arg_types [2] = LLVMInt1Type ();
-#if LLVM_API_VERSION >= 4
arg_types [3] = LLVMInt32Type ();
-#endif
sprintf (name, "llvm.mono.load.i%d.p0i%d", i * 8, i * 8);
- LLVMAddFunction (module, name, LLVMFunctionType (LLVMIntType (i * 8), arg_types, 3 + EXTRA_MONO_LOAD_STORE_ARGS, 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 ();
-#if LLVM_API_VERSION >= 4
arg_types [4] = LLVMInt32Type ();
-#endif
sprintf (name, "llvm.mono.store.i%d.p0i%d", i * 8, i * 8);
- LLVMAddFunction (module, name, LLVMFunctionType (LLVMVoidType (), arg_types, 4 + EXTRA_MONO_LOAD_STORE_ARGS, 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: