#include "mini.h"
#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/debug-mono-symfile.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/utils/mono-tls.h>
#include <mono/utils/mono-dl.h>
+#include <mono/utils/mono-time.h>
+#include <mono/utils/freebsd-dwarf.h>
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#include "mini-llvm-cpp.h"
+#ifdef __MINGW32__
+
+#include <stddef.h>
+extern void *memset(void *, int, size_t);
+void bzero (void *to, size_t count) { memset (to, 0, count); }
+
+#endif
+
/*
* Information associated by mono with LLVM modules.
*/
LLVMValueRef got_var;
const char *got_symbol;
GHashTable *plt_entries;
+ GHashTable *plt_entries_ji;
+ GHashTable *method_to_lmethod;
char **bb_names;
int bb_names_len;
GPtrArray *used;
LLVMTypeRef ptr_type;
+ GPtrArray *subprogram_mds;
MonoEERef *mono_ee;
LLVMExecutionEngineRef ee;
+ gboolean external_symbols;
+ gboolean emit_dwarf;
+ int max_got_offset;
} MonoLLVMModule;
/*
int *pindexes;
LLVMValueRef imt_rgctx_loc;
GHashTable *llvm_types;
-
+ LLVMValueRef dbg_md;
+ MonoDebugMethodInfo *minfo;
char temp_name [32];
} EmitContext;
static void init_jit_module (MonoDomain *domain);
+static void emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsigned char *cil_code);
+static LLVMValueRef emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, const char *name);
+static void emit_dbg_info (MonoLLVMModule *lmodule, const char *filename, const char *cu_name);
+
/*
* IntPtrType:
*
switch (t->type) {
case MONO_TYPE_U1:
case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
case MONO_TYPE_U4:
case MONO_TYPE_U8:
return TRUE;
type_to_llvm_arg_type (EmitContext *ctx, MonoType *t)
{
LLVMTypeRef ptype = type_to_llvm_type (ctx, t);
-
+
+ /*
+ * This works on all abis except arm64/ios which passes multiple
+ * arguments in one stack slot.
+ */
+#ifndef TARGET_ARM64
if (ptype == LLVMInt8Type () || ptype == LLVMInt16Type ()) {
/*
* LLVM generates code which only sets the lower bits, while JITted
*/
ptype = LLVMInt32Type ();
}
+#endif
return ptype;
}
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 (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 && ainfo->storage == 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) {
+ } else if (ainfo && ainfo->storage == 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) {
+ param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
+ pindex ++;
} else {
param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]);
}
{
char *callee_name = mono_aot_get_plt_symbol (type, data);
LLVMValueRef callee;
+ MonoJumpInfo *ji = NULL;
if (!callee_name)
return NULL;
g_hash_table_insert (ctx->lmodule->plt_entries, (char*)callee_name, callee);
}
+ if (ctx->cfg->compile_aot) {
+ ji = g_new0 (MonoJumpInfo, 1);
+ ji->type = type;
+ ji->data.target = data;
+
+ g_hash_table_insert (ctx->lmodule->plt_entries_ji, ji, callee);
+ }
+
return callee;
}
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 (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) {
+#if LLVM_API_VERSION >= 4
+ 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;
+ }
+#endif
+
/*
* 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);
+#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);
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) {
+#if LLVM_API_VERSION >= 4
+ 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;
+ }
+#endif
+
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);
+#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);
} 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:
*
/* Treat these as normal values */
ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
}
+ } else if (ainfo->storage == 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 (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i])));
+ 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]));
}
}
*/
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");
}
* their own calling convention on some platforms.
*/
#ifndef TARGET_AMD64
- if (abs_ji->type == MONO_PATCH_INFO_MONITOR_ENTER || abs_ji->type == MONO_PATCH_INFO_MONITOR_EXIT || abs_ji->type == MONO_PATCH_INFO_GENERIC_CLASS_INIT)
+ if (abs_ji->type == MONO_PATCH_INFO_MONITOR_ENTER || abs_ji->type == MONO_PATCH_INFO_MONITOR_ENTER_V4 ||
+ abs_ji->type == MONO_PATCH_INFO_MONITOR_EXIT || abs_ji->type == MONO_PATCH_INFO_GENERIC_CLASS_INIT)
LLVM_FAILURE (ctx, "trampoline with own cconv");
#endif
target = mono_resolve_patch_target (cfg->method, cfg->domain, NULL, abs_ji, FALSE);
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
} else if (ainfo->storage == LLVMArgVtypeByVal) {
g_assert (addresses [reg]);
args [pindex] = addresses [reg];
+ } else if (ainfo->storage == LLVMArgAsIArgs) {
+ g_assert (addresses [reg]);
+ args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
} else {
g_assert (args [pindex]);
if (i == 0 && sig->hasthis)
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;
char *dname = NULL;
char dname_buf [128];
+ emit_dbg_loc (ctx, builder, ins->cil_code);
+
nins ++;
if (nins > 5000 && builder == starting_builder) {
/* some steps in llc are non-linear in the size of basic blocks, see #5714 */
//mono_add_patch_info (cfg, 0, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
got_offset = mono_aot_get_got_offset (cfg->patch_info);
+ ctx->lmodule->max_got_offset = MAX (ctx->lmodule->max_got_offset, got_offset);
indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
indexes [1] = LLVMConstInt (LLVMInt32Type (), (gssize)got_offset, FALSE);
break;
}
case OP_MEMORY_BARRIER: {
- mono_llvm_build_fence (builder);
+ 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: {
+#if LLVM_API_VERSION >= 4
+ 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);
+#else
+ LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
+#endif
+ 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: {
+#if LLVM_API_VERSION >= 4
+ 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;
+#else
+ LLVM_FAILURE (ctx, "atomic mono.store intrinsic");
+#endif
break;
}
case OP_RELAXED_NOP: {
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);
if (!has_terminator && bb->next_bb && (bb == cfg->bb_entry || bb->in_count > 0))
LLVMBuildBr (builder, get_bb (ctx, bb->next_bb));
- if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID)
+ if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID) {
+ emit_dbg_loc (ctx, builder, cfg->header->code + cfg->header->code_size - 1);
LLVMBuildRetVoid (builder);
+ }
if (bb == cfg->bb_entry)
ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry));
/* This causes an assertion in later LLVM versions */
LLVMSetVisibility (method, LLVMHiddenVisibility);
#endif
+ if (ctx->lmodule->external_symbols) {
+ LLVMSetLinkage (method, LLVMExternalLinkage);
+ LLVMSetVisibility (method, LLVMHiddenVisibility);
+ }
} else {
LLVMSetLinkage (method, LLVMPrivateLinkage);
}
}
g_free (names);
+ if (ctx->lmodule->emit_dwarf && cfg->compile_aot && mono_debug_enabled ()) {
+ ctx->minfo = mono_debug_lookup_method (cfg->method);
+ ctx->dbg_md = emit_dbg_subprogram (ctx, cfg, method, method_name);
+ }
+
max_block_num = 0;
for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
max_block_num = MAX (max_block_num, bb->block_num);
/* FIXME: Free the LLVM IL for the function */
}
+ if (ctx->lmodule->method_to_lmethod)
+ g_hash_table_insert (ctx->lmodule->method_to_lmethod, cfg->method, method);
+
goto CLEANUP;
FAILURE:
}
case LLVMArgVtypeByVal:
case LLVMArgVtypeInReg:
+ case LLVMArgAsIArgs:
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 ();
+#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, FALSE));
+ LLVMAddFunction (module, name, LLVMFunctionType (LLVMIntType (i * 8), arg_types, 3 + EXTRA_MONO_LOAD_STORE_ARGS, 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, FALSE));
+ LLVMAddFunction (module, name, LLVMFunctionType (LLVMVoidType (), arg_types, 4 + EXTRA_MONO_LOAD_STORE_ARGS, FALSE));
}
}
}
}
void
-mono_llvm_create_aot_module (const char *got_symbol)
+mono_llvm_create_aot_module (const char *got_symbol, gboolean external_symbols, gboolean emit_dwarf)
{
/* Delete previous module */
if (aot_module.plt_entries)
aot_module.module = LLVMModuleCreateWithName ("aot");
aot_module.got_symbol = got_symbol;
+ aot_module.external_symbols = external_symbols;
+ aot_module.emit_dwarf = emit_dwarf;
+ /* The first few entries are reserved */
+ aot_module.max_got_offset = 16;
add_intrinsics (aot_module.module);
add_types (&aot_module);
aot_module.llvm_types = g_hash_table_new (NULL, NULL);
aot_module.plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
+ aot_module.plt_entries_ji = g_hash_table_new (NULL, NULL);
+ aot_module.method_to_lmethod = g_hash_table_new (NULL, NULL);
}
/*
* Emit the aot module into the LLVM bitcode file FILENAME.
*/
void
-mono_llvm_emit_aot_module (const char *filename, int got_size)
+mono_llvm_emit_aot_module (const char *filename, const char *cu_name)
{
LLVMTypeRef got_type;
LLVMValueRef real_got;
+ MonoLLVMModule *module = &aot_module;
/*
* Create the real got variable and replace all uses of the dummy variable with
* the real one.
*/
- got_type = LLVMArrayType (aot_module.ptr_type, got_size);
+ got_type = LLVMArrayType (aot_module.ptr_type, module->max_got_offset + 1);
real_got = LLVMAddGlobal (aot_module.module, got_type, aot_module.got_symbol);
LLVMSetInitializer (real_got, LLVMConstNull (got_type));
- LLVMSetLinkage (real_got, LLVMInternalLinkage);
-
+ if (module->external_symbols) {
+ LLVMSetLinkage (real_got, LLVMExternalLinkage);
+ LLVMSetVisibility (real_got, LLVMHiddenVisibility);
+ } else {
+ LLVMSetLinkage (real_got, LLVMInternalLinkage);
+ }
mono_llvm_replace_uses_of (aot_module.got_var, real_got);
mark_as_used (&aot_module, real_got);
LLVMDeleteGlobal (aot_module.got_var);
emit_llvm_used (&aot_module);
+ emit_dbg_info (&aot_module, filename, cu_name);
+
+ /* Replace PLT entries for directly callable methods with the methods themselves */
+ {
+ GHashTableIter iter;
+ MonoJumpInfo *ji;
+ LLVMValueRef callee;
+
+ g_hash_table_iter_init (&iter, aot_module.plt_entries_ji);
+ while (g_hash_table_iter_next (&iter, (void**)&ji, (void**)&callee)) {
+ if (mono_aot_is_direct_callable (ji)) {
+ LLVMValueRef lmethod;
+
+ lmethod = g_hash_table_lookup (module->method_to_lmethod, ji->data.method);
+ /* The types might not match because the caller might pass an rgctx */
+ if (lmethod && LLVMTypeOf (callee) == LLVMTypeOf (lmethod)) {
+ mono_llvm_replace_uses_of (callee, lmethod);
+ mono_aot_mark_unused_llvm_plt_entry (ji);
+ }
+ }
+ }
+ }
#if 0
{
LLVMWriteBitcodeToFile (aot_module.module, filename);
}
+
+static LLVMValueRef
+md_string (const char *s)
+{
+ return LLVMMDString (s, strlen (s));
+}
+
+/* Debugging support */
+
+static void
+emit_dbg_info (MonoLLVMModule *lmodule, const char *filename, const char *cu_name)
+{
+ LLVMModuleRef module = lmodule->module;
+ LLVMValueRef args [16], cu_args [16], cu, ver;
+ int n_cuargs;
+ char *build_info, *s, *dir;
+
+ /*
+ * This can only be enabled when LLVM code is emitted into a separate object
+ * file, since the AOT compiler also emits dwarf info,
+ * and the abbrev indexes will not be correct since llvm has added its own
+ * abbrevs.
+ */
+ if (!lmodule->emit_dwarf)
+ return;
+
+ /*
+ * Emit dwarf info in the form of LLVM metadata. There is some
+ * out-of-date documentation at:
+ * http://llvm.org/docs/SourceLevelDebugging.html
+ * but most of this was gathered from the llvm and
+ * clang sources.
+ */
+
+ n_cuargs = 0;
+ cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), DW_TAG_compile_unit, FALSE);
+ /* CU name/compilation dir */
+ dir = g_path_get_dirname (filename);
+ args [0] = LLVMMDString (cu_name, strlen (cu_name));
+ args [1] = LLVMMDString (dir, strlen (dir));
+ cu_args [n_cuargs ++] = LLVMMDNode (args, 2);
+ g_free (dir);
+ /* Language */
+ cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), DW_LANG_C99, FALSE);
+ /* Producer */
+ build_info = mono_get_runtime_build_info ();
+ s = g_strdup_printf ("Mono AOT Compiler %s (LLVM)", build_info);
+ cu_args [n_cuargs ++] = LLVMMDString (s, strlen (s));
+ g_free (build_info);
+ /* Optimized */
+ cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ /* Flags */
+ cu_args [n_cuargs ++] = LLVMMDString ("", strlen (""));
+ /* Runtime version */
+ cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ /* Enums */
+ cu_args [n_cuargs ++] = LLVMMDNode (args, 0);
+ cu_args [n_cuargs ++] = LLVMMDNode (args, 0);
+ /* Subprograms */
+ if (lmodule->subprogram_mds) {
+ LLVMValueRef *mds;
+ int i;
+
+ mds = g_new0 (LLVMValueRef, lmodule->subprogram_mds->len);
+ for (i = 0; i < lmodule->subprogram_mds->len; ++i)
+ mds [i] = g_ptr_array_index (lmodule->subprogram_mds, i);
+ cu_args [n_cuargs ++] = LLVMMDNode (mds, lmodule->subprogram_mds->len);
+ } else {
+ cu_args [n_cuargs ++] = LLVMMDNode (args, 0);
+ }
+ /* GVs */
+ cu_args [n_cuargs ++] = LLVMMDNode (args, 0);
+ /* Imported modules */
+ cu_args [n_cuargs ++] = LLVMMDNode (args, 0);
+ /* SplitName */
+ cu_args [n_cuargs ++] = LLVMMDString ("", strlen (""));
+ /* DebugEmissionKind = FullDebug */
+ cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ cu = LLVMMDNode (cu_args, n_cuargs);
+ LLVMAddNamedMetadataOperand (module, "llvm.dbg.cu", cu);
+
+ args [0] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ args [1] = LLVMMDString ("Dwarf Version", strlen ("Dwarf Version"));
+ args [2] = LLVMConstInt (LLVMInt32Type (), 2, FALSE);
+ ver = LLVMMDNode (args, 3);
+ LLVMAddNamedMetadataOperand (module, "llvm.module.flags", ver);
+
+ args [0] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ args [1] = LLVMMDString ("Debug Info Version", strlen ("Debug Info Version"));
+ args [2] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ ver = LLVMMDNode (args, 3);
+ LLVMAddNamedMetadataOperand (module, "llvm.module.flags", ver);
+}
+
+static LLVMValueRef
+emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, const char *name)
+{
+ MonoLLVMModule *module = ctx->lmodule;
+ MonoDebugMethodInfo *minfo = ctx->minfo;
+ char *source_file, *dir, *filename;
+ LLVMValueRef md, args [16], ctx_args [16], md_args [64], type_args [16], ctx_md, type_md;
+ int n_il_offsets;
+ int *il_offsets;
+ int *line_numbers;
+
+ if (!minfo)
+ return NULL;
+
+ mono_debug_symfile_get_line_numbers_full (minfo, &source_file, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
+ if (!source_file)
+ source_file = g_strdup ("<unknown>");
+ dir = g_path_get_dirname (source_file);
+ filename = g_path_get_basename (source_file);
+
+ ctx_args [0] = LLVMConstInt (LLVMInt32Type (), 0x29, FALSE);
+ args [0] = md_string (filename);
+ args [1] = md_string (dir);
+ ctx_args [1] = LLVMMDNode (args, 2);
+ ctx_md = LLVMMDNode (ctx_args, 2);
+
+ type_args [0] = LLVMConstInt (LLVMInt32Type (), DW_TAG_subroutine_type, FALSE);
+ type_args [1] = NULL;
+ type_args [2] = NULL;
+ type_args [3] = LLVMMDString ("", 0);
+ type_args [4] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ type_args [5] = LLVMConstInt (LLVMInt64Type (), 0, FALSE);
+ type_args [6] = LLVMConstInt (LLVMInt64Type (), 0, FALSE);
+ type_args [7] = LLVMConstInt (LLVMInt64Type (), 0, FALSE);
+ type_args [8] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ type_args [9] = NULL;
+ type_args [10] = NULL;
+ type_args [11] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ type_args [12] = NULL;
+ type_args [13] = NULL;
+ type_args [14] = NULL;
+ type_md = LLVMMDNode (type_args, 14);
+
+ /* http://llvm.org/docs/SourceLevelDebugging.html#subprogram-descriptors */
+ md_args [0] = LLVMConstInt (LLVMInt32Type (), DW_TAG_subprogram, FALSE);
+ /* Source directory + file pair */
+ args [0] = md_string (filename);
+ args [1] = md_string (dir);
+ md_args [1] = LLVMMDNode (args ,2);
+ md_args [2] = ctx_md;
+ md_args [3] = md_string (cfg->method->name);
+ md_args [4] = md_string (name);
+ md_args [5] = md_string (name);
+ /* Line number */
+ if (n_il_offsets)
+ md_args [6] = LLVMConstInt (LLVMInt32Type (), line_numbers [0], FALSE);
+ else
+ md_args [6] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ /* Type */
+ md_args [7] = type_md;
+ /* static */
+ md_args [8] = LLVMConstInt (LLVMInt1Type (), 0, FALSE);
+ /* not extern */
+ md_args [9] = LLVMConstInt (LLVMInt1Type (), 1, FALSE);
+ /* Virtuality */
+ md_args [10] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ /* Index into a virtual function */
+ md_args [11] = NULL;
+ md_args [12] = NULL;
+ /* Flags */
+ md_args [13] = LLVMConstInt (LLVMInt1Type (), 0, FALSE);
+ /* isOptimized */
+ md_args [14] = LLVMConstInt (LLVMInt1Type (), 1, FALSE);
+ /* Pointer to LLVM function */
+ md_args [15] = method;
+ /* Function template parameter */
+ md_args [16] = NULL;
+ /* Function declaration descriptor */
+ md_args [17] = NULL;
+ /* List of function variables */
+ md_args [18] = LLVMMDNode (args, 0);
+ /* Line number */
+ md_args [19] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+ md = LLVMMDNode (md_args, 20);
+
+ if (!module->subprogram_mds)
+ module->subprogram_mds = g_ptr_array_new ();
+ g_ptr_array_add (module->subprogram_mds, md);
+
+ g_free (dir);
+ g_free (filename);
+ g_free (source_file);
+ g_free (il_offsets);
+ g_free (line_numbers);
+
+ return md;
+}
+
+static void
+emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsigned char *cil_code)
+{
+ MonoCompile *cfg = ctx->cfg;
+
+ if (ctx->minfo && cil_code && cil_code >= cfg->header->code && cil_code < cfg->header->code + cfg->header->code_size) {
+ MonoDebugSourceLocation *loc;
+ LLVMValueRef loc_md, md_args [16];
+ int nmd_args;
+
+ loc = mono_debug_symfile_lookup_location (ctx->minfo, cil_code - cfg->header->code);
+
+ if (loc) {
+ nmd_args = 0;
+ md_args [nmd_args ++] = LLVMConstInt (LLVMInt32Type (), loc->row, FALSE);
+ md_args [nmd_args ++] = LLVMConstInt (LLVMInt32Type (), loc->column, FALSE);
+ md_args [nmd_args ++] = ctx->dbg_md;
+ md_args [nmd_args ++] = NULL;
+ loc_md = LLVMMDNode (md_args, nmd_args);
+ LLVMSetCurrentDebugLocation (builder, loc_md);
+ mono_debug_symfile_free_location (loc);
+ }
+ }
+}
+
/*
DESIGN:
- Emit LLVM IR from the mono IR using the LLVM C API.