typedef struct {
LLVMModuleRef module;
LLVMValueRef throw, rethrow, throw_corlib_exception;
- LLVMValueRef generic_class_init_tramp;
GHashTable *llvm_types;
LLVMValueRef got_var;
const char *got_symbol;
size = mono_class_value_size (mono_class_from_mono_type (t), NULL);
+ /* LLVMArgAsIArgs depends on this since it stores whole words */
while (size < 2 * sizeof (gpointer) && mono_is_power_of_two (size) == -1)
size ++;
if (t->byref)
return LLVMPointerType (LLVMInt8Type (), 0);
- t = mini_get_underlying_type (ctx->cfg, t);
+ t = mini_get_underlying_type (t);
switch (t->type) {
case MONO_TYPE_VOID:
return LLVMVoidType ();
if (sinfo)
memset (sinfo, 0, sizeof (LLVMSigInfo));
- rtype = mini_get_underlying_type (ctx->cfg, sig->ret);
+ rtype = mini_get_underlying_type (sig->ret);
ret_type = type_to_llvm_type (ctx, rtype);
CHECK_FAILURE (ctx);
if (cinfo) {
- if (cinfo->ret.storage == LLVMArgVtypeInReg) {
+ switch (cinfo->ret.storage) {
+ case 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 if (cinfo->ret.pair_storage [0] == LLVMArgNone && cinfo->ret.pair_storage [1] == LLVMArgNone) {
+ /* Empty struct */
+ ret_type = LLVMVoidType ();
} else {
g_assert_not_reached ();
}
- } else if (cinfo->ret.storage == LLVMArgVtypeByVal) {
+ break;
+ case LLVMArgVtypeByVal:
/* Vtype returned normally by val */
- } else if (cinfo->ret.storage == LLVMArgFpStruct) {
+ break;
+ case LLVMArgVtypeAsScalar:
+ /* LLVM models this by returning an int */
+ g_assert (cinfo->ret.nslots == 1 || cinfo->ret.nslots == 2);
+ ret_type = LLVMIntType (cinfo->ret.nslots * sizeof (mgreg_t) * 8);
+ break;
+ case LLVMArgFpStruct: {
/* Vtype returned as a fp struct */
LLVMTypeRef members [16];
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;
+ break;
+ }
+ case LLVMArgVtypeByRef:
+ /* Vtype returned using a hidden argument */
ret_type = LLVMVoidType ();
+ break;
+ default:
+ if (mini_type_is_vtype (rtype)) {
+ g_assert (cinfo->ret.storage == LLVMArgVtypeRetAddr);
+ vretaddr = TRUE;
+ ret_type = LLVMVoidType ();
+ }
+ break;
}
}
pindexes = g_new0 (int, sig->param_count);
param_types = g_new0 (LLVMTypeRef, (sig->param_count * 8) + 3);
pindex = 0;
+ if (cinfo && cinfo->ret.storage == LLVMArgVtypeByRef) {
+ /*
+ * Has to be the first argument because of the sret argument attribute
+ * FIXME: This might conflict with passing 'this' as the first argument, but
+ * this is only used on arm64 which has a dedicated struct return register.
+ */
+ if (sinfo)
+ sinfo->vret_arg_pindex = pindex;
+ param_types [pindex] = type_to_llvm_arg_type (ctx, sig->ret);
+ CHECK_FAILURE (ctx);
+ param_types [pindex] = LLVMPointerType (param_types [pindex], 0);
+ pindex ++;
+ }
if (cinfo && cinfo->rgctx_arg) {
if (sinfo)
sinfo->rgctx_arg_pindex = pindex;
param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
pindex ++;
break;
+ case LLVMArgVtypeByRef:
+ param_types [pindex] = type_to_llvm_arg_type (ctx, sig->params [i]);
+ CHECK_FAILURE (ctx);
+ param_types [pindex] = LLVMPointerType (param_types [pindex], 0);
+ pindex ++;
+ break;
case LLVMArgAsFpArgs: {
int j;
pindex += ainfo->nslots;
break;
}
+ case LLVMArgVtypeAsScalar:
+ g_assert_not_reached ();
+ break;
default:
param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]);
break;
MonoInst *var = cfg->varinfo [i];
LLVMTypeRef vtype;
- if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || mini_type_is_vtype (cfg, var->inst_vtype)) {
+ if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || mini_type_is_vtype (var->inst_vtype)) {
vtype = type_to_llvm_type (ctx, var->inst_vtype);
CHECK_FAILURE (ctx);
/* Could be already created by an OP_VPHI */
}
break;
}
+ case LLVMArgVtypeByRef: {
+ /* The argument is passed by ref */
+ ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, ctx->pindexes [i]);
+ break;
+ }
case LLVMArgAsIArgs: {
LLVMValueRef arg = LLVMGetParam (ctx->lmethod, ctx->pindexes [i]);
LLVMBuildStore (ctx->builder, arg, convert (ctx, ctx->addresses [reg], LLVMPointerType (LLVMTypeOf (arg), 0)));
break;
}
+ case LLVMArgVtypeAsScalar:
+ g_assert_not_reached ();
+ 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;
if (sig->hasthis)
emit_volatile_store (ctx, cfg->args [0]->dreg);
for (i = 0; i < sig->param_count; ++i)
- if (!mini_type_is_vtype (cfg, sig->params [i]))
+ if (!mini_type_is_vtype (sig->params [i]))
emit_volatile_store (ctx, cfg->args [i + sig->hasthis]->dreg);
- if (sig->hasthis && !cfg->rgctx_var && cfg->generic_sharing_context) {
+ if (sig->hasthis && !cfg->rgctx_var && cfg->gshared) {
LLVMValueRef this_alloc;
/*
;
}
-/* Have to export this for AOT */
-void
-mono_personality (void)
-{
- /* Not used */
- g_assert_not_reached ();
-}
-
static void
process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, MonoInst *ins)
{
if (call->imt_arg_reg)
cinfo->imt_arg = TRUE;
- vretaddr = cinfo && cinfo->ret.storage == LLVMArgVtypeRetAddr;
+ vretaddr = cinfo && (cinfo->ret.storage == LLVMArgVtypeRetAddr || cinfo->ret.storage == LLVMArgVtypeByRef);
llvm_sig = sig_to_llvm_sig_full (ctx, sig, cinfo, &sinfo);
CHECK_FAILURE (ctx);
args [sinfo.imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->lmodule->ptr_type);
#endif
}
-
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 (), "");
+ if (cinfo && cinfo->ret.storage == LLVMArgVtypeByRef)
+ args [sinfo.vret_arg_pindex] = addresses [call->inst.dreg];
+ else
+ args [sinfo.vret_arg_pindex] = LLVMBuildPtrToInt (builder, addresses [call->inst.dreg], IntPtrType (), "");
}
for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
g_assert (addresses [reg]);
args [pindex] = addresses [reg];
break;
+ case LLVMArgVtypeByRef:
+ g_assert (addresses [reg]);
+ args [pindex] = addresses [reg];
+ break;
case LLVMArgAsIArgs:
g_assert (addresses [reg]);
args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
break;
+ case LLVMArgVtypeAsScalar:
+ g_assert_not_reached ();
+ break;
default:
g_assert (args [pindex]);
if (i == 0 && sig->hasthis)
if (!sig->pinvoke)
LLVMSetInstructionCallConv (lcall, LLVMMono1CallConv);
+ if (cinfo && cinfo->ret.storage == LLVMArgVtypeByRef)
+ LLVMAddInstrAttribute (lcall, 1 + sinfo.vret_arg_pindex, LLVMStructRetAttribute);
if (call->rgctx_arg_reg)
LLVMAddInstrAttribute (lcall, 1 + sinfo.rgctx_arg_pindex, LLVMInRegAttribute);
if (call->imt_arg_reg)
case LLVMArgVtypeInReg: {
LLVMValueRef regs [2];
+ if (LLVMTypeOf (lcall) == LLVMVoidType ())
+ /* Empty struct */
+ break;
+
if (!addresses [ins->dreg])
addresses [ins->dreg] = build_alloca (ctx, sig->ret);
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;
+ case LLVMArgVtypeAsScalar:
+ 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 */
if (cfg->compile_aot) {
/* Use a dummy personality function */
- personality = LLVMGetNamedFunction (module, "mono_aot_personality");
+ personality = LLVMGetNamedFunction (module, "mono_personality");
g_assert (personality);
} else {
personality = LLVMGetNamedFunction (module, "mono_personality");
if (bb->flags & BB_EXCEPTION_HANDLER) {
if (!bblocks [bb->block_num].invoke_target) {
- //LLVM_FAILURE (ctx, "handler without invokes");
+ LLVM_FAILURE (ctx, "handler without invokes");
}
emit_handler_start (ctx, bb, builder);
}
case OP_SETRET:
- if (linfo->ret.storage == LLVMArgVtypeInReg) {
+ switch (linfo->ret.storage) {
+ case LLVMArgVtypeInReg: {
LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (method)));
LLVMValueRef part1, retval;
int size;
LLVMBuildRet (builder, retval);
break;
}
+ case LLVMArgVtypeAsScalar: {
+ LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (method)));
+ LLVMValueRef retval;
+ int size;
+
+ size = get_vtype_size (sig->ret);
+
+ g_assert (addresses [ins->sreg1]);
- if (linfo->ret.storage == LLVMArgVtypeByVal) {
+ retval = LLVMBuildLoad (builder, LLVMBuildBitCast (builder, addresses [ins->sreg1], LLVMPointerType (ret_type, 0), ""), "");
+ LLVMBuildRet (builder, retval);
+ break;
+ }
+ case LLVMArgVtypeByVal: {
LLVMValueRef retval;
g_assert (addresses [ins->sreg1]);
LLVMBuildRet (builder, retval);
break;
}
-
- if (linfo->ret.storage == LLVMArgVtypeRetAddr) {
+ case LLVMArgVtypeByRef: {
LLVMBuildRetVoid (builder);
break;
}
-
- if (linfo->ret.storage == LLVMArgFpStruct) {
+ case LLVMArgVtypeRetAddr: {
+ LLVMBuildRetVoid (builder);
+ break;
+ }
+ case LLVMArgFpStruct: {
LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (method)));
LLVMValueRef retval;
LLVMBuildRet (builder, retval);
break;
}
-
- if (!lhs || ctx->is_dead [ins->sreg1]) {
- /*
- * The method did not set its return value, probably because it
- * ends with a throw.
- */
- if (cfg->vret_addr)
- LLVMBuildRetVoid (builder);
- else
- LLVMBuildRet (builder, LLVMConstNull (type_to_llvm_type (ctx, sig->ret)));
- } else {
- LLVMBuildRet (builder, convert (ctx, lhs, type_to_llvm_type (ctx, sig->ret)));
+ default: {
+ if (!lhs || ctx->is_dead [ins->sreg1]) {
+ /*
+ * The method did not set its return value, probably because it
+ * ends with a throw.
+ */
+ if (cfg->vret_addr)
+ LLVMBuildRetVoid (builder);
+ else
+ LLVMBuildRet (builder, LLVMConstNull (type_to_llvm_type (ctx, sig->ret)));
+ } else {
+ LLVMBuildRet (builder, convert (ctx, lhs, type_to_llvm_type (ctx, sig->ret)));
+ }
+ has_terminator = TRUE;
+ break;
+ }
}
- has_terminator = TRUE;
break;
case OP_ICOMPARE:
case OP_FCOMPARE:
case OP_LCONV_TO_R8:
values [ins->dreg] = LLVMBuildSIToFP (builder, lhs, LLVMDoubleType (), dname);
break;
+ case OP_ICONV_TO_R_UN:
case OP_LCONV_TO_R_UN:
values [ins->dreg] = LLVMBuildUIToFP (builder, lhs, LLVMDoubleType (), dname);
break;
case OP_LDADDR: {
MonoInst *var = ins->inst_p0;
- values [ins->dreg] = addresses [var->dreg];
+ if (var->opcode == OP_VTARG_ADDR) {
+ /* The variable contains the vtype address */
+ values [ins->dreg] = values [var->dreg];
+ } else {
+ values [ins->dreg] = addresses [var->dreg];
+ }
break;
}
case OP_SIN: {
break;
}
- if (mini_is_gsharedvt_klass (cfg, klass)) {
+ if (mini_is_gsharedvt_klass (klass)) {
// FIXME:
LLVM_FAILURE (ctx, "gsharedvt");
break;
if (cfg->vret_addr) {
values [cfg->vret_addr->dreg] = LLVMGetParam (method, sinfo.vret_arg_pindex);
LLVMSetValueName (values [cfg->vret_addr->dreg], "vret");
+ if (linfo->ret.storage == LLVMArgVtypeByRef) {
+ LLVMAddAttribute (LLVMGetParam (method, sinfo.vret_arg_pindex), LLVMStructRetAttribute);
+ LLVMAddAttribute (LLVMGetParam (method, sinfo.vret_arg_pindex), LLVMNoAliasAttribute);
+ }
}
if (sig->hasthis) {
values [cfg->args [0]->dreg] = LLVMGetParam (method, sinfo.this_arg_pindex);
g_free (name);
if (linfo->args [i + sig->hasthis].storage == LLVMArgVtypeByVal)
LLVMAddAttribute (LLVMGetParam (method, sinfo.pindexes [i]), LLVMByValAttribute);
+
+ if (linfo->args [i + sig->hasthis].storage == LLVMArgVtypeByRef) {
+ /* For OP_LDADDR */
+ cfg->args [i + sig->hasthis]->opcode = OP_VTARG_ADDR;
+ }
}
g_free (names);
break;
}
case LLVMArgVtypeByVal:
+ case LLVMArgVtypeByRef:
case LLVMArgVtypeInReg:
+ case LLVMArgVtypeAsScalar:
case LLVMArgAsIArgs:
case LLVMArgAsFpArgs:
MONO_INST_NEW (cfg, ins, OP_LLVM_OUTARG_VT);
LLVMSetInitializer (lmodule->got_var, LLVMConstNull (got_type));
}
- /* Add a dummy personality function */
- {
- LLVMBasicBlockRef lbb;
- LLVMBuilderRef lbuilder;
- LLVMValueRef personality;
-
- personality = LLVMAddFunction (lmodule->module, "mono_aot_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
- LLVMSetLinkage (personality, LLVMInternalLinkage);
- lbb = LLVMAppendBasicBlock (personality, "BB0");
- lbuilder = LLVMCreateBuilder ();
- LLVMPositionBuilderAtEnd (lbuilder, lbb);
- LLVMBuildRetVoid (lbuilder);
- mark_as_used (lmodule, personality);
- }
-
lmodule->llvm_types = g_hash_table_new (NULL, NULL);
lmodule->plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
lmodule->plt_entries_ji = g_hash_table_new (NULL, NULL);
LLVMValueRef v;
s = g_strdup_printf ("%s%s", lmodule->global_prefix, name);
- v = LLVMAddGlobal (lmodule->module, type, s);
+ v = LLVMAddGlobal (lmodule->module, LLVMInt8Type (), s);
g_free (s);
return v;
}
fields [tindex ++] = LLVMConstNull (eltype);
}
+ for (i = 0; i < MONO_AOT_FILE_INFO_NUM_SYMBOLS; ++i)
+ fields [2 + i] = LLVMConstBitCast (fields [2 + i], eltype);
+
/* Scalars */
fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->plt_got_offset_base, FALSE);
fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->got_size, FALSE);